PHP中password_hash()与password_verify()验证不匹配问题求助
password_verify验证始终返回false的问题排查
问题场景
开发带密码哈希功能的用户登录系统,哈希生成代码如下:
function mk_password_hash($password) { $options = [ 'cost' => 12, ]; $hashed_password = password_hash($password, PASSWORD_BCRYPT, $options); return $hashed_password; }
登录验证代码:
$query = 'SELECT id, status, pass FROM users WHERE email = ? LIMIT 1'; $stmt = $mysqli->prepare($query); $stmt->bind_param('s', $email); $stmt->execute(); $stmt->store_result(); $num_rows = $stmt->num_rows; if ($num_rows < 1) { echo '[error-login-wrong]'; } else { $stmt->bind_result($uid, $user_status, $user_pass); $stmt->fetch(); if ($user_status == 1) { if (password_verify($pass, $user_pass)) { $_SESSION['my-uid'] = $uid; $_SESSION['logged'] = TRUE; echo '[success]'; } else { echo '[error-login-wrong]'; } } else { echo '[error-login-disabled]'; } }
已知哈希生成与验证无时间间隔、无算法变更,但password_verify始终返回false,导致登录失败。
可能的原因及解决办法
- 数据库字段长度不足:PASSWORD_BCRYPT生成的哈希值固定为60字符,若
pass字段长度小于60(比如设为VARCHAR(50)),存储时哈希会被截断,取出的内容不完整必然验证失败。解决:将pass字段修改为VARCHAR(255)或TEXT类型,重新生成哈希存入数据库。 - 用户输入密码被篡改:检查
$pass变量在传递过程中是否被意外处理——比如开启了已废弃的magic_quotes_gpc导致密码被转义,或者用trim()误删了密码首尾的必要空格,亦或是前端输入框限制了特殊字符。解决:登录时输出$pass的原始值,确认和用户输入完全一致;同时确保密码输入框允许所有合法字符(包括特殊字符、空格)。 - 数据取出过程出错:虽然
bind_result的参数顺序和查询字段顺序一致,但仍需确认取出的$user_pass是否和存储的哈希完全一致。比如数据库连接编码错误导致哈希出现乱码,或者fetch()过程中数据被截断。解决:在验证前添加var_dump($user_pass);,查看取出的哈希是否完整、无乱码。 - 哈希生成前密码编码不一致:如果密码包含多字节字符(如中文),生成哈希和验证时的字符串编码不统一,会导致实际比对的字符串不同。解决:确保应用全链路编码统一为UTF-8,包括数据库连接(执行
$mysqli->set_charset('utf8mb4');)、页面编码、表单提交编码。 - 哈希存储前被额外处理:若存储哈希时做了
addslashes()等转义操作,会导致存储的哈希值被修改。解决:检查存储逻辑,确保直接将mk_password_hash返回的结果存入数据库(使用预处理语句无需额外转义)。
快速排查步骤
- 注册新用户时直接输出生成的哈希值,手动复制到数据库,再用相同密码登录验证,看是否成功。
- 登录时输出
$pass和$user_pass的原始值,对比哈希是否完整、输入密码是否正确。 - 检查数据库
pass字段的类型和长度,确认足够容纳60字符的哈希值。
内容的提问来源于stack exchange,提问作者medk
相关产品推荐
相关产品推荐

