2

過去数日間、本番サーバーのAPNサーバーに接続するためにソケットを使用すると、PHPで奇妙な動作が発生します。

ほとんどの場合、ペイロードはエラーなしでプッシュされ、クライアントは通知を受け取ります。ただし、場合によっては、PHPエラーを受け取り始めます(エラーを受け取っていても、通知がプッシュされることがあります)。このエラーが発生し始めると、何時間も続き、その後消え、PHPは何も起こらなかったように動作し続けます。

もう1つの奇妙なことは、シェルから同じPHPコードを実行しても、エラーがまったく発生しないことです。Web(nginx / php-fpm)から実行すると...シェルとWebで実行されているPHPは同じ構成であり、同じphp.iniを共有します。唯一の違いは、Webがphp-fpmで実行されていることです。

また、同じコード+証明書が、エラーなしでステージングサーバー上で実行されます。本番サーバーはステージングサーバーのコピーであるため、すべての構成は同じです。

stackoverflow.comからの回答を含め、このエラーの原因となる可能性のあるいくつかの回答を見つけることができましたが、解決策を見つけることも解決することもできませんでした。

Appleサーバーへの通知は、バンドルとしてではなく、1つずつ送信されます。しかし、私たちはあまり多くの接続を行っていません(おそらく1日1000)。キューシステムはありません。

つまり、要するに

  • 通知の送信中にPHPエラーが発生することがありますが、常にそうとは限りません。
  • 同じPHPを介してシェルから通知を送信してもエラーは発生しません
  • ステージングサーバーから通知を送信してもエラーは発生しません

これらを試しました

  • 証明書とキーの再作成
  • PEMファイルの再作成
  • ssl://をsslv3://に変更します
  • stream_socket_clientを使用する
  • fsockopenを使用する
  • 証明書のパスワードの変更/削除

エラーは次のとおりです。

2012/08/28 12:18:09 [error] 4282#0: *225858 FastCGI sent in stderr: 
"PHP message: PHP Warning:  fwrite() [<a href='function.fwrite'>function.fwrite</a>]:
SSL operation failed with code 1. OpenSSL Error messages:
error:1409F07F:SSL routines:func(159):reason(127) in 
/usr/local/nginx/html/play/classes/PushNotification.php on line 283"
while reading response header from upstream, client: 94.---.---.---,
server: play.--------.com, request: "POST /game_request_random.php HTTP/1.1",
upstream: "fastcgi://unix:/var/run/phpfpm.sock:",
host: "play.--------.com", referrer: "http://--------.com/"

phpからペイロードを接続して送信するコードは、実際にはクラスの一部です。この部分は、接続を確立してペイロードを送信するものです。

  private function ConnectAndSend ( $msg = false ) {
    $ctx = stream_context_create();
    stream_context_set_option( $ctx, 'ssl', 'local_cert', $this->certificate );
    stream_context_set_option( $ctx, 'ssl', 'passphrase', $this->certificatepass );

    // Open a connection to the APNS server
    $fp = stream_socket_client( APN_SERVER, $err, $errstr, 60, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx );
    if ( !$fp ) {
      errorlog( "Push notification error : $err $errstr" );
      $this->error = "$err $errstr";
      return;
    }

    // Build the notification
    if ( !$msg ) {
      $msg = chr( 0 ) . pack( 'n', 32 ) . pack( 'H*', $this->devicetoken ) . pack( 'n', strlen( $this->payload ) ) . $this->payload;
    }

    // Send it to the server
    if ( !($result = fwrite( $fp, $msg, strlen( $msg ) )) ) {
      // Could not send
      $this->error = 'Notification could not be send';
      errorlog( "Push notification error : {$this->error}" );
    } else {
      // Notification sent
      $this->error = false;
      errorlog( "Push notification sent" );
    }

    fclose($fp);

    // Reset the content
    $this->devicetoken = false;
    $this->message = false;
    $this->command = false;
    $this->badge = 0;
    $this->payload = false;
    $this->sound = false;
  }
  • stream_socket_connectionは、エラーメッセージに表示される283行目です。
  • サンドボックスを使用していません(sslv3://gateway.push.apple.com:2195)
  • PHPのバージョンは5.3.15です

これは、私たちが知らないPHPまたはOpenSSLのバグですか?何をどこでチェックするかについてのアイデアはありますか?Appleには、APNネットワークの現在の状態を確認できるサイトがありますか?

どんな助けでも大歓迎です...ありがとう

4

1 に答える 1

-2

複数のメッセージを送信するには、このコードを確認してください

$i = 0;
while($res = mysql_fetch_array( $result )) {
    $deviceTokens[$i] = $res['token'];
    $i++;
}

// APNs Push testen auf Token
//$deviceToken = $token; // Hier das Device-Token angeben, ist 64-stellig

// Payload erstellen und JSON codieren
$message = $_POST['message'];
$message = utf8_encode($message);


$payload['aps'] = array('alert' => 'Neuer Artikel in Aktuelles', 'badge' => +1, 'sound' => 'default');
if (trim($message) != '') {
    $payload['aps'] = array('alert' => "$message", 'badge' => 1, 'sound' => 'default');
}
$payload = json_encode($payload);

//Development: $apnsHost = 'gateway.sandbox.push.apple.com';
$apnsHost = 'gateway.push.apple.com';
$apnsPort = 2195;

//Development: $apnsCert = 'apsDevBundle.pem';
$apnsCert = 'apns-dev.pem';

// Stream erstellen
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);

$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
if ($error==0)
{     
  for($i = 0; $i<count($deviceTokens); $i++) {

      // Build the binary notification
      $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceTokens[$i])) . chr(0) . chr(strlen($payload)) . $payload;

      fwrite($apns, $apnsMessage);
  }

  // Verbindung schliessen
  fclose($apns);
}
else
{
  var_dump($error);
  var_dump($errorString);
  die("Fehler aufgetreten.");
}
于 2013-04-05T11:58:16.827 に答える