PHP Apple 增强型推送通知读取错误响应
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10058768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP Apple Enhanced Push Notification read error response
提问by jsherk
In PHP, how do you use fread() to check if there is an error response when sending enhanced push notifications?
在PHP中,如何使用fread()来检查发送增强推送通知时是否有错误响应?
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.
我已经阅读了 Apple 文档、通过 Google 发布的一些模糊帖子,以及关于 SO 的几个问题/答案,但这仍然非常令人困惑。
Here is what I looked at: http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.htmlReading error from Apple enhanced push notification with PHPiPhone Push Notification - Error response problem
这是我查看的内容:http: //developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.html从 Apple 增强推送通知中读取错误,使用 PHP iPhone 推送通知 - 错误响应问题
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: http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/
我将在下面回答我自己的问题,基于以下事实:(1)我发现这是一个非常令人困惑的话题,并且(2)我必须通过大量的反复试验将信息拼凑在一起才能使其正常工作,和 (3) 这篇博文表示鼓励:http: //blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/
回答by jsherk
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.
如果出现问题,Apple 会断开与您的连接,但您并不知道。当您使用基本通知时,无法知道它们是否全部发送。解决方案:这就是使用增强通知然后检查错误响应的全部意义所在。请注意,我们将在数据库查询中使用“ORDER BY id”,然后使用该 id 作为我们在通知中发送的标识符。这样,如果出现问题,我们就可以确切地知道数据库中的哪一行导致了问题(因此我们知道 Apple 何时断开了我们的连接并停止发送通知)。然后我们可以继续向导致问题的行之后的所有行发送推送通知,而不必重新发送到我们已经发送到的行。
如果一切正常,Apple 不会发送任何响应,因此这可能导致您的脚本暂停并永远等待 fread() 等待未到来的数据。解决方案:需要将 stream_set_blocking 设置为 0,以便 fread 总是立即返回。请注意,这会导致 fread 可以在收到错误响应之前返回的另一个小问题,但请参阅代码中的解决方法,即在所有发送完成后暂停 1/2 秒,然后再次检查 fread .
您可以发送多个推送通知的速度比收到错误响应的速度要快得多。解决方案:这也是上面提到的相同解决方法......在所有发送完成后暂停 1/2 秒,然后再检查一次 fread。
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 的解决方案,它解决了我遇到的所有问题。它非常基本,但可以完成工作。我已经通过一次发送一些通知以及一次发送 120,000 个通知来测试它。
<?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;
}
?>
回答by Baba
Am not sure the content of you code but you should try ApnsPHPit is well tested works perfectly fine and it able to handle all possible exception and error for you.
我不确定您的代码内容,但您应该尝试ApnsPHP,它经过充分测试,运行良好,并且能够为您处理所有可能的异常和错误。
Other Alternatives
其他替代品
https://github.com/sebastianborggrewe/PHP-Apple-Push-Notification-Serverhttps://github.com/bortuzar/PHP-Mysql---Apple-Push-Notification-Server
https://github.com/sebastianborggrewe/PHP-Apple-Push-Notification-Serverhttps://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.
已经测试了 3 个 i 示例中的 2 个,并且没有实现和错误管理的问题。
Thanks
谢谢
:)
:)

