Вопрос или проблема
Я создал пользовательский плагин для входа, регистрации и восстановления пароля.
Я добавил в свой плагин хуки template_redirect для проверки электронной почты, когда пользователь входит в систему, а затем перенаправляется на главную страницу, а также для восстановления пароля.
Но у меня есть ошибки, я думаю, что хуки template_redirect не знают, какое перенаправление для проверки, а какое для восстановления пароля.
Пожалуйста, посмотрите на мой код:
это custom-plugin.php
<?php
if( ! defined('PLUGIN_PATH') ){
define('PLUGIN_PATH' , plugin_dir_path(__FILE__));
}
require_once ABSPATH . 'wp-admin/includes/plugin.php';
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
require_once PLUGIN_PATH . 'includes/register.php';
require_once PLUGIN_PATH . 'includes/login.php';
require_once PLUGIN_PATH . 'includes/forgot-password.php';
require_once PLUGIN_PATH . 'includes/change-password.php';
require_once PLUGIN_PATH . 'includes/functions.php';
if( ! class_exists('main')){
class main {
function register(){
// Начать сессии при инициализации.
add_action( 'init', array('myFunctions','wpse16119876_init_session') );
add_action ('template_redirect', array( 'forgotPasswordForm', 'forgotPassword'));
add_action ('template_redirect', array( 'loginForm', 'verify'));
add_action ('template_redirect', array( 'loginForm', 'set_submit_login_func'));
}
}
$main = new main();
$main->register();
}
?>
Предположим, что я вставил настройки SMTP и у меня есть форма. Я даю только функции, которые имеют wp_redirect.
А это login.php,
<?php
class loginForm extends registerForm{
public function set_submit_login_func(){
global $wpdb;
$account = filter_input(INPUT_POST, 'account');
$password = filter_input(INPUT_POST, 'password');
$users = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}users WHERE user_email="$account" OR user_login = '$account'", ARRAY_A));
ob_start();
if(isset($_POST["login"])){
if($users){
if($users->user_status == 0){
if(wp_check_password($password, $users->user_pass)){
$credentials = array(
'user_login' => $account,
'user_password' => $password
);
wp_signon($credentials, true);
wp_redirect(site_url());
exit;
} else{
$_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Неправильный пароль</div>';
}
} else{
$_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Учетная запись еще не активирована!</div>';
}
}else{
if($account != ($users->user_email && $user_login)){
$_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Учетная запись не зарегистрирована!</div>';
}
}
}
session_destroy();
return ob_get_clean();
}
public function verify(){
global $wpdb;
$email = $_GET["em"];
$token = $_GET["tk"];
$url = site_url() .'/login';
$registered_date = date( 'Y-m-d H:i:s', current_time( 'timestamp', 0 ) );
$users = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}users WHERE user_email="$email"", ARRAY_A));
if($users){
$user_token = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}user_token WHERE token = '$token'", ARRAY_A));
if($user_token){
if(time() - $user_token->date_created < (60*60*24)){
$wpdb->update($wpdb->prefix . 'users', ["user_status" => 0, "user_registered" => $registered_date], ["user_email" => $email]);
$wpdb->delete($wpdb->prefix . 'user_token', ['email' => $email]);
$_SESSION["message"] = '<div style="background-color: darkcyan; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.$email.' '.'активирован, пожалуйста, войдите'.'</div>';
wp_redirect($url);
exit;
}else{
$wpdb->delete($wpdb->prefix . 'users', ['user_email' => $email]);
$wpdb->delete($wpdb->prefix . 'user_token', ['email' => $email]);
$_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка активации учетной записи! Токен истек'.'</div>';
wp_redirect($url);
exit;
}
}else{
if(($token != $user_token) === true){
$_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка активации учетной записи! Неверный токен'.'</div>';
wp_redirect($url);
exit;
}
}
}else{
if(($email != $users->user_email) === true){
$_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка активации учетной записи! Неверный адрес электронной почты'.'</div>';
wp_redirect($url);
exit;
}
}
session_destroy();
}
}
?>
это forgot-password.php
<?php
class forgotPasswordForm extends loginForm{
public function forgotPassword(){
global $wpdb;
$email = $_GET["em"];
$token = $_GET["tk"];
$url = site_url() .'/login/forgotpassword';
$other_url = add_query_arg(
array(
'req:em' =>$email,
'tk' => $token
), site_url().'/changepassword'
);
$users = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}users WHERE user_email="$email"", ARRAY_A));
if($users){
$user_token = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}user_token WHERE token = '$token'", ARRAY_A));
if($user_token){
if(time() - $user_token->date_created < (60*60*24)){
$_SESSION["message"] = '<div style="background-color: darkcyan ; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Сбросить пароль: '.$email.'</div>';
wp_redirect($other_url);
exit;
}
else{
$wpdb->delete($wpdb->prefix . 'user_token', ['email' => $email]);
$_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка сброса пароля! Токен истек'.'</div>';
wp_redirect($url);
exit;
}
}
else{
if($token != $user_token){
$_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка сброса пароля! Неверный токен'.'</div>';
wp_redirect($url);
exit;
}
}
}else{
if($email != $users->user_email){
$_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка сброса пароля! Неверный адрес электронной почты'.'</div>';
wp_redirect($url);
exit;
}
}
}
}
?>
и я разместил функции sendEmail в functions.php
<?php
class myFunctions {
protected static function _sendEmail($token, $type){
$sendto = filter_input(INPUT_POST, 'email');
$sendfrom = '[email protected]';
$headers = array("Content-type:text/html; charset=UTF-8","From: Me Myself <". $sendfrom . ">");
if($type == 'verify'){
$sendsub = 'Подтверждение учетной записи';
$sendmess="Пожалуйста, нажмите, чтобы активировать вашу учетную запись:<a href="".site_url(). '/login/verify?em='.filter_input(INPUT_POST, 'email'). '&tk='.urlencode_deep($token).'">Активировать</a>";
}
if($type == 'forgot'){
$sendsub = 'Сброс пароля';
$sendmess="Пожалуйста, нажмите, чтобы сбросить ваш пароль:<a href="".site_url(). '/login/forgotpassword?em='.filter_input(INPUT_POST, 'email'). '&tk='.urlencode_deep($token).'">Сбросить пароль</a>";
}
wp_mail($sendto, $sendsub, $sendmess, $headers);
}
}
?>
И для наследования, мой код выглядит так:
class myFunctions
class registerForm extends myFunctions
class loginForm extends registerForm
class forgotPasswordForm extends loginForm
class changePasswordForm extends forgotPasswordForm
Вот где вызывается статическая функция _sendEmail:
это внутри forgot-password.php
public function set_submit_forgot_password_func(){
global $wpdb;
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING);
$token = $this->token = base64_encode(random_bytes(32));
ob_start();
if(isset($_POST["forgot-password"])){
if(!filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL) === true){
$this->error["email"] = "* электронный адрес недействителен";
}
else if(!email_exists($email)){
$this->error["email"] = "* электронный адрес не зарегистрирован";
}
else{
if($this->error["email"]){
unset($_POST);
return false;
}
else{
$_SESSION["message"] = '<div style="background-color: darkcyan; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Мы отправили письмо на '.$_POST["email"].', пожалуйста, сбросьте пароль в течение 24 часов!'.'</div>';
$user_token = [
'id' => '',
'email' => $email,
'token' => $token,
'date_created' => time()
];
$wpdb->insert($wpdb->prefix . 'user_token', $user_token);
forgotPasswordForm::_sendEmail($token, 'forgot');
}
}
}
session_destroy();
return ob_get_clean();
}
Вот как register.php отправляет проверку по электронной почте:
public function set_submit_func(){
global $wpdb;
$fname = filter_input(INPUT_POST, 'fname', FILTER_SANITIZE_STRING);
$lname = filter_input(INPUT_POST, 'lname', FILTER_SANITIZE_STRING);
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING);
$password = wp_hash_password(filter_input(INPUT_POST, 'password', FILTER_DEFAULT));
$repeat_password = wp_hash_password(filter_input(INPUT_POST, 'repeat_password', FILTER_DEFAULT));
$regexp_username = array("options"=>array("regexp"=>"/^[a-zA-Z\d\D]+$/"));
$regexp_name = array("options"=>array("regexp"=>"/^[a-zA-Z\s]+$/"));
$regexp_password = array("options"=>array("regexp"=>"/^[a-zA-Z\d\D]+$/"));
$token = $this->token = base64_encode(random_bytes(32));
ob_start();
if(isset($_POST["submit2"])){
if(!filter_input(INPUT_POST, 'fname', FILTER_VALIDATE_REGEXP, $regexp_name ) === true){
$this->error["fname"] = "* имя не валидно";
}
if(!filter_input(INPUT_POST, 'lname', FILTER_VALIDATE_REGEXP, $regexp_name) === true){
$this->error["lname"] = "* фамилия не валидна";
}
if(!filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL) === true){
$this->error["email"] = "* электронный адрес недействителен";
}
else if (email_exists($email)) {
$this->error["email"] = "* электронный адрес уже зарегистрирован";
}
if(!filter_input(INPUT_POST, 'username', FILTER_VALIDATE_REGEXP, $regexp_username ) === true){
$this->error["username"] = "* имя пользователя недействительно";
}
else if (username_exists($username)){
$this->error["username"] = "* имя пользователя уже зарегистрировано";
}
if(!filter_input(INPUT_POST, 'password', FILTER_VALIDATE_REGEXP, $regexp_password) === true){
$this->error["password"] = "* пароль недействителен";
}
else if(strlen($_POST["password"]) < 5){
$this->error["password"] = "* пароль не может быть меньше 5 символов";
}
else if($_POST["repeat_password"] != $_POST["password"]){
$this->error["repeat_password"] = "* пароли не совпадают";
}
else{
if($this->error["lname"] || $this->error["fname"] || $this->error["username"] || $this->error["email"] || $this->error["password"] || $this->error["repeat_password"] ){
unset($_POST);
return false;
}
else{
$_SESSION["message"] = '<div style="background-color: darkcyan; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Мы отправили письмо на '.$_POST["email"].', пожалуйста, подтвердите его в течение 24 часов!</div>';
$data = [
'ID' => '',
'user_login' => $username,
'user_pass' => $repeat_password,
'user_nicename' => $username,
'user_email' => $email,
'user_status' => '1',
'display_name' => $username
];
$user_token = [
'id' => '',
'email' => $email,
'token' => $token,
'date_created' => time()
];
$wpdb->insert($wpdb->prefix . 'users', $data);
$wpdb->insert($wpdb->prefix . 'user_token', $user_token);
registerForm::_sendEmail($token, 'verify');
}
}
}
return ob_get_clean();
}
Это то, как вызывается функция _sendEmail для сброса пароля:
Но когда я нажимаю на ссылку, перенаправляет на страницу входа, а не на страницу смены пароля:
Надеюсь, я смогу получить помощь в решении этих ошибок. Спасибо!
Код добавляет функции таким образом:
add_action ('template_redirect', array( 'loginForm', 'set_submit_login_func'));
Что сообщает PHP сделать это, когда происходит template_redirect
:
loginForm::set_submit_login_func();
Но мы видим set_submit_login_func
в коде вопросов, и очевидно, что это не статическая функция:
public function set_submit_login_func(){
Что вам нужно, это динамическая вызываемая функция, например:
class MyClass {
public function test() { }
}
$obj = new MyClass();
add_action( '...', array( $obj, 'test' ) );
Где array( $obj, 'test' )
такое же, как $obj->test()
. Обратите внимание, что первый параметр – это объект, на котором нужно вызвать функцию, а не имя класса.
Я настоятельно рекомендую ознакомиться с тем, как использовать вызываемые функции PHP, чтобы лучше понять это: https://www.php.net/manual/en/language.types.callable.php
Ответ или решение
Решение проблемы с неправильной переадресацией на основе template_redirect
Вам нужно обратить внимание на то, как вы используете хуки template_redirect
. В текущем коде вы пытаетесь установить действие для вызова функций на основе класса, что может привести к проблемам с контекстом вызова. Давайте рассмотрим основные ошибки и пути их решения.
1. Статические против нестатических методов
Ваша проблема заключена в том, что вы пытаетесь использовать нестатические методы (например, set_submit_login_func
) как статические. Это неправильно, так как вызываемый метод не является статическим и не может быть вызван через имя класса. В результате, вызов array('loginForm', 'set_submit_login_func')
не будет работать должным образом, поскольку вы не создаете экземпляр класса.
Правильный способ:
Создайте экземпляр класса и передайте его в метод add_action
. Это выглядит следующим образом:
$loginForm = new loginForm();
add_action('template_redirect', array($loginForm, 'set_submit_login_func'));
$forgotPasswordForm = new forgotPasswordForm();
add_action('template_redirect', array($forgotPasswordForm, 'forgotPassword'));
add_action('template_redirect', array($loginForm, 'verify'));
Преимущества такого подхода заключаются в том, что мы вызываем методы на конкретном экземпляре, что поддерживает правильный контекст.
2. Использование глобальных переменных и сессий
Убедитесь, что вы инициализируете сессии и корректно работаете с глобальными переменными, такими как $_SESSION
и $_GET
. Это важно, поскольку неправильное использование или незадействованная сессия может привести к не корректной работе вашей логики:
- Проверьте, что сессии инициализируются в нужный момент (обычно в
init
илиplugins_loaded
). - Убедитесь, что вы корректно обрабатываете переменные, поступающие через
$_GET
и$_POST
.
3. Сообщения и редиректы
Вы также можете рассмотреть пункт, касающийся вывода сообщений об ошибках или успехах. Если редирект необходимо выполнять, а сообщения следует показывать на следующем загруженном URL, используйте:
if(isset($_SESSION["message"])) {
add_action('wp_footer', function() {
echo $_SESSION["message"];
unset($_SESSION["message"]); // Очищаем сообщение после вывода
});
}
Это позволяет показать сообщение после перенаправления.
4. Код редиректа и проверок
В ваших методах verify
и forgotPassword
, перед редиректом добавьте проверки, чтобы убедиться, что вы переходите на правильный URL. Например:
if (condition) {
wp_redirect($url);
exit;
} else {
// Обработка ошибок
}
Заключение
Эти изменения должны исправить ваши ошибки с переадресацией и помочь обеспечить правильное функционирование вашего плагина. Убедитесь, что класс и методы организованы корректно, чтобы они работали в нужном контексте. Если проблема сохраняется, рассмотрите возможность добавления логирования для отслеживания, на какие URL происходит переадресация, и какие проверки не проходят.
Если вам нужна дополнительная помощь или разъяснения по какому-либо из пунктов, не стесняйтесь задавать вопросы. Удачи в разработке!