ThinkPHP中实现文件打包下载需用ZipArchive动态生成ZIP并即时响应:先校验文件路径,再创建临时ZIP包,设置HTTP下载头后输出流并删除临时文件。

ThinkPHP 中实现文件打包下载,核心是使用 PHP 的 ZipArchive 类将多个文件(或目录)压缩为 ZIP 包,并通过 HTTP 响应输出供浏览器下载。注意不能直接用 readfile() 输出 ZIP 文件路径,而应动态生成、即时响应、及时清理临时包。
1. 准备待打包的文件列表
确保所有要打包的文件路径真实存在且 Web 服务器有读取权限。推荐使用绝对路径,可通过 ThinkPHP 的 app()->getRuntimePath() 或 root_path() 拼接:
- 支持单个文件、多个文件、或指定目录下的所有文件(需递归读取)
- 避免打包敏感路径(如
app/、config/、runtime/),建议限定在public/uploads/等安全目录 - 文件名含中文时,需在 ZIP 中设置正确编码(PHP 8.2+ 原生支持 UTF-8 文件名;低版本需用
iconv()转码)
2. 使用 ZipArchive 动态创建 ZIP 包
不依赖第三方扩展,原生 ZipArchive 即可完成。关键步骤:新建 ZIP 对象 → 打开临时文件 → 逐个添加文件(addFile() 或 addFromString())→ 关闭存盘。
- 临时 ZIP 文件建议放在
runtime/目录下,例如:runtime/download/temp_'.date('YmdHis').'.zip - 添加文件时用
$zip->addFile($realPath, $archiveName),其中$archiveName可自定义压缩包内路径(如'images/photo.jpg'),支持子目录结构 - 若需添加内容而非物理文件,可用
$zip->addFromString('readme.txt', 'This is a dynamic file.')
3. 设置 HTTP 响应头并输出下载
生成 ZIP 后,清空输出缓冲,设置标准下载响应头,再用 readfile() 输出二进制流,最后删除临时 ZIP 文件(防止磁盘占用):
立即学习“PHP免费学习笔记(深入)”;
- 必须设置:
Content-Type: application/zip、Content-Disposition: attachment; filename="package.zip"(注意 filename 值需 URL 编码中文) - 推荐加
Content-Transfer-Encoding: binary和Expires: 0防止缓存 - 务必在
readfile()后调用unlink($zipFile),否则临时包会越积越多
4. ThinkPHP 控制器中完整示例(TP6)
以下是一个简洁可用的下载方法,放在控制器中(如 DownloadController.php):
public function downloadFiles()
{
$filePaths = [
public_path('uploads/a.pdf'),
public_path('uploads/b.jpg'),
public_path('uploads/c.txt'),
];
// 过滤不存在的文件
$filePaths = array_filter($filePaths, 'is_file');
if (empty($filePaths)) {
return json(['code' => 0, 'msg' => '无有效文件']);
}
$zipFile = runtime_path('download/' . date('YmdHis') . '.zip');
@mkdir(dirname($zipFile), 0755, true);
$zip = new \ZipArchive();
if ($zip->open($zipFile, \ZipArchive::CREATE) !== TRUE) {
return json(['code' => 0, 'msg' => '压缩失败']);
}
foreach ($filePaths as $path) {
$fileName = basename($path);
$zip->addFile($path, $fileName); // 可改用 $zip->addFile($path, 'custom/'.$fileName) 设子目录
}
$zip->close();
if (!is_file($zipFile)) {
return json(['code' => 0, 'msg' => '生成压缩包失败']);
}
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . urlencode(basename($zipFile)) . '"');
header('Content-Length: ' . filesize($zipFile));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
readfile($zipFile);
unlink($zipFile); // 下载后立即删除
exit;
}



















