APNS SSL操作失败,代码为1

Mar*_*ina 10 php push-notification apple-push-notifications apns-php

编辑 - 使用增强的二进制格式

结果我没有使用增强的二进制格式,所以我改变了我的代码.

<?php

$message = $_POST['message'];
$passphrase = $_POST['pass'];

//Connect to db


if ($db_found) {

// Create the payload body
$body['aps'] = array(
    'alert' => $message,
    'sound' => 'default'
);

$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', 'x.pem');
stream_context_set_option($streamContext, 'ssl', 'passphrase', $passphrase);

$fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $error, $errorString, 15, STREAM_CLIENT_CONNECT, $streamContext);
stream_set_blocking ($fp, 0); 

if (!$fp)
    exit("Failed to connect: $err $errstr" . PHP_EOL);

echo 'Connected to APNS for Push Notification' . PHP_EOL;

// Keep push alive (waiting for delivery) for 90 days
$apple_expiry = time() + (90 * 24 * 60 * 60);



$tokenResult = //SQL QUERY TO GET TOKENS

while($row = mysql_fetch_array($tokenResult)) {
    $apple_identifier = $row["id"];
    $deviceToken = $row['device_id'];
    $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.
// 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
usleep(500000); 

checkAppleErrorResponse($fp);

echo 'Completed';

fclose($fp);


// SIMPLE BINARY FORMAT
/*for($i = 0; $i<count($deviceToken); $i++) {

    // Encode the payload as JSON
    $payload = json_encode($body);

    // Build the binary notification
    $msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken[$i]) . pack('n', strlen($payload)) . $payload;

    // Send it to the server
    $result = fwrite($fp, $msg, strlen($msg));

    $bodyError .= 'result: '.$result.', devicetoken: '.$deviceToken[$i].'';

    if (!$result) {
        $errCounter = $errCounter + 1;
        echo 'Message not delivered' . PHP_EOL;
    }
    else
        echo 'Message successfully delivered' . PHP_EOL;
}*/


// Close the connection to the server
//fclose($fp);


//Insert message into database

mysql_close($db_handle);

}

else {

    print "Database niet gevonden ";
    mysql_close($db_handle);
}

// 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>&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;
}

?>
Run Code Online (Sandbox Code Playgroud)

使用这个新代码时,由于此错误,我仍然无法发送超过300条消息:

Warning: fwrite() [function.fwrite]: SSL operation failed with code 1. OpenSSL Error messages: error:1409F07F:SSL routines:SSL3_WRITE_PENDING:bad write retry in PATH_TO_SCRIPT.php on line NUMBER
Run Code Online (Sandbox Code Playgroud)

发送一些推送消息时,此代码工作正常.

具有简单二进制格式的旧问题 所以我很久以前就集成了推送通知,它对发送给少于500人的消息工作正常.现在我正在尝试向超过1000人发送推送通知,但后来我得到了错误的错误

Warning: fwrite() [function.fwrite]: SSL: Broken pipe in PATH_TO.PHP on line x
Run Code Online (Sandbox Code Playgroud)

我已经阅读了苹果文档,我知道无效的令牌会导致套接字断开连接.一些在线解决方案建议检测断开连接和重新连接,如下所示:

Your server needs to detect disconnections and reconnect if necessary. Nothing is
"instant" when networking is involved; there's always some latency and code needs to take
that into account. Also, consider using the enhanced binary interface so you can check the
return response and know why the connection was dropped. The connection can also be
dropped as a result of TCP keep-alive, which is outside of Apple's control.
Run Code Online (Sandbox Code Playgroud)

我还运行一个反馈服务,它检测无效令牌(想要推送通知但删除了应用程序的用户)并且运行正常.那个php脚本回显了已删除的ID,我可以确认这些令牌是从我们的MySQL数据库中删除的.

我怎样才能检测到断开或损坏的管道并对此作出反应,以便我的推送通知可以达到1000多人?

目前我正在使用这个简单的push.php脚本.

<?php

 $message = $_POST['message'];
 $passphrase = $_POST['pass'];

 //Connect to database stuff

 if ($db_found) {
      $streamContext = stream_context_create();
      stream_context_set_option($streamContext, 'ssl', 'local_cert', 'x.pem');
      stream_context_set_option($streamContext, 'ssl', 'passphrase', $passphrase);

      $fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $error, $errorString, 15, STREAM_CLIENT_CONNECT, $streamContext);

 if (!$fp)
    exit("Failed to connect: $err $errstr" . PHP_EOL);

 echo 'Connected to APNS for Push Notification' . PHP_EOL;

 $deviceToken[] = //GET ALL TOKENS FROM DATABASE AND STORE IN ARRAY

for($i = 0; $i<count($deviceToken); $i++) {
    // Create the payload body
    $body['aps'] = array(
    'alert' => $message,
    'sound' => 'default'
    );

    // Encode the payload as JSON
    $payload = json_encode($body);

    // Build the binary notification
    $msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken[$i]) . pack('n', strlen($payload)) . $payload;

    // Send it to the server
    $result = fwrite($fp, $msg, strlen($msg));

    $bodyError .= 'result: '.$result.', devicetoken: '.$deviceToken[$i].'';

    if (!$result) {
        $errCounter = $errCounter + 1;
        echo 'Message not delivered' . PHP_EOL;
    }
    else
        echo 'Message successfully delivered' . PHP_EOL;
}


echo $bodyError;

// Close the connection to the server
fclose($fp);


//CODE TO SAVE MESSAGE TO DATABSE HERE

if (!mysql_query($SQL,$db_handle)) { 
    die('Error: ' . mysql_error()); 
}

}
 else {
     print "Database niet gevonden ";
     mysql_close($db_handle);
 }


 ?>
Run Code Online (Sandbox Code Playgroud)

当SLL Broken Pipe错误发生时,fwrite也会返回0个写入的字节.

我还必须提到,我不是PHP或Web开发人员,而是应用程序开发人员所以我的PHP技能不是那么好.

Lom*_*baX 4

当你这样做时:

fwrite($fp, $msg);
Run Code Online (Sandbox Code Playgroud)

您正在尝试写入套接字。如果出现问题,fwrite 将返回false或 0(取决于 php 版本)作为返回值。当它发生时,你必须管理它。你有两种可能性:

  • 放弃整个操作
  • 重试上次的写入操作

如果您选择第二个选项,则必须使用fwrite($fp, $msg)失败操作的相同 $fp 和 $msg执行新操作fwrite()。如果更改参数,1409F07F:SSL则会返回错误

此外,在某些情况下,fwrite 只能写入“一些字节”,您甚至应该管理这种情况,将返回值与 $msg 的长度进行比较。在这种情况下,您应该发送消息的剩余部分,但在某些情况下,您必须再次发送整个消息(根据此链接)。

看看 fwrite 参考和评论:链接