Forum Moderators: coopster

Message Too Old, No Replies

PHP Download Problems

Some weird problems.

         

Fourjays

4:58 pm on Jul 25, 2006 (gmt 0)

10+ Year Member



Well I've been talking to friends and googling all day for an answer to my problems, but noone seems to know what's up with this, and I can't find any answers on the web.

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;
}


I have no idea what is wrong. If it makes a difference, it is currently operating off a Windows PHP installation for offline use only. When it goes live, it will go on to a Linux server.

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]

coopster

8:31 pm on Jul 25, 2006 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Which version of PHP? How large are the files? Does it work with smaller files?

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...]

Fourjays

9:08 pm on Jul 25, 2006 (gmt 0)

10+ Year Member



I always forget to put my PHP version. It is PHP version 4.4.2. As I mentioned in the first post, I have tried it with a 400kb file and a 4Mb file. Both give the same results - weird behaviour with the download, but the content upon completion of the download is absolutely fine.

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]

coopster

10:49 am on Jul 26, 2006 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



There you have it! You cannot send header() [php.net]s if any other content has been pushed to output (the browser).

I'm guessing that your

Content-Length
wasn't correct since you were sizing it up prior to compression and after the output buffer was compressed the new
Content-Length
didn't match what you earlier told the browser it was going to be (in bytes that were not compressed).