NYCPHP Meetup

NYPHP.org

[nycphp-talk] NEW PHundamentals Question - Headers & Downloads

Hans Zaunere hans at nyphp.com
Wed Oct 13 14:00:18 EDT 2004


It's PHunny Time! - 

> > For the next PHundamentals article, we are exploring best practices
in
> > the use of headers.  Over the next few weeks, we'll be asking about
the
> > various ways in which headers are used.  This week's question (see
> > below) concerns the use of headers which force downloads.
> 
> I have used this combination of headers with pretty good success:
> 
> Given an array containing the details of the file like:
> 
> $attach = array(
>    'filename' => 'myfile.pdf',
>    'mimetype' => 'application/pdf',
>    'content'  => 'pdf here'
> );
> 
> header('Content-Disposition: attachment; filename='.
$attach['filename']);
> header('Content-length: '. strlen($attach['content']));
> header('Content-type: '. $attach['mimetype']);
> echo $attach['content'];
> exit;
> 
> The Content-Disposition header tells the browser to open the download
> dialog, and lets it know the correct filename/extension.
> 
> The Content-length header allows the browser to display a meaningful
> progress bar.
> 
> The Content-type header lets the browser correctly display an
indication
> of the file type to the user (PDF,XLS,EXE etc).  In most browsers it
> will also influence the default action (open vs download).
> 
> For some files (pdf mostly) it can be a good idea to use a different
> Content-Disposition header, namely:
> 
> header('Content-Disposition: inline; filename='. $attach['filename']);
> 
> In most browsers this will result in the pdf file being opened within
> the browser window.
> 
> I have a bunch more information regarding the use of headers for cache
> control...but that wasn't what you were asking was it ;)

Maybe that'll be the next PHunny question on headers :)

Anyway, I've done much the same as Dan.

For instance, to force a download, even if a plugin for the file type
exists, this I think generally works:

header('Content-type: application/x-download');


And of course the disposition - we don't want a grumpy file...

header("Content-Disposition: attachment; filename=$filesaveas");

Then spit the file out:

readfile($filepath);

This of course would be an echo for non-filesystem content.

That's all well and good, but I've run into some tricky problems with IE
and SSL.  Now some would argue that this is a bug, but I think IE is
actually inline with the standard.  Details are at:

http://support.microsoft.com/default.aspx?scid=KB;EN-US;q316431&

Basically, when a previous header has been sent to not cache anything,
it won't let you save a file - that actually makes sense.  So, the
workaround, which I've found works all the time, it to replace the
default caching headers (ie, no-cache) with this:

header('Cache-Control: must-revalidate', TRUE);
header('Pragma: ', TRUE);

Next would be to send the standard disposition, type and so forth
headers, per above.

So that's one little gotcha, that I think I've been able to resolve.

Another gotcha, that I can't resolve, actually involves Mozilla.  For
instance, Mozilla (and derivatives) always append the file extension of
the type of page originally viewed.  What do people do for this?  For
instance, in phpMyAdmin, downloading a .sql file will be saved as a
.sql.php file.  I frankly haven't looked too deeply, but a work around
for the future would be nice.

So at the end of the day, I think it's somewhat of a black art.  On
occasion, trying to force a download vs a file open seems impossible,
depending on browser, version, and plugins.  Has anyone developed a
matrix like:

Browser -> Version -> Required Behavior -> Use These Headers?

Getting some definitive answers from the Browser/HTTP/Front-End guys
would be invaluable.

---
Hans Zaunere
President, Founder
New York PHP
http://www.nyphp.org





More information about the talk mailing list