PHPで複数のURLを404チェックする関数の速度比較
amazonのAPIなんかを利用して画像のパスを取得し保存していると稀に画像が削除されてしまってる事がある。
毎回、amazonのAPIを叩く様にしてもいいかもしれないけど頻繁にアクセスするとamazonに怒られるかもしれない。
そこで、ファイルが存在するかチェックする事にしたのだけどPHPには色々関数があるのでそれぞれチェックしてみた。
まずはPHPで外部ファイルを読むという事に関しては一番メジャーな「file_get_contents」。
if (!$data = @file_get_contents($url)) echo '無いよ';
その次にローカルファイルの読み書きによく使うが実が外部ファイルも読める「fopen」。
if (!$fp = @fopen($url, "r")) echo '無いよ';
PHP5から使える様になったHTTPヘッダー読み用関数「get_headers」。
$header = @get_headers($url);
if(strpos($header[0], '404') !== false) echo '無いよ';
これもPHP5から使える様になった強力な関数「CURL」
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, TRUE); // ヘッダーあり
curl_setopt($ch, CURLOPT_NOBODY, TRUE); // 本文なし
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // 返答はテキストで
curl_setopt($ch, CURLOPT_TIMEOUT, 2); // タイムアウト
$res = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode == 404) echo '無いよ';
そして、複数のアドレスに一気にアクセス出来る本命の「curl Multi」
$mh = curl_multi_init();
$ch_list = array();// Curlハンドル
foreach($urls as $mykey => $url) {
$ch_list[$mykey] = curl_init($url);
curl_setopt($ch_list[$mykey], CURLOPT_HEADER, TRUE);
curl_setopt($ch_list[$mykey], CURLOPT_NOBODY, TRUE);
curl_setopt($ch_list[$mykey], CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch_list[$mykey], CURLOPT_TIMEOUT, 2);
curl_multi_add_handle($mh, $ch_list[$mykey]);
}
$running = null;
do { curl_multi_exec($mh, $running); } while ( $running );
foreach($urls as $mykey => $url) {
$httpCode = curl_getinfo($ch_list[$mykey], CURLINFO_HTTP_CODE);
if ($httpCode == 404) echo '無いよ';
curl_multi_remove_handle($mh, $ch_list[$mykey]);
curl_close($ch_list[$mykey]);
}
curl_multi_close($mh);
※socketでもいけそうな気がしたがうまく動かなかったのでパスした。
10コのurlをチェックするスクリプトを5回計測して平均を出した。
curl Multi 0.014秒
curl 0.105秒
get_headers 0.161秒
fopen 0.162秒
file_get_contents 0.278秒
一位のcurl Multiの高速さが目立つもっと個数が増えるともっと差は拡がりそうだ。
amazonは色んなステータスコードを吐き200と404はわかり易いが、ちょっと詰まる(混んでる)と403を吐きこの場合ファイルがあるのか無いのか分からないと言う問題がある。
これを踏まえると、比較的アクセスの少ない時間帯にササッとチェックするならcurl Multiで時間を選ばずチェックするならfopenを使うのが安全な気もする。
Tags: PHP
[…] PHPで複数のURLを404チェックする関数の速度比較 […]