#php #ios #mysql #swift #wordpress
#php #iOS #mysql #swift #wordpress
Вопрос:
Итак, я последние два дня работал над *% amp; off, пытаясь заставить это работать, но я всегда застреваю на одной и той же части: сравнение пароля компьютера, полученного из приложения iOS, с хэшированным паролем, хранящимся в базе данных WordPress.
Небольшая справка: По сути, просто страница входа в систему на раскадровке ios, отправляющая электронное письмо и пароль, которые пользователь вводит в php-скрипт, который проверяет, совпадает ли хэшированный пароль, связанный с отправленным электронным письмом, с хэшированной версией отправленного пароля.
Swift и iOS здесь не проблема, поэтому я избавлю вас от этого кода. Я провожу тестирование с использованием PostMan для отправки HTTP-запроса POST с правильными параметрами :
- Заголовок -> Тип содержимого: application/x-www-form-urlencoded
- Тело —> электронная почта: email@email.com и пароль: testpasswd
Теперь вот исходный код для страницы входа :
<?php
require("Connection.php");
require("SQLDao.php");
$email = htmlentities($_POST["email"]);
$password = htmlentities($_POST["password"]);
$returnValue = array();
echo json_encode("Hello World");
if(empty($email) || empty($password))
{
$returnValue["status"] = "error";
$returnValue["message"] = "There is a missing field";
echo json_encode($returnValue);
return;
}
$dao = new MySQLDao();
$dao->openConnection();
$userDetails = $dao->getUserDetailsWithPassword($email,$password);
if($userDetails) {
$returnValue["status"] = "Success";
$returnValue["message"] = "User logged in !";
echo json_encode($returnValue);
} else {
$returnValue["status"] = "error";
$returnValue["message"] = "User not found";
echo json_encode($returnValue);
}
$dao->closeConnection();
?>
Большинство из SQLDao.php
в основном обрабатывает функции подключения SQL, но также и эту функцию :
public function getUserDetailsWithPassword($email, $userPassword)
{
$returnValue = array();
$sql = "select id,user_email from vswp_users where user_email='" . $email . "' and user_pass='" .$userPassword . "'";
$result = $this->conn->query($sql);
if ($result != null amp;amp; (mysqli_num_rows($result) >= 1)) {
$row = $result->fetch_array(MYSQLI_ASSOC);
if (!empty($row)) {
$returnValue = $row;
}
}
return $returnValue;
}
Но этот код, очевидно, проверяет отправленный пароль на хешированную версию WordPress, поэтому он всегда возвращает false .
Благодаря моим исследованиям я нашел это, но это не дало мне рабочего решения :
Исследование № 1: включить(phpass.php ) Функция CheckPassword, где у меня было бы что-то похожее на это :
public function getUserDetailsWithHashedPassword($email, $userPassword)
{
include_once("../wp-config.php");
include_once("../wp-includes/class-phpass.php");
$returnValue = array();
$query = mysql_query("SELECT * FROM vswp_users WHERE user_email = '$email'");
$row = mysql_fetch_array($query);
$wp_hasher = new PasswordHash(8, TRUE);
$password_hashed = $row['user_pass'];
$passwordMatch = $wp_hasher->CheckPassword($userPassword, $password_hashed) || $password_hashed == md5($userPassword);
if ($passwordMatch) {
echo json_encode("Passwords match");
$returnValue = TRUE;
} else {
echo json_encode("Passwords do not match");
$returnValue = FALSE;
}
return $passwordMatch;
}
Но это просто возвращает «Hello World», но ни один из параметров if ($ passwordMatch) не отображается.
Прошу прощения за этот длинный вопрос, надеюсь, кто-нибудь сможет указать мне правильное направление, чтобы исправить это.
Спасибо за вашу помощь!!
РЕДАКТИРОВАТЬ 1: С помощью некоторого тестирования с использованием echo json_encode("Hello World");
я смог обнаружить, что в основном скрипт останавливается после строки —> УДАЛЕНО, ПОСКОЛЬКУ БОЛЬШЕ НЕ АКТУАЛЬНО
РЕДАКТИРОВАНИЕ 2: я приближаюсь, благодаря CBroe idea я смог найти больше информации с помощью надлежащей отчетности PHP. Я смог заставить это работать, поместив хэшированный пароль, хранящийся в базе данных, непосредственно в файл входа в систему в качестве значения $storedPassword
, и это сработало. Но теперь единственная проблема, с которой я сталкиваюсь, заключается в том, что при выполнении этого с mysql я получаю следующую ошибку: substr() expects parameter 1 to be a string, array given in /[...]/class-phpass.php
. Похоже, мне не хватает только кое-чего, чтобы преобразовать пароль из базы данных mysql в его строковую версию. Вот моя функция :
public function getUserDetailsWithHashedPassword($email, $userPassword)
{
require_once("/home/[hosting provider directories]/public_html/wp-includes/class-phpass.php");
$returnValue = array();
$sql = "select user_pass from vswp_users where user_email='" . $email . "'";
$result = $this->conn->query($sql);
if ($result != null amp;amp; (mysqli_num_rows($result) >= 1)) {
$row = $result->fetch_array(MYSQLI_ASSOC);
if (!empty($row)) {
$storedPassword = $row;
}
}
$wp_hasher = new PasswordHash(8, TRUE);
$passwordMatch = $wp_hasher->CheckPassword($userPassword, $storedPassword);
if($passwordMatch === TRUE) {
$returnValue = TRUE;
} else {
$returnValue = FALSE;
}
return $returnValue;
}
Еще раз спасибо!!
Комментарии:
1. Включите правильное сообщение об ошибках PHP и проверьте ответ на сетевой панели браузера.
2. Хорошая идея. Я обнаружил, что действительно была проблема с
require_once()
URL-адресами.3. Но теперь я получаю другую ошибку: «Класс ‘WP_User’ не найден в /[…]/pluggable.php . Есть идеи о том, что может быть причиной этого?
Ответ №1:
Сначала извлеките данные пользователя из базы данных. А затем проверьте хэшированный пароль пользователя с помощью обычного текстового пароля.
Чтобы получить пользователя, вы можете попробовать:
$user = get_user_by( 'email', $email );
Затем:
if ( $user amp;amp; wp_check_password( $userPassword, $user->data->user_pass, $user->ID) ){
echo json_encode("Passwords match");
$returnValue = TRUE;
}
else{
echo json_encode("Passwords do not match");
$returnValue = FALSE;
}
ссылки по теме:
Комментарии:
1. И я предполагаю, что мне нужно было бы также поместить
include_once("../wp-includes/pluggables.php");
?2. Я пробовал это, но, похоже, я все еще не получаю возвращаемое значение. «Hello Word» все еще отображается, но
$returnValue
в основном равно нулю.3. Вам также необходимо включить
wp-includes/pluggable.php
для вызоваget_user_by(..)
. Пожалуйста,var_dump($user)
и проверьте, что он возвращает. Также проверьте, какое значение имеетwp_check_password( $userPassword, $user->data->user_pass, $user->ID)
.
Ответ №2:
Я, наконец, смог заставить это работать. Моя последняя проблема с $row
заключалась в том, что я не указал, какой ключ массива я хотел отобразить. Вот рабочий код, если кто-нибудь окажется здесь и ему понадобится рабочее решение! (Очевидно, что [каталоги хостинг-провайдера] — это просто моя внутренняя файловая система, измените ее на свою, если потребуется)
public function getUserDetailsWithHashedPassword($email, $userPassword)
{
require_once("/home/[hosting provider directories]/public_html/wp-includes/class-phpass.php");
$returnValue = array();
$sql = "select user_pass from vswp_users where user_email='" . $email . "'";
$result = $this->conn->query($sql);
if ($result != null amp;amp; (mysqli_num_rows($result) >= 1)) {
$row = $result->fetch_array(MYSQLI_ASSOC);
if (!empty($row)) {
$storedPassword = $row['user_pass'];
}
}
$wp_hasher = new PasswordHash(8, TRUE);
$passwordMatch = $wp_hasher->CheckPassword($userPassword, $storedPassword);
if($passwordMatch === TRUE) {
$returnValue = TRUE;
} else {
$returnValue = FALSE;
}
return $returnValue;
}
Ответ №3:
Я знаю, что это старый вопрос, но я хотел бы немного улучшить его, потому что он все еще работает сегодня, в 2021 году, и потому что class-phpass.php
файл WordPress с тех пор также не сильно изменился.
Идея заключается в том, чтобы безопасно сопоставлять учетные данные WordPress, чтобы позволить пользователям входить во внешнюю программу, которая может либо находиться на том же сервере, либо нет (поскольку удаленная система имеет доступ к базе данных WordPress). Для удаленных систем потребуется копия class-phpass.php
файла, в противном случае его можно просто запросить из его исходного местоположения в пути WordPress. Оба случая будут работать просто отлично.
Внесенные мной изменения минимальны, но значительны. Самое главное, я использую PDO вместо MySQLi.
Я также изменил функцию, позволяющую определять, предпринимается ли попытка входа с помощью имени пользователя или электронной почты. Это очень небольшое изменение, но оно очень помогает и может быть легко применено к тому или иному по мере необходимости.
Здесь новая функция:
/** Request WordPress portable PHP password hashing framework */
require_once "/[PATH-TO-WORDPRESS]/wp-includes/class-phpass.php";
/**
* Validate Login using WordPress user's information
*
* @param string $login The user login information (can either be username or email).
* @param string $password The unhashed password for the proposed account.
* @return boolean Returns TRUE if login/password combination is valid, FALSE otherwise.
*/
function validateLogin(string $login, string $password): bool
{
global $pdo;
/** Identify if $login is an email or a username */
$field = filter_var($login, FILTER_VALIDATE_EMAIL) ? "user_email" : "user_login";
/** Request data from MySQL using PDO */
$request = $pdo->prepare("SELECT user_pass FROM users WHERE {$field} = :login LIMIT 1");
$request->bindValue(":login", $login, PDO::PARAM_STR);
$request->execute();
$result = $request->fetchAll();
/** If $result is empty, simply fail the validation */
if (empty($result)) return false;
/**
* Process the received $password against the hashed password from the user identified as $login
* in the WordPress database and return the result of the validation process.
*/
$wordpress_hasher = new PasswordHash(8, TRUE);
return $wordpress_hasher->CheckPassword($password, $result[0]['user_pass']);
}
Конечно, я ожидаю, что вы будете знать, как установить подключение PDO вне функции и перед ее вызовом (в этом примере оно определено в глобальной переменной $pdo
). Если вы мало знаете о PDO, вот отличное руководство:https://phpdelusions.net/pdo_examples/connect_to_mysql
Я также включил class-phpass.php
файл вне функции. Это * можно* включить в него, как это было сделано в исходном ответе, но я предпочел бы сделать иначе. 🙂
Если по какой-то причине вы предпочитаете, чтобы функция была менее совместима с PHP 7 или PHP 8, просто используйте ее следующим образом:
function validateLogin($login, $password)
{
[...]
}