Чат PHP-разработчиков
Как сделать активацию пользователей по email на PHP

Система активации пользователей по email на PHP

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

Прежде чем начать, вам нужно настроить OpenServer для отправки писем.

После того, как вы это сделали, можно приступать к написанию кода. Первое, что нам нужно – создать новую табличку, в которой мы будем хранить коды для активации пользователей.
Называем её «users_activation_codes», и указываем, что нам требуются три столбца:

  • id – это просто id записи в таблице;
  • user_id – id пользователя;
  • code – код для активации этого пользователя.

Таблица с кодами активации

Теперь нам нужно написать специальный сервис, который позволит нам создавать новые коды активации для пользователей, а также проверять код активации для конкретного пользователя. Пишем.

src/MyProject/Models/Users/UserActivationService.php

<?php

namespace MyProject\Models\Users;

use MyProject\Services\Db;

class UserActivationService
{
    private const TABLE_NAME = 'users_activation_codes';

    public static function createActivationCode(User $user): string
    {
        // Генерируем случайную последовательность символов, о функциях почитайте в документации
        $code = bin2hex(random_bytes(16));

        $db = Db::getInstance();
        $db->query(
            'INSERT INTO ' . self::TABLE_NAME . ' (user_id, code) VALUES (:user_id, :code)',
            [
                'user_id' => $user->getId(),
                'code' => $code
            ]
        );

        return $code;
    }

    public static function checkActivationCode(User $user, string $code): bool
    {
        $db = Db::getInstance();
        $result = $db->query(
            'SELECT * FROM ' . self::TABLE_NAME . ' WHERE user_id = :user_id AND code = :code',
            [
                'user_id' => $user->getId(),
                'code' => $code
            ]
        );
        return !empty($result);
    }
}

И теперь нам нужно сделать ещё один сервис, который будет предназначен для отправки email-сообщений.

src/MyProject/Services/EmailSender.php

<?php

namespace MyProject\Services;

use MyProject\Models\Users\User;

class EmailSender
{
    public static function send(
        User $receiver,
        string $subject,
        string $templateName,
        array $templateVars = []
    ): void {
        extract($templateVars);

        ob_start();
        require __DIR__ . '/../../../templates/mail/' . $templateName;
        $body = ob_get_contents();
        ob_end_clean();

        mail($receiver->getEmail(), $subject, $body, 'Content-Type: text/html; charset=UTF-8');
    }
}

Здесь вам все функции уже знакомы – мы использовали похожий функционал для рендеринга шаблонов. Теперь у нас появится еще один тип шаблонов – специально для email-ов.

Давайте создадим наш первый шаблон, который будет предназначен для писем активации.

templates/mail/userActivation.php

Добро пожаловать на наш портал!<br>
Для активации вашего аккаунта нажмите <a href="http://myproject.loc/users/<?=$userId?>/activate/<?=$code?>">сюда</a>.

Ну и, собственно, остаётся только взять эти компоненты и собрать воедино. Делаем это в контроллере пользователя в экшене с регистрацией.

src/MyProject/Controllers/UsersController.php

public function signUp()
{
    if (!empty($_POST)) {
        try {
            $user = User::signUp($_POST);
        } catch (InvalidArgumentException $e) {
            $this->view->renderHtml('users/signUp.php', ['error' => $e->getMessage()]);
            return;
        }

        if ($user instanceof User) {
            $code = UserActivationService::createActivationCode($user);

            EmailSender::send($user, 'Активация', 'userActivation.php', [
                'userId' => $user->getId(),
                'code' => $code
            ]);

            $this->view->renderHtml('users/signUpSuccessful.php');
            return;
        }
    }

    $this->view->renderHtml('users/signUp.php');
}

Теперь пробуем зарегистрироваться на свою почту в нашей системе.
Регистрация в системе на реальную почту

И после этого смотрим в базу данных.
Пользователи:
Зарегистрированный пользователь

Коды активации:
Код активации

Как видим, все успешно отработало, и кроме того, нам пришло письмо на почту!
Письмо с активацией

После перехода по ссылке мы видим, что такой страницы не существует.
Отсутствие страницы с активацией

Еще бы, ведь мы не добавляли для нее соответствующий роутинг. Добавляем его.

src/routes.php

...
'~^users/(\d+)/activate/(.+)$~' => [\MyProject\Controllers\UsersController::class, 'activate'],
...

И добавляем соответствующий экшен в контроллере:

src/MyProject/Controllers/UsersController.php

public function activate(int $userId, string $activationCode)
{
    $user = User::getById($userId);
    $isCodeValid = UserActivationService::checkActivationCode($user, $activationCode);
    if ($isCodeValid) {
        $user->activate();
        echo 'OK!';
    }
}

И добавляем у модели пользователя метод activate().

src/MyProject/Models/Users/User.php

public function activate(): void
{
    $this->isConfirmed = true;
    $this->save();
}

Снова пробуем обновить страничку для активации.

Успешная активация пользователя по email

Видим заветное “OK!”.

Проверяем, что в базе наш пользователь теперь подтвержден.
Активированный пользователь

Успех! Теперь осталось довести систему до ума – создать нормальные шаблоны для странички активации и обрабатывать возможные ошибки. Это вам предоставляется сделать самостоятельно в домашнем задании.

Присоединяйтесь к нам в ВКонтакте и в Facebook, чтобы не пропустить новые уроки. А также вступайте в наш чат PHP-разработчиков в Telegram.
Домашнее задание

Реализуйте следующий функционал:

  • после того как код был использован, он должен удаляться из базы;
  • обработайте все возможные ошибки в экшене activate() - подумайте, что будет, если в ссылку активации подставить несуществующего пользователя, что будет, если код не найден, и т.д. Чем больше сделаете - тем лучше;
  • добавьте шаблоны для всех этих случаев.
Курс программирования на PHP
Подготовка до уровня устройства на работу!
Начать бесплатно
Комментарии (12)
Отправка домашек на проверку и вопросы к уроку доступны только для патронов проекта.
Самый понятный курс PHP
Онлайн-уроки в удобное время!
Начать бесплатно
Популярное за сутки
Онлайн-курсы PHP и MySQL
Обучение с полного нуля до уровня джуниора!
Начать бесплатно
Сейчас читают
Онлайн-курсы PHP и MySQL
Обучение с полного нуля до уровня джуниора!
Начать бесплатно
Новые статьи
Логические задачи с собеседований