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

PHP脚本无法触发PDF强制下载,Chrome循环加载问题求助

PDF文件强制下载问题排查与修复

问题描述

开发的PHP脚本可正常下载docx、srt、pptx等格式文件,但PDF文件无法触发强制下载,Chrome浏览器会进入循环加载状态,始终无法完成下载。

原脚本代码

<?php
require_once 'includes/constants.php';

$pathFileUrl = '../'.WEBSITE_NAME_URL_FILES.'/docs/'.urldecode($fileUrl);

if (isset($fileUrl) && !empty($fileUrl) && file_exists($pathFileUrl)) {

    $finfo = finfo_open(FILEINFO_MIME);
    $mime = finfo_file($finfo, $pathFileUrl);
    finfo_close($finfo);

    header('Content-Description: File Transfer');
    header('Content-Type: '.$mime); //application/octet-stream
    header('Content-Transfer-Encoding: binary');
    header('Content-Disposition: attachment; filename=&quot;'.basename($pathFileUrl).'&quot;');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($pathFileUrl));
    
    // Read file and send to browser
    readfile($pathFileUrl);
    exit;

} else {
    redirect(WEBSITE_NAME_URL);
}

问题排查与修复方案

1. MIME类型触发Chrome内置PDF阅读器冲突

Chrome识别到application/pdf的MIME类型时,会优先调用内置阅读器打开文件,即便设置了attachment也可能出现加载异常。解决方法是强制将PDF的Content-Type改为application/octet-stream,绕过浏览器的类型识别:

// 在获取MIME类型后添加判断
$finfo = finfo_open(FILEINFO_MIME);
$mime = finfo_file($finfo, $pathFileUrl);
finfo_close($finfo);
// 针对PDF强制替换MIME类型
if (str_contains($mime, 'application/pdf')) {
    $mime = 'application/octet-stream';
}

2. 文件名转义格式错误

原脚本使用&quot;转义引号,可能导致浏览器解析文件名时出现异常,建议用htmlspecialchars处理文件名,确保特殊字符能被正确解析:

// 替换原Content-Disposition行
$filename = basename($pathFileUrl);
header('Content-Disposition: attachment; filename="'.htmlspecialchars($filename, ENT_QUOTES).'"');

3. 隐性输出干扰HTTP头发送

如果脚本执行前有隐性输出(比如空格、文件BOM头、其他引入文件的多余输出),会导致HTTP头发送异常,进而卡住PDF下载。可以在发送头之前清空缓冲区:

// 在输出任何内容前添加
ob_clean();
flush();

4. 文件大小计算异常

filesize()可能因文件权限、符号链接等问题返回错误值,导致浏览器判断文件不完整,进入循环加载。可以选择跳过Content-Length(浏览器会自动处理分块传输),或者增加权限判断确保能正确获取文件大小:

// 可选:如果文件大小获取不可靠,直接注释该行
// header('Content-Length: ' . filesize($pathFileUrl));

// 或者增加判断确保获取有效
$fileSize = filesize($pathFileUrl);
if ($fileSize !== false) {
    header('Content-Length: ' . $fileSize);
}

修复后的完整脚本示例

<?php
require_once 'includes/constants.php';

$pathFileUrl = '../'.WEBSITE_NAME_URL_FILES.'/docs/'.urldecode($fileUrl);

if (isset($fileUrl) && !empty($fileUrl) && file_exists($pathFileUrl) && is_readable($pathFileUrl)) {
    // 清空缓冲区,避免隐性输出干扰
    ob_clean();
    flush();

    $finfo = finfo_open(FILEINFO_MIME);
    $mime = finfo_file($finfo, $pathFileUrl);
    finfo_close($finfo);

    // 强制PDF使用octet-stream类型
    if (str_contains($mime, 'application/pdf')) {
        $mime = 'application/octet-stream';
    }

    $filename = basename($pathFileUrl);
    header('Content-Description: File Transfer');
    header('Content-Type: '.$mime);
    header('Content-Transfer-Encoding: binary');
    header('Content-Disposition: attachment; filename="'.htmlspecialchars($filename, ENT_QUOTES).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    
    // 仅在能正确获取文件大小时发送
    $fileSize = filesize($pathFileUrl);
    if ($fileSize !== false) {
        header('Content-Length: ' . $fileSize);
    }
    
    readfile($pathFileUrl);
    exit;

} else {
    redirect(WEBSITE_NAME_URL);
}

内容的提问来源于stack exchange,提问作者Oge

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:01:03