😽

【PHP】file_get_contents の HTTP/2 対応について考えてみた

2024/07/11に公開

file_get_contents の HTTP/2 対応について考えてみた。コンテキストで指定できるようにするとしたら次のようになるだろう

// ALPN(Application-Layer Protocol Negotiation) で h2 が提示された場合 HTTP/2 通信を選ぶ
$ctx = stream_context_create(['http'=> ['protocol_version'=>'2.0']]);
$ret = file_get_contents('https://example.com', false, $ctx);
// リクエスト先が HTTP/2 であることをわかっている場合 
$ctx = stream_context_create(['http'=> ['http2_prior_knowledge'=> true]]);

HTTP/2 実装のパターンとして curl や nghttp2 などの外部ライブラリに丸投げするのか HPack だけ外部ライブラリに依存してほかの処理は自前でつくるということが考えられる。

標準関数が curl に依存する案に違和感を感じるかもしれないが、curl エクステンションよりも手軽に使えるメリットがある。ちょっとしたリクエストを送信するのに次のようなコードを毎回コピペするのはめんどうだろう。

$url = 'https://example.com/';
$opts = [
    CURLOPT_HTTP_VERSION   =>CURL_HTTP_VERSION_2_0,
    CURLOPT_URL            => $url,
    CURLOPT_HEADER         => true,
    CURLOPT_NOBODY         => true,
    CURLOPT_RETURNTRANSFER => true,   
];

$ch = curl_init();
curl_setopt_array($ch, $opts);
$res = curl_exec($ch);

curl と比べると file_get_contents のほうはエラー情報が少ないのと、HTTP/2 のほうがいろいろデバッグが大変なので、エラー情報表示の改善も必要になるだろう。Go の net/http では 環境変数 GODEBUG=http2debug=2 を設定することでいろいろなログが表示されるようになる。

file_get_contents の HTTP/2 対応だけ考えるのであれば HPACK だけ外部ライブラリを使うパターンが妥当に思える。JavaScript 実行環境の Bun は LS-HPACK (LiteSpeed HPACK) を採用して、HTTP/2 クライアントに対応している。

nghttp2 は curl、Node.js、Apache mod_http2 や Swoole/Open Swoole などさまざまなプロジェクトで実績がある。nghttp2 を導入するのであれば、ビルトインサーバーの HTTP/2 対応やほかの PHP 開発者が HTTP/2 クライアントやサーバーを開発しやすくするための API の開発も考えるべきだろう。たとえば HTTP/2 フレームをあらわすクラスやフレームをパースするクラスを用意することが考えられる。

Discussion