直接贴出代码,可自行包装成一个类:
set_time_limit(0);
function getMicrotime() {
list ($usec, $sec) = explode(" ", microtime());
return ((float) $usec + (float) $sec);
}
$stime = getMicrotime();//开始时间
/**
* curl 多线程下载图片
*
* @param array $array 并行网址
* @param int $timeout 超时时间
* @return mix
*/
function Curl_down_image($array,$timeout='15')
{
$res = array();
$mh = curl_multi_init();//创建多个curl语柄
foreach($array as $k=>$url)
{
$conn[$k]=curl_init($url);//创建cURL资源
curl_setopt($conn[$k], CURLOPT_TIMEOUT, $timeout);//设置超时时间
curl_setopt($conn[$k], CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($conn[$k], CURLOPT_MAXREDIRS, 7);//HTTp定向级别 ,7最高
curl_setopt($conn[$k], CURLOPT_HEADER, false);//这里不要header,加块效率
curl_setopt($conn[$k], CURLOPT_FOLLOWLOCATION, 1); // 302 redirect
curl_setopt($conn[$k], CURLOPT_RETURNTRANSFER,1);//要求结果保存到字符串中(1)还是输出到屏幕上
curl_setopt($conn[$k], CURLOPT_HTTPGET, true);
curl_multi_add_handle ($mh,$conn[$k]);
}
$active = null;
/*执行批处理句柄,防止死循环耗死cpu*/
//当正在接受数据时
do {
$mrc = curl_multi_exec($mh,$active);//当无数据,active=true
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
//当无数据时或请求暂停时,active=true
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
/*curl获取的输出的文本流*/
foreach ($array as $k => $url) {
if(!curl_errno($conn[$k])){//curl解析正常
$data[$k]=curl_multi_getcontent($conn[$k]);//数据保存到array中
$header[$k]=curl_getinfo($conn[$k]);//返回http头信息
curl_close($conn[$k]);//关闭语柄
curl_multi_remove_handle($mh,$conn[$k]); //释放资源
}else{
//curl解析失败操作
}
}
unset($array,$conn);
curl_multi_close($mh);
return $data;
}
//图片地址数组集
$array = array(
'http://img842.ph.126.net/PJbIezP4bNn4WcG-vgTNwQ==/875105702595657274.jpg',
'http://img842.ph.126.net/PJbIezP4bNn4WcG-vgTNwQ==/875105702595657274.jpg'
);
//根据$data数组中保存的图片文本流数据生成相应图片
$data = Curl_down_image($array,$timeout='105');
foreach ((array)$data as $k=>$v){
if($v !=''){ //图片数据存在
$basename = getMicrotime().".jpg";//保存为jpg格式的文件
$fname = realpath('.').'/'.$basename;
file_put_contents($fname, $v);
}else{
//图片数据不存在操作
}
}
unset($data);
//时间统计
$etime = getMicrotime();//结束时间
echo ($etime-$stime)."";
curl 多线程下载流程:
第一步:调用curl_multi_init
第二步:循环调用curl_multi_add_handle
这一步需要注意的是,curl_multi_add_handle的第二个参数是由curl_init而来的子handle。
第三步:持续调用curl_multi_exec
第四步:根据需要循环调用curl_multi_getcontent获取结果
第五步:调用curl_multi_remove_handle,并为每个字handle调用curl_close
第六步:调用curl_multi_close
实例扩展:
可以下载多张图片或下载多个页面,
将下载的数据文本流全部保存至数组中,
然后将其生成图片或页面数据
可优化部分:站长教学网 eduyo.com
curl获取的输出的文本流部分可以优化,获取后直接执行想要对数据的操作,这样可以减少很多内存的使用,执行时间更短
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); 如果成功只将结果返回,不自动输出任何内容 如果失败返回FALSE curl_setopt($ch, CURLOPT_RETURNTRANSFER,0); 或着不使用这个选项: 如果成功只返回TRUE,自动输出返回的内容 如果失败返回FALSE
do {
$mrc = curl_multi_exec($mh,$active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active and $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
/*
因为$active要等全部url数据接受完毕才变成false,所以这里用到了curl_multi_exec的返回值判断是否还有数据,当有数据的时候就不停调用curl_multi_exec,暂时没有数据就进入select阶段,新数据一来就可以被唤醒继续执行。这里的好处就是CPU的无谓消耗没有了。
另外:还有一些细节的地方可能有时候要遇到:
控制每一个请求的超时时间,在curl_multi_add_handle之前通过curl_setopt去做:
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
判断是否超时了或者其他错误,在curl_multi_getcontent之前用:curl_error($conn[$i]);
*/
/**
* curl 远程单张图片下载
* @param str $url 远程单张图url
* @param str $fname 本地存储文件src
* @param int $timeout 超时时间
* @return $int 返回写入到文件内数据的字节数
*/
function curl_down_image($url,$fname,$timeout='15')
{
$ch=curl_init($url);//创建cURL资源
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);//设置超时时间
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($ch, CURLOPT_MAXREDIRS, 7);//HTTp定向级别 ,7最高
curl_setopt($ch, CURLOPT_HEADER, false);//这里不要header,加块效率
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 302 redirect
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_HTTPGET, true);
//如果 CURLOPT_RETURNTRANSFER选项被设置,函数执行成功时会返回执行的结果,失败时返回 FALSE
$data = curl_exec($ch);
if(!$data) die('无法获取图片');
$int = file_put_contents($fname, $data);
return $int;
}
function getMicrotime() {
list ($usec, $sec) = explode(" ", microtime());
return ((float) $usec + (float) $sec);
}
$url = 'http://img842.ph.126.net/PJbIezP4bNn4WcG-vgTNwQ==/875105702595657274.jpg';
$basename = getMicrotime().".jpg";//保存为jpg格式的文件
$fname = realpath('.').'/'.$basename;
$int = curl_down_image($url,$fname);
print_r($int);
/**
* @description curl method,post方法params字符串的位置不同于get
*
* @access public
* @param mixed $url
* @param string $params
* @param string $method
* @param mixed $connectTimeout
* @param mixed $readTimeout
* @return json
*/
public function httpCall($url ,$params = '',$method = 'get', $connectTimeout = self::CONNECT_TIMEOUT,$readTimeout = self::READ_TIMEOUT) {
if ($this->conf['print_request_params']) {
var_dump('url:'.$url,'params:'.$params);
}
$result = "";
if (function_exists('curl_init')) {
$timeout = $connectTimeout + $readTimeout;
// Use CURL if installed...
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if(strtolower($method)==='post'){
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
}
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connectTimeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, '56.com API PHP5 Client 1.1 (curl) ' . phpversion());
$result = curl_exec($ch);
} else{
if(isset($params) and $params){
$url = $url."?".http_build_query($params);
}
// Non-CURL based version...
$ctx = stream_context_create(
array(
'http' => array(
'timeout' => 5 /** 设置一个超时时间,单位为秒 */
)
)
);
$result = file_get_contents($url, 0, $ctx);
}
return $result;
}
(责任编辑:ken)
