Немного о компьютере

Защита идентификатора сессий в PHP. Сессии в PHP Сессия в php

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

Подробно расписывать нужду в таком механизме я не буду. Это такие хрестоматийнык случаи, как корзина покупок в е-магазине, авторизация, а так же, и не совсем тривиальные проблемы, такие, например, как защита интерактивных частей сайта от спама.

В принципе, довольно несложно сделать собственный аналог сессий, не такой функциональный, как встроенный в 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, с помощью которой задать собственный каталог для сохранения файлов сессий. Это более безопасно, чем когда они хранятся в общем временном каталоге сервера по умолчанию.

Дополнительная информация:

  • Кроме кук, механизм сессий посылает еще и заголовки, запрещающие кэширование страниц (тот самый cache limiter). Для html это правильно и необходимо. Но вот когда вы пытаетесь скриптом, проверяющим авторизацию, отдать файл, то интернет эксплорер отказывается его скачивать. Именно из-за этого заголовка. Вызов
    session_cache_limiter ("private" );
    перед стартом сессии должен решить проблему.
  • Как это ни кажется странным, но в массиве $_SESSION нельзя использовать числовые индексы - $_SESSION [ 1 ], $_SESSION [ "10" ] - cессии работать не будут.
  • Где-то между версиями 4.2 и 5.0 невозможно было установить session.use_trans_sid с помощью ini_set () . Начиная с 5.0 уже можно снова.
  • До версии 4.3.3 куку PHP отправлял куку только если при старте сессии в запросе отсутстввал идентификатор. Теперь же кука посылается при каждом вызове session_start ()

    Пример авторизации с помощью сессий
    Проиллюстрируем все вышенаписанное небольшим примером:
    создадим файл 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 уже давно просто не работают.
    Огромное Диме спасибо за нее, это была первая статья по сессиям на русском языке, я сам по ней учился, но сейчас надо ее отправить на заслуженный отдых.
    Так же, устарели к сожалению, и многие другие статьи, лежащие в интернете и не обновлявшиеся годами.

  • Сессии в PHP или как данные о зашедшем на сайт пользователе или покупателе сохраняются при переходе между страницами сайта без особого труда. Урок очень важный. Актуален для создания 95% сайтов.

    Что такое сессия в php

    Сессии используются для хранения сведений временных данных (например, о том, что пользователь зашёл на сайт) при переходах между страницами одного сайта. При использовании сессий данные сохраняются во временных файлах на сервере.
    Чаще всего сессиями (и куками впрочем тоже) пользуются при создании Интернет-магазинов, форумов, досок объявлений, социальных сетях, блогах и других ресурсах. Удобство системы сессий заключается хранении временной информации зашедшего пользователя/покупателя, данные о котором находятся в быстром доступе определённое время. У сессии существует естесственный срок годности - до закрытия браузера. Если закрыть только страницу, то при открытии сайта данные о пользхователе/покупателе всё равно будут доступны.

    Логика работы сессии

    Session (или сессия) это некое временное хранилище данных. Сразу предупреждаю, сохранять стоит небольшой объём данных. Например, логин и пароль заходящего пользователя или его порядковый номер в базе данных.

    Пример работы
    1. Пользователь вводит логин и пароль и заходит на сайт
    2. Данные с логином и паролем сохраняются в сессии одной из страниц сайта:

    Файл index.php

    Session_start(); // каждый файл, в котором Вы хотите использовать данные сессий должен в начале кода содержать команду "запуска сессии"

    $login = "admin";
    $password = "pass";
    $_SESSION["login"] = $login; // сохраняем переменную содержащую логин
    $_SESSION["password"] = $password; // сохраняем переменную содержащую пароль

    3. При переходе на другую страницу сайта эти данные также будут доступны:

    Файл example.php (или любая другая страница)

    Echo "Ваш логин ".$_SESSION["login"]; // выведет "Ваш логин admin", хотя на этой странице мы не записывали данных!
    Видите, все просто!

    4. Если хотите очистить данные сессии, то достаточно:

    Файл example.php

    Session_start(); // снова "запускаем сессиию"

    Unset($_SESSION["login"]); // так разрегистрировали переменную или "уничтожили"
    echo "Ваш логин ".$_SESSION["login"]; // выведет "Ваш логин " . Так как мы её уничтожили в прошлой строке, то и данных нет

    Session_destroy(); // разрушаем сессию. Всех данных, включая $_SESSION["password"] уже нет. При их запросе будет выводить ошибка
    В целом подобная передача похожа на метод POST, но только Вы уже не должны писать много лишнего кода, а все данные, передаваемые от страницы к странице, хранятся во временных файлах на сервере. Повторюсь, сессии должны содержать небольшие объёмы данных, поэтому они подходят под хранение логина/пароля, корзины покупателя и других небольших объёмов.

    Передача значения или массива с помощью сессии PHP

    В сессию можно записывать не только строку, но и массив данных. Только не переусердствуйте с объёмом массива, так как всё это повлияет на быстройдействие и занятое пространство на сервере.

    Вновь используем некую стартовую страницу index.php

    Session_start();

    $r = array("one", "two", "three");

    $_SESSION["arr"] = $r;

    На страницу, где все отобразится
    Сохранили данные в сессии и переходим по ссылке на другую страницу, где всё данные и будем выводить.

    Файл получатель, страница test.php где открываем массив

    Session_start();
    print_r($_SESSION["arr"]);
    // выведет
    /*
    Array
    => one
    => two
    => three
    */
    ?>
    Возможно, Вы захотите освежить в памяти урок по . В целом же всё должно быть понятно.

    Другие функции для работы с сессиями

    session_unregister(string) - сессия забывает значение заданной глобальной переменной;
    session_destroy() - сессия уничтожается (например, если пользователь покинул систему, нажав кнопку выход);
    session_set_cookie_params(int lifetime [, string path [, string domain]]) - с помощью этой функции можно установить, как долго будет жить сессия, задав unix_timestamp определяющий время смерти сессии.

    Список функций для работы с сессиями (session) в php
    session_cache_expire - возвращает окончание действия текущего кэша
    session_cache_limiter - получает и/или устанавливает текущий ограничитель кэша
    session_commit - псевдоним session_write_close()
    session_decode - декодирует данные сессии из строки
    session_destroy - уничтожает все данные, зарегистрированные для сессии
    session_encode - шифрует данные текущей сессии как строку
    session_get_cookie_params - получает параметры куки сессии
    session_id - получает и/или устанавливает текущий session id
    session_is_registered - определяет, зарегистрирована ли переменная в сессии
    session_module_name - получает и/или устанавливает модуль текущей сессии
    session_name - получает и/или устанавливает имя текущей сессии
    session_regenerate_id - модифицирует текущий идентификатор сеанса недавно сгенерированным
    session_register - регистрирует одну или более переменных для текущей сессии
    session_save_path - получает и/или устанавливает путь сохранения текущей сессии
    session_set_cookie_params - устанавливает параметры куки сессии
    session_set_save_handler - устанавливает функции хранения сессии уровня пользователя
    session_start - инициализирует данные сессии
    session_unregister - дерегистрирует переменную из текущей сессии
    session_unset - освобождает все переменные сессии
    session_write_close - записывает данные сессии и конец сессии

    Примеры работы сессий

    Счётчик просмотров страницы во время сессии. Наглядно пример работы. Однако после закрытия браузера отсчёт начнётся заново.

    Счётчик посещений одной страницы в рамках одной сессии

    // Простой пример использования сессий без Cookies.
    session_name("test");
    session_start();
    $_SESSION["count"] = @$_SESSION["count"] + 1;
    ?>

    Счетчик


    В текущей сессии работы с браузером Вы открыли эту страницу
    раз(а).
    Закройте браузер, чтобы обнулить этот счетчик.
    Нажмите сюда для обновления страницы!
    При каждом переходе счётчик будет увеличиваться на 1)

    Спасибо за внимание! Удачи в начинаниях!

    Сессии позволяют установить связь между посетителем и сайтом при помощи идентификатора сессии .

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

    Идентификатор сессии, хранящийся на компьютере пользователя, это файл cookie .

    Cookie хранится в браузере пользователя, при этом соответствующий файл создается и на сервере.

    Создаем сессию

    Самый простой способ открытия сессии заключается в использовании функции session_start:

    // инициировать сессию session_start();

    Эта функция проверяет, существует ли идентификатор сессии, и, если нет, то создает его. Если идентификатор текущей сессии уже существует, то загружаются зарегистрированные переменные сессии.

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

    Когда создается сессия в браузер ‛прилетает“ кука следующего вида:

    PHP

    echo "Имя сессии: ".session_name(). " Идентификатор сессии: ".session_id(); // Имя сессии: PHPSESSID Идентификатор сессии: mceu820l02id3ds0vcvtgnht04

    Создаем переменную сессии

    Переменная сессии создается путем добавлением какого-либо значения суперглобальному массиву $_SESSION:

    $_SESSION["nick"] = $_POST["name"];

    Уничтожаем переменные сессии и саму сессию

    1 . Удалить переменную сессии можно следующим образом:

    Unset($_SESSION["nick"]);

    Этим мы предотвратим повторное использование информации.

    Но лучше просто очистить массив $_SESSION (удалить все переменные сессии):

    //очистить массив $_SESSION $_SESSION = array();

    2 . Также необходимо сделать следующее:

    Установить файл cookie сессии недействительным:

    If (isset($_COOKIE)) { // session_name() - получаем название текущей сессии setcookie(session_name(), "", time()-86400, "/"); }

    Имя сессии ссылается на session id в куках и URL

    3 . Уничтожить (завершить) сессиию

    Session_destroy();

    Буферизация вывода

    Если у вас уже есть какой-либо вывод, вы можете воспользоваться фукцией ob_start() . Данная функция делает буферизацию вывода. Теперь вывод не будет отправлен браузеру, пока вы не отправите его принудительно при помощи функции ob_end_flush() .

    "; unset($_SESSION["nick"]); if (isset($_COOKIE)) { setcookie(session_name(), "", time()-86400, "/"); // содержимое сессии - пустая строка } // setcookie сработает безошибочно, так как мы только сейчас ob_end_flush(); // отправили браузеру вывод session_destroy();

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

    Пересоздаем идентификатор сессии

    При каждом входе в систему необходимо, в целях безопасности, пересоздавать идентификатор сессии. Информация в переменных сессии сохраняется, меняется лишь идентификатор сессии . Не забывайте, информация о сессии хранится на веб-сервере в виде текста в соответствующем файле. Чтобы пересоздать идентификатор вызовите session_regenerate_id() и обновите текущую страницу или перенаправьте пользователя на другую страницу.

    Механизм работы сессий


    Уменьшаем время жизни сессии

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

    $_SESSION["start"] = time(); // временная метка авторизации пользователя $now = time(); // текущее время $time_limit = 1000; // максимально допустимое время бездействия пользователя в сек. if ($now > $_SESSION["start"] + $time_limit) { echo "Ваше время истекло"; //....... // и удаляем сессию и ее cookie } else { $_SESSION["start"] = time(); } // если порядок, обновляем

    Как сделать время жизни сессии вечной?

    Для того чтобы клиент оставался всегда залогиненным, не надо делать время жизни сессии вечной. Сессия - на то она и сессия, чтобы начаться, когда клиент пришел, и завершиться, когда клиент ушел.

    Когда клиент пришел вновь - надо начать новую сессию, но загрузить в неё данные о клиенте, основываясь на уникальной для клиента куке, которая надолго устанавливается ему при выборе галочки, например, "запомнить меня".

    Работа с сессией при отключенных куках

    Если для настройки session.use_trans_sid установить 1 , то при отключенных куках PHP будет передавать PHPSESSID методом GET в строке запроса.

    С самого начала PHP все приняли на ура, но как только на этом языке стали создавать достаточно крупные проекты, разработчики столкнулись с новой проблемой - в PHP отсутствовало понятие глобальных переменных! То есть, выполнялся некий скрипт, посылал сгенерированную страницу клиенту, и все ресурсы, используемые этим скриптом уничтожались. Попробую проиллюстрировать: предположим есть две страницы одного сайта, index.php и dothings.php. Исходники к этим страницам выглядят так:

    index.php dothings.php

    Если выполнить эти два скрипта, то на первой странице мы увидим надпись "Меня задали на index.php", а вторая страница будет пустой.

    Разработчики web-сайтов, недолго думая, стали использовать cookie для хранения глобальных переменных на стороне клиента. Процесс выглядел примерно так: пользователь приходит на главную страницу сайта, делает какие-то действия, и вся информация, связанная с этим пользователем, которая может потребоваться на других страницах сайта, будет храниться у него в браузере в виде cookie. Этот метод имеет довольно серьезные минусы, из-за которых от PHP в своё время отвернулось немало разработчиков. Например, нам нужно авторизовать пользователя, чтобы разрешить ему доступ к закрытым (или принадлежащим только ему) разделам сайта. Придется отправлять пользователю cookie, который будет служит его последующим идентификатором на сайте. Такой подход становится очень громоздким и не удобным, как только сайт начинает собирать всё больше и больше сведений о поведении пользователя, ведь всю информацию, посылаемую пользователю, желательно кодировать, чтобы её нельзя было подделать. Ещё совсем недавно подделкой cookie можно было "уложить" не один чат, а порой и пробраться в чужую почту. К тому же есть ещё на свете странные люди, у которых браузер cookie не поддерживает.

    Я не буду вдаваться в технологические вопросы устройства механизма работы сессий, а только опишу, как правильно работать с сессиями в PHP.

    Как работать с сессиями?

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

    "Warning: open(/var/state/php/sess_6f71d1dbb52fa88481e752af7f384db0, O_RDWR) failed: No such file or directory (2)".

    Это значит всего лишь, что у вас неправильно настроен PHP. Решить эту проблему можно, прописав правильный путь (на существующую директорию) для сохранения сессий в файле php.ini и перезапустить сервер.

    Любой скрипт, который будет использовать переменные (данные) из сессий, должен содержать следующую строчку:

    Session_start();

    Эта команда говорит серверу, что данная страница нуждается во всех переменных, которые связаны с данным пользователем (браузером). Сервер берёт эти переменные из файла и делает их доступными. Очень важно открыть сессию до того, как какие-либо данные будут посылаться пользователю; на практике это значит, что функцию session_start() желательно вызывать в самом начале страницы, например так:

    Session_start(); ?> ... Для задания директории в которой будут сохраняться файлы сессий используется функция session_save_path() : session_save_path($_SERVER["DOCUMENT_ROOT"]."/session"); session_start();

    После начала сессии можно задавать глобальные переменные. Ари присвоении какого-либо значения любому полю массива $_SESSION, переменная с таким же именем автоматически регистрируется, как переменная сессии. Этот массив доступен на всех страницах, использующих сессию. Для примера разберем програму:

    index.php Всё ОК. Сессию загрузили! Пройдём, посмотрим что там: dothings.php

    При последовательном запуске этих файлов, первый скрипт "index.php" выдаст следующий результат:

    Всё ОК. Сессию загрузили! Пройдём, посмотрим что там:

    А второй "dothings.php" вот это:

    Меня задали на index.php

    Переменная $a теперь доступна на всех страницах данного сайта, которые запустили сессии.

    Другие полезные функции и приемы для работы с сессиями:

    • unset($_SESSION["a"]) - сессия "забывает" значение заданной сессионой переменной;
    • session_destroy () - сессия уничтожается (например, если пользователь покинул систему, нажав кнопку "выход");
    • session_set_cookie_params (int lifetime [, string path [, string domain]]) - с помощью этой функции можно установить, как долго будет "жить" сессия, задав unix_timestamp определяющий время "смерти" сессии. По умолчанию, сессия "живёт" до тех пор, пока клиент не закроет окно браузера.
    • session_write_close () - запись переменных сесии и закрытие ее. Это необходимо для открытия сайта в новом окне, если страница выполняет длительную обработу и заблокировала для вашего браузера файл сессий.

    Примеры

    Теперь обратимся к практическому применению механизма сессий. Здесь мы рассмотрим пару довольно простых и в то же время полезных примеров.

    Авторизация Пользователя

    Вопросы по авторизации пользователей с помощью PHP-сессий постоянно задаются в конференциях по web-программированию. Механизм авторизации пользователей в системе с помощью сессий довольно хорош с точки зрения безопасности (см.раздел ).

    Наш пример будет состоять из трёх файлов: index.php, authorize.php и secretplace.php. Файл index.php содержит форму, где пользователь введёт свой логин и пароль. Эта форма передаст данные файлу authorize.php, который в случае успешной авторизации допустит пользователя к файлу secretplace.php, а в противном случае выдаст сообщение об ошибке.

    Примеры: index.php Вводи пароль

    Логин:
    Пароль:
    authorize.php страницу... header("Location: secretplace.php"); exit; } } // если что-то было не так, то пользователь получит // сообщение об ошибке. ?> Вы ввели неверный пароль! secretplace.php Привет, , ты на секретной странице!!! :)

    Безопасность

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

    • на компьютере пользователя стоит "троян", который ворует номера сессий;
    • злоумышленник отлавливает трафик между компьютером пользователя и сервером. Конечно, есть защищенный (зашифрованный) протокол SSL, но им пользуются не все;
    • к компьютеру нашего пользователя подошел сосед и стащил номер сессии.

    Такие ситуации, основанные на том, что кто-то что-то у кого-то стащит, в общем, не входят в компетенцию программиста. Об этом должны заботиться администраторы и сами пользователи.

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

    • Файл authorize.php - попытка подбора пароля с помощью стороннего скрипта;
    • Файл secretplace.php - попытка обмануть программу путём вписывания значений переменной $logged_user в адресной строке браузера, например так:
      "http://www.yoursite.ru/secretplace.php?logged_user=hacker "

    Итак, в нашей программе явно видны две "дыры", одна маленькая и не особо заметная, а вот вторая - просто огромная, через которую большинство хакеров и лезет туда, куда не надо.

    Как "залатать" дыру номер 1?

    Не будем писать тонны кода по блокировке IP-адреса и т.п., а просто проверим, откуда приходит запрос, а точнее с какой страницы пришёл запрос, если это будет любая страница с нашего сайта, то всё нормально, а во всех остальных случаях пускать не будем. Подкорректируем файл authorize.php:

    authorize.php V2 страницу... header("Location: secretplace.php"); exit; } } } ?> Вы ввели неверный пароль!
    Как избавиться от "дыры" номер 2?

    Предположим, у вас есть сайт, где каждый смертный может зарегистрироваться чтобы добавлять сообщения в форум. Естественно, в форуме у некоторых пользователей (админов, модераторов), возможностей больше чем у других, они, например, могут удалять сообщения других пользователей. Уровень доступа пользователя вы храните в сессии, в переменной $user_status, где $user_status = 10 соответствует полному доступу к системе. Пришедшему на сайт злоумышленнику достаточно зарегистрироваться штатным образом, а потом дописать в адресной строке браузера ?user_status=10 . Вот и завёлся у вас на форуме новый админ!

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

    secretplace.php V2 переменную unset($_SESSION["logged_user"]); // открываем сессию session_start(); /* просто зайти на эту страницу нельзя... если имя пользователя не зарегистрировано, то перенаправляем его на страницу index.php для ввода логина и пароля... тут на самом деле можно много чего сделать, например запомнить IP пользователя, и после третьей попытки получить доступ к файлам, его перекрыть. */ if(!isset($_SESSION["logged_user"])){ header("Location: index.php"); exit; } ?> Привет, , ты на секретной странице! Итоги

    Механизм сессий - довольно удачная особенность языка PHP. Сессии просты, очень гибки в использовании. Кстати, есть одна, мало где документированная возможность сессий PHP (доступна начиная с версии 4.0.3) - в сессиях можно хранить не только переменные, но и объекты.

    Примеры

    ?>
    // Автоматическая вставка SID в ссылки. ini_set("session.use_trans_sid", true); session_start(); ?> Click here!
    Click here!!

    // Пример работы с сессиями. session_start(); // Если на сайт только-только зашли, обнуляем счетчик. if (!isset($_SESSION["count"])) $_SESSION["count"] = 0; // Увеличиваем счетчик в сессии. $_SESSION["count"] = $_SESSION["count"] + 1; ?>

    Счетчик

    раз(а).
    Закройте браузер, чтобы обнулить счетчик.
    " target="_blank"> Открыть дочернее окно браузера.
    // Простой пример использования сессий без Cookies. session_name("test"); session_start(); $_SESSION["count"] = @$_SESSION["count"] + 1; ?>

    Счетчик

    В текущей сессии работы с браузером Вы открыли эту страницу раз(а).
    Закройте браузер, чтобы обнулить этот счетчик.
    ?">Нажмите сюда для обновления страницы!

    Сессии являются простым способом хранения информации для отдельных пользователей с уникальным идентификатором сессии. Это может использоваться для сохранения состояния между запросами страниц. Идентификаторы сессий обычно отправляются браузеру через сессионный cookie и используются для получения имеющихся данных сессии. Отсутствие идентификатора сессии или сессионного cookie сообщает PHP о том, что необходимо создать новую сессию и сгенерировать новый идентификатор сессии.

    Сессии используют простую технологию. Когда сессия создана, PHP будет либо получать существующую сессию, используя переданный идентификатор (обычно из сессионного cookie) или, если ничего не передавалось, будет создана новая сессия. PHP заполнит суперглобальную переменную $_SESSION сессионной информацией после того, как будет запущена сессия. Когда PHP завершает работу, он автоматически сериализует содержимое суперглобальной переменной $_SESSION и отправит для сохранения, используя сессионный обработчик для записи сессии.

    По умолчанию PHP использует внутренний обработчик files для сохранения сессий, который установлен в INI-переменной session.save_handler . Этот обработчик сохраняет данные на сервере в директории, указанной в конфигурационной директиве session.save_path .

    Сессии могут запускаться вручную с помощью функции session_start() . Если директива session.auto_start установлена в 1 , сессия автоматически запустится, в начале запроса.

    Сессия обычно завершает свою работу, когда PHP заканчивает исполнять скрипт, но может быть завершена и вручную с помощью функции session_write_close() .

    Предостережение

    Внимание

    Замечание :

    Сессии, использующие файлы (по умолчанию в PHP), блокируют файл сессии сразу при открытии сессии функцией session_start() или косвенно при указании session.auto_start . После блокировки, ни один другой скрипт не может получить доступ к этому же файлу сессии, пока он не будет закрыт или при завершении скрипта или при вызове функции session_write_close() .

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

    Похожие публикации