如何在mPDF(PHP)中一键批量在新标签页打印多份PDF
解决mPDF生成多份PDF并逐个在新标签页打开的问题
你的问题核心在于单个请求中调用$mpdf->Output()后,后续代码无法执行,因为这个方法会直接发送PDF的二进制响应和HTTP头,浏览器收到后就会终止当前请求的处理,后续的JS跳转/PHP包含逻辑根本跑不起来。另外用Session计数的方式也不可靠,因为每个新标签的请求是独立的,Session状态同步容易出问题。
下面是重构后的可行方案:
思路调整
把「单个请求循环生成所有PDF」改成「前端逐个请求单份PDF接口,每个请求对应一个新标签页」,让每个PDF都由独立的HTTP请求生成,避免响应冲突。
1. 单份PDF生成接口(get_pdf.php)
负责接收单个模型参数,生成并输出对应的PDF:
<?php // 数据库连接配置 $servername = "你的服务器地址"; $username = "数据库用户名"; $password = "数据库密码"; $dbname = "数据库名称"; // 建立安全连接 $conn = mysqli_connect($servername, $username, $password, $dbname); if (!$conn) die("连接失败: " . mysqli_connect_error()); require_once __DIR__ . '/vendor/autoload.php'; // 获取请求参数并防SQL注入 if (!isset($_GET['model'])) die("缺少必要参数"); $safeModel = mysqli_real_escape_string($conn, $_GET['model']); // 查询对应模型的数据 $query = "SELECT * FROM Hardware WHERE Model = '$safeModel'"; $result = mysqli_query($conn, $query); $mpdf = new \Mpdf\Mpdf(); if (mysqli_num_rows($result) > 0) { $row = mysqli_fetch_assoc($result); $bullets = explode("|", $row["Bullets"]); foreach ($bullets as $item) { // 转义HTML特殊字符避免格式错乱 $mpdf->WriteHTML('<font style="font-size:9px; font-family:Calibri"><b>•</b> '. htmlspecialchars($item) .' </font><br>'); } } else { $mpdf->WriteHTML('<p style="font-size:9px; font-family:Calibri">0 results</p>'); } // 以inline方式在浏览器中打开PDF $mpdf->Output('', 'I'); mysqli_close($conn); ?>
2. 前端触发页面(index.php)
先从数据库获取所有需要生成PDF的模型,再通过JS逐个打开新标签请求接口:
<?php // 连接数据库获取所有需要处理的模型 $servername = "你的服务器地址"; $username = "数据库用户名"; $password = "数据库密码"; $dbname = "数据库名称"; $conn = mysqli_connect($servername, $username, $password, $dbname); if (!$conn) die("连接失败: " . mysqli_connect_error()); $query = "SELECT DISTINCT Model FROM Hardware"; $result = mysqli_query($conn, $query); $models = []; while ($row = mysqli_fetch_assoc($result)) { $models[] = $row['Model']; } mysqli_close($conn); ?> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>批量生成PDF</title> </head> <body> <script> window.onload = function() { const models = <?php echo json_encode($models); ?>; // 延迟打开新标签,避免浏览器拦截弹窗 models.forEach((model, index) => { setTimeout(() => { window.open(`get_pdf.php?model=${encodeURIComponent(model)}`, '_blank'); }, index * 500); // 每500ms打开一个标签,可根据需求调整 }); }; </script> </body> </html>
为什么原来的方案不行?
$mpdf->Output()会直接发送PDF的响应头和二进制内容,一旦执行,当前PHP请求的后续代码(包括include 'caller.php')都会被浏览器忽略,因为HTTP响应已经完成。- 用Session计数的方式不可靠:每个新标签的请求是独立的,Session的更新不会实时同步,容易出现计数混乱的情况。
- 浏览器有弹窗拦截机制,一次性打开多个标签很容易被拦截,延迟打开能降低被拦截的概率。
注意事项
- 务必做好SQL注入防护,示例中用了
mysqli_real_escape_string,更安全的方式是使用预处理语句。 - 如果浏览器仍然拦截弹窗,需要提示用户手动允许当前站点的弹窗权限。
- 可以根据服务器性能和浏览器承受能力调整标签打开的间隔时间。
内容的提问来源于stack exchange,提问作者Harish_Pradhan
相关产品推荐
相关产品推荐

