Пишем свою авторизацию на PHP и MySQL

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

ВНИМАНИЕ.
Содержимое данной статьи морально устарело но сохранено для академических целей.

И так, в базе у нас будет 1 база из 4 полей: users_id, users_login, users_password и users_hash. SQL запрос:

CREATE TABLE IF NOT EXISTS `users` (
  `users_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `users_login` VARCHAR(30) NOT NULL,
  `users_password` VARCHAR(32) NOT NULL,
  `users_hash` VARCHAR(32) NOT NULL,
  PRIMARY KEY  (`users_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
  • conf.php — Файл конфигурации, в котором так же содержится подключение к бд;
  • register.php — Регистрация нового пользователя;
  • login.php — Авторизация пользователя;
  • check.php — Скрипт проверки авторизации;

Давайте разберем каждый файл.

conf.php

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

<?php
# настройки
define ('DB_HOST', 'localhost');
define ('DB_LOGIN', 'example_user');
define ('DB_PASSWORD', 'example_password');
define ('DB_NAME', 'example_base');
mysql_connect(DB_HOST, DB_LOGIN, DB_PASSWORD) or die ("MySQL Error: " . mysql_error());
mysql_query("set names utf8") or die ("<br>Invalid query: " . mysql_error());
mysql_select_db(DB_NAME) or die ("<br>Invalid query: " . mysql_error());

# массив ошибок
$error[0] = 'Я вас не знаю';
$error[1] = 'Включи куки';
$error[2] = 'Тебе сюда нельзя';
?>

register.php

Файл регистрации, тут содержится простейшая форма и ее обработчик. Исходный код прокомментирован, но общий процесс я коротко опишу. Вначале проверяем наш логин, он может содержать только английские буквы и цифры. Далее мы проверяем длину логина, от 3 до 30 символов. Проверяем свободен ли логин. При успешных проверках добавляем нового пользователя в базу. Из введенного пароля мы вырезаем пробелы на случай если пользователь хранит свои пароли в каком ни будь текстовом файле (в windows текстовые редакторы любят «хватать» пробелы в начале или конце выделяемого текста). Шифруем пароль в двойном MD5 и добавляем в базу данные о новом пользователе. Перебрасываем пользователя на login.php.

<?php
# Подключаем конфиг
include 'conf.php';

if(isset($_POST['submit']))
{

    $err = array();

    # проверям логин
   if(!preg_match("/^[a-zA-Z0-9]+$/",$_POST['login']))
    {
        $err[] = "Логин может состоять только из букв английского алфавита и цифр";
    }
     
    if(strlen($_POST['login']) < 3 or strlen($_POST['login']) > 30)
    {
        $err[] = "Логин должен быть не меньше 3-х символов и не больше 30";
    }
     
    # проверяем, не сущестует ли пользователя с таким именем
  $query = mysql_query("SELECT COUNT(users_id) FROM users WHERE users_login='".mysql_real_escape_string($_POST['login'])."'")or die ("<br>Invalid query: " . mysql_error());
    if(mysql_result($query, 0) > 0)
    {
        $err[] = "Пользователь с таким логином уже существует в базе данных";
    }
 
     
    # Если нет ошибок, то добавляем в БД нового пользователя
   if(count($err) == 0)
    {
         
        $login = $_POST['login'];
         
        # Убераем лишние пробелы и делаем двойное шифрование
       $password = md5(md5(trim($_POST['password'])));
         
        mysql_query("INSERT INTO users SET users_login='".$login."', users_password='".$password."'");
        header("Location: login.php"); exit();
    }
}
?>

  <form method="POST" action="">
  Логин <input type="text" name="login" id="reg_inp" /><br />
  Пароль <input type="password" name="password" id="reg_inp" /><br />
  <input name="submit" type="submit" value="Зарегистрироваться">
  </form>
  <?php
    if (isset($err)) {
      print "<b>При регистрации произошли следующие ошибки:</b><br>";
      foreach($err AS $error)
      {
        print $error."<br>";
      }  
    }
  ?>

login.php

Опять кратко расскажу о действиях совершаемых в данном скрипте. В самом начале у нас висит функция для генерации случайной строки, она служит для хеша пользователя (чуть позже более подробно). Далее мы проверяем наличие куков с ошибками (они ставятся в check.php). Подключаем файл конфигурации и проверяем пользователя. Вытаскиваем из бд логин и пароль, сравниваем с введенными и генерируем хеш. Записываем в бд новый хеш пользователя и ставим куки. В куках находится id и хеш пользователя. Пересылаем пользователя на check.php.

<?php
  # Функция для генерации случайной строки
  function generateCode($length=6) {
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPRQSTUVWXYZ0123456789";
    $code = "";
    $clen = strlen($chars) - 1;  
    while (strlen($code) < $length) {
        $code .= $chars[mt_rand(0,$clen)];  
    }
    return $code;
  }
 
  # Если есть куки с ошибкой то выводим их в переменную и удаляем куки
  if (isset($_COOKIE['errors'])){
      $errors = $_COOKIE['errors'];
      setcookie('errors', '', time() - 60*24*30*12, '/');
  }

  # Подключаем конфиг
  include 'conf.php';

  if(isset($_POST['submit']))
  {
   
    # Вытаскиваем из БД запись, у которой логин равняеться введенному
    $data = mysql_fetch_assoc(mysql_query("SELECT users_id, users_password FROM `users` WHERE `users_login`='".mysql_real_escape_string($_POST['login'])."' LIMIT 1"));
     
    # Соавниваем пароли
    if($data['users_password'] === md5(md5($_POST['password'])))
    {
      # Генерируем случайное число и шифруем его
      $hash = md5(generateCode(10));
           
      # Записываем в БД новый хеш авторизации и IP
      mysql_query("UPDATE users SET users_hash='".$hash."' WHERE users_id='".$data['users_id']."'") or die("MySQL Error: " . mysql_error());
       
      # Ставим куки
      setcookie("id", $data['users_id'], time()+60*60*24*30);
      setcookie("hash", $hash, time()+60*60*24*30);
       
      # Переадресовываем браузер на страницу проверки нашего скрипта
      header("Location: check.php"); exit();
    }
    else
    {
      print "Вы ввели неправильный логин/пароль<br>";
    }
  }
?>
  <form method="POST">
  Логин <input name="login" type="text"><br>
  Пароль <input name="password" type="password"><br>
  <input name="submit" type="submit" value="Войти">
  </form>
  <?php
  # Проверяем наличие в куках номера ошибки
  if (isset($errors)) {print '<h4>'.$error[$errors].'</h4>';}

  ?>

check.php

И последний файл, который содержит проверку авторизации пользователя. В начале подключаем конфиг и если существуют куки начинаем проверку, если их нет, то ставим куки с номером ошибки и отсылаем на login.php. И так проверка. Вытаскиваем из бд id и хеш. Если они не проходят проверку на соответствие с теми куками которые стоят у посетителя, то удаляем существующие куки посетителя и ставим куки с номером ошибки, пересылаем на login.php. Если же все нормально то пользователь увидит страницу.

<?php
# подключаем конфиг
include 'conf.php';  

# проверка авторизации
if (isset($_COOKIE['id']) and isset($_COOKIE['hash']))
{    
    $userdata = mysql_fetch_assoc(mysql_query("SELECT * FROM users WHERE users_id = '".intval($_COOKIE['id'])."' LIMIT 1"));

    if(($userdata['users_hash'] !== $_COOKIE['hash']) or ($userdata['users_id'] !== $_COOKIE['id']))
    {
        setcookie('id', '', time() - 60*24*30*12, '/');
        setcookie('hash', '', time() - 60*24*30*12, '/');
    setcookie('errors', '1', time() + 60*24*30*12, '/');
    header('Location: login.php'); exit();
    }
}
else
{
  setcookie('errors', '2', time() + 60*24*30*12, '/');
  header('Location: login.php'); exit();
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
  <title></title>
</head>
<body>
  hello!
</body>
</html>

Выход

Выход можно осуществить любым удобным для вас способом просто удалив куки, допустим так:

<form action="" method="post"><input type='submit' name='exit' value='Выйти'/></form>
<?php
if($_REQUEST['exit'])
  {
        setcookie('id', '', time() - 60*60*24*30, '/');
        setcookie('hash', '', time() - 60*60*24*30, '/');
        header('Location: login.php'); exit();
  }
?>

Сразу хочу предупредить о том что ваши файлы должны быть в кодировке UTF8 и БЕЗ BOM! Приятного пользования!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Copyright © Programmer Weekdays | Powered by WordPress