Forum Moderators: coopster
I'm trying to make a simple download.php file, which I can call from anywhere on my website, which then downloads the file specified in the id. For eg: download.php?fileid=12345. They are everywhere, so I'm sure you know what I mean.
I'm doing the method suggested in the php.net docs, and everywhere else; send headers, then use readfile. Except the browsers seem to be allergic to it.
The one that shows the problem best, is Firefox - on a 400Kb ZIP it hung on "starting" in the transfer dialog, then after about 3-5 seconds would jump to 100% and say it was complete. I later tried it on a 4Mb RAR file, and when I requested the download, it sat loading the page for about 10-20 seconds, then brought up the "save download" dialog. I clicked save, and it immediately jumped to 100% and complete. IE and Opera are both doing the same (Opera also says "Error" instead of "Finished" when it is done). I must point out that the content of the downloaded archives is absolutely fine.
In the full blown version of the script (which didn't work), I get the ID, then check the DB for it. Get the filename from the DB, and setup the transfer. For the stripped out version, I commented out all the DB stuff, so I was left with just the transfer.
I can't see anything wrong in the code, and my friend assues me the headers are fine (although the rar mime type isn't correct).
The code:
//Clean the inputs, before using them in any further code.
$cln_fid = cleantxtinput($_GET['fid']);//Check the database for an artwork with a matching id, and a download filename that is NOT empty.
$get_file = runquery("SELECT download FROM fti_art_artwork WHERE artid = '$cln_fid' AND download!= ''");
if (mysql_num_rows($get_file) == 1) {
while($row = mysql_fetch_array($get_file, MYSQL_ASSOC)) {
$file_name = $row['download'];
}
//Get the file extension.
$ext = explode('.',$file_name);
$ext = $ext[count($ext)-1];
//Specify the mime type, depending on the file extension.
if(preg_match('/rar/i', $ext)) {
$mime = 'application/octet-stream';
} elseif(preg_match('/zip/i', $ext)) {
$mime = 'application/x-zip';
}
header('Content-Type: '.$mime);
header('Content-Disposition: attachment; filename="'.$file_name.'"');
header('Content-Length: '.filesize('files/'.$file_name));
readfile('files/'.$file_name);
} else {
//Log the error.
$level = 4;
$error = "The user \'$usersess_name\' requested to download the file with id \'$cln_fid\', except the file didn't exist, or more than one file was found.";
logdata($level,$error,'1');
//Display the error.
$tpl_errcode = $errcode;
$tpl_errtxt = 'The file you requested couldn\'t be found. If you got to this page by following a link on our website, please contact our support desk.';
$tpl_redirect = conf_baseurl.'index'.url_sess;
include('templates/default/error.tpl.php');
exit;
}
My only thought, is the file is being downloaded prior to the download dialog. Any other methods of doing the same thing?
All help is greatly appreciated.
[edited by: Fourjays at 5:02 pm (utc) on July 25, 2006]
There were some bugs in earlier versions of PHP, up to PHP 5.05 if I remember correctly where readfile() would choke. Here are a couple examples:
[bugs.php.net...]
[bugs.php.net...]
Ok, I just managed to get the area of what is causing the problem narrowed down.
In my full version, I have a head.php and foot.php which do things that need doing on every page. I hadn't put these on my "stripped" version, so I just tried it. With head.php, I get the problem. With foot.php alone, I get no problem. Now from my learners knowledge of php, the only thing in head.php that is even related to the download script is ob_start("ob_gzhandler"); as it is for output buffering (without it, I get the "headers already sent" errors)? Could this be causing my problems? Do I need to use a different variation of it?
Thanks
EDIT: I just managed to fix this, by using ob_start(), opposed to ob_start("ob_gzhandler").
[edited by: Fourjays at 9:21 pm (utc) on July 25, 2006]
I'm guessing that your
Content-Lengthwasn't correct since you were sizing it up prior to compression and after the output buffer was compressed the new
Content-Lengthdidn't match what you earlier told the browser it was going to be (in bytes that were not compressed).