Last active
March 18, 2020 02:32
-
-
Save bcat95/4236f6d81d3cbddb12fd8c65166330e5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require $_SERVER['DOCUMENT_ROOT']."/admin/include/conn.php"; | |
require $_SERVER['DOCUMENT_ROOT']."/admin/push/push-func.php"; | |
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/autoload.php'; | |
require_once $_SERVER['DOCUMENT_ROOT'].'/push/PushNotification.php'; | |
// lay danh sach notification chua gui | |
function get_schedule_notification(){ | |
global $connect; | |
$query="SELECT * FROM lwb_notifications_schedule t1 WHERE status!=2 ORDER BY schedule_id ASC LIMIT 1"; | |
$result=mysqli_query($connect,$query);// or die(mysqli_error($connect)); | |
if ($result){ | |
$row = $result->fetch_assoc(); | |
return $row; | |
} else return false; | |
} | |
// update danh sach notification chua gui | |
function set_schedule_notification($notification_id,$endpoint_start,$endpoint_end){ | |
global $connect; | |
$status = ' , status=1 '; | |
if ($endpoint_start >= ($endpoint_end-1)) $status= ' , status=2 '; | |
$query="UPDATE lwb_notifications_schedule SET endpoint_start='".$endpoint_start."' ".$status." WHERE notification_id = '".$notification_id."'"; | |
if ($connect->query($query) === TRUE) { | |
} else { | |
echo "Error: " . $query . "<br/>" . $connect->error; | |
} | |
} | |
// lay danh sach endpoint can gui | |
function get_schedule_endpoint_list($endpoint_start,$endpoint_end){ | |
global $connect; | |
$query="SELECT endpoint_id FROM lwb_user_push_subscription t1 WHERE subscribed = 1 AND endpoint_id >= '".$endpoint_start."' AND endpoint_id <= '".$endpoint_end."' ORDER BY endpoint_id LIMIT 250"; | |
$result=mysqli_query($connect,$query);// or die(mysqli_error($connect)); | |
if ($result){ | |
$rows = array(); | |
while($row = $result->fetch_assoc()) { | |
$rows[] = $row['endpoint_id']; | |
} | |
return $rows; | |
} else return false; | |
} | |
// gửi nội dung và danh sách đến hàm gửi | |
function send_notifications($data,$arr_endpoint_id){ | |
// $actions = array(); | |
// foreach ($data['action_id'] as $key => $value) { | |
// if ($value != '') { | |
// $action = array(); | |
// $action['action'] = $data['action_id'][$key]; | |
// $action['title'] = $data['action_value'][$key]; | |
// $action['icon'] = $data['action_icon'][$key]; | |
// $action['url'] = $data['action_url'][$key]; | |
// $actions[$key] = $action; | |
// } | |
// } | |
$sendList = array_chunk($arr_endpoint_id, 100, true); | |
$data['title'] = $data['headings']; | |
$data['body'] = $data['contents']; | |
$data['url'] = $data['url']; | |
$actions = json_decode($data['actions'], TRUE); | |
foreach ($sendList as $key => $arr_endpoint_id) { | |
$pushNotification = new PushNotification($arr_endpoint_id); | |
$pushNotification->setNotificationId($data['notification_id']); | |
if (sizeof($actions) > 0) { | |
$pushNotification->setActions($actions); | |
} | |
if ($data['title'] != '' && $data['body'] != '' && $data['url'] != ''){ | |
$pushNotification->setNotificationContent($data['title'], $data['body'], $data['url']); | |
} | |
if ($data['icon'] != '' && $data['badge'] != ''){ | |
$pushNotification->setIconAndBadge($data['icon'], $data['badge']); | |
} | |
if ($data['image'] != ''){ | |
$pushNotification->setImage($data['image']); | |
} | |
try { | |
$pushNotification->sendNotifications(); | |
} catch (Exception $e) { | |
echo 'Caught exception: ', $e->getMessage(), "\n<br/>"; | |
continue; | |
} | |
} | |
// sleep(3); | |
return TRUE; | |
} | |
// kiem tra va gui | |
function schedule_main(){ | |
$milliseconds = round(microtime(true) * 1000000); | |
$notification = get_schedule_notification(); | |
if (!$notification){ | |
echo "notification schedule null<br/>"; | |
return false; | |
} else { | |
$endpoint_start = $notification['endpoint_start']; | |
$endpoint_end = $notification['endpoint_end']; | |
$arr_endpoint_id = get_schedule_endpoint_list($endpoint_start,$endpoint_end); | |
if ($arr_endpoint_id) { | |
$endpoint_start = $arr_endpoint_id[sizeof($arr_endpoint_id)-1]; | |
$data = get_notification($notification['notification_id']); | |
if (!$data) { | |
echo "notification data null<br/>"; | |
return false; | |
} else { | |
if (send_notifications($data,$arr_endpoint_id)) | |
set_schedule_notification($notification['notification_id'],$endpoint_start,$endpoint_end); | |
else set_schedule_notification($notification['notification_id'],$endpoint_start,$endpoint_end); | |
} | |
} else echo "arr_endpoint_id null<br/>"; | |
} | |
$milliseconds=round(microtime(true) * 1000000)-$milliseconds; | |
echo "{'success': [{'message': 'Kiểm tra Log ".($milliseconds/1000000)."s'}]}<br/>"; | |
} | |
while(get_schedule_notification()) { | |
schedule_main(); | |
} | |
echo '{"success":[{"message":"notification schedule null"}]}'; | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Minishlink\WebPush\Encryption; | |
use Minishlink\WebPush\Subscription; | |
use Minishlink\WebPush\WebPush; | |
class PushNotification | |
{ | |
/** | |
* @var User | |
*/ | |
protected $receiver; | |
/** | |
* @var array | |
*/ | |
protected $subscriptions; | |
/** | |
* @var array | |
*/ | |
protected $payloadData = []; | |
public function __construct($receiver) | |
{ | |
$this->receiver = $receiver; | |
} | |
public function logError($messages){ | |
echo $messages; | |
} | |
public function setNotificationId($notification_id) | |
{ | |
$this->payloadData['notification_id'] = $notification_id; | |
} | |
public function setNotificationContent($title, $body, $url = null) | |
{ | |
$this->payloadData['title'] = $title; | |
$this->payloadData['body'] = $body; | |
$this->payloadData['url'] = $url; | |
} | |
public function setImage($image) | |
{ | |
$this->payloadData['image'] = $image; | |
} | |
public function setIconAndBadge($icon, $badge = null) | |
{ | |
$this->payloadData['icon'] = $icon; | |
if ($badge) | |
{ | |
$this->payloadData['badge'] = $badge; | |
} | |
} | |
public function setDirection($direction) | |
{ | |
$this->payloadData['dir'] = $direction; | |
} | |
public function setNotificationTag($tag) | |
{ | |
$this->payloadData['tag'] = $tag; | |
} | |
public function setActions($actions) | |
{ | |
$actions = json_encode($actions,JSON_UNESCAPED_UNICODE); | |
$this->payloadData['actions'] = $actions; | |
} | |
public function setCustomPayloadData($name, $value) | |
{ | |
$this->payloadData[$name] = $value; | |
} | |
protected function applyPayloadDefaults() | |
{ | |
$this->payloadData = array_replace([ | |
'title' => 'Thông báo từ ABCDEF', | |
'body' => 'Bạn có thông báo mới từ ABCDEF', | |
'url' => 'https://ABCDEF.com/?utm_source=push', | |
'image' => $this->getDefaultImageForVisitor(), | |
'badge' => $this->getDefaultBadgeForVisitor(), | |
'icon' => $this->getDefaultIconForVisitor(), | |
'subscriber_id' => '', | |
'notification_id' => '', | |
'dir' => 'ltr', | |
'tag' => '', | |
'tag_phrase' => 'plus_x_previous', | |
'actions' => $this->getDefaultActionsForVisitor(), | |
], $this->payloadData); | |
return $this->payloadData; | |
} | |
public function isPushAvailable() | |
{ | |
return true; | |
} | |
public function isReceiverSubscribed() | |
{ | |
$subscriptions = $this->getReceiverSubscriptions(); | |
return boolval(count($subscriptions)); | |
} | |
protected function getReceiverSubscriptions() | |
{ | |
if ($this->subscriptions === null) | |
{ | |
$this->subscriptions = $this->getUserSubscriptions($this->receiver); | |
} | |
return $this->subscriptions; | |
} | |
public function sendNotifications() | |
{ | |
if (!$this->isPushAvailable()) | |
{ | |
return; | |
} | |
$payload = $this->applyPayloadDefaults(); | |
$webPush = $this->getWebPushObject(); | |
$webPush->setDefaultOptions([ | |
'TTL' => 86400, // if undelivered after 1 day, expire the notification | |
]); | |
$subscriptions = $this->getReceiverSubscriptions(); | |
foreach ($subscriptions AS $subscription) | |
{ | |
$authData = json_decode($subscription['data'], true); | |
$payload['subscriber_id'] = $subscription['endpoint_id']; | |
$array = [ | |
'endpoint' => $subscription['endpoint'], | |
'publicKey' => $authData['key'], | |
'authToken' => $authData['token'], | |
'contentEncoding' => $authData['encoding'] | |
]; | |
try | |
{ | |
$webPush->setAutomaticPadding($this->getEndpointPadding($subscription['endpoint'])); | |
$subObj = Subscription::create($array); | |
// $subObj = Subscription::create([ | |
// 'endpoint' => $subscription['endpoint'], | |
// 'publicKey' => $authData['key'], | |
// 'authToken' => $authData['token'], | |
// 'contentEncoding' => $authData['encoding'] | |
// ]); | |
$webPush->sendNotification( | |
$subObj, | |
json_encode($payload) | |
); | |
} | |
catch (\Exception $e) | |
{ | |
// generally indicates that the payload is too big which at ~3000 bytes shouldn't happen for a typical alert... | |
continue; | |
} | |
} | |
foreach ($webPush->flush() as $report) { | |
$results[] = $report->jsonSerialize(); | |
} | |
$this->handleResults($results, $subscriptions); | |
} | |
protected function getEndpointPadding($endpoint) | |
{ | |
if (strpos($endpoint, 'mozilla') !== false) | |
{ | |
// firefox, at least on Android, has an issue with automatic padding which | |
// is used to make encryption more secure, but makes encryption slower. | |
// see: https://github.com/web-push-libs/web-push-php/issues/108 | |
// TODO: ideally won't need this forever if Mozilla ever fix this or if library works-around it | |
return 0; | |
} | |
if (strpos($endpoint, '.ucweb.com') !== false) | |
{ | |
return 0; | |
} | |
return Encryption::MAX_COMPATIBILITY_PAYLOAD_LENGTH; | |
} | |
protected function handleResults($results, array $subscriptions) | |
{ | |
if (is_array($results)) // may have errors | |
{ | |
global $connect; | |
$notification_id = $this->payloadData['notification_id']; | |
$remaining = 0; | |
$successful = 0; | |
$failed = 0; | |
$canceled = 0; | |
foreach ($results AS $result) | |
{ | |
if ($result['success']) | |
{ | |
if (isset($result['endpoint'])) | |
{ | |
$endpointHash = $this->getEndpointHash($result['endpoint']); | |
$remaining += 1;$successful += 1; | |
$query = "UPDATE user_push_subscription SET last_seen = '".time()."' WHERE endpoint_hash = '".$endpointHash."'"; | |
mysqli_query($connect,$query) or die(mysqli_error($connect)); | |
} | |
else | |
{ | |
// Mozilla doesn't appear to send anything other than 'success' in its successful results. | |
continue; | |
} | |
} | |
else if (!empty($result['expired'])) | |
{ | |
switch ($result['expired']) | |
{ | |
// 401 and 403 generally represent when something in the request doesn't match, likely | |
// due to VAPID keys changing | |
case 401: | |
case 403: | |
case 404: | |
case 410: | |
if (isset($result['endpoint'])) | |
{ | |
$endpointHash = $this->getEndpointHash($result['endpoint']); | |
$remaining += 1;$failed += 1; | |
$query = "UPDATE user_push_subscription SET subscribed = '0' WHERE endpoint_hash = '".$endpointHash."'"; | |
mysqli_query($connect,$query) or die(mysqli_error($connect)); | |
} | |
break; | |
case 406: | |
// not a server error but rate limiting - future pushes should work | |
case 500: | |
case 502: | |
case 503: | |
case 504: | |
// these indicate server errors that are likely temporary - future pushes should work | |
break; | |
default: | |
$this->logError ("Push notification failure: " . \GuzzleHttp\json_encode($result)); | |
if (isset($result['endpoint'])) | |
{ | |
$endpointHash = $this->getEndpointHash($result['endpoint']); | |
$remaining += 1;$failed += 1;$canceled+=1; | |
// $query = "UPDATE user_push_subscription SET subscribed = '0' WHERE endpoint_hash = '".$endpointHash."'"; | |
// mysqli_query($connect,$query) or die(mysqli_error($connect)); | |
} | |
break; | |
} | |
} | |
else | |
{ | |
$this->logError("Push notification failure: " . \GuzzleHttp\json_encode($result)); | |
if (isset($result['endpoint'])) | |
{ | |
$endpointHash = $this->getEndpointHash($result['endpoint']); | |
// $query = "UPDATE user_push_subscription SET subscribed = '0' WHERE endpoint_hash = '".$endpointHash."'"; | |
// mysqli_query($connect,$query) or die(mysqli_error($connect)); | |
} | |
$remaining += 1;$failed += 1;$canceled+=1; | |
} | |
} | |
// update notification data | |
$query = "UPDATE push_notifications SET completed_at = '".time()."',canceled = canceled+".$canceled.", failed = failed+".$failed.", successful = successful+".$successful.", remaining = remaining-".$remaining." WHERE notification_id = '".$notification_id."'"; | |
mysqli_query($connect,$query) or die(mysqli_error($connect)); | |
} | |
else // no errors so mark all as seen | |
{ | |
// $endpointHashes = array_map( | |
// [$pushRepo, 'getEndpointHash'], | |
// array_column($subscriptions, 'endpoint') | |
// ); | |
// $db->update('xf_user_push_subscription', [ | |
// 'last_seen' => time() | |
// ], 'endpoint_hash IN(' . $db->quote($endpointHashes) . ')'); | |
} | |
} | |
/** | |
* @return WebPush | |
*/ | |
protected function getWebPushObject() | |
{ | |
$auth = array( | |
'VAPID' => array( | |
'subject' => 'https://ABCDEF.com/', // NBH Key | |
'publicKey' => 'ABCDEF', // don't forget that your public key also lives in app.js | |
'privateKey' => 'ABCDEF' // in the real world, this would be in a secret file | |
) | |
); | |
$clientOptions = [ | |
\GuzzleHttp\RequestOptions::ALLOW_REDIRECTS => false, | |
]; // see \GuzzleHttp\RequestOptions | |
return new WebPush($auth, [], 10, $clientOptions); | |
} | |
protected function getDefaultImageForVisitor() | |
{ | |
$image = ''; | |
return $image; | |
} | |
protected function getDefaultBadgeForVisitor() | |
{ | |
$badge = 'hhttps://ABCDEF.com/icon-96x96.png'; | |
return $badge; | |
} | |
protected function getDefaultIconForVisitor() | |
{ | |
$icon = 'https://ABCDEF.com/main/styles/s-logo.png'; | |
return $icon; | |
} | |
protected function getDefaultActionsForVisitor() | |
{ | |
$actions = '[ | |
{ "action": "close", "title": "Đóng"} | |
]'; | |
$actions = json_decode($actions, TRUE); | |
return json_encode($actions); | |
} | |
protected function getUserSubscriptions($receiver) | |
{ | |
$subscriptions = array(); | |
foreach ($receiver as $key => $value) { | |
if (get_endpoint($value)) $subscriptions[$key] = get_endpoint($value); | |
} | |
return $subscriptions; | |
} | |
protected function getEndpointHash($endpoint) | |
{ | |
return md5($endpoint); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment