ストリームコンテキストで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_create で method を POST にし、header と content を指定して第3引数に渡します。
Q. タイムアウトは設定すべきですか?
A. すべきです。指定しないと default_socket_timeout(既定60秒)まで待つので、timeout を明示しておくと相手が固まっても巻き込まれにくいです。
Q. レスポンスのステータスはどこで見ますか?
A. リクエスト後に $http_response_header という特殊変数に入ります。4xx/5xx でも例外は飛ばないので、ここを見て自分で成功判定します。