Question on using PHP for downloads

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
DuFF
Forum Contributor
Posts: 495
Joined: Tue Jun 24, 2003 7:49 pm
Location: USA

Question on using PHP for downloads

Post by DuFF »

I'm sure you've all seen them when you're downloading a file:

Code: Select all

Thank you for downloading the file!
If the download doesn't start within 5 seconds click here.
Now, I am currently making a site that lets users download files via PHP scripts, but mine works a little different. When the users click a link, it redirects them to download.php which increments the total downloads by 1 and then quickly redirects the user straight to the file (example: /path/to/file/file.zip). In fact you don't even see the download.php because it doesn't output anything to the browser, so all you see is the download popup straight away.

Now here's the question, is this a "bad" way of doing this? And if it is, what is happening on the other pages the make you wait 5 seconds to download?

Thanks in advance for any pointers.
Straterra
Forum Regular
Posts: 527
Joined: Mon Nov 24, 2003 8:46 am
Location: Indianapolis, Indiana
Contact:

Post by Straterra »

Code: Select all

<meta http-equiv="refresh" content="timeinseconds;url=your_url">

If you use the code above, instead of headers, you can get a time delay for the redirect.
Gen-ik
DevNet Resident
Posts: 1059
Joined: Mon Aug 12, 2002 7:08 pm
Location: London. UK.

Post by Gen-ik »

@ DuFF

I've personally been using the way you are suggesting for file downloads for a while now without any problems. User clicks on a link to something like download.php?file=fileToDownload and then download.php will spit out the relevant header information and file, and update and database info etc.

The only problem I have come across are the names of the file(s) which are downloaded. For example if I wanted download.php to kick out images.zip using the url download.php?file=images.zip then for some reason the name of the actual file is displayed as download.php?file=images.zip instead of just images.zip..... which is annoying for me and will probably cause some confusion for the user.

If anyone knows of a good work-around for getting the file names to display correctly then I think this method of file downloading is pretty solid, and (apart from the file names) I haven't had any trouble with it.
redmonkey
Forum Regular
Posts: 836
Joined: Thu Dec 18, 2003 3:58 pm

Post by redmonkey »

@Gen-ik

try using content disposition....

Code: Select all

$file = 'readme.txt';

header("Content-Disposition: attachment; filename=" . '"' . $file . '"');
I have found that by enclosing the filename in double-quotes within the header definition, it seems to be recognised and handled by more browsers types.
Gen-ik
DevNet Resident
Posts: 1059
Joined: Mon Aug 12, 2002 7:08 pm
Location: London. UK.

Post by Gen-ik »

redmonkey wrote:@Gen-ik

try using content disposition....

Code: Select all

$file = 'readme.txt';

header("Content-Disposition: attachment; filename=" . '"' . $file . '"');
I have found that by enclosing the filename in double-quotes within the header definition, it seems to be recognised and handled by more browsers types.

Works for NS/Firebird but not for IE.
This is the test code I'm using...

Code: Select all

<?php ob_start();

$file = $_GET["file"];

header("Cache-Control: private\r\n");
header("Content-Type: application/x-zip-compressed\r\n");
header("Content-Disposition: attachment; filename=" . '"' . $file . '"'); 

readfile($file);

ob_end_flush(); ?>
The file is called with download.php?file=testFile.zip
redmonkey
Forum Regular
Posts: 836
Joined: Thu Dec 18, 2003 3:58 pm

Post by redmonkey »

Code: Select all

$file = $_GET["file"];
$mime_type = 'application/x-compress';
$filesize = filesize($file);

header("Content-Type: " . $mime_type);
header("Content-Length: ".$filesize);
header("Content-Disposition: attachment; filename=" . '"' . $file . '"');
header("Content-Transfer-Encoding: binary");

$contents = @readfile($tmpfile);
I have used this and it works for IE,NS,Mozilla without any problems (for me anyway).

I also use 'application/x-compress' as the mime type for zips, I don't know if it makes any difference.

The only other thing is I don't use ob_start(), I had some problems with this perhaps maybe PHP version specific but it ended up throwing the file out twice within one file.
User avatar
DuFF
Forum Contributor
Posts: 495
Joined: Tue Jun 24, 2003 7:49 pm
Location: USA

Post by DuFF »

Gen-ik wrote:User clicks on a link to something like download.php?file=fileToDownload and then download.php will spit out the relevant header information and file, and update and database info etc.
Header information? Whats that? Heres how I'm currently doing it:

mapdl.php?id=183

Code: Select all

<?php
        $id = $_GET["id"];
        //connect
        include("dbclass.php");
        $db = new dbSQL;
        $db->dbConnect();

        //increment number of downloads
        $query="UPDATE maps SET downloads=downloads+1 WHERE id='$id'";
        $db->dbQuery($query, 0);
        
        //get file info
        $query2="SELECT * FROM maps WHERE id='$id'";
        $r = $db->dbQuery($query2, 1);
        $db->dbClose();
        
        //redirect to file
        $path = $_SERVER['DOCUMENT_ROOT'] . $r[category] . "/maps/" . $r[file];
        $redirect = "Location: $filepath";
?>
Do I need to add anything?
Gen-ik
DevNet Resident
Posts: 1059
Joined: Mon Aug 12, 2002 7:08 pm
Location: London. UK.

Post by Gen-ik »

Nope that way works as well.

The only reason I use PHP as a 'stream' for any downloads is to keep the location of the actual files secure (not always needed) and also if I use a class() to dynamically build a ZIP file then headers() etc are required.

In your code though you are redirecting directly to the file you want to download which is another way of doing it... and there's nothing wrong with that :)
redmonkey
Forum Regular
Posts: 836
Joined: Thu Dec 18, 2003 3:58 pm

Post by redmonkey »

I should point out (and perhaps that is what you are talking about) when you use those headers in IE the initial pop-up asking if you want to save to disk does contain the filename as 'download.php?file=testFile.zip', I have not found a way round this, however when the save dialog opens it should have the correct filename.

My code example above has a small typo, it should be $contents = @readfile($file); and not $contents = @readfile($tmpfile);
Gen-ik
DevNet Resident
Posts: 1059
Joined: Mon Aug 12, 2002 7:08 pm
Location: London. UK.

Post by Gen-ik »

redmonkey wrote:I should point out (and perhaps that is what you are talking about) when you use those headers in IE the initial pop-up asking if you want to save to disk does contain the filename as 'download.php?file=testFile.zip', I have not found a way round this, however when the save dialog opens it should have the correct filename.

My code example above has a small typo, it should be $contents = @readfile($file); and not $contents = @readfile($tmpfile);
Yep, this is what I was on about :)

I do need the filename to be correct though (even on IE) so I'm thinking about using mod-rewrite as part of the download... so pointing to something like downloads/myImages.zip would actually be pointed to download.php?file=myImages.zip... that would work on all browsers and display the correct filename (in this case myImages.zip) and not (as IE likes to do) the PHP filename.
Post Reply