Problem with PHP readfile() dumping binary data to the browser - php

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.

Related

Teamspeak Hostbanner doesn't work with PHP File

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;

App cache manifest is getting cached by Firefox. How set header that allows caching and updating?

When I server my manifest to Firefox it caches it. What header can I send with the manifest file (which is a PHP page) so it's not cached forever?
/* Firefox still caches the manifest with these headers */
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
This one also is ignored by Firefox:
Cache-Control: no-cache, private

502 Bad Gateway When Using Header Content-Length

I am trying to force the browser to download an mp3 when the user visits this site. The issue I am running into is if i set the Content-Length header the page throws a 502 Bad Gateway error, and if I don't it attempts to download the file, but the file is 0 bytes in size. The site happens to be running wordpress. Any direction would be really appreciated. I am not familiar with wordpress.
$file = '../uploads/2015/01/Thunder.mp3';
header('Content-type: application/mp3');
header("Content-Disposition: attachment; filename=\"$file\"");
header('Content-Length: '.filesize($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
Try Adding:
readfile($file);
after:
header('Pragma: public');

PHP headers for PDF.js to load and display progressively

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.

Stream mp3 with PHP, on Linux+FireFox

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.

Categories