如何使用PHPMailer从数据库获取邮件模板并插入变量
问题分析与修复建议
嘿,我看了你这段代码,发现几个关键问题需要调整,咱们一步步来解决:
1. mysqli_multi_query 的结果处理完全错了
mysqli_multi_query执行后,返回的只是第一个查询的结果集,根本不能用foreach直接遍历所有三个查询的结果。你得手动依次获取每个结果集才行。
2. 存在严重的SQL注入风险
直接把用户提交的$bookid和$username拼进SQL语句里,相当于给攻击者开了后门,必须用预处理语句来避免这个问题,这是Web开发的基础安全要求。
3. 模板变量替换没做
你只是把模板内容直接赋值给了$mail->Body,但没把$title和$name替换到模板里的对应位置——比如你的模板里应该有像{{title}}或者{name}这类占位符,得把这些占位符换成实际的变量值才行。
修正后的完整代码示例
if(isset($_POST['issue'])) { $username = $_POST['studentname']; $bookid = $_POST['bookdetails']; // 1. 用预处理语句分别处理每个查询,彻底避免SQL注入 // 获取邮件模板 $stmt = mysqli_prepare($connection, "SELECT option_value FROM settings WHERE option_name = 'email_temp_issue';"); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); $templateRow = mysqli_fetch_assoc($result); $email_template = $templateRow['option_value'] ?? ''; // 处理模板不存在的情况,避免报错 mysqli_stmt_close($stmt); // 获取书籍标题(注意:如果bookid是整数,把bind_param的第二个参数改成"i") $stmt = mysqli_prepare($connection, "SELECT title FROM books WHERE id = ?;"); mysqli_stmt_bind_param($stmt, "s", $bookid); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); $bookRow = mysqli_fetch_assoc($result); $title = $bookRow['title'] ?? '未知书籍'; mysqli_stmt_close($stmt); // 获取学生姓名 $stmt = mysqli_prepare($connection, "SELECT fullName from students WHERE email = ?;"); mysqli_stmt_bind_param($stmt, "s", $username); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); $studentRow = mysqli_fetch_assoc($result); $name = $studentRow['fullName'] ?? '未知用户'; mysqli_stmt_close($stmt); // 2. 替换模板中的占位符(这里假设模板里用{{title}}和{{name}}作为标记,你可以根据实际模板调整) $mailBody = str_replace( ['{{title}}', '{{name}}'], [$title, $name], $email_template ); // 3. 把替换后的内容赋值给PHPMailer的Body $mail->Body = $mailBody; if(!$mail->Send()) { echo "<script>alert('Error while sending Email.')</script>"; var_dump($mail); } else { echo "<script>alert('Email sent successfully')</script>"; } }
额外说明
- 为什么不用
multi_query? 虽然它能执行多个查询,但可读性差,而且处理结果集容易出错,分开处理每个查询更清晰,也更容易维护。 - 如果一定要用
multi_query(不推荐),正确的处理方式是这样的:$sql= "SELECT option_value FROM settings WHERE option_name = 'email_temp_issue';"; $sql .="SELECT title FROM books WHERE id = ?;"; $sql .="SELECT fullName from students WHERE email = ?"; // 还是要用预处理绑定参数,不能直接拼变量 $stmt = mysqli_prepare($connection, $sql); mysqli_stmt_bind_param($stmt, "ss", $bookid, $username); mysqli_stmt_execute($stmt); // 获取第一个结果集(邮件模板) $result = mysqli_stmt_get_result($stmt); $templateRow = mysqli_fetch_assoc($result); $email_template = $templateRow['option_value'] ?? ''; // 切换到第二个结果集(书籍标题) mysqli_stmt_next_result($stmt); $result = mysqli_stmt_get_result($stmt); $bookRow = mysqli_fetch_assoc($result); $title = $bookRow['title'] ?? '未知书籍'; // 切换到第三个结果集(学生姓名) mysqli_stmt_next_result($stmt); $result = mysqli_stmt_get_result($stmt); $studentRow = mysqli_fetch_assoc($result); $name = $studentRow['fullName'] ?? '未知用户'; mysqli_stmt_close($stmt); - 模板占位符:如果你的模板里用的是其他标记(比如
%title%或者{name}),记得修改str_replace里的搜索数组,匹配你的实际占位符。
内容的提问来源于stack exchange,提问作者Carol H
相关产品推荐
相关产品推荐

