Восстановлени пароля пользователя php + mysq

Восстановлени пароля пользователя php + mysq

Восстановлени пароля пользователя php + mysq

Привет друзья. В самом начале создания своего блога я написал статью как создать регистрацию и авторизацию на PHP + MySQL. Данная статья стала очень актуальной на моем блоге и требует своего логического продолжения, а именно это восстановление пароля пользователя. Ища информацию на просторах Рунета вы много найдете статей как создать регистрацию и авторизацию пользователей на сайте, но при этом все опускают тот момент, когда пользователь забыл свой пароль. В данной статье мы исправим этот досадный момент.

Восстановление пароля пользователя может быть двух способов:

  • Когда пароль в базе данных хранится не в зашифрованном виде, то вы можете выслать данный пароль пользователю на его email. (Хранить пароли в открытом виде очень небезопасно и так делать нельзя!).
  • Второй вариант, когда пароль хранится в зашифрованном виде, например, по средствам md5() и возможность дешифровать его нет. Тогда нужно создавать новый пароль и обновлять запись в таблице.

Рассмотрим структуру нашей таблицы:

Таблица bez_reg

У нас есть ID, есть логин, пароль в зашифрованном виде с солью, соль, active_hex и статус пользователя. Исходя из этих данных будем создавать алгоритм восстановления пароля на сайте. Особое внимание нужно уделить полю active_hex так как оно будет непосредственно участвовать в восстановлении пароля пользователя.

Сейчас попробуем описать алгоритм действий для реализации восстановления пароля пользователя на php + mysql.

  • Показываем форму с вводом логина для восстановления.
  • Если такой логин есть, то шлем ему письмо ссылкой и ключом в качестве ключа используем строку из ячейки active_hex.
  • Когда пользователь прошел по ссылке проверяем ключ, если ключ совпадает с полем active_hex то выводим форму с двумя полями для вода нового пароля. Как только пользователь сменил пароль, в целях безопасности генерируем новый active_hex, чтобы никто не смог воспользоваться ссылкой восстановления пароля повторно! Далее отправляем письмо о том, что пароль сменен и ссылку для входа.
  • Пользователь входит с новым паролем.

Я не буду здесь расписывать все скрипты, вы можете ознакомится с ними в первой статье регистрация и авторизация на PHP + MySQL. Здесь я выложу дополнения к данным скриптам.

В каталоге scripts создаем новую папку reminder. В данном каталоге создаем три файла:

  • form_reminder.html
  • new_pass_form.html
  • reminder.php

Структура каталогов регистрация и авторизация php + mysql

Далее переходим в index.php и подключаем наши файлы в switch();


<?php
    /**
    * Главный файл (переключатель)
    * Site: http://bezramok-tlt.ru
    * Регистрация пользователя письмом
    */

    //Запускаем сессию
    session_start();

    //Устанавливаем кодировку и вывод всех ошибок
    header('Content-Type: text/html; charset=UTF8');
    error_reporting(E_ALL);

    //Включаем буферизацию содержимого
    ob_start();

    //Определяем переменную для переключателя
    $mode = isset($_GET['mode'])  ? $_GET['mode'] : false;
    $user = isset($_SESSION['user']) ? $_SESSION['user'] : false;
    $err = array();


    //Устанавливаем ключ защиты
    define('BEZ_KEY', true);
     
    //Подключаем конфигурационный файл
    include './config.php';
     
    //Подключаем скрипт с функциями
    include './func/funct.php';

    //подключаем MySQL
    include './bd/bd.php';

    switch($mode)
    {
        //Подключаем обработчик с формой регистрации
        case 'reg':
            include './scripts/reg/reg.php';
            include './scripts/reg/reg_form.html';
        break;
        
        //Подключаем обработчик с формой авторизации
        case 'auth':
            include './scripts/auth/auth.php';
            include './scripts/auth/auth_form.html';
            include './scripts/auth/show.php';
        break;

        //Восстановление пароля
        case 'reminder';
            include './scripts/reminder/reminder.php';
            //Выводим нужную форму для пользователя
            //Проверяем что ключ не проходит по ссылке после восстановления
            if(isset($_GET['key']))
            {
                //Проверяем есть ли такой ключ
                $sql = 'SELECT COUNT(*) AS `total`
                        FROM `'. BEZ_DBPREFIX .'reg`
                        WHERE `active_hex` = :active_hex';

                //Подготавливаем PDO выражение для SQL запроса
                $stmt = $db->prepare($sql);
                $stmt->bindValue(':active_hex', $_GET['key'], PDO::PARAM_STR);
                if($stmt->execute())
                {
                    $row = $stmt->fetch(PDO::FETCH_ASSOC);

                    //Проверяем что вернул запрос
                    if($row['total'] == 0)
                        include './scripts/reminder/form_reminder.html';
                    else
                    {
                        //Отправляем на главную страницу
                        //header('Location: '. BEZ_HOST);
                        //exit;
                        include './scripts/reminder/new_pass_form.html';
                    }
                }
            }
            else
            {
                if(!isset($_GET['newpass']))
                    include './scripts/reminder/form_reminder.html';
            //  include './scripts/reminder/new_pass_form.html';
            }
        break;
    
    }
    
    //Получаем данные с буфера
    $content = ob_get_contents();
    ob_end_clean();

    //Подключаем наш шаблон
    include './html/index.html';
?>
           

Создаем html разметку для формы восстановления пароля пользователя в файле form_reminder.html


<div class="col-md-8 col-md-offset-2"> 
<div class="panel panel-primary">
  <div class="panel-heading"><h4>Восстановление параметров авторизации</h4></div>
  <div class="panel-body">
    <p>Если забыли свои параметры авторизации, не переживайте, их можно восстановить. Для этого введите, пожалуйста, ниже свой email.</p>
    <form class="form-horizontal" action="" method="POST">
  <div class="form-group">
    <label for="inputEmail" class="col-xs-2 control-label">Адрес email:</label>
    <div class="col-xs-10">
     <input type="email" class="form-control" id="inputEmail" name="email" placeholder="Введите email">
    </div>
  </div>
 <div class="form-group">
    <div class="col-xs-offset-2 col-xs-10">
      <button type="submit" class="btn btn-primary" name="reminder">Восстановить</button>
   </div>
  </div>
</form>
  </div>
</div>
</div>

Далее создаем html разметку для ввода нового пароля пользователя в файле new_pass_form.html


<div class="col-md-8 col-md-offset-2"> 
<div class="panel panel-primary">
  <div class="panel-heading"><h4>Восстановление пароля</h4></div>
  <div class="panel-body">
    <form class="form-horizontal" action="" method="POST">
  <div class="form-group">
    <label for="inputPass" class="col-xs-2 control-label">Пароль:</label>
    <div class="col-xs-10">
     <input type="password" class="form-control" id="inputPass" name="pass" placeholder="Введите пароль">
    </div>
  </div>
    <div class="form-group">
    <label for="inputPass2" class="col-xs-2 control-label">Повторите пароль:</label>
    <div class="col-xs-10">
     <input type="password" class="form-control" id="inputPass2" name="pass2" placeholder="Введите подтверждение пароля">
    </div>
  </div>
 <div class="form-group">
    <div class="col-xs-offset-2 col-xs-10">
      <button type="submit" class="btn btn-primary" name="newPass">Изменить</button>
   </div>
  </div>
</form>
  </div>
</div>
</div>

Формы мы сделали, самое время написать обработчик данных форм reminder.php


<?php
 /**
 * Обработчик формы восстановления пароля
 * Site: http://bezramok-tlt.ru
 * Авторизация пользователя
 */

 //Ключ защиты
 if(!defined('BEZ_KEY'))
 {
     header("HTTP/1.1 404 Not Found");
     exit(file_get_contents('./../404.html'));
 }
 
 //Выводим сообщение об отправки ссылки для восстановления пароля
 if(isset($_GET['send']) and $_GET['send'] == 'ok')
    echo '<div class="alert alert-success"><h4 class="text-center">Ваш запрос на восстановление пароля отправлен на указаный вами email!</h4></div>';

  //Выводим сообщение об успешно смене пароля
  if(isset($_GET['newpass']) and $_GET['newpass'] == 'ok')
    echo '<div class="alert alert-success"><h4 class="text-center">Ваш пароль успешно изменен, проверьте свой email!</h4></div>';

 //Если нажата кнопка восстановить пароль утюжим переменные 
 if(isset($_POST['reminder'])){
    
    //Если email существует, то проверяем есть ли он в нашей базе
    if(emailValid($_POST['email'])){
        //Запрос на выборку аккаунта для восстановления
        $sql = 'SELECT * FROM `'. BEZ_DBPREFIX .'reg`
                WHERE `status` = 1
                AND `login` = :email';

        //Подготавливаем PDO выражение для SQL запроса
        $stmt = $db->prepare($sql);
        $stmt->bindValue(':email', $_POST['email'], PDO::PARAM_STR);
        if($stmt->execute())
        {
            //Получаем ответ от MySQL
            $rows = $stmt->fetch(PDO::FETCH_ASSOC);
            
            //Проверяем что такой email есть
            if(!empty($rows))
            {
                //Шлем письмо для восстановления пароля
                $title = 'Вы запросили восстановление пароля на http://bezramok-tlt.ru';
                $message = 'Для смены пароля Вам нужно пройти по ссылке <a href="'. BEZ_HOST .'?mode=reminder&key='. $rows['active_hex'] .'">'. BEZ_HOST .'?mode=reminder&key='. $rows['active_hex'] .'</a>';
                    
                sendMessageMail($_POST['email'], BEZ_MAIL_AUTOR, $title, $message);
                    
                //Перенаправляем пользователя на нужную нам страницу
                header('Location:'. BEZ_HOST .'?mode=reminder&send=ok');
                exit;
            }
            else
            {
                echo showErrorMessage('Нет такого пользователя!');
            }
        }
        else
        {
                echo showErrorMessage('Что-то пошло не так :(');
        }

    }
    else
    {
        echo showErrorMessage('Не верные данные!');
    }

}

 //Если пользователь сменил пароль
if(isset($_POST['newPass']))
{
    //Утюжим переменные
    if(empty($_POST['pass']))
        $err[] = 'Поле Пароль не может быть пустым';
    
    if(empty($_POST['pass2']))
        $err[] = 'Поле Подтверждения пароля не может быть пустым';
    
    //Проверяем равенство паролей
    if($_POST['pass'] != $_POST['pass2'])
        $err[] = 'Пароли не совпадают!';
    
    //Проверяем наличие ошибок и выводим пользователю
    if(count($err) > 0)
        echo showErrorMessage($err);
    else
    {
        //Получаем данные о пользователе
        $sql = 'SELECT * FROM `'. BEZ_DBPREFIX .'reg`
                WHERE `status` = 1
                AND `active_hex` = :active_hex';

        //Подготавливаем PDO выражение для SQL запроса
        $stmt = $db->prepare($sql);
        $stmt->bindValue(':active_hex', $_GET['key'], PDO::PARAM_STR);
        if($stmt->execute())
        {
            //Получаем ответ от MySQL
            $rows = $stmt->fetch(PDO::FETCH_ASSOC);
            
            //Почтовый ящик
            $email = $rows['login'];
            
            //Солим пароль
            $pass = md5(md5($_POST['pass']).$rows['salt']);
            
            //Создаем новый active_hex для защиты
            $active_hex = md5($pass);

            //Обновляем данные в таблице
            $sql = 'UPDATE `'. BEZ_DBPREFIX .'reg`
                SET 
                    `pass` = :pass, 
                    `active_hex` = :active_hex
                WHERE `id` = '. $rows['id'];
            
            //Подготавливаем PDO выражение для SQL запроса
            $stmt = $db->prepare($sql);
            
            //Если запрос выполнился
            if($stmt->execute(array(':pass' => $pass, ':active_hex' => $active_hex)))
            {
                //Отправляем сообщение на почту об успешной смене пароля
                $title = 'Вы успешно сменили пароль на http://bezramok-tlt.ru';
                $message = 'Вы успешно сменили пароль на '. $_POST['pass'] .'
                <p>для входа в систему перейдите по ссылке <a href="'. BEZ_HOST .'?mode=auth">'. BEZ_HOST .'?mode=auth</a></p>';
                        
                sendMessageMail($email, BEZ_MAIL_AUTOR, $title, $message);
                    
                //Перенаправляем пользователя на нужную нам страницу
                header('Location:'. BEZ_HOST .'?mode=reminder&newpass=ok');
                exit;
            }

        }
    }
    
}

?>

Как видите написание данного функционала совсем не сложное дело, проблема в том, что новички в программирование не могут выразить человеческим языком последовательность действий (алгоритма работы), тем самым и создаются трудности в написании того или иного скрипта. С вами был админ https://bezramok-tlt.ru до новых встреч друзья и удачного кодинга!

Архив перезолил: 02.02.2017г.

Скачать: Восстановлени пароля пользователя php + mysq


Теги

Поддержи проект:


...
Андрей
Еще такой вопрос, я добавил в сессию ID пользователя после

$_SESSION['user'] = true;
добавил

$_SESSION['user_id'] = $rows[0]['id'];
я так понимаю сессия должна работать на всех страницах на вашей странице Index.php - user_id работает

Array(
[user] => 1
[user_id] => 4
)
я перехожу на другую страницу с кодом:

if(!$_SESSION['user'] = true)
{ header('Location:'. BEZ_HOST .'user/?mode=auth'); }
else
{
  echo "Вы авторизированы<br><br><br><pre>";
  print_r($_SESSION);
  echo "</pre>";
}
и на ней user_id куда-то теряется

Array(
[user] => 1
)
Что это может быть? Спасибо!

12/08/2017 20:44:36

Администрация
Администрация

У Вас ошибка в условии if(!$_SESSION['user'] = true)  должен стоять оператор сравнения ==

29/08/2017 18:10:31

...
Андрей
Я так понимаю при смене пароля как-то не корректно отправляется письмо. обратный адрес BEZ_MAIL_AUTOR  в письмо не попадает, присьмо приходит без обратного адреса и попадает в спам. Попробую найт ошибку, может вы найдете ее быстрее. Спасибо.

12/08/2017 19:39:43

Администрация
Администрация

Так как сервер ваш или арендованный у хостера, я не смогу ничем помочь. Т.к. в СПАМ письмо уходит благодаря фильтру почтового сервиса, например маил.ру

29/08/2017 18:05:28

...
Андрей
Письмо с ссылкой для подтверждения регистрации, и после этого письмо о благополучной регистрации - приходит А восстановление пароля - нет Вот что удивительно. Я на почтовом ящике гугля тестирую

09/08/2017 21:17:23

Администрация
Администрация

Ради эксперимента заведите почту другого сервиса маил или яндекс, посмотрите как к ним будут приходить письма. 

09/08/2017 21:21:13

...
Андрей
Я перешел по ссылке, открылась форма смены пароля, пароль поменял, все нормально, подтверждение измененного пароля письмо пришло, но тоже криво и тоже в спам.

08/08/2017 17:18:01

Администрация
Администрация

По поводу писем обратитесь к хостеру. Скорей всего ваш почтовый сервис использует фильтр, по этому письма попадают в спам.

09/08/2017 10:45:02

...
Андрей
Да, в спаме, как-то криво приходит, может что-то поправить? A message that you sent contained no recipient addresses, and therefore no delivery could be attempted. ------ This is a copy of your message, including all the headers. ------ To: Subject: =?utf-8?b?0JLRiyDQt9Cw0L/RgNC+0YHQuNC70Lgg0LLQvt1?= Content-type: text/html; charset="utf-8" From: Регистрация на МОЙДОМЕН <no-reply@МОЙДОМЕН> MIME-Version: 1.0 Date: Tue, 08 Aug 2017 05:08:54 +0300 Message-Id: <E1df5Bm-0001yt-1W@ef105.mirohost.net>

08/08/2017 17:14:04

Администрация
Администрация

Это вам нужно к хостеру вашему обратиться.

09/08/2017 10:43:17

...
Андрей
PS а также поля <b>active_hex </b> и <b> pass </b>видимо не меняются, так как после запроса пароля я могу зайти со старым паролем.

08/08/2017 00:41:53

Администрация
Администрация

Поля меняются после того как смените пароль! Во время запроса пароль не меняется, мало ли вдруг вы его вспомнили )

08/08/2017 07:18:10

...
Андрей
Добрый день! Тестирую, регистрация - все нормально! Когда запрашиваю восстановление пароля на емайл, на почту ничего не приходит. Хотя пишет - Ваш запрос на восстановление пароля отправлен на указаный вами email! В чем может быть ошибка? Смотрю не могу найти. Спасибо!

08/08/2017 00:38:13

Администрация
Администрация

На чем тестируете? (локальный сервер типа DENWER или полноценный хостинг). Если скажем полноценный хостинг, то попробуйте ваше письмо найти в СПАМ возможно что почтовый сервер отфильтровал его. Так же гляньте логи сервера, была ли отправка?

08/08/2017 07:17:11

...
я заметил
Админчик тут такое дело, при восстановлении пароля, какие поля меняться должны все? Просто меняется поле active_hex на новые значения, а соль и сам пароль остаются прежним, это не баг? 

09/03/2017 23:15:13

Администрация
Администрация

Меняется active_hex и pass остальные поля не меняются.

10/03/2017 12:04:59

...
Владимир
На примерчике не покажешь куда подставить сесионые данные?

09/03/2017 23:09:01

Администрация
Администрация

Посмотрите здесь http://bezramok-tlt.ru/?mode=2&post=4

Сегодня уже отвечал на данный вопрос.

 

10/03/2017 12:31:46

...
я заметил
Привет админ, я так не хочу искать что ты и где изменял в файле, не мог бы ты указать в каком куске была ошибка, что бы внести изменения в файле. Для предупреждения что такой адресс для перехода по ссылке использовался уже ранее. Спасибо!

08/03/2017 00:22:43

Администрация
Администрация

Смотри в index.php

09/03/2017 20:09:51


Copyright © 2014 - 2021 All rights reserved.