PHP 7.1:HTTP/2 没有 cURL

PHP 7.1: no cURL with HTTP/2

我的问题不是查明服务器是否支持 HTTP/2(他们都支持),而是如何确保 PHP 使用 HTTP/2 CentOS 中最新 PHP 版本的正确 cURL 设置(从 Remi 的存储库构建)。我自己的回答解决了一些与此有关的奇怪之处。

我已经设置我的 CentOS 7 服务器以支持 HTTP/2 借助这个很好的指南:Setting up HTTP/2 on your web server

所以我得到了最新版本,编译并安装了它们,一切正常。页面以 HTTP/2 headers 提供,完全按照它们应有的方式提供。

现在我想在我的 PHP 脚本中使用 HTTP/2 功能。主要是通过 HTTP/2 方式进行 cURL 调用。我发现我需要升级 libcurl 并使用特定的 HTTP/2 支持来构建和编译它。经历了一些挫折,我成功了。

所以 curl -V 告诉我:

curl 7.55.0-DEV (x86_64-unknown-linux-gnu) libcurl/7.55.0-DEV OpenSSL/1.1.0f zlib/1.2.7 nghttp2/1.23.1
Release-Date: [unreleased]
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 libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy 

太棒了!

phpinfo()结合新安装的OpenSSL给我相同的版本(7.55.0-DEV),即:

OpenSSL 1.1.0f 25 May 2017

还有 Apache,顺便说一句:

Server version: Apache/2.4.26 (Unix)
Server built:   Jul  7 2017 09:47:22

但是,当我使用 cURL 调用编写一个简单的 PHP 脚本并将 CURLOPT_HTTP_VERSION 选项设置为 CURL_HTTP_VERSION_2_0 时,如本例所述:,它告诉我服务器没有 HTTP/2 支持...

怎么会这样?

我注意到的一件事是 phpinfo() 中关于 OpenSSL 模块的部分仍然提到了我的旧 OpenSSL 版本(OpenSSL 1.0.1e-fips),尽管 OpenSSL-version 提到了 cURL 模块声明 OpenSSL 1.1.0f.

我已经从 Remi 的存储库安装了 PHP 7.1(目前版本为 7.1.7),它是否是针对旧的 OpenSSL 版本构建的,所以它不能与我的新版本一起使用?我还阅读了 PHP 7 中的支持,因为 HTTP/2 不是很明显,但我想这应该不是问题,对吗?

或者 OpenSSL 不是问题所在,我应该看看其他地方,也许从带有一些预期标志的源代码编译 PHP?

我存储库中的包是针对标准基本存储库构建的,因此 OpenSSL 1.0.1e 和 Curl 7.29.0(使用 NSS)。

所以你必须重建所有使用这些库的东西来利用新功能(包括PHP)

经过一些摆弄,我似乎 可以 通过 PHP cURL 调用 Remi 的 PHP 包和一个 HTTP/2 得到一个响应新建 cURL/OpenSSL.

我正在使用这段代码进行测试(摘自):

if (curl_version()["features"] & CURL_VERSION_HTTP2 !== 0) {
    $url = "https://www.google.com/";
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            =>$url,
        CURLOPT_HEADER         =>true,
        CURLOPT_NOBODY         =>true,
        CURLOPT_RETURNTRANSFER =>true,
        CURLOPT_HTTP_VERSION   =>CURL_HTTP_VERSION_2_0,
    ]);
    $response = curl_exec($ch);
    if ($response !== false && strpos($response, "HTTP/2.0") === 0) {
        echo "HTTP/2 support!";
    } elseif ($response !== false) {
        echo "No HTTP/2 support on server.";
    } else {
        echo curl_error($ch);
    }
    curl_close($ch);
} else {
    echo "No HTTP/2 support on client.";
}

所需的调整是:

CURLOPT_HTTP_VERSION => 3

...和:

if ($response !== false && strpos($response, "HTTP/2") === 0)

因此,我在 cURL 选项中使用了 3,而不是 CURL_HTTP_VERSION_2_0 作为 HTTP 版本,这应该意味着相同,但显然 PHP 在使用 CURL_HTTP_VERSION_2_0.

查看这给出的原始响应,我注意到 Google 正在发回 HTTP/2 而不是 HTTP/2.0

希望对大家有所帮助!