Как проверить пароль, сгенерированный WordPress в базе данных с помощью PHP?
Я работаю с сайтом, созданным на WordPress, и мне нужно добавить некоторые элементы вне WP, а также проверять вход пользователей вне WordPress.
Я пробовал использовать md5 пароля, но это не работает...
Я пробовал этот код:
require_once( 'wp-includes/class-phpass.php' );
$wp_hasher = new PasswordHash( 8, TRUE );
$password = "passwordhere";
$hashed_password = $wp_hasher->HashPassword( $password );
$encryptedpass = md5($hashed_password);
Но это работает только при первом создании пароля, и он всегда получается разным.
Мне нужен код, который можно использовать в таком запросе:
SELECT * FROM wp_customers WHERE email = "ccc@aaa.com" AND password = "<что здесь должно быть?>"
Возможно ли это как-то реализовать?
Спасибо.

Судя по вашему другому вопросу... похоже, что вы пытаетесь проверить введённый пароль в открытом виде с тем, что хранится в базе данных. Вот функция, которую использует WordPress для этой цели:
function wp_check_password($password, $hash, $user_id = '') {
global $wp_hasher;
// Если хеш всё ещё в md5...
if ( strlen($hash) <= 32 ) {
$check = ( $hash == md5($password) );
if ( $check && $user_id ) {
// Перехешируем с использованием нового алгоритма.
wp_set_password($password, $user_id);
$hash = wp_hash_password($password);
}
return apply_filters('check_password', $check, $password, $hash, $user_id);
}
// Если сохранённый хеш длиннее MD5, предполагаем,
// что это новый стиль phpass portable hash.
if ( empty($wp_hasher) ) {
require_once ( ABSPATH . 'wp-includes/class-phpass.php');
// По умолчанию используем portable hash из phpass
$wp_hasher = new PasswordHash(8, TRUE);
}
$check = $wp_hasher->CheckPassword($password, $hash);
return apply_filters('check_password', $check, $password, $hash, $user_id);
}
Сначала этот плагин проверяет, совпадает ли MD5-хеш введённого пароля с сохранённым (захешированным) паролем пользователя. Также он проверяет, совпадает ли PHPass-хеш введённого пароля с сохранённым паролем пользователя.
Вы можете следовать аналогичной логике.
Допустим, у вас есть имя пользователя и пароль, которые нужно проверить (my_password_validation( $username, $password )
). Вы используете имя пользователя для получения захешированного пароля из базы данных. Затем сравниваете хеш введённого пароля с сохранённым значением, чтобы проверить его валидность.
Вот непроверенный псевдокод:
function my_password_validation( $username, $password ) {
// Выбираем хеш пароля пользователя из базы данных
$stored = query( 'SELECT * FROM wp_customers WHERE email = ' . $username );
require_one( 'class-phpass.php' );
$hasher = new PasswordHash(8, TRUE);
return $hasher->CheckPassword( $password, $stored );
}
Если пароль, переданный в функцию, после хеширования совпадает с сохранённым значением, функция вернёт true. В противном случае вернётся false.
Судя по комментариям к другому вопросу, у вас есть и другие проблемы. Цитирую:
Итак, я получаю:
$P$BqVYujC/jqNY4aylZpHi475jwcaSUs1
Но как сравнить его с тем, что в БД?В БД хранится:
fa063a4ed35e092a2d4e15c1b6a61871
Как сравнить эти два значения в MySQL?
Могу сразу сказать, что пароль в базе данных не хешировался с помощью утилиты PHPass. Такие хеши всегда начинаются с $P$B
, потому что это указывает системе, как они были захешированы. PHPass основан на Blowfish, который использует такой префикс для зашифрованных строк.
Ваш хеш fa063...
больше похож на стандартный MD5-хеш... так что если MD5-хеш открытого текста не совпадает, возможно, у вас неверный пароль.
Отвечая на вопрос "как сравнить эти два значения в MySQL"... никак. MySQL — это хранилище данных, не выполняйте бизнес-логику или сравнения в хранилище. Читайте данные из БД, а затем используйте PHP-скрипт для сравнения.

Эти утверждения вроде "MySQL — это хранилище данных... не выполняйте бизнес-логику или сравнения в хранилище данных" немного преувеличены, если честно. Серверы баз данных — это мощные инструменты. Они определенно не являются "просто" хранилищами данных, и в последние годы их недооценивают, что, на мой взгляд, вредит всем.

Это очень просто..
<?php
include_once($_SERVER['DOCUMENT_ROOT'].'/wp-includes/class-phpass.php' );
// подготовка подключения к базе данных
$ip_address="localhost";
$user_db="userdb";
$pass_db="passdb";
$conn= mysql_connect($ip_address,$user_db,$pass_db);
mysql_select_db("dbname",$conn);
if (!$conn){
echo "Не удалось подключиться: " . mysql_error();
exit();
}
// имя пользователя WordPress, пароль которого нужно сравнить
$user = 'test';
$user_name = htmlspecialchars($user,ENT_QUOTES);
// обычный пароль для сравнения
$password = 'tespass';
$hasher = new PasswordHash(8, TRUE);
// получаем хешированный пароль пользователя из базы данных WordPress
$queryx = "select * from wa1gty5f_users where user_login='$user_name'";
$Resultx = mysql_query($queryx,$conn);
while($row = mysql_fetch_array($Resultx)){
$passnya = $row[user_pass];
}
// сравниваем обычный пароль с хешированным
if ($hasher->CheckPassword( $password, $passnya )){
echo "СОВПАДАЕТ";
} else {
echo "НЕ СОВПАДАЕТ";
}
?>

PasswordHash
не является классом ядра PHP, поэтому если вы его не подключите, вы получите ошибку. Помните, что пользователь просил проверить пароль вне WordPress, поэтому классы и функции WP недоступны.

У меня возникла эта проблема, и я нашел решение прямо в wp_hash_password()
Сравнение уже захэшированного пароля с его текстовой строкой
<?php
$wp_hasher = new PasswordHash(8, TRUE);
$password_hashed = '$P$B55D6LjfHDkINU5wF.v2BuuzO0/XPk/';
$plain_password = 'test';
if($wp_hasher->CheckPassword($plain_password, $password_hashed)) {
echo "ДА, совпадает";
} else {
echo "Нет, неверный пароль";
}
?>

Наконец, спустя почти 10 лет. Нашел точный ответ на вопрос, который искали.
Вы хотите сделать это с использованием чистого PHP, верно?
Вот код для вас!
Сначала вам нужно добавить класс:
-> просто скопируйте его из wp-includes/class-phpass.php
-> не волнуйтесь, он написан на чистом PHP.
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
/**
* Конструктор PHP5.
*/
function __construct( $iteration_count_log2, $portable_hashes )
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
$iteration_count_log2 = 8;
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime() . uniqid(rand(), TRUE); // удален getmypid() для совместимости
}
/**
* Конструктор PHP4.
*/
public function PasswordHash( $iteration_count_log2, $portable_hashes ) {
self::__construct( $iteration_count_log2, $portable_hashes );
}
function get_random_bytes($count)
{
$output = '';
if ( @is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .=
pack('H*', md5($this->random_state));
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 +
((PHP_VERSION >= '5') ? 5 : 3), 30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# Мы используем "$P$", phpBB3 использует "$H$" для того же самого
if ($id != '$P$' && $id != '$H$')
return $output;
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8)
return $output;
# Мы вынуждены использовать MD5 здесь, так как это единственная
# криптографическая примитивная функция, доступная во всех версиях PHP
# в настоящее время. Реализация собственной низкоуровневой криптографии
# на PHP приведет к значительному снижению производительности и,
# следовательно, к уменьшению количества итераций и хешей, которые
# легче взломать (не-PHP кодом).
if (PHP_VERSION >= '5') {
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
} else {
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
}
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_extended($input)
{
$count_log2 = min($this->iteration_count_log2 + 8, 24);
# Это должно быть нечетным, чтобы не раскрывать слабые ключи DES, и
# максимальное допустимое значение (2**24 - 1) в любом случае нечетное.
$count = (1 << $count_log2) - 1;
$output = '_';
$output .= $this->itoa64[$count & 0x3f];
$output .= $this->itoa64[($count >> 6) & 0x3f];
$output .= $this->itoa64[($count >> 12) & 0x3f];
$output .= $this->itoa64[($count >> 18) & 0x3f];
$output .= $this->encode64($input, 3);
return $output;
}
function gensalt_blowfish($input)
{
# Здесь нужно использовать другой порядок символов и другую
# схему кодирования, чем в encode64() выше.
# Это важно, потому что последний символ в закодированной строке будет
# представлять только 2 бита. Хотя две известные реализации
# bcrypt спокойно принимают и исправляют строку соли, в которой
# 4 неиспользуемых бита установлены в ненулевое значение, мы не хотим
# рисковать и также не хотим терять дополнительный байт энтропии.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
if ( strlen( $password ) > 4096 ) {
return '*';
}
$random = '';
if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) == 60)
return $hash;
}
if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
if (strlen($random) < 3)
$random = $this->get_random_bytes(3);
$hash =
crypt($password, $this->gensalt_extended($random));
if (strlen($hash) == 20)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
# Возврат '*' при ошибке безопасен здесь, но не был бы безопасен
# в функции, подобной crypt(3), используемой как для генерации новых
# хешей, так и для проверки паролей против существующих хешей.
return '*';
}
function CheckPassword($password, $stored_hash)
{
if ( strlen( $password ) > 4096 ) {
return false;
}
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] == '*')
$hash = crypt($password, $stored_hash);
return $hash === $stored_hash;
}
}
Вы почти закончили.
$password = 'binary1001';//пароль, который вы хотите проверить
$hasher = new PasswordHash(8, TRUE);
$passnya = '$P$BFG8I1k171qgRKqZvj0K3tn3bBSrsW/';//хеш этого пароля из базы данных WordPress
// сравнение обычного пароля с хешированным паролем
if ($hasher->CheckPassword( $password, $passnya )){
echo "СОВПАДАЕТ";
} else {
echo "НЕ СОВПАДАЕТ";
}
Я сделал это здесь методом проб и ошибок. Теперь ваша очередь разобраться. Удачного кодинга!!!

Но это же просто ответ BagusS с удалённым доступом к базе данных, не так ли? И даже это по сути просто часть ответа EAMann, помеченная как 'непроверенный псевдокод', который был опубликован десять лет назад.
