新的 APNS 提供程序 API 和 PHP

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34684099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 00:09:42  来源:igfitidea点击:

New APNS Provider API and PHP

phpiosiphoneapple-push-notifications

提问by Ben Holness

I started creating some code based upon thisfor sending push notifications from PHP.

我开始基于创建一些代码,用于从 PHP 发送推送通知。

However now that I have understood there is a new API which utilizes HTTP/2 and provides feedback in the response, I am trying to figure out what I need to do to get that feedback.

但是,现在我知道有一个新的 API 使用 HTTP/2 并在响应中提供反馈,我试图弄清楚我需要做什么才能获得该反馈。

I haven't been able to find any tutorials or sample code to give me direction (I guess because it is so new).

我一直找不到任何教程或示例代码来给我指导(我猜是因为它太新了)。

Is it possible to use the stream_socket_client()method of connecting to APNS with the new provider API? How do I get the feedback? All I get back from fwrite($fp, $msg, strlen($msg))right now is a number. For all intents and purposes, you can consider my code the same as the code from the SO question I based my code on

是否可以使用stream_socket_client()通过新的提供程序 API 连接到 APNS的方法?我如何获得反馈?我fwrite($fp, $msg, strlen($msg))现在得到的只是一个数字。出于所有意图和目的,您可以将我的代码视为与基于我的代码的 SO 问题中的代码相同

Thanks!

谢谢!

回答by tiempor3al

With the new HTTP/2 APNS provider API, you can use curl to send push notifications.

使用新的 HTTP/2 APNS 提供程序 API,您可以使用 curl 发送推送通知。

EDIT

编辑

Before proceeding (as noted by @Madox), openssl >= 1.0.2e of should be installed (from package preferably). Verify with the command

在继续之前(如@Madox 所述),应安装 openssl >= 1.0.2e 的(最好从软件包中)。用命令验证

openssl version

a) Your version of PHP should be >= 5.5.24 so that the constant CURL_HTTP_VERSION_2_0 is defined.

a) 您的 PHP 版本应该 >= 5.5.24,以便定义常量 CURL_HTTP_VERSION_2_0。

b) Make sure that you have curl version 7.46+ installed in your system with

b) 确保您的系统中安装了 curl 7.46+ 版本

curl --version

c) Curl should have http/2 support enabled. In the output when typing the previous command, you should see a line like this one:

c) Curl 应该启用 http/2 支持。在输入上一个命令时的输出中,您应该看到如下一行:

Features: IDN IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets 

if HTTP2 doesn't show up, you can follow this excellent tutorial to install http/2 for curl https://serversforhackers.com/video/curl-with-http2-support

如果 HTTP2 没有出现,你可以按照这个优秀的教程为 curl 安装 http/2 https://serversforhackers.com/video/curl-with-http2-support

Verify that curl detected openssl >= 1.0.2e, doing curl --version should output something like this:

验证 curl 检测到 openssl >= 1.0.2e,执行 curl --version 应该输出如下内容:

curl 7.47.1 (x86_64-pc-linux-gnu) libcurl/7.47.1 OpenSSL/1.0.2f zlib/1.2.8 libidn/1.28 nghttp2/1.8.0-DEV librtmp/2.3

e) Once you everything installed, you can test it in the command line:

e) 安装完所有内容后,您可以在命令行中对其进行测试:

curl -d '{"aps":{"alert":"hi","sound":"default"}}' \ 
--cert <your-certificate.pem>:<certificate-password> \ 
-H "apns-topic: <your-app-bundle-id>" \ 
--http2  \ 
https://api.development.push.apple.com/3/device/<device-token>

f) Here is a sample code in PHP that I have successfully tried:

f) 这是我成功尝试过的 PHP 示例代码:

if(defined('CURL_HTTP_VERSION_2_0')){

    $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';


    $sample_alert = '{"aps":{"alert":"hi","sound":"default"}}';
    $url = "https://api.development.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);

    //On successful response you should get true in the response and a status code of 200
    //A list of responses and status codes is available at 
    //https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH107-SW1

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

}

回答by Madox

I want to add some information to tiempor3al answer.

我想在 tiempor3al 答案中添加一些信息。

1) curl must be compiled with openssl version >=1.0.2 to fully support http/2. I receive "?@@?HTTP/2 client preface string missing or corrupt..." error when I compiled it with CentOS stock openssl-1.0.1e.

1)curl必须用openssl版本>=1.0.2编译才能完全支持http/2。当我使用 CentOS 股票 openssl-1.0.1e 编译它时,我收到“?@@?HTTP/2 客户端前言字符串丢失或损坏...”错误。

2) if your version of php module mod_curl.so compiled without CURL_HTTP_VERSION_2_0 constant, you could replace it with integer number 3:

2) 如果你的 php 模块 mod_curl.so 版本没有 CURL_HTTP_VERSION_2_0 常量编译,你可以用整数 3 替换它:

curl_setopt($ch, CURLOPT_HTTP_VERSION, 3);

curl_setopt($ch, CURLOPT_HTTP_VERSION, 3);

回答by valfer

I could successfully send push via HTTP2 using php CURL and read the feedback directly in the response body (here I wrote a short tutorial on how to do this: Sending Push Notification with HTTP2 (and PHP)). I think that you can check the response body reading from the socket (I don't remember exactly the php function, perhaps "fgets").

我可以使用 php CURL 通过 HTTP2 成功发送推送并直接在响应正文中读取反馈(在这里我写了一个关于如何执行此操作的简短教程:使用 HTTP2(和 PHP)发送推送通知)。我认为您可以检查从套接字读取的响应正文(我不记得确切的 php 函数,也许是“fgets”)。

回答by Samo

I'm using CentOS 6 and the way to solve was to install from source cURL and OpenSSL.

我正在使用 CentOS 6,解决方法是从源 cURL 和 OpenSSL 安装。

It may look very simple but it took me 3 days to figure out the right configuration for the packages so I think I can help someone by posting what I did here.

它可能看起来很简单,但我花了 3 天的时间来找出包的正确配置,所以我想我可以通过在这里发布我所做的来帮助某人。

It proved a little tricky for me since I'm not used to install packages from source, but I now can connect to APNs using HTTPS over HTTP/2.

事实证明这对我来说有点棘手,因为我不习惯从源代码安装软件包,但我现在可以通过 HTTP/2 使用 HTTPS 连接到 APN。

The details of what I did is here:

我所做的细节在这里:

  1. Download and uncompress cURL and OpenSSL:

    wget https://curl.haxx.se/download/curl-7.47.1.tar.gz
    wget https://www.openssl.org/source/openssl-1.0.2h.tar.gz
    
  2. Configure OpenSSL with the following flags (I'm not sure what they do, but is what worked for me):

    export CXXFLAGS="$CXXFLAGS -fPIC"
    ./config zlib enable-ssl3 enable-shared
    
  3. make and install OpenSSL

  4. Configure cURL with the following flag:

    ./configure --with-ssl=/usr/local/ssl/
    
  5. Make and install cURL

  6. set LD_LIBRARY_PATH to /usr/local/ssl/lib/

    export LD_LIBRARY_PATH=/usr/local/ssl/lib/                  
    
  7. Test

    /usr/local/bin/curl -v -d '{"aps":{"alert":"hi","sound":"default"}}' --cert cert.crt --key cert.key -H "apns-topic: topics" --http2 https://api.development.push.apple.com:443/3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
    
  1. 下载并解压 cURL 和 OpenSSL:

    wget https://curl.haxx.se/download/curl-7.47.1.tar.gz
    wget https://www.openssl.org/source/openssl-1.0.2h.tar.gz
    
  2. 使用以下标志配置 OpenSSL(我不确定它们是做什么的,但对我有用):

    export CXXFLAGS="$CXXFLAGS -fPIC"
    ./config zlib enable-ssl3 enable-shared
    
  3. 制作并安装 OpenSSL

  4. 使用以下标志配置 cURL:

    ./configure --with-ssl=/usr/local/ssl/
    
  5. 制作和安装 cURL

  6. 将 LD_LIBRARY_PATH 设置为 /usr/local/ssl/lib/

    export LD_LIBRARY_PATH=/usr/local/ssl/lib/                  
    
  7. 测试

    /usr/local/bin/curl -v -d '{"aps":{"alert":"hi","sound":"default"}}' --cert cert.crt --key cert.key -H "apns-topic: topics" --http2 https://api.development.push.apple.com:443/3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
    

The result:

结果:

*   Trying 17.172.238.203...
* Connected to api.development.push.apple.com (17.172.238.203) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=api.development.push.apple.com; OU=management:idms.group.533599; O=Apple Inc.; ST=California; C=US
*  start date: Jun 19 01:49:43 2015 GMT
*  expire date: Jul 18 01:49:43 2017 GMT
*  subjectAltName: host "api.development.push.apple.com" matched cert's "api.development.push.apple.com"
*  issuer: CN=Apple IST CA 2 - G1; OU=Certification Authority; O=Apple Inc.; C=US
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* TCP_NODELAY set
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x1091110)
> POST /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0 HTTP/1.1
> Host: api.development.push.apple.com
> User-Agent: curl/7.48.0
> Accept: */*
> apns-topic: topics
> Content-Length: 40
> Content-Type: application/x-www-form-urlencoded
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
* We are completely uploaded and fine
< HTTP/2.0 400
<
* Connection #0 to host api.development.push.apple.com left intact
{"reason":"BadDeviceToken"}

As you can see, I got rid of the ugly

如你所见,我摆脱了丑陋

?@@?HTTP/2 client preface string missing or corrupt. Hex dump for received bytes: 504f5354202f332f6465766963652f746573742048545450

回答by Norbert

To resolve HTTP/2 client preface string missing or corrupterrors in PHP 5.6 I created an Apacheand CLIPHP Docker image that you might want to rely on or just look up what I did in the Dockerfile to build your own. Same can probably apply to PHP 7.0 although I haven't tried.

为了解决HTTP/2 client preface string missing or corruptPHP 5.6 中的错误,我创建了一个ApacheCLIPHP Docker 映像,您可能想要依赖它,或者只是查找我在 Dockerfile 中所做的来构建自己的映像。尽管我还没有尝试过,但同样可能适用于 PHP 7.0。

回答by KeranMarinov

Follow this guide [http://cloudfields.net/blog/ios-push-notifications-encryption/][1]to generate and merge your certificate and private key. Once you merge and your sslcert and pkey as described in the guide with same file names, just try the curl command below.

按照本指南 [ http://cloudfields.net/blog/ios-push-notifications-encryption/][1]生成并合并您的证书和私钥。按照指南中的说明合并您的 sslcert 和 pkey 并使用相同的文件名后,只需尝试下面的 curl 命令。

curl -X POST -H 'apns-topic: com.mycompany.ios.BadassApp' -d '{"aps":{"content-available":1,"alert":"hi","sound":"default"}}' --cert apns_cert.pem:yourCertPassword --http2 'https://api.development.push.apple.com:443/3/device/b8de1sf067effefc398d792205146fc67dn0e96b0ff21ds81cabe384bbe71353'

回答by Roman Laptev

yes, it's possible:

是的,这是可能的:

$errno=0;$errstr="";
$sock = stream_socket_client(
  "api.push.apple.com:443",
  $errno,
  $errstr,
  4,
  STREAM_CLIENT_CONNECT,
  stream_context_create(["ssl" => ["local_cert" => "/path/to/cert.pem","verify_peer"=>false,"verify_peer_name"=>false]])
);
stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);