ダウンロードをマルチスレッドで@動画サイトへの道
こんばんは。ダウンロード自動化エントリであったダウンロード処理をマルチスレッドで行うことにしました。
順番に処理していったらなかなか終わらないと思うので…
というわけで、サイトを参考に作ってみましょう。
ハァハァ、マルチスレッドとか初めて///
参考サイト
→http://techblog.ecstudio.jp/tech-tips/php-multi.html
・
・
・
(てってってー)
・
・
・
curlを使ってマルチスレッドでファイルダウンロードします
・
・
・
あああっ!なんで落としてきたファイルサイズがゼロなんだっ!
と悩むこと3時間ほど。オプションをいじりまくって、もうfwriteでいいからファイルに書かせてくれ!と叫びたかった。
オチは…ファイルポインタ渡してなかっただけでした。Orz
そして、できた!マルチスレッドでファイルダウンロードするクラスを作りました。
というわけで、公開〜
恥ずかしながら、オプションを全ては把握していないのと、ネーミングセンスに自信が全くないので適切に変えてくださいw
<?php class Curl { const MAX_REDIRECT = 5; const DEFAULT_TIMEOUT = 30; const CURL_SELECT_FAILED = -1; protected $connect = array(); protected $handler; public function __construct() { $this->handler = curl_multi_init(); } public function addUrl($url, $timeout = self::DEFAULT_TIMEOUT, $redirect = self::MAX_REDIRECT, $fp = NULL) { $this->connect[$url] = curl_init($url); curl_setopt($this->connect[$url], CURLOPT_HEADER, 0); curl_setopt($this->connect[$url], CURLOPT_FAILONERROR, true); curl_setopt($this->connect[$url], CURLOPT_FOLLOWLOCATION, true); curl_setopt($this->connect[$url], CURLOPT_MAXREDIRS, $redirect); //curl_setopt($this->connect[$url], CURLOPT_SSL_VERIFYPEER, false); //curl_setopt($this->connect[$url], CURLOPT_SSL_VERIFYHOST, false); curl_setopt($this->connect[$url], CURLOPT_TIMEOUT, $timeout); if (is_null($fp) === false) { curl_setopt($this->connect[$url], CURLOPT_FILE, $fp); } else { curl_setopt($this->connect[$url], CURLOPT_RETURNTRANSFER, true); } curl_multi_add_handle($this->handler, $this->connect[$url]); } public function exec() { $status = $this->multiAccess(); while ($status['activeconnect'] > 0 && $status['mrc'] == CURLM_OK) { if (curl_multi_select($this->handler, self::DEFAULT_TIMEOUT) === self::CURL_SELECT_FAILED) { break; } $status = $this->multiAccess(); } } public function fetch($key) { if (array_key_exists($key, $this->connect) === false) { return false; } //取得 return curl_multi_getcontent($this->connect[$key]); } public function multiAccess() { do { $mrc = curl_multi_exec($this->handler, $activeConnect); } while ($mrc == CURLM_CALL_MULTI_PERFORM); $status = array(); $status['mrc'] = $mrc; $status['activeconnect'] = $activeConnect; return $status; } public function __destruct() { foreach ($this->connect as $key => $value) { curl_multi_remove_handle($this->handler, $this->connect[$key]); curl_close($this->connect[$key]); } curl_multi_close($this->handler); } }
軽いファイルならcurl_multi_getcontentでもいいですが、大きなファイルになると、PHPのメモリ上限(デフォルトで128Mだっけ?)に引っかかる可能性があるのでCURLOPT_FILEオプションにファイルポインタをつけて都度書き込みさせています。
ついでにDBからダウンロードするURLリストを取ってくるクラスもできて、こいつを使ってダウンロードしてきます。
これでダウンロードの自動化の8割は完成〜
このまま例の自動変換ディレクトリに放り込んでしまうと、ダウンロード中のファイルも勝手に登録されて勝手にエンコード開始されてしまうので、キャッシュ用のディレクトリを作成。一旦ダウンロード終了を待ってからrenameして移動させます。
あとは、バッチ処理させればいいかな。