Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force-downloading, from php file

I'm attempting to download a .mp4 file. (about 1.3GB size). I'm using following:

<?php 
$path = "video.mp4";
header('Accept-Ranges: bytes');  // For download resume
header('Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header('Content-Description: File Transfer' );
header('Content-Disposition: attachment; filename="'.basename( $path ).'"' );
header('Content-Length: ' . filesize($path));  // File size
header('Content-Transfer-Encoding: binary');  // For Gecko browsers mainly
header('Content-Type: application/octet-stream' );
header('Expires: 0' );
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT');
header('Pragma: no-cache' );
ob_clean();
flush();
readfile($path);

I open my php file, and firefox pops up with the "want to save" menu. Size looks right. I press Save As, to my desktop. The final downloaded file, lists as a random size, around 400MB (330, 463 and 440).

Response Headers are:

Connection: Keep-Alive
Content-Disposition:    attachment; filename="//www.frederikspang.dk/elevgallavideo.mp4"
Content-Length: 1422778850
Content-Type:   video/mp4
Date:   Sun, 30 Jun 2013 22:12:30 GMT
Keep-Alive: timeout=10, max=50
Pragma: public
Server: Apache
content-transfer-encoding:  binary
like image 385
Frederik Spang Avatar asked Nov 02 '22 19:11

Frederik Spang


1 Answers

THis is hard - most php configuration will fail after 30 seconds. If you own php.ini you can change that to longer limit. But still - is that even worth it? I mean - the files can get bigger or network slower - and once more you will hit the timeout.

This is why downloaders were made - to download big files in smaller chunks Half Crazed showed you code for that i THIS answer (its not only one - this only takes into account one of the ways clients negotiate the transfers - but still its a good start).

Mega.co.nz for example uses new html5 features. Downloads the file in browser using chunks, joining the file on user and and then ,,downloading'' it from the browser disk space. It can resume files, pause files and so on. (Sorry - no code for that as it would be quite big and include more than one language (php, js)).

PS: change yours readfile($path); into:

$handle=fopen($path, 'rb');
while (!feof($handle))
{
    echo fread($handle, 8192);
    flush();
}
fclose($handle);

This will not load WHOLE file into memory, just parts of 8KiB at once and then send them to user.

like image 120
Seti Avatar answered Nov 15 '22 06:11

Seti