如何修改PHP代码实现网页导出PDF/Word格式报告?
问题描述
现有一套HTML/PHP表单系统,点击表单Line Z处的「Download」按钮会提交到fr_get.php执行。Line A处的下拉选择框包含「Hi」「Hello」「Good Morning」「Good Evening」四个选项,选中「Hi」并点击下载按钮时,会执行对应的hi.php文件。
现有表单代码:
<form method="get" action="fr_get.php"> <h1>Report</h1> <select name="report"> <!-- Line A --> <?php foreach ($reports->getReports() as $report) { $users = $report->getAll('AllowedUser'); ?> <option value="<?= $report->path; ?>"><?= (is_array($users) && in_array('deleted', $users) ? 'DELETED --- ' : '').$report->getFirst('Title'); ?></option> <?php } ?> </select> <div class="submit"><input type="submit" value="Download"/></div> <!-- Line Z --> </form>
fr_get.php现有代码:
<?php $db = connect_mysql(); if (!is_admin()) { die('Access Denied.'); } $report = $_GET['report']; include($report);
需求:修改fr_get.php代码,实现点击下载按钮时,直接下载PDF或Word格式的报告文件。
修改方案
1. 优先处理安全校验(必须步骤)
原代码直接使用$_GET['report']包含文件,存在严重的路径遍历、代码注入风险,必须先对参数做严格校验:
<?php $db = connect_mysql(); if (!is_admin()) { die('Access Denied.'); } // 定义允许的报告文件白名单,拦截非法请求 $allowed_reports = [ 'hi.php', 'hello.php', 'good_morning.php', 'good_evening.php' ]; $report = $_GET['report'] ?? ''; // 校验参数是否在白名单内 if (!in_array($report, $allowed_reports)) { die('Invalid report request.'); } // 额外安全层:确保文件在当前目录下,避免跨目录访问 $report_path = __DIR__ . '/' . $report; if (!file_exists($report_path) || !is_file($report_path)) { die('Report file not found.'); }
2. 添加下载响应逻辑
根据报告脚本的输出方式,分两种情况处理:
情况一:报告脚本直接输出文件二进制内容
如果hi.php等脚本直接生成PDF/Word的内容并输出,可在包含脚本前设置HTTP响应头,触发浏览器下载:
// 映射每个报告对应的文件名与MIME类型 $report_meta = [ 'hi.php' => ['filename' => 'hi_report.pdf', 'mime' => 'application/pdf'], 'hello.php' => ['filename' => 'hello_report.docx', 'mime' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], 'good_morning.php' => ['filename' => 'morning_report.pdf', 'mime' => 'application/pdf'], 'good_evening.php' => ['filename' => 'evening_report.docx', 'mime' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'] ]; $file_meta = $report_meta[$report]; // 设置下载响应头 header('Content-Type: ' . $file_meta['mime']); header('Content-Disposition: attachment; filename="' . $file_meta['filename'] . '"'); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); // 包含报告生成脚本,直接输出内容 include($report_path); exit;
情况二:报告脚本生成物理文件
如果hi.php会生成一个临时物理文件(比如/tmp/hi_report.pdf),则读取文件内容并输出:
// 执行报告脚本,获取生成的文件路径 ob_start(); include($report_path); $generated_file = ob_get_clean(); // 校验生成的文件是否存在 if (!file_exists($generated_file) || !is_file($generated_file)) { die('Generated report file not found.'); } // 自动识别文件MIME类型 $finfo = new finfo(FILEINFO_MIME_TYPE); $mime_type = $finfo->file($generated_file); // 设置响应头 header('Content-Type: ' . $mime_type); header('Content-Disposition: attachment; filename="' . basename($generated_file) . '"'); header('Content-Length: ' . filesize($generated_file)); header('Content-Transfer-Encoding: binary'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); // 输出文件内容 readfile($generated_file); // 若为临时文件,下载完成后删除 unlink($generated_file); exit;
3. 补充说明
- MIME类型需对应正确:PDF用
application/pdf,新版Word(.docx)用application/vnd.openxmlformats-officedocument.wordprocessingml.document,旧版Word(.doc)用application/msword。 - 若报告生成耗时较长,可添加缓冲处理避免输出乱码。
内容的提问来源于stack exchange,提问作者flash
相关产品推荐
相关产品推荐

