これは罠。PHPでiPhone端末にPUSH通知を送る際の落とし穴

これは罠。PHPでiPhone端末にPUSH通知を送る際の落とし穴

段田

段田

段田です。

最近、PHPからiphone端末にPUSH通知を送る機能の開発に携わりました。PHPでプログラムを実装する場合、フルスクラッチとライブラリを使用するケースがあるのですが、各ケースでのポイントを忘れないよう書きたいと思います。

なおPUSH通知の概要、証明証の作成については省略します。概要などは下記の記事がわかりやすく、参考になりました。


Apple Push Notification サービス(APNs) の実装方法

iPhoneプッシュ通知まとめ

フルスクラッチのケース

フルスクラッチでやる場合、こちらのはてなの記事が参考になりました。


https://irss.hatenablog.com/entry/20111026/1319632548

しかし、試しに作成すると送信はできるのですが、下記の様な制約があることを知ります。

  1. 1つのメッセージで256バイトを超えてはいけない
  2. 1回の通信で全パケットが5000〜7000バイトを超えるとAPNSから切断される

1に関してはApple公式ドキュメントに記載があるのですが、
2に関しては記述がありません。
(色んな人に聞いたりして判明しました。)
実際に複数送信をした場合、一定送信件数を超えるとAPNSから切断されます。あの世まで行ってジョブズに焼き土下座させたい気分なのですが、ここはグッと堪えます。

対応策としては

  • 5000〜7000Byte毎にsleepした後に再接続をする(今回は5000Byte)
  • APNSからエラーが返却された場合はsleepした後に再接続をする


という処理をいれてやると解決できます。sleepは1秒ぐらいで良いかと思います。
下記では入れていませんが、APNSが落ちている可能性等もありますので、
エラーが指定回数を超えたら、処理を中断するのも良いかと思います。

function connectAPSN($sslclient,$pem_path,$passphrase){
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', $pem_path);
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client($sslclient, $err,
	 $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp){
echo "接続エラーになったので1秒後再接続を試みます。メメタア!" . PHP_EOL;
sleep(1);
$fp = connectAPSN($sslclient,$pem_path,$passphrase);
return $fp;
}else{
echo "APNS接続できたぞおおおWRYYYYYYYYYYYYYYY" . PHP_EOL;
return $fp;
}

}

//送信処理
$passphrase = 'password';
$pem_path = '/xxx/xxx.pem';
$sslclient = 'ssl://gateway.sandbox.push.apple.com:2195';
$fp = connectAPSN($sslclient,$pem_path,$passphrase);
//PUSH内容設定
$body['aps'] = array(
	'alert' => "PUSHメッセージ送信します",//20文字以内で
	'sound' => 'default',
	'badge'=> 1,
);
//PUSH内容をJSON化
$payload = json_encode($body);
$json_size = strlen($payload);//json化したメッセージのサイズ確認
$size = 0;
foreach ($device_Token_array as $deviceToken){
	$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken["device_token"]) . pack('n', $json_size) . $payload;
	$msg_size = strlen($msg);
	$result = fwrite($fp, $msg, $msg_size);
	if (!$result){
		echo '送信できなかったガッデム!' . PHP_EOL;
	}else{
		echo '送信できたわよー' . PHP_EOL;
	}
	$size += $msg_size;
	if($size >= 5120){
		echo '通信容量超えたので再接続します。ジョブズマジ許さねえ。' . PHP_EOL;
		fclose($fp);
		sleep(1);
		$fp = connectAPSN($sslclient,$pem_path,$passphrase);
		echo '再接続しました。ジョブズとりあえずファンタ買ってこい。' . PHP_EOL;
		$size = 0;
	}
}
fclose($fp);

ライブラリのケース

ライブラリはApnsPHPがお勧めです。


apns-php送信に使用するsend()メソッド内でエラー時の再接続処理を実装されているので、フルスクラッチで書いた対応策を別途実装する必要はありません。apns-phpのサイトに記載のサンプルスクリプトで大体、実装できます。

注意点

複数送信する際ですが、何万件、何十万件をPUSH送信する場合、一気にアプリへのアクセスが予想されます。外部サーバーへのデータ連携やWEBVIEWによるサイト表示をしている場合、負荷が高まる可能性がありますので、負荷対策を考えたほうが良いでしょう。

LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。

Webサイト制作の実績・料金を見る

この記事のシェア数

段田です。いつも仕事中は14の言葉を呟いています。らせん階段 カブト虫 廃墟の街 イチジクのタルト カブト虫 ドロローサへの道 カブト虫 特異点 ジョット 天使 紫陽花 カブト虫 特異点 秘密の皇帝...

このメンバーの記事をもっと読む