curl 多线程下载
- 批量下载图片:
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_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 实例扩展: 可以下载多张图片或下载多个页面, 将下载的数据文本流全部保存至数组中, 然后将其生成图片或页面数据 可优化部分: curl获取的输出的文本流部分可以优化,获取后直接执行想要对数据的操作,这样可以减少很多内存的使用,执行时间更短
- 理解:CURLOPT_RETURNTRANSFER
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); 如果成功只将结果返回,不自动输出任何内容 如果失败返回FALSE curl_setopt($ch, CURLOPT_RETURNTRANSFER,0); 或着不使用这个选项: 如果成功只返回TRUE,自动输出返回的内容 如果失败返回FALSE
- 关于do while的那段解释:
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);
- API调用中常用的 curl和file_get_contents方法使用
/** * @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; }
尤其要注意file_get_contents的超时使用方法