PHPのfile_get_contentsをcURLへ置き換える
PHPのfile_get_contents関数ってチョー手軽でチョー便利ですよね。
$html = file_get_contents('test.txt');
こんな風にファイル名を指定するだけで全部読み込んでくれるし。
$html = file_get_contents('https://blog.ver001.com/');
こんな風にURL指定することでWebサイトのHTMLだって簡単に読み込んでくれます。
また、以前の記事「Windows版PHPでSFTP接続するにはphp_ssh2.dllが必要」で書いたとおり、FTP接続だってSFTP接続だって使えます。
でも、そんな素敵なfile_get_contentsですが…
file_get_contentsよりcURLのほうが速い?
元々はPHPで非同期処理が出来ないかなぁーと調べていたんです。
ほら、例えばRSSフィードとか、数十個のサイトを巡回するのにループして1つ1つ読み込み待ちをするのって無駄じゃないですか。サイトごとにコンテンツ量も回線の太さも違うわけですから、一度に数十個のリクエストだけ送って、返ってきた順に処理するほうが効率的です。
まぁ最悪、system関数やpopen関数でPHPコマンド自体をキックして、10個くらいのプロセスを同時に走らせても良いかなぁとも思ったのですが、どうやらcurl関数で非同期処理できるというじゃないですか。
それで使い方をちょっと調べていたのですが、どのページでもfile_get_contentsよりもcURLのほうが速い、というのです。
非同期のことはすっかり頭から抜けて脱線して調べはじめてしまいました。
cURLの使い方
fopen関数がfopen~fread~fcloseと手順を踏むように、curlも
- curl_initで初期化
- curl_setoptでオプション設定
- curl_execで処理実行
- curl_closeで終了処理
という流れになります。file_get_contentsが簡単過ぎるだけで、curlが別段難しいということもありません。
■実際のコード例
function file_get_contents_curl($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$html = curl_exec($ch);
curl_close($ch);
return $html;
}
既存のfile_get_contentsを置き換えられるようにfile_get_contents_curlという名前で作ってみました。
………ネーミングセンスください(´・ω・`)
cURLのオプションについては見ればだいたい想像つくかと思いますけど、こんな感じ。
CURLOPT_URL | URLの指定 |
CURLOPT_HEADER | ヘッダーの有無(false=いらない) |
CURLOPT_RETURNTRANSFER | データを文字列に変換するか(true=する) |
CURLOPT_SSL_VERIFYPEER | SSL証明書の検証をするか(false=しない) |
CURLOPT_TIMEOUT | タイムアウトする時間(秒) |
※ここにないオプションについては下記ページ参照
https://secure.php.net/manual/ja/function.curl-setopt.php
file_get_contentsとcurl関数で速度を比較してみる
$url = 'https://blog.ver001.com/';
$t1 = microtime(true);
$html = file_get_contents($url);
//$html = file_get_contents_curl($url);
echo sprintf("%.20f", (microtime(true) - $t1)).' sec.';
誰もが口を揃えてcurlのほうが速いというのだから、ひと目でわかるのだろうとわくわくしながら、自分のサイトを読み込んでみました。
……が、正直よくわかりません。
どちらも0.4~0.6秒ほどなのですが、手動でコメントアウトして比べていると、後のほうがキャッシュされて有利なのか、単純に後に実行したほうが徐々に速くなっている感じです。
うーん、かと言って100回ループとかさせるのもレンタルサーバーの迷惑だろ、ってことでLAN環境でテストすることにしました。
■テストコード
$t1 = microtime(true);
$url = 'http://testpc/test.txt';
for ($i = 0; $i < 100; $i++) {
$html = file_get_contents($url);
//$html = file_get_contents_curl($url);
}
echo sprintf("%.20f", (microtime(true) - $t1)).' sec.';
function file_get_contents_curl($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$html = curl_exec($ch);
curl_close($ch);
return $html;
}
ApacheとPHPがセットアップされたtestpcのルートに1MBくらいあるtest.txtを置いて、別のPCからChromeで読み込む感じです。
結果、
file_get_contents | 14.18512892723083496094 sec. |
file_get_contents_curl | 13.97751998901367187500 sec. |
………………びっみょー…
正直こんなの誤差だよね…。
うーん、LAN環境、しかもただのテキストファイルじゃテストとして微妙だったかなぁ。
まとめ
実際のテストはもう少し色々やってみたのですが、他のサイトで提示されているような明らかな優位性は見いだせませんでした。もしかしたらPHPのバージョン違い(こちらはPHP 7.2.11)かも知れませんし、WindowsとLinuxサーバーの違いかも知れませんし、使っているプロバイダーの違いかも知れませんし、何よりも読み取り先のサイト次第というのが一番大きいでしょう。
でもまぁ良いんです。
興味本位でテストしはじめちゃったけど、「file_get_contentsより遅いということはない」というのさえわかれば、置き換える理由としては十分なので。
ひとまず、自前で作っているスクリプトのfile_get_contentsを順次file_get_contents_curlへ変更して様子を見てみることにします。
それで問題なさそうなら、curl_multi_execを使った非同期処理をしてみようかなと思います(`・ω・´)ゞ