ローカル環境でfile_get_contentsがタイムアウト

はじめに

PHPの関数file_get_contents、とても手軽なのでよく使ってしまいますが、たまにうまく動いてくれない時があります。今回は取得先のURLからのレスポンスが返ってこず、タイムアウトしてしまったので、解決方法をメモしておきます。

経緯

具体的には、ローカル(docker)のPHP環境でのサイト制作で、Googleのサービス「reCAPTCHA」を実装中、判定結果を受け取るために、reCAPTCHAのAPIにfile_get_contents()した時にタイムアウトが発生。

原因

不明。いろいろ調べてみましたが、はっきりとした原因にはたどり着けませんでした。

同じコードを本番サーバ上で実行すると問題は起きないので、ローカル環境に問題がありそうですが、Google側で何かしらの規制をしているのか、はたまたfile_get_contentsの仕様の可能性も。

解決方法

原因はわからなかったものの、解決方法が2つのほどあったので載せておきます。自分はその2の方で対処しました。

その1

file_get_contentsのタイムアウト時間を設定する。

$context = stream_context_create([
    'http' => [
        'ignore_errors' => true,
        'timeout' => 5
    ]
]);
$url = 'https://xxxxxx';
$res = file_get_contents($url, false, $context);

上記のようにfile_get_contentsの第3引数にコンテキストでタイムアウト時間を設定する。ignore_errorsの指定はなくても結果は変わらなかったが、エラーを無視するために一応入れてあります。

勝手な考察

多分、file_get_contents内で何らかのエラーによって処理が止まってしまっている。取得先URLからのレスポンス自体は受け取っているが、処理が止まっていて返ってこない。なのでタイムアウト設定で無理やり返させる。

タイムアウトを設定しない場合、PHP側のタイムアウト(デフォルト60s)でエラーとなる。PHP側がエラーを吐く前にfile_get_contents側でタイムアウトさせてレスポンスを受け取るという感じ。

その2

file_get_contentsはあきらめてcURLを使う。

できればfile_get_contentsで解決したかったが、根本的な解決方法がわからなかったので、素直にcurlを使うことにしました。

function file_get_contents_curl($url)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 文字列で受け取る
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

$url = 'https://xxxxxx';
$res = file_get_contents_curl($url);

file_get_contentsライクに使いたかったので自作関数を作っています。

curlにはオプションがたくさんありますが、上記のコードは最低限のオプションのみです。取得先に合わせてカスタマイズしてください。

まとめ

原因がわからずスッキリしない結果となりましたが、そもそもcurlの方が有能なのでトラブルを避けるためにも極力curlを使った方が良いのかもしれませんね。

原因・対処法わかる方がいたら教えてもらえると助かります。よろしくお願いします😅