PHP使用password_hash/verify遇问题:密码验证失败、同密码哈希不同
password_hash() and password_verify() Hey there, let's tackle this problem step by step. First off, the fact that the same password generates different hashes is totally normal—that's a feature, not a bug! password_hash() automatically creates a unique salt for each hash, which is why the output varies every time. The password_verify() function knows how to extract that salt from the stored hash and use it to validate the input, so that part isn't the issue here.
The real problem is why password_verify() keeps returning false. Here are the most common culprits and how to fix them:
1. Database Field Length is Too Short
By default, password_hash() with PASSWORD_DEFAULT (which uses bcrypt) produces a hash around 60 characters long. If your password field is set to something shorter (like VARCHAR(30) or even VARCHAR(60)—some systems truncate at the limit), the stored hash will get cut off, making verification impossible.
Fix:
Update your database password field to VARCHAR(255) or TEXT to ensure the full hash is stored without truncation.
2. You're Not Storing the Hash Correctly
If during registration you run any extra processing on the hash (like addslashes(), htmlspecialchars(), or manually modifying it in any way), you'll corrupt the hash. The only thing you should store is the exact string returned by password_hash().
Correct Registration Example:
public function register_user($username, $password) { // Generate the hash with secure default settings $passwordHash = password_hash($password, PASSWORD_DEFAULT); // Insert directly into the database without altering the hash $this->db->insert('users', [ 'username' => $username, 'password_hash' => $passwordHash ]); }
3. You're Retrieving the Wrong Hash (or No Hash At All)
Double-check that your login query is actually fetching the correct hash for the username. If the query returns no user, or pulls the wrong row, password_verify() will naturally fail.
Add Debugging to Your Login Code:
public function login_user($username, $password){ // Fetch the user record $user = $this->db->where(['username' => $username])->get('users')->row(); // First, confirm the user exists and has a stored hash if (!$user || empty($user->password_hash)) { error_log("User not found or no password hash stored for username: $username"); return false; } // Debug: Print the stored hash and a new hash for the same password // (Note: These hashes will differ, but verify should still pass) var_dump("Stored hash: ", $user->password_hash); var_dump("New hash for input password: ", password_hash($password, PASSWORD_DEFAULT)); // Perform verification $isValid = password_verify($password, $user->password_hash); var_dump("Verification result: ", $isValid); return $isValid; }
Run this and check the output—if the stored hash looks truncated or doesn't match the format of the new hash, you know the issue is with how the hash is being stored.
4. Character Encoding Issues
If your database, table, or database connection isn't using UTF-8 (specifically utf8mb4), there's a chance the hash is being corrupted during storage or retrieval due to encoding conversion.
Fix:
- Set your database and table character sets to
utf8mb4with collationutf8mb4_unicode_ci. - Ensure your PHP database connection uses UTF-8 (for example, in CodeIgniter, set
'charset' => 'utf8mb4'in your database config; with MySQLi, usemysqli_set_charset($conn, 'utf8mb4');).
5. The Input Password is Being Modified
Check if the $password parameter passed to login_user() is being altered somewhere before verification—for example, if you're trimming whitespace, applying filters, or sanitizing it in a way that changes the original input.
Fix:
Add a var_dump($password); at the start of your login_user() function to confirm it matches exactly what the user entered.
内容的提问来源于stack exchange,提问作者Karl Jucutan




