最近再做一个推送项目,需要搭建APNS
服务器,再将PHP代码部署到Server
上时遇到了如下错误:
Warning: stream_socket_client() [function.stream-socket-client]: Unable to set local cert chain file `ck.pem'; Check that your cafile/capath settings include details of your certificate and its issuer in D:\AppServ\www\push1\push.php on line 24 Warning: stream_socket_client() [function.stream-socket-client]: failed to create an SSL handle in D:\AppServ\www\push1\push.php on line 24 Warning: stream_socket_client() [function.stream-socket-client]: Failed to enable crypto in D:\AppServ\www\push1\push.php on line 24 Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Unknown error) in D:\AppServ\www\push1\push.php on line 24 Failed to connect: 0
上网Google之,发现很多人遇到此问题,给出的解决方案照做后错误依然存在。最终还是自己解决,从问题本身出发吧,自己当初调试时Server
是部署在Mac os
上的,而现在却要部署在Windows Server 2008
上。所以很可能是两边的配置出了问题,而代码的第24行为:
<?php $fp = stream_socket_client( 'ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx); ?>
PHP
给出的错误大概是说,没有找到证书,无法建立ssl连接。
首先.pem
证书已经制作,并且可用。还有就是证书的路径需要放正确
<?php stream_context_set_option($ctx, 'ssl', 'local_cert',$this->localcert); ?>
确保该函数的最后一个参数所指的路径能正确找到证书。经过测试在Mac OS
下这样就可以了,但是在Windows
下要改成这样:
<?php stream_context_set_option($ctx, 'ssl', 'local_cert',dirname(__FILE__) . '\\' .$this->localcert); ?>
但是做了这些,问题仍然不能解决,剩下的问题就是Apache
需要开启ssl
模块,通过查看Apache
的官方文档得知,使用ssl
需要Apache
开启三个支持模块分别是:
mod_include
mod_cgi
mod_expires
接下来打开Apache
的配置文件httpd.conf
大概50-100行之间模块加载部分,放开这三个模块加载前的注释:
LoadModule reqtimeout_module libexec/apache2/mod_reqtimeout.so LoadModule ext_filter_module libexec/apache2/mod_ext_filter.so LoadModule include_module libexec/apache2/mod_include.so #注释放开 LoadModule filter_module libexec/apache2/mod_filter.so LoadModule substitute_module libexec/apache2/mod_substitute.so LoadModule deflate_module libexec/apache2/mod_deflate.so LoadModule log_config_module libexec/apache2/mod_log_config.so LoadModule log_forensic_module libexec/apache2/mod_log_forensic.so LoadModule logio_module libexec/apache2/mod_logio.so LoadModule env_module libexec/apache2/mod_env.so LoadModule mime_magic_module libexec/apache2/mod_mime_magic.so LoadModule cern_meta_module libexec/apache2/mod_cern_meta.so LoadModule expires_module libexec/apache2/mod_expires.so #注释放开 LoadModule headers_module libexec/apache2/mod_headers.so LoadModule ident_module libexec/apache2/mod_ident.so
保存,重启Apache
,再试,问题已解决。
最后附上推送部分的PHP
代码:PHP代码下载地址
<?php class Push { public $deviceToken;//需要在构造时候设置 //本地证书和密码 public $localcert =''; public $passphrase = ''; /* * 功能:构造函数,设置deviceToken */ function Push($deviceToken) { $this->deviceToken = $deviceToken; } /* 功能:生成发送内容并且转化为json格式 */ private function createPayload($message,$type,$sound) { // Create the payload body $body['aps'] = array( 'alert' => $message, 'sound' => $sound, 'type' =>$type ); // Encode the payload as JSON $payload = json_encode($body); return $payload; } // Put your private key's passphrase here: public function pushData($message,$type,$sound) { $ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'local_cert',$this->localcert); stream_context_set_option($ctx, 'ssl', 'passphrase', $this->passphrase); // Open a connection to the APNS server //这个为正是的发布地址 //$fp = stream_socket_client(“ssl://gateway.push.apple.com:2195“, $err, $errstr, 60, //STREAM_CLIENT_CONNECT, $ctx); //这个是沙盒测试地址,发布到appstore后记得修改哦 $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; // 创建消息 $payload =$this->createPayload($message,$type,$sound); // Build the binary notification $msg = chr(0) . pack('n', 32) . pack('H*', $this ->deviceToken) . pack('n', strlen($payload)) . $payload; // Send it to the server $result = fwrite($fp, $msg, strlen($msg)); if (!$result) { echo 'Message not delivered' . PHP_EOL; } else { echo 'Message successfully delivered' . PHP_EOL; } // Close the connection to the server fclose($fp); } } ?>