Handle large file downloads in PHP
In order to handle file download, we need to response several HTTP headers and write a file to the output buffer.
1. Content-Type
Use finfo-file method to get the MIME-TYPE of a file.
$filePath = "data.zip";
$fInfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($fInfo, $filePath);
finfo_close($fInfo);
Return the Content-Type
header to inform the client of the file type.
header("Content-Type: application/zip");
2. Content-Disposition
In a regular HTTP response, the Content-Disposition
response header is a header indicating if the content is expected to be displayed inline in the browser, that is, as a Web page or as part of a Web page, or as an attachment, that is downloaded and saved locally.
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
We specify Content-Disposition
as the attachment and specify the file name of the attachment.
header("Content-Disposition: attachment; filename=\"data.zip\"");
3. Content-Length
Content-Length
is used to indicate the size of the response content. For file download, you need to specify the size of the file.
$filePath = "data.zip";
$fileSize = filesize($filePath);
header("Content-Length: " . $fileSize);
4. Outputs a file
readfile is a simple way to ouput files files.
$filePath = "data.zip";
readfile($filePath);
But readfile()
reads all the contents of the file into the memory, which is not a good way for large files. The simplest way to handle this is to output the file in "chunks".
$filePath = "data.zip";
$file = fopen($filePath, "r");
while (!feof($file)) {
print(fread($file, 1024 * 8));
ob_flush();
flush();
}
Example
$filePath = "data.zip";
if (!file_exists($filePath)) {
exit("file not exist");
}
$fInfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_file($fInfo, $filePath);
finfo_close($fInfo);
$fileSize = filesize($filePath);
header("Content-Type: " . $type);
header("Content-Disposition: attachment; filename=\"{$filePath}\"");
header("Content-Length: " . $fileSize);
$file = fopen($filePath, "r");
while (!feof($file)) {
print(fread($file, 1024 * 8));
ob_flush();
flush();
}