PHP下载远程文件可以通过多种方式。如果下载链接直接对应于远程文件,使用fopen($url, 'rb');返回句柄读取即可。
Warning: 注意设置fopen的timeout;注意判断句柄是否为空。
1 function download($src, $dst) 2 { 3 $timeout = 100; 4 $old = ini_set('default_socket_timeout', $timeout); 5 $srcH = fopen($src, "rb"); 6 ini_set('default_socket_timeout', $old); 7 if(!$srcH){ 8 fclose($srcH); 9 Util::log($src. " not exists!"); 10 return false; 11 } 12 $dstH = fopen($dst, "wb"); 13 # file open error. filePath not exists. 14 if(!$dstH) { 15 $dirname = dirname($dst); 16 if(!file_exists($dirname)) { 17 mkdir($dirname); 18 } 19 $dstH = fopen($dst, "wb"); 20 } 21 while (!feof($srcH)) { 22 $part = fread($srcH, 65535); 23 fwrite($dstH, $part); 24 } 25 fclose($srcH); 26 fclose($dstH); 27 return true; 28 }
有些时候,网站会释放一个下载地址查询接口,访问接口查询到真实下载地址,通过302跳转到下载地址,完成下载。
function download($src, $dst) { $ch = curl_init($src); $dstH = fopen($dst, "wb"); # 判断路径是否存在 if(!$dstH) { $dirname = dirname($dst); if(!file_exists($dirname)) { mkdir($dirname); } $dstH = fopen($dst, "wb"); } curl_setopt($ch, CURLOPT_FILE, $dstH); curl_setopt($ch, CURL_HEADER, 0); # 这个参数非常重要。 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_TIMEOUT, 60); $result = curl_exec($ch); $ret['curl_info'] = curl_getinfo($ch); if($result === false || $ret['curl_info']['http_code']!=200){ $ret['curl_errno'] = curl_errno($ch); $ret['curl_error'] = curl_error($ch); Util::log(var_export($ret, true)); $result = false; } curl_close($ch); fclose($dstH); return $result; }
开发期间需要开发一个下载功能。首先完成第一版,但是使用fopen有一个严重问题。很多下载地址是一个302跳转,fopen无法继续打开后续的跳转地址,在第一地址,fopen失败。
PHP Warning: fopen(http://down.mumayi.com/222904/xxxxx): failed to open stream: HTTP request failed! HTTP/1.1 404 Site or Page Not Found
curl中有一个重要参数CURLOPT_FOLLOWLOCATION: 启用时会将服务器服务器返回的"Location: "放在header中递归的返回给服务器,使用CURLOPT_MAXREDIRS可以限定递归返回的数量。
加入这个参数,遇到302跳转,会继续访问跳转地址,直到遇到非302,从而获得真正的下载地址,进行下载。