11

Is there a way to force PHP to make a HTTP2 connection to another server just to see if that server supports it?

I've tried:

$options = stream_context_create(array(
               'http' => array(
                    'method' => 'GET',
                    'timeout' => 5,
                    'protocol_version' => 1.1
                )
              ));
$res = file_get_contents($url, false, $options);
var_dump($http_response_header);

And tried:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTP_VERSION, 3);
$response = curl_exec($ch);
var_dump($response);
curl_close($ch);

But both ways give me a HTTP1.1 response if I use the following URL https://www.google.com/#q=apache+2.5+http%2F2

I'm sending the request from a HTTP/2 + SSL enabled domain. What am I doing wrong?

Fidelity
  • 125
  • 1
  • 2
  • 8

1 Answers1

17

As far as I'm aware, cURL is the only transfer method in PHP that supports HTTP 2.0.

You'll first need to test that your version of cURL can support it, and then set the correct version header:

if (
    defined("CURL_VERSION_HTTP2") &&
    (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 && str_starts_with($response, "HTTP/2")) {
        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.";
}
miken32
  • 42,008
  • 16
  • 111
  • 154
  • Depending on your platform/versions, it might need a few tweaks to get it done, as it did with me: [https://stackoverflow.com/a/45110402/1005334] – kasimir Jul 14 '17 at 19:37
  • Any ideas why CLI requests such as `curl --http2 -I https://nghttp2.org/` do work in HTTP2 mode but when switching to PHP, they are sent as HTTP 1.1 instead? I've tested your code and it still doesn't work in HTTP2 mode. I have PHP 5.6 and curl 7.54. – andreszs Aug 03 '17 at 18:03
  • 1
    @Andrew Because the curl you’re using in the command line isn’t necessarily the same on that’s complied into PHP for its curl support. – miken32 Aug 03 '17 at 19:00
  • 2
    The minor version (2.0) was dropped from HTTP2. https://http2.github.io/faq/#is-it-http20-or-http2 – Ryre Nov 28 '18 at 17:03
  • Thanks for the edit @Ryre. This code will, of course, continue to work with older servers still sending "2.0" as well. – miken32 Nov 28 '18 at 20:13
  • The first line of this answer doesn't work. Should be `if ( !empty(@constant('CURL_VERSION_HTTP2')) ) {` – FoulFoot Dec 11 '20 at 14:17
  • @FoulFoot 1) the constant can be defined without the feature being available 2) don't use the error suppression operator, it's an ugly hack; use `defined()` to test 3) if you're running a PHP version so old that the constant isn't defined, you've got bigger problems than an undefined constant notice. – miken32 Dec 11 '20 at 16:48
  • I would suggest trying your code out on a client server that does not support HTTP/2, and you will see that it does not work. My correction does work. This isn't a function of old PHP, but old Apache -- which is much more common than Apache which supports HTTP/2. – FoulFoot Dec 11 '20 at 20:43
  • Well, don't know what to tell you. Running this on my server with PHP 7.3 results in this: `Warning: Use of undefined constant CURL_VERSION_HTTP2 - assumed 'CURL_VERSION_HTTP2' (this will throw an Error in a future version of PHP) in /home/server/public_html/test.php on line 10 Warning: Use of undefined constant CURL_HTTP_VERSION_2_0 - assumed 'CURL_HTTP_VERSION_2_0' (this will throw an Error in a future version of PHP) in /home/server/public_html/test.php on line 18 No HTTP/2 support on server.` At the very least, indicating that it didn't trigger the "else" clause. – FoulFoot Dec 12 '20 at 00:44
  • @FoulFoot ok when in doubt, go to the source. It looks like I was wrong about the constant always being defined; [there is a version check](https://github.com/php/php-src/blob/PHP-7.4.13/ext/curl/interface.c#L499) on the library done before the constant is defined. You can check your server's version with `echo curl_version()['version'];`. I've updated the code to check for the constant. Thanks for pushing back! – miken32 Dec 12 '20 at 01:33