PHP Version 5.2.17
I have the following PHP script for downloading a binary file:
<?php
$download_dir = '.';
$download_file = $_GET['get'];
$path = $download_dir.'/'.$download_file;
if(file_exists($path))
{
$size = filesize($path);
header('Content-Type: application/x-download');
header('Content-Disposition: attachment; filename='.$download_file);
header('Content-Length: '.$size);
header('Content-Transfer-Encoding: binary');
readfile($path);
}else{
echo "<font face=$textfont size=3>";
echo "<center><br><br>The file [<b>$download_file</b>] is not available for download.<br>";
}
?>
URL used to call this script:
Downloading works but the downloaded file has an additional byte (0x0a) appended.
The headers of the response also show a Content-Length that is one byte larger than the size of the requested file:
HTTP/1.1 200 OK
Date: Mon, 05 Dec 2011 10:29:32 GMT
Server: Apache/2.2
Content-Disposition: attachment; filename=FooBar_Setup.exe
Content-Length: 1417689
Content-Transfer-Encoding: binary
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/x-download
The size of the file on the server is 1417688 bytes.
I have verified that filesize($path)
returns the correct file size. It seems that PHP alters the Content-Length header with filesize($path)+1
.
I see this behavior with two different files.
How can I get prevend PHP from appending 0x0a to the downloaded binary files?
You most likely have an extra blank line after the closing ?>
, which is being echoed with the data. The closing ?>
is always optional at the end of a PHP file. Leaving it out is a good practice to prevent this sort of problem.
The reason the Content-Length changes is because the HTTP server (or PHP?) is ignoring it and adding a new one to match the actual data response before it gets sent it to the browser, so I think you can just leave that out. (If you do manage to send data with the wrong Content-Length, I've found browsers can act very weird.)
You have a line break in your PHP script after the closing ?>
tag. This is where the stray line break is coming from.
The best way to avoid this problem (which crops up a lot here on SO, by the way) is to not use the closing ?>
. PHP does not require it, and it helps avoid this problem.
Try Adding exit after readfile:
//ob_clean();
//flush();
readfile($path);
exit;
or you can remove the ?> if there is only 1 block of php code in the current file:
<?php
$download_dir = '.';
$download_file = $_GET['get'];
$path = $download_dir.'/'.$download_file;
if(file_exists($path))
{
$size = filesize($path);
header('Content-Type: application/x-download');
header('Content-Disposition: attachment; filename='.$download_file);
header('Content-Length: '.$size);
header('Content-Transfer-Encoding: binary');
readfile($path);
exit;
}else{
echo "<font face=$textfont size=3>";
echo "<center><br><br>The file [<b>$download_file</b>] is not available for download.<br>";
}
Compression can also cause extra bytes to show up in downloaded files. At the top of your script, add:
ini_set("zlib.output_compression", "off");
to disable it for that PHP script. Alternatively, or in addition, you may want to verify that your web server isn't also compressing your output for that script.