We manage a push notifications for both platforms iOS and Android. The procedure for Android is well, the device has been registered to GCM and the notifications are received. The problem is with APNS for iOS, the notifications are not received! even the device had been registered correctly and APNS generated a token for the device.
Below are the Javascript for receiving push and PHP code for sending messages.
Javascript code for receiving push:
var pushNotification;
document.addEventListener("deviceready", onDeviceReadyEvent, false);
function onDeviceReadyEvent(){
pushNotification = window.plugins.pushNotification;
var sk_deviceplatform = device.platform;
sk_deviceplatform = sk_deviceplatform.toLowerCase();
if(sk_deviceplatform === 'android'){
pushNotification.register(successHandler, errorHandler, {"senderID":"XXXXXXXXX","ecb":"onNotificationGCM"});
} else {
pushNotification.register(tokenHandler, errorHandler, {"badge":"true","sound":"true","alert":"true","ecb":"onNotificationAPN"});
}
}
function tokenHandler(result) {
console.log("Token: " + result);
alert("Token: "+ result);
}
function errorHandler(error) {
console.log("Error: " + error);
alert('Error:' + error);
}
function onNotificationAPNS(e){
if(e.alert.title) {
$.mobile.changePage( "handle_notifications.html?id="+e.eventid, { transition: "slide"} );
}
if(e.sound) {
var skpn_snd = new Media(e.sound);
skpn_snd.play();
}
if (e.badge) {
pushNotification.setApplicationIconBadgeNumber(successHandler, errorHandler, e.badge);
}
if (e.foreground===0){
// when application is not active
}else{
navigator.notification.alert(e.alert.title, null, 'News Notification', 'OK');
}
}
PHP code for sending push:
/*** PUSH NOTIFICATION FOR IOS VIA APNS ***/
set_time_limit(0);
// charset header for output
header('content-type: text/html; charset: utf-8');
$deviceIds = array(/* get all devices token ids from the database */);
if(count($deviceIds)>0){
// this is where you can customize your notification
$body['aps'] = array(
'badge' => +1,
'alert' => "News Event!",
'sound' => 'default'
);
$payload = json_encode($body);
////////////////////////////////////////////////////////////////////////////////
// start to create connection
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', "XXXX.pem");
stream_context_set_option($ctx, 'ssl', 'passphrase', "XXXXXXX");
foreach ($deviceIds as $item_device) {
// Open a connection to the APNS server
$fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx);
if(!$fp){ exit("Failed to connect: $err $errstr" . '<br />');}else{/* service online */}
// Build the binary notification
$msg_notification = chr(0) . pack('n', 32) . pack('H*', $item_device) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg_notification, strlen($msg_notification));
if (!$result) { echo 'Undelivered message count: ' . $item_device . '<br />';}
else { /* notifications are sent */ }
if ($fp){
## check for errors
$apple_error_response = fread($fp, 6); //byte1=always 8, byte2=StatusCode, bytes3,4,5,6=identifier(rowID). Should return nothing if OK.
//NOTE: Make sure you set stream_set_blocking($fp, 0) or else fread will pause your script and wait forever when there is no response to be sent.
if ($apple_error_response) {
$error_response = unpack('Ccommand/Cstatus_code/Nidentifier', $apple_error_response); //unpack the error response (first byte 'command" should always be 8)
if ($error_response['status_code'] == '0') {
$error_response['status_code'] = '0-No errors encountered';
} else if ($error_response['status_code'] == '1') {
$error_response['status_code'] = '1-Processing error';
} else if ($error_response['status_code'] == '2') {
$error_response['status_code'] = '2-Missing device token';
} else if ($error_response['status_code'] == '3') {
$error_response['status_code'] = '3-Missing topic';
} else if ($error_response['status_code'] == '4') {
$error_response['status_code'] = '4-Missing payload';
} else if ($error_response['status_code'] == '5') {
$error_response['status_code'] = '5-Invalid token size';
} else if ($error_response['status_code'] == '6') {
$error_response['status_code'] = '6-Invalid topic size';
} else if ($error_response['status_code'] == '7') {
$error_response['status_code'] = '7-Invalid payload size';
} else if ($error_response['status_code'] == '8') {
$error_response['status_code'] = '8-Invalid token';
} else if ($error_response['status_code'] == '255') {
$error_response['status_code'] = '255-None (unknown)';
} else {
$error_response['status_code'] = $error_response['status_code'].'-Not listed';
}
echo '<br><b>ERROR</b> Response Command:<b>' . $error_response['command'] . '</b> Identifier:<b>' . $error_response['identifier'] . '</b> Status:<b>' . $error_response['status_code'] . '</b><br>';
echo 'Identifier is the rowID (index) in the database that caused the problem, and Apple will disconnect you from server. To continue sending Push Notifications, just start at the next rowID after this Identifier.<br>';
}
fclose($fp);
$_ENV['connection_status'] = 'The connection has been closed by the client' . '<br />';
}
}
set_time_limit(30);
}
When we send a message, there is no errors and every think is well, but the push notifications are not received.
The problem is either inside the PHP script or with the apache cordova script...
Thank you for your suggestions...
You forgot to install these two cordova plugins.
https://github.com/apache/cordova-plugin-device
https://github.com/apache/cordova-plugin-console
Because these two, you can't detect your device type and console your output.
We had found the problem...We tried to send push via APNS with development certificate using the production connection server.
For production, use the connection below:
ssl://gateway.push.apple.com:2195
For development, use the connection below:
ssl://gateway.sandbox.push.apple.com:2195
Related
I have a PHP script that sends push notifications to an Apple APNS server.
It is supposed to echo the response code 485, which shows that the message was successfully sent. However, when I run the code, it shows a different numeric code each time, and the message is not sent.
Here is the code:
$payload = array(
'aps' => array(
'alert' => $message,
'T_ID' => $data["trip_id"],
'S' => $state,
'Api' => 2,
'sound' => 'default'
));
$body = array();
$body['aps'] = array('alert' => "request trip");
$body['aps']['notifurl'] = $payload;
$body['aps']['badge'] = 2;
$payload = json_encode($body);
$ret = array(
"error" => 0
);
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', dirname(BASEPATH) . "/uploads/" . $this->_apnsCert);
stream_context_set_option($streamContext, 'ssl', 'passphrase', $this->_passphrase);
#$apns = stream_socket_client('tls://' . $this->_apnsHost . ':' . $this->_apnsPort, $error, $errorString, 200, STREAM_CLIENT_CONNECT, $streamContext);
if (!$apns) {
//die('Error creating ssl socket ' . $error . ' ' . $errorString);
$ret["error"] = 1;
$ret["details"] = 'Error creating ssl socket ' . $error . ' ' . $errorString;
}
$apnsMessage = // Command "1"
chr(1)
// Identifier "88"
. pack('N', 88)
// Expiry "tomorrow"
. pack('N', time() + 86400)
// Token length
. chr(0) . chr(32)
// Device token
. pack('H*', str_replace(' ', '', $deviceToken))
// Payload length
. chr(0) . chr(strlen($payload))
// Actual payload
. $payload . $payload;
echo fwrite($apns, $apnsMessage);
fclose($apns);
Why is this not working as expected?
I see at least 2 errors in the code:
1) the original value in $payload is overwritten when you encode the message body with json_encode($body), although this is likely not the final culprit
2) you're echoing the result from the fwrite, when you should be reading the response from the stream and echoing that.
See the example at Working with Apple Push Notification to understand how to handle the return values. The following code is derived from there:
// FUNCTION to check if there is an error response from Apple
// Returns TRUE if there was and FALSE if there was not
function checkAppleErrorResponse($fp) {
//byte1=always 8, byte2=StatusCode, bytes3,4,5,6=identifier(rowID).
// Should return nothing if OK.
//NOTE: Make sure you set stream_set_blocking($fp, 0) or else fread will pause your script and wait
// forever when there is no response to be sent.
$apple_error_response = fread($fp, 6);
if ($apple_error_response) {
// unpack the error response (first byte 'command" should always be 8)
$error_response = unpack('Ccommand/Cstatus_code/Nidentifier', $apple_error_response);
if ($error_response['status_code'] == '0') {
$error_response['status_code'] = '0-No errors encountered';
} else if ($error_response['status_code'] == '1') {
$error_response['status_code'] = '1-Processing error';
} else if ($error_response['status_code'] == '2') {
$error_response['status_code'] = '2-Missing device token';
} else if ($error_response['status_code'] == '3') {
$error_response['status_code'] = '3-Missing topic';
} else if ($error_response['status_code'] == '4') {
$error_response['status_code'] = '4-Missing payload';
} else if ($error_response['status_code'] == '5') {
$error_response['status_code'] = '5-Invalid token size';
} else if ($error_response['status_code'] == '6') {
$error_response['status_code'] = '6-Invalid topic size';
} else if ($error_response['status_code'] == '7') {
$error_response['status_code'] = '7-Invalid payload size';
} else if ($error_response['status_code'] == '8') {
$error_response['status_code'] = '8-Invalid token';
} else if ($error_response['status_code'] == '255') {
$error_response['status_code'] = '255-None (unknown)';
} else {
$error_response['status_code'] = $error_response['status_code'].'-Not listed';
}
echo '<br><b>+ + + + + + ERROR</b> Response Command:<b>' . $error_response['command'] . '</b> Identifier:<b>' . $error_response['identifier'] . '</b> Status:<b>' . $error_response['status_code'] . '</b><br>';
echo 'Identifier is the rowID (index) in the database that caused the problem, and Apple will disconnect you from server. To continue sending Push Notifications, just start at the next rowID after this Identifier.<br>';
return true;
}
return false;
}
Note that the example recommends that you make sure to set the stream to non-blocking mode with stream_set_blocking($fp, 0) before reading from it, but that's only necessary if you want to do any interim error checking; your code example does not do this, so it may not be an issue for you.
I'm trying to implement the APNS (Push notification).
I've created the certificates, etc.. everything was created like iv'e done many many times.
but i cant get an error from apple APNS server and it seems that everything is ok but i still not getting any push in the devices.
this is the PHP code I'm using to make the magic :)
I ensure that the PORTS are open in the hosting.
basically I'm getting the user token from the DB and sending the push text with default sound.
can someone please look and tell me if you can see any problem in this code or let me know how can i get the real result of the process / response from APNS Server?
<?php
error_reporting(0);
header("Content-type: application/json; charset=utf-8");
include "dbconn.php";
$data = array();
$json= array();
$users = array();
$opponent_id = $_REQUEST['opponent_id'];
$sender_id = $_REQUEST['sender_id'];
$message = $_REQUEST['message'];
$sql = "SELECT * FROM `registration` WHERE `chat_id` ='$opponent_id'";
$result = mysql_query($sql);
if (!$result) {
echo "Could not successfully run query ($sql) from DB: " . mysql_error();
exit;
}
if (mysql_num_rows($result) == 0) {
echo "No rows found, nothing to print so am exiting";
exit;
}
while ($row = mysql_fetch_assoc($result)) {
$token = $row['token'];
}
echo "\n$token";
$passphrase = 'certificate_password';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
//stream_context_set_option($ctx, 'ssl', 'local_cert','push/some_prod_certificate.pem');
stream_context_set_option($ctx, 'ssl', 'local_cert','push/some_dev_certificate.pem');
stream_context_set_option($ctx, 'ssl', 'cafile', 'push/entrust_root_certification_authority.pem');
# Open a connection to the APNS server
$fp = stream_socket_client(//'ssl://gateway.push.apple.com:2195', $err,
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp){
echo "Error: ".$err;
exit;
}
echo "\n".'Connected to APNS Push Notification' . PHP_EOL;
$body['aps'] = array(
'alert' => $message,
'sound' => 'default'
);
$payload = json_encode($body);
echo "\n$payload";
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $token) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
//set blocking
stream_set_blocking($fp,0);
//Check response
checkAppleErrorResponse($fp);
// Close the connection to the server
fclose($fp);
function checkAppleErrorResponse($fp) {
$apple_error_response = fread($fp, 6); //byte1=always 8, byte2=StatusCode, bytes3,4,5,6=identifier(rowID). Should return nothing if OK.
//NOTE: Make sure you set stream_set_blocking($fp, 0) or else fread will pause your script and wait forever when there is no response to be sent.
if ($apple_error_response) {
$error_response = unpack('Ccommand/Cstatus_code/Nidentifier', $apple_error_response); //unpack the error response (first byte 'command" should always be 8)
if ($error_response['status_code'] == '0') {
$error_response['status_code'] = '0-No errors encountered';
} else if ($error_response['status_code'] == '1') {
$error_response['status_code'] = '1-Processing error';
} else if ($error_response['status_code'] == '2') {
$error_response['status_code'] = '2-Missing device token';
} else if ($error_response['status_code'] == '3') {
$error_response['status_code'] = '3-Missing topic';
} else if ($error_response['status_code'] == '4') {
$error_response['status_code'] = '4-Missing payload';
} else if ($error_response['status_code'] == '5') {
$error_response['status_code'] = '5-Invalid token size';
} else if ($error_response['status_code'] == '6') {
$error_response['status_code'] = '6-Invalid topic size';
} else if ($error_response['status_code'] == '7') {
$error_response['status_code'] = '7-Invalid payload size';
} else if ($error_response['status_code'] == '8') {
$error_response['status_code'] = '8-Invalid token';
} else if ($error_response['status_code'] == '255') {
$error_response['status_code'] = '255-None (unknown)';
} else {
$error_response['status_code'] = $error_response['status_code'].'-Not listed';
}
echo '<br><b>+ + + + + + ERROR</b> Response Command:<b>' . $error_response['command'] . '</b> Identifier:<b>' . $error_response['identifier'] . '</b> Status:<b>' . $error_response['status_code'] . '</b><br>';
echo 'Identifier is the rowID (index) in the database that caused the problem, and Apple will disconnect you from server. To continue sending Push Notifications, just start at the next rowID after this Identifier.<br>';
return true;
}
echo "\nPush respnse OK";
return false;
}
?>
You can't get error responses from Apple because you are using the simple binary format that doesn't return error responses :
$msg = chr(0) . pack('n', 32) . pack('H*', $token) . pack('n', strlen($payload)) . $payload;
If you want a format that can returns an error response, you can use one of the enhanced formats.
For example, the format that starts with 1 :
The msg would start with chr(1), followed by 4 bytes of message ID, 4 bytes of expiration time and the rest of the message would be the same as what you have now pack('n', 32) . pack('H*', $token) . pack('n', strlen($payload)) . $payload
It should look like this :
$msg = chr(1) . pack("N", $msg_id) . pack("N", $expiry) . pack('n', 32) . pack('H*', $token) . pack('n', strlen($payload)) . $payload;
I created a push notification server for my apps. This server works fine on test and production. I created an API which can recieve a serialized array of device tokens.
This API is created in PHP, and the call to the API is PHP as well.
This is the array:
'devices' => serialize(array(
//'aaaaaa',
'bbbbb',
'ccccc'
)),
The real tokens are replaced by placeholders for security reasons, ofcourse.
I got one token that screws up the push notifications for the other tokens. When I disable this token in the array (aaaaa in this case), the other 2 devices receive the token. When I enable the aaaa token, no push notification is delivered at all.
The API side to send the actual push:
foreach($devices as $device) {
$msg = chr(0) . pack('n', 32) . pack('H*', $device) . pack('n', strlen($payload)) . $payload;
$result = fwrite($fp, $msg, strlen($msg));
}
Ofcourse there is some variable explaination missing in the code above, but this works fine in the case without token aaa, so that shouldnt be the problem.
Anyone knows why one faulty token can screw up pushes for valid tokens?
EDIT:
I now use the enhanced method for APNS, using this code:
$error = false;
foreach($devices as $deviceToken) {
$msg = pack("C", 1) . pack("N", $deviceToken) . pack("N", time() + 86400) . pack("n", 32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n", strlen($payload)) . $payload;
fwrite($fp, $msg);
$error = $this->checkAppleErrorResponse($fp);
debug($error);
}
And the checkAppleErrorResponse function:
function checkAppleErrorResponse($fp) {
$apple_error_response = fread($fp, 6);
if ($apple_error_response) {
$error_response = unpack('Ccommand/Cstatus_code/Nidentifier', $apple_error_response);
if ($error_response['status_code'] == '0') {
$error_response['status_code'] = '0-No errors encountered';
} else if ($error_response['status_code'] == '1') {
$error_response['status_code'] = '1-Processing error';
} else if ($error_response['status_code'] == '2') {
$error_response['status_code'] = '2-Missing device token';
} else if ($error_response['status_code'] == '3') {
$error_response['status_code'] = '3-Missing topic';
} else if ($error_response['status_code'] == '4') {
$error_response['status_code'] = '4-Missing payload';
} else if ($error_response['status_code'] == '5') {
$error_response['status_code'] = '5-Invalid token size';
} else if ($error_response['status_code'] == '6') {
$error_response['status_code'] = '6-Invalid topic size';
} else if ($error_response['status_code'] == '7') {
$error_response['status_code'] = '7-Invalid payload size';
} else if ($error_response['status_code'] == '8') {
$error_response['status_code'] = '8-Invalid token';
} else if ($error_response['status_code'] == '255') {
$error_response['status_code'] = '255-None (unknown)';
} else {
$error_response['status_code'] = $error_response['status_code'].'-Not listed';
}
echo 'Response Command:<b>' . $error_response['command'] . '</b> Identifier:<b>' . $error_response['identifier'] . '</b> Status:<b>' . $error_response['status_code'] . '</b><br>';
echo 'Identifier is the rowID (index) in the database that caused the problem, and Apple will disconnect you from server. To continue sending Push Notifications, just start at the next rowID after this Identifier.<br>';
return true;
}
return false;
}
Sending only the valid token, $numchanged is 0. Sending the invalid token and then the valid token, $numchanged is 1 for both cases.
You are using the simple binary format for sending push notifications to Apple (starts with a 0 byte). With this format, Apple never return any responses, but when the APNS server encounters a bad notification (often caused by invalid device token, but there are other error types, such as payload too long), it closes the connection. Any messages that were sent after the faulty one won't be processed by Apple. In that case you have to open a new connection and resend the other messages.
If you switch to the more advanced formats (that start with a 1 byte or a 2 byte), Apple will send you an error response before closing the connection, and if you manage to read that response, you'll know the type of the error (for example 8 means invalid token) and the identifier of the faulty message. This lets you know which message was faulty, and therefore tells you which messages need to be resent (all the ones following the faulty message).
Read more about it here and here.
When you use the enhanced format, make sure to give a unique message ID to each notification you send. That's the ID you'll get back from Apple in an error response, so it must be unique for you to be able to identify the invalid notification.
Following code alws works for me.
It will just ignore the faulty token as per my experience, it won't disturb other pushes beign sent to other valid tokens.
foreach ( $devices as $deviceToken ) {
$apnsMessage = chr ( 0 ) . chr ( 0 ) . chr ( 32 ) . pack ( 'H*', str_replace ( ' ', '', $deviceToken ) ) . chr ( 0 ) . chr ( strlen ( $payload ) ) . $payload;
if (fwrite ( $apns, $apnsMessage ) != FALSE) {
$cnt_apple ++;
}
}
echo "sent to $cnt_apple devices";
In PHP, how do you use fread() to check if there is an error response when sending enhanced push notifications?
I have read the Apple docs, a couple vague posts thru Google, and a couple questions/answers here on SO but this was still very confusing.
Here is what I looked at:
http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.html
Reading error from Apple enhanced push notification with PHP
iPhone Push Notification - Error response problem
I am going to answer my own question below, based on the fact that: (1) I found this a very confusing topic, and (2) I had to piece the information together with lots of trial and error to get it to work, and (3) this blog post that says it is encouraged: https://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/
When you send a push notification, there are several problems:
If there is a problem, Apple will disconnect you but you don't know about it. When you use basic notifications there is no way to know if they were all sent or not. SOLUTION: This is the whole point of using an enhanced notification and then checking for an error response. Note that we will use "ORDER BY id" in database query and then use the id as the identifier that we send in notification. This way, if there is a problem, we know exactly which row in the db caused the problem (and therefore we know when Apple disconnected us and stopped sending the notifications). We can then continue sending Push notifications to all the rows after the row that caused the problem, without having to resend to the ones we already sent to.
Apple does NOT send any response back if everything is ok, so this can cause your script to pause and wait forever while fread() is waiting for data that is not coming. SOLUTION: Need to set stream_set_blocking to 0 so that fread always returns right away. Note that this causes another minor issue that fread can return before it receives an error response, but see the workaround in the code, which is just to pause for 1/2 a second AFTER all your sending is done and then check fread one more time.
You can send multiple push notifications much faster than it takes an error response to get back to you. SOLUTION: Again this is the same workaround mentioned above... pause for 1/2 a second AFTER all your sending is done and then check fread one more time.
Here is my solution using PHP, which addresses all my problems that I encountered. Its pretty basic but gets the job done. I have tested it with sending a few notifications at a time as well as sending out 120,000 at one time.
<?php
/*
* Read Error Response when sending Apple Enhanced Push Notification
*
* This assumes your iOS devices have the proper code to add their device tokens
* to the db and also the proper code to receive push notifications when sent.
*
*/
//database
$host = "localhost";
$user = "my_db_username";
$pass = "my_db_password";
$dbname = "my_db_name";
$con = mysql_connect($host, $user, $pass);
if (!$con) {
die('Could not connect to database: ' . mysql_error());
} else {
mysql_select_db($dbname, $con);
}
// IMPORTANT: make sure you ORDER BY id column
$result = mysql_query("SELECT id,token FROM `device_tokens` ORDER BY id");
//Setup notification message
$body = array();
$body['aps'] = array('alert' => 'My push notification message!');
$body['aps']['notifurl'] = 'http://www.myexampledomain.com';
$body['aps']['badge'] = 1;
//Setup stream (connect to Apple Push Server)
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'passphrase', 'password_for_apns.pem_file');
stream_context_set_option($ctx, 'ssl', 'local_cert', 'apns.pem');
$fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
stream_set_blocking ($fp, 0); //This allows fread() to return right away when there are no errors. But it can also miss errors during last seconds of sending, as there is a delay before error is returned. Workaround is to pause briefly AFTER sending last notification, and then do one more fread() to see if anything else is there.
if (!$fp) {
//ERROR
echo "Failed to connect (stream_socket_client): $err $errstrn";
} else {
$apple_expiry = time() + (90 * 24 * 60 * 60); //Keep push alive (waiting for delivery) for 90 days
//Loop thru tokens from database
while($row = mysql_fetch_array($result)) {
$apple_identifier = $row["id"];
$deviceToken = $row["token"];
$payload = json_encode($body);
//Enhanced Notification
$msg = pack("C", 1) . pack("N", $apple_identifier) . pack("N", $apple_expiry) . pack("n", 32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n", strlen($payload)) . $payload;
//SEND PUSH
fwrite($fp, $msg);
//We can check if an error has been returned while we are sending, but we also need to check once more after we are done sending in case there was a delay with error response.
checkAppleErrorResponse($fp);
}
//Workaround to check if there were any errors during the last seconds of sending.
usleep(500000); //Pause for half a second. Note I tested this with up to a 5 minute pause, and the error message was still available to be retrieved
checkAppleErrorResponse($fp);
echo 'DONE!';
mysql_close($con);
fclose($fp);
}
//FUNCTION to check if there is an error response from Apple
// Returns TRUE if there was and FALSE if there was not
function checkAppleErrorResponse($fp) {
//byte1=always 8, byte2=StatusCode, bytes3,4,5,6=identifier(rowID). Should return nothing if OK.
$apple_error_response = fread($fp, 6);
//NOTE: Make sure you set stream_set_blocking($fp, 0) or else fread will pause your script and wait forever when there is no response to be sent.
if ($apple_error_response) {
//unpack the error response (first byte 'command" should always be 8)
$error_response = unpack('Ccommand/Cstatus_code/Nidentifier', $apple_error_response);
if ($error_response['status_code'] == '0') {
$error_response['status_code'] = '0-No errors encountered';
} else if ($error_response['status_code'] == '1') {
$error_response['status_code'] = '1-Processing error';
} else if ($error_response['status_code'] == '2') {
$error_response['status_code'] = '2-Missing device token';
} else if ($error_response['status_code'] == '3') {
$error_response['status_code'] = '3-Missing topic';
} else if ($error_response['status_code'] == '4') {
$error_response['status_code'] = '4-Missing payload';
} else if ($error_response['status_code'] == '5') {
$error_response['status_code'] = '5-Invalid token size';
} else if ($error_response['status_code'] == '6') {
$error_response['status_code'] = '6-Invalid topic size';
} else if ($error_response['status_code'] == '7') {
$error_response['status_code'] = '7-Invalid payload size';
} else if ($error_response['status_code'] == '8') {
$error_response['status_code'] = '8-Invalid token';
} else if ($error_response['status_code'] == '255') {
$error_response['status_code'] = '255-None (unknown)';
} else {
$error_response['status_code'] = $error_response['status_code'] . '-Not listed';
}
echo '<br><b>+ + + + + + ERROR</b> Response Command:<b>' . $error_response['command'] . '</b> Identifier:<b>' . $error_response['identifier'] . '</b> Status:<b>' . $error_response['status_code'] . '</b><br>';
echo 'Identifier is the rowID (index) in the database that caused the problem, and Apple will disconnect you from server. To continue sending Push Notifications, just start at the next rowID after this Identifier.<br>';
return true;
}
return false;
}
?>
Am not sure the content of you code but you should try ApnsPHP it is well tested works perfectly fine and it able to handle all possible exception and error for you.
Other Alternatives
https://github.com/sebastianborggrewe/PHP-Apple-Push-Notification-Server
https://github.com/bortuzar/PHP-Mysql---Apple-Push-Notification-Server
Have tested 2 out of the 3 i examples and did not have issue of implementation and error management.
Thanks
:)
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);