Регистрация | Авторизация на сайте PHP и MySQLi

В этой теме хочу поговорить о том для чего нужна регистрация/авторизация на сайте, и как её написать самому на языке PHP и MySQLi.

Сейчас практически уже все Интернет ресурсы имеют регистрацию и авторизацию пользователя. Авторизованному пользователю открываются закрытые от неавторизованного пользователя возможности сайта, например: написать комментарий или подписаться на рассылку новостей. Регистрация - это ввод личных данных: электронная почта и пароль - это основные данные, которые требуются ввести для добавления себя в систему. Но это далеко не все данные, которые могут потребоваться при регистрации, быть может потребуется придумать себе Логин, придумать вопрос и самому же на него ответить (для восстановления своего аккуанта), ввести знаки нарисованные на картинки (капча - антиспам), дата рождения, место жительство, и так далее. В общем при регистрации могут потребоваться любые данные.

Теперь давайте напишем простую регистрацию, где будет три поля: Логин, Электронная почта и пароль.
В БД выполняем запрос:
CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `login` varchar(20) NOT NULL,
  `email` varchar(50) NOT NULL,
  `password` varchar(35) NOT NULL,
  PRIMARY KEY (`id`)
);

Создадим файл reg.php, с таким содержимым:
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <title>Регистрация</title>
</head>
<body>

<form action="reg.php" method="POST" />
    <table>
        <tr>
            <td>Введите логин:</td>
            <td><input type="text" size="20" name="login" /></td>
        </tr>
        <tr>
            <td>Введите почту:</td>
            <td><input type="text" size="20" name="email" /></td>
        </tr>
        <tr>
            <td>Введите пароль:</td>
            <td><input type="password" size="20" maxlength="20" name="password" /></td>
        </tr>
        <tr>
            <td colspan="2"><input class="button" type="submit" value="Зарегистрироваться" name="submit" /></td>
        </tr>
    </table>
</form>

<?php
$connection = mysqli_connect('Хост БД', 'Пользователь БД', 'Пароль БД', 'Имя БД') or die(mysqli_error($connection));

if (isset($_POST['submit'])) 
{
    if (empty($_POST['login'])) 
    {
        $info_reg = 'Вы не ввели Логин';
    }          
    elseif (empty($_POST['email'])) 
    {
        $info_reg = 'Вы не ввели почту';
    }           
    elseif (empty($_POST['password'])) 
    {
        $info_reg = 'Вы не ввели пароль';
    }                      
    else 
    {
        $login = $_POST['login'];
        $email = $_POST['email'];               
        $password = $_POST['password'];
  
        $query = "INSERT INTO `users` (login, email, password)
        VALUES ('$login', '$email', '$password')";
        $result = mysqli_query($connection, $query) or die(mysqli_error($connection));
                    
        $info_reg = 'Вы успешно зарегистрировались!';
    }
}

$info_reg = isset($info_reg) ? $info_reg : NULL;
echo $info_reg;
?>

</body>
</html>

Это простой скрипт, который проверяет три поля, введена ли в них информация или нет, если какое то поле не заполнено, выйдет сообщение об ошибке. Если же все поля заполнены, то данные будут переданы в базу данных.
После успешной регистрации, необходимо войти на сайт, для этого сделаем форму авторизации.
Создаем файл login.php, с таким содержанием:
<?php
session_start();
?>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <title>Вход на сайт</title>
</head>
<body>

<form action="login.php" method="POST" />
    <table>
        <tr>
            <td>Введите логин:</td>
            <td><input type="text" name="login" /></td>
        </tr>
        <tr>
            <td>Введите пароль:</td>
            <td><input type="password" name="password" /></td>
        </tr>
        <tr>
            <td colspan="2"><input class="button" type="submit" value="Войти" name="submit" /></td> 
        </tr>
    </table>
</form>

<?php
$connection = mysqli_connect('Хост БД', 'Пользователь БД', 'Пароль БД', 'Имя БД') or die(mysqli_error());

if (isset($_POST['submit'])) 
{
    if (empty($_POST['login'])) 
    {
        $info_input = 'Вы не ввели логин';
    }
    elseif (empty($_POST['password'])) 
    {
        $info_input = 'Вы не ввели пароль';
    }
    else 
    {    
        $login = $_POST['login'];
        $password = $_POST['password'];            
        $user = mysqli_query($connection, "SELECT `id` FROM `users` WHERE `login` = '$login' AND `password` = '$password'");
        $id_user = mysqli_fetch_array($user);
                
        if (empty($id_user['id'])) 
        {
            $info_input = 'Введенные данные не верны';
        }
        else 
        {
            $_SESSION['password'] = $password; 
            $_SESSION['login'] = $login; 
            $_SESSION['id'] = $id_user['id']; 

            $info_input = 'Вы успешно вошли в систему';         
        }     
    }
}
        
$info_input = isset($info_input) ? $info_input : NULL;
echo $info_input;
?>

</body>
</html>

После входа в систему, мы можем показать, что вздумается, то что не увидит неавторизованный пользователь. Для этого пишем условие:
if (isset($_SESSION['login']) && isset($_SESSION['id'])) 
{
    # Здесь все, что может видеть авторизованный пользователь.
}

Ну а то что можно видеть гостям (неавторизованным пользователям), а от авторизованных надо скрыть, пишем такое условие:
if (empty($_SESSION['login']) || empty($_SESSION['id'])) 
{
    # Здесь все, что может видеть неавторизованный пользователь.
} 

Это может быть полезно, например если Вы хотите показывать рекламу только гостям своего сайта.
Теперь, что бы выйти из системы, используйте следующий скрипт:
unset($_SESSION['password']);
unset($_SESSION['login']); 
unset($_SESSION['id']);

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

Чуть позже, я расскажу, как сделать проверку ввода пароля на правильность, как защититься от инъекции, как сделать проверку корректности почты и так далее.

Возможно, будет интересно:
- Активация учётной записи по ссылке на PHP

Похожие темы

Ввести пароль ещё раз
В нашей форме регистрации находится одно поле для ввода пароля, это значит, что пользователь при вводе пароля может ошибиться, например случайно нажмет другую кнопку. А когда будет авторизовываться, то не сможет войти в систему. Что бы исключить ошибку с вводом пароля, необходимо добавить еще одно поле для повторного ввода пароля. Если пароли не совпадут, то скрипт выдаст сообщение о том, что пароли не не совпадают.
И так, в форм регистрации, после:
        <tr>
            <td>Введите пароль:</td>
            <td><input type="password" size="20" maxlength="20" name="password" /></td>
        </tr>

Добавляем:
        <tr>
            <td>Введите пароль ещё раз:</td>
            <td><input type="password" size="20" maxlength="20" name="password2" /></td>
        </tr>

В самом скрипте регистрации после:
    elseif (empty($_POST['password'])) 
    {
        $info_reg = 'Вы не ввели пароль';
    }

Добавляем следующие:
    elseif ($_POST['password'] != $_POST['password2']) 
    {
        $info_reg = 'Пароли не совпадают';
    }

Вот и всё! Теперь пользователю трудно будет ошибиться.

Если Вы хотите, что бы была проверка заполнено ли поле ввода повторного пароля, добавьте перед:
    elseif ($_POST['password'] != $_POST['password2']) 
    {
        $info_reg = 'Пароли не совпадают';
    }

Этот код:
    elseif (empty($_POST['password2'])) 
    {
        $info_reg = 'Вы не ввели пароль повторно';
    }
Проверка корректно ли введен Email
Небольшая доработка скрипта регистрации, которая будет проверять корректно ли введена электронная почта регистрирующего.

И так, находим в нашем скрипте регистрации вот этот код:
    elseif (empty($_POST['email']))  
    {
        $info_reg = 'Вы не ввели почту';
    }

И ниже добавляем:
    elseif (!preg_match("/^[a-zA-Z0-9_\.\-]+@([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,6}$/", $_POST['email'])) 
    {
        $info_reg = 'Неправильно введен адрес электронной почты';
    }


Проверка на минимальное количество символов
На данный момент наш скрипт регистрации позволяет создать свой логин из одного символа, я считаю, что логин из одного символа - это не совсем хорошо... Если Вы считаете так же, как и я то следующая доработка скрипта для Вас.
Значит, после кода:
    if (empty($_POST['login']))
    {
        $info_reg = 'Вы не ввели Логин';
    }

Добавляем:
    else if (iconv_strlen($user_login, 'utf-8') < 3)
    {
        $info_reg = 'Вы ввели слишком короткий Логин';
    }

В данном случаи минимальное количество символов в логине 3. Что бы сделать минимальное количество символов больше или меньше, просто исправьте число 3 на то, которое нужно Вам.

Защита от инъекций
Защищаемся от инъекции, делаем регистрацию безопаснее.
Находим в нашем скрипте регистрации следующею строчку:
        $login = $_POST['login'];

И меняем её на:
        $login = mysqli_real_escape_string($connection, $_POST['login']);

Готово.

Подробнее о инъекциях читайте в статье: Как предотвратить PHP, SQL и XSS инъекции (Безопасность).
Как сделать редирект при успешной авторизации?
спс за предоставленный способ
Отредактировано 7:39 pm, Январь 16, 2019 (sergeybutakov).
Замените:
            $info_input = 'Вы успешно вошли в систему';

На:
            header('Location: url');

Вместо url адрес страницы, куда надо отправить пользователя.
получаю:
Warning: Cannot modify header information - headers already sent by (output started at /home/p511161/www/x-mod.ru/regid/login.php:4) in ...login.php on line 57
Отредактировано 8:30 pm, Январь 16, 2019 (sergeybutakov).
Покажите весь свой код.
Держите, буду признателен
reg.php
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <title>Регистрация</title>
</head>
<body>

<form action="reg.php" method="POST" />
    <table>
        <tr>
            <td>Введите логин:</td>
            <td><input type="text" size="20" name="login" /></td>
        </tr>
        <tr>
            <td>Введите пароль:</td>
            <td><input type="password" size="20" maxlength="20" name="password" /></td>
        </tr>
        <tr>
            <td colspan="2"><input class="button" type="submit" value="Зарегистрироваться" name="submit" /></td>
        </tr>
    </table>
</form>

<?php
$connection = mysqli_connect('p511161.mysql.ihc.ru', 'p511161_serial', '8MeY6cnq', 'p511161_serial') or die(mysqli_error($connection));

if (isset($_POST['submit'])) 
{
    if (empty($_POST['login'])) 
    {
        $info_reg = 'Вы не ввели Логин';
    }                   
    elseif (empty($_POST['password'])) 
    {
        $info_reg = 'Вы не ввели пароль';
    }                      
    else 
    {
        $login = $_POST['login'];             
        $password = $_POST['password'];
  
        $query = "INSERT INTO `admin` (login, password)
        VALUES ('$login', '$password')";
        $result = mysqli_query($connection, $query) or die(mysqli_error($connection));
                    
        $info_reg = 'Вы успешно зарегистрировались!';
    }
}

$info_reg = isset($info_reg) ? $info_reg : NULL;
echo $info_reg;
?>

</body>
</html>

login.php
<?php
session_start();
?>

<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <title>Вход на сайт</title>
</head>
<body>

<form action="login.php" method="POST" />
    <table>
        <tr>
            <td>Введите логин:</td>
            <td><input type="text" name="login" /></td>
        </tr>
        <tr>
            <td>Введите пароль:</td>
            <td><input type="password" name="password" /></td>
        </tr>
        <tr>
            <td colspan="2"><input class="button" type="submit" value="Войти" name="submit" /></td> 
        </tr>
    </table>
</form>

<?php
$connection = mysqli_connect('Хост БД', 'Пользователь БД', 'Пароль БД', 'Имя БД') or die(mysqli_error());

if (isset($_POST['submit'])) 
{
    if (empty($_POST['login'])) 
    {
        $info_input = 'Вы не ввели логин';
    }
    elseif (empty($_POST['password'])) 
    {
        $info_input = 'Вы не ввели пароль';
    }
    else 
    {    
        $login = $_POST['login'];
        $password = $_POST['password'];            
        $user = mysqli_query($connection, "SELECT `id` FROM `admin` WHERE `login` = '$login' AND `password` = '$password'");
        $id_user = mysqli_fetch_array($user);
                
        if (empty($id_user['id'])) 
        {
            $info_input = 'Введенные данные не верны';
        }
        else 
        {
            $_SESSION['password'] = $password; 
            $_SESSION['login'] = $login; 
            $_SESSION['id'] = $id_user['id'];
            header('Location: reg.php'); 
        } 
    }
}

$info_input = isset($info_input) ? $info_input : NULL;
echo $info_input;

unset($_SESSION['password']);
unset($_SESSION['login']); 
unset($_SESSION['id']);
?>
</body>
</html>
Зачем удалять переменные в сессии сразу после авторизации?
$info_input = isset($info_input) ? $info_input : NULL;
echo $info_input;

unset($_SESSION['password']);
unset($_SESSION['login']); 
unset($_SESSION['id']);

Так пользователь будет всегда гостем и ни когда не сможет авторизоваться.
спс за поправку
sergeybutakov, проверил ваш код, все работает...
Уберите пустую строку перед <html> (в своем посте я тоже уберу). Непонятно, зачем перенаправлять пользователя после авторизации на форму регистрации:
header('Location: reg.php');

Если пользователь авторизуется, значит он уже зарегистрирован.

Это:
unset($_SESSION['password']);
unset($_SESSION['login']); 
unset($_SESSION['id']);

Нужно только в том случае, если пользователю необходимо выйти из системы, удалять сессию сразу после авторизации - плохая идея.
Единственная страница под рукой была reg.php)) поэтому ее и написал
Спасибо сейчас попробую!
Очень интересно, перепробовал 3 браузера, сбрасывал кэш, один черт вижу ошибку в 56строке
Warning: Cannot modify header information - headers already sent by (output started at /home/.../login.php:4) in /home/.../login.php on line 56
Браузер тут не причем, ошибка на стороне сервера, так, что она должна появляться в любом браузере.
Сейчас код файла начинается с HTML, попробуйте изменить, чтобы файл начинался с PHP кода:
<?php
    // PHP код авторизации
?>
<html>
    <!-- HTML код авторизации -->
</html>

Надо сделать так, чтобы функция header была до того, как браузер получит, какую то информацию. Изменение порядка кода должно помочь, я надеюсь.
Спасибо! помогло
Пользуясь Вашими знаниями, куда можно вставить
if (empty($_SESSION['login']) || empty($_SESSION['id']))

на странице (к примеру рег.пхп, на которую идет редирект после авторизации), чтобы не авторизованные пользователи не могли получить доступ. Понятно, что не авторизованного пользователя не перекинет на рег.пхп, но на нее можно зайти просто так, зная адрес.
sergeybutakov сказал:
5:56 pm, Январь 17, 2019 (id: #3004)
Понятно, что не авторизованного пользователя не перекинет на рег.пхп, но на нее можно зайти просто так, зная адрес.

Я наверно вас неправильно понял... Вам надо скрыть форму регистрации от гостей (неавторизованные пользователи)? Я бы не стал прятать от гостей форму регистрации и форму авторизации, а вот авторизованным доступ к этим формам бы закрыл. Так как без формы регистрации гости не смогут стать участниками системы, а без формы авторизации, они не смогут зайти в систему. Сначала человек регистрируется, затем авторизуется, не иначе. Считаю правильным давать ссылку на регистрацию и авторизацию гостям... Но, возможно, я вас не правильно понял...

Вообще, я бы написал функцию, которая выполняла бы проверку на то, кем является пользователь, вот, например, как тут: Проверка: Кем является пользователь сайта на PHP (Группа пользователя). Перед тем, как отдать данные формы регистрации, проверяем, кем является пользователь (гость | авторизованный), если гость - даем зеленый свет, если человек уже авторизован, то просто перенаправляем на главную страницу, или выводим 404 ошибку. Тоже самое и с авторизацией и с любым другим контентом.

Пробуем написать простую функцию проверки пользователя:
	function isUser()
	{
		if (!empty($_SESSION['login']) && !empty($_SESSION['id']))
		{
			return true;
		}

		return false;
	}

Теперь перед кодо авторизации проверяем зашедшего сюда, если человек авторизован, перенаправляем его на главную сайта:
	if (isUser())
	{
		header('Location: /');
	}
Прошу извинить за недосказанность, не хотел Вас утруждать всем объемом информации.
Суть следующая: есть форма регистрации юзеров, которых регистрирует админ, тем самым ведя базу этих юзеров. Но чтобы эти юзеры сами себя не смогли занести туда - делается форма авторизации, для админа.
Получается как то так))
В таком случае необходимо проверять самого админа, например так:
if (!empty($_SESSION['login']) && !empty($_SESSION['id']) && $_SESSION['id'] == 1)
{
    // Тут то, что доступно только админу
}

Или:
if (empty($_SESSION['login']) || empty($_SESSION['id']) || $_SESSION['id'] != 1)
{
    // Зашел не админ, перенаправляем его на главную
    header('Location: /');
}

1 - это ID админа, если ID у админа другой, изменяйте на свой. Можно сделать проверку группы пользователей, это будет удобнее, если, например, админов несколько.
Как в этот код обернуть форму регистрации (html которая)
if (!empty($_SESSION['login']) && !empty($_SESSION['id']) && $_SESSION['id'] == 1)
{
    // Тут то, что доступно только админу
}

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