PHP 提供文件以及大文件下载的正确方式

Php 2020-08-05 阅读 7 评论 0

使用 PHP 提供文件以及大文件的下载服务,需要回应几个 HTTP 头以及文件的内容。

1. 设置 Content-Type

使用 finfo-file 方法,获取文件的 MIME 类型。

$filePath = "data.zip";
$fInfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($fInfo, $filePath);
finfo_close($fInfo);

返回 Content-Type响应头,告知客户端文件的类型。

header("Content-Type: application/zip");

2. 设置 Content-Disposition

在常规的HTTP应答中,Content-Disposition 响应头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"

我们指定附件形式,并指定附件的文件名。

header("Content-Disposition: attachment; filename=\"data.zip\"");

3. 设置 Content-Length

Content-Length 用于指示回应内容的大小。对于文件下载,需指定文件的大小。

$filePath = "data.zip";
$fileSize = filesize($filePath);
header("Content-Length: " . $fileSize);

4. 返回文件内容

使用 readfile 可以读取文件并写入到输出缓冲中。这是最简单的一种方法。

$filePath = "data.zip";
readfile($filePath);

但是该方法将文件的所有内容都读进去内存了,对于大文件,不太可行,处理这个问题最简单的方法是以块的形式输出文件。

$filePath = "data.zip";
$file = fopen($filePath, "r");
while (!feof($file)) {
    print(fread($file, 1024 * 8));
    ob_flush();
    flush();
}

完整示例

$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();
}
最后更新 2020-08-05