PHP登录认证系统$msg/echo无法输出、程序流程异常问题排查
PHP登录认证系统无输出问题排查
问题复现代码
<?php ob_start(); session_start(); include "../navbar.php"; require_once '../database-connection.php'; include "../login.html"; if (isset($_SESSION['session_id'])) { header('Location: ../index.php'); exit; } if (isset($_POST['login'])) { $email = $_POST['email'] ?? ''; $password = $_POST['password'] ?? ''; $query = " SELECT email, password FROM users WHERE email = :email "; $check = $pdo->prepare($query); $check->bindParam(':email', $email, PDO::PARAM_STR); $check->execute(); $user = $check->fetch(PDO::FETCH_ASSOC); if ($email == $user['email']) { if (password_verify($password, $user['password'])) { session_regenerate_id(); $_SESSION['session_id'] = session_id(); $sql = " SELECT username, id FROM users WHERE email = :email"; $check = $pdo->prepare($sql); $check->bindParam(':email', $email); $check->execute(); $user = $check->fetch(); $_SESSION['session_user'] = $user['username']; $_SESSION['email'] = $email; $_SESSION['user_id'] = $user['id']; header('Location: ../index.php'); exit; } else { $msg = "Wrong Password"; } } else { $msg = "Wrong Email"; } printf($msg, '<a href="../login.html">back</a>'); }
异常现象
- 已注册用户的登录认证、跳转功能完全正常
- 登录失败时的
$msg错误提示完全不显示 - 代码任意位置添加的
echo调试语句都没有输出,看起来像是include文件后程序阻塞,但认证逻辑又能正常执行
调试习惯:通过echo打印内容标记脚本执行断点,定位代码运行位置。
核心原因
三个问题叠在一起导致看不到输出:
- 代码第一行开了
ob_start()输出缓冲,所有echo、打印内容都会先存在内存里不会直接发给浏览器,登录成功分支直接exit跳转时,缓冲的内容会被直接丢弃,根本不会输出。 - 你在所有业务逻辑执行前就引入了
login.html,整个登录页的HTML内容先被写入缓冲,后面的错误提示、调试内容都会被追加到整个HTML文档的末尾(也就是</html>标签之后),大部分浏览器会忽略HTML闭合标签外的内容,自然看不到提示。 - 当用户输入的邮箱在数据库不存在时,
$user返回布尔值false,你直接访问$user['email']会触发PHP数组键不存在的警告,如果PHP配置关闭了错误显示,这个警告不会有任何输出,同时判断逻辑会走到错误分支,但输出的内容位置不对还是看不到。另外你用printf()输出$msg的时候,字符串里没有%s占位符,传入的返回链接根本不会被拼接到提示里。
修复方案
按优先级改:
- 调整代码执行顺序:把
navbar.php、login.html这类输出HTML的文件引入,挪到所有业务逻辑执行完成、$msg这类需要在页面展示的变量都准备好之后,不要在逻辑开头就加载视图文件。 - 修复空查询判断:拿到用户查询结果后先判断是否查到有效数据,再做后续校验,避免PHP警告:
$user = $check->fetch(PDO::FETCH_ASSOC); if ($user && $email === $user['email']) { // 原有密码校验、登录成功逻辑 } else { $msg = "Wrong Email"; } - 修正错误提示输出:不要用无占位符的
printf,直接拼接返回链接,并且把$msg的输出位置放到登录表单内你想要展示提示的地方,不要放在文档末尾。 - 调试适配:如果保留
ob_start(),加echo调试的时候,在echo语句后补ob_end_flush();exit;,强制把内存里的缓冲内容输出并终止程序,就能正常看到断点打印内容,不需要的话直接删掉开头的ob_start()即可。
内容的提问来源于stack exchange,提问作者Deborah
相关产品推荐
相关产品推荐

