ストリームコンテキストでHTTPの細かい設定を渡す

ストリームコンテキストとは、stream_context_create で作る通信設定です。これを渡すと file_get_contents にメソッドやヘッダ、ボディ、タイムアウトを指定できます。

file_get_contentsにヘッダやメソッドを足す

ちょっとした API 呼び出しなら curl を持ち出さず file_get_contents() で済ませたいことがあります。とはいえ素のままだと GET しか投げられず、ヘッダも付けられません。そこで stream_context_create() でコンテキストを作って渡すと、メソッドやヘッダ、ボディまで指定できます。

$context = stream_context_create([
    'http' => [
        'method'  => 'POST',
        'header'  => "Content-Type: application/json\r\n"
                   . "Authorization: Bearer {$token}\r\n",
        'content' => json_encode(['name' => '田中']),
    ],
]);

$body = file_get_contents('https://api.example.com/users', false, $context);

複数ヘッダは \r\n で連結するか、配列で渡してもいいです。個人的には配列のほうが読みやすい気がします。

タイムアウトを必ず設定する

外部への通信でいちばん怖いのは、相手が固まったときに自分まで巻き込まれることです。timeout を指定しないと default_socket_timeout(既定 60 秒)まで待ってしまうので、明示しておくのが無難ですね。あと、4xx/5xx でも例外は飛ばず警告になるだけなので、ignore_errors を立ててステータスは自分で見る形にしています。

$context = stream_context_create([
    'http' => [
        'method'        => 'GET',
        'timeout'       => 5,      // 秒
        'ignore_errors' => true,   // 4xx/5xx でも本文を取る
    ],
]);

$body = @file_get_contents($url, false, $context);

レスポンスのステータスを読む

ステータス行やヘッダは、リクエスト後にセットされる $http_response_header という特殊変数に入っています。関数のスコープに現れるので、うっかり見落としがちなのですが、ここを見ないと成功判定ができません。

$body = @file_get_contents($url, false, $context);

// 直近リクエストのヘッダがここに入る
$status = $http_response_header[0] ?? '';
if (!preg_match('#\s(2\d\d)\s#', $status, $m)) {
    throw new RuntimeException("HTTP error: {$status}");
}

本格的な用途なら curl や Guzzle に寄せますが、小さなスクリプトではこの手軽さがちょうどいいと思います。

まとめ

ストリームコンテキストを使えば file_get_contents() でもメソッド・ヘッダ・ボディを扱えて、curl なしでそれなりの HTTP 通信ができます。ただしタイムアウトの明示と、$http_response_header でのステータス確認は忘れないようにしたいところ。ここを押さえておかないと、失敗しても気づけない静かなバグになりがちですね。

よくある質問

Q. file_get_contents で POST できますか?
A. できます。stream_context_createmethod を POST にし、headercontent を指定して第3引数に渡します。

Q. タイムアウトは設定すべきですか?
A. すべきです。指定しないと default_socket_timeout(既定60秒)まで待つので、timeout を明示しておくと相手が固まっても巻き込まれにくいです。

Q. レスポンスのステータスはどこで見ますか?
A. リクエスト後に $http_response_header という特殊変数に入ります。4xx/5xx でも例外は飛ばないので、ここを見て自分で成功判定します。

類似投稿

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です