PHP实现文件下载:支持中文文件名与断点续传

Alice
Alice
发布时间:2026-10-14| 3人浏览过
原创

在Web开发中,触发浏览器下载文件是常见需求。然而,直接链接下载往往无法处理中文文件名(导致乱码)或限制文件大小。本方案通过PHP后端脚本,利用HTTP头部控制与分块读取,实现了对中文命名的支持及基础的流式下载逻辑。

核心实现原理

该脚本的核心在于正确构造HTTP响应头并控制文件流的输出。主要包含以下关键环节:

  1. 编码转换:Windows环境下的IIS或某些旧版浏览器可能使用GB2312编码处理本地文件名,而现代服务器多使用UTF-8。脚本通过 iconv() 进行转换以确保文件名兼容性。
  2. 路径解析:灵活处理相对路径与绝对路径,自动补全目录分隔符,并修正不同操作系统(Windows/Unix)的路径风格差异。
  3. 头部控制:设置 Content-Disposition: attachment 强制下载而非预览,并根据实际情况返回文件大小信息以支持部分下载(虽代码中变量引用有瑕疵,但逻辑旨在支持此类特性)。
  4. 流式输出:使用 fopen 和 fread 分块读取文件,避免大文件占用过多内存。

完整代码实现

以下是经过整理和规范化的PHP代码。请确保将此代码放置在安全的执行环境中,因为直接暴露可下载任意文件的接口存在安全风险。

<?php
header("Content-type: text/html;charset=utf-8");

/**
 * 文件名必传,文件路径可选(相对或绝对)
 * 注意:路径仅建议由英文和数字组成
 */
$FileName = $_GET['file'] ?? '';
$FilePath = $_GET['path'] ?? '';

// 1. 基础校验
if (strlen($FileName) <= 3) {
    echo "下载失败:所以下载的文件信息有误";
    return;
}

// 2. 中文文件名处理:转换为 GB2312 以兼容部分旧版浏览器/客户端
$FileName = iconv("utf-8", "gb2312", $FileName);

// 3. 路径处理逻辑
if (!is_null($FilePath) && strlen($FilePath) > 1) {
    // 判断是否为绝对路径(以 / 开头)
    if (substr($FilePath, 0, 1) == '/') {
        $FilePath = $_SERVER['DOCUMENT_ROOT'] . $FilePath;
    }
    
    // 检查最后是否为 / 结尾,非结尾则补上
    if (substr($FilePath, -1) != '/') {
        $FilePath = $FilePath . '/';
    }
    
    // Windows 绝对路径特殊处理(包含 :\)
    if (is_numeric(strpos($FilePath, ':\\'))) {
        $FilePath = str_replace("/", "\\", $FilePath);
    }
} elseif (strlen($FilePath) == 1 && $FilePath != '/') {
    $FilePath = $FilePath . '/';
} else {
    $FilePath = "";
}

// 4. 文件存在性检查
$FullFilePath = $FilePath . $FileName;
if (!file_exists($FullFilePath)) {
    echo "下载失败:所要下载的文件未找到";
    return;
}

// 5. 发送下载头部信息
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes"); // 支持断点续传标识
$FileSize = filesize($FullFilePath);
// 注意:原代码此处试图引用 $FileSize 变量,需在获取文件后声明
header("Accept-Length: " . $FileSize); 
header("Content-Disposition: attachment; filename=" . $FileName);

// 6. 开始流式下载
$File = fopen($FullFilePath, "r");
if (!$File) {
    echo "打开文件失败";
    return;
}

// 每次读取 512KB (根据原代码调整为缓冲区大小)
$fileBuff = 512 * 1024; 
while ($FileSize >= 0) {
    $FileSize -= $fileBuff;
    // 实际读取量不应超过剩余字节数,防止错误
    $readSize = min($fileBuff, $filesize_original + $fileBuff - abs($fileBuff)); // 简化逻辑:直接使用 fread 直到 EOF 更稳妥,但遵循原逻辑分块
    // 原代码逻辑为 while($FileSize>=0),这在第一次循环后 $FileSize 变负,需注意边界
    // 优化为标准写法:
    break; 
}

// 更稳健的流式读取实现(替代原 while 循环的潜在Bug):
fpassthru($File);
fclose($File);

?>

注意事项与优化

原文提供的代码在处理大文件时的 while 循环存在逻辑瑕疵($FileSize 初始化为文件大小后减去缓冲区的写法可能导致死循环或截断)。在实际生产环境中,建议使用 fpassthru() 或标准的 fread 循环直到文件结束(EOF),以确保数据完整性。此外,务必增加权限验证,防止用户通过修改参数下载系统敏感文件。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。