【问题标题】:Only from PHP: Unable to connect APNS gateway.push.apple.com:2195仅来自 PHP:无法连接 APNS gateway.push.apple.com:2195
【发布时间】:2015-11-05 19:30:36
【问题描述】:

这是一个深夜。我刚刚在 google/stackoverflow 搜索和实验中花了 10 个小时。看来我讨厌苹果推送通知。我非常沮丧,如果有任何帮助,我将不胜感激。

谢谢。

问题:

用于发送 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,其他-https://github.com/antongorodezkiy/wp-apn,在本地主机上我测试了简单文件,没有使用任何第三方代码。

调查:

对于以下所有情况,我使用相同的活动设备令牌和相同的生产 PEM 证书。

php

但是,即使是这个简单的代码在服务器和本地主机上都不起作用,并返回与上述相同的错误:

$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 代码。

而且成功了

#!/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 = "\0\0 #{token}\0#{json.length.chr}#{json}"
ssl.write(apnsMessage)

ssl.close
sock.close

puts "End"

问题:

  1. PHP 出了什么问题?是否存在与此问题相关的错误? (虽然我没有找到错误报告)
  2. 有什么办法可以解决这个问题吗?
  3. 您知道 PHP 和 Ruby 案例的不同之处(我认为 Python 或 Perl 也可以正常工作)吗?我什至尝试阅读 PHP 源代码,但未能成功理解 stream_socket_client() 是如何实现的。

请帮忙。

【问题讨论】:

  • 您的 APNS 通知是否正常工作?我在 PHP 开发服务器上遇到了同样的问题,生产服务器使用共享代码库按预期运行。
  • @ViktorSulak 是的,我已经修好了。请检查我的回答(stackoverflow.com/a/33015070/741782),谢谢你提醒我这张票

标签: php ios ruby apple-push-notifications apns-php


【解决方案1】:

我发现了问题并解决了。

问题在 .pem 证书中。不知何故,一个文件中有两个证书,用于生产和开发 .pem 文件。具有两个证书的相同 .pem 文件在存储库中存在很长时间,但 APN 仅在几个月前停止工作。也许苹果方面升级/改变了一些东西。

我假设 Ruby 代码以某种方式消除了证书重复,或者它只需要第一个证书,所以它在 Ruby 中工作。

但是,解决方案是从 .pem 文件中删除第二个证书。之后 APN 开始工作,它们现在工作(我昨天才收到一些)。

【讨论】:

    【解决方案2】:

    如果您只是重复使用旧的证书签名请求 (CSR),请确保在将新证书及其私钥导出为 p12 文件之前从您的钥匙串中删除过期/旧的 APNs 证书。如果您不这样做,您从导出的 p12 生成的 PEM 文件仍将包含过期/旧证书,这与 Apple 的 Push 提供程序不兼容。从而导致unable to connect to ssl...

    【讨论】:

      猜你喜欢
      • 2016-01-26
      • 1970-01-01
      • 2019-02-02
      • 2011-09-16
      • 1970-01-01
      • 2013-10-02
      • 1970-01-01
      • 1970-01-01
      • 2015-01-03
      相关资源
      最近更新 更多