2011-08-17 55 views
3

我決定使用curl_multi函數在PHP中使用curl啓動一個關於下載加速的項目。如何與PHP的捲曲庫並行下載文件的多個部分?

這裏是我的代碼:

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個字節。 當然可執行文件沒有工作:(

請注意,部分文件具有相同的大小,即使是最後一個,應該有更多的字節。所以問題是在下載範圍或某事,而不是在合併過程中。

我做了什麼錯?

回答

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); 
} 
+0

以上是的工作!!我真的很感激你,我的意思是我已經傷心了一段時間,直到我讀了xD –

2

$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 
+0

是的,我忘記在第一線 $大小= getFileSize($ URL)來複制此; –

+0

再次這不是預期的大小:( –

+0

所以getFileSize返回不正確的大小? –

2

您想要使用ceil()而不是一輪。舍入可能會向下滾動,這會截斷文件的結尾。 CEIL將圓UP,保證在指定的範圍(或多個)覆蓋了整個文件:

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

例如如果文件的大小是12,並且你輪到(13/5),那麼你最終會得到2.

+0

不錯的建議人,我已經改變它,但這不是目前的問題:( –

+0

和我已經更新我的代碼 –

3

我建議你fclose($final);後添加此以刪除不再需要的fileparts!

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