仅来自 PHP:无法连接 APNS gateway.push.apple.com:2195
Only from PHP: Unable to connect APNS gateway.push.apple.com:2195
夜深了。我刚刚花了 10 个小时进行 google/Whosebug 搜索和实验。似乎我讨厌苹果推送通知。我非常沮丧,非常感谢任何帮助。
谢谢。
问题:
两周前成功运行的用于发送 Apple 推送通知的 PHP 代码现在停止运行并抛出以下错误:
PHP Warning: stream_socket_client(): Failed to enable crypto in /home/...
PHP Warning: stream_socket_client(): unable to connect to ssl://gateway.push.apple.com:2195 (Unknown error) in /home/...
它停止在两个单独的服务器上工作,它们使用单独的脚本发送 APN。
环境:
服务器:CentOS 6.5 PHP 5.4.32 和 Ubuntu 14.04.3 PHP 5.5.9
APN:生产模式
证书:使用 700 多个推送通知进行测试。
其中一个服务器正在使用 https://github.com/immobiliare/ApnsPHP, other - https://github.com/antongorodezkiy/wp-apn,我在本地主机上测试了简单文件,没有使用任何第三方代码。
调查:
对于以下所有情况,我使用相同的活动设备令牌和相同的生产 PEM 证书。
php
然而,即使是这个简单的代码在服务器和本地主机上都不起作用并且return出现与上面相同的错误:
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', '/absolute/path/to/apn_prod.pem');
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
我也尝试使用 stream_context_set_option()
选项,包括 entrust_2048_ca.cer
等,甚至 this article 中的一些选项。尽管提供的代码在 2015 年 8 月之前无需任何修改即可运行。
openssl
连接有效 与 openssl (link):
openssl s_client -connect gateway.push.apple.com:2195 -cert /absolute/path/to/apn_prod.pem -debug -showcerts -CAfile /absolute/path/to/server-ca-cert.pem
并获得 CONNECTED(00000003)
和 Verify return code: 0 ( ok )
。
远程登录
连接正常 telnet:
-sh-4.1$ telnet gateway.push.apple.com 2195
Trying 17.172.233.150...
Connected to gateway.push.apple.com.
pecl apn
它没有发送推送通知。我刚刚尝试使用 sample code 的改编,但出现错误 Invalid token
。该令牌是活动的,我在任何地方以及休斯顿和 Ruby 都使用过相同的令牌。
houston
在休斯顿工作
apn push "0346a53f...231d9d6abe11" -c /absolute/path/to/apn_prod.pem -m "Hello from the command line!" -e "production"
ruby
我不是 Ruby 程序员(至少),但在 Houston 取得成功后,我发现并改编了 Ruby 没有休斯顿依赖的代码。
并且有效:
#!/usr/bin/env ruby
require 'openssl'
require 'socket'
require 'json'
token = "0346a53f...231d9d6abe11"
cert = File.read("/absolute/path/to/apn_prod.pem")
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = OpenSSL::PKey::RSA.new(cert, '') #set passphrase here, if any
ctx.cert = OpenSSL::X509::Certificate.new(cert)
sock = TCPSocket.new('gateway.push.apple.com', 2195) #development gateway
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.connect
payload = {"aps" => {"alert" => "Oh hai!", "badge" => 1, "sound" => 'default'}}
json = payload.to_json()
token = [token.delete(' ')].pack('H*') #something like 2c0cad 01d1465 346786a9 3a07613f2 b03f0b94b6 8dde3993 d9017224 ad068d36
apnsMessage = "[=17=][=17=] #{token}[=17=]#{json.length.chr}#{json}"
ssl.write(apnsMessage)
ssl.close
sock.close
puts "End"
问题:
- PHP 怎么了?是否存在与此问题相关的错误? (虽然我没有找到错误报告)
- 有什么解决这个问题的想法吗?
- 任何想法在 PHP 和 Ruby 情况下可能有什么区别(我假设 Python 或 Perl 也可以正常工作)?我什至尝试阅读 PHP 来源,但未能成功理解
stream_socket_client()
是如何实施的。
请帮忙
我发现了问题并解决了它。
问题 出现在 .pem 证书中。不知何故,一个文件中有两个证书用于生产和开发 .pem 文件。带有两个证书的同一个 .pem 文件在 repo 中存在了很长时间,但 APNs 仅在几个月前才停止工作。也许苹果方面 upgraded/changed 有问题。
我假设 Ruby 代码以某种方式删除了证书重复,或者它可能只使用了第一个证书,所以它在 Ruby 中工作。
但是,解决方案 是从 .pem 文件中删除第二个证书。在那之后 APNs 开始工作并且他们现在工作(我昨天刚收到一些)。
如果您只是重复使用旧的证书签名请求 (CSR),请确保在将新证书及其私钥导出为 p12 文件之前从钥匙串中删除 expired/old APNs 证书。如果您不这样做,您从导出的 p12 生成的 PEM 文件仍将包含 expired/old 证书,这与 Apple 的推送提供程序不兼容。因此导致 unable to connect to ssl...
.
夜深了。我刚刚花了 10 个小时进行 google/Whosebug 搜索和实验。似乎我讨厌苹果推送通知。我非常沮丧,非常感谢任何帮助。
谢谢。
问题:
两周前成功运行的用于发送 Apple 推送通知的 PHP 代码现在停止运行并抛出以下错误:
PHP Warning: stream_socket_client(): Failed to enable crypto in /home/...
PHP Warning: stream_socket_client(): unable to connect to ssl://gateway.push.apple.com:2195 (Unknown error) in /home/...
它停止在两个单独的服务器上工作,它们使用单独的脚本发送 APN。
环境:
服务器:CentOS 6.5 PHP 5.4.32 和 Ubuntu 14.04.3 PHP 5.5.9
APN:生产模式
证书:使用 700 多个推送通知进行测试。
其中一个服务器正在使用 https://github.com/immobiliare/ApnsPHP, other - https://github.com/antongorodezkiy/wp-apn,我在本地主机上测试了简单文件,没有使用任何第三方代码。
调查:
对于以下所有情况,我使用相同的活动设备令牌和相同的生产 PEM 证书。
php
然而,即使是这个简单的代码在服务器和本地主机上都不起作用并且return出现与上面相同的错误:
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', '/absolute/path/to/apn_prod.pem');
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
我也尝试使用 stream_context_set_option()
选项,包括 entrust_2048_ca.cer
等,甚至 this article 中的一些选项。尽管提供的代码在 2015 年 8 月之前无需任何修改即可运行。
openssl
连接有效 与 openssl (link):
openssl s_client -connect gateway.push.apple.com:2195 -cert /absolute/path/to/apn_prod.pem -debug -showcerts -CAfile /absolute/path/to/server-ca-cert.pem
并获得 CONNECTED(00000003)
和 Verify return code: 0 ( ok )
。
远程登录
连接正常 telnet:
-sh-4.1$ telnet gateway.push.apple.com 2195
Trying 17.172.233.150...
Connected to gateway.push.apple.com.
pecl apn
它没有发送推送通知。我刚刚尝试使用 sample code 的改编,但出现错误 Invalid token
。该令牌是活动的,我在任何地方以及休斯顿和 Ruby 都使用过相同的令牌。
houston
在休斯顿工作
apn push "0346a53f...231d9d6abe11" -c /absolute/path/to/apn_prod.pem -m "Hello from the command line!" -e "production"
ruby
我不是 Ruby 程序员(至少),但在 Houston 取得成功后,我发现并改编了 Ruby 没有休斯顿依赖的代码。
并且有效:
#!/usr/bin/env ruby
require 'openssl'
require 'socket'
require 'json'
token = "0346a53f...231d9d6abe11"
cert = File.read("/absolute/path/to/apn_prod.pem")
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = OpenSSL::PKey::RSA.new(cert, '') #set passphrase here, if any
ctx.cert = OpenSSL::X509::Certificate.new(cert)
sock = TCPSocket.new('gateway.push.apple.com', 2195) #development gateway
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.connect
payload = {"aps" => {"alert" => "Oh hai!", "badge" => 1, "sound" => 'default'}}
json = payload.to_json()
token = [token.delete(' ')].pack('H*') #something like 2c0cad 01d1465 346786a9 3a07613f2 b03f0b94b6 8dde3993 d9017224 ad068d36
apnsMessage = "[=17=][=17=] #{token}[=17=]#{json.length.chr}#{json}"
ssl.write(apnsMessage)
ssl.close
sock.close
puts "End"
问题:
- PHP 怎么了?是否存在与此问题相关的错误? (虽然我没有找到错误报告)
- 有什么解决这个问题的想法吗?
- 任何想法在 PHP 和 Ruby 情况下可能有什么区别(我假设 Python 或 Perl 也可以正常工作)?我什至尝试阅读 PHP 来源,但未能成功理解
stream_socket_client()
是如何实施的。
请帮忙
我发现了问题并解决了它。
问题 出现在 .pem 证书中。不知何故,一个文件中有两个证书用于生产和开发 .pem 文件。带有两个证书的同一个 .pem 文件在 repo 中存在了很长时间,但 APNs 仅在几个月前才停止工作。也许苹果方面 upgraded/changed 有问题。
我假设 Ruby 代码以某种方式删除了证书重复,或者它可能只使用了第一个证书,所以它在 Ruby 中工作。
但是,解决方案 是从 .pem 文件中删除第二个证书。在那之后 APNs 开始工作并且他们现在工作(我昨天刚收到一些)。
如果您只是重复使用旧的证书签名请求 (CSR),请确保在将新证书及其私钥导出为 p12 文件之前从钥匙串中删除 expired/old APNs 证书。如果您不这样做,您从导出的 p12 生成的 PEM 文件仍将包含 expired/old 证书,这与 Apple 的推送提供程序不兼容。因此导致 unable to connect to ssl...
.