Toruble with corrupted files delivered through php-header-download

Hello there,

I googled for this problem a lot and did some digging in this forum, but nothing really matches my problem.

As the summary suggests, I made a script which serves a file, thus masking its path on the server and supporting authorisation.
Unfortunately some customers complain about getting corrupted files. Even reloading the files does not help. The data on the server is definitely not corrupted for this problem does only occur very rarely. Alas I have not got further information about those having trouble with corrupted files.
I checked whether there are chars before <?php or after ?>, which is not the case. To be sure, I even set error_reporting(0); for testing purposes on the download page.

Recently I realised that the response headers on the customer’s server server differ from my local Apache and my private webspace. Especially the Content-Length header is not set on my customer’s server for a reason I cannot understand. I also suspect the “Transfer-Encoding: chunked” which magically appears although never being set by me to maybe cause trouble.

Before posting the basic code of my script with all the headers and the different response headers, I shape my question:

Is it possible that these cases with corrupted data occur due to the headers sent on the customer’s server?
If yes: What can I do about it? The headers below are the only ones I set in my entire script.
If no: What else can cause the files being corrupted constantly for several customers?

I appreciate any help, thank you in anticipation!

Sincerely yours.


error_reporting(0);

$file = "file.exe";

header('Content-Description: File Transfer');
$modified = gmdate('D, d M Y H:i:s').' GMT';
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Last-Modified: $modified");

$filesize = filesize($file);

header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: binary");
header("Expires: ".date("r", time() + (24 * 3600))); 
header('Accept-Ranges: bytes');
header("Cache-Control: private", false);
header("Pragma: private");

header("Content-Length: ".$filesize);
header('Content-Disposition: attachment; filename="'.basename($file).'"');
	
ob_clean();
flush();
readfile($file);
exit;

Output on the customer’s server:


HTTP/1.1 200 OK
Date	Thu, 11 Mar 2010 13:05:14 GMT
Server	Apache/2.2.14 (Unix)
X-Powered-By	PHP/5.2.12
Content-Description	File Transfer
Cache-Control	must-revalidate, post-check=0, pre-check=0, private
Content-Transfer-Encoding	binary
Last-Modified	Thu, 11 Mar 2010 13:05:15 GMT
Expires	Fri, 12 Mar 2010 14:05:15 +0100
Accept-Ranges	bytes
Vary	Accept-Encoding
Pragma	private
Content-Encoding	gzip
Content-Disposition	attachment; filename="file.exe"
Content-Type	application/octet-stream
Transfer-Encoding	chunked

Output on my webspace:


HTTP/1.1 200 OK
Date	Thu, 11 Mar 2010 13:12:12 GMT
Server	Apache/2.2.9 (Debian) DAV/2 mod_ssl/2.2.9 OpenSSL/0.9.8g PHP/5.2.6-1+lenny3 with Suhosin-Patch
X-Powered-By	PHP/5.2.6-1+lenny3
Content-Description	File Transfer
Cache-Control	must-revalidate, post-check=0, pre-check=0
Content-Transfer-Encoding	binary
Last-Modified	Thu, 11 Mar 2010 13:12:12 GMT
Expires	Fri, 12 Mar 2010 14:12:12 +0100
Accept-Ranges	bytes
Cache-Control	private
Pragma	private
Content-Length	573943
Content-Disposition	attachment; filename="file.exe"
Content-Type	application/octet-stream

Output on my local Apache:


HTTP/1.1 200 OK
Date	Thu, 11 Mar 2010 13:02:53 GMT
Server	Apache/2.2.13 (Win32) PHP/5.2.11
X-Powered-By	PHP/5.2.11
Content-Description	File Transfer
Cache-Control	must-revalidate, post-check=0, pre-check=0
Content-Transfer-Encoding	binary
Last-Modified	Thu, 11 Mar 2010 13:02:53 GMT
Expires	Fri, 12 Mar 2010 14:02:53 +0100
Accept-Ranges	bytes
Cache-Control	private
Pragma	private
Content-Length	573943
Content-Disposition	attachment; filename="file.exe"
Content-Type	application/octet-stream