Does anyone know how to get PDF.js load and display pages progressively when PDF file is output by PHP ? When called directly, the PDF file loads fine and is displayed progressively but when PHP is taking care of the output of the same PDF file, PDF.js waits for the entire file to be loaded before displaying the first page. I tried different headers such as these without success :
$file = 'big.pdf';
$filename = 'fakefilename.pdf';
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
header('Accept-Ranges: bytes');
#readfile($file);
Thanks in advance for any help.
EDIT after #Rob's comment :
here are the logs from the web browser :
Accept-Ranges 0-23822222
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection Keep-Alive
Content-Length 23822222
Content-Range bytes 0-23822221/23822222
Content-Type application/pdf
Date Mon, 23 Jun 2014 13:06:33 GMT
Expires Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive timeout=15, max=99
Pragma no-cache
Server Apache/2.2.16 (Debian)
X-Powered-By PHP/5.3.3-7+squeeze19
Just adding the "Accept-Ranges" headers will not magically activate chunked responses. You have to recognize the HTTP Range header, seek in the file, then send this data together with a "206 Partial Content" status line and "Content-Range" header.
Here is sample code for streaming a MP4 file, it can almost directly be copy-pasted for PDFs. To have optimal display times, make sure that your PDF is linearized (also known as "Web optimized"). This is a feature of PDF document generators, which outputs the PDF stream in order so that all data required to render the first page(s) is available when the first chunks of the PDF file have been loaded.
Related
I have a few projects where file downloads don't works anymore. It seems due to a recent Chrome policy change.
Downloads tries fails with this error in the console :
Mixed Content: The site at 'https://example.com/' was loaded over a secure connection, but the file at 'https://example.com/logs_view.php?export=true' was redirected through an insecure connection. This file should be served over HTTPS. This download has been blocked. See https://blog.chromium.org/2020/02/protecting-users-from-insecure.html for more details.
My files are served thru PHP :
header("Content-Type: application/xls");
header("Content-Disposition: attachment; filename=".$filename.".xls");
header("Pragma: no-cache");
header("Expires: 0");
echo utf8_decode($export);
It seems this method don't send the file with HTTPS headers... Any idea on how to fix this ?
You can find below the headers of the server response header :
HTTP/1.1 200 OK
Date: Tue, 19 Jan 2021 11:33:14 GMT
Server: Apache
Expires: 0
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Disposition: attachment; filename=base_changelog_2021-01-19_12-33-14.xls
Content-Length: 899
Keep-Alive: timeout=5, max=92
Connection: Keep-Alive
Content-Type: application/xls
Thanks a lot for your support.
Ben
There is nothing wrong in Your code.
When You make redirect to the url which returns file You are trying to do it from http while you are on https secure connection. Probably You have link with wrong protocol.
I find a way to force chrome to "upgrade" the download.
I added to my .htaccess this tweak, and it did the job!!!
<ifModule mod_headers.c>
Header always set Content-Security-Policy "upgrade-insecure-requests;"
</IfModule>
i have this php page that looks like this:
/get_data.php?forid=123&pdid=456&exclude_ids=
it's accessed publicly and return the same content when provided with the same variables -"GET" variables that are included in the link- ,and i can't seem to have the browser cache the page so it won't bother the server every time the page is needed!
I've tried and added this line to the head of get_data.php but no luck
header('Cache-Control: public, max-age=7200');
this is the php file code:
<?php
header('Content-type: application/json');
header('Cache-Control: public, max-age=7200');
require('config.php');
$link_database = new mysqli($host,$dbusername,$dbpassword,$database);
...
?>
accessed like this in javascript:
xmlhttp.open("GET", "/get_data.php?forid="+forid+"&pdid="+pdid+"&exclude_ids="+existing_ids.join(","), true);
tested with firefox i get this raw response headers:
HTTP/1.1 200 OK
Date: Sat, 15 Jun 2019 16:04:54 GMT
Server: Apache/2.4.25 (Debian)
Cache-Control: public, max-age=7200
Keep-Alive: timeout=5, max=91
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json
is what i'm trying to do even a possibility?
if it is, how can i?
ps: the php code execute a simple sql, and a pure php cache system will not give any advantages(i think!).
I'm having a PHP file that is imitating a PNG file by setting the mime-type to image/png.
Thanks to a .htaccess-file that I have, I can access my image in these ways:
/img/img
/img/img.png
/img/img.php
and all of them are working well in my browser, but they don't load on my Teamspeak server.
I'm not sure what you expect to happen, these are the headers being returned:
CF-Cache-Status
MISS
CF-RAY
21cddbcc942220ae-LAX
Cache-Control
no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection
keep-alive
Content-Encoding
gzip
Content-Type
text/html; charset=UTF-8
Date
Fri, 28 Aug 2015 06:11:24 GMT
Expires
Thu, 19 Nov 1981 08:52:00 GMT
Pragma
no-cache
Server
cloudflare-nginx
Transfer-Encoding
chunked
Vary
Accept-Encoding
X-Powered-By
PHP/5.4.41-0+deb7u1
So first off, you are returning text/html. That is not the proper mime type for a .png image.
Secondarily, your script needs to actually return .png data.
I'm assuming here you plan to create the .png in your script using GD or ImageMagick, but whatever you plan to do, nothing will appear when an image is expected, when you don't actually provide the proper mime type and the proper image data that is expected to follow that mime type.
Setting the mime type at the top of your script is as easy as:
header('Content-type: image/png');
You are also going through Cloudflare. You should have Cloudflare turned off until you've debugged things and are sure that the script is operating as expected.
Thanks to #gview's answer I found out that Cloudflare was protecting the /img/ folder, so I made a page rule to stop this. Just in case you need it, this now is my script and it sets the correct headers:
# Generate $im and Stuff
# ...
# Now Output it
http_response_code(200);
$file = "./temp.png";
imagepng($im, $file);
header("Content-Type: image/png");
header("Content-Length: ".filesize($file));
readfile($file);
exit;
I'm trying to stream an mp3 file with PHP and play it on the browser.
I'm using Ubuntu for both the server ( apache ) and client for testing. My code works on Chrome, but not on FireFox.
When I access the mp3 directly ( so it's served by the web server ) it works on FireFox as well, but comparing the headers that the web server generates with the headers I send in PHP I couldn't find how to fix the problem. ( I'm spying the headers using FireBug )
Here are the webserver generated headers ( That does work ):
Accept-Ranges bytes
Connection Keep-Alive
Content-Length 490265
Content-Type audio/mpeg
Date Sun, 11 Mar 2012 04:01:45 GMT
Etag "22064e-77b19-4badff4a88200"
Keep-Alive timeout=5, max=100
Last-Modified Sat, 10 Mar 2012 09:15:52 GMT
Server Apache/2.2.20 (Ubuntu)
Here are the headers that are sent to the browser from my PHP script:
Accept-Ranges bytes
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection Keep-Alive
Content-Length 490265
Content-Type audio/mpeg
Date Sun, 11 Mar 2012 04:16:00 GMT
Expires Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive timeout=5, max=100
Pragma no-cache
Server Apache/2.2.20 (Ubuntu)
X-Powered-By PHP/5.3.6-13ubuntu3.6
This is the code I use to stream the mp3:
header('Content-length: ' . filesize($path));
header('Content-Type: audio/mpeg');
header('Accept-Ranges: bytes');
readfile($path);
exit;
I did also tried other headers which didn't help, such as:
header('Content-Disposition: inline; filename="name.mp3"');
header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
header('Pragma: no-cache');
header('Cache-Control: no-cache');
But like I said, none of these fixed the problem.
Many thanks for any help,
Oded.
EDIT:
OK this appears to be extremely strange. After much debugging, I made sure that the headers and content of the PHP version and the webserver versions are the same, and then I found out what breaks it, but I have no idea why. Here is the scenario that breaks it:
1) Store a string of a path in $_SESSION in a previous script.
2) Read this string in the script that streams the mp3.
3) Use this string as the path to load the mp3 file.
If I do that, FireFox cannot play the file, when I press on the mp3 player, it prints a "GstDecodeBin2: This appears to be a text file" message.
If I hard code the path instead of using the $_SESSION, it works. The crazy thing is that I made absolutely sure that the path in the $_SESSION is correct! Remember that the headers and content of the PHP and webserver versions are identical!
The HTTP Accept-Ranges header allows the browser to send a starting and ending point of the file to download, this allows for multi-part downloading of the same file. There are plenty of PHP implementations of this, here is one found on the PHP.net documentation page for fread().
http://www.php.net/manual/en/function.fread.php#106999
I found what the problem is using WireShark to monitor the requests. Earlier I used FireBug and HTTPFox, and they don't show all the requests!
WireShark showed me that after the initial successful request there is another request for the same URI. This second request was not caught by xdebug, and was missed by FireBug, and HTTPFox. The problem is that this request does not include the PHPSESSID! Obviously as a result the session did not work, and because it did work on the first request I was confused.
This seems to me like a bug in FireFox with its media player module.
I can work around this by manually adding the PHPSESSID to the URL as query string.
I trying to force a download by the browser here is my code:
header("Content-Type: application/force-download");
header('Content-type: audio/mp3');
header('Content-Description: File Download');
header('Content-Disposition: attachment; filename=' . $file_name);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-length: ' . filesize($file_path);
ob_clean();
flush();
readfile($file_path);
This works perfectly on my local machine, but when I upload it to my live server, the binary file is dumped to the browser and those gibberish characters fill up the browser window. What could be the problem? I am on a shared server so I don't know if my apache configuration needs to be changed or something.
I took #sanmi advice and used Firebug to see the response header and here is what I got:
Here is what I got sanmai:
Server nginx/0.7.67
Date Tue, 06 Sep 2011 15:02:03 GMT
Content-Type text/html; charset=UTF-8
Transfer-Encoding chunked
Connection keep-alive
Expires Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma no-cache
Vary Accept-Encoding,User-Agent
Content-Encoding gzip
I can see that the content-type entry has changed to text/html, and that the server is actually a nginx one. So is this a nginx issue or are my header entries wrong?
Thanks,
Tsega
It turns our one of the files I include had a blank line after the closing php tag. That was the problem, thanks everyone for your help.
Here
header("Content-Type: application/force-download");
header('Content-type: audio/mp3');
You send two Content-Type, only one is necessary.
I am not sure if this might be causing it, but content type audio/mp3 isn't defined(officially): http://www.iana.org/assignments/media-types/audio/index.html . Try using audio/mpeg?
Use FireBug or other means to view HTTP headers your server actually sending. It may hide or alter any of them. If so, talk to your hosting's support.