Проверка правильности имени пользователя в настраиваемой форме входа
Я использовал руководство Джеффа Стара для создания собственной формы входа http://digwp.com/2010/12/login-register-password-code/. Всё работает отлично, но есть одна проблема. В форме сброса пароля, если кто-то вводит неправильное имя пользователя (которое не проходит проверку), происходит перенаправление на стандартную страницу wp-login.php?action=lostpassword с сообщением об ошибке.
Есть ли способ перенаправить пользователя на мою собственную страницу с ошибкой?
Спасибо!
Код, который он опубликовал в этом руководстве (очень хорошем, кстати), отправляет форму во встроенный модуль "сброса пароля", который перенаправляет на login.php в случае ошибки. Но вы можете изменить это и создать свой собственный на основе оригинального, добавив его в шаблон страницы. Измените:
<form method="post" action="<?php echo site_url('wp-login.php?action=lostpassword', 'login_post') ?>" class="wp-user-form">
<div class="username">
<label for="user_login" class="hide"><?php _e('Username or Email'); ?>: </label>
<input type="text" name="user_login" value="" size="20" id="user_login" tabindex="1001" />
</div>
<div class="login_fields">
<?php do_action('login_form', 'resetpass'); ?>
<input type="submit" name="user-submit" value="<?php _e('Reset my password'); ?>" class="user-submit" tabindex="1002" />
<?php $reset = $_GET['reset']; if($reset == true) { echo '<p>A message will be sent to your email address.</p>'; } ?>
<input type="hidden" name="redirect_to" value="<?php echo $_SERVER['REQUEST_URI']; ?>?reset=true" />
<input type="hidden" name="user-cookie" value="1" />
</div>
</form>
на:
<form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>" class="wp-user-form">
<div class="username">
<label for="user_login" class="hide"><?php _e('Username or Email'); ?>: </label>
<input type="text" name="user_login" value="" size="20" id="user_login" tabindex="1001" />
</div>
<div class="login_fields">
<?php do_action('login_form', 'resetpass'); ?>
<input type="submit" name="user-submit" value="<?php _e('Reset my password'); ?>" class="user-submit" tabindex="1002" />
<?php
if (isset($_POST['reset_pass']))
{
global $wpdb;
$username = trim($_POST['user_login']);
$user_exists = false;
if (username_exists($username))
{
$user_exists = true;
$user_data = get_userdatabylogin($username);
} elseif (email_exists($username))
{
$user_exists = true;
$user = get_user_by_email($username);
} else
{
$error[] = '<p>' . __('Username or Email was not found, try again!') . '</p>';
}
if ($user_exists)
{
$user_login = $user->user_login;
$user_email = $user->user_email;
// Генерируем случайный ключ для пароля... md5 от текущего времени с случайной солью
$key = substr(md5(uniqid(microtime())), 0, 8);
// Вставляем новый хеш пароля в базу данных
$wpdb->query("UPDATE $wpdb->users SET user_activation_key = '$key' WHERE user_login = '$user_login'");
// Создаем сообщение email
$message = __('Someone has asked to reset the password for the following site and username.') . "\r\n\r\n";
$message .= get_option('siteurl') . "\r\n\r\n";
$message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";
$message .= __('To reset your password visit the following address, otherwise just ignore this email and nothing will happen.') . "\r\n\r\n";
$message .= get_option('siteurl') . "/wp-login.php?action=rp&key=$key\r\n";
// Отправляем сообщение email
if (FALSE == wp_mail($user_email, sprintf(__('[%s] Password Reset'), get_option('blogname')), $message))
$error[] = '<p>' . __('The e-mail could not be sent.') . "<br />\n" . __('Possible reason: your host may have disabled the mail() function...') . '</p>';
}
if (count($error) > 0)
{
foreach ($error as $e)
{
echo $e . '<br/>';
}
} else
{
echo '<p>' . __('A message will be sent to your email address.') . '</p>';
}
}
?>
<input type="hidden" name="reset_pass" value="1" />
<input type="hidden" name="user-cookie" value="1" />
</div>
</form>

Хорошо, у меня всё получилось, с небольшими изменениями. Было несколько синтаксических ошибок, и генератор md5 ключа не работал, поэтому я взял его из wp-login.php. Теперь осталась только одна проблема. Когда кто-то переходит по ссылке из письма для создания нового пароля, их перенаправляет на стандартную форму, так что теперь мне нужно создать и эту форму тоже.

@pippin: код генератора md5 ключа здесь взят из wp-login.php, а что касается перенаправления, попробуйте добавить &redirect_to=$_SERVER['REQUEST_URI']
к ссылке в отправляемом письме.

Моя ссылка теперь выглядит так $message .= get_option('siteurl') . "/wp-login.php?action=rp&key=$key&login=$user_login&redirect_to=$_SERVER['REQUEST_URI']\r\n";
, но что странно - когда я добавляю &redirect, сообщение не отправляется... И еще - разве мне не нужно создать новую форму, где пользователь сможет ввести свой новый пароль и т.д.?

Да, я забыл об этом - тебе нужно будет создать свою собственную форму для сброса пароля и, вероятно, заменить ссылку, которая отправляется пользователю, на текущий URL, а затем на основе ключа проверить, что это нужный пользователь, и показать ему форму.

строка 17 get_user_by('login', $user_login);
, так как get_userdatabylogin
устарел...

Я понимаю, что этот ответ довольно старый, и я не совсем уверен в его надежности. Хотя, думаю, он должен работать, я бы не хотел возиться с SQL, так как он может измениться в будущем. С другой стороны, я не могу найти деталей об альтернативах.

Вот обновленная версия кода от @bainternet с исправленными синтаксическими ошибками, предложением от @Val и генератором ключей из wp-login.php 3.4.2:
global $wpdb;
$username = trim($_POST['user_login']);
$user_exists = false;
// Сначала проверяем по имени пользователя
if ( username_exists( $username ) ){
$user_exists = true;
$user = get_user_by('login', $username);
}
// Затем по адресу электронной почты
elseif( email_exists($username) ){
$user_exists = true;
$user = get_user_by_email($username);
}else{
$error[] = '<p>'.__('Имя пользователя или Email не найдены, попробуйте снова!').'</p>';
}
if ($user_exists){
$user_login = $user->user_login;
$user_email = $user->user_email;
$key = $wpdb->get_var($wpdb->prepare("SELECT user_activation_key FROM $wpdb->users WHERE user_login = %s", $user_login));
if ( empty($key) ) {
// Генерируем случайный ключ...
$key = wp_generate_password(20, false);
do_action('retrieve_password_key', $user_login, $key);
// Вставляем новый md5 ключ в базу данных
$wpdb->update($wpdb->users, array('user_activation_key' => $key), array('user_login' => $user_login));
}
// Создаем сообщение для email
$message = __('Кто-то запросил сброс пароля для следующего сайта и имени пользователя.') . "\r\n\r\n";
$message .= get_option('siteurl') . "\r\n\r\n";
$message .= sprintf(__('Имя пользователя: %s'), $user_login) . "\r\n\r\n";
$message .= __('Для сброса пароля перейдите по следующему адресу, в противном случае просто проигнорируйте это письмо и ничего не произойдет.') . "\r\n\r\n";
$message .= network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . "&redirect_to=".urlencode(get_option('siteurl'))."\r\n";
// Отправляем email сообщение
if (FALSE == wp_mail($user_email, sprintf(__('[%s] Сброс пароля'), get_option('blogname')), $message))
$error[] = '<p>' . __('Не удалось отправить письмо.') . "<br />\n" . __('Возможная причина: ваш хостинг мог отключить функцию mail()...') . '</p>';
}
if (count($error) > 0 ){
foreach($error as $e){
echo $e . "<br/>";
}
}else{
echo '<p>'.__('Сообщение будет отправлено на ваш адрес электронной почты.').'</p>';
}

Я всё ещё сталкивался с проблемами некорректной работы ключа сброса пароля. Ссылка в электронном письме перенаправляла на стандартную страницу сброса пароля с параметром URL, указывающим на проблему с ключом. Поэтому я тщательно проанализировал файл wp-login.php и добавил объект $wp_hasher, что решило проблему — теперь сброс пароля через электронное письмо работает корректно.
if (($_SERVER['REQUEST_METHOD'] === (string) 'POST') && (isset($_POST['reset_pass']))) {
// Доступ к глобальным свойствам
global $wpdb, $wp_hasher;
// Переменные
$error_pass_reset = array();
$username = (string) trim($_POST['user_login']);
$user_exists = (bool) false;
// ---- СУЩЕСТВУЕТ ЛИ ИМЯ ПОЛЬЗОВАТЕЛЯ ИЛИ EMAIL ---- //
if (username_exists($username)) {
$user_exists = (bool) true;
$user = (object) get_user_by('login', $username);
} // end if
else if (email_exists($username)) {
$user_exists = (bool) true;
$user = (object) get_user_by('email', $username);
} // end else if
else {
$error_pass_reset[] = '<p>Имя пользователя или Email не найдены, пожалуйста, попробуйте снова.</p>';
} // end else
// ---- ПОЛЬЗОВАТЕЛЬ СУЩЕСТВУЕТ ---- //
if ($user_exists === (bool) true) {
// Переменные
$user_login = (string) $user -> user_login;
$user_email = (string) $user -> user_email;
// Генерация ключа сброса пароля
if (empty($key)) {
$key = (string) wp_generate_password(20, false);
do_action('retrieve_password_key', $user_login, $key);
// Создание объекта $wp_hasher
if (empty($wp_hasher)) {
require_once(ABSPATH . WPINC . '/class-phpass.php');
$wp_hasher = new PasswordHash(8, true);
}
// Ключ сброса с применённым хешированием (MD5 выводит строку)
$hashed = (string) time() . ':' . $wp_hasher -> HashPassword($key);
// Вставка нового ключа в базу данных
$wpdb -> update(
$wpdb -> users,
array(
'user_activation_key' => $hashed
),
array(
'user_login' => $user_login
)
);
} // end if
// Текст письма
$message = (string)
'Кто-то запросил сброс пароля для следующей учетной записи:' . "\r\n\r\n" .
get_option('siteurl') . "\r\n\r\n" .
'Имя пользователя: ' . $user_login . "\r\n\r\n" .
'Если это была ошибка, просто проигнорируйте это письмо и ничего не произойдет.' . "\r\n\r\n" .
'Для сброса пароля перейдите по следующей ссылке:' . "\r\n\r\n" .
get_option('siteurl') . '/wp-login.php?action=rp&key=' . $key . '&login=' . $user_login . "\r\n";
// Отправка письма
if ((bool) false === wp_mail($user_email, get_option('blogname') . ' Сброс пароля', $message)) {
$error_pass_reset[] = '<p>В данный момент письмо не может быть отправлено.</p>' . "\n";
} // end if
} // end if
// Отправка письма для сброса пароля
do_action('login_form', 'resetpass');
} // end if (($_SERVER['REQUEST_METHOD'] === (string) 'POST') && (isset($_POST['reset_pass'])))
