Search code examples
phphttpshttp-headershttp2

How to detect if a site supports HTTP/2 in PHP


Is there a simple way in PHP to test if a URL supports HTTP/2? I tried checking for connection upgrade or h2 in curl_setopt($curl, CURLOPT_HEADER, true) as per HTTP/2 identification in the specs . There are many sites where you can add a URL and it will tell if the site supports HTTP/2 or not. Just wondering how they are testing it and if something similar can be done in PHP. On command line I can do something like $ curl -vso --http2 https://www.example.com/


Solution

  • Update 2021-02-25:
    As mentioned by djdance, HTTP/2.0 has been HTTP/2 for some time now. Therefore, you should really check against HTTP/2 (and HTTP/3 for the upcoming HTTP 3).

    If you do not want to use strpos, you can now also use str_starts_with($response, "HTTP/2") when using PHP 8. Otherwise you can use substr($response, 0, 6) === "HTTP/2" for PHP 7.

    For PHP 7.3 and cURL 7.50.0, curl_getinfo now also supports CURLINFO_HTTP_VERSION:

    echo curl_getinfo($ch, CURLINFO_HTTP_VERSION);
    // 3 for HTTP/2
    

    The values which may be returned by CURLINFO_HTTP_VERSION (as of PHP 7.3):

    CURL_HTTP_VERSION_NONE              === 0
    CURL_HTTP_VERSION_1_0               === 1
    CURL_HTTP_VERSION_1_1               === 2
    CURL_HTTP_VERSION_2                 === 3
    CURL_HTTP_VERSION_2_0               === 3
    CURL_HTTP_VERSION_2TLS              === 4
    CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE === 5
    

    This means you can check for a specific (e.g., CURL_HTTP_VERSION_2TLS, which is HTTP/2 over TLS):

    if (
        $response !== false
        && curl_getinfo($ch, CURLINFO_HTTP_VERSION) === CURL_HTTP_VERSION_2TLS
    ) {
        // The connection was established using HTTP/2 over TLS
        // if the server does not support TLS HTTP/1.1 will be used.
    }
    

    Original:
    Both your server and your installation of cURL need to support HTTP/2.0. After that you can just make a normal cURL request and add the CURLOPT_HTTP_VERSION parameter which will make cURL try to make an HTTP/2.0 request. After that you'll have to check the Headers from the request to check if the server does indeed support HTTP/2.0.

    Example:

    $url = "https://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, // cURL will attempt to make an HTTP/2.0 request (can downgrade to HTTP/1.1)
    ]);
    $response = curl_exec($ch);
    

    Now you'll need to check if cURL did indeed make an HTTP/2.0 request:

    if ($response !== false && strpos($response, "HTTP/2.0") === 0) {
        echo "Server of the URL has HTTP/2.0 support."; // yay!
    } elseif ($response !== false) {
        echo "Server of the URL has no HTTP/2.0 support."; // nope!
    } else {
        echo curl_error($ch); // something else happened causing the request to fail
    }
    curl_close($ch);