You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP生成含XLS文件的ZIP下载失败问题求助

问题描述

使用PHP(Yii框架)编写的ZIP下载功能,打包HTML格式的XLS文件时失败,终端返回乱码符号,无法正常生成导出文件。相关代码如下:

$directory = Yii::getAlias('@console/runtime/tmp');
if (!file_exists($directory)) {
   mkdir($directory);
}

$this->zip = new \ZipArchive();
$this->zipFile = tempnam($directory, "zip");

....
$html = '<table><thead><tr><th>no</th><th>name</th></tr></thead><tbody></tbody></table>';
$output = '';
$output .= "<html>\n";
$output .= "<head>\n";
$output .= "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />\n";
$output .= "</head>\n";
$output .= "<body>\n";
$output .= $html;
$output .= "</body>\n";
$output .= "</html>\n";

$fileName = "test" . '.xls';

if ($this->zip->open($this->zipFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) === TRUE) {
   file_put_contents($fileName, $output);
   $this->zip->addFile($fileName, basename($fileName));
}

$this->zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=' . $this->getFilename());
header("Content-Length: " . filesize($this->zipFile));
header("Pragma: no-cache");
header("Expires: 0");
readfile($this->zipFile);
exit();

修复方案

1. 修正HTML内容转义问题

代码中使用的<、>是HTML转义字符,直接写入文件会导致生成的XLS内容为无效文本,需替换为真实HTML标签:

$html = '<table><thead><tr><th>no</th><th>name</th></tr></thead><tbody></tbody></table>';
$output = '';
$output .= "<html>\n";
$output .= "<head>\n";
$output .= "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />\n";
$output .= "</head>\n";
$output .= "<body>\n";
$output .= $html;
$output .= "</body>\n";
$output .= "</html>\n";

2. 规范临时文件存储路径

当前file_put_contents会将XLS文件写入执行目录,易出现权限或路径混乱问题,应指定到临时目录:

// 生成临时XLS文件到指定目录
$fileName = $directory . DIRECTORY_SEPARATOR . "test.xls";
// 写入时锁定文件并确保UTF-8编码
file_put_contents($fileName, $output, LOCK_EX);

3. 完善ZipArchive错误处理

添加open、addFile的失败判断,避免无效操作:

if ($this->zip->open($this->zipFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) === TRUE) {
    if (file_put_contents($fileName, $output, LOCK_EX) !== false) {
        if (!$this->zip->addFile($fileName, basename($fileName))) {
            throw new \Exception("Failed to add file to zip");
        }
        // 添加后删除临时XLS文件
        unlink($fileName);
    } else {
        throw new \Exception("Failed to write XLS file");
    }
    $this->zip->close();
} else {
    throw new \Exception("Failed to open zip file");
}

4. 避免输出干扰(适配Yii框架)

发送响应前清空所有输出,使用Yii响应组件替代原生header,更符合框架规范:

// 清空之前的输出缓存
ob_clean();
flush();

$response = Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_RAW;
$response->headers->set('Content-Type', 'application/zip');
$response->headers->set('Content-Disposition', 'attachment; filename="' . $this->getFilename() . '"');
$response->headers->set('Content-Length', filesize($this->zipFile));
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', '0');

// 输出文件并删除临时Zip
$response->sendFile($this->zipFile)->send();
unlink($this->zipFile);
exit();

5. 确保目录权限

创建临时目录时设置合适权限,避免写入失败:

$directory = Yii::getAlias('@console/runtime/tmp');
if (!file_exists($directory)) {
    // 递归创建目录并设置权限
    mkdir($directory, 0775, true);
}

内容的提问来源于stack exchange,提问作者Susy Valentina Rahardjo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:40:19