【问题标题】:How can I download multiple parts of a file in parallel with PHP's curl library?如何与 PHP 的 curl 库并行下​​载文件的多个部分?
【发布时间】:2011-08-17 21:48:29
【问题描述】:

我决定在 PHP 中使用 curl_multi 函数启动一个关于 curl 下载加速的项目。

这是我的代码:

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 字节。 当然,可执行文件不起作用:(

请注意,零件文件的大小相同。即使是最后一个,它应该有更多的字节。所以问题出在下载范围什么的,而不是在合并过程中。

我做错了什么?

【问题讨论】:

    标签: php multithreading curl download


    【解决方案1】:

    我建议你在fclose($final);之后添加这个来删除不再需要的文件部分!

    foreach($partnames as $files_to_delete){ 
        unlink($files_to_delete); 
    }
    

    【讨论】:

      【解决方案2】:

      您必须在 fread 之前将文件指针设置为 0。从末尾读取 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);
      }
      

      【讨论】:

      • 是的,有效!我真的很感谢你,我的意思是我已经伤心了一段时间,直到我读到那个 xD
      【解决方案3】:

      $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
      

      【讨论】:

      • 是的,我忘了在第一行复制这个 $size = getFileSize($url);
      • 这不是预期的大小:(
      • 不,我有原始文件,我在 windows 上仔细检查了文件大小,它是正确的
      【解决方案4】:

      您希望使用ceil() 而不是圆形。 Round 可能会向下舍入,这会切断文件的结尾。 CEIL 会向上取整,保证指定的范围覆盖整个文件:

      $splits = range(0, $size, ceil($size/5));
                                ^^^^
      

      例如如果文件的大小是 12,并且你做 round(13/5),你会得到 2。

      【讨论】:

      • 好建议,我已经改了,但这不是当前的问题:(
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-27
      • 2011-01-03
      • 2014-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-10
      相关资源
      最近更新 更多