Регистрация и авторизация пользователей на PHP. Часть пятая

У нас, наконец-то, всё готово для непосредственной регистрации пользователя на сайте. Так давайте же попробуем!

Заполняем поля формы данными. Намеренно делаем ошибку в данных: в адресе электропочты вместо точки укажем запятую, а пароль напишем символами кирилицы.

Поле логина подсвечено красной рамкой. Это сделал браузер, так как атрибут type поля input имеет значение email. Адрес электропочты написан с ошибкой, форма не отправится. Позже исправим запятую на точку.

Проходим через тест капчи Google reCAPTCHA.

Отмечаем то, что нас просят выбрать.

Подтверждаем выбор.

Нам остается исправить запятую в адресе электропочты на точку, и отправить данные на регистрацию.

Регистрируем нового пользователя

Не тут-то было. Пароль содержит недопустимые символы. Конечно. Мы же сами написали его кирилицей. Хорошо, исправляем пароль.

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

Авторизация зарегистрированного пользователя

Сначала в сценарии файла-обработчика AJAX-запросов вызывается метод authUser() для объект модели пользователя.

<?php
// Файл service.php
// Инициализируем ядро сайта
require_once("bootstrap.php");

// Делаем что-либо только если выполняется запрос
if (!empty($_REQUEST) && !empty(Core_Array::getRequest("request")))
{
	// По умолчанию данные передаём в формате JSON
	$bJson = TRUE;
	
	// По умолчанию прерываем работу сценария
	$bExit = TRUE;
	
	// Данные, отправляемые в ответ на запрос по умолчанию
	$response = array(
		"success" => FALSE,
		"message" => "При выполнении запроса что-то пошло не так"
	);
	
	// Сохраняем строку значения типа запроса
	$sRequest = strval(Core_Array::getRequest("request"));
	
	// Для разных типов запроса разные действия
	switch ($sRequest)
	{
		// Проверка корректности капчи Google reCAPTCHA
		case "checkCaptcha":
			
			// Сохраняем полученное значение капчи
			$sCaptcha = strval(Core_Array::getRequest("captchaValue"));
			
			// Получаем параметры конфигурации для Google reCAPTCHA
			$aCaptcha_Config = Core_Config::instance()->get("captcha");
			
			// Формируем данные для передачи в запросе
			$aData = array(
				"secret" => $aCaptcha_Config["secret_key"],
				"response" => $sCaptcha
			);
			
			// Запрос к серверу Google выполним через cURL
			$curl = curl_init();
			
			// Указываем параметры запроса
			curl_setopt($curl, CURLOPT_URL, $aCaptcha_Config["url_verify"]);
			// Нам нужен возврат результата, а не вывод в браузер
			curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
			// Будем ли передавать заголовки
			curl_setopt($curl, CURLOPT_HEADER, FALSE);
			// Подставляем передаваемые данные
			curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($aData));
			
			// Выполняем запрос и сохраняем его результат
			$sResponse = curl_exec($curl);
			
			// Преобразуем ответ в массив
			$response = json_decode($sResponse, TRUE);
			
		break;
		
		// Проверка уникальности логина пользователя
		case "checkLoginExists":
			
			// Сохраняем переданное значение логина
			$sEmail = strval(Core_Array::getRequest("email"));
			
			// Пробуем найти пользователя по указанному логину
			$oUser = Core::factory("User")
				->getByLogin($sEmail);
				
			// Если такого пользователя нет
			if (is_null($oUser))
			{
				$response["success"] = TRUE;
				$response["message"] = "Указанный вами логин доступен для регистрации";
			}
			// Если такой логин в системе уже зарегистрирован
			else
			{
				$response["message"] = "Пользователь с указанным логином уже зарегистрирован";
			}
			
		break;
		
		// Регистрация нового пользователя
		case "userRegistration":
			
			// Сохраняем переданные данные 
			$login = strval(Core_Array::getRequest("login"));
			$password = strval(Core_Array::getRequest("password"));
			$password_approve = strval(Core_Array::getRequest("password_approve"));
			
			// Создаем объект модели пользователя
			$oUser = Core::factory("User");
			
			// Создаем объект контроллера пользователя
			$User_Controller = new User_Controller($oUser);
			
			// Добавляем в контроллер полученные данные
			$User_Controller->setLogin($login)
				->setPassword($password)
				->setPasswordApprove($password_approve);
			
			// Сначала проверяем все переданные данные
			// Если данные не прошли проверку, больше ничего не делаем
			if (!$User_Controller->checkRegistrationData())
			{
				$response["message"] = "Переданные на регистрацию данные о пользователе не прошли проверку.";
				
				break;
			}
			
			// Регистрируем пользователя, сохраняя его в БД
			$iUserId = $User_Controller->registration();
			
			// Если пользователь успешно сохранен
			if (!is_null($iUserId))
			{
				
				// Авторизуем на сайте нового пользователя сразу же
				$oUser->authUser();
				
				/**
				 * Это может показаться странным, но методу authUser() действительно
				 * не передаётся никакой идентификатор. В объект модели уже были 
				 * загружены необходимые данные пользователя в процессе его регистрации
				 */
				
				$response["success"] = TRUE;
				$response["message"] = "Пользователь с логином " . $oUser->login . " успешно зарегистрирован";
			}
			else
			{
				$response["message"] = "Не удалось зарегистрировать пользователя с логином " . $login;
			}
			
		break;
	}
	
	// Если требуется представить данные в формате JSON
	$bJson && print json_encode($response);
	
	// Если требуется прервать выполнение скрипта
	$bExit && exit();
}
else
{
	exit("Доступ к разделу запрещен");
}
?>

А теперь давайте посмотрим, что делает этот метод.

<?php
// Файл modules/core/user/model.php

defined("LEZH") || exit("Доступ к файлу запрещен");

class User_Model extends Core_ORM
{
	// Запрещенные к загрузке значения полей
	protected $_forbiddenFields = array(
		"password"	// Пароль пользователя не получаем из БД
	);
	
	/**
	 * Конструктор класса
	 * Сразу же предусмотрим возможность создания экземпляра класса для конкретного 
	 * пользователя, для которого будет передан его идентификатор
	 */
	public function __construct($iPrimaryKey = NULL)
	{
		// Основные действия будут происходить в конструкторе родительского класса
		parent::__construct($iPrimaryKey);
	}
	
	/**
	 * Устанавливает авторизованного пользователя
	 */
	public function authUser()
	{
		// На момент авторизации пользователя уже должен быть известен его идентификатор
		// Этот идентификатор должен уже быть загружен в данные модели
		if (!empty($this->id))
		{
			throw new Exception("User_Model::authUser() не установлен идентификатор пользователя");
		}
		
		// Стартуем сессию, генерируем её новый идентификатор
		Core_Session::sessionRegenerateId();
		
		// Записываем в сессию идентификатор пользователя
		$_SESSION["user_id"] = $this->id;
		
		// Пользователь авторизован
		
		return $this;
	}
	
	/**
	 * Получает авторизованного пользователя
	 */
	public function getAuthUser()
	{
		
	}
}
?>
Если читателя интересуют причины, по которым перед записью в сессию был вызван метод Core_Session::sessionRegenerateId(), ему следует изучить информацию из официальной документации, относящейся к этому вопросу.

Итак, пользователь зарегистрирован, авторизован. Что происходит после его перенравления на главную страницу? Давайте вспомним, что у нас в файле bootstrap.php в корне сайта.

<?php
// Файл bootstrap.php

// Включаем сессионную опцию use_strict_mode
ini_set('session.use_strict_mode', 1);

// Инициализируем константу для защиты от стороннего доступа
define("LEZH", TRUE);

// Определяем каталог исходных файлов нашего сайта
define("SITE_DIR", __DIR__);

// Определяем путь к каталогу файла с определением ядра сайта
define("CORE_DIR", SITE_DIR . DIRECTORY_SEPARATOR . "modules" . DIRECTORY_SEPARATOR . "core" . DIRECTORY_SEPARATOR);

// Подключаем файл с определением класса ядра нашего сайта
require_once(CORE_DIR . "core.php");

// Определяем путь для подключения внешних файлов для страниц сайта
define("INCLUDE_BLOCKS_PATH", SITE_DIR . DIRECTORY_SEPARATOR . "blocks" . DIRECTORY_SEPARATOR);

// Инициализируем ядро сайта
Core::init();

// Получаем информацию об авторизации пользователя
$oCurrentUser = Core::factory("User")->getAuthUser();

// Сохраняем информацию об авторизованном пользователе в хранилище
Core_Page::instance()->user = $oCurrentUser;
?>

Метод User_Model::getAuthUser() получает и загружает в объект модели пользователя информацию о нём, если пользователь авторизован. А затем этот объект мы сохраняем в наше глобальное хранилище. Нам осталось лишь написать реализацию этого метода. Обновим код класса User_model

Получение информации об авторизованном пользователе

<?php
// Файл modules/core/user/model.php

defined("LEZH") || exit("Доступ к файлу запрещен");

class User_Model extends Core_ORM
{
	// Запрещенные к загрузке значения полей
	protected $_forbiddenFields = array(
		"password"	// Пароль пользователя не получаем из БД
	);
	
	/**
	 * Конструктор класса
	 * Сразу же предусмотрим возможность создания экземпляра класса для конкретного 
	 * пользователя, для которого будет передан его идентификатор
	 */
	public function __construct($iPrimaryKey = NULL)
	{
		// Основные действия будут происходить в конструкторе родительского класса
		parent::__construct($iPrimaryKey);
	}
	
	/**
	 * Устанавливает авторизованного пользователя
	 */
	public function authUser()
	{
		// На момент авторизации пользователя уже должен быть известен его идентификатор
		// Этот идентификатор должен уже быть загружен в данные модели
		if (!empty($this->id))
		{
			throw new Exception("User_Model::authUser() не установлен идентификатор пользователя");
		}
		
		// Стартуем сессию, генерируем её новый идентификатор
		Core_Session::sessionRegenerateId();
		
		// Записываем в сессию идентификатор пользователя
		$_SESSION["user_id"] = $this->id;
		
		// Пользователь авторизован
		
		return $this;
	}
	
	/**
	 * Получает авторизованного пользователя
	 */
	public function getAuthUser()
	{
		// Запускаем сессию
		Core_Session::start();
		
		// Получаем идентификатор авторизованного пользователя
		$iUserId = intval(Core_Array::getSession("user_id"));
		
		// Если такой пользователь есть 
		if (!empty($iUserId))
		{
			// Загружаем данные о пользователе в модель
			$this->find($iUserId);
			
			return $this;
		}
		
		return NULL;
	}
}
?>

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

<?php
// Файл index.php

require_once('bootstrap.php');
?>
<!doctype html>
<html>
	<head>
		<title>Регистрация и авторизация пользователей</title>
		<?php
		// Подключаем необходимые CSS-файлы
		require_once(INCLUDE_BLOCKS_PATH . "css.php");
		
		// Подключаем необходимые JS-файлы сценариев
		require_once(INCLUDE_BLOCKS_PATH . "scripts.php");
		?>
	</head>
	<body>
		
		<?php
		// Подключаем блок header для страницы
		require_once(INCLUDE_BLOCKS_PATH . "header.php");
		?>
		
		<main>
			<div class="container-fluid container-lg">
				
				<h1>Главная страница сайта регистрации и авторизации пользователей</h1>
				
				<?php
				// Если пользователь авторизован
				if (!is_null(Core_Page::instance()->user))
				{
					// Получаем сохраненный объект модели пользователя 
					$oAuthUser = Core_Page::instance()->user;
					
					// Покажем логин
					print "<p>Вы авторизовались с логином: <strong>" . $oAuthUser->login . "</strong></p>";
					
					// Покажем дату регистрации
					print "<p>Дата вашей регистрации: <strong>" . (new DateTime($oAuthUser->registration_date))->format("d.m.Y") . "</strong></p>";
					
					// Покажем хэшированный пароль
					print "<p>Ваш пароль: <strong>" . $oAuthUser->password . "</strong></p>";
				}
				?>
				
			</div>
		</main>
		
	</body>
</html>

Проверяем!

А почему на экране не отображается хэш пароля? Всё верно. Ведь это поле относится к запрещенным для чтения.

Теперь очевидно, что содержимое заголовка страницы, где находится форма аутентификации, требует внесения изменений, так как авторизованному пользователю не нужно показывать форму авторизации. И нам нужна кнопка выхода.

Займемся этим в следующей статье.


Сайт принадлежит ООО Группа Ралтэк. 2014 — 2021 гг