2

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?

Community
  • 1
  • 1
lesolorzanov
  • 3,536
  • 8
  • 35
  • 53
  • `Content-type` twice... `Content-disposition` twice... The first headers won't do anythnig (won't be sent). Also `filesize($dir)` is a bit strange, don't you think? A **dir**'s **file**size... – Rudie Apr 25 '11 at 00:33

5 Answers5

3

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?

Jon
  • 428,835
  • 81
  • 738
  • 806
1

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

Community
  • 1
  • 1
jac2r
  • 31
  • 2
1
readfile($dir); // without the quotes?

Also, make sure that $dir actually exists

is_file($dir) or file_exists($dir)

Halcyon
  • 57,230
  • 10
  • 89
  • 128
1

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\">";
?>
lesolorzanov
  • 3,536
  • 8
  • 35
  • 53
0

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);
Alix Axel
  • 151,645
  • 95
  • 393
  • 500