用PHP发送iOS推送通知

7

我正在开发一款使用iOS推送通知的iOS应用程序。我希望从我的服务器上的php脚本发送通知。我的应用程序中的代码非常好地实现了远程通知的注册和接收。我使用这个php脚本来发送通知,它也工作得很好:

<?php

// My device token here (without spaces):
$deviceToken = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

// My private key's passphrase here:
$passphrase = 'myPrivateKey';

// My alert message here:
$message = 'New Push Notification!';

//badge
$badge = 1;

$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);

// Open a connection to the APNS server
$fp = stream_socket_client(
    'ssl://gateway.sandbox.push.apple.com:2195', $err,
    $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);

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

echo 'Connected to APNS' . PHP_EOL;

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

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

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

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

if (!$result)
    echo 'Error, notification not sent' . PHP_EOL;
else
    echo 'notification sent!' . PHP_EOL;

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

我的问题是,如果我在我的iMac上通过终端运行此脚本,一切正常并且通知被发送,但是如果我将其上传到服务器上,则无法正常工作。我的证书是有效的,并且与脚本位于同一个文件夹中。当我尝试在服务器上运行脚本时,我会添加这行以包含证书文件并使用变量$certificate:
$certificate = file_get_contents('ck.pem');

这是php服务器端的错误:

Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Connection timed out) in script.php on line 29
Failed to connect: 110 Connection timed out

为什么会出现这种情况?我需要在服务器上添加一些内容才能启用pans连接吗?
-----更新问题-----
我的第一个问题是,我没有权限在端口2195上发送连接并在端口2196上接收响应。现在,我的服务器管理员已经启用了这些连接,但我遇到了不同的错误:
Warning: stream_socket_client() [function.stream-socket-client]: SSL operation failed with code 1. OpenSSL Error messages: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure in script.php on line 28

Warning: stream_socket_client() [function.stream-socket-client]: Failed to enable crypto in script.php on line 28

Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Unknown error) in script.php on line 28

连接失败:0


你能否从服务器控制台建立到APNS服务器的Telnet连接? - Rok Jarc
1
有时服务器不允许您使用所需的端口...最好询问您的服务器管理员并确认是否拥有特权...您正在使用共享主机吗?这种情况在共享主机中经常发生... - Adnan Aftab
1
是的,我正在使用共享主机,并已经写信给我的服务器管理员。 @rokjarc 对不起,但我无法测试telnet连接,因为不知道如何操作,非常抱歉,但我是一名新程序员 :( - lubilis
如果您可以访问服务器控制台(不确定是否可以),则可以键入“telnet gateway.push.apple.com 2195”并观察响应。 - Rok Jarc
不,我认为我没有访问它的权限。我可以访问数据库、控制面板或FTP。 - lubilis
显示剩余2条评论
1个回答

6

当你使用共享主机时,主机提供商不允许你在2195和2196端口上使用出站连接时,就会出现这种情况。你应该使用VPS或使用像urbanAirship和parse.com这样的其他提供商。甚至你可以运行自己的本地服务器...为此


我的证书是有效的,因为我可以从我的电脑发送通知,执行 PHP 脚本,对吧?在服务器上,我的 pem 文件与 PHP 脚本位于同一目录中,如果我回显证书,我可以在浏览器中看到它。所以设置正确了,对吧?我不明白如何使用 allow_self_signed 和 verify_peer,我应该在哪里使用它们? - lubilis
好的,我添加了这些行但是没有任何变化。 stream_context_set_option($ctx, "ssl", "allow_self_signed", true); stream_context_set_option($ctx, "ssl", "verify_peer", false); - lubilis
执行 fwrite 时出现错误,你是否在本地服务器上检查过你的 PHP 脚本?这个问题只发生在线上服务器中吗?而且在本地服务器上运行正常吗? - Adnan Aftab
在本地服务器上,所有功能都正常工作,并且使用allow_self_signed和verify_peer选项也没有问题。错误不在fwrite上,而是在这里:($fp = stream_socket_client( 'sslv2://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);) - lubilis
3
好的,现在一切运行良好!我的问题是这样的,我替换了这个: $certificate = file_get_contents('/path/ck.pem'); stream_context_set_option($ctx, 'ssl', 'local_cert', $certificate); 用了这个: stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem'); 证书必须与 PHP 脚本在同一个目录下,并且不能使用 file_get_contents。感谢帮助! - lubilis
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接