PHP发送邮件后调用header重定向页面失效问题求助
问题:PHP执行邮件发送逻辑后页面重定向失效
已尝试通用PHP重定向方案、部分JavaScript重定向方案均未生效,相关代码片段如下:
function redirect($url) { ob_start(); header('Location: '.$url); ob_end_flush(); exit(); } if ( isset($_REQUEST['sendemail']) ) { header("Content-Type: text/plain"); header("X-Node: $hostname"); $from = $_REQUEST['from']; $name = $_REQUEST['name']; $toemail = "djsuson@gmail.com"; $subject = "Customer question"; $message = $_REQUEST['message']; ob_start(); //start capturing output buffer because we want to change output to html $mail = new PHPMailer; $mail->SMTPDebug = 2; $mail->IsSMTP(); if ( strpos($hostname, 'cpnl') === FALSE ) //if not cPanel $mail->Host = 'relay-hosting.secureserver.net'; else $mail->Host = 'localhost'; $mail->SMTPAuth = false; $mail->From = $from; $mail->FromName = $name; $mail->AddAddress($toemail); $mail->Subject = $subject; $mail->Body = $message; $mailresult = $mail->Send(); $mailconversation = nl2br(htmlspecialchars(ob_get_clean())); if ( !$mailresult ) { echo 'FAIL: ' . $mail->ErrorInfo . '<br />' . $mailconversation; redirect('http://otterlywoods.com/failure.html'); } else { echo $mailconversation; redirect('http://otterlywoods.com/success.html'); }
失效原因
- 重定向头发送时机不符合HTTP规范:所有响应头必须在响应正文传输前发送,代码调用
redirect()之前已经通过echo输出了报错信息、SMTP调试内容,此时响应头已经随正文一起发送给客户端,后续再调用header()设置Location头不会产生任何效果。 - 自定义redirect函数逻辑错误:函数内部临时开启
ob_start()无法拦截函数调用前已经输出的内容,且ob_end_flush()会直接输出缓冲内的内容,完全违背重定向"仅返回跳转头、不返回响应正文"的要求。 - 代码逻辑顺序混乱:输出缓冲直到邮件处理逻辑段才开启,无法拦截之前已经输出的响应头之外的隐形输出(比如文件BOM头、PHP标签外的空行);开启SMTP调试模式后,调试信息被捕获后没有做持久化存储,反而直接echo输出,进一步触发了正文提前发送的问题。
修复方案
- 修正redirect函数逻辑,重定向前清空所有已生成的输出,避免残留内容影响响应头发送:
function redirect($url) { // 逐层清空所有已存在的输出缓冲 while (ob_get_level() > 0) { ob_end_clean(); } // 强制设置302跳转头,替换之前可能存在的同名头 header('Location: ' . $url, true, 302); exit; }
- 调整代码执行顺序
- 把
ob_start()放到整个PHP脚本的最开头,在所有业务逻辑执行前就开启输出缓冲,从入口处拦截所有意外输出。 - 生产环境直接关闭SMTP调试:将
$mail->SMTPDebug = 2;修改为$mail->SMTPDebug = 0;,从根源上避免调试信息输出。如果需要留存调试日志,把$mailconversation内容存入Session或者写入本地日志文件,不要直接echo到响应中。 - 删除重定向前的所有echo语句,不要在跳转前输出任何正文内容。
- 把
- 排查隐形输出问题
检查PHP文件编码是否为无BOM的UTF-8格式,确认文件开头<?php标签前没有多余空格、换行,文件末尾不要加?>标签,避免标签后多余空行被当作正文输出。
内容的提问来源于stack exchange,提问作者Dan Suson
相关产品推荐
相关产品推荐

