通过firewall.php强制下载docx文件出现乱码如何解决
问题原因
- 路径处理逻辑错误:你使用了
htmlspecialchars()处理从GET参数获取的文件路径,这个函数的作用是转义HTML输出场景的特殊字符,会把&、<、>、"等字符转换为&、<这类HTML实体,最终拼接出的文件路径和实际存储路径不符,导致读取到错误的内容。 - 输出污染:输出二进制文件前没有清空输出缓冲区,如果你引入的
app.php存在多余输出(比如文件首尾的空格、UTF-8 BOM头、代码运行的警告提示等),这些内容会和docx的二进制内容混合,导致文件损坏乱码。 - 缺少错误校验:代码没有校验目标文件是否存在、是否可读,无法提前定位路径错误问题。
- 路径拼接可能有误:你给出的
$file参数值为users/1/304811_Doc_02-2021_330.docx,代码拼接路径时增加了uploads目录,但是你给出的实际文件路径没有包含uploads字段,需要确认实际存储路径和拼接逻辑是否匹配。
修复方案
调整代码逻辑,修复路径处理、输出缓冲问题,增加安全校验,参考代码如下:
<?php require_once( $_SERVER['DOCUMENT_ROOT'] .'/app.php'); $user_id = intval( $_SESSION['user_id']); if( $user_id) { // 去掉htmlspecialchars处理,直接获取参数 $file = $_GET['file']; // 安全校验:防止目录穿越攻击 if (str_contains($file, '..') || str_contains($file, "\0")) { echo '400: Bad Request'; exit; } $file_arr = explode('/', $file); // 用pathinfo更稳妥的获取后缀 $file_ext = pathinfo($file, PATHINFO_EXTENSION); $disposition = 'inline'; if( $file_ext === 'docx') { $file_ext = 'vnd.openxmlformats-officedocument.wordprocessingml.document'; $disposition = 'attachment'; } // 校验用户权限 if( intval( $file_arr[1] ?? 0) == $user_id) { // 这里根据你的实际存储路径修正,确认是否需要保留uploads目录 $file_path = __DIR__ ."/app/uploads/$file"; // 增加文件存在、可读性校验 if (!file_exists($file_path) || !is_readable($file_path)) { echo '404: File Not Found'; exit; } // 清空输出缓冲区,避免多余输出污染文件内容 ob_clean(); flush(); header('Content-Description: File Transfer'); header('Content-Disposition: '. $disposition .'; filename="'. $file_arr[2] .'"'); header('Content-Type: application/'. $file_ext); header('Content-Transfer-Encoding: binary'); header('Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0'); header('Expires: 0'); header('Pragma: public'); header('Content-Length: ' . filesize( $file_path)); readfile( $file_path); // 读取完成后立即终止执行 exit; } else { echo '403: Forbidden'; exit; } } die();
如果你使用的PHP版本低于8.0,将代码中的
str_contains判断替换为strpos($file, '..') !== false即可。
如果修复后还有问题,可以检查app.php文件是否在开头/结尾输出了多余的空行,或者是否开启了PHP错误提示导致警告信息混入输出内容。
内容的提问来源于stack exchange,提问作者Nate
相关产品推荐
相关产品推荐

