PHPMailer发送找回密码邮件响应缓慢,如何实现重定向同时发送邮件?
解决PHPMailer发送邮件时页面卡顿,实现先重定向后台执行的方案
嗨,我完全懂你的困扰——用户提交邮箱后得等好几分钟才能跳转,体验真的很差!其实实现先重定向、后台悄悄发邮件的方法很简单,咱们不仅能解决这个问题,还能顺便修复你代码里的安全隐患(比如SQL注入),一起来看:
核心思路
PHP里可以通过提前结束浏览器响应的方式,让用户立刻看到跳转,而脚本在服务器后台继续执行邮件发送逻辑。具体分两种常见环境处理:
步骤1:先修复SQL注入问题(非常重要!)
你现在直接把$_POST['recovery']拼进SQL语句里,这是严重的SQL注入漏洞,黑客能轻松篡改你的数据库。必须改成预处理语句,同时调整执行逻辑:
<?php define('DB_NAME', '#######'); define('DB_USER', '#######'); define('DB_PASSWORD', '#######'); define('DB_HOST', 'localhost'); $conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); if (!$conn) { die('Could not connect: ' . mysqli_connect_error()); } // 用预处理语句替代直接拼接SQL,杜绝注入风险 $recovery = $_POST['recovery'] ?? ''; $sql = "SELECT forgotpass FROM members WHERE username = ?"; $stmt = mysqli_prepare($conn, $sql); mysqli_stmt_bind_param($stmt, "s", $recovery); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); // 检查是否找到对应用户 if ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) { // 第一步:先发送重定向指令,让用户立刻跳转 header('Location: ./success.php'); // 清空输出缓冲,确保浏览器能立刻收到跳转信号 ob_end_flush(); flush(); // 关键:结束与浏览器的连接,让脚本在后台继续执行 if (function_exists('fastcgi_finish_request')) { // PHP-FPM环境(大部分主机用这个)的最优方案 fastcgi_finish_request(); } else { // Apache mod_php等其他环境的兼容方案 ignore_user_abort(true); // 用户断开连接后脚本仍继续执行 set_time_limit(0); // 取消脚本执行时间限制 echo str_repeat(' ', 1024); // 输出足够内容触发浏览器跳转 flush(); } // 第二步:后台悄悄执行邮件发送逻辑 $mailto = $recovery; $mailSub = "Here's your password!"; $mailMsg = $row['forgotpass']; require 'PHPMailer-master/PHPMailerAutoload.php'; $mail = new PHPMailer(); $mail->IsSmtp(); $mail->SMTPDebug = 0; $mail->SMTPAuth = true; $mail->SMTPSecure = 'ssl'; $mail->Host = "bemoresocial.co.uk"; $mail->Port = 465; // or 587 $mail->IsHTML(true); $mail->Username = "info@bemoresocial.co.uk"; $mail->Password = "#########"; $mail->SetFrom("info@bemoresocial.co.uk"); $mail->Subject = $mailSub; $mail->Body = $mailMsg; $mail->AddAddress($mailto); // 后台执行时错误不会显示给用户,建议记录到服务器日志 if(!$mail->Send()) { error_log("找回密码邮件发送失败:" . $mail->ErrorInfo); } } else { // 如果没找到用户,跳转到错误提示页面 header('Location: ./error.php'); exit; } mysqli_close($conn); ?>
关键部分解释
- 预处理语句:用
mysqli_prepare和mysqli_stmt_bind_param绑定参数,彻底杜绝SQL注入风险,这是生产环境必须做的安全措施。 - 提前重定向:先发送
Location响应头,再清空输出缓冲,让浏览器立刻收到跳转指令,用户不会再看到"Please wait..."的卡顿页面。 - 后台执行触发:
- 如果你用的是PHP-FPM(大部分虚拟主机、云服务器都是这个环境),
fastcgi_finish_request()是最优解,它会立刻切断与浏览器的连接,脚本继续在服务器后台运行。 - 如果是Apache的mod_php环境,就用
ignore_user_abort(true)+set_time_limit(0)的组合,再输出空白内容触发浏览器跳转。
- 如果你用的是PHP-FPM(大部分虚拟主机、云服务器都是这个环境),
- 错误日志记录:后台执行的脚本不会把错误显示给用户,所以用
error_log()把发送失败的信息记录到服务器日志,方便你后续排查问题。
额外建议
- 尽量不要直接发送明文密码(你代码里的
forgotpass字段看起来是明文?),最好生成一个限时的密码重置链接,这样安全性更高。 - 确认你的服务器允许脚本后台执行,部分主机可能会限制脚本运行时间,必要时联系服务商调整配置。
内容的提问来源于stack exchange,提问作者Daniel Faulkner
相关产品推荐
相关产品推荐

