APNs Provider API（HTTP/2）をPHPで試してみる

# この記事は？

iOSでPush通知するための新しいAPI（APNs Provider API）が去年の12月から提供されています！

APNs Provider API：
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/APNsProviderAPI.html

ソケット通信をするややこしい旧APIとは違い、HTTP/2ベースになって、とってもシンプルに。
送信結果も簡単に取得出来るようになっていいことづくめなので、遅ればせながら、PHP on Mac（OS X El Capitan）で試してみました。

# HTTP/2環境整備

まず、PHPでHTTP2のリクエスト実現するには以下の環境が必要です。

* openssl 1.0.2e以上
* curl 7.46以上（+nghttp2）
* PHP 5.5.24以上

## opensslインストール

Macにプリインされているopensslのバージョンが古かったので、brewでインストールします。

```
$ brew install openssl
```

次にbrewで入れたopensslにリンクを貼ります。

```
$ brew link openssl --force
```

バージョン確認して問題なければOK！

```
$ which openssl
/usr/local/bin/openssl
$ openssl version
OpenSSL 1.0.2f  28 Jan 2016
```

## curlインストール

こちらもプリインされているバージョンが古かったので、brewでインストールします。
nghttp2も一緒にインストール！

```
$ brew install curl --with-nghttp2 --with-openssl
```

こちらもリンクを貼るのを忘れないように。

```
$ brew link curl --force
```

バージョン確認して以下のような感じになっていればOK！
Featuresに```HTTP2```の記載があることを要確認。

```
$ which curl
/usr/local/bin/curl
$ curl --version
curl 7.47.1 (x86_64-apple-darwin15.0.0) libcurl/7.47.1 OpenSSL/1.0.2f zlib/1.2.5 nghttp2/1.7.1
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets
```

## PHPインストール

PHPはインストール済の方も多いと思いますが、一回入れ直した方がハマらないかも。

```
$ brew install --with-homebrew-curl --with-homebrew-openssl  --without-snmp php56
$ brew install php56-mcrypt
```

phpinfoで確認して、

```
$ php -r 'phpinfo();'
```

こんな感じの結果が表示されていればOK！

```
PHP Version => 5.6.18
（省略）
curl

cURL support => enabled
cURL Information => 7.47.1
（省略）
openssl

OpenSSL support => enabled
OpenSSL Library Version => OpenSSL 1.0.2f  28 Jan 2016
（省略）
```

# PHPスクリプト作成

ここまで来たら楽勝です。

```PHP:new_api.php
<?php
if(defined('CURL_HTTP_VERSION_2_0')){

    $device_token   = 'your device token';
    $pem_file       = 'path to your pem file';
    // $pem_secret     = 'your pem secret'; // パスワードを設定している場合は必要
    $apns_topic     = 'your apns topic. Can be your app bundle ID';

    $alert = '{"aps":{"alert":"Hello, Nogizaka46","sound":"default"}}';
    $url = "https://api.push.apple.com/3/device/$device_token";

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $sample_alert);
    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("apns-topic: $apns_topic"));
    curl_setopt($ch, CURLOPT_SSLCERT, $pem_file);
    // curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $pem_secret); // パスワードを設定している場合は必要
    $response = curl_exec($ch);
    $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    var_dump($response);
    var_dump($httpcode);

    // デバッグ用
    // $info = curl_getinfo($ch);
    // $errno = curl_errno($ch);
    // $error = curl_error($ch);

　　 // var_dump($info);
    // var_dump($errno);
    // var_dump($error);
}
```

このPHPをスクリプトを実行して、ステータスコードが200だったらOK！
エラーの場合は、```{"reason":"DeviceTokenNotForTopic"}```みたいなJSONがレスポンスされます。

## 感想

HTTP/2に対応した環境をつくるのに少し苦労しましたが、実装やエラーハンドリングが楽になったし、今風のAPIなので、これから積極的に使っていこうと思います。

# 参考サイト

New APNS Provider API and PHP：
http://stackoverflow.com/questions/34684099/new-apns-provider-api-and-php/34955920
APNs Provider API (HTTP/2 ) を go (1.6) から扱う：
http://soh335.hatenablog.com/entry/2015/12/22/222041
curl エクステンションで HTTP/2 リクエストを送信する：
http://qiita.com/masakielastic/items/f563437c44b0d4c04f87
macのPHPからcURLでhttpsアクセスすると失敗する件：
http://takemaru123.hatenablog.jp/entry/2015/05/22/123753