最近再做一个推送项目,需要搭建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);
}
}
?>