[メモ] PHPのfile_get_contentsを、HTTPリクエストに使うときのTIPS

file_get_contentsにまつわるTIPS

$res = file_get_contents('http://example.com');

file_get_contentsはローカルのファイルパスだけでなく、URLを入れることでHTTPリクエストを送信することもできます。しかし、その仕様は奥深く難解であり、TIPSが数多く存在する関数でもあります。今回はそんなfile_get_contentsにまつわるTIPSをまとめてみます。

PHP5.3.3で確認していますが、大まかな挙動は他の5.x系でもそんなに変わらないはず。

仕様的なこと

2xx, 3xx以外のレスポンスボディを取得しない

HTTPステータスコードが204または304でなければレスポンスボディを含んでいる可能性があります。しかし、file_get_contentsは、2xx, 3xxのみ( それが204や304であっても! )ボディを返し、4xxや5xxではボディを返しません。

4xx, 5xxのステータスコードだとWarnningを発生させる

必要に応じて、file_get_contentsを使う場所の前後でエラーレベルを変更するか、@マークでエラーを抑制し、後述の方法でレスポンスヘッダーからステータスコードを読み込み分岐させるほうが良いでしょう。エラーを抑制した場合でも、レスポンスボディは取得できません。

レスポンスの取り扱い

レスポンスヘッダーは $http_response_header で取得できる

file_get_contentsを使用すると、$http_response_header という変数にレスポンスヘッダーが自動で格納されます。リクエスト直後にこの変数を参照すれば、ヘッダーを確認できます。この変数は、ローカルスコープに作成されます。

5.3.x以降であれば ignore_errorsでエラーを抑制しながら、レスポンスボディを取得できる

過剰なエラー反応や、2xx&3xx以外のレスポンスボディを取得しない問題は、PHP5.3系であればコンテキストにignore_errorsを与えることで解決します。

$context = stream_context_create(array(
      'http' => array('ignore_errors' => true)
 ));
$body = file_get_contents('http://example.com/', false, $context);

こうなっていると、4xxや5xxのステータスコードであってもWarnningを発生させず、本来のレスポンスボディが返ってくるようになります。

へんな使い方

実はPOSTメソッドも使える

散々既出な話ですが、file_get_contentsはコンテキストを詳細に設定することでPOSTメソッドでリクエストすることもできます。

$context = stream_context_create(array(
    "http" => array(
        'method'  => 'POST',
        'header'  => implode("\r\n", array(
             'Content-Type: application/x-www-form-urlencoded',
        )),
        'content' => http_bulid_query(array(
             'foo' => 'bar',
             'hoge'     => 'fuga',
        )),
    )
));
$res = file_get_contents('http://example.com/', false, $context);

トラブルシューティング

HTTPS周りで不自然なエラーがでるときはエラーを抑制

PHP: file_get_contents - Manual

IIS のような、いくつかの標準に 対応してない Web サーバは、PHP に警告を発生させるような手順でデータを送信します。 このようなサーバを使用する場合は、error_reporting を警告を発生しないレベルまで小さくする必要があります。 PHP 4.3.7 以降では、https:// ラッパーでストリームをオープンする際に バグがある IIS サーバソフトウエアを検出することができ、この警告を抑制することができます。 あなたが ssl:// ソケットを作成するために fsockopen() を使用している場合、 自らこの警告を検出し、抑制する必要があります。

ボディは取得できるので、file_get_contents自体はエラーを抑制し、レスポンスヘッダーを元にエラー処理を切り分けて実装するのが望ましいんじゃないでしょうか。

根本的に動作しないときはallow_url_fopenがOnか確認

file_get_contentsでURLを直接開く場合は、allow_url_fopenディレクティブがONになっている必要があります。共用サーバーなどで、よほど意図した設定がされていなければ、あまり気にするところではありません。

allow_url_fopen = On

参考