└── readme.md /readme.md: -------------------------------------------------------------------------------- 1 | # APNS (HTTP/2) with PHP simple push ( Ubuntu 14.04) 2 | 3 | # 內容物 4 | - CURL HTTP/2 伺服器啟用 5 | - APNS 憑證產生教學 6 | - PHP simple push code 7 | 8 | ## Requirements 9 | - curl >= 7.43.0 | https://curl.haxx.se/docs/http2.html 10 | - nghttp2 11 | - openssl >= 1.0.2j | https://www.openssl.org/ | APNS要求~ 12 | 13 | ##### 先看看你的 curl 版本 14 | ```sh 15 | > curl --version 16 | curl 7.35.0 (x86_64-pc-linux-gnu) libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3 17 | Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smtp smtps telnet tftp 18 | Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP 19 | ``` 20 | Features 裡面沒有http2 不支援 OpenSSL也過舊一起更新吧QQ 21 | 22 | ##### 不死心先執行看看 23 | ```sh 24 | curl --http2 -I https://google.com.tw/ 25 | # Unsupported protocol error (不支援) 26 | ``` 27 | 28 | # CURL HTTP/2 伺服器啟用 29 | Install Git 30 | ```sh 31 | sudo apt-get install -y git 32 | ``` 33 | 34 | Install nghttp2 35 | ```sh 36 | # Get build requirements 37 | # Some of these are used for the Python bindings 38 | # this package also installs 39 | sudo apt-get install g++ make binutils autoconf automake autotools-dev libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev libjemalloc-dev cython python3-dev python-setuptools 40 | 41 | # Build nghttp2 from source 42 | git clone https://github.com/tatsuhiro-t/nghttp2.git 43 | cd nghttp2 44 | autoreconf -i 45 | automake 46 | autoconf 47 | ./configure 48 | make 49 | sudo make install 50 | ``` 51 | 52 | Install or Upgrade to latest curl 53 | ```sh 54 | cd /tmp 55 | sudo apt-get build-dep curl 56 | wget http://curl.haxx.se/download/curl-7.52.1.tar.bz2 57 | tar -xvjf curl-7.52.1.tar.bz2 58 | cd curl-7.52.1 59 | ./configure --with-nghttp2=/usr/local --with-ssl 60 | make 61 | sudo make install 62 | 63 | echo '/usr/local/lib' > /etc/ld.so.conf.d/local.conf #可能需要sudo su 執行 64 | sudo ldconfig 65 | ``` 66 | 67 | 滾完鍵盤測試一下 (成功回傳) 68 | ```sh 69 | curl --http2 -I https://google.com.tw 70 | HTTP/2 301 71 | location: https://www.google.com.tw/ 72 | content-type: text/html; charset=UTF-8 73 | date: Mon, 09 Jan 2017 08:49:08 GMT 74 | expires: Wed, 08 Feb 2017 08:49:08 GMT 75 | cache-control: public, max-age=2592000 76 | server: gws 77 | content-length: 223 78 | x-xss-protection: 1; mode=block 79 | x-frame-options: SAMEORIGIN 80 | alt-svc: quic=":443"; ma=2592000; v="35,34" 81 | ``` 82 | 83 | Upgrade OpenSSL 84 | ```sh 85 | cd /tmp 86 | wget https://openssl.org/source/openssl-1.1.0c.tar.gz 87 | tar -zxvf openssl-1.1.0c.tar.gz 88 | cd openssl-1.1.0c 89 | ./config 90 | sudo make 91 | sudo make install 92 | sudo mv /tmp/openssl-1.1.0c /root/ 93 | sudo mv /usr/bin/openssl /usr/bin/openssl.old 94 | sudo ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl 95 | echo "/usr/local/ssl/lib" >> /etc/ld.so.conf 96 | ldconfig 97 | ``` 98 | 99 | 確認OpenSSL完成更新 100 | ```sh 101 | openssl version 102 | #OpenSSL 1.1.0c 10 Nov 2016 103 | ``` 104 | 105 | # APNS 產生憑證 106 | 這邊只寫現有ID產生出憑證,至於要怎麼新建App ID... google it~ 107 | 108 | 請用Mac OS 產生: 109 | 110 | 1. 登入你的 控制台 [https://developer.apple.com/account/ios/certificate/](https://developer.apple.com/account/ios/certificate/) 111 | 112 | 2. 選擇 Certificates -> all 113 | 114 | 3. 按下右上角 + -> 選擇 Production 之下的 Apple Push Notification service SSL (Sandbox & Production) ->下一步 115 | 116 | 4. 選擇所要產生的App IDs (這也是之後的 apns-topic ) -> 下一步 117 | 118 | 5. 跟著螢幕指示 -> Launchpad -> 鑰匙圈存取 -> 左上角 "鑰匙圈存取"-> 憑證輔助程式 -> 從憑證授權要求憑證 -> 填完資訊儲存到硬碟 -> 回到 apple 頁面上傳 -> 下一步 119 | 120 | 6. 下載會獲得一個 "aps.cer" -> 按一下登入到鑰匙圈 -> 登入完成後找到剛剛登入的憑證 名稱 " Apple Push Services:xxxxxxxxxxxxxxxx" -> 右鍵輸出 server_certificates.p12 121 | 122 | 7. 開啟 Terminal 到檔案位子 123 | ```sh 124 | openssl pkcs12 -in server_certificates.p12 -out server_certificates.pem -nodes -clcerts 125 | ``` 126 | 127 | #### 現在就可以使用APNS HTTP/2 推播拉 ~ 128 | 129 | # APNS with PHP 130 | 131 | 可以先在 terminal 做推送 132 | ```sh 133 | > curl -d '{"aps":{"alert":"[MESSAGE]","sound":"default"}}' --cert "[PATH TO APS CERTIFICATE.pem]":"" -H "apns-topic: [BUNDLE IDENTIFIER]" --http2 https://api.development.push.apple.com/3/device/[TOKEN] 134 | ``` 135 | 136 | 會像這樣 發送成功後往下一步前進 137 | ```sh 138 | > curl -d '{"aps":{"alert":"Hi!","sound":"default"}}' --cert "server_certificates.pem":"" -H "apns-topic: vocolboy.samplepush" --http2 https://api.development.push.apple.com/3/device/c4942de20b30792b8f1e04c2f5488e05a24bf72f14f1fc849e6581faf957d8e1 139 | ``` 140 | 141 | 先產生 phpinfo 檔案確定所需配件都有了 142 | ```sh 143 | > php -i > phpinfo.txt 144 | ``` 145 | 146 | 比對一下這幾項有符合就可以了~ 147 | > 詳情看開頭的 Requirements 148 | 149 | ```sh 150 | ... 151 | curl 152 | 153 | cURL support => enabled 154 | cURL Information => 7.52.1 155 | ... 156 | HTTP2 => Yes 157 | ... 158 | SSL Version => OpenSSL/1.0.2j 159 | ... 160 | ``` 161 | 162 | ---- 163 | # PHP sendHTTP2Push code 164 | ``` 165 | /** 166 | * @param $http2ch the curl connection 167 | * @param $http2_server the Apple server url 168 | * @param $apple_cert the path to the certificate 169 | * @param $app_bundle_id the app bundle id 170 | * @param $message the payload to send (JSON) 171 | * @param $token the token of the device 172 | * @return mixed the status code 173 | */ 174 | function sendHTTP2Push($http2ch, $http2_server, $apple_cert, $app_bundle_id, $message, $token) { 175 | 176 | // url (endpoint) 177 | $url = "{$http2_server}/3/device/{$token}"; 178 | 179 | // certificate 180 | $cert = realpath($apple_cert); 181 | 182 | // headers 183 | $headers = array( 184 | "apns-topic: {$app_bundle_id}", 185 | "User-Agent: My Sender" 186 | ); 187 | 188 | // other curl options 189 | curl_setopt_array($http2ch, array( 190 | CURLOPT_URL => $url, 191 | CURLOPT_PORT => 443, 192 | CURLOPT_HTTPHEADER => $headers, 193 | CURLOPT_POST => TRUE, 194 | CURLOPT_POSTFIELDS => $message, 195 | CURLOPT_RETURNTRANSFER => TRUE, 196 | CURLOPT_TIMEOUT => 30, 197 | CURLOPT_SSL_VERIFYPEER => false, 198 | CURLOPT_SSLCERT => $cert, 199 | CURLOPT_HEADER => 1 200 | )); 201 | 202 | // go... 203 | $result = curl_exec($http2ch); 204 | if ($result === FALSE) { 205 | throw new Exception("Curl failed: " . curl_error($http2ch)); 206 | } 207 | 208 | // get response 209 | $status = curl_getinfo($http2ch, CURLINFO_HTTP_CODE); 210 | 211 | return $status; 212 | } 213 | ``` 214 | 215 | Use 216 | ``` 217 | // open connection 218 | $http2ch = curl_init(); 219 | curl_setopt($http2ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); 220 | 221 | // send push 222 | $apple_cert = '/certificates/samplepush/development.pem'; 223 | $message = '{"aps":{"alert":"Hi!","sound":"default"}}'; 224 | $token = 'c4942de20b30792b8f1e04c2f5488e05a24bf72f14f1fc849e6581faf957d8e1'; 225 | $http2_server = 'https://api.development.push.apple.com'; // or 'api.push.apple.com' if production 226 | $app_bundle_id = 'it.tabasoft.samplepush'; 227 | 228 | $status = sendHTTP2Push($http2ch, $http2_server, $apple_cert, $app_bundle_id, $message, $token); 229 | echo "Response from apple -> {$status}\n"; 230 | 231 | // close connection 232 | curl_close($http2ch); 233 | ``` 234 | 235 | ### 打完收工 236 | > 心得 APNS 真的坑 237 | > 重點是這個Server Certificates一年後就失效要renew ....fuck --------------------------------------------------------------------------------