6

深夜です。google/stackoverflow の検索と実験に 10 時間費やしました。そして、私は Apple プッシュ通知が嫌いなようです。私は完全にイライラしており、助けていただければ幸いです。

ありがとうございました。

問題:

2 週間前に正常に機能していた 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/...

APNs 送信用に別々のスクリプトを使用している 2 つの別々のサーバーで動作しなくなりました。

環境:

サーバー: PHP 5.4.32 を使用する CentOS 6.5 および PHP 5.5.9 を使用する Ubuntu 14.04.3

APN: 本番モード

証明書: 700 以上のプッシュ通知でテスト済み。

サーバーの 1 つは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()また、オプション、 includeentrust_2048_ca.cerなど、さらにはこの記事のいくつかのオプションで遊んでみました。提供されたコードは、2015 年 8 月までは変更なしで機能しましたが。

openssl

接続はopensslで機能しました(リンク):

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

接続はtelnetで機能しました:

-sh-4.1$ telnet gateway.push.apple.com 2195
Trying 17.172.233.150...
Connected to gateway.push.apple.com.

ペクルapn

プッシュ通知を送信しませんでしたサンプル コードの適応を使用しようとしましたが、エラーが発生しましInvalid tokenた。トークンはアクティブで、どこでも、ヒューストンとルビーにも使用したのと同じトークンです。

ヒューストン

ヒューストンで働いた

apn push "0346a53f...231d9d6abe11" -c /absolute/path/to/apn_prod.pem -m "Hello from the command line!" -e "production"

ルビー

私は (少なくとも) Ruby プログラマーではありませんが、Houston で成功した後、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 = "\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()実装方法を理解することはできませんでした。

助けてください。

4

2 に答える 2

5

問題を見つけて修正しました。

問題は .pem 証明書にありました。どういうわけか、本番用と開発用の両方の .pem ファイルに対して 1 つのファイルに 2 つの証明書がありました。2 つの証明書を含む同じ .pem ファイルが長い間レポにありましたが、数か月前に APN が機能しなくなりました。Apple側で何かがアップグレード/変更されたのかもしれません。

Rubyコードが証明書の重複を何らかの形で削除するか、最初の証明書だけを使用したため、Rubyで機能したと思います。

ただし、解決策は .pem ファイルから 2 番目の証明書を削除することでした。その後、APN が機能し始め、現在も機能しています (昨日いくつか受け取りました)。

于 2015-10-08T11:55:06.507 に答える