I am using Zend and have some files outside of the webroot that I would like to be able to serve up. I have tried two approaches, both of which work in all browsers except for versions of IE 8 or lower.
The two (working) approaches that I have tried are the following:
// Approach #1
header('Content-Type: application/pdf');
header("Pragma: ");
header("Content-Disposition: attachment; filename=\"$filename\"");
//header('Content-Transfer-Encoding: binary');
header("Pragma: no-cache");
header("Expires: 0");
readfile($file);
// Approach #2
$this->getResponse()
->setHeader('Content-Disposition', "attachment; filename=$filename")
->setHeader('Content-type', 'application/x-pdf');
fpassthru($file);
Like I said, both approaches work in modern browsers (even IE9) but not in older versions of IE. The error I am getting is the following: http://cl.ly/image/1G3x370b1s09
I have looked into several posts on this topic and tried more different combinations of headers than I can even count. Is there a more bulletproof way of handling this functionality that wont cause issues with older browsers?
Thanks!
I've fought with this before and I think it stems from caching headers.
There's three: Expires, Cache-Control (HTTP 1.1), and Pragma (HTTP 1.0). My experience has been the older versions of IE like to see all three of these headers. Try using the following prior to any other headers and content you send:
header("Cache-control: no-cache");
header("Pragma: no-cache");
header("Expires: -1");
This article from Microsoft goes in to more discussion about the caching headers.
This is what I have done in the past to get it to work:
$file = $fileInfo->openFile('r');
header("Pragma: public");
header("Cache-Control: public");
header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="'.$file->getFilename().'"');
print $file->fpassthru()
Against my will I gave up on trying to fight with headers and completely changed the way I am handling file downloads. When a user requests a file now, it is temporarily hashed, copied to an area that the web-server can see, the user is redirect to that file and once they leave the download area the file is deleted. If they go inactive the file is deleted automatically at a set interval.
Thank you for all of the input kulishch and how ironic is it that you are from Minnesota as well!? Happy Holidays!
-- Nicholas
Follwing the advice at http://support.microsoft.com/default.aspx?scid=KB;EN-US;q316431&, these headers worked for me:
header("Cache-control: max-age=3600, must-revalidate");
header("Pragma: public");
header("Expires: -1");
I always get caught out by this! :(
Related
My question is simply: how can I output an mp3 with PHP that is seekable? I believe I have the appropriate headers set and I have tried with both readfile() and fopen() because my research has led me to believe that readfile() does not support byteranges and fopen() does. However, I really don't understand how to work with or set byteranges, just that I apparently need to. I am playing the song through jPlayer and the song plays fine, but it not seekable. In other words, you can't skip through the song by clicking different places on the seek bar.
Here is the code that is outputting the mp3 file:
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false); // required for certain browsers
header("Content-Type: audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3");
header("Content-Disposition: inline; filename=" . $file . ";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($path));
//readfile("$path");
$music = fopen($path, 'r');
fseek($music, 0);
fpassthru($music);
exit();
If I need to read the Range header, how do I do that?
I've spent days trying to solve the same thing. I'm yet to crack it, but I have noticed this.
Mp3s aren't skipping ahead (due to quicktime grabbing the first byte then going back to the rest)
soundcloud streams (which are mp3) however, are letting me skip ahead (when played through the same player)
I suspect you might find the solution in the the soundcloud headers (since they somehow cracked it).
I'm trying to force download a image file (jpg for example) using php. So I have a script here force.php and here would be the code:
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header('Content-Description: File Transfer');
header("Content-Type: image/jpeg");
header('Content-Length: ' . filesize($file));
header('Content-Disposition: attachment; filename=test.jpg');
readfile($file);
Now the problem is for some browsers (mobile phone browsers especially), it'll work properly and prompt test.jpg for the user to save. However on some browser, it'll prompt force.php as download. Any solution?
Thank you!
Content disposition header highly depends on how a particular browser implements it. Sometimes there are encoding issues (I do not see in your case).
The document at Test Cases for HTTP Content-Disposition shows behavior for various browsers.
To be safe with mobile browsers you should consider having the http request's last part be equal to the actual filename of the attachment, for example http://some.url/download/test.jpg .
Use apache mod_rewrite or similar to route such requests to your download script.
I'm offering a sermon downloading site and I have a user experiencing an issue with his download. Anyone have any ideas on how I can improve this code, or perhaps send better headers...
$path = "http://www.domain.com/sermon_files/".date("Y", $array["preached"])."/".$array["filename"];
$corePath = "/home/user/public_html/sermon_files/".date("Y", $array["preached"])."/".$array["filename"];
if (!file_exists($corePath)) {
echo "An error has occured with this download.";
} else {
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-Type: audio/mp3");
header("Content-Disposition: attachment; filename=\"".$array["title"]."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($corePath));
readfile($path);
exit();
}
Take a look at this thread, I had similar problems: PHP: Force file download and IE, yet again. Also consider using Fiddler to capture the exact HTTP headers that are being sent to the client.
Combine your PHP ( ? ) code with a server with X-Send available, lighttpd has it so does apache
Watch out for Expires: 0 on downloads. This messes with IE6's tiny little brain and makes it think there is no data to save/open. Try expiring in a minute from access and see if that fixes the problem. Otherwise, tell us exactly what the problem is.
I am generating dynamic PDF reports in PHP and having some issues with links to the web.
My links are to a PHP script that forces the download of a file attachment. This script works perfectly in all browser when accessed via the browser. It also works from the PDF in all browser except Internet Explorer.
Instead of IE seeing the file as a PDF, PNG, or whatever the file is, the download prompt says the document type is: "HTML Plugin Document"
If the user clicks "Open" or "Save" IE says it cannot download the file and gives the filename as "index2.php". That is the beginning of the URI of address.
The correct filesize is given so I know it is getting the file. Maybe it is a header issue?
Here is the header I'm creating on the download script:
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT;");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT;");
header("Pragma: no-cache;"); // HTTP/1.0
header('Content-Type: '.$file->file_mime_type.';');
header("Content-Description: File Transfer");
header("Cache-Control: public");
header('Content-Disposition: attachment; filename="'.$file->file_name.'";');
header('Content-Length: '.$file->file_size.';');
header('Content-transfer-encoding: binary');
Any input would be greatly appreciated.
Here's what I use and that is proven to work:
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="'.$file->file_name.'"');
readfile($filename);
have you tried something like this?
header('Content-Disposition: attachment; filename="'.$file->filename.'"');
It might be worth mentioning that there is also a known issue on several versions of IE when transferring files over SSL which requires the following work around:
header("Cache-Control: maxage=1");
header("Pragma: public");
There is more information regarding this bug here: http://support.microsoft.com/kb/812935
So, I have a file that sends the following:
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: private");
header("Content-type: application/pdf");
header("Content-disposition: inline; filename=file.pdf");
header("Content-length: 7735");
then I echo out the file - it is a PDF file.
Works fine in IE6 & 7 on XP (and FF for that matter)
The very same code shows nothing when running on IE8 on either XP or Vista.
There are no security warnings, etc so I don't think it has to do with that.
And, if my memory serves me correctly, this worked on IE8 a while ago.
What am I doing wrong here? Am I missing something out of the headers?
Is there a way for me to see what header information normal comes over when viewing a PDF in IE8 so I know what to emulate?
After looking at things it still works in IE8 EXCEPT when SSL is on
Under HTTPS and IE8, those headers fix the download problem:
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Pragma: public");
Other X-something headers did not make any difference.
It has probably to do do with the SSL. I read this article (in German, with code examples) where the author set the following header:
header('Pragma: anytextexeptno-cache', true);
I'm not sure what is needed, but here is what you could do.
Put the file temporarily in a public place on your server, make syre you can download that with a direct link in IE8, Use firefox LiveHTTP headers or similar to grab all headers that the server sends. Spit them out in exactly the same way and order in your script. (And don't forget to delete the file).
Something I want to add, as I faced this problem, too, in a slightly different way using Joomla.
Normal PDF-Output of content worked fine, in all browsers.
But the generation of a pdf from within my own component (using JDocument, tho) generated the bevahiour mentioned above.
My solution: Explicitly enable caching for my component using the following statement in view.html.php:
JResponse::allowCache(true);
Maybe that helps somebody.
I'm using HTTPS and i had some problems, but using those headers the download did.
Try it.
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Pragma: public");
header("X-Download-Options: noopen "); // For IE8
header("X-Content-Type-Options: nosniff"); // For IE8
header("Content-type: application/pdf");
header("Content-disposition: inline; filename=file.pdf");
header("Content-length: 7735");
The problem is you cant direct open. Just save.
Possibly related: Can't display PDF from HTTPS in IE 8 (on 64-bit Vista)