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

Эта статья является развитием моей давней статьи про регистрацию и авторизацию пользователей. Она очень долго ждала актуализации, и, наконец, дождалась. Будет столь же полезной как и её предшественница.

Вступление

Прежде, чем мы начнем, поговорим о том, что будет в себе содержать настоящая статья. Нам нужно следующее.

  1. Создать страницы сайта доступные зарегистрированным и недоступные незарегистрированным пользователям.
  2. Данные о пользователя храним в таблице MySQL.
  3. Предложить незарегистрированным пользователям зарегистрироваться на нашем сайте.
  4. Отобразить пользователю форму регистрации.
  5. Проверить введенные пользователем данные на корректность и уникальность.
  6. Зарегистрировать пользователя.
  7. Предложить пользователю авторизоваться на нашем сайте.
  8. Авторизовать пользователя через форму для аутентификации.

Мы сразу же весь код будем писать, применяя ООП.

Конечно же, львиная доля читателей не хочет идти от начала статьи до самого её логического конца, такие читатели могут пройти посмотреть сразу же на рабочий пример.

Сайт для тренировки

Главная страница нашего тренировочного сайта ничем особым не выделяется. Она доступна и зарегистрированным, и незарегистрированным пользователям. Код её на настоящий момент очень прост.

	<!-- Файл index.php -->
	
	<!doctype html>
	<html>
		<head>
			<title>Регистрация и авторизация пользователей</title>
			<!-- Подключаем необходимые файлы для работы Bootstrap 4 -->
			<!-- CSS -->
			<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous" />
			
			<!-- jQuery -->
			<script src="https://yastatic.net/jquery/3.3.1/jquery.min.js"></script>
			<!-- JS Bootstrap 4 -->
			<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
			<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
		</head>
		<body>
			
			<main>
				<div class="container-fluid container-lg">
					
					<h1>Главная страница сайта регистрации и авторизации пользователей</h1>
					
				</div>
			</main>
			
		</body>
	</html>

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

	<?php
	// Файл index.php
	
	require_once('boorstrap.php');
	?>
	
	<!doctype html>
	<html>
		<head>
			<title>Регистрация и авторизация пользователей</title>
			<!-- Подключаем необходимые файлы для работы Bootstrap 4 -->
			<!-- CSS -->
			<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous" />
			
			<!-- jQuery -->
			<script src="https://yastatic.net/jquery/3.3.1/jquery.min.js"></script>
			<!-- JS Bootstrap 4 -->
			<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
			<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
		</head>
		<body>
			
			<main>
				<div class="container-fluid container-lg">
					
					<h1>Главная страница сайта регистрации и авторизации пользователей</h1>
					
				</div>
			</main>
			
		</body>
	</html>

Код файла index.php несколько изменится.

Ядро системы

Для функционирования всего того, что мы описали, нам потребуется реализовать некое ядро системы. Давайте напишем его класс. Но этот класс сначала нужно определить. Определение класса Core поместим в отдельный файл, а подключать его будем из файла bootstrap.php.

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

	// Инициализируем константу для защиты от стороннего доступа
	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");
	?>	

Конечно же, сейчас произойдет фигня. Нужно создать файл core.php, и определить в нём наш класс ядра сайта. Пока что все будет так.

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

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

	/**
	 * Класс ядра сайта будет статическим
	 */
	class Core 
	{
		/**
		 * Инициализирует ядро сайта
		 * ничего не возвращает
		 */
		static public function init()
		{
			
		}
	}
	?>

Метод Core::init() должен, помимо прочего, устанавливать соединение с СУБД MySQL. Будем вызывать его из файла bootstrap.php.

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

	// Инициализируем константу для защиты от стороннего доступа
	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");

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

Итак, нам нужно создать подключение к СУБД MySQL. Сделаем это при инициализации ядра сайта.

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

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

	/**
	 * Класс ядра сайта будет статическим
	 */
	class Core 
	{
		// Конфигурации чего-либо на нашем сайте
		static protected $_config = array();
		
		/**
		 * Инициализирует ядро сайта
		 * ничего не возвращает
		 */
		static public function init()
		{
			
			// Получаем конфигурацию подключения к СУБД
			// Данные для подключения хранятся внутри каталога core в каталоге config
			static::$_config["database"] = include("config/database.php");
		}
	}
	?>

Самое время записать конфигурацию подключения к СУБД. И здесь вам нужно подставить ваши данные для подключения.

	<?php
	// Файл modules/core/config/database.php

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

	return array(
		"host" => "localhost",
		"database" => "my_db_name",
		"user" => "my_username",
		"password" => "my_username_password"
	);
	?>	

В этот файл мы уже не будем вносить изменения впредь.

Для подключения к СУБД мы будем использовать класс Core_Database, и придётся поработать над тем, чтобы нам удалось его подключить и использовать. Для этого нам потребуется зарегистрировать функцию в качестве реализации метода _autoload().

Подключаемся к СУБД

Подключаемся к СУБД при инициализации ядра сайта. Сначала преобразуем файл ядра сайта, а затем добавим файл с определением класса подключения к СУБД.

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

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

	/**
	 * Класс ядра сайта будет статическим
	 */
	class Core 
	{
		// Конфигурации чего-либо на нашем сайте
		static protected $_config = array();
		
		/**
		 * Инициализирует ядро сайта
		 * ничего не возвращает
		 */
		static public function init()
		{
			
			// Получаем конфигурацию подключения к СУБД
			// Данные для подключения хранятся внутри каталога core в каталоге config
			static::$_config["database"] = include("config/database.php");
			
			// Регистрируем функции
			Core::_registerFunctions();
			
			// Подключаемся к СУБД
			Core_Database::instance()
				->setConfig(static::$_config["database"])
				->connect();
		}
		
		/**
		 * Регистрируем пользовательские функции
		 * @param string $class путь к файлу с определением класса
		 */
		static protected function _registerFunctions()
		{
			// Реализация метода _autoload
			spl_autoload_register(array("Core", "_autoload"));
		}
		
		/**
		 * Подключает пользовательские классы
		 */
		static public function _autoload($class)
		{
			// Получаем путь к файлу с определением класса
			$path = CORE_DIR . static::getClassPath($class);
			
			// Подключаем файл с определением класса
			require_once($path);
		}
		
		/**
		 * Получает путь к файлу с определением класса
		 */
		static public function getClassPath($class)
		{
			// Разбираем путь к файлу
			$aPathToClass = explode("_", $class);
			
			// Если имя начиналось с Core, убираем его из массива
			if (strtolower($aPathToClass[0]) == "core")
			{
				array_shift($aPathToClass);
			}
			
			// Последним элементом массива должно быть имя файла
			$sFileName = strtolower(array_pop($aPathToClass));
			
			// Если нет имени файла, ничего не делаем
			if (empty($sFileName))
			{
				return;
			}
			
			// Если такой файл существует
			if (is_file(CORE_DIR . $sFileName . ".php"))
			{
				$path = strtolower(implode(DIRECTORY_SEPARATOR, $aPathToClass)) . $sFileName . ".php";
			}
			
			// Возвращаем путь к файлу
			return $path;
		}
	}
	?>
	<?php
	// Файл modules/core/database.php

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

	/**
	 * Класс для работы с СУБД
	 * Класс будет статическим
	 */
	class Core_Database
	{
		// Экземпляр созданного класса
		static protected $_instance = NULL;
		
		// Конфигурация подключения к СУБД
		static protected $_aConfig = array();
		
		// Подключение к СУБД
		static protected $_connection = NULL;
		
		/**
		 * Получает и возвращает экземпляр класса 
		 */
		static public function instance()
		{
			// Если экземпляр класса не был созданс создаем его
			if (is_null(static::$_instance))
			{
				static::$_instance = new self();
			}
			
			// Возвращаем уже имеющийся экземпляр класса
			return static::$_instance;
		}
		
		/**
		 * Устанавливает параметры подключения к СУБД
		 */
		public function setConfig($options)
		{
			if (empty($options))
			{
				throw new Exception("Не переданы параметры для подключения к СУБД");
			}
			
			static::$_aConfig = $options;
			
			return $this;
		}
		
		/**
		 * Подключается к СУБД
		 */
		public function connect()
		{
			// Получаем параметры подключения к СУБД
			$aConfig = static::$_aConfig;
			
			// Строка подключения к СУБД
			$sDsn = "mysql:dbname=" . $aConfig["database"] . ";host=" . $aConfig["host"];
			
			try
			{
				static::$_connection = new PDO($sDsn, $aConfig["user"], $aConfig["password"]);
			}
			catch (PDOException $e)
			{
				throw new Exception("Не удалось подключиться к СУБД: " . $e->getMessage());
			}
		}
		
	}
	?>

Сейчас главная страница нашего тестового сайта исправно работает, нет никаких ошибок. На этом остановимся, завершив нашу первую часть большой статьи.


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