Авторизация на сессиях PHP и MySQL

Итак, как я и обещал, сегодня я расскажу как сделать свою авторизацию используя session, php и mysql. Для начала определимся что такое сессия и чем она отличается от cookie.

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


Session – это механизм, позволяющий однозначно идентифицировать браузер и создающий для этого браузера файл на сервере, в котором хранятся переменные сеанса.
Cookies — это механизм хранения данных браузером удаленного компьютера для идентификации возвращающихся посетителей и хранения параметров веб-страниц.
Т.е. главное различие это место хранения данных, у сессий на стороне сервера, у куков на стороне клиента, это различие критично. Если украсть у пользователя cookie довольно просто то с сессиями не все так просто. Ну а теперь перейдем к практической части а именно к написанию своей авторизации.
Для начала определим имена файлов:

  • config.php — хранит данные для подключения к Базе Данных ( далее БД )
  • functions.php — содержит в себе все функции для работы авторизации
  • join.php — простейший пример регистрации пользователя в системе
  • login.php — служит для входа в систему
  • logout.php — служит для выхода из системы
  • members.php — служит для проверки авторизации ( простейший пример «закрытой» части сайта

Для начала создадим БД и таблицу где будут храниться данные пользователей.

SQL дамп таблицы пользователей

CREATE TABLE users (
  id INT(5) NOT NULL AUTO_INCREMENT,
  login VARCHAR(15) DEFAULT '0' ,
  password VARCHAR(15) DEFAULT '0' ,
  PRIMARY KEY (id)
);

config.php

Что содержит данный файл я уже говорил, поэтому просто приведу его код.

<?php
# Запуск сессии
session_start();
# Служит для отладки, показывает все ошибки, предупреждения и т.д.
error_reporting(E_ALL);
# Подключение файлов с функциями
include_once("functions.php");
# В этом массиве далее мы будем хранить сообщения системы, т.е. ошибки.
$messages=array();
# Данные для подключения к БД
$dbhost="localhost";
$dbuser="database_user";
$dbpass="user_password";
$dbname="datebase";
# Вызываем функцию подключения к БД
connectToDB();
?>

functions.php

Самый большой файл из всех в данной статье, содержит все функции. Приведу исходный код а потом прокомментирую каждую функцию.

<?php

function connectToDB() {
  global $link, $dbhost, $dbuser, $dbpass, $dbname;
  ($link = mysql_pconnect("$dbhost", "$dbuser", "$dbpass")) || die("Couldn't connect to MySQL");
  mysql_select_db("$dbname", $link) || die("Couldn't open db: $dbname. Error if any was: ".mysql_error() );
}



function newUser($login, $password) {
  global $link;

  $query="INSERT INTO users (login, password) VALUES('$login', '$password')";
  $result=mysql_query($query, $link) or die("Died inserting login info into db.  Error returned if any: ".mysql_error());

  return true;
}



function displayErrors($messages) {
  print("<b>Возникли следующие ошибки:</b>\n<ul>\n");

  foreach($messages as $msg){
    print("<li>$msg</li>\n");
  }
  print("</ul>\n");
}




function checkLoggedIn($status){
  switch($status){
    case "yes":
      if(!isset($_SESSION["loggedIn"])){
        header("Location: login.php");
        exit;
      }
      break;
    case "no":
      if(isset($_SESSION["loggedIn"]) && $_SESSION["loggedIn"] === true ){
        header("Location: members.php");
      }
      break;
  }
  return true;
}



function checkPass($login, $password) {
  global $link;

  $query="SELECT login, password FROM users WHERE login='$login' and password='$password'";
  $result=mysql_query($query, $link)
    or die("checkPass fatal error: ".mysql_error());

  if(mysql_num_rows($result)==1) {
    $row=mysql_fetch_array($result);
    return $row;
  }
  return false;
}


function cleanMemberSession($login, $password) {
  $_SESSION["login"]=$login;
  $_SESSION["password"]=$password;
  $_SESSION["loggedIn"]=true;
}


function flushMemberSession() {
  unset($_SESSION["login"]);
  unset($_SESSION["password"]);
  unset($_SESSION["loggedIn"]);
  session_destroy();
  return true;
}

function field_validator($field_descr, $field_data, $field_type, $min_length="", $max_length="", $field_required=1) {

  global $messages;

  if(!$field_data && !$field_required){ return; }

  $field_ok=false;

  $email_regexp="^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|";
  $email_regexp.="(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";

  $data_types=array(
    "email"=>$email_regexp,
    "digit"=>"^[0-9]$",
    "number"=>"^[0-9]+$",
    "alpha"=>"^[a-zA-Z]+$",
    "alpha_space"=>"^[a-zA-Z ]+$",
    "alphanumeric"=>"^[a-zA-Z0-9]+$",
    "alphanumeric_space"=>"^[a-zA-Z0-9 ]+$",
    "string"=>""
  );

  if ($field_required && empty($field_data)) {
    $messages[] = "Поле $field_descr является обезательным";
    return;
  }

  if ($field_type == "string") {
    $field_ok = true;
  } else {
    $field_ok = ereg($data_types[$field_type], $field_data);
  }

  if (!$field_ok) {
    $messages[] = "Пожалуйста введите нормальный $field_descr.";
    return;
  }

  if ($field_ok && ($min_length > 0)) {
    if (strlen($field_data) < $min_length) {
      $messages[] = "$field_descr должен быть не короче $min_length символов.";
      return;
    }
  }

  if ($field_ok && ($max_length > 0)) {
    if (strlen($field_data) > $max_length) {
      $messages[] = "$field_descr не должен быть длиннее $max_length символов.";
      return;
    }
  }
}
?>

А теперь по порядку

  • function connectToDB() — служит для подключения к базе данных
  • function newUser($login, $password) — служит для создания нового пользователя в системе
  • function displayErrors($messages) — выводит массив ошибок
  • function checkLoggedIn($status) — проверяет авторизацию пользователя.
  • function checkPass($login, $password) — проверяет пользователя по БД во время авторизации
  • function cleanMemberSession($login, $password) — авторизует пользователя
  • function flushMemberSession() — выход, или если вам будет удобнее logout
  • function field_validator($field_descr, $field_data, $field_type, $min_length=»», $max_length=»», $field_required=1) — Валидатор данных, проверяет соответствие полей требованиям системы

Работу каждой функции я описывать не буду, т.к. они довольно простые, в данный момент нас интересует только логика. Если будут вопросы — спрашивайте.

join.php

Итак исходник:

<?php
include_once("config.php");

checkLoggedIn("no");

$title="страница регистрации";

if(isset($_POST["submit"])){
  field_validator("login name", $_POST["login"], "alphanumeric", 4, 15);
  field_validator("password", $_POST["password"], "string", 4, 15);
  field_validator("confirmation password", $_POST["password2"], "string", 4, 15);

  if(strcmp($_POST["password"], $_POST["password2"])) {

    $messages[]="Ваши пароли не совпадают";
  }
 
  $query="SELECT login FROM users WHERE login='".$_POST["login"]."'";

  $result=mysql_query($query, $link) or die("MySQL query $query failed.  Error if any: ".mysql_error());

  if( ($row=mysql_fetch_array($result)) ){
    $messages[]="Логин \"".$_POST["login"]."\" уже занят, попробуйте другой.";
  }

  if(empty($messages)) {
    newUser($_POST["login"], $_POST["password"]);

    cleanMemberSession($_POST["login"], $_POST["password"]);

    header("Location: members.php");

  }
}
?>
<html>
<head>
<title><?php print $title; ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=uft-8">
</head>
<body>
<h1><?php print $title; ?></h1>
<?php
if(!empty($messages)){
  displayErrors($messages);
}
?>
<form action="<?php print $_SERVER["PHP_SELF"]; ?>" method="POST">
<table>
<tr><td>Логин:</td><td><input type="text" name="login"
value="<?php print isset($_POST["login"]) ? $_POST["login"] : "" ; ?>"
maxlength="15"></td></tr>
<tr><td>Пароль:</td><td><input type="password" name="password" value="" maxlength="15"></td></tr>
<tr><td>Повторить пароль:</td><td><input type="password" name="password2" value="" maxlength="15"></td></tr>
<tr><td> </td><td><input name="submit" type="submit" value="Submit"></td></tr>
</table>
</form>
</body>
</html>

Если кратко описать работу скрипта получится что то вроде:
1. Если уже авторизованы пересылаем на members.php ( строка 4 )
2. Если существует $_POST[‘submit’] ( если отправили данные с формы ) проверяем поля валидатором, проверяем наличие такого пользователя, если никаких ошибок нет, добавляем нового пользователя, ставим сессию и пускаем на members.php
3. Если есть ошибки — выводим
4. Выводим форму

login.php

Код:

<?php
include_once("config.php");

checkLoggedIn("no");

$title="Страница авторизации";

if(isset($_POST["submit"])) {
  field_validator("login name", $_POST["login"], "alphanumeric", 4, 15);
  field_validator("password", $_POST["password"], "string", 4, 15);
  if($messages){
    doIndex();
    exit;
  }

    if( !($row = checkPass($_POST["login"], $_POST["password"])) ) {
        $messages[]="Incorrect login/password, try again";
    }

  if($messages){
    doIndex();
    exit;
  }

  cleanMemberSession($row["login"], $row["password"]);

  header("Location: members.php");
} else {
  doIndex();
}

function doIndex() {
  global $messages;
  global $title;
?>
<html>
<head>
<title><?php print $title; ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<h1><?php print $title; ?></h1>
<?php
if($messages) { displayErrors($messages); }
?>
<form action="<?php print $_SERVER["PHP_SELF"]; ?>" method="POST">
<table>
<tr><td>Логин:</td><td><input type="text" name="login"
value="<?php print isset($_POST["login"]) ? $_POST["login"] : "" ; ?>"
maxlength="15"></td></tr>
<tr><td>Пароль:</td><td><input type="password" name="password" value="" maxlength="15"></td></tr>
<tr><td> </td><td><input name="submit" type="submit" value="Submit"></td></tr>
</table>
</form>
</body>
</html>
<?php
}
?>

Во первых тут стоит указать что вывод html и ошибок происходит в функции doIndex() которая вызывается в некоторых случаях, это не очень удобно поэтому кто хочет переписать — милости прошу, лично я сделал это для примера, к каждому проекту я пишу собственную авторизацию и стараюсь не повторяться. Поэтому здесь только пример.
А теперь по порядку.
1. подключаем конфиг
2. если уже авторизованы пересылаем на страницу members.php ( функция checkLoggedIn с параметром no )
3. Если отправлена форма, проверяем поля валидатором, если есть ошибки вызываем функцию doIndex(), если пароли не совпадают ставим ошибку, если есть ошибки вызываем функцию doIndex(), если все в порядке ставим сессию и отправляем на members.php, иначе опять вызываем функцию doIndex()
4. Функция doIndex() выводит html код, ошибки и форму для авторизации.

logout.php

<?php
include_once("config.php");
checkLoggedIn("yes");
flushMemberSession();
header("Location: login.php");
?>

Тут все просто:
1. Подключаем конфиг
2. Проверяем авторизован ли пользователь
3. Уничтожаем сессию
4. Отправляем пользователя на страницу авторизации

members.php

<?php
include_once("config.php");
checkLoggedIn("yes");
print("<b>".$_SESSION["login"]."</b>! Добро пожаловать<br>\n");
print("Ваш пароль: <b>".$_SESSION["password"]."</b><br>\n");
print("<a href=\"logout.php"."\">Выход</a>");
?>

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

Ну вот собственно и все, хотя все довольно просто — пожалуй это самая длинная моя статья в блоге на данный момент. Если что то не понятно — спрашивайте! И если вы нашли ошибки или есть замечания, не молчите 🙂

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

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

Copyright © Programmer Weekdays | Powered by WordPress