Bottyz Posted October 10, 2011 Share Posted October 10, 2011 Hi all, I've tried many, many variations of php download script using readfile() fread() fpassthru() etc... but none seem reliable. I can download small files perfectly fine, but say I have a 30 or 90mb zip file the download ocassionally bombs out and says the download is complete even though the full file hasn't been transferred. I have tired it on several browsers with pretty much the same issue. The interesting bit for me is that if I download the same file across different browsers (whether or not they start at the same time or not) on my computer the download stops at the same time (not same point into download) for each browser. Its as if the connection is being reset on my website on a global basis... The important part of my script as it is at the moment: // resumable download? $is_resume = TRUE; //Gather relevant info about file $size = filesize($path); $fileinfo = pathinfo($path); @ini_set('magic_quotes_runtime', 0); set_time_limit(0); apache_setenv('no-gzip', '1'); mb_http_output("pass"); // required for IE, otherwise Content-disposition is ignored if(ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); } //workaround for IE filename bug with multiple periods / multiple dots in filename //that adds square brackets to filename - eg. setup.abc.exe becomes setup[1].abc.exe $filename = (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ? preg_replace('/\./', '%2e', $fileinfo['basename'], substr_count($fileinfo['basename'], '.') - 1) : $fileinfo['basename']; $file_extension = strtolower($fileinfo['extension']); //This will set the Content-Type to the appropriate setting for the file switch($file_extension) { case 'zip': $ctype='application/zip'; break; case 'pdf': $ctype='application/pdf'; break; default: $ctype='application/force-download'; } //check if http_range is sent by browser (or download manager) if($is_resume && isset($_SERVER['HTTP_RANGE'])) { list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2); if ($size_unit == 'bytes') { //multiple ranges could be specified at the same time, but for simplicity only serve the first range //http://tools.ietf.org/id/draft-ietf-http-range-retrieval-00.txt list($range, $extra_ranges) = explode(',', $range_orig, 2); } else { $range = ''; } } else { $range = ''; } //figure out download piece from range (if set) list($seek_start, $seek_end) = explode('-', $range, 2); //set start and end based on range (if set), else set defaults //also check for invalid ranges. $seek_end = (empty($seek_end)) ? ($size - 1) : min(abs(intval($seek_end)),($size - 1)); $seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)),0); //add headers if resumable if ($is_resume) { //Only send partial content header if downloading a piece of the file (IE workaround) if ($seek_start > 0 || $seek_end < ($size - 1)) { header('HTTP/1.1 206 Partial Content'); } header('Accept-Ranges: bytes'); header('Content-Range: bytes '.$seek_start.'-'.$seek_end.'/'.$size); } header("Cache-Control: cache, must-revalidate"); header("Pragma: public"); header('Content-Type: ' . $ctype); header("Content-Disposition: attachment; filename=\"".$filename."\""); header('Content-Length: '.($seek_end - $seek_start + 1)); //open the file $fp = fopen($path, 'rb'); //seek to start of missing part fseek($fp, $seek_start); //start buffered download while(!feof($fp)) { //reset time limit for big files set_time_limit(0); print(fread($fp, 1024*); flush(); ob_flush(); } fclose($fp); exit(); I did have the following section in replace of the above fread section up until this morning (but same issue): // http headers for zip downloads header("Pragma: public"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Cache-Control: public"); header("Content-Description: File Transfer"); header("Content-type: application/octet-stream"); header("Content-Disposition: attachment; filename=\"".$filename."\""); header("Content-Transfer-Encoding: binary"); header('Content-Length: '.$size); ob_end_flush(); @readfile($path); I have tried different headers and so forth, but all generally seem to bomb out occassionally before the download completes. But they don't bomb out at a particular point in the file size (ie at 25mb). Just seems to work and then die at the same time across different browsers, even when they are started at different times. Very strange and I've spent days modifying the script and still no answers. Sometimes the files download fine, but bomb out too many times for it to be satifactory to leave. Any help or pointers would be much appreciated. Quote Link to comment Share on other sites More sharing options...
Bottyz Posted October 10, 2011 Author Share Posted October 10, 2011 Hi all, Guessing no one can help with the problem? Or suggest any ideas? Anyways, I'm not sure if it is a problem with php but rather a problem with the setup of the host server? I just tried implementing the following code with the exact same results: /* Execution Time Unlimited */ set_time_limit(0); /* |---------------- | Header | Forcing a download using readfile() |---------------- */ header('Content-Description: File Transfer'); header('Content-Type: ' . $file_mime_type); header('Content-Disposition: attachment; filename=' . $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: ' . $file_size); ob_clean(); flush(); readfile($file_path); exit; I'm running out of options now, and not sure what else to pursue. Does anyone have any alternatives they could suggest? Thank you. Quote Link to comment Share on other sites More sharing options...
Muddy_Funster Posted October 10, 2011 Share Posted October 10, 2011 If you're just trying to get a file from a remote server onto your PHP webserver, I would go with ftp if you can. Quote Link to comment Share on other sites More sharing options...
Bottyz Posted October 10, 2011 Author Share Posted October 10, 2011 If you're just trying to get a file from a remote server onto your PHP webserver, I would go with ftp if you can. Hi muddy, No, I use cURL for that. This is a download script in a login area for some of our customers. The script is for software zip files mainly, but the occassion pdf is used. I think it has to be something wrong with the connection to the website. The files need to be secured so that they can't be stolen. Is there anything else I can use to stop the connection dropping or anything other than php that is reliable and easy to use as an alternative? Quote Link to comment Share on other sites More sharing options...
Muddy_Funster Posted October 10, 2011 Share Posted October 10, 2011 if your trying to get to a client machine then PHP doesn't strike me as the best option to take, I'd look at JAVAScript or AJAX options for the big files, and use <object> containers in the HTML for the likes of PDF Files, which will allow the users to download the files or view them live using existing commercial plugins. Quote Link to comment Share on other sites More sharing options...
Bottyz Posted October 10, 2011 Author Share Posted October 10, 2011 if your trying to get to a client machine then PHP doesn't strike me as the best option to take, I'd look at JAVAScript or AJAX options for the big files, and use <object> containers in the HTML for the likes of PDF Files, which will allow the users to download the files or view them live using existing commercial plugins. The problem is that all of the files are stored outside of the www root. We don't want the software etc to be downloaded without the right permissions, and we don't want the url openly available. I don't think I can do that with <object> containers. I've never used AJAX, but that is a type of javascript isn't it? So would it fall foul of people that don't have javascript enabled browsers? If not, I'll certainly have a closer look. Thanks for you comments thus far. Quote Link to comment Share on other sites More sharing options...
Muddy_Funster Posted October 10, 2011 Share Posted October 10, 2011 AJAX does require java enable browsing, bo if that's not a condition that you can set with the client machines then it's not going to be an option. Best I can suggest is that you force the browsers download manager to take charge of the file transfer, or at the extem end, program something specific that will manage downloads in a local language like C#/++ / pascal / VB and have the end users install and use that for the files. As for the object problem, you could simply have the tags published to the page by PHP only on event of an end user being validated. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.