问题描述
最近几天,我们在使用套接字连接到生产服务器上的 APN 服务器时遇到了一些奇怪的 PHP 行为.
For the last few days, we are experiencing some strange behaviour with PHP when using sockets to connect to APN servers on our production server.
在大多数情况下,payload 的推送没有任何错误,客户端会收到通知.然而,在某些情况下,我们开始收到 PHP 错误(即使我们收到错误,有时也会推送通知).当我们开始看到这个错误时,它会持续几个小时然后消失,PHP 继续工作,就像什么也没发生一样.
For most of the times, the payload is pushed without any errors and the client receives the notification. However on some cases we start receiving a PHP error (even though we are receiving an error, sometimes the notification is pushed). When we start to see this error, it continues for hours then disappears and PHP continues to work like nothing has happened.
另一个奇怪的事情是,从 shell 运行相同的 PHP 代码不会产生任何错误.从 web (nginx/php-fpm) 运行它确实......在 shell 和 web 上运行的 PHP 具有相同的配置并共享相同的 php.ini.唯一的区别是 web 运行在 php-fpm 上.
Another strange thing is that, running the same PHP code from shell produces no errors whatsoever. Running it from web (nginx / php-fpm) does... PHP running on shell and web have the same configuration and share the same php.ini. The only difference is web is running on php-fpm.
此外,相同的代码 + 证书在我们的临时服务器上运行没有任何错误.生产服务器是临时服务器的副本,因此每个配置都相同.
Also, the same code + certificate runs on our staging server without any errors. Production server is a copy of the staging server, so every configuration is same.
我们能够找到可能导致此错误的原因的一些答案,包括来自 stackoverflow.com 的答案,但我们无法找到解决方案或解决它.
We were able to find a few answers to what might be causing this error, including answers from stackoverflow.com, but we were not able to find a solution or solve it.
发送到 Apple 服务器的通知是一个接一个地发送的,而不是一个包.但是我们并没有建立太多的联系(也许每天一千个).没有排队系统.
Notifications to Apple servers are sent one by one, and not as a bundle. But we are not making too many connections (a thousand a day maybe). There is no queue system.
所以,简而言之
- 我们有时会在发送通知时收到 PHP 错误,但并非总是如此.
- 通过相同的 PHP 从 shell 发送通知不会产生任何错误
- 从临时服务器发送通知不会产生任何错误
我们尝试了这些
- 重新创建证书和密钥
- 重新创建 PEM 文件
- 将 ssl://更改为 sslv3://
- 使用stream_socket_client
- 使用 fsockopen
- 更改/删除证书密码
错误是:
2012/08/28 12:18:09 [error] 4282#0: *225858 FastCGI sent in stderr:
"PHP message: PHP Warning: fwrite() [<a href='function.fwrite'>function.fwrite</a>]:
SSL operation failed with code 1. OpenSSL Error messages:
error:1409F07F:SSL routines:func(159):reason(127) in
/usr/local/nginx/html/play/classes/PushNotification.php on line 283"
while reading response header from upstream, client: 94.---.---.---,
server: play.--------.com, request: "POST /game_request_random.php HTTP/1.1",
upstream: "fastcgi://unix:/var/run/phpfpm.sock:",
host: "play.--------.com", referrer: "http://--------.com/"
从php连接和发送payload的代码实际上是一个类的一部分,这部分是建立连接和发送payload的部分:
The code connecting and sending the payload from the php is actually part of a class, this part is what makes the connection and sends the payload:
private function ConnectAndSend ( $msg = false ) {
$ctx = stream_context_create();
stream_context_set_option( $ctx, 'ssl', 'local_cert', $this->certificate );
stream_context_set_option( $ctx, 'ssl', 'passphrase', $this->certificatepass );
// Open a connection to the APNS server
$fp = stream_socket_client( APN_SERVER, $err, $errstr, 60, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx );
if ( !$fp ) {
errorlog( "Push notification error : $err $errstr" );
$this->error = "$err $errstr";
return;
}
// Build the notification
if ( !$msg ) {
$msg = chr( 0 ) . pack( 'n', 32 ) . pack( 'H*', $this->devicetoken ) . pack( 'n', strlen( $this->payload ) ) . $this->payload;
}
// Send it to the server
if ( !($result = fwrite( $fp, $msg, strlen( $msg ) )) ) {
// Could not send
$this->error = 'Notification could not be send';
errorlog( "Push notification error : {$this->error}" );
} else {
// Notification sent
$this->error = false;
errorlog( "Push notification sent" );
}
fclose($fp);
// Reset the content
$this->devicetoken = false;
$this->message = false;
$this->command = false;
$this->badge = 0;
$this->payload = false;
$this->sound = false;
}
- stream_socket_connection 是错误信息中出现的第 283 行
- 我们没有使用沙盒 (sslv3://gateway.push.apple.com:2195)
- PHP 版本为 5.3.15
这是我们不知道的 PHP 或 OpenSSL 错误吗?任何想法和在哪里检查?Apple 是否有网站可以让我们检查 APN 网络的当前健康状况?
Is this a PHP or OpenSSL bug that we don't know of? Any ideas what and where to check?Does Apple have a site where we can check the current health of the APN network?
非常感谢任何帮助...谢谢
Any help is greatly appreciated...Thanks
推荐答案
查看此代码以发送多条消息
Check out this code to send multiple messages
$i = 0;
while($res = mysql_fetch_array( $result )) {
$deviceTokens[$i] = $res['token'];
$i++;
}
// APNs Push testen auf Token
//$deviceToken = $token; // Hier das Device-Token angeben, ist 64-stellig
// Payload erstellen und JSON codieren
$message = $_POST['message'];
$message = utf8_encode($message);
$payload['aps'] = array('alert' => 'Neuer Artikel in Aktuelles', 'badge' => +1, 'sound' => 'default');
if (trim($message) != '') {
$payload['aps'] = array('alert' => "$message", 'badge' => 1, 'sound' => 'default');
}
$payload = json_encode($payload);
//Development: $apnsHost = 'gateway.sandbox.push.apple.com';
$apnsHost = 'gateway.push.apple.com';
$apnsPort = 2195;
//Development: $apnsCert = 'apsDevBundle.pem';
$apnsCert = 'apns-dev.pem';
// Stream erstellen
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
if ($error==0)
{
for($i = 0; $i<count($deviceTokens); $i++) {
// Build the binary notification
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceTokens[$i])) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
}
// Verbindung schliessen
fclose($apns);
}
else
{
var_dump($error);
var_dump($errorString);
die("Fehler aufgetreten.");
}
这篇关于Apple 推送通知 - PHP - SSL 操作失败,代码 1的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!