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

通过firewall.php强制下载docx文件出现乱码如何解决

问题原因
  • 路径处理逻辑错误:你使用了htmlspecialchars()处理从GET参数获取的文件路径,这个函数的作用是转义HTML输出场景的特殊字符,会把&、<、>、"等字符转换为&amp;、&lt;这类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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 08:54:03