views:

355

answers:

1

I have a PHP script being served over https:// that is trying to push a PDF file to the user. The problem that in Internet Explorer 6 (which unfortunately I still have to support) is not obeying the filename being set in the header. FireFox and IE7 are both working properly.

The file name keeps coming out as a random name with the correct extension. Example: "CAOTC5K3.pdf", "CAXSIPXV.pdf" or "CA1OCVTX.pdf"

If I un-comment out the "Content-type" line, IE6 gives me an error, and tries to download the file inline with the name of the querystring that was passed to PHP.

<?php
//header( "Content-type: application/pdf" );
$filename = 'quickquote.pdf';
header( "Content-Disposition: attachment;filename=$filename" );
echo file_get_contents( "/example.pdf" );
die;
?>

I have tried wrapping the file name in quotes, adding a \n at the end of the header lines, adding header('Content-type: application/octet-stream');, adding header("Content-Type: application/force-download");

+3  A: 

I think you might need a space after attachment;:

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

If that doesn't work, check out some of the points in this article, including:

  • On IE 6.0, things mostly work, but if you ALSO setup Cache-Control: no-cache, your suggested filename (and type!) will be IGNORED. A bummer if you have to choose between security and convienence. Of course, security wins.
  • On nearly all versions of IE, including 6.0, sometimes the browser will use the filename in the address bar instead of the Content-Disposition Header, and with IE5.5SP2 you're expected to change the UseCDFileName registry key, see Q303750. This was fixed with IE6.0SP1.

EDIT: Here's the code I use, directly copied from my application's source. Let me know if this works any better...

function forceDownload($filename,$mime=false,$downloadName=false)
{
    if(file_exists($filename) && is_readable($filename))
    {
        if(!$mime)      $mime = DFStdLib::determineMimeType($filename);

        if(!$expire)    $expire = DFStdLib::HOUR_IN_SECONDS;

        if(!$downloadName) $downloadName = basename($filename);

        header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($filename)).' GMT', true, 200);
        header('Cache-Control: no-cache',true);
        header('Pragma: Public',true);
        header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT',true);
        header('Content-Length: '.filesize($filename),true);
        header("Content-Type: {$mime}",true);
        header("Content-disposition: attachment; filename=$downloadName",true);
        readfile($filename);
        exit();
    }
    else
    {
        header('HTTP/1.1 404 Not Found',true,404);
        echo "<html><head><title>Not Found</title></head><body>The file was not found.</body></html>";
        exit();
    }
}

Usage for your case would be:

forceDownload('/example.pdf','application/pdf','quickquote.pdf');

Also you'll need to change DFStdLib::HOUR_IN_SECONDS to 3600 and write your own determineMimeType function, or delete that line and make the $mime argument required...

Josh
@Josh I did make this change however, it did not remedy my problem. Thanks so much.
bkulyk
@bkulyk: OK... thinking about how to respond... back at you soon!
Josh
@bkulyk: I just pasted in some code directly out of an app that's live and in use, and works fine. Actually it's code from my company's standard PHP library so it's probably been used a number of times. Does that help at all?
Josh
@Josh It seems to be the `header('Pragma: Public',true);` that did the trick. Thanks!!!
bkulyk
@bkulyk: Glad I could help!
Josh