Система активации пользователей по email на PHP
В этом уроке мы напишем систему активации пользователей по email. После регистрации пользователь будет получать письмо со специальной ссылкой, содержащей код. При открытии этой ссылки будет происходить активация этого пользователя.
Прежде чем начать, вам нужно настроить OpenServer для отправки писем.
После того, как вы это сделали, можно приступать к написанию кода. Первое, что нам нужно – создать новую табличку, в которой мы будем хранить коды для активации пользователей.
Называем её «users_activation_codes», и указываем, что нам требуются три столбца:
- id – это просто id записи в таблице;
- user_id – id пользователя;
- code – код для активации этого пользователя.
CREATE TABLE `users_activation_codes` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`code` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `users_activation_codes`
ADD PRIMARY KEY (`id`);
ALTER TABLE `users_activation_codes`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
Теперь нам нужно написать специальный сервис, который позволит нам создавать новые коды активации для пользователей, а также проверять код активации для конкретного пользователя. Пишем.
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();
}
Снова пробуем обновить страничку для активации.
Видим заветное “OK!”.
Проверяем, что в базе наш пользователь теперь подтвержден.
Успех! Теперь осталось довести систему до ума – создать нормальные шаблоны для странички активации и обрабатывать возможные ошибки. Это вам предоставляется сделать самостоятельно в домашнем задании.
Текущая версия проекта на гитхабе.
Комментарии