php開啟多線程下載
<pre>
<?php
/**
* 多進程批量下載文件(使用php curl_multi_exec實現)
* Date: 2017-07-16
* Author: fdipzone
* Version: 1.0
*
* Func
* public download 下載處理
* public process 多進程下載
* private to_log 將執行結果寫入日志文件
*/
class BatchDownLoad {
// 下載文件設置
private $download_config = array();
// 最大開啟進程數量
private $max_process_num = 10;
// 超時秒數
private $timeout = 10;
// 日志文件
private $logfile = null;
/**
* 初始化
* @param Array $download_config 下載的文件設置
* @param Int $max_process_num 最大開啟的進程數量
* @param Int $timeout 超時秒數
* @param String $logfile 日志文件路徑
*/
public function __construct($download_config, $max_process_num=10, $timeout=10, $logfile=''){
$this->download_config = $download_config;
$this->max_process_num = $max_process_num;
$this->timeout = $timeout;
// 日志文件
if($logfile){
$this->logfile = $logfile;
}else{
$this->logfile = dirname(__FILE__).'/batch_download_'.date('Ymd').'.log';
}
}
/**
* 執行下載
* @result Int
*/
public function download(){
// 已處理的數量
$handle_num = 0;
// 未處理完成
while(count($this->download_config)>0){
// 需要處理的大於最大進程數
if(count($this->download_config)>$this->max_process_num){
$process_num = $this->max_process_num;
// 需要處理的小於最大進程數
}else{
$process_num = count($this->download_config);
}
// 抽取指定數量進行下載
$tmp_download_config = array_splice($this->download_config, 0, $process_num);
// 執行下載
$result = $this->process($tmp_download_config);
// 寫入日志
$this->to_log($tmp_download_config, $result);
// 記錄已處理的數量
$handle_num += count($result);
}
return $handle_num;
}
/**
* 多進程下載文件
* @param Array $download_config 本次下載的設置
* @return Array
*/
public function process($download_config){
// 文件資源
$fp = array();
// curl會話
$ch = array();
// 執行結果
$result = array();
// 創建curl handle
$mh = curl_multi_init();
// 循環設定數量
foreach($download_config as $k=>$config){
$ch[$k] = curl_init();
$fp[$k] = fopen($config[1], 'a');
curl_setopt($ch[$k], CURLOPT_URL, $config[0]);
curl_setopt($ch[$k], CURLOPT_FILE, $fp[$k]);
curl_setopt($ch[$k], CURLOPT_HEADER, 0);
curl_setopt($ch[$k], CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch[$k], CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)');
// 加入處理
curl_multi_add_handle($mh, $ch[$k]);
}
//下面幾句話就是執行多線程curl 不用理解為什么這樣寫 照着寫就是了 如果執行好 $active會變成0的
$active = null;
do{
$mrc = curl_multi_exec($mh, $active);
} while($active);
// 獲取數據
foreach($fp as $k=>$v){
fwrite($v, curl_multi_getcontent($ch[$k]));
}
// 關閉curl handle與文件資源
foreach($download_config as $k=>$config){
curl_multi_remove_handle($mh, $ch[$k]);
fclose($fp[$k]);
// 檢查是否下載成功
if(file_exists($config[1])){
$result[$k] = true;
}else{
$result[$k] = false;
}
}
curl_multi_close($mh);
return $result;
}
/**
* 寫入日志
* @param Array $data 下載文件數據
* @param Array $flag 下載文件狀態數據
*/
private function to_log($data, $flag){
// 臨時日志數據
$tmp_log = '';
foreach($data as $k=>$v){
$tmp_log .= '['.date('Y-m-d H:i:s').'] url:'.$v[0].' file:'.$v[1].' status:'.$flag[$k].PHP_EOL;
}
// 創建日志目錄
if(!is_dir(dirname($this->logfile))){
mkdir(dirname($this->logfile), 0777, true);
}
// 寫入日志文件
file_put_contents($this->logfile, $tmp_log, FILE_APPEND);
}
}
date_default_timezone_set('Asia/Shanghai');
$base_path = dirname(__FILE__).'/phototest';
$download_config = array(
array('http://img.ads.csdn.net/2017/201707141625579530.jpg', $base_path.'/p1.jpg'),
array('http://geek.csdn.net/assets/images/geek_logo.png', $base_path.'/p2.jpg'),
array('http://images.csdn.net/20170718/Hans_meitu_401.jpg', $base_path.'/p3.jpg'),
);
$obj = new BatchDownLoad($download_config, 2, 10);
$handle_num = $obj->download();
echo 'download num:'.$handle_num.PHP_EOL;
?>
</pre>
ps:經過測試單線程和多線程下載速度是差不多的 因為帶寬就這些 這是多線程能更好的使用帶寬利用率