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="'.basename($pathFileUrl).'"'); 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. 文件名转义格式错误
原脚本使用"转义引号,可能导致浏览器解析文件名时出现异常,建议用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
相关产品推荐
相关产品推荐

