I decided to start a project about download acceleration with curl in PHP, using curl_multi functions.
Here is my code:
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;
}
Everything goes OK, except one thing:
The last part file doesn’t reach the end of the file.
the actual file size is : 3279848 bytes
ranges are:
0-655970
655971-1311940
1311941-1967910
1967911-2623880
2623881-3279848
part files with size
tv.exe0 655360
tv.exe1 655360
tv.exe2 655360
tv.exe3 655360
tv.exe4 655360
That makes the final file 3276800 bytes length, but it must be 3279848 bytes.
And of course the executable didn’t work 🙁
Notice that the part files have the same size. Even the last one, which should have some more bytes. So the problem is in the download range or something, not in the merge process.
What did I do wrong?
you must set your filepointers to 0 before fread. reading xy bytes from end is 0 bytes 😉