Here is my problem. I am trying to download a file using header. Here is my code:
$content_type = mime_content_type('uploads/MyBBIntegrator_v1.3.1.zip');
$file = 'uploads/MyBBIntegrator_v1.3.1.zip';
header("Cache-Control: public");
header('Content-type: application/octet-stream');
header("Content-Description: File Transfer");
header('Content-Disposition: attachment; filename="MyBBIntegrator_v1.3.1.zip');
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile('uploads/MyBBIntegrator_v1.3.1.zip');
However, the only result of this is that the page displays the contents of the file (it is a text file) or a string of strange symbols if the file is image/zip/exe etc
What should I do to solve this problem?
First of all, mime_content_type() is deprecated, you should try another method to fetch the MIME value.
I have checked your code and it works fine on my server, and it works fine for me. You should check for INI directives which might block the download. Try a fresh install server.
Also, there should be no output generated by the script before the snippet you put into your question.
Related
I have a form which the user fills out with their details & serial number, the software installer is then downloaded, named as their input. e.g. serial.exe
Once the form is submitted I check the file exists and then attempt the file download:
$directory = get_template_directory();
$file = $directory . '/filename.exe';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$Serial.'.exe"');
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));
readfile($file);
exit;
}
This causes the loading to freeze, nothing below this code is loaded but i can't see any errors & no file is generated.
If i change the file to a .png the code works.
I've also copied the same code to a php page outside of wordpress, the same code runs & downloads the file as desired.
Is it possible that Wordpress is somehow blocking the readfile() request because its an .exe?
EDIT:
It appears to be a problem with the size of the file, rather than the type of file.
A small .exe file has worked & is downloaded correctly.
I've a strange behavior with a simple PHP code. When I try to force the download or print out the image using the correct content-type, the output file is corrupted.
Seems that the webserver (apache) adds two bytes (0x20 and 0x0A) at the begin of the file.
This is the code:
$file = "image.png";
$image = file_get_contents($file);
// Test
file_put_contents("test.png", $image);
// Download
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
echo $image;
I use the same code on other websites hosted on the same server without problems.
The problem is only on download only because test.png works properly. The MD5 checksum of text.png and the original image are equals.
This is the hex code of test.png.
And this is the hex code of the corrupted file after download:
As you can see, there are 2 extra bytes at the begin. If I remove them, the file returns to work properly.
I attach the screen of Wireshark (as you can see is not a browser issue):
How can I fix it?
The server is Ubuntu 16.04 with PHP-5.6 (yes I done the downgrade from 7.0 to 5.6 for compatibility issues with roundcube)
UPDATE 1: I'm trying to find if somewhere in the file there is a space + newline
UPDATE 2:
First of all: thanks.
The code is part of a Wordpress plugin and the download is called using the AJAX system. I wrote a simple plugin test:
<?php
/*
Plugin Name: Test
Plugin URI: http://www.google.com
Description: Test
Author: Anon
Version: 4.0
*/
function downlod_test() {
echo "test";
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=prova.html');
die();
}
function iopman_shared_download_doc_ajax() {
downlod_test();
}
add_action('wp_ajax_frontend_download_doc', 'iopman_shared_download_doc_ajax');
//downlod_test();
?>
If I call downlod_test with /wp-admin/admin-ajax.php?action=frontend_download_doc it adds the 2 extra bytes. If I call it directly (by removing the comments), it works.
So the problem now is: how to strip out these bytes that wordpress adds?
$file = "image.png";
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($file));
header("Content-Encoding: gzip");
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header("Content-Length: " . filesize($file));
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
ob_get_clean();
readfile($file);
exit;
To help you find that unwanted whitespace you can track loaded files with get_included_files(). Additionally, a backtrace could also shred some light on what your script does.
In many cases, it'll come from closing PHP tags at the end of the file. Since they're optional it's recommended to just not use them.
Once you locate the file where that white space is, you only need to load in your favourite text editor and remove them (you might need to enable your editor's Show hidden chars feature).
P.S. I understand that's probably simplified code to illustrate the issue but you may want to give readfile() a try.
What I'm trying to do:
Im trying to push a jpg file to download witout user seeing the URL. In this case the file is located at: http://www.example.com/upload/asdasdsadpokdaspdso/36.jpg.
My current code:
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$download->name.'.jpg"');
readfile($weburl."/upload/".$hiddenpassage."/".$download->link);
My vars / db values:
$weburl = "http://wwww.example.com";
$hiddenpassage = "asdasdsadpokdaspdso";
$download->link = 36.jpg //not a var, just drom db.
$download->name = The First Test Product //not a var, just from db.
The problem:
When I get the download I open it and I get the following error:
The file “The First Test Product (28).jpg” could not be opened.
It may be damaged or use a file format that Preview doesn’t recognize.
Renaming .jpg to .txt:
http://pastebin.com/K9NGL5RP
Most of that is the content of the page I downloaded it from.
I think you need to specify the whole header (untested). Specially the Content-Length.:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$download->name.'.jpg');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($weburl."/upload/".$hiddenpassage."/".$download->link));
readfile($weburl."/upload/".$hiddenpassage."/".$download->link);
Hope this helps.
I'm using PHP to generate a PDF via browser for my web-application. Recently, the client changed the webserver to Apache and now this feature is no longer working. Instead of generating the PDF, the browser is showing the PDF as text, just as it was ignoring Content-Type (that is set to "application/pdf"). In fact, I successfully simulated the problem by commenting the line setting the Content-Type in the source code.
I need ideas about where and what to look for, any help will be very welcome :)
Since you generate PDF files through PHP, you can try to add these headers:
$file_default = 'default filename you want to appear when the user downloads.pdf';
$file_location = '/path/to/file.pdf';
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$file_default);
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file_location));
ob_clean();
flush();
readfile($file_location);
I guess you'd have to force apache to download PDF content rather than showing:
check this: http://www.thingy-ma-jig.co.uk/blog/06-08-2007/force-a-pdf-to-download
This concerns downloading files with PHP
My php version is 5.3.5 and my apache is 2.2.17
I am trying to dowload files (pdf,jpg,tiff) that I have uploaded in my server, and they download with the same size and type but I can not see them. I am guessing they are not copied right. But when I open the original uploaded ones they work just fine.
I have seen almost all the questions that appeared as suggested and none of them answered the question, te only similar one is this, but still doesnt answer my question.
to download I am using this code
header("Content-type: application/force-download");
header('Content-Disposition: inline; filename="' . $dir . '"');
header("Content-Transfer-Encoding: Binary");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Content-length: ".filesize($dir));
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $file . '"');
readfile("$dir");
where $dir="62756d616769636e63/646973736572746174/ehddggh/1.JPG"
and $file="1.JPG"
can anyone give me a hint on what I am doing wrong, or give me a better solution to download files?
This smells like you are getting extra (spurious) content in your downloaded files.
Make sure you have no BOM headers, spaces, or anything else before your PHP open tags in your files; also, that you have no trailing whitespace or any other data after the closing PHP tags (if you close your PHP tags).
Also, clean up your code a bit: why multiple Content-Type headers? Why multiple Content-Disposition headers?
readfile($dir); // without the quotes?
Also, make sure that $dir actually exists
is_file($dir) or file_exists($dir)
Thank you all for the answers. I was calling the download as a function in a file with other functions in it so in the end I had to write a script alone, apart from other files. My problem was that I needed it to be safe and to only download a file if it belonged to the user and the user was logged in, so I send all the data I need, ciphered and inside the script I use a series of things to see if the owner is really the logged user. So if anyone wants to know this is the code I used and works perfectly.
<?php
session_start();
$a=$_GET['a'];
$parts=explode("-",$a);
$tres=$parts[0];
$nombre=$partes[1];
$dbcodletra=substr($tres,2);
if($dbcod!=$_SESSION["username"])$boolt=0;
if($ext==1) $extl=".jpg";
if($ext==2) $extl=".jpeg";
if($ext==3) $extl=".tif";
if($ext==4) $extl=".tiff";
if($ext==5) $extl=".pdf";
if($ext==6) $extl=".doc";
if($ext==7) $extl=".docx";
if($tipoproy==1) $dir="rute/".$dbcodletra."/".$nombre.$extl;
if($tipoproy==2) $dir="rute/".$dbcodletra."/".$nombre.$extl;
if($tipoproy==3) $dir="rute/".$dbcodletra."/".$nombre.$extl;
if($tipoproy==4) $dir="rute/".$dbcodletra."/".$nombre.$extl;
if (file_exists($dir) && $boolt) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($dir));
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($dir));
ob_clean();
flush();
readfile($dir);
exit;
}else echo "<meta http-equiv=\"Refresh\" content=\"0;url=misdocumentos.php\">";
?>
Paying it forward on a two-year old question...
I had a similar issue with corrupt downloads that could not be opened (when right-click & save-as worked perfectly). After reading #Jon's answer, I figured he was on to something. If you look at the docs for readfile (linked below), you will see an ob_clean(), a flush(), and an exit in their example. All of those will minimize leakage of extra character data in the response. I just copied their Example #1 and my problem was solved.
http://php.net/readfile
Your headers look messy, try just doing this:
header('Pragma: public');
header('Cache-Control: public, no-cache');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . filesize($dir));
header('Content-Disposition: attachment; filename="' . basename($dir) . '"');
header('Content-Transfer-Encoding: binary');
readfile($dir);