Last active
September 1, 2023 06:11
-
-
Save efreed/89b64d4c0c2a760466dca170b11e10eb to your computer and use it in GitHub Desktop.
PHP NotificationPusher to mobile devices (namespace is ready to work with Symfony)
This file contains hidden or 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 | |
namespace App\Service\Notification\PushNotification; | |
use Exception; | |
// composer require edamov/pushok | |
// https://github.com/edamov/pushok | |
use Pushok\AuthProvider; | |
use Pushok\Client; | |
use Pushok\Notification; | |
use Pushok\Payload; | |
use Pushok\Payload\Alert; | |
class ApnsPushService { | |
private $options; | |
private $production; | |
/** | |
* Looks for these vars in $_ENV, unless they are part of $envOverrides. Only provide a P8 or P12 config. | |
* APNS_P8_PATH An absolute path to the .cert file | |
* APNS_P8_PASSPHRASE Optionally provide if the cert file needs a passphrase | |
* APNS_P8_KEY_ID Provide the Key ID from Apple | |
* APNS_P8_TEAM_ID Provide The Team ID from Apple | |
* APNS_P12_PATH An absolute path to the P12 .cert file | |
* APNS_P12_PASSPHRASE Optionally provide if the cert file needs a passphrase | |
* APNS_BUNDLE_ID Optionally provide if the cert file needs a passphrase | |
* APNS_ENVIRONMENT Optional as it will default to using $_ENV['APP_ENV'] | |
* @param array $envOverrides | |
*/ | |
public function __construct($envOverrides=[]) { | |
$this->options = [ | |
'app_bundle_id' => isset($envOverrides['APNS_BUNDLE_ID']) ? $envOverrides['APNS_BUNDLE_ID'] : ($_ENV['APNS_BUNDLE_ID']??null) | |
]; | |
$p12Path = isset($envOverrides['APNS_P12_PATH']) ? $envOverrides['APNS_P12_PATH'] : ($_ENV['APNS_P12_PATH']??null); | |
if ($p12Path) { | |
$this->options['certificate_path'] = $p12Path; | |
$this->options['certificate_secret'] = isset($envOverrides['APNS_P12_PASSPHRASE']) ? $envOverrides['APNS_P12_PASSPHRASE'] : ($_ENV['APNS_P12_PASSPHRASE']??null); | |
} else { | |
$this->options['private_key_path'] = isset($envOverrides['APNS_P8_PATH']) ? $envOverrides['APNS_P8_PATH'] : ($_ENV['APNS_P8_PATH']??null); | |
$this->options['private_key_secret'] = isset($envOverrides['APNS_P8_PASSPHRASE']) ? $envOverrides['APNS_P8_PASSPHRASE'] : ($_ENV['APNS_P8_PASSPHRASE']??null); | |
$this->options['key_id'] = isset($envOverrides['APNS_P8_KEY_ID']) ? $envOverrides['APNS_P8_KEY_ID'] : ($_ENV['APNS_P8_KEY_ID']??null); | |
$this->options['team_id'] = isset($envOverrides['APNS_P8_TEAM_ID']) ? $envOverrides['APNS_P8_TEAM_ID'] : ($_ENV['APNS_P8_TEAM_ID']??null); | |
} | |
// Input validation | |
// if (!$this->options['...']) { | |
// throw new Exception('ApnsPushService is missing $_ENV["..."]'); | |
// } | |
$defaultEnvironment = (($_ENV['APP_ENV']??null) == 'production'); | |
$environment = isset($envOverrides['APNS_ENVIRONMENT']) ? $envOverrides['APNS_ENVIRONMENT'] : ($_ENV['APNS_ENVIRONMENT']??$defaultEnvironment); | |
$this->production = ($environment == 'prod' || $environment == 'production'); | |
} | |
/** | |
* Send the message now | |
* @param string|array[string] $deviceTokens Message(s) will be sent to these one or many devices | |
* @param string|array[string] $messages Send one or many messages to all deivces | |
* @param array $params provide a ['title'] to be shared across all messages, and or specify a ['sound'] | |
* @return array Truthy values confirming each message was sent. The value is the number of bytes sent. | |
*/ | |
public function push($deviceTokens, $messages, $params=[]) { | |
if (!is_array($deviceTokens)) { | |
$deviceTokens = [$deviceTokens]; | |
} | |
if (!is_array($messages)) { | |
$messages = [$messages]; | |
} | |
// Be aware of thing that Token will stale after one hour, but ok to reuse it for a whole page request | |
if (!($GLOBALS['ApnsPushService_authProvider']??null)) { | |
if ($this->options['certificate_path']??null) { | |
$GLOBALS['ApnsPushService_authProvider'] = AuthProvider\Certificate::create($this->options); | |
} else { | |
$GLOBALS['ApnsPushService_authProvider'] = AuthProvider\Token::create($this->options); | |
} | |
} | |
$notifications = []; | |
foreach ($messages as $message) { | |
$alert = Alert::create();//->setTitle('Hello!'); | |
$alert = $alert->setBody($message); | |
$payload = Payload::create(); | |
$payload->setAlert($alert); | |
$payload->setSound('default'); | |
$payload->setBadge(1); | |
// Add custom value to your notification, needs to be customized | |
//$payload->setCustomValue('key', 'value'); | |
foreach ($deviceTokens as $deviceToken) { | |
$notifications[] = new Notification($payload,$deviceToken); | |
} | |
} | |
// If you have issues with ssl-verification, you can temporarily disable it. Please see attached note. | |
// Disable ssl verification | |
// $client = new Client($authProvider, $production = false, [CURLOPT_SSL_VERIFYPEER=>false] ); | |
$client = new Client($GLOBALS['ApnsPushService_authProvider'], $this->production); | |
$client->addNotifications($notifications); | |
$responses = $client->push(); // returns an array of ApnsResponseInterface (one Response per Notification) | |
$results = []; | |
foreach ($responses as $response) { | |
// dump([ | |
// // The device token | |
// 'device' => $response->getDeviceToken(), | |
// // A canonical UUID that is the unique ID for the notification. E.g. 123e4567-e89b-12d3-a456-4266554400a0 | |
// // 'notification_id' => $response->getApnsId(), | |
// // Status code. E.g. 200 (Success), 410 (The device token is no longer active for the topic.) | |
// 'status' => $response->getStatusCode(), | |
// // E.g. The device token is no longer active for the topic. | |
// 'reason' => $response->getReasonPhrase(), | |
// // E.g. Unregistered | |
// 'error' => $response->getErrorReason(), | |
// // E.g. The device token is inactive for the specified topic. | |
// 'error_message' => $response->getErrorDescription(), | |
// 'timestamp' => $response->get410Timestamp(), | |
// ]); | |
$error = $response->getErrorReason(); | |
$results[] = $error ?: true; | |
} | |
return $results; | |
} | |
} |
This file contains hidden or 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 | |
namespace App\Service\NotificationPusher; | |
use Exception; | |
class GcmPushService { | |
private $apiKey; | |
private $environment; | |
/** | |
* Looks for these 2 vars in $_ENV, unless they are part of $envOverrides | |
* GCM_PUSH_KEY The GCM key | |
* GCM_PUSH_ENVIRONMENT Optional as it will default to using $_ENV['APP_ENV'] | |
* @param array $envOverrides | |
*/ | |
public function __construct($envOverrides=[]) { | |
$this->apiKey = $envOverrides['GCM_PUSH_KEY'] ?: ($_ENV['GCM_PUSH_KEY']??null); | |
if (!$this->apiKey) { | |
throw new Exception('GcmPushService is missing $_ENV["GCM_PUSH_KEY"]'); | |
} | |
$defaultEnvironment = (($_ENV['APP_ENV']??null) == 'production') ? 'prod' : 'dev'; | |
$environment = $envOverrides['GCM_PUSH_ENVIRONMENT'] ?: ($_ENV['GCM_PUSH_ENVIRONMENT']??$defaultEnvironment); | |
$this->environment = $environment == 'prod' ? 'prod' : 'dev'; | |
} | |
/** | |
* Send the message now | |
* @param string|array[string] $deviceTokens Message(s) will be sent to these one or many devices | |
* @param string|array[string] $messages Send one or many messages to all deivces | |
* @param array $params provide a ['title'] to be shared across all messages, and or specify a ['sound'] | |
* @return array Responses from Gcm | |
*/ | |
public function push($registrationIds, $messages, $params=[]) { | |
if (!is_array($registrationIds)) { | |
$registrationIds = [$registrationIds]; | |
} | |
if (!is_array($messages)) { | |
$messages = [$messages]; | |
} | |
$url = 'https://fcm.googleapis.com/fcm/send'; | |
// TODO What if $this->environment is not 'prod' ? | |
$headers = array( | |
'Authorization: key=' . $this->apiKey, | |
'Content-Type: application/json' | |
); | |
$results = []; | |
foreach ($messages as $message) { | |
$fields = array( | |
'registration_ids' => $registrationIds, | |
'data' => array( | |
'title' => $params['title'] ?? '', | |
'message' => $message, | |
'subtitle' => $params['subtitle'] ?? '', | |
'tickerText' => $params['ticker'] ?? '', | |
'msgcnt' => $params['messagecount'] ?? 1, | |
'vibrate' => $params['vibrate'] ?? 1 | |
) | |
); | |
$results[] = $this->useCurl($url, $headers, json_encode($fields)); | |
} | |
return $results; | |
} | |
private function useCurl($url, $headers, $fields = null) { | |
if (!$url) { | |
return; | |
} | |
// Open connection | |
$ch = curl_init(); | |
// Set the url, number of POST vars, POST data | |
curl_setopt($ch, CURLOPT_URL, $url); | |
curl_setopt($ch, CURLOPT_POST, true); | |
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
// Disabling SSL Certificate support temporarly | |
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); | |
if ($fields) { | |
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); | |
} | |
// Execute post | |
$result = curl_exec($ch); | |
if ($result === FALSE) { | |
die('Curl failed: ' . curl_error($ch)); | |
} | |
// Close connection | |
curl_close($ch); | |
return $result; | |
} | |
} |
This file contains hidden or 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
// To send notifications to Windows Phones, start with a copy of GcmPushService.php and merge in this example logic for the push() function. | |
// Source: https://gist.github.com/joashp/b2f6c7e24127f2798eb2 | |
public function pushExample($data, $uri) { | |
$delay = 2; | |
$msg = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" . | |
"<wp:Notification xmlns:wp=\"WPNotification\">" . | |
"<wp:Toast>" . | |
"<wp:Text1>".htmlspecialchars($data['mtitle'])."</wp:Text1>" . | |
"<wp:Text2>".htmlspecialchars($data['mdesc'])."</wp:Text2>" . | |
"</wp:Toast>" . | |
"</wp:Notification>"; | |
$sendedheaders = array( | |
'Content-Type: text/xml', | |
'Accept: application/*', | |
'X-WindowsPhone-Target: toast', | |
"X-NotificationClass: $delay" | |
); | |
$response = $this->useCurl($uri, $sendedheaders, $msg); | |
$result = array(); | |
foreach(explode("\n", $response) as $line) { | |
$tab = explode(":", $line, 2); | |
if (count($tab) == 2) | |
$result[$tab[0]] = trim($tab[1]); | |
} | |
return $result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment