Downloading large files with PHP

First define, what do you mean, by "large" and "huge"? In this post I present the quickest solution of using file chunking. It works fine (tested!) for files of size up to 2 GB. If this is enough for you, fine -- go ahead. If you need to download something bigger, consider using mod-xsendfile (only on Apache -- more here and here).

Chunking files is the fastest / simplest method in PHP, if you can't or don't want to make use of something a bit more professional like cURL, mod-xsendfile on Apache or some dedicated script.

The simplest example of fil chunking in PHP is here:

$filename = $filePath.$filename;

$chunksize = 5 * (1024 * 1024); //5 MB (= 5 242 880 bytes) per one chunk of file.

if(file_exists($filename))
{
    set_time_limit(300);

    $size = intval(sprintf("%u", filesize($filename)));

    header('Content-Type: application/octet-stream');
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: '.$size);
    header('Content-Disposition: attachment;filename="'.basename($filename).'"');

    if($size > $chunksize)
    { 
        $handle = fopen($filename, 'rb'); 

        while (!feof($handle))
        { 
            print(@fread($handle, $chunksize));

            ob_flush();
            flush();
        } 

        fclose($handle); 
    }
    else readfile($path);

    exit;
}
else echo 'File "'.$filename.'" does not exist!';

Ported from richnetapps.com / NeedBee. Tested on 200 MB files, on which readfile() died, even with maximum allowed memory limit set to 1G, that is five times more than downloaded file size.

I tested this also on files larger than 2 GB, but PHP only managed to write first 2 GB of file and then broke the connection. File-related functions (fopen, fread, fseek) uses INT, so you ultimately hit the limit of 2 GB. Above mentioned solutions (i.e. mod-xsendfile) seems to be the only option in this case.

BTW: Actually, it can be even the browers, which breaks the connection. Since filesize($filename) always returns 2 GB at most, no matter, what real file size is, it seems, that browser doesn't even know, that it should download something beyond 2 GB.

Note Make yourself 100% that your file (on server) is saved in utf-8. If you omit that, downloaded files will be corrupted. This is, because this solutions uses print to push chunk of a file to a browser.

Leave a Reply