Чат 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.
Домашнее задание
Задание и его проверка доступны только для патронов проекта. От 1$/месяц.
Читайте также
Комментарии (6)
Комментирование урока доступно только для патронов проекта. От 1$/месяц.