PHP调用ILovePDF REST API压缩PDF自动下载的问题排查与解决
问题解决:PHP调用ILovePDF API压缩PDF后直接浏览器下载
问题总结
当前代码存在三个核心问题:
- 压缩后下载的文件名与原上传文件名不一致
- 下载的PDF文件损坏无法打开
- 控制台报错:
Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
需求目标:压缩后的PDF以原文件名直接下载到用户浏览器,不保存到服务器(或下载后自动删除临时文件)
错误原因分析
- 错误调用
$myTask->download():该方法默认会将压缩文件保存到服务器本地,而非直接输出到浏览器,后续的header设置完全无效(因为已经有文件内容输出) filesize($file)参数错误:$file是ILovePDF SDK返回的文件对象,不是本地文件路径,无法获取正确文件大小- 未处理临时文件:上传的原文件和压缩后的文件都留在服务器,不符合需求
- 输出顺序错误:header必须在任何内容输出前发送,原代码先执行下载保存,再设置header,导致header无法生效
修正后的代码
<?php require_once('../vendor/autoload.php'); use Ilovepdf\CompressTask; if ($_SERVER["REQUEST_METHOD"] === "POST") { if (isset($_FILES["pdf_file"]) && $_FILES["pdf_file"]["error"] === 0) { $tempFileName = $_FILES["pdf_file"]["tmp_name"]; $originalFileName = $_FILES["pdf_file"]["name"]; // 确保文件名是安全的PDF格式 $safeFileName = preg_replace('/[^a-zA-Z0-9_\-\.]/', '', $originalFileName); if (!str_ends_with(strtolower($safeFileName), '.pdf')) { $safeFileName .= '.pdf'; } $myTask = new CompressTask('public_key', 'secret_key'); // 直接使用上传的临时文件,无需移动到服务器目录 $file = $myTask->addFile($tempFileName, $originalFileName); try { $myTask->execute(); // 获取压缩后的文件内容(不保存到服务器) $compressedContent = $myTask->download('string'); // 发送下载header header("Content-Type: application/pdf"); header("Content-Disposition: attachment; filename=\"{$safeFileName}\""); header("Content-Length: " . strlen($compressedContent)); header("Cache-Control: no-cache"); header("Pragma: no-cache"); // 输出文件内容到浏览器 echo $compressedContent; exit; } catch (Exception $e) { echo "压缩失败:" . $e->getMessage(); } } else { echo "文件上传错误:" . $_FILES["pdf_file"]["error"]; } } ?>
关键改动说明
- 移除
move_uploaded_file:直接使用PHP上传的临时文件,避免在服务器留存原文件 - 使用
$myTask->download('string'):获取压缩后的文件内容字符串,而非保存到本地 - 提前设置header:确保在输出文件内容前发送所有响应头,避免文件损坏
- 安全处理文件名:过滤非法字符,确保文件名符合HTTP规范,避免下载时出现文件名异常
- 添加异常捕获:处理API调用过程中可能出现的错误(如密钥无效、文件格式错误等)
- 输出内容后立即
exit:防止后续输出多余内容导致文件损坏
可选方案(需临时保存文件的场景)
如果需要临时保存压缩文件(比如记录日志),可以在下载后删除:
// 替换上述代码中的download和输出部分 $tempCompressedPath = sys_get_temp_dir() . '/' . uniqid() . '.pdf'; $myTask->download($tempCompressedPath); // 发送header header("Content-Type: application/pdf"); header("Content-Disposition: attachment; filename=\"{$safeFileName}\""); header("Content-Length: " . filesize($tempCompressedPath)); header("Cache-Control: no-cache"); header("Pragma: no-cache"); // 输出文件内容 readfile($tempCompressedPath); // 删除临时文件 unlink($tempCompressedPath); exit;
内容的提问来源于stack exchange,提问作者Hüseyin Hamo
相关产品推荐
相关产品推荐

