Download PDF in Chrome from TCPDF - php

When a downloading PDF file in Chrome 12.0.742.91 (either as an attachment and inline), the download is interrupted (at the beginning it shows 125KB, but later 127518/0 B and then it stops entirely).
The file download works correctly in Firefox and IE. Headers are correct, apache returns 200 OK.
Previously, everything was ok, probably until a Chrome update a few days ago.

Just for further reference: The problem is related to the gzip handling. Disabling transparent gzip compression solved it.

Check your Content-Length header. It seems to be returning a size smaller than the file itself. I suspect Chrome is interrupting the download as its receiving more bytes than it should. It would be easy to put a test case in place for this however.

I had problems when the name of the file served contained weird characters like some accents (á é í ó ú) or this degree symbol: º.

Related

BOM being added to any return or die response

I'm using jQuery to retrieve a json response from an endpoint
die(json_encode(array('success' => 3, 'message' => 'You must use at least 1 credit or more.')));
Whenever I check the JSON response received in chrome developer tools I'm getting a red dot showing \ufeff is being added before the json response. I've encoded the PHP file with UTF-8 in Notepad++ however it still adds the BOM character infront of any response. If I return anything or change the die it will still show the BOM character in the response.
I've tried the same file on my localhost and it works absolutely fine however on the server it adds the character.
I'm at a loss as to what's causing the issue, any help would be greatly appreciated.
This is an 13 year old issue
There are workarounds (removing BOM from all PHP files, ob_clean at script start), but the real solution is to have a PHP compiled with --enable-zend-multibyte or --enable-mbstring, or wait until it is fixed by the PHP team.
As you sometimes have no control over the PHP version and compilation flags on hosted environments, I prefer removing BOMs from all PHP files, to prevent this kind of issues. This will work on any server.
Your solution is to fix the output with JS. But for other usages, e.g. generating an image or other binary data via PHP, or sending headers, you cannot solve this way.
It seems it was specifically an issue with this server configuration as it works on other servers. For the meantime I've filtered the response to remove any BOM chracters using javascript before parsing the JSON response.

PHP readfile() works but giving corrupted file

I'm using readfile() and header() for make the user download a file. This works good but today when I tried the script with a mp4 video file, the video get corrupted.
The video was uploaded with success for sure, because if I access the video directly in the address bar I can download it, but if I use my script (example download.php?id=105) I got a corrupted video. What I can't understand is because all other files (videos, images, pdf, ecc) were all downloaded correctly and this file is corrupted instead.
P.S The script I used (I repeat, it works for all file except this new video) is:
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Type: '.$mime);
header("Content-Transfer-Encoding: Binary");
header('Content-length: '.filesize($href));
header('Content-Disposition: inline; filename="'.(pathinfo($href, PATHINFO_BASENAME)).'"');
readfile($href);
EDIT: If i remove the headers and readfile, no error is shown.
Your problem is here:
echo readfile($href);
readfile() will return integer value (number of bytes that were read). This function will output result by itself - you don't need to do echo (and you shouldn't, in fact), use:
readfile($href);
-because otherwise you'll definitely get not the thing that you're expecting
May be change max_execution_time & max_input_time in php.ini (php config system)
; Maximum execution time of each script, in seconds
; http://php.net/max-execution-time
; Note: This directive is hardcoded to 0 for the CLI SAPI
max_execution_time = 300
; Maximum amount of time each script may spend parsing request data. It's a good
; idea to limit this time on productions servers in order to eliminate unexpectedly
; long running scripts.
; Note: This directive is hardcoded to -1 for the CLI SAPI
; Default Value: -1 (Unlimited)
; Development Value: 60 (60 seconds)
; Production Value: 60 (60 seconds)
; http://php.net/max-input-time
max_input_time = 300
My guess is wrong file path, but you said it is correct.
Only 1 possible error source left! Where? In code above the headers, which you did not show to us.
EDIT: If I remove the headers and readfile, no error is shown.
Please, remove the headers again (not the readfile part tho), and enable error reporting:
<?php
// Put these lines to the very top of your script
error_reporting(E_ALL);
ini_set('display_errors', true);
ini_set('display_startup_errors', true);
ini_set('xmlrpc_errors', true);
Quite sure you will see an error now.
I have same problem. The downloaded file corrupts, but the one on the server is correct. This sort of happens randomly. Sometimes, the downloaded file takes the name of the script plus its .php extension. I guess it's a problem with windows. Try uploading to a linux server and see if problem persists
I've been using PHP for most of my web apps, which usually included some form of download or another. They all worked fine until my most recent project. Videos/other files are uploaded correctly, but are corrupted on download. In order to inspect the problem, I used Burp Suite to intercept/inspect web traffic and here's what I got:
Image showing unwanted space in Video file
Notice the number of blank lines in the response at the right of the image (after "Content-Length: 11028102"). In HTTP standard, only one blank line (new line character) is to be left before the response body (which in this case is the video--what appears to be garbled text from line 21). In other words, the response body/video text should have started at line 13.
Initially, I thought it was a server problem, so I changed from Apache running on LAMPP to Nginx. Still problem persisted. I then supposed it was a PHP readfile() function problem, so I set up a Node Server on port 3000 strictly for download. So PHP /download page processes the request and fetches from Node server (which is JavaScript). I thought it'd be sufficient and faster since Node server does not create a new thread for each new connection unlike PHP and many other languages. It worked out well, the video file started from line 13 (in my case) as it ought to, and the files were no longer corrupted, plus it was very fast. However, this isn't a probable solution.
Simple Solution: So recently, I got curious again as regarding this problem, and inspected my index page using Burp Suite again and noticed similar occurrence to what was corrupting files: unnecessary space before the HTML as can be seen in the image below:
Image showing index file wrongly returned
The same space was there but the HTML comment was showing correctly starting at line 12. This was the top code portion of my index file:
<!--header-->
<?php
require_once "core/init.php";
require_once "header.php";
?>
This showed that the comment was output normally, starting from line 12 but there was space before the < !DOCTYPE html> contained in "header.php". Apparently, it was only "init.php" which sat between the HTML comment and the "header.php" where the HTML code starts. THIS HAD TO MEAN SOMETHING WAS WRONG WITH MY "init.php file
I then opened the file and noticed several blank lines corresponding in number to the blank lines that were output on Burp Suite, as shown in this image:
Image showing culprit blank lines in "init.php"
I simply deleted the blank lines and my files (in this case videos) were properly outputted as shown in this image:
Image showing properly outputted file from PHP
So, if you've got corrupted files on download, this is the problem. On that page, remove ANY SPACE before your PHP tags, check the files included on that page directly or indirectly using PHP, e.g., "init.php", "function files", "database connection files"; make sure there is NO SPACE before the PHP opening tag AND AFTER THE PHP closing tag. Clear all these blank lines and you're good to go! Good luck with your projects!

php inserts HEX number of characters before the content

I'm moving a website to a new server. (Old server had php 5.3.2, the new one has php 5.5.9)
Centos, httpd Apache/2.2.26.
I've copied files and it works fine except the only weird thing:
some strange HEX number is inserted before the content of pages:
Also, in the bottom of the page, 0 is inserted after the </html> tag.
I've noticed two things:
1) In my case only two headers are sent from php script:
header("HTTP/1.1 200 OK");
header("Status: 200");
If I comment the first header than It will be ok - no strange numbers.
2) It looks like that number is the number of characters on the page (I've checked it).
And if the page is less then 8000 characters, than the number doesn't appear, but if page has 8001 characters than 1F41 appears
P.S. I was advised to remove all BOM from files. Files were OK - already without BOM. So it's not about BOM.
UPD:
I made a very simple test (index.php):
<?php header("HTTP/1.1 200 OK"); ?>
Lorem Ipsum ... 8000 characters
Everything is OK.
<?php header("HTTP/1.1 200 OK"); ?>
Lorem Ipsum ... 8001 characters
Bug happens 1f41 before Lorem Ipsum.
This is not PHP nor a BOM. You have a problem with Content-Transfer-Encoding.
The server is sending along a Chunked encoding (this is usually done when the Content-Length is unavailable) which the client apparently doesn't know how to handle, or the header combination makes the client believe that it can bypass dechunking.
Therefore, what is actually the "length of next chunk" gets interpreted by the client, and you see it as a hex bit before the content:
05
These
05
Are
03
the
1F
first characters of the senten
03
ce.
instead of
Content-Length: 48
These are the first characters of the sentence.
(I calculated the lengths by eye, they're probably wrong)
The likely cause is that you have some kind of buffering which interferes with Content Encoding. If everything stays in the buffer, all well and good, a Content-Length is available, gets sent and Bob's your uncle. But if you send more than the 8000 bytes of the buffer, the buffer is flushed and something untoward happens. Try looking in the documentation for zlib and output buffering, you might have some conflict in php.ini between what Apache does and what PHP does.
Interesting links that show how exactly 8000 is (was?) a buffer size used in some portions of apache:
https://bugs.php.net/bug.php?id=45945
https://serverfault.com/questions/366996/how-can-the-apache-2-2-deflate-module-length-limit-be-increased
This last link suggests me to suggest you to try checking whether zlib, mod_gzip, ob_gzhandler and/or mod_deflate are enabled, and possibly conflicting, or to try exchanging the one for the other.
Update (as per comment)
Adding the appropriate Transfer-Encoding header fixes the problem.
So what really happened? We know that the output was correctly chunked-encoded (i.e. the chunking itself was correct), and the client was able to interpret it after being told to. So what was missing was simply the knowledge of the content being chunked, which looks absurd and a good bit buggy: for whatever chunked the content had to know it would get chunked (d'oh!), so it had responsibility of adding the appropriate header, and yet it did not (or it did, but something else stripped it), until the OP rectified the situation adding a header himself by hand.
The problem is now solved, but I think there must be still a bug lingering somewhere in the workflow, either in the modules, the application, or in how the headers are processed.
As discussed in the PHP chat room yesterday 9F 1A is the BOM for UTF-16BE Encoding
In my case only two headers are sent from php script:
header("HTTP/1.1 200 OK"); header("Status: 200");
What's going here? Why are you setting both? One is a proper http response, the other is a CGI response. You shouldn't need to set either, as PHP will default to a 200 OK if the script completes. And setting a CGI style header is probably wrong, unless you're definitely running PHP in CGI mode through Apache.
Had this problem for serving HTML as well as plain text.
EXPLICITLY setting header Transfer-Encoding to "chunked"
header("Transfer-Encoding: chunked");
indeed solved the problem (not sure how reliably though).
That Transfer-Encoding header was being added automatically even if i didn't set it - but the problem was still there. Setting the header explicitly in PHP code solved it, but not exactly - see below. Tested using websniffer.cc, PHP 7.4.9, CentOS 7.8
UPDATE: adding the header might confuse some clients. https://securityheaders.com/ failed to connect to the site with this header explicitly set on (regardless of content length)

$_GET encoding problem with cyrillic text

I'm trying this code (on my local web server)
<?php
echo 'the word is / думата е '.$_GET['word'];
?>
but I get corrupted result when enter ?word=проба
the word is / думата е ����
The document is saved as 'UTF-8 without BOM' and headers are also UTF-8.
I have tried urlencode() and urldecode() but the effect was same.
When upload it on web server, works fine...
What if you try sending a HTTP Content-type header, to indicate the browser which encoding / charset your page is generating ?
For instance, something like this might help :
header('Content-type: text/html; charset=UTF-8');
echo 'the word is / думата е '.$_GET['word'];
Of course, this is if you are generating HTML -- you probably are.
Considering there is a configuration setting at the server's level that defines which encoding is sent by default, maybe the default encoding on your server is OK -- while the one on your local server is not.
Sending such a header by yourself would solve the problem : it would make sure the encoding is always set properly.
I suppose you are using the Apache web server.
There is a common problem with Apache configuration - a line with "AddDefaultCharset" in the config should be commented out (add # in the begining of the line, or replace the line with "AddDefaultCharset off") because it "overrides any encoding given in the files in meta http-equiv or xml encoding tags".
In my current installation (Apache2 # Ubuntu Linux) the line is found in "/etc/apache2/conf.d/charset" but in other (Linux/Unix) setups can be in "/etc/apache2/httpd.conf", or "/etc/apache/httpd.conf" (if you are using Apache 1). If you don't find it in these files you can search for it with "cd /etc/apache2 ; grep -r AddDefaultCharset *" (for Apache 2 # Unix/Linux).
Take a look at Changing the server encoding. An excellent read!
Cheers!
If You recieve $_GET from AJAX make sure that Your blablabla.js file in UTF-8 encode. Also You can use iconv("cp1251","utf8",$_GET['word']); to display your $_GET['word'] in UTF-8
I just had the issue and it sometimes happens if you filter the GET variable with htmlentities(). It seems like this function converts cyrillic characters into weird stuff.

Strange http gzip issue

Here's a strange one:
I've got nginx reverse proxying requests to apache 2 with mod_php.
A user (using firefox 3.1b3) reported that recently, he's started getting sporadic "What should firefox do with this file?" popups during normal navigation. We haven't had any other reports of this issue, and haven't been able to reproduce it ourselves.
I checked Nginx and apache's logs. Nothing in the error logs, and they both show a normal HTTP 200 for the request.
I had him send me the downloaded file, and it's generated HTML, as it should be -- except it has some trailing and leading bytes tacked on.
The opening byte sequence is the magic gzip header: 1F8B08
Here are the opening characters, C-escaped for convenience:
\x1F\x8B\x089608\r\n<!DOCTYPE HTML ...
and the file ends with:
...</html>\n\r\n0\r\n\r\n
When I fetch the same URL via wget, it starts with as expected; the mysterious opening and closing bytes are nowhere to be seen.
Has anyone ever seen anything similar to this? Could this be a FF 3.1b3 bug?
Never seen an issue exactly like that, but I did have an issue once with a transparent proxy that would claim to the web server that it could handle gzip compressed content when, in fact, it received the gzipped content from the server, stripped the gzip headers without decompressing it, and sent the result to the browser. The behavior we saw was what you describe: a save/open file dialog for what should have been a normal web page. In this case the browser in question was IE.
I'm not sure if you're problem is related, but as an experiment, you could look at the requests between the proxy and Apache and see if they are gzipped, or else turn off the gzip compression for requests in Apache and see if that fixes the issue. If so, then you probably have a problem with gzip handling in your proxy.
wget doesn't request a compressed response. Try:
curl --compressed <URL>
You could also try adding a -v to print the response headers, and check that a sensible Content-Type is being returned.

Categories