View source
<?php
namespace Drupal\push_notifications;
class PushNotificationsBroadcasterApns implements PushNotificationsBroadcasterInterface {
const PUSH_NOTIFICATIONS_APNS_PORT = 2195;
protected $tokens;
protected $payload;
protected $countAttempted = 0;
protected $countSuccess = 0;
protected $success = FALSE;
protected $message;
protected $apns;
private $certificate_path;
private $config;
private $gateway;
public function __construct() {
$this->config = \Drupal::config('push_notifications.apns');
$this
->determineCertificatePath();
$this
->determineGateway();
}
public function setTokens($tokens) {
$this->tokens = $tokens;
}
public function setMessage($message) {
$this->message = $message;
$this->payload = array(
'aps' => array(
'alert' => $message,
),
);
}
private function determineGateway() {
switch ($this->config
->get('environment')) {
case 'development':
$this->gateway = 'gateway.sandbox.push.apple.com';
break;
case 'production':
$this->gateway = 'gateway.push.apple.com';
break;
}
}
private function openConnection() {
$stream_context = stream_context_create();
stream_context_set_option($stream_context, 'ssl', 'local_cert', $this->certificate_path);
if (strlen($this->config
->get('passphrase'))) {
stream_context_set_option($stream_context, 'ssl', 'passphrase', $this->config
->get('passphrase'));
}
if ($this->config
->get('set_entrust_certificate')) {
stream_context_set_option($stream_context, 'ssl', 'CAfile', drupal_get_path('module', 'push_notifications') . '/certificates/entrust_2048_ca.cer');
}
$this->apns = stream_socket_client('ssl://' . $this->gateway . ':' . self::PUSH_NOTIFICATIONS_APNS_PORT, $error, $error_string, 2, STREAM_CLIENT_CONNECT, $stream_context);
if (!$this->apns) {
throw new \Exception('APNS connection could not be established. Check to make sure you are using a valid certificate file.');
}
}
private function determineCertificatePath() {
$path = $this->config
->get('certificate_folder');
if (empty($path)) {
$path = drupal_realpath(drupal_get_path('module', 'push_notifications'));
$path .= DIRECTORY_SEPARATOR . 'certificates' . DIRECTORY_SEPARATOR;
}
$path .= push_notifications_get_certificate_name($this->config
->get('environment'));
if (!file_exists($path)) {
throw new \Exception(t("Cannot find apns certificate file at @path", array(
'@path' => $path,
)));
}
$this->certificate_path = $path;
}
public function sendBroadcast() {
if (empty($this->tokens) || empty($this->payload)) {
throw new \Exception('No tokens or payload set.');
}
$payload = json_encode($this->payload);
$stream_counter = 0;
foreach ($this->tokens as $token) {
if ($stream_counter == 0) {
$this
->openConnection();
}
$stream_counter++;
$this->countAttempted++;
$apns_message = chr(0) . chr(0) . chr(32) . pack('H*', $token) . pack('n', strlen($payload)) . $payload;
$success = fwrite($this->apns, $apns_message);
if ($success) {
$this->countSuccess++;
}
elseif ($success == 0 || $success == FALSE || $success < strlen($apns_message)) {
\Drupal::logger('push_notifications')
->notice("APNS message could not be sent. Token: @token. fwrite returned @success_message", array(
'@token' => $token,
'@success_message' => $success,
));
}
if ($stream_counter >= $this->config
->get('stream_context_limit')) {
$stream_counter = 0;
if (is_resource($this->apns)) {
fclose($this->apns);
}
}
}
if (is_resource($this->apns)) {
fclose($this->apns);
}
$this->success = TRUE;
}
public function getResults() {
return array(
'network' => PUSH_NOTIFICATIONS_NETWORK_ID_IOS,
'payload' => $this->payload,
'count_attempted' => $this->countAttempted,
'count_success' => $this->countSuccess,
'success' => $this->success,
);
}
}