simplexml_load_file()でタイムアウト指定できない問題の解決

WebページにRSSフィードを表示させるため、
PHP内で simplexml_load_file() を使ってRSSフィードを取得していたところ、
画面の応答が遅れる現象が発生しました。

調査したところ、フィード取得先のサーバが応答を返さずタイムアウトしているログを発見。

どのくらいでタイムアウトしたか確認すると、なんと simplexml_load_file() にはタイムアウト設定がありませんでした。

php.ini の ‘default_socket_timeout’ の値 x 2 がタイムアウト秒数となるようです。
‘default_socket_timeout’ は(デフォルトのまま) 60秒なので、応答が返らなかった場合、タイムアウトまで 120秒間も 処理できない状態となっていたようです。

スポンサーリンク

テスト用ファイルを用意しておく

30秒遅延させ、フィードを返すphpファイルをサーバに置いておきます。

sleep(30); // 30秒待ってから表示
echo '<?xml version='1.0' encoding='utf-8'?>
  <?rss>
   <?channel>
     <?item>
       <?link>http://example.com/mypage
       <?pubDate>Mon, 27 Jun 2011 19:34:00 +0100
     <?/item>
     <?item>
     <?/item>
   <?/channel>
  <?/rss>
';

simplexml_load_file()のタイムアウトを短くする

方法は3つあります。

default_socket_timeoutの値を変更

最も簡単です。

ini_set('default_socket_timeout', 5);
var_dump(simplexml_load_file('https://nijoen.net/xxx.php')); // テスト用ファイル

実際にタイムアウトする秒数は「default_socket_timeout」の2倍になります。
これ以外にもタイムアウトに影響する要素があるから、のようですが、よくわかりませんでした。
stackoverflow

実行してみると、5 x 2 = 10秒でタイムアウトしました。

simplexml_load_file(https://nijoen.net/xxx.php): failed to open stream: HTTP request failed!

stream_context_createを使用

手軽かつ真っ当な手法。
‘http’オプションは、httpsから始まるURLに対しても有効です。

$ctx = stream_context_create(['http'=>['timeout'=>5]]);
var_dump(file_get_contents('https://nijoen.net/xxx.php', false, $ctx));

curlを使用

長くなりますが、他の箇所とも統一でき、エラー処理もきちんとできます。

// curl
$ch = curl_init('https://news.yahoo.co.jp/pickup/rss.xml');
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );//データではなく文字列で返却
curl_setopt( $ch, CURLOPT_TIMEOUT, 5 );//タイムアウト(秒)

$res = curl_exec($ch);

if (! curl_errno($ch))
{
  if ( curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 200)
  {
    exit('エラー');
  }
}
curl_close($ch);

var_dump($res);

まとめ

取得できたら表示する、エラー処理も必要ない!という場合には「default_socket_timeout」が簡単。
それ以外であれば「curl」で実装しておけば問題なさそうです。

スポンサーリンク

シェアする

スポンサーリンク