Что такое сессия?
В компьютерной технике, в частности при организации сетей, сессией называется почти неизменный интерактивный обмен информацией, также известный под термином соединение или диалог между двумя взаимодействующими устройствами или между пользователем и компьютером (см. тему Процедура идентификации). Сессия устанавливается в определенное время и прерывается через определенный промежуток. Во время установленной сессии в каждом направлении передается более одного сообщения. Обычно сессия является стабильной, то есть, хотя бы одна из взаимодействующих сторон должна хранить информацию о сессионной истории, чтобы сохранить возможность обмена информацией в отличие от обмена без запоминания состояния, суть которого состоит в обмене независимыми запросами и ответами.
Сессии соединения могут быть в часть протоколов или сервисов на уровне приложений, сеансовом или транспортном уровнях модели OSI .
В маршрутизаторе используется таблица сессий для сохранения информации о них. Таблица занимает часть памяти и ресурсов центрального процессора для таких функций, как, например, подсчет сессий. Размер сессии в таблице является фиксированным; если она переполняется, маршрутизатор не в состоянии передавать информацию даже при наличии выходного потока данных.
Попробуем объяснить назначение сессии на следующих примерах.
1. Когда вы открываете web-сайт, например, www.. Все произойдет буквально за минуту, поэтому вам не нужно беспокоиться о скорости вашего Интернет-соединения. Но почему же тогда необходимо так много сессий? На сайте размещена различная информация - много рисунков, видео. Для того, чтобы открыть страницу в браузере, нужно загрузить их во временную папку на вашем компьютере.
2. Когда мы выполняем загрузку через BT , это требует большого количества сессий. На время инициализации необходимо примерно 2000 сессий, однако их число уменьшится при стабильной загрузке. В списке сессий, приведенном ниже, показано количество текущих сессий при соответствующей скорости входящих и исходящих загрузок через BT .
Также происходит и при использовании другого программного обеспечения P2P , поскольку они работают по схожей схеме.
Учтите, что нет четкой связи между скоростью и количеством сессий. При наличии большого количества сессий скорость не всегда будет высокой, так же, как и наличие высокой скорости не означает наличия большого числа сессий. Но, в основном, когда сессий много, скорость больше.
Для чего устанавливать лимит сессий?
1) Это позволяет избежать замедлений в работе сети, поскольку программное обеспечение P2P ограничено в количестве сессий.
2) Это позволяет избежать поглощения ресурсов сети каким либо вирусом или другим видом сетевых атак, которым требуется большое количество сессий.
Как настроить ограничение сессий на маршрутизаторе TP - LINK ?
Шаг 1
Откройте браузер и введите в адресную строку сетевой IP адрес маршрутизатора; по умолчанию это 192.168.1.1, затем нажмите Enter (Ввод).
Шаг 2
Введите имя пользователя и пароль для входа в web-интерфейс; по умолчанию и логин, и пароль admin .
Шаг 3
Нажмите Session Limit (Лимит сессий) -> Session Limit (Лимит сессий) в левой части страницы, активируйте функцию Session Limit (Лимит сессий), затем нажмите кнопку Save (Сохранить) для сохранения настроек.
Шаг 4
Нажмите Add New (Добавить), чтобы настроить правило ограничения сессий, введите сетевой IP адрес компьютера, для которого вы хотите установить ограничение, и установите максимальное количество сессий (Max Session).
Примечание
Max Session - это индивидуальный лимит для конкретного компьютера, даже если вы ввели массив сетевых адресов.
Так как HTTP - это клиент-серверный протокол, HTTP сессия состоит из трёх фаз:
- Клиент устанавливает TCP соединения (или другое соединение, если не используется TCP транспорт).
- Клиент отправляет запрос и ждёт ответа.
- Сервер обрабатывает запрос и посылает ответ, в котором содержится код статуса и соответствующие данные.
Начиная с версии HTTP/1.1, после третьей фазы соединение не закрывается, так как клиенту позволяется инициировать другой запрос. То есть, вторая и третья фазы могут повторяться.
Установка соединения
Так как HTTP это клиент-серверный протокол, соединение всегда устанавливается клиентом. Открыть соединение в HTTP - значит установить соединение через соответствующий транспорт, обычно TCP.
В случае с TCP, в качестве порта HTTP сервера по умолчанию на компьютере используется порт 80, хотя другие также часто используются, например 8000 или 8080. URL загружаемой страницы содержит доменное имя и порт, который можно и не указывать если он соответствует порту по умолчанию.
Имеем в виду: Клиент-серверная модель не позволяет серверу посылать данные клиенту без явного запроса этих данных. Чтобы обойти эту проблему, веб разработчики используют различные техники: периодически пингуют сервер используя XMLHTTPRequest Javascript объект, HTML WebSockets API , или похожие протоколы.
Отправка запроса клиента
Когда соединение установлено user-agent может послать запрос. (user-agent это обычно веб браузер, но может им не быть) Клиентский запрос это текстовые директивы, разделенные между собой при помощи CRLF (переноса строки). Сам запрос включает в себя три блока:
- Первые строки содержат метод запроса и его параметры:
- путь к документу - абсолютная URL без указания протокола и доменного имени
- версию HTTP протокола
- Каждая последующая строка представляет собой HTTP заголовок и передает серверу некоторую информацию о типах предпочитаемых данных (наприм. какой язык, какие MIME типы) или инструкции меняющие поведение сервера (наприм. не отправлять ответ, если он уже в кэше) . Эти HTTP заголовки формируют блок, который заканчивается пустой строкой.
- Последний блок является не обязательным и содержит дополнительные данные. По большей части используется методом POST.
Примеры запросов
Получаем главную страницу сайт, и говорим серверу, что user-agent предпочитает страницу на французском, если это возможно:
GET / HTTP/1.1 Host: сайт Accept-Language: fr
Обращаем внимание на пустую строку в конце, которая отделяет блок данных от блока заголовков. Так как в запросе отсутствует Content-Length: HTTP заголовок, блок с данными пуст и сервер может начать обработку запроса, как только получит пустую строку, означающую конец заголовков.
Отправляем результат сабмита формы:
POST /contact_form.php HTTP/1.1 Host: сайт Content-Length: 64 Content-Type: application/x-www-form-urlencoded name=Joe%20User&request=Send%20me%20one%20of%20your%20catalogue
Методы запроса
HTTP определяет набор методов запроса с указанием желаемого действие на ресурсе. Хотя они также могут быть и существительными, эти запросы методы иногда называют HTTP-командами. Наиболее распространенные запросы GET и POST:
- GET используется для запроса содержимого указанного ресурса. Запрос с использованием GET должен только получать данные.
- POST метод отправляет данные на сервер, так что он может изменять свое состояние. Этот метод часто используется для HTML форм .
Структура ответа от сервера
После того как присоединенный агент отправил свой запрос, веб сервер обрабатывает его и отправляет ответ. По аналогии с клиентским запросом, ответ сервера - это текстовые директивы разделенные между собой CRLF, сгруппированные в три разных блока:
- Первая строка - строка статуса, состоит из подтверждения используемой HTTP версии и статуса запроса (и его значения в виде, понятном человеку).
- Последующие строки представляют собой HTTP заголовки, дающие клиенту некоторую информацию о посылаемых данных (прим. тип, размер, алгоритм сжатия, подсказки по кэшированию). Так же как и в случае клиентского запроса, эти HTTP заголовки формируют блок, заканчивающийся пустой строкой.
- Последний блок содержит данные (если таковые имеются).
Примеры ответов
Успешное получение веб страницы:
HTTP/1.1 200 OK Date: Sat, 09 Oct 2010 14:28:02 GMT Server: Apache Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT ETag: "51142bc1-7449-479b075b2891b" Accept-Ranges: bytes Content-Length: 29769 Content-Type: text/html (здесь идут 29769 байтов запрошенной веб-страницы)
Сообщение о том, что запрашиваемый ресурс был перемещен:
HTTP/1.1 301 Moved Permanently Server: Apache/2.2.3 (Red Hat) Content-Type: text/html; charset=iso-8859-1 Date: Sat, 09 Oct 2010 14:30:24 GMT Location: (это новый адрес запрошенного ресурса, ожидается, что клиент запросит его ) Keep-Alive: timeout=15, max=98 Accept-Ranges: bytes Via: Moz-Cache-zlb05 Connection: Keep-Alive X-Cache-Info: caching X-Cache-Info: caching Content-Length: 325 (Контент содержит стандартную страницу, которая будет показана, если клиент не может перейти по ссылке)
Moved Permanently
The document has moved here.
Apache/2.2.3 (Red Hat) Server at сайт Port 80
Сообщение о том, что запрашиваемый ресурс не существует:
Сессия (от лат. – sessio - заседание, англ. – session) – это промежуток времени, охватывающий работу пользователя в интернете с момента открытия первой и до последней ссылок. Рассчитывается как разница во времени между начальным и финальным запросами. Однако последняя страница может просматриваться пользователем различное время, из чего, следовательно, измерение времени между двумя запросами становится более затруднительным.
Как связана сессия с протоколом HTTP и COOKIES
Что такое сессия можно объяснить, отталкиваясь от протокола HTTP. Сам по себе, этот протокол не располагает способом сохранения состояния между двумя операциями. Т.е., проще говоря, открывая одну страничку, а затем, перейдя с неё на другую, HTTP не сможет установить, что оба запроса принадлежат одному пользователю. И тут на помощь приходит особый метод отслеживания – управление сеансами (нашими сессиями).
Отсюда, отвечая на вопрос, что такое сессия, можно сказать, что это – вспомогательный логический объект, способствующий передачи данных между последовательными HTTP – запросами от одного юзера.
Cookies, как и сессия, хранят сведения о пользователе во время его перемещения по разным страницам и улучшают работу протокола. Но в отличие от второй, где данные хранятся во временных файлах на сервере, они сохраняют их на компьютере пользователя в виде небольших фрагментов.
Для чего нужны сессии
Использование сессий становится незаменимым при работе с такими сайтами, как форумы, доски объявлений и Интернет – магазины, ведь в этом случае нужно сохранять данные о юзере на протяжении нескольких страниц.
Этапы сессии
Всю сессию можно разделить на три этапа:
- открытие сессии (когда пользователь начинает работу с определенным сайтом),
- учет переменных сессии (при переходе на различные страницы),
- завершение сессии.
Из-за того, что данные сессии сохраняются на стороннем сервере, то лучше всего не держать большие объемы информации в них, а использовать cookies.
Веб-сервер не поддерживает постоянного соединения с клиентом, и каждый запрос обрабатывается, как новый, безо всякой связи с предыдущими.
То есть, нельзя ни отследить запросы от одного и того же посетителя, ни сохранить для него переменные между просмотрами отдельных страниц. Вот для решения этих двух задач и были изобретены сессии.
Собственно, сессии, если в двух словах - это механизм, позволяющий однозначно идентифицировать браузер и создающий для этого браузера файл на сервере, в котором хранятся переменные сеанса.
Подробно расписывать нужду в таком механизме я не буду. Это такие хрестоматийнык случаи, как корзина покупок в е-магазине, авторизация, а так же, и не совсем тривиальные проблемы, такие, например, как защита интерактивных частей сайта от спама.
В принципе, довольно несложно сделать собственный аналог сессий, не такой функциональный, как встроенный в PHP, но похожий по сути. На куках и базе данных.
При запросе скрипта смотрим, пришла ли кука с определенным именем. Если куки нет, то ставим ее и записываем в базу новую строку с данными пользователя. Если кука есть, то читаем из базы данные. Еще одним запросом удаляем из базы старые записи и вот у нас готов механизм сессий. Совсем несложно. Но есть некоторые нюансы, которые делают предпочтительным использование именно встроенного механизма сессий.
Если включена только первая, то при старте сессии (при каждом вызове session_start() ) клиенту устанавливается кука. Браузер исправно при каждом следующем запросе эту куку возвращает и PHP имеет идентификатор сессии. Проблемы начинаются, если браузер куки не возвращает. В этом случае, не получая куки с идентификатором, PHP будет все время стартовать новую сессию, и механизм работать не будет.
Если включена только вторая, то кука не выставляется. А происходит то, ради чего, в основном, собственно, и стоит использовать встроенный механизм сессий. После того, как скрипт выполняет свою работу, и страница полностью сформирована, PHP просматривает ее всю и дописывает к каждой ссылке и к каждой форме передачу идентификатора сессии. Это выглядит примерно так:
Index
превращается в
Index
а к формам добавляется скрытое поле
И браузер при клике на любую ссылку, или при нажатии на кнопку в форме, пошлет в запросе нужную нам переменную - идентификатор сессии!
По очевидным причинам идентификатор добавляется только к относительным ссылкам.
Теоретически, в наших с вами самодельных сессиях на куках и базе, можно самому, руками приписать ко всем ссылками передачу ид - и тогда наши собственные сессии будут работать независимо от кук. Но, согласитесь - приятнее, когда эту работу делает кто-то другой? ;-)
По умолчанию в последних версиях PHP включены обе опции. Как PHP поступает в этом случае? Кука выставляется всегда. А ссылки автодополняются только если РНР не обнаружил куку с идентификатором сессии. Когда пользователь в првый раз за этот сеанс заходит на сайт, ему ставится кука, и дополняются ссылки. При следующем запросе, если куки поддерживаются, PHP видит куку и перестает дополнять ссылки. Если куки не работают, то PHP продолжает исправно добавлять ид к ссылкам, и сессия не теряется.
Пользователи, у которых работают куки, увидят длинную ссылку с ид только один раз.
Фух. С передачей идентификатора закончили.
Теперь осталось привязать к нему файл с данными на стороне сервера.
PHP это сделает за нас. Достаточно просто написать
session_start();
$_SESSION["test"]="Hello world!";
И PHP запишет в файл, связанный с этой сессией, переменную test.
Здесь очень важное замечание.
Массив $_SESSION
- особенный.
В нем, собственно, и находятся переменные, которые мы ходим сделать доступными в различных скриптах.
Чтобы поместить переменную в сессию, достаточно присвоить ее элементу массива $_SESSION.
Чтобы получить ее значение - достаточно обратиться к тому же элементу. Пример будет чуть ниже.
Cборкой мусора - удалением устаревших файлов PHP тоже занимается сам. Как и кодированием данных и кучей всяких других нужных вещей. В результате этой заботы работа с сессиями оказывается очень простой.
Вот мы, собственно, и подошли к примеру работы сессий.
Пример очень маленький:
session_start();
echo "Вы обновили эту страницу ".$_SESSION["counter"]++." раз. ";
echo "
обновить";
?>
Мы проверяем, есть ли у нас в сессии переменная counter, если нет, то создаем ее со значением 0, а дальше выводим ее значение и увеличиваем на единицу. Увеличенное значение запишется в сессию, и при следующем вызове скрипта переменная будет иметь значение 1, и так далее.
Все очень просто.
Для того, чтобы иметь доступ к переменным сессии на любых страницах сайта, надо написать ТОЛЬКО ОДНУ(!) строчку в самом начале КАЖДОГО файла, в котором нам нужны сессии:
session_start();
И далее обращаться к элементам массива $_SESSION. Например, проверка авторизации будет выглядеть примерно так:
session_start();
if ($_SESSION["authorized"]<>1) {
header("Location: /auth.php");
exit;
}
Удаление переменных из сессии.
Если у вас register_globals=off
, то достаточно написать
unset($_SESSION["var"]);
Если же нет, то тогда рядом
с ней надо написать
session_unregister("var");
Самыми распространенными ошибками, которые выдает РНР при попытке работать с сессиями, являются такие:
Две из них,
Warning: Cannot send session cookie - headers already sent
Warning: Cannot send session cache limiter - headers already sent
вызваны одной и той же причиной, решение описано в этом факе
Третья,
Warning: open(/tmp\sess_SID, O_RDWR) failed: No such file or directory (2) in full_script_path on line number
(ранее она выглядела, как Warning: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/tmp)
),
если перевести ее с английского, подробно объясняет проблему: недоступен указанный в php.ini путь к каталогу, в который пишутся файлы сессий. Эту ошибку исправить проще всего. Просто прописать каталог, который существует, и доступен на запись, например,
session.save_path = c:\windows\temp
И не забыть перезагрузить апач после этого.
Как выясняется, сообразительность людская не имеет пределов, и поэтому я вынужден пояснить:
сообщение о третьей ошибке (невозможно найти каталог) НЕИЗБЕЖНО приведет к появлению первых двух, поскольку сообщение об ошибке - это вывод в браузер и после него заголовками пользоваться нельзя. Поэтому не спешите искать преждевременный вывод, а сначала пропишите правильный путь!
Следующей по распространенности проблемой при работе с сессиями является тяжелое наследие register_globals. НЕ давайте переменным скрипта имена, совпадающие с индексами массива $_SESSION!
При register_globals=on значения будут перезаписывать друг друга, и вы запутаетесь.
А при register_globals=off появится другая ошибка: "Your script possibly relies on a session side-effect which existed until PHP 4.2.3.", в случае, если в скрипте есть переменная сессии не имеющая значения, и глобальная переменная с тем же именем. Чтобы от неё избавиться, надо всегда инициализировать переменные перед использованием (или хотя бы проверять на существование) и не давать глобальным переменным имена, совпадающие с индексами массива $_SESSION.
Если не работает, но и никаких сообщений не выводится, то добавьте в самое начало скрипта две строчки, отвечающие за вывод ВСЕХ ошибок на экран - вполне возможно, что ошибки есть, но вы их просто не видите.
ini_set("display_errors",1);
error_reporting(E_ALL);
или смотрите ошибки в error_log. Вообще, тема отображения сообщений об ошибках выходит за рамки данной статьи, поэтому просто убедитесь хотя бы, что вы можете их видеть. Чуть продробнее о поиске ошибок можно прочитать в этом разделе .
Если вы уверены, что ошибок нет, но приведенный пример не работает все равно, то, возможно, в PHP не включена передача ид через урл, а куки по каким-то причинам не работают
.
Смотрите, что у вас с куками.
Вообще, если у вас "не работают" сессии, то сначала попробуйте передать идентификатор сессии руками, то есть, сделать ссылку и приписать к ней идентификатор:
session_start();
if (!isset($_SESSION["counter"])) $_SESSION["counter"]=0;
echo "Вы обновили эту страницу ".$_SESSION["counter"]++." раз.
обновить";
?>
При этом следует убедиться, что не включена директива session.use_only_cookies
, которая запрещает PHP принимать идентификатор сессии, если он был передан через URL
Если этот пример не заработает, то проблема либо в банальных опечатках
(половина "проблем" с сессиями происходит от неправильно написанного имени переменной), либо в слишком старой версии PHP: поддержка сессий появилась в версии 4.0, а массив $_SESSION
- в 4.1 (До этого использовался $HTTP_SESSION_VARS
).
Если же заработает - то проблема в куках. Отслеживайте - что за куку ставит сервер браузеру, возвращает ли браузер ее. Искать очень полезно, просматривая просматривая обмен HTTP-заголовками между браузером и сервером.
Объяснение принципа работы кук выходит за рамки этого и так уж слишком большого текста, но хотя бы убедитесь, что сервер куку с идентификатором посылает, а браузер - возвращает. И при этом идентификаторы совпадают друг с другом =)
Установка куки должна выглядеть, как
Set-Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6;
или как
Set-Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6; path=/
(если вы запрашиваете скрипт не из корневого каталога)
Ответ сервера должен выглядеть, как
Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6
либо
Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6; b=b
если браузер возвращает другие куки, кроме идентификатора сессии.
Если браузер куки не возвращает - проверьте, работают ли куки вообще.
Убедитесь, что домен, к которому вы обращаетесь, имеет нормальное имя (в котором есть хотя бы одна точка и не содержится запрещенных символов, например подчеркивания) и почистите кэш браузера - это две основные причины, по которм куки могут не работать.
Если пример отсюда работает, а ваш собственный код - нет, то проблема, очевидно, не в сессиях, а в алгоритме. Ищите, где потеряли переменную, по шагам переносите пример отсюда, отлаживайте свой скрипт.
Еще одна проблема может возникнуть, если вы используете перенаправление через header или навигацию с помощью JavaScript.
Дело в том, что РНР автоматически дописывает идентификатор сессии только к ссылкам вида
, но не делает этого для header-ов, яваскрипта, мета-тегов.
Поэтому надо добавлять идентификатор руками, например, так:
header("Location: /script.php?".session_name()."=".session_id());
Так же, весьма редкая, и совершенно непонятно, откуда появляющаяся, проблема бывает в том, что настройка session.save_handler имеет значение, отличное от files. Если это не так - исправляйте.
Безопасность
Безопасность сессий - тема обширная. Поэтому остановлюсь на нескольких основных моментах.
Самый хрестоматийный - не передавать идентификатор через адресную строку. Об этом написано даже в php.ini, но это ограничивает функциональность сессий. Если вы решите последовать этому совету, то кроме session.use_trans_sid = 0 не забудьте session.use_only_cookies = 1
Желательно привязывать сессию к IP адресу: таким образом, если идентификатор будет украден, то злодей все равно не сможет им воспользоваться в большинстве случаев.
Рекомендуется пользоваться директивой session.save_path, с помощью которой задать собственный каталог для сохранения файлов сессий. Это более безопасно, чем когда они хранятся в общем временном каталоге сервера по умолчанию.
session_cache_limiter("private");
перед стартом сессии должен решить проблему.
Пример авторизации с помощью сессий
Проиллюстрируем все вышенаписанное небольшим примером:
создадим файл auth.php:
if (isset($_POST
[
"auth_name"
]))
{
$sql
=
"SELECT * FROM users WHERE name=?s"
;
$row
=
$db
->
getRow
($sql
,
$_POST
[
"auth_name"
]);
if ($row
&&
password_verify
($_POST
[
"auth_pass"
],
$row
[
"pass"
])) {
$_SESSION
[
"user_id"
] =
$row
[
"id"
];
}
header
("Location: http://"
.
$_SERVER
[
"HTTP_HOST"
].
$_SERVER
[
"REQUEST_URI"
]);
exit;
}
if (isset($_GET
[
"action"
]) AND
$_GET
[
"action"
]==
"logout"
) {
session_start
();
session_destroy
();
header
("Location: http://"
.
$_SERVER
[
"HTTP_HOST"
].
"/"
);
exit;
}
if (!isset($_SESSION
[
"user_id"
])) {
?>
exit;
}
Теперь достаточно написать во всех защищаемых скриптах строчку
require "auth.php";
В данном примере предполагается, что сессия уже стартовала и соединение с БД создано, с использованием Класс для безопасной и удобной работы с MySQL . Также предполагается, что пароль хэширован с использованием рекомендованной функции password_hash
.
Пример защищаемого файла:
session_start
();
include
"safemysql.class.php"
;
$db
= new
safemysql
([
"db"
=>
"test"
]);
include
"auth.php"
;
?>
secret
logout
ОПС! Очень Полезные Ссылки:
http://www.php.net/manual/ru/ref.session.php - самая последняя и свежая информация о поддержке сессий в PHP в официальной документации, плюс многочисленные комментарии пользователей. Настоятельно рекомендуется к прочтению.
http://phpclub.ru/manrus/f/ref.session.html - ВЕСЬМА устаревший перевод этой главы на русский, из документации в переводе Александра Пирамидина.
http://phpclub.ru/detail/article/sessions
Статья с пафосным названием "Правда о сессиях". Двойственное впечатление оставляет. Вначале автор ОЧЕНЬ доступно рассказывает о механизме сессий, но методы, которые он предлагает к концу статьи - совершенно мутные.
Хрестоматийная статья Дмитрия Бородина с сайта
http://php.spb.ru/ настоятельно НЕ рекомендуется.
Ребята, она страшно устарела. Мало того, что в ней есть фактические неточности, так с сессиями в PHP уже давно просто не работают.
Огромное Диме спасибо за нее, это была первая статья по сессиям на русском языке, я сам по ней учился, но сейчас надо ее отправить на заслуженный отдых.
Так же, устарели к сожалению, и многие другие статьи, лежащие в интернете и не обновлявшиеся годами.