5

I'm using php to download files, rather than the file itself opening in a new window. It seems to work ok for smaller files, but does not work for large files (I need this to work on very large files). Here's the code I have to download the file:

function downloadFile($file) {   
    if (file_exists($file)) {         
        //download file
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename='.basename($file));
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');
        header('Content-Length: '.filesize($file));
        ob_clean();
        flush();
        readfile($file);
        exit;   
    };    
};

But when I try to download a large file (example 265mb) the browser tells me that it can't find the file? The files are definately on the server, and the script works fine for the smaller files. Is there any way of downloading large files similar to what I already have?

SoulieBaby
  • 5,405
  • 25
  • 95
  • 145

3 Answers3

8

This download script is capable of downloading very large files (MBs or GBs). Also make sure that you set the ini settings as tomit said. For massively large files, it's usually better to use X-Sendfile method in PHP. Learn more here. Anyway, I post the working code. Maybe it's useful for people looking for error-free, working script. Script is taken from PHPsnips, hope you find it useful.

/**  
* @author     Jack Mason  
* @website    volunteer @ http://saleemkce.github.io/timeonsite, modern & accurate user engagement tracker for web and mobile browsers.    
* @copyright Free script, use anywhere as you like, no attribution required 
*/ 

/* You may need these ini settings too */ 
set_time_limit(0); 
ini_set('memory_limit', '512M');

//THE DOWNLOAD SCRIPT 
$filePath = "D:/Software/versions/windows/windows_7.rar"; // set your download file path here. 
download($filePath); // calls download function 
function download($filePath) 
{     
    if(!empty($filePath)) 
    { 
        $fileInfo = pathinfo($filePath); 
        $fileName  = $fileInfo['basename']; 
        $fileExtnesion   = $fileInfo['extension']; 
        $default_contentType = "application/octet-stream"; 
        $content_types_list = mimeTypes(); 
        // to find and use specific content type, check out this IANA page : http://www.iana.org/assignments/media-types/media-types.xhtml 
        if (array_key_exists($fileExtnesion, $content_types_list))  
        { 
            $contentType = $content_types_list[$fileExtnesion]; 
        } 
        else 
        { 
            $contentType =  $default_contentType; 
        } 
        if(file_exists($filePath)) 
        { 
            $size = filesize($filePath); 
            $offset = 0; 
            $length = $size; 
            //HEADERS FOR PARTIAL DOWNLOAD FACILITY BEGINS 
            if(isset($_SERVER['HTTP_RANGE'])) 
            { 
                preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches); 
                $offset = intval($matches[1]); 
                $length = intval($matches[2]) - $offset; 
                $fhandle = fopen($filePath, 'r'); 
                fseek($fhandle, $offset); // seek to the requested offset, this is 0 if it's not a partial content request 
                $data = fread($fhandle, $length); 
                fclose($fhandle); 
                header('HTTP/1.1 206 Partial Content'); 
                header('Content-Range: bytes ' . $offset . '-' . ($offset + $length) . '/' . $size); 
            }//HEADERS FOR PARTIAL DOWNLOAD FACILITY BEGINS 
            //USUAL HEADERS FOR DOWNLOAD 
            header("Content-Disposition: attachment;filename=".$fileName); 
            header('Content-Type: '.$contentType); 
            header("Accept-Ranges: bytes"); 
            header("Pragma: public"); 
            header("Expires: -1"); 
            header("Cache-Control: no-cache"); 
            header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0"); 
            header("Content-Length: ".filesize($filePath)); 
            $chunksize = 8 * (1024 * 1024); //8MB (highest possible fread length) 
            if ($size > $chunksize) 
            { 
              $handle = fopen($_FILES["file"]["tmp_name"], 'rb'); 
              $buffer = ''; 
              while (!feof($handle) && (connection_status() === CONNECTION_NORMAL))  
              { 
                $buffer = fread($handle, $chunksize); 
                print $buffer; 
                ob_flush(); 
                flush(); 
              } 
              if(connection_status() !== CONNECTION_NORMAL) 
              { 
                echo "Connection aborted"; 
              } 
              fclose($handle); 
            } 
            else  
            { 
              ob_clean(); 
              flush(); 
              readfile($filePath); 
            } 
         } 
         else 
         { 
           echo 'File does not exist!'; 
         } 
    } 
    else 
    { 
        echo 'There is no file to download!'; 
    } 
}     
     

/* Function to get correct MIME type for download */ 
function mimeTypes() 
{ 
/* Just add any required MIME type if you are going to download something not listed here.*/ 
$mime_types = array("323" => "text/h323", 
                    "acx" => "application/internet-property-stream", 
                    "ai" => "application/postscript", 
                    "aif" => "audio/x-aiff", 
                    "aifc" => "audio/x-aiff", 
                    "aiff" => "audio/x-aiff", 
                    "asf" => "video/x-ms-asf", 
                    "asr" => "video/x-ms-asf", 
                    "asx" => "video/x-ms-asf", 
                    "au" => "audio/basic", 
                    "avi" => "video/x-msvideo", 
                    "axs" => "application/olescript", 
                    "bas" => "text/plain", 
                    "bcpio" => "application/x-bcpio", 
                    "bin" => "application/octet-stream", 
                    "bmp" => "image/bmp", 
                    "c" => "text/plain", 
                    "cat" => "application/vnd.ms-pkiseccat", 
                    "cdf" => "application/x-cdf", 
                    "cer" => "application/x-x509-ca-cert", 
                    "class" => "application/octet-stream", 
                    "clp" => "application/x-msclip", 
                    "cmx" => "image/x-cmx", 
                    "cod" => "image/cis-cod", 
                    "cpio" => "application/x-cpio", 
                    "crd" => "application/x-mscardfile", 
                    "crl" => "application/pkix-crl", 
                    "crt" => "application/x-x509-ca-cert", 
                    "csh" => "application/x-csh", 
                    "css" => "text/css", 
                    "dcr" => "application/x-director", 
                    "der" => "application/x-x509-ca-cert", 
                    "dir" => "application/x-director", 
                    "dll" => "application/x-msdownload", 
                    "dms" => "application/octet-stream", 
                    "doc" => "application/msword", 
                    "dot" => "application/msword", 
                    "dvi" => "application/x-dvi", 
                    "dxr" => "application/x-director", 
                    "eps" => "application/postscript", 
                    "etx" => "text/x-setext", 
                    "evy" => "application/envoy", 
                    "exe" => "application/octet-stream", 
                    "fif" => "application/fractals", 
                    "flr" => "x-world/x-vrml", 
                    "gif" => "image/gif", 
                    "gtar" => "application/x-gtar", 
                    "gz" => "application/x-gzip", 
                    "h" => "text/plain", 
                    "hdf" => "application/x-hdf", 
                    "hlp" => "application/winhlp", 
                    "hqx" => "application/mac-binhex40", 
                    "hta" => "application/hta", 
                    "htc" => "text/x-component", 
                    "htm" => "text/html", 
                    "html" => "text/html", 
                    "htt" => "text/webviewhtml", 
                    "ico" => "image/x-icon", 
                    "ief" => "image/ief", 
                    "iii" => "application/x-iphone", 
                    "ins" => "application/x-internet-signup", 
                    "isp" => "application/x-internet-signup", 
                    "jfif" => "image/pipeg", 
                    "jpe" => "image/jpeg", 
                    "jpeg" => "image/jpeg", 
                    "jpg" => "image/jpeg", 
                    "js" => "application/x-javascript", 
                    "latex" => "application/x-latex", 
                    "lha" => "application/octet-stream", 
                    "lsf" => "video/x-la-asf", 
                    "lsx" => "video/x-la-asf", 
                    "lzh" => "application/octet-stream", 
                    "m13" => "application/x-msmediaview", 
                    "m14" => "application/x-msmediaview", 
                    "m3u" => "audio/x-mpegurl", 
                    "man" => "application/x-troff-man", 
                    "mdb" => "application/x-msaccess", 
                    "me" => "application/x-troff-me", 
                    "mht" => "message/rfc822", 
                    "mhtml" => "message/rfc822", 
                    "mid" => "audio/mid", 
                    "mny" => "application/x-msmoney", 
                    "mov" => "video/quicktime", 
                    "movie" => "video/x-sgi-movie", 
                    "mp2" => "video/mpeg", 
                    "mp3" => "audio/mpeg", 
                    "mpa" => "video/mpeg", 
                    "mpe" => "video/mpeg", 
                    "mpeg" => "video/mpeg", 
                    "mpg" => "video/mpeg", 
                    "mpp" => "application/vnd.ms-project", 
                    "mpv2" => "video/mpeg", 
                    "ms" => "application/x-troff-ms", 
                    "mvb" => "application/x-msmediaview", 
                    "nws" => "message/rfc822", 
                    "oda" => "application/oda", 
                    "p10" => "application/pkcs10", 
                    "p12" => "application/x-pkcs12", 
                    "p7b" => "application/x-pkcs7-certificates", 
                    "p7c" => "application/x-pkcs7-mime", 
                    "p7m" => "application/x-pkcs7-mime", 
                    "p7r" => "application/x-pkcs7-certreqresp", 
                    "p7s" => "application/x-pkcs7-signature", 
                    "pbm" => "image/x-portable-bitmap", 
                    "pdf" => "application/pdf", 
                    "pfx" => "application/x-pkcs12", 
                    "pgm" => "image/x-portable-graymap", 
                    "pko" => "application/ynd.ms-pkipko", 
                    "pma" => "application/x-perfmon", 
                    "pmc" => "application/x-perfmon", 
                    "pml" => "application/x-perfmon", 
                    "pmr" => "application/x-perfmon", 
                    "pmw" => "application/x-perfmon", 
                    "pnm" => "image/x-portable-anymap", 
                    "pot" => "application/vnd.ms-powerpoint", 
                    "ppm" => "image/x-portable-pixmap", 
                    "pps" => "application/vnd.ms-powerpoint", 
                    "ppt" => "application/vnd.ms-powerpoint", 
                    "prf" => "application/pics-rules", 
                    "ps" => "application/postscript", 
                    "pub" => "application/x-mspublisher", 
                    "qt" => "video/quicktime", 
                    "ra" => "audio/x-pn-realaudio", 
                    "ram" => "audio/x-pn-realaudio", 
                    "ras" => "image/x-cmu-raster", 
                    "rgb" => "image/x-rgb", 
                    "rmi" => "audio/mid", 
                    "roff" => "application/x-troff", 
                    "rtf" => "application/rtf", 
                    "rtx" => "text/richtext", 
                    "scd" => "application/x-msschedule", 
                    "sct" => "text/scriptlet", 
                    "setpay" => "application/set-payment-initiation", 
                    "setreg" => "application/set-registration-initiation", 
                    "sh" => "application/x-sh", 
                    "shar" => "application/x-shar", 
                    "sit" => "application/x-stuffit", 
                    "snd" => "audio/basic", 
                    "spc" => "application/x-pkcs7-certificates", 
                    "spl" => "application/futuresplash", 
                    "src" => "application/x-wais-source", 
                    "sst" => "application/vnd.ms-pkicertstore", 
                    "stl" => "application/vnd.ms-pkistl", 
                    "stm" => "text/html", 
                    "svg" => "image/svg+xml", 
                    "sv4cpio" => "application/x-sv4cpio", 
                    "sv4crc" => "application/x-sv4crc", 
                    "t" => "application/x-troff", 
                    "tar" => "application/x-tar", 
                    "tcl" => "application/x-tcl", 
                    "tex" => "application/x-tex", 
                    "texi" => "application/x-texinfo", 
                    "texinfo" => "application/x-texinfo", 
                    "tgz" => "application/x-compressed", 
                    "tif" => "image/tiff", 
                    "tiff" => "image/tiff", 
                    "tr" => "application/x-troff", 
                    "trm" => "application/x-msterminal", 
                    "tsv" => "text/tab-separated-values", 
                    "txt" => "text/plain", 
                    "uls" => "text/iuls", 
                    "ustar" => "application/x-ustar", 
                    "vcf" => "text/x-vcard", 
                    "vrml" => "x-world/x-vrml", 
                    "wav" => "audio/x-wav", 
                    "wcm" => "application/vnd.ms-works", 
                    "wdb" => "application/vnd.ms-works", 
                    "wks" => "application/vnd.ms-works", 
                    "wmf" => "application/x-msmetafile", 
                    "wps" => "application/vnd.ms-works", 
                    "wri" => "application/x-mswrite", 
                    "wrl" => "x-world/x-vrml", 
                    "wrz" => "x-world/x-vrml", 
                    "xaf" => "x-world/x-vrml", 
                    "xbm" => "image/x-xbitmap", 
                    "xla" => "application/vnd.ms-excel", 
                    "xlc" => "application/vnd.ms-excel", 
                    "xlm" => "application/vnd.ms-excel", 
                    "xls" => "application/vnd.ms-excel", 
                    "xlt" => "application/vnd.ms-excel", 
                    "xlw" => "application/vnd.ms-excel", 
                    "xof" => "x-world/x-vrml", 
                    "xpm" => "image/x-xpixmap", 
                    "xwd" => "image/x-xwindowdump", 
                    "z" => "application/x-compress", 
                    "rar" => "application/x-rar-compressed", 
                    "zip" => "application/zip"); 
return $mime_types;                     
}
?>
webblover
  • 1,196
  • 2
  • 12
  • 30
  • 1
    Very nice solution. – Pradeepta Dec 30 '16 at 07:25
  • For file path should we use relative path from our application directory or from the os directory. – Pradeepta Dec 30 '16 at 07:29
  • 2
    @Pradeepta Yes, you may use accessible URL on web. For example, `$filePath = 'http://example.com/assests/videos/movie.rar'; /*change it as per your requirements. This is more preferrable */ download($filePath);` If this doesn't work. You may try relative path. Either should work great. – webblover Dec 31 '16 at 06:53
  • 2
    I personally modified usual download script in PHP to make it capable of downloading large files; The code, I posted above, is capable of downloading almost 2GB or so. When tested, it worked great. For this to work for your application, you need to make appropriate settings in your php.ini and Apache web server config to allow maximum execution time. – webblover Dec 31 '16 at 07:05
7

PHP has limits on how long a script can run, and how much memory it can use. It's possible that the script is timing out before it has completed, or is using up too much memory by reading in the large file.

Try tweaking the max_execution_time and memory_limit variables in php.ini. If you don't have access to php.ini, try the set_time_limit and/or ini_set functions.

tomit
  • 720
  • 4
  • 6
  • .."or is using up too much memory by reading in the large file." **Yes.** One should use `ob_clean_end` with `readfile`, not `ob_clean`. Other limits may still be reached, however. – user2864740 Jul 08 '15 at 17:30
5

I see you're using ob_clean. If you have output buffering enabled, try disabling it (e.g. by replacing the ob_clean call with ob_end_clean).

Artefacto
  • 96,375
  • 17
  • 202
  • 225
  • changed it to ob_end_clean but it still isn't downloading the large files.. smaller files still work ok.. does it make a difference that i'm trying to download a large zip file? – SoulieBaby Jul 05 '10 at 02:26
  • @Soul are you sure there are no errors? Check the PHP error log, if any, or, if display_errors is turned on, comment out all the `header` calls and try again. – Artefacto Jul 05 '10 at 02:31