iOs 10 - SWIFT 3 - Notification push - php

I have a little problem with notification push and iOs 10 (with Swift 3)..
I followed this tutorial : https://www.sitepoint.com/developing-push-notifications-for-ios-10/
With Pusher, it's ok, works fine..
I receive the notification on my phone.
But I would like to send notifications from my web server..
I generate my .pem file (http://www.apptuitions.com/generate-pem-file-for-push-notification/)
My php code :
$apnsServer = 'ssl://gateway.sandbox.push.apple.com:2195';
$privateKeyPassword = 'mykey';
$message = "My message here !";
$deviceToken ='MYTOKENHERE';
$pushCertAndKeyPemFile = 'pushcert.pem';
$stream = stream_context_create();
stream_context_set_option($stream,'ssl','passphrase',$privateKeyPassword);
stream_context_set_option($stream,'ssl','local_cert',$pushCertAndKeyPemFile);
$connectionTimeout = 30;
$connectionType = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
$connection = stream_socket_client($apnsServer, $errorNumber, $errorString, $connectionTimeout,$connectionType,$stream);
if (!$connection){
echo "Failed to connect to the APNS server. Error = $errorString <br/>";
exit;
}
else{
echo "Successfully connected to the APNS. Processing...</br>";
}
$messageBody['aps'] = array('alert' => $message,'badge' => 1, 'sound' => 'default');
$payload = json_encode($messageBody);
$notification = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
$wroteSuccessfully = fwrite($connection, $notification, strlen($notification));
if (!$wroteSuccessfully){
echo "Could not send the message<br/>";
} else {
echo "Successfully sent the message<br/>";
}
Result :
Successfully connected to the APNS. Processing...
Successfully sent the message
But I never receive notification on my phone
Why ?
How to send a notification push with php ?
Thanks for your help :)
[EDIT]
Ok, i found a solution..
Just add at the end:
fclose($connection);

Related

Push notification work on browser doesn't on commandline

I have php file for running apns. And it does work when i call web page on browser. However it doesn't work on terminal with calling
php deneme.php
I comfirm that .pem file is correctly created. And also determine its location in php file is correct too(because work correctly on browser). I run out with option. I hope you give me an idea.
The deneme.php file is:
<?php
$apnsServer = 'ssl://gateway.sandbox.push.apple.com:2195';
$privateKeyPassword = 'MyPassword123';
$message = 'Test Push Notifications';
$deviceToken =
'2877b691ffd9a3edfa45ee31ff25083f1845e016e7902d130eb09713b1c2ed2f';
$pushCertAndKeyPemFile = $_SERVER['DOCUMENT_ROOT'].'/ck.pem';// 'ck.pem';
$stream = stream_context_create();
stream_context_set_option($stream,
'ssl',
'passphrase',
$privateKeyPassword);
stream_context_set_option($stream,
'ssl',
'local_cert',
$pushCertAndKeyPemFile);
$connectionTimeout = 20;
$connectionType = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
$connection = stream_socket_client($apnsServer,
$errorNumber,
$errorString,
$connectionTimeout,
$connectionType,
$stream);
if (!$connection){
echo "Failed to connect to the APNS server. Error no = $errorNumber<br/>";
exit;
} else {
echo "Successfully connected to the APNS. Processing...</br>";
}
$messageBody['aps'] = array('alert' => $message,
'sound' => 'default',
'badge' => 2,
);
$payload = json_encode($messageBody);
$notification = chr(0) .
pack('n', 32) .
pack('H*', $deviceToken) .
pack('n', strlen($payload)) .
$payload;
$wroteSuccessfully = fwrite($connection, $notification, strlen($notification));
if (!$wroteSuccessfully){
echo "Could not send the message<br/>";
}
else {
echo "Successfully sent the message<br/>";
}
fclose($connection);
?>
There are no $_SERVER[] superglobals available when running from CLI, since there is no server running. Replace$_SERVER['DOCUMENT_ROOT'].'/ck.pem'; with the absolute path to your ck.pem file.

APNS not working, SSL Broken Pipe & bad write retry

I'm developing apple application for my company,
I'm working on server side using PHP, laravel framework to send message to APNS.
For testing, I use hardcode device token.
I get it work on one device that I hardcode.
so I'm advance to function that send apns, a device token that requested in function.
so when I call this function, it get device token from database and send to apns.
I get error
fwrite(): SSL operation failed with code 1. OpenSSL Error messages: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry
and
fwrite(): SSL: Broken pipe
I change the code back to first testing, but it does not work like before.
anyone have idea what I made wrong or did I made a mistake in my request?
for note this is my code
$apnsServer = 'ssl://gateway.sandbox.push.apple.com:2195';
$privateKeyPassword = 'my_private_key';
$id = $request->input('id');
$message = "message_here";
$userSelected = User::select('device_token')->where('id', $id)->first();
$deviceToken = str_replace(' ', '', $userSelected['device_token']);
$pushCertAndKeyPemFile = $_SERVER['DOCUMENT_ROOT'].'my_certificate.pem';
$stream = stream_context_create();
stream_context_set_option($stream, 'ssl', 'passphrase', $privateKeyPassword);
stream_context_set_option($stream, 'ssl', 'local_cert', $pushCertAndKeyPemFile);
$connectionTimeout = 30;
$connectionType = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
$connection = stream_socket_client($apnsServer, $errorNumber, $errorString, $connectionTimeout, $connectionType, $stream);
if (!$connection){
echo "Failed to connect to the APNS server. Error = $errorString <br/>";
exit;
}else{
echo "Successfully connected to the APNS. Processing...</br>";
}
$messageBody['aps'] = array('alert' => $message, 'sound' => 'default', 'badge' => 1);
$payload = json_encode($messageBody);
$notification = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
$wroteSuccessfully = fwrite($connection, $notification, strlen($notification));
if (!$wroteSuccessfully){
echo "Could not send the message<br/>";
} else {
echo "Successfully sent the message<br/>";
}
After some research, i've found my problem.
When our server send PUSH message to APNS, there is response error need to check for every request.
After check error, i get error message 8, invalid token
When using development certificate, and there is user register using development application, they get device token
but when you change to production, you have to change production certificate and registered user need to get new device token to make PUSH notification work
because device token you get in development apps, will not work with production certificate..
it's totally my mistake to miss important things..

APNS Bulk Not delivering but works individually

Building from samplePush.php I have been able to build a transactional APNS script for my app. This works great and gives me the ability to one to one push notifications to a phone.
I need to move this to batch notifications and so built:
$APNSMessage = 'Test from APNS Bulk!';
// Bulk PUSH is the service designed to send iOS PUSH Notifications to hundreds of devices all at the same time using the same APNS connection.
function bulkPushToAPNS($TokenArray, $MessageToPush) {
echo "Sending to " . count($TokenArray) . " Devices ";
$body = array('aps' => array('alert' => $MessageToPush, 'badge' => 1, 'sound' => 'default'));
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'apnsCert.pem');
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
print "Failed to connect $token $err $errstrn";
return;
}
print "Connection OK ";
$payload = json_encode($body);
foreach($TokenArray as $token) {
$msg = chr(0) . chr(0) . pack("n",32) . pack('H*', str_replace(' ', '', $token)) . pack("n",strlen($payload)) . $payload;
print $payload;
//fwrite($fp, $msg);
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
}
fclose($fp);
}
$TokensToPushToArray = array('ThisIsTokenOne', 'ThisIsTokenTwo');
bulkPushToAPNS($TokensToPushToArray, $APNSMessage);
When the script runs it gets passed an array of iOS tokens that need this message.
The output of the script is:
Sending to 2 Devices Connection OK {"aps":{"alert":"Test from APNS Bulk!","badge":1,"sound":"default"}}Message successfully delivered {"aps":{"alert":"Test from APNS Bulk!","badge":1,"sound":"default"}}Message successfully delivered
So the feedback from Apple is that these are getting delivered. But nothing is making it to the handhelds.
If I run each device token individually they work, so its something in the batch thats playing up..? Any ideas?
Answering my own question here;
Moved the code around so that the foreach is inside the connection:
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'apnsCert.pem');
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
foreach ($APNSTokens as $APNSToken) {
// Create the payload body
$body['aps'] = array(
'alert' => $APNSMessage,
'sound' => 'default',
'badge' => 1
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $APNSToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
}
// Close the connection to the server
fclose($fp);
Now the connection is still live and runs until the foreach is complete.
Tested and working.

Sending multiple iPhone push notifications + APNS + PHP

I am working on a PHP website + iPhone application and API for iPhone application, has a messaging system for students and doctors, when any one sends message (from website or iPhone) the other user should get push notification on his iphone. For example if student adds a new question for teacher, a push notification on teachers iPhone/iPad will be send to teacher and when teacher replies to student's answer, student will get a push notification.
Since there is no restriction on number of teachers and student registering to website, my question is how to send push messages to registered user's iPhone? I want to send push message as soon as someone replies or adds a question. Please provide me PHP code for sending multiple push messages.
I am saving device token for each user while registration.
When teacher reply to question I am sending mail to student, I want to send a push notification too to student and vice versa so please specify code able to manage error conditions.
Simple way to do it without use any file. You can call it multiple times with different tokeid.
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ckipad.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195',
$err,
$errstr,
60,
STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT,
$ctx);
//if (!$fp)
//exit("Failed to connect amarnew: $err $errstr" . PHP_EOL);
//echo 'Connected to APNS' . PHP_EOL;
// Create the payload body
$body['aps'] = array(
'badge' => +1,
'alert' => $message,
'sound' => 'default'
);
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered amar'.$message. PHP_EOL;
// Close the connection to the server
fclose($fp);
You should better use APNS library for PHP. You can find it here. Look through samples that developers provide.
I also had problems with certificates. My actions were:
locate file ApnsPHP/Abstract.php
make some changes to _connect() method, paste this lines
$streamContext = stream_context_create(
array(
'ssl' => array(
'local_cert' => $this->_sProviderCertificateFile,
'passphrase' => ''
)
)
);
$this->_hSocket = #stream_socket_client(
$sURL,
$nError,
$sError,
$this->_nConnectTimeout,
STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT,
$streamContext);
instead of original listed there
now you can use *.pem certificates without need of entrust_root_certification_authority.
This worked fine for me.
This is the way I have done it finally
Downloaded apns-php
PHP Code
set_time_limit(0);
$root_path = "add your root path here";
require_once($root_path."webroot\cron\library\config.php");
require_once($root_path."Vendor\ApnsPHP\Autoload.php");
global $obj_basic;
// Basic settings
$timezone = new DateTimeZone('America/New_York');
$date = new DateTime();
$date->setTimezone($timezone);
$time = $date->format('H:i:s');
//Get notifications data to send push notifications
$queueQuery = " SELECT `notifications`.*, `messages`.`mes_message`, `messages`.`user_id`, `messages`.`mes_originated_from` FROM `notifications`
INNER JOIN `messages`
ON `notifications`.`message_id` = `messages`.`mes_id`
WHERE `notifications`.`created` <= NOW()";
$queueData = $obj_basic->get_query_data($queueQuery);
if(!empty($queueData)) {
// Put your private key's passphrase here:
$passphrase = 'Push';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'server_certificates_bundle_sandbox.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo '<br>'.date("Y-m-d H:i:s").' Connected to APNS' . PHP_EOL;
foreach($queueData as $val) {
// Put your device token here (without spaces):
$deviceToken = $val['device_token'];
// Create message
// Get senders name
$sql = "SELECT `name` FROM `users` WHERE id =".$val['user_id'];
$name = $obj_basic->get_query_data($sql);
$name = $name[0]['name'];
$message = $name." : ";
// Get total unread messaged for receiver
$query = "SELECT COUNT(*) as count FROM `messages` WHERE mes_parent = 0 AND user_id = ".$val['user_id']." AND mes_readstatus_doc != 0 AND mes_status = 1";
$totalUnread = $obj_basic->get_query_data($query);
$totalUnread = $totalUnread[0]['count'];
$message .= " This is a test message.";
// Create the payload body
$body['aps'] = array(
'alert' => $message,
'badge' => $totalUnread,
'sound' => 'default'
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
if (!$result) {
echo '<br>'.date("Y-m-d H:i:s").' Message not delivered' . PHP_EOL;
} else {
$sqlDelete = "DELETE FROM `notifications` WHERE id = ".$val['id'];
$query_delete = $obj_basic->run_query($sqlDelete,'DELETE');
echo '<br>'.date("Y-m-d H:i:s").' Message successfully delivered' . PHP_EOL;
}
}
// Close the connection to the server
fclose($fp);
echo '<br>'.date("Y-m-d H:i:s").' Connection closed to APNS' . PHP_EOL;
} else {
echo '<br>'.date("Y-m-d H:i:s").' Queue is empty!';
}

Iphone Push Notification Wrong Device Token

Finally,I found out the sandbox tokens,which were mixed with the production tokens,and I update the code,receive the error response from apple,when post a sandbox token to apple,the next tokens all failed....While the push msg was "$payload['aps'] = array('content-available' => 1); ",apple will push the msg ,but the device will not show this msg,when I find the wrong one,I delete it,and retest.
There is an amusing problem of apple push notification service:
when I generate a post notification for my device and send to apple's server,for a while,my device will receive the notification.
But if I first post a notification by a wrong devicetoken,then post a right notification to my device,my device will be responseless,just like the push notification was eaten by apple?
What wrong with this?
I use php code for push service,here is the most important part:
$payload['aps'] = array('content-available' => 1);
while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
foreach ($line as $deviceToken) {
break;
}
print_r($deviceToken);
$apnsMessage = chr(1) . $time . $time . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
$ret = fwrite($apns, $apnsMessage);
if ($ret !== strlen($apnsMessage)) {
echo "push error";
}
ob_flush();
flush();
$read = array($apns);
$null = null;
$changedStreams = stream_select($read, $null, $null, 0, 100000);//wait for 0.1s
if ($changedStreams === false) {
echo "Error: Unabled to wait for a stream availability";
} elseif ($changedStreams > 0) {
print "can't receive any notification behind this token";
$responseBinary = fread($apns, 6);
if ($responseBinary !== false || strlen($responseBinary) == 6) {
$response = unpack('Ccommand/Cstatus_code/Nidentifier', $responseBinary);
print_r($response);
}
} else {
//update the success push status in database
}
print "<br>";
}
I dont know what's wrong with this,and I have also add feedback service in another php,and get none wrong token from apple,Because I have many devicetoken in my database,I cant find which one of them is wrong.
Someone help me,forgive my poor english
Assuming your $apns is implemented in this way
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2,STREAM_CLIENT_CONNECT, $streamContext);
you should check the $errorString to find out the error.
or try to close the socket for each message and see if there is any difference
fwrite($apns, $apnsMessage);
socket_close($apns);
fclose($apns);

Categories