当前位置: 首页 > 面试题库 >

PHP Apple增强的推送通知读取错误响应

任绪
2023-03-14
问题内容

在PHP中,发送增强的推送通知时,如何使用fread()检查是否有错误响应?

我已经阅读了Apple文档,在Google上发表了一些模糊的帖子,在SO上有一些疑问/答案,但这仍然很令人困惑。


问题答案:

发送推送通知时,存在几个问题:

  • 如果有问题,Apple会断开与您的连接,但您对此一无所知。使用基本通知时,无法知道是否已全部发送。 解决方案: 这是使用增强的通知,然后检查错误响应的全部内容。请注意,我们将在数据库查询中使用“ ORDER BY id”,然后将其用作通知中发送的标识符。这样,如果出现问题,我们可以确切地知道数据库中的哪一行导致了问题(因此我们知道苹果何时断开我们的连接并停止发送通知)。然后,我们可以继续向导致问题的行之后的所有行发送“推送”通知,而不必重新发送到我们已经发送到的通知。

  • 如果一切正常,Apple不会发回任何响应,因此这可能导致脚本暂停并在fread()等待即将到来的数据时永远等待。 解决方案: 需要将stream_set_blocking设置为0,以便fread总是立即返回。请注意,这会导致另一个次要问题,即fread可以在收到错误响应之前返回,但是请参见代码中的解决方法,该方法只是在完成所有发送之后暂停1/2秒,然后再次检查fread 。

  • 您发送多个推送通知的速度比错误回复要快得多。 解决方案: 同样,这是上述相同的解决方法…在完成所有发送后,暂停1/2秒,然后再检查一次。

这是我使用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>&nbsp;&nbsp;&nbsp;Identifier:<b>' . $error_response['identifier'] . '</b>&nbsp;&nbsp;&nbsp;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;
}
?>


 类似资料:
  • 我用push notification与解析服务器连接了应用程序,但问题是我遇到了错误,它说:registerforRemotenotification类型在IOS 8.0版本中不推荐使用:请使用register for remote notification和register user notification设置。但这段代码是针对iOS8的。 有谁能帮我找到正确的代码吗?

  • 使用Phonegap推送通知,如下所示 http://devgirl.org/2013/07/17/tutorial-implement-push-notifications-in-your-phoneGap-application/ 在使用.apk构建.apk时,我得到了这个错误.. 失败 失败:生成失败,出现异常。 出了什么问题: null 总时间:15.085秒 错误:带有args:/s,/

  • 首先,我想声明我一直在研究推送通知和web通知之间的关系,但我有点困惑。 我从这里读到PWAs的推送通知在Safari上的iOS(iPhone)不起作用:从PWA向iOS发送推送通知 然而,如果iPhone用户使用的是Chrome,这是否意味着它们可以工作呢?或者推送通知在任何浏览器上对iPhone中的PWAs都不起作用? 这就把我带到了web通知。web通知在后台对PWAs起作用吗?我的问题是w

  • 我无法发送通知 {“多播id”:2200169071930988341,“成功”:0,“失败”:1,“规范id”:0,“结果”:[{“错误”:“无效注册”}]

  • 我正在尝试获取关于我在电子邮件中收到的所有新收件箱邮件的推送通知。我已经配置了pubsub文档中提到的pubsub客户端。以下是代码: 当我运行上述程序时,我遇到以下错误: 回溯(最后一次调用):文件“/home/kmittal/workspace/engine/workers/newPubSubClient.py”,第82行,正在使用中。用户()。监视(userId='me',body=requ

  • 通过上面的行,我得到了一个URL,它将在大约一个月内有用。 现在我不可能做的是将推送通知发送到应用程序。 任何关于如何使用Uri和如何将信息发送到它的光我会很高兴,因为我的400错误,那是关于我的post消息的一些错误。 我可以在发布或调试模式下获得推送通知吗? 使用PHP可以完成带有正确Uri的推送通知吗?