PHP 7.2 password_verify()从数据库取数后失效问题求助
嘿,我之前折腾Argon2的时候也踩过这个一模一样的坑——明明哈希正常存进数据库了,登录时password_verify()死活返回false,但在同一个页面直接生成哈希并验证就完全没问题。结合你的情况,咱们挨个排查最可能的几个点:
数据库字段长度不足
Argon2生成的哈希字符串长度可不短(比如Argon2i的哈希大概有90-100个字符),如果你的数据库字段设成了varchar(60)或者更短的长度,存储时就会自动截断哈希值——这绝对是最常见的触发原因!解决办法很简单:把存储哈希的字段改成varchar(255)或者text类型,确保能完整容纳整个哈希字符串。存储/读取时混入隐形字符或空格
有时候你可能没注意,生成哈希后不小心带了换行、空格,或者数据库读取时被自动trim了?你可以做个小测试快速确认:- 在设置密码的页面,输出并复制生成的哈希:
echo password_hash('你的测试密码', PASSWORD_ARGON2I); - 从数据库取出哈希后,用
var_dump($stored_hash)查看,对比和你复制的哈希的长度、内容是否完全一致,有没有多出来的隐形字符。
- 在设置密码的页面,输出并复制生成的哈希:
数据库连接字符集配置不完整
虽然你说数据库和PHP文件都是UTF-8,但如果数据库连接时没指定正确的字符集(比如用PDO时没在DSN里加charset=utf8mb4,或者mysqli没调用mysqli_set_charset($conn, 'utf8mb4')),可能会导致哈希中的特殊字符被转义或乱码,从而验证失败。SQL插入时的转义问题
如果你没用预处理语句插入哈希,而是直接把哈希拼进SQL里,旧的转义函数(比如mysql_real_escape_string)可能会把哈希里的$等字符转义成\$,导致存储的哈希和生成的不一致。一定要用PDO或mysqli的预处理语句来插入数据,避免手动转义带来的问题。
最后给你个快速定位的小技巧:在登录页面把从数据库取出的哈希直接写死到password_verify里测试,比如:
var_dump(password_verify('用户输入的测试密码', '数据库里取出的完整哈希字符串'));
如果这个测试返回true,那说明问题出在数据库读取或存储的环节;如果还是false,那大概率是哈希在存储时就已经被修改了。
内容的提问来源于stack exchange,提问作者Pablo Hermida Mourelle

