Сессии (sessions), Кукисы (cookies) и авторизация в PHP

Логотип PHPВ сети можно найти много информации на эту тему, конкретно в этой заметке краткое изложение теории в виде комментариев в коде и простой пример.

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

Примером в данном случае будет php-скрипт авторизации представляющий собой одновременно и форму для логина и скрытую информацию.
Пользователь владеющий логином и паролем может авторизоваться и просмотреть скрытые данные, при этом параметры определяющие какую информацию (пусть это будут какие-то «заказы») показывать будут для примера браться из переменных сессии, куда они будут заблаговременно записаны.

<?php
 
session_start(); // стартуем сессию, PHP записывает в нее данные находя их по загруженным кукам если они уже есть
 
if (isset($_GET['logout'])) // блок обрабатывающий завершение сессии
{
	if (isset($_SESSION['user_id']))
	unset($_SESSION['user_id']);
 
	setcookie('login', '', 0, "/");
	setcookie('password', '', 0, "/");
	header('Location: .'); // перезагружаем файл
	exit;
}
 
if (isset($_SESSION['user_id'])) // если юзер залогинился показываем ему нужные данные
{
	$user_id = $_SESSION['user_id']; // запоминаем id юзера из переменных сессии
	$user_name = $_SESSION['user_name']; // запоминаем имя юзера из переменных сессии
 
	$conn = mysql_connect('localhost2','root2','password2')  or die (mysql_error()); // соединение с сервером БД с данными
	$db = mysql_select_db('ordersdb', $conn);
 
	$sql = "select o.`id`, o.`date`, p.`desc`" // фейковый запрос для примера
	." from `orders` AS o, `products` AS p"
	." where o.`product_id` = p.`id`"
	." and o.`user_id` = '$user_id'" // используем $user_id в запросе
	." order by t.`id`";
 
	$result = mysql_query($sql,$conn);
 
	echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
	<html>'.
	"\n\t".'<head>'.
	"\n\t".'<meta http-equiv="Content-Type" content="text/html; charset=windows-1251" />'.
	"\n\t".'<title>Заказы '.$user_name.'</title>'.
	"\n\t".'<style>'.
	"\n\t".'body {font-family:arial;font-size:14px;}'.
	"\n\t".'</style>'.
	"\n\t".'</head>'.
	"\n\t".'<body>'.
	"\n\t".'<h2>Заказы '.$user_name.'</h2>
	<tr>
		<th><b>Номер</b></th>
		<th><b>Дата</b></th>
		<th><b>Товар</b></th>
	</tr>'; 
 
	while($row = mysql_fetch_row ($result)){
		echo '
	<tr>'.
	"\n\t".'<td>'.$row[0].'</td>'.
	"\n\t".'<td>'.$row[1].'</td>'.
	"\n\t".'<td>'.$row[2].'</td>
	</tr>';
	}
	echo "\n".'</table>'."\n".'<br>'."\n"
	.'<a href="?logout">Выход</a>'."\n".'<br><br>'."\n"
	"\n".'</body>'.
	"\n".'</html>';
}
 
if (!empty($_POST) && !isset($_SESSION['user_id']))
{
	// производим авторизацию если было обращение к файлу, а сессии еще не существует
	// коннект к базе с юзерами
	mysql_connect("localhost1", "root1", "password1") or die (mysql_error());
	mysql_select_db("authdb") or die (mysql_error());
 
	mysql_query("set character_set_client  ='cp1251'");
	mysql_query("set character_set_results ='cp1251'");
	mysql_query("set collation_connection  ='cp1251_general_ci'");
 
	// очищение суперглобальных массивов от слешей
	function slashes(&$el)
	{
		if (is_array($el))
		foreach($el as $k=>$v)
		slashes($el[$k]);
		else $el = stripslashes($el);
	}
 
	if (ini_get('magic_quotes_gpc'))
	{
		slashes($_GET);
		slashes($_POST);
		slashes($_COOKIE);
	}
 
	$login = (isset($_POST['login'])) ? mysql_real_escape_string($_POST['login']) : '';
 
	$query = "SELECT `salt`
				FROM `users`
				WHERE `login`='{$login}'
				LIMIT 1";
	$sql = mysql_query($query) or die(mysql_error());
 
	if (mysql_num_rows($sql) == 1)
	{
		$row = mysql_fetch_assoc($sql);
 
		// соль, соответствующая этому логину:
		$salt = $row['salt'];
 
		// теперь хешируем введенный пароль (тем же способом что при регистрации)
		$password = md5(md5($_POST['password']) . $salt);
 
		// делаем запрос к БД - ищем юзера с таким логином и паролем
 
		$query = "SELECT `id`, `name`
					FROM `users`
					WHERE `login`='{$login}' AND `password`='{$password}'
					LIMIT 1";
		$sql = mysql_query($query) or die(mysql_error());
 
		// если такой пользователь нашелся
		if (mysql_num_rows($sql) == 1)
		{
			// то записываем в сессию id и name юзера, которыми воспользуемся позднее
 
			$row = mysql_fetch_assoc($sql);
			$_SESSION['user_id'] = $row['id'];
			$_SESSION['user_name'] = $row['name'];
 
			// если пользователь решил "запомнить себя"
			// то записываем ему в куку логин с хешем пароля на 24 часа
 
			$time = 86400;
 
			if (isset($_POST['remember']))
			{
				setcookie('login', $login, time()+$time, "/");
				setcookie('password', $password, time()+$time, "/");
			}
 
			//и перезагружаем скрипт
			header('Location: .');
			exit;
 
			// если вам понядобится использовании данных сесси на других страницах используйте в их начале session_start();
		}
		else
		{
			die('Такой логин с паролем не найдены в базе данных — <a href="">Авторизоваться</a>');
		}
	}
	else
	{
		die('Пользователь с таким логином не найден — <a href="">Авторизоваться</a>');
	}
}
if (!isset($_SESSION['user_id'])) { // если сесси нет показваем форму авторизации
	print '
	<form action="index.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>Запомнить:</td>
				<td><input type="checkbox" name="remember" /></td>
			</tr>
			<tr>
				<td></td>
				<td><input type="submit" value="Авторизоваться" /></td>
			</tr>
		</table>
	</form>
	';
}
?>

Скрипт регистрации, дамп базы данных юзеров и остальные использованные скрипты можно взять из материала послужившего основой для приведенного выше примера (http://pyha.ru/articles/php/auth/), а именно тут.

Как осуществить авторизацию при отключенных куках?

Приведу цитату из лучшей статьи в рунете на тему сессий в PHP:

Если вы хотите поддерживать работу сайта с отключенными куками но не хотите, чтобы ПХП автоматически заменял ссылки и формы, либо если ПХП на какой-то конкретной ссылке/форме глючит и не вставляет идентификатор, проделывайте это вручную. Это очень просто. Для начала отпределим новую константу SIDFORM (после session_start()):

define ("SIDFORM","<input type=hidden name=".session_name()." value=".session_id().">");

Представим, что у нас есть ссылки и формы (еще бывают фреймы и теги типа AREA, но там делают аналогично). С помощью двух констант SID — определена в ПХП и SIDFORM — придумали сами себе, переработаем текст:

------------------БЫЛО (ПХП-файл)------------------
<html><body>
Ссылка: <a href=test.php?a=1>click here</a> ...
Форма:  <form action=test.php>  
        ... 
        </form>
------------------МЫ ЗАМЕНЯЕМ НА (новая версия ПХП-файла)------------------
<html><body>
Ссылка: <a href=test.php?a=1&<?=SID?>>click here</a> ....
Форма:  <form action=test.php>
        <?=SIDFORM?>  
        ...
        </form>
------------------РЕЗУЛЬТАТ ВЫПОЛНЕНИЯ (это получит браузер)------------------
<html><body>
Ссылка: <a href=test.php?a=1&PHPSESSID=ac4f4a45bdc893434c95dcaffb1c1811>click here</a> ....
Форма:  <form action=test.php>
        <input type="text" name="PHPSESSID" value="ac4f4a45bdc893434c95dcaffb1c1811">
        ... 
        </form>

Тоже самое будет и в ПХП-варианте: echo «<a href=test.php?e=2>click here»; надо заменить на echo «<a href=test.php?e=2&».SID.»<click here</a<»;
Обратите внимание, что SID — это константа. И если вы хотите иметь переменную $SID, то просто напишите в начале программы $SID=SID; (после старта сессий).

Итак, подведем итог автозамене. Если вы не хотите вставлять идентификаторы — полагайтесь на ПХП, который постарается все ссылки заменить. Если вы хотите 100% надежность того, что все смогут использовать ваш сайт и ни один пользователь ни на одной старнице случайно не потеряет сессию, то прибавляйте к каждой форме и ссылке по небольшой константе (их можно названить очень коротко, типа «X» и «Y»).

Если вы нашли в моем примере неточность или даже откровенную чушь :) (а также просто что-то интересное) напишите, пожалуйста, в комментах.

Комментариев: 2

  • 11.02.2012 seogar:

    .'<a href="?logout" rel="nofollow">Выход</a>'."\n".''."\n" "\n".''.

    забыл поставить .

    .'<a href="?logout" rel="nofollow">Выход</a>'."\n".''."\n". "\n".''.

  • 30.05.2012 Сергей:

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


Добавление комментария:

 css.php