简体   繁体   中英

PHP7, HTTP2 with cURL

I got error message when I send push message to APNs via PHP7+cURL.

error message:

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

I guess it's because of PHP7 but not very sure. with phpinfo() I can see that no mod_ssl loaded but from Internet it says PHP7 support ssl by nature so openssl.so is not existed in system any more. Also it's strange with phpinfo() I saw the openssl version is 1.0.1e which is coming with redhat7, not the one I installed from source.

I installed php7 by yum, and the rest, openssl, nghttp, curl installed from source.

Php code:

$ch = curl_init();

curl_setopt($ch, CURLOPT_HTTP_VERSION, 3);
//curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $alert);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("apns-topic: $apns_topic"));
curl_setopt($ch, CURLOPT_SSLCERT, $pemfile);
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $pempwd);
$response = curl_exec($ch);

The server is REDHAT 7. The environment info can be found as below.

$ openssl version
OpenSSL 1.0.2g  1 Mar 2016

curl --version
curl 7.48.0 (x86_64-pc-linux-gnu) libcurl/7.48.0 OpenSSL/1.0.2g nghttp2/1.9.2
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: IPv6 Largefile NTLM NTLM_WB SSL TLS-SRP HTTP2 UnixSockets 

$ php --version
PHP 7.0.5 (cli) (built: Apr  2 2016 13:08:13) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies

$ curl --http2 -I https://nghttp2.org
HTTP/2.0 200
date:Sun, 17 Apr 2016 13:15:27 GMT
content-type:text/html
last-modified:Sat, 16 Apr 2016 14:56:04 GMT
etag:"57125284-1a0a"
accept-ranges:bytes
content-length:6666
x-backend-header-rtt:0.001459
strict-transport-security:max-age=31536000
server:nghttpx nghttp2/1.10.0-DEV
via:2 nghttpx
x-frame-options:SAMEORIGIN
x-xss-protection:1; mode=block
x-content-type-options:nosniff

Even I can use command line to send push message to my phone:

curl -d '{"aps":{"alert":"test message","sound":"default"}}' --cert /xxx/xxx.pem:xxxx -H "apns-topic:chs.itsme" --http2 https://api.development.push.apple.com/3/device/85f0257xxxxx

I have been a same issue and found out the main reason is a certifcate of the root CA .

The below is my env:

  • curl : 7.48
  • openssl : 1.0.2g
  • php : 5.6.18

Why?

The main reason is a certifcate. Especially, a certifcate of the root CA. The error might be occur when it is not existed or has a wrong path in your system.

And you need to know how to work CURLOPT_SSL_VERIFYPEER about this issue. If you undefine CURLOPT_SSL_VERIFYPEER option, it will have a default value, true. This options enables to verify the endpoint host ssl certificate to avoid a security issue, such as man in the middle attack. And it uses a certificate of the root CA installed your system during the verification process.

solution 1

Check out or install a certificate of the root CA. Generally, it is installed with an openssl. If you met an error message, it will have not installed in the appropriate path or existed.

So, check out the file with the following command.

$ php -r "var_dump(openssl_get_cert_locations());"

an example of the result :

array(8) {
  ["default_cert_file"]=>
  string(38) "/usr/local/openssl-1.0.2g/ssl/cert.pem"
  ["default_cert_file_env"]=>
  string(13) "SSL_CERT_FILE"
  ["default_cert_dir"]=>
  string(35) "/usr/local/openssl-1.0.2g/ssl/certs"
  ["default_cert_dir_env"]=>
  string(12) "SSL_CERT_DIR"
  ["default_private_dir"]=>
  string(37) "/usr/local/openssl-1.0.2g/ssl/private"
  ["default_default_cert_area"]=>
  string(29) "/usr/local/openssl-1.0.2g/ssl"
  ["ini_cafile"]=>
  string(0) ""
  ["ini_capath"]=>
  string(0) ""
}

In the above, the default cert file path is "/usr/local/openssl-1.0.2g/ssl/cert.pem". Would you have a certificate of the root CA in there? If you have it but located in the different path, move it to the default cert file path with filename "cert.pem". If you don't have it, you need to download it, such as http://curl.haxx.se/ca/cacert.pem .

$ wget http://curl.haxx.se/ca/cacert.pem

then move it in the default cert file path.

solution 2

CURLOPT_SSL_VERIFYPEER => false

This option can solve your problem. But it is possible to exposure your system against the man in the middle attack.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM