Я использую PHP 5.4 с этим сценарием обратной совместимости: https://github.com/ircmaxell/password_compat/blob/master/lib/password.php
это не должно иметь значения, потому что я могу заставить процесс хеширования и проверки работать в моей функции регистрации:
$hash = password_hash($pass, PASSWORD_DEFAULT);
echo $pass;
echo $hash;
if( password_verify($pass,$hash) )
echo 'success';
else echo 'failure';
//success is always shown
//EXAMPLE INPUT
$pass = 'password';
//EXAMPLE OUTPUT
password$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSsuccess
но всякий раз, когда я пытаюсь сохранить хеш в базе данных MySQL, а затем извлечь его для функции проверки, он всегда завершается неудачей. Вот моя функция входа в систему:
function user_login( $mysqli, $email, $pass ){
$err_msg = 'login: '.$mysqli->error.' | '.$email;
if( $stmt = $mysqli->prepare('SELECT password FROM users WHERE email=?') ) :
if( !$stmt->bind_param('s', $email) ) log_sql_error( $err_msg );
if( !$stmt->execute() ) log_sql_error( $err_msg );
if( !$stmt->bind_result( $hash ) ) log_sql_error( $err_msg );
if( $stmt->fetch() === FALSE ) log_sql_error( $err_msg );
if( !$stmt->close() ) log_sql_error( $err_msg );
//I can see that these values are identical to the ones
//echoed out in the registration function
echo $pass;
echo $hash;
if( password_verify($pass,$hash) )
echo 'success';
else echo 'failure';
else : log_sql_error( $err_msg );
endif;
}
//failure is always shown
//EXAMPLE INPUT
$pass = 'password';
//EXAMPLE OUTPUT
password$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSfailure
Мой столбец «пароль» имеет этот тип данных: VARCHAR(255) NOT NULL
Ошибки php не отображаются, поэтому единственное, о чем я могу думать, это то, что значение хеш-функции не форматируется таким же образом, когда оно выходит из базы данных, когда оно входит, но когда я выводю значения, они выглядят как идентичны.
Как еще можно отладить это / что не так с моим кодом?
Спасибо
ОБНОВИТЬ:
Это определенно связано с кодировкой:
$hardcode_hash = '$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS';
echo $hash;
echo '<br/>';
echo $hardcode_hash;
echo '<br/>';
if( $hash == $hardcode_hash )
echo 'success';
else echo 'failure';
//OUTPUT
$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS
$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS
failure
Как мне переформатировать значение SQL, чтобы соответствовать выводу password_hash? Вот что я попробовал:
(string)$hash
utf8_encode($hash)
если я сделаю:
$hash = settype($hash,"string");
if($hash == $hardcode_hash)
возвращает истину, но password_verify($pass, $hash)
все еще возвращает ложь
Нашел проблему. когда я сделал это:
echo strlen($hash)
он напечатал 90, что странно, потому что в конце, когда я распечатывал сообщение об успехе / неудаче, точно не было пробелов, а поле имеет длину varchar 255
Я добавил эту строку:
$hash = substr( $hash, 0, 60 );
И теперь работает нормально.
Странно, что никто больше не сталкивался с этой проблемой. Есть похожие сообщения о password_verify, но ни один из них не требовал такого типа преобразования или какого-либо преобразования в этом отношении:
php password_verify не работает
password_verify php не совпадает
http://forums.phpfreaks.com/topic/283407-need-help-with-password-verify/
Использование PHP 5.5 функции password_hash и password_verify
Одна вещь, которая беспокоит меня, — это предотвращение прямой совместимости кода. Как я узнаю, что при изменении значения по умолчанию хеш имеет длину 60 символов?
Просто для дальнейшего использования. У меня была та же самая проблема с паролями, терпящими неудачу без причины. Когда я присмотрелся к нему, я увидел, что поле пароля в базе данных было недостаточно большим, чтобы хранить полный хэш, поэтому некоторые символы были обрезаны. После увеличения размера поля базы данных все заработало отлично.
У меня была та же проблема, что и у вас, когда она не работала, по какой-то причине она, кажется, помогает поставить:
$hash = substr( $hash, 0, 60 );
в код, хотя моя строка была уже 60 символов.
У меня была та же проблема, и она все еще не работала, несмотря на то, что мои столбцы базы данных были varchar (255), что хэши были 60 символами, и что все мои кодировки были UTF-8. Я довольно новичок в PHP и SQL, поэтому я не буду притворяться, что точно понимаю, почему это работает, но мне удалось это исправить, поэтому я надеюсь, что этот пост поможет другим людям с такой же проблемой.
Оказалось, что основной причиной, по которой password_verify () не проверял мои хэши, было то, что я сделал подготовленный оператор, который использовал хранимую процедуру ранее в скрипте, не извлекая все результаты из запроса, чтобы очистить буфер перед закрытием и повторное открытие соединения для выполнения следующего запроса. Вызов next_result () для mysqli_link после закрытия оператора гарантирует, что все результаты будут использованы.
Кроме того, я использовал другой подготовленный оператор с хранимой процедурой для вставки пароля, но мне все еще нужно было вызывать store_result () и free_result (), даже если наборы результатов не возвращались из вставки. Я предполагаю, что сочетание этих вещей повредило мои данные где-то вдоль линии, в результате чего password_verify () возвращал false на казалось бы идентичных хешах.
Этот ответ было для другой проблемы, но я нашел это полезным для изучения, как правильно закрыть подготовленные операторы с помощью хранимых процедур.