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
相关产品推荐
相关产品推荐

