MySQL查询无法返回用户行导致PHP登录失败求助
登录功能无法匹配数据库用户凭证,始终返回"Wrong credentials"
我已经成功用PHP连接MySQL数据库(该连接在其他功能中正常工作),搭建了注册/登录页面。注册功能正常,用户信息能正常存入数据库,但登录功能无法使用——代码始终进入else分支,返回“Wrong credentials”,看起来查询从未获取到对应用户行。我的登录代码如下:
if (isset($_POST['login_btn'])) { $username = $_POST['username']; $password = $_POST['password']; if (empty($username)) { array_push($errors, "Username is required"); } if (empty($password)) { array_push($errors, "Password is required"); } if (empty($errors)) { $password = md5($password); $stmt = $conn->prepare("SELECT * FROM users WHERE username='$username' and password='$password' LIMIT 1"); $stmt->execute(); $result = $stmt->get_result(); if (mysqli_num_rows($result) > 0) { $reg_user_id = mysqli_fetch_assoc($result)['id']; $_SESSION['user'] = getUserById($reg_user_id); if ( in_array($_SESSION['user']['role'], ["Admin", "Author"])) { $_SESSION['message'] = "You are now logged in"; header('location: ' . BASE_URL . '/admin/dashboard.php'); exit(0); } else { $_SESSION['message'] = "You are now logged in"; header('location: index.php'); exit(0); } } else { array_push($errors, 'Wrong credentials'); } } }
问题排查与解决方案
1. 优先检查密码加密逻辑的一致性
这是最常见的原因:注册时的密码加密方式和登录时是否一致?
- 如果你的注册代码用的是
password_hash($password, PASSWORD_DEFAULT)(推荐的安全加密方式),那登录时用md5()加密的密码肯定和数据库里的哈希值不匹配。这种情况下应该改用password_verify()来验证:// 登录时不要用md5,直接用原始密码验证 $stmt = $conn->prepare("SELECT * FROM users WHERE username=? LIMIT 1"); $stmt->bind_param("s", $username); $stmt->execute(); $result = $stmt->get_result(); if (mysqli_num_rows($result) > 0) { $user = mysqli_fetch_assoc($result); // 用password_verify验证原始密码和数据库中的哈希值 if (password_verify($password, $user['password'])) { // 登录成功逻辑 $_SESSION['user'] = getUserById($user['id']); // ... 后续跳转逻辑 } else { array_push($errors, 'Wrong credentials'); } } - 如果注册时确实用了
md5(),那检查数据库中存储的密码是不是正确的md5值(可以手动计算测试用户密码的md5,和数据库里的字段对比)。
2. 修复SQL语句的安全问题与潜在语法错误
你当前的预处理语句其实没起到作用——还是用了字符串拼接username='$username',这不仅有SQL注入风险,还可能因为用户名包含特殊字符(比如单引号、反斜杠)导致查询语法错误,返回空结果。正确的预处理方式应该是绑定参数:
$password = md5($password); // 如果注册时用了md5的话 $stmt = $conn->prepare("SELECT * FROM users WHERE username=? AND password=? LIMIT 1"); // 绑定两个字符串类型的参数("ss"表示两个string) $stmt->bind_param("ss", $username, $password); $stmt->execute(); $result = $stmt->get_result();
这种方式能避免特殊字符导致的查询失败,同时提升安全性。
3. 增加调试信息定位问题
在开发环境中,可以临时添加调试代码,确认提交的参数和数据库存储的内容是否一致:
if (empty($errors)) { $password = md5($password); // 临时打印调试信息(生产环境要删除) echo "提交的用户名: " . htmlspecialchars($username) . "<br>"; echo "加密后的密码: " . $password . "<br>"; // 同时去数据库执行手动查询,看是否能找到结果 // SELECT * FROM users WHERE username='你的测试用户名' AND password='上面输出的md5值' LIMIT 1; $stmt = $conn->prepare("SELECT * FROM users WHERE username=? AND password=? LIMIT 1"); $stmt->bind_param("ss", $username, $password); $stmt->execute(); $result = $stmt->get_result(); // ... 后续逻辑 }
如果手动查询能找到结果,但代码里查不到,那可能是连接或预处理语句的问题;如果手动查询也查不到,那肯定是注册时的存储逻辑有问题。
4. 其他次要排查点
- 确认页面顶部已经调用了
session_start();,否则SESSION无法正常初始化(不过这个一般会导致跳转后没有登录状态,而不是直接返回错误)。 - 检查
getUserById()函数是否正常工作——不过你现在连查询结果都没有,所以先聚焦前面的步骤。
内容的提问来源于stack exchange,提问作者Balázs Kozma
相关产品推荐
相关产品推荐

