我决定开始一个关于在PHP中使用curl加速下载的项目,使用curl_multi函数
下面是我的代码:set_time_limit(0);
error_reporting(E_ALL);
$fileurl = "http://hq-scenes.com/tv.exe";
$filename = basename($fileurl);
$size = getFileSize($fileurl);
$splits = range(0, $size, round($size/5));
$megaconnect = curl_multi_init();
$partnames = array();
for ($i = 0; $i < sizeof($splits); $i++) {
$ch[$i] = curl_init();
curl_setopt($ch[$i], CURLOPT_URL, $fileurl);
curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 0);
curl_setopt($ch[$i], CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch[$i], CURLOPT_VERBOSE, 1);
curl_setopt($ch[$i], CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch[$i], CURLOPT_FRESH_CONNECT, 0);
curl_setopt($ch[$i], CURLOPT_CONNECTTIMEOUT, 10);
$partnames[$i] = $filename . $i;
$bh[$i] = fopen(getcwd(). '/' . $partnames[$i], 'w+');
curl_setopt($ch[$i], CURLOPT_FILE, $bh[$i]);
$x = ($i == 0 ? 0 : $splits[$i]+1);
$y = ($i == sizeof($splits)-1 ? $size : $splits[$i+1]);
$range = $x.'-'.$y;
curl_setopt($ch[$i], CURLOPT_RANGE, $range);
curl_setopt($ch[$i], CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.29 Safari/535.1");
curl_multi_add_handle($megaconnect, $ch[$i]);
}
$active = null;
do {
$mrc = curl_multi_exec($megaconnect, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($megaconnect) != -1) {
do {
$mrc = curl_multi_exec($megaconnect, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
$final = fopen($filename, "w+");
for ($i = 0; $i < sizeof($splits); $i++) {
$contents = fread($bh[$i], filesize($partnames[$i]));
fclose($bh[$i]);
fwrite($final, $contents);
}
fclose($final);
function getFileSize($url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$h = fopen('header', "w+");
curl_setopt($ch, CURLOPT_WRITEHEADER, $h);
$data = curl_exec($ch);
curl_close($ch);
if (preg_match('/Content-Length: ('d+)/', $data, $matches)) {
return $contentLength = (int)$matches[1];
}
else return false;
}
一切顺利,除了一件事:
最后一个零件文件没有到达文件的末尾。实际文件大小为:3279848字节
范围是:
0-655970
655971-1311940
1311941-1967910
1967911-2623880
2623881-3279848
部件文件大小
tv.exe0 655360
tv.exe1 655360
tv.exe2 655360
tv.exe3 655360
tv.exe4 655360
使最终文件长度为3276800字节,但必须是3279848字节。当然,可执行文件不工作:(
注意,部件文件具有相同的大小。即使是最后一个,它应该有更多的字节。所以问题是在下载范围或其他地方,而不是在合并过程中。
我做错了什么?
我建议您在fclose($final);
之后添加这个,以删除不再需要的文件部分!
foreach($partnames as $files_to_delete){
unlink($files_to_delete);
}
必须在读取前将文件指针设置为0。从end读取xy字节为0字节;)
$final = fopen($filename, "w+");
for ($i = 0; $i < sizeof($splits); $i++) {
fseek($bh[$i], 0, SEEK_SET);
$contents = fread($bh[$i], filesize($partnames[$i]));
fclose($bh[$i]);
fwrite($final, $contents);
}
$size
未设置为任何值
设置为预期的大小后
655971 17 Aug 22:59 tv.exe0
655970 17 Aug 22:59 tv.exe1
655970 17 Aug 22:59 tv.exe2
655970 17 Aug 22:59 tv.exe3
655967 17 Aug 22:59 tv.exe4
您需要使用ceil()
而不是round。Round可以Round DOWN,这将切断文件的末端。CEIL将四舍五入,保证指定的范围覆盖整个文件:
$splits = range(0, $size, ceil($size/5));
^^^^
。如果文件的大小是12,而你取整(13/5),你将得到2。