Force to Download File in PHP



If you want to require a force to download file upon the user visiting a web page with PHP or want to control or track your downloadable contents then this file downloader script can give you more option. Especially if you want make images or other contents like document files (doc, docx, pdf), compressed files (zip, rar), music files, css, js or any downloadable file then you must need to use a force to download file script. In this post I am sharing a simple force to download file script.

You need to add following header script to force to download file.

header('Pragma: public');
header('Expires: -1');
header('Cache-Control: public, must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Content-Length: " . filesize($path));
header("Content-Type: $mime_type");
header("Content-Description: File Transfer");

After this header script you need to add following code:

ob_clean();
flush();
readfile($path);
exit;

But if you have large files readfile function may cause a large memory usages issue because it stores the whole file to memory and then start download. So you need to read the file as chunks to reduce memory usages.

if ( $fp = fopen($path, 'rb') ) {
	ob_end_clean();

	while( !feof($fp) and (connection_status()==0) ) {
		print(fread($fp, 8192));
		flush();
	}

	@fclose($fp);
	exit;
}

Before a complete script to force download we need a function or class something(any source you want) to get mime-type of the file. I write a function getMimeType for this purpose, you can use it simply and add more extension mime-type to this function.

function getMimeType($filename){
	$ext = pathinfo($filename, PATHINFO_EXTENSION);
	$ext = strtolower($ext);

	$mime_types=array(
		"pdf" => "application/pdf",
		"txt" => "text/plain",
		"html" => "text/html",
		"htm" => "text/html",
		"exe" => "application/octet-stream",
		"zip" => "application/zip",
		"doc" => "application/msword",
		"xls" => "application/vnd.ms-excel",
		"ppt" => "application/vnd.ms-powerpoint",
		"gif" => "image/gif",
		"png" => "image/png",
		"jpeg"=> "image/jpg",
		"jpg" =>  "image/jpg",
		"php" => "text/plain",
		"csv" => "text/csv",
		"xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
		"pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
		"docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
	);

	if(isset($mime_types[$ext])){
		return $mime_types[$ext];
	} else {
		return 'application/octet-stream';
	}
}

So the complete script is as follow:

$path = "file/path/to/download.php";

// check file is readable or not exists
if (!is_readable($path))
	die('File is not readable or not exists!');

$filename = pathinfo($path, PATHINFO_BASENAME);

// get mime type of file by extension
$mime_type = getMimeType($filename);

// set headers
header('Pragma: public');
header('Expires: -1');
header('Cache-Control: public, must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Content-Length: " . filesize($path));
header("Content-Type: $mime_type");
header("Content-Description: File Transfer");

// read file as chunk
if ( $fp = fopen($path, 'rb') ) {
	ob_end_clean();

	while( !feof($fp) and (connection_status()==0) ) {
		print(fread($fp, 8192));
		flush();
	}

	@fclose($fp);
	exit;
}