Chrome adds "-, attachment" to downloaded file - php

I use Symfony2 Framework and use the following code to export an xml file:
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'application/xml');
$response->headers->set('Content-Description', 'Submissions Export');
$response->headers->set('Content-Disposition', 'attachment; filename="' . $filename .'"');
$response->headers->set('Content-Transfer-Encoding', 'binary');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', '0');
I does not matter whether I take "Content-Transfer-Encoding" or "Pragma" or all of them except "Content-Type" and "Content-Disposition" away. The result in Chrome is always: "filename-, attachment" (without the ").
In Firefox this works fine.
So for instance, if I have a file called home.xml Firefox will download home.xml, whereas Chrome will give me home.xml-, attachment.

I know this is a pretty old discussion, but if anyone gets here looking for help with this, I determined that chrome seems to want a semicolon at the end of the filename and then it's happy. As in (VBScript):
Response.AddHeader "Content-Disposition", "attachment;filename=Something.xls;"
That fixed it for me.
-Dave

I had the same problem in ZEND because I found a lot of non working stuff I wanted to add my anwser to this post. Since it took me a while to solve it thought more users and developers would wanted to know how I solved it. I add this just before my fopen call.
header('Content-Disposition: attachment; filename='.time().'.csv');
Solved the issue for me. Before I used a contextswitched what was buggy but now it works as a charm. Do not forget to remove previous content disposition headers hence you might get a double header error.

Related

Content-type ignored

this is my first question to the community, although I usually find all the answers I need on the forum, I had no luck on this one.
The problem is I have a php script witch outputs an inline pdf like so:
$doc = base64_decode( $rapport );
header('Content-type: application/pdf');
header("Content-Disposition: inline; filename='rapport.pdf'");
echo $doc;
But it only works when i open the page as an admin on my wordpress site.
If another user opens it, the Content-type header just get ignored ... but i can see the bytes of the doc.
I tested myself by opening the same page in the same browser logged in as another user and the header I see in chrome dev-tool is Text while it is application/pdf normally.
Any help would be appreciated.
Thx!
Edit: Problem half solved, the wp super cache plugin was compressing the output so everything works fine again without the cache... Any suggestions as how I should set the cache plugin to avoid breaking the dynamic content?

PDF Generation Results in ERR_INVALID_RESPONSE in Chrome

When generating a PDF in the browser programmatically (via PHP) the rendered PDF displays fine in both Firefox and Safari, but Chrome returns an ERR_INVALID_RESPONSE. It is a valid PDF - can be opened locally with Adobe Reader/Preview once saved from the working browsers, and will even open in Chrome once the PDF is saved from a different browser.
The PDF file is being read through file_get_contents(), is given a current timestamp and then passed to the browser. A workaround would involve saving the file to a temporary spot and redirecting the user (for Chrome, at least) but this is not ideal.
I've researched it and only been able to find bug reports dating from 2008.
I have an inkling it's a header error. After the PDF is generated, the following headers are sent to the browser (again working fine in FF, Safari and IE):
header('Content-type:application/pdf');
header("HTTP/1.1 200 OK");
I've also tried adding the following headers after searching on Stack Overflow, but to no avail:
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
Are there missing headers that Chrome requires? Does anyone have experience with getting dynamically generated PDFs to display in Chrome?
EDIT: One of my more salient questions is what could be causing this to work fine locally in Chrome, but wouldn't work on a server environment.
In my case I had to add these 2 parameters to headers because wordpress was sending 404 code as it didn't recognize the url of my php function:
header("Content-type: application/pdf",true,200);
as stated in this answer on wordpress.stackexchange.
This forces the headers to replace (2nd param true) the 404 status code generated by wordpress as it does not recognize the custom url, and sets 200 OK (3rd param 200).
So it ended being something like this:
$pdf_name = "test.pdf";
$pdf_file = "/absolute/path/to/my/pdfs/on/my/server/{$pdf_name}";
header('Content-type: application/pdf',true,200);
header("Content-Disposition: attachment; filename={$pdf_name}");
header('Cache-Control: public');
readfile($pdf_file);
exit();
Try this
<?php
$filename = 'Physical Path to PDf file.pdf';
$content = file_get_contents($filename);
header("Content-type:application/pdf");
// It will be called downloaded.pdf
header("Content-Disposition:inline;filename='".basename($filename)."'");
header('Content-Length: '.strlen( $content ));
// The PDF source is in original.pdf
readfile($filename);
?>
<html>
<body>
...
...
...
Make sure that above header code is called before output of PHP script is
sent to browser.
I want to thank everyone for their answers.
It turns out this was not related to the headers. After attempting to change/remove headers in various ways (detecting encoding, trying with and without content-length, etc.) we decided to dig into the deeper httpd logs to see if anything was resolving differently for Chrome.
It turns out that mod_sec on our server was flagging the request (only from Chrome for some reason) as an attempt at a file injection attack and was returning a 403 forbidden response. Chrome displayed this as the ERR_INVALID_RESPONSE rather than a 403.
The hostname of the CDN was present in the request (we had ample checking at the endpoint to ensure that the file was indeed an allowed resource), and instead are building the URL out on the server instead.

IE wants to download my JSON response; other browsers work as expected

My searching leads me to believe this is an issue with the headers being set for the response. This application is built using the Zend framework, and here are the headers being set (this response contains information about a file upload):
$response
->setHeader('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT')
->setHeader('Cache-Control', 'private, no-cache')
->setHeader('Pragma', 'no-cache')
->setHeader('Content-Disposition', 'inline; filename="files.json"')
->setHeader('X-Content-Type-Options', 'nosniff')
->setHeader('Content-type', 'application/json; charset=UTF-8');
This is the contents of the "files.json":
{"webpath":"http://www.domain.com/avatar/38b/3ef/f8b/a4c62a71.jpg","file_id":"484","height":250,"width":250}
Edit: I'm having this issue in all versions of IE, including IE9. I have also attempted to use 'text/plain' for the Content-type, with no avail. Also fixed the typo on the word "private".
When I am returning json I set the following in whateverAction():-
$this->getResponse()->setHttpResponseCode(200);
$this->getResponse()->setHeader('Content-Type', 'application/json');
$this->getResponse()->setBody($Json());
That's it, nothing else and it works across all browsers. All those I can test anyway, which includes IE 9.
If browsers ask you to download a JSON document nothing goes wrong. By default browsers do not display JSON which has a proper content type inline unless you have some extension installed (e.g. JSONView in Firefox).
If you just want to view the JSON created by your script, use such an extension or temporarily use a text content type (such as text/plain or text/javascript). In other cases leave it as-is since JSON should be sent with a proper content type.
Have you tried setting Content-Disposition to just "inline" (i.e. remove '; filename="files.json"')?
The headers tell IE to download the file. I would remove
->setHeader('Content-Disposition', 'inline; filename="files.json"')
because I think this one triggers the download.
If that's not the case, I would remove all headers at first, then review if they are all written properly (see "private") and test first with no headers and then adding them one by one to find out which one triggers your problem. Then please write which one it is to look further into it.

Zend Framework how to set headers

I have a question, how can I do something like this:
header("Content-Disposition: inline; filename=result.pdf");
header("Content-type: application/x-pdf");
With Zend Framework, I have tried:
$this->getResponse()
->setHeader('Content-Disposition:inline', ' filename=result.pdf')
->setHeader('Content-type', 'application/x-pdf');
But doesn't work correctly.
Your statement to set the response headers is slightly malformed:
$this->getResponse()
->setHeader('Content-Disposition', 'inline; filename=result.pdf')
->setHeader('Content-type', 'application/x-pdf');
The above should work - please note the difference in the Content-Disposition-header.
By the way... When you want to force a download box (instead of loading the document in the browser) you should use the Content-Disposition attachment.
$this->getResponse()
->setHeader('Content-Disposition', 'attachment; filename=result.pdf')
->setHeader('Content-type', 'application/x-pdf');
Depending on the browser it may be possible that you also have to set the Content-Length or change the Content-type to a combination (multiple headers) of one or more of application/force-download, application/octet-stream and/or application/download. And as I wrote in the comment sometimes caching headers may interfere with your download. Check to see which caching-headers are sent.
Late to the table, I can recommend this action helper as a simple, reusable component for sending files or in memory data to the browser.
Has options for caching, disposition and can utilise Apache Sendfile
My guess is that you're doing something like:
$this->getResponse()
->setHeader('Content-Disposition:inline', ' filename=result.pdf')
->setHeader('Content-type', 'application/x-pdf');
fpassthru($filename);
exit();
or something.
The response here will never be rendered (which renders the headers). The response is rendered during post-action printing, usually.
You will have to directly set the headers (as you noted in the non-oo code), or use $this->getResponse()->sendHeaders() directly.
I had a header set.
It was not set, but ADDED.
So I had a Content-Type of text/html and also application/pdf.
Flagging the Content-Type with TRUE made the download possible in IOS and other devices which showed only cryptic symbols after the download or an error:
->setHeader('Content-type', 'application/x-pdf', true);
setHeader($name, $value, $replace = false)
from:
https://framework.zend.com/manual/1.12/de/zend.controller.response.html
Solved
$this->getResponse()
->setHeader('Content-Disposition:inline', ';filename=result.pdf')
->setHeader('Content-Type', 'application/x-pdf');

File downloads in IE6

I've come across a rather interesing (and frustrating) problem with IE6. We are serving up some server generated pdfs and then simply setting headers in PHP to force a browser download of the file. Works fine and all, except in IE6 but only if the windows user account is set to standard user (ie. not administrator).
Since this is for a corporate environment, of course all their accounts are setup this way. Weird thing is, that in the download dialog, the Content-Type is not recognized:
header( 'Pragma: public' );
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate, pre-check=0, post-check=0' );
header( 'Cache-Control: public' );
header( 'Content-Description: File Transfer' );
header( 'Content-Type: application/pdf' );
header( 'Content-Disposition: attachment; filename="xxx.pdf"' );
header( 'Content-Transfer-Encoding: binary' );
echo $content;
exit;
I also tried writing the file content to a temporary file first so I could also set the Content-Length in the header but that didn't help.
These headers are bogus!
Content-Transfer-Encoding: binary
This header is copied from e-mail headers. It doesn't apply to HTTP simply because HTTP doesn't have any other mode of transfer than binary. Setting it makes as much sense as setting X-Bits-Per-Byte: 8.
Cache-control: pre-check=0, post-check=0
These non-standard values define when IE should check whether cached content is still fresh. 0 is the default, so setting it to 0 is waste of time. These directives apply only to cacheable content, and Expires:0 and must-revalidate hint that you wanted to make it non-cacheable.
Content-Description: File Transfer
This is another e-mail copycat. By design this header doesn't affect download in any way. It's just informative free-form text. It's technically as useful as X-Hi-Mom: I'm sending you a file! header.
header( 'Cache-Control: must-revalidate, pre-check=0, post-check=0' );
header( 'Cache-Control: public' );
In PHP second line completely overwrites the first one. You seem to be stabbing in the dark.
What really makes a difference
Content-Disposition: attachment
You don't have to insert filename there (you can use mod_rewrite or index.php/fakefilename.doc trick – it gives much better support for special characters and works in browsers that ignore the optional Content-Disposition header).
In IE it makes difference whether file is in cache or not ("Open" doens't work for non-cacheable files), and whether user has plug-in that claims to support type of file that IE detects.
To disable cache you only need Cache-control:no-cache (without 20 extra fake headers), and to make file cacheable you don't have to send anything.
NB: PHP has horrible misfeature called session.cache_limiter which hopelessly screws up HTTP headers unlesss you set it to none.
ini_set('session.cache_limiter','none'); // tell PHP to stop screwing up HTTP
some versions of IE seem to take
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate, pre-check=0, post-check=0' );
way too seriously and remove the downloaded content before it's passed to the plugin to display it.
Remove these two and you should be fine.
And make sure you are not using any server-side GZIP compression when working with PDFs because some versions of Acrobat seem to struggle with this.
I know I'm vague here, but above tips are based on real-world experience I got using a web application serving dynamically built PDFs containing barcodes. I don't know what versions are affected, I only know that using the two "tricks" above made the support calls go away :p
I have had the exact same problem about a year ago, and after much googling and research, my headers (from Java code) look for IE6 & PDFs like this:
response.setHeader("Content-Type", "application/pdf "; name=" + file.getName());
response.setContentType("application/pdf");
response.setHeader("Last-Modified", getHeaderDate(file.getFile());
response.setHeader("Content-Length", file.getLength());
Drop everything else.
There is apparently something a bit whacky with IE6, caching, forced downloading and plug-ins. I hope this works for you...a small difference for me is that the request initially comes from a Flash swf file. But that should not matter.
I appreciate the time you guys spent on this post. I tried several combinations and finally got my symfony project to work. Here I post the solutions in case anyone will have the same problem:
public function download(sfResponse $response) {
$response->clearHttpHeaders();
$response->setHttpHeader('Pragma: public', true);
$response->addCacheControlHttpHeader("Cache-control","private");
$response->setContentType('application/octet-stream', true);
$response->setHttpHeader('Content-Length', filesize(sfConfig::get('sf_web_dir') . sfConfig::get('app_paths_docPdf') . $this->getFilename()), true);
$response->setHttpHeader("Content-Disposition", "attachment; filename=\"". $this->getFilename() ."\"");
$response->setHttpHeader('Content-Transfer-Encoding', 'binary', true);
$response->setHttpHeader("Content-Description","File Transfer");
$response->sendHttpHeaders();
$response->setContent(readfile(sfConfig::get('sf_web_dir') . sfConfig::get('app_paths_docPdf') . $this->getFilename()));
return sfView::NONE;
}
This works just fine for me in IE6,IE7, Chrome, Firefox.
Hope this will help someone.
As pilif already mentions, make sure to turn off the server-side gzip compression. For me this has caused problems with PDF files (among other types) and for maybe-not-so-obscure reasons also with .zip files both under Internet Explorer and FireFox.
As far as I could tell, the last bit of the zip footer would get stripped (at least by FireFox) causing a corrupted format.
In PHP you can use the following code:
ini_set("zlib.output_compression",0);
The following bit of Java code works for me (tested on Firefox 2 and 3, IE 6 and 7):
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
response.setContentType(getServletContext().getMimeType(file.getName()));
response.setContentLength(file.length());
No other headers were necessary at all.
Also, I tested this code both with gzip compression on and off (using a separate servlet filter that does the compression). Doesn't make any difference (works without any problem in the four browsers I tested it on).
Plus, this works for other filetypes as well.
You can add an additional parameter that the server won't read to the url it might help too.
http://www.mycom.com/services/pdf?action=blahblah&filename=pdf0001.pdf
I have run into cases where ie will be more likely to read the filename on the end of the url than any of the headers
I had a similar problem, but it might not be exactly related. My issue was that IE6 seems to have a problem with special characters (specifically slashes) in the file name. Removing these fixed the issue.
If you are using SSL:
Make sure you do not include any cache control (or Pragma) headers. There is a bug in IE6 which will prevent users from downloading files if cache control headers are used. They will get an error message.
I pulled my hair out over this for 2 days, so hopefully this message helps someone.
simply switch to this content type and it will work, also be sure Pragma ist set to something NOT equal "no-cache"
header( 'Content-type: application/octet-stream'); # force download, no matter what mimetype
header( 'Content-Transfer-Encoding: binary' ); # is always ok, also for plain text

Categories