File download is not working - showing non readable text or content on same page


I have used below file download php script which works fine on my PC. But when I published this code to server, it throws two errors

  1. Warning: Cannot modify header information - headers already sent by… To avoid this warning I have used ob_start();… which helped to remove these warnings but major problem is
  2. when clicked download button, it shows text which is not in readable format.

Code used

		$file = "upload/".$filecode;
		$actualfilename = $filecode;
		if (file_exists($file))
			$INC_DIR = $_SERVER["DOCUMENT_ROOT"]. "/inc/"; 
			$con = $db->fnInitConn();
			header('Content-Description: File Transfer');
			//Below line is replace by force-download because this was not working when downloaded from web server
			header('Content-Type: application/x-msdownload');
			//header("Content-Type: application/force-download");
			//header("Content-Type: application/zip");
			header('Content-Disposition: attachment; filename='.$actualfilename);		    

			//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));
		    //$handle=fopen($file,"r") or exit("Unable to open file!"); //This code is not tested

I have kept some commented code just to show that I have tried multiple options. It’s not just that an executable or zip file not able to download but other files like TXT or EXCEL are showing same non readable text.

Please help!

There must be no output whatsoever before the header, not even a blank line or any html. If your <?php tag is not in position 1 on line 1 you’ll get the error. Any output causes headers to be sent.

You don’t need ob_start();

BTW, the order of your logic is not good.

//Do all your error checking first,
//then get the file contents
//then output headers
//then output file
//then kill the script [exit;];

More importantly, you cant have ob_clean();

Your current script does this:
Start an output buffer.
Check if the file exists.
Start a database connection for no discernable reason, as it’s never used.
Put all your content headers into the output buffer.
Throw away the output buffer (ob_clean)
Output the (now empty) output buffer.
Read file to output buffer.
Die; Garbage cleanup closes database connection and dumps buffer to browser.