| 
 Сессии в PHPАвтор:Алексей КуликовИсточник: www.koulikov.cc
 В разнообразных конференциях, посвященных программированию меня в 
      первую очередь всегда интересуют такие разделы, как "Web-программирование" 
      и "Скрипты". По большей части, вопросы о PHP в таких форумах довольно 
      простые, требующие лишь общего понимания PHP, тем не менее, самый часто 
      задаваемый вопрос по моим наблюдениям, это: "Что такое сессии в PHP и с 
      чем/как их можно кушать?". Хотелось бы разъяснить этот вопрос раз и 
      навсегда. С самого начала PHP все приняли на ура, но как только на этом языке 
      стали создавать достаточно крупные проекты, разработчики столкнулись с 
      новой проблемой - в PHP отсутствовало понятие глобальных переменных! То 
      есть, выполнялся некий скрипт, посылал сгенерированную страницу клиенту, и 
      все ресурсы, используемые этим скриптом уничтожались. Попробую 
      проиллюстрировать: предположим есть две страницы одного сайта, index.php и 
      dothings.php. Исходники к этим страницам выглядят так: - index.php -
<?php
  $a = "Меня задали на index.php";
?>
<html><body>
<?php
  echo $a;
?>
</body></html>
- dothings.php -
<html><body>
<?php
  echo $a;
?>
</body></html>
 Если выполнить эти два скрипта, то на первой странице мы увидим надпись 
      "Меня задали на index.php", а вторая страница будет пустой. Разработчики web-сайтов, недолго думая, стали использовать cookie для 
      хранения глобальных переменных на стороне клиента. Процесс выглядел 
      примерно так: пользователь приходит на главную страницу сайта, делает 
      какие-то действия, и вся информация, связанная с этим пользователем, 
      которая может потребоваться на других страницах сайта, будет храниться у 
      него в браузере в виде cookie. Этот метод меет довольно серьезные минусы, 
      из-за которых от PHP в своё время отвернулось немало разработчиков. 
      Например, нам нужно авторизовать пользователя, чтобы разрешить ему доступ 
      к закрытым (или принадлежащим только ему) разделам сайта. Придёться 
      <кидать> пользователю cookie, который будет служит его последующим 
      идентификатором на сайте. Такой подход становится 
      очень громоздким и не удобным, как только сайт начинает собирать всё 
      больше и больше сведений о поведении пользователя, ведь всю информацию, 
      посылаемую пользователю, желательно кодировать, чтобы её нельзя было 
      подделать. Ещё совсем недавно подделкой cookie можно было 
      <повалить> не один чат, а порой и пробраться в чужую почту. К тому 
      же есть ещё на свете странные люди, у которых браузер cookie не 
      поддерживает. При использовании сессий вся информация хранится не на стороне клиента, 
      а на стороне сервера, и потому лучше защищена от манипуляций 
      злоумышленников. Да и работать с сессиями куда проще и 
      удобнее, так как все данные автоматически проходят через алгоритмы 
      криптографии модуля PHP. В броузере клиента, лишь хранится уникальный 
      идентификатор номера сессии, либо в форме cookie, либо в виде переменной в 
      адресной строке броузера, какой из двух способов использовать для передачи 
      идентификатора сессии между страницами интерпретатор PHPвыбирает сам. Это 
      на 100 безопасно, так как идентификатор сессии уникален, и подделать его 
      практически невозможно (об этом чуть далее, в разделе о безопасности 
      сессий). Я не буду вдаваться в технологические вопросы устройства механизма 
      работы сессий, а только опишу, как правильно работать с сессиями в 
      PHP.Как работать с сессиями? Если вы будете тестировать примеры из статьи (или ваши скрипты) на 
      каком-либо коммерческом хостинге, проблем с работой с сессиями быть не 
      должно. Если же вы сами настраивали ваш сервер (будь то реальный сервер, 
      или эмулятор), могут появляться ошибки примерно такого содержания:  "Warning: open(/var/state/php/sess_6f71d1dbb52fa88481e752af7f384db0, 
      O_RDWR) failed: No such file or directory (2)". Это значит всего лишь, что у вас неправильно настроен PHP. Решить эту 
      проблему можно, прописав правильный путь (на существующую директорию) для 
      сохранения сессий в файле php.ini и перезапустить сервер. Любой скрипт, который будет использовать переменные (данные) из сессий, 
      должен содержать следующую строчку:session_start(); 
 Эта команда говорит серверу, что данная страница нуждается во всех 
      переменных, которые связаны с данным пользователем (браузером). Сервер 
      берёт эти перемнные (из файла, либо из БД) и делает их доступными. Очень 
      важно открыть сессию до того, как какие-либо данные будут посылаться 
      пользователю; на практике это значит, что функцию session_start() 
      желательно вызывать в самом начале страницы, например так: <?php
  session_start();
?>
<html>
 <head>
 </head>
 ...
 После начала сессии можно задавать глобальные переменные. Это 
      элементарно: вызываем функцию session_register('var_name'); и переменная 
      $var_name становится доступной на всех страницах, использующих сессию. Для 
      примера поковыряем программку, приведенную в начале статьи: - index.php -
<?php
  // открываем сессию
  session_start();
  // задаём значение переменной
  $a = "Меня задали на index.php";
  // регистрируем переменную с открытой сессией
  // важно: названия переменных передаются функции session_register()
  // без знака $
  session_register("a");
?>
<html>
 <body>
  Всё ОК. Сессию загрузили! 
  Пройдём, посмотрим что <a href="dothings.php>там:</a>
 </body>
</html>
- dothings.php -
<?php
  // открываем сессию
  session_start();
?>
<html>
 <body>
 <?php
   echo $a;
 ?>
 </body>
</html>
При запуске этих файлов (в логической последовательности конечно), 
      первый скрипт (index.php) выдаст следующий результат:Всё ОК. Сессию 
      загрузили! Пройдём, посмотрим что там: А второй (dothings.php) вот это:Меня задали на index.php Переменная $a теперь доступна на всех страницах данного сайта, которые 
      запустили сессии. Другие полезные функции для работы с сессиями: 
       
        Примерыsession_unregister(string)- сессия 
        <забывает> значение заданной глобальной переменной;session_destroy()- сессия уничтожается 
        (например, если пользователь покинул систему, нажав кнопку 
        <выход>);session_set_cookie_params(int lifetime [, string path [, 
        string domain]])-с помощью этой функции можно установить, как 
        долго будет <жить> сессия, задав unix_timestampопределяющий время 
        <смерти> сессии. По умолчанию, сессия <живёт> до тех пор, 
        пока клиент не закроет окно браузера. Теперь обратимся к практическому применению механизма сессий. Давайте 
      рассмотрим пару довольно простых и в то же время полезных 
      примеров.Авторизация Пользователя Вопросы по авторизации пользователей с помощью PHP-сессий постоянно 
      задаются в конференциях по web-программированию. Механизм авторизации 
      пользователей в системе с помощью сессий довольно хорош с точки зрения 
      безопасности (см. раздел <Безопасность> ниже).  Наш пример будет состоять из трёх файлов: index.php, authorize.php и 
      secretplace.php. Файл index.php содержит форму, где пользователь введёт 
      свой логин и пароль. Эта форма передаст данные файлу authorize.php, 
      который в случае успешной авторизации допустит пользователя к файлу 
      secretplace.php, а в противном случае выдаст сообщение об ошибке. Приступим: - index.php -
<html>
 <head>
  <title>Введи пароль, смертный</title>
 </head>
 <body>
  <form action="authorize.php" method="post">
   Логин:<input type="text" name="user_name"><br>
   Пароль:<input type="password" name="user_pass"><br>
   <input type="submit" name="Submit">
  </form>
 </body>
</html>
- authorize.php -
<?php
  // открываем сессию
  session_start();
  // данные были отправлены формой?
  if($Submit){
    // проверяем данные на правильность... в данном случае я
    // вписал имя пользователя и пароль прямо в код, целесообразней
    // было бы проверить логин/пароль в базе данных и при сов-
    // падении дать доступ пользователю...
    if(($user_name=="cleo")&&($user_pass=="password")){
      $logged_user = $user_name;
      // запоминаем имя пользователя
      session_register("logged_user");
      // и переправляем его на <секретную> страницу...
      header("Location: secretplace.php");
      exit;
    }
  }
  // если что-то было не так, то пользователь получит сообщение об ошибке.
?>
<html><body>
Вы ввели неверный пароль!
</body></html>
- secretplace.php -
<?php
  // открываем сессию
  session_start();
  /*
    просто зайти на эту страницу нельзя... если
    имя пользователя не зарегистрировано, то
    перенаправляем его на страницу index.php
    для ввода логина и пароля... тут на самом деле
    можно много чего сделать, например запомнить
    IP пользователя, и после третьей попытки получить
    доступ к файлам, его закрыть.
  */
  if(!isset($logged_user)){
    header("Location: index.php");
    exit;
  }
?>
<html>
 <body>
  Привет, <?php echo $logged_user; ?>, ты на секретной странице!!! :)
 </body>
</html>
БезопасностьИтак, мы умеем передавать идентификатор от одной страницы (PHP-скрипта) 
      к другой (до следующего вызова с нашего сайта), а значит мы можем 
      различать всех посетителей сайта. Так как идентификатор сессии - это очень 
      большое число (128 бит), шансов, что его удастся подобрать перебором, 
      практически нет. Поэтому злоумышленнику остаются следующие возможности: 
       
        на компьютере пользователя стоит <троян>, который ворует 
        номера сессий; 
        злоумышленник отлавливает трафик между компьютером пользователя и 
        сервером. Конечно, есть защищенный (зашифрованный) протокол SSL, но им 
        пользуются не все; 
        к компьютеру нашего пользователя подошел сосед и стащил номер 
        сессии.  Такие ситуации, основанные на том, что кто-то что-то у кого-то стащит, 
      в общем, не входят в компетенцию программиста. Об этом должны заботиться 
      администраторы и сами пользователи. Впрочем, PHP очень часто можно <обмануть>. Давайте рассмотрим 
      возможные точки взлома в программе авторизации пользователя: 
       Итак, в нашей программе явно видны две <дыры>, одна маленькая и 
      не особо заметная, а вот вторая - просто огромная, через которую 
      большинство хакеров и лезет туда, куда не надо.Как <залатать> 
      дыру номер 1? Не будем писать тонны кода по блокировке IP-адреса и т.п., а просто 
      проверим, откуда приходит запрос, а точнее с какой страницы пришёл запрос, 
      если это будет любая страница с нашего сайта, то всё нормально, а во всех 
      остальных случаях пускать не будем. Подкорректируем файл 
authorize.php: - authorize.php V2 -
<?php
  // открываем сессию
  session_start();
  
  // полный путь к корневой директории где расположены скрипты
  $SERVER_ROOT = "http://localhost/test1/";
  
  // если пользователь пришёл с любой страницы нашего сайта
  // то он вроде наш...
  // Переменная $HTTP_REFERER всегда доступна по умолчанию
  // и содержит полный адрес ссылающейся страницы...
  // функция eregi() проверяет, начинается ли адрес ссылающейся страницы
  // со значения в переменной $SERVER_ROOT
  
  if(eregi("^$SERVER_ROOT",$HTTP_REFERER)){
    // данные были отправлены формой?
    if($Submit){
      // далее все как раньше
      if(($user_name=="cleo")&&($user_pass=="password")){
        $logged_user = $user_name;
        // запоминаем имя пользователя
        session_register("logged_user");
        // и переправляем его на <секретную> страницу...
        header("Location: secretplace.php");
        exit;
      }
    }
  }
?>
<html><body>
  Вы ввели неверный пароль!
</body></html>
Как избавиться от <дыры> номер 2?Предположим, у вас есть сайт, где каждый смертный может 
      зарегистрироваться чтобы добавлять сообщения в форум. Естественно, в 
      форуме у некоторых пользователей (админов, модераторов), возможностей 
      больше чем у других, они, например, могут удалять сообщения других 
      пользователей. Уровень доступа пользователя вы храните в сессии, в 
      переменной $user_status, где $user_status = 10 соответствует полному 
      доступу к системе. Пришедшему на сайт злоумышленнику достаточно 
      зарегистрироваться штатным образом, а потом дописать в адресной строке 
      браузера ?user_status=10. Вот и завёлся у вас на форуме новый 
      админ! В принципе, любую переменную скрипта можно задать через адресную 
      строку, просто дописав после полного адреса к скрипту вопросительный знак 
      и название переменной с её значением. Давайте поправим наш код, чтобы 
      этого избежать: - secretplace.php V2 -
<?php
  // убираем всё лишнее из адресной строки
  // функция unset() <освобождает> переменную
  unset($logged_user);
  
  // открываем сессию
  session_start();
  
  // и корректируем испорченные перменные.
  // Важно: в этом случае, переменная регистрируется не как новая
  // переменная, а как уже существующая, а потому знак $ не опускается
  session_register($logged_user);
  
  /*
    просто зайти на эту страницу нельзя... если
    имя пользователя не зарегистрировано, то
    перенаправляем его на страницу index.php
    для ввода логина и пароля... тут на самом деле
    можно много чего сделать, например запомнить
    IP пользователя, и после третьей попытки получить
    доступ к файлам, его перекрыть.
  */
  if(!isset($logged_user)){
    header("Location: index.php");
    exit;
  }
?>
<html>
 <body>
  Привет, <?php echo $logged_user; ?>, ты на секретной странице!!! :)
 </body>
</html>
ИтогиМеханизм сессий - довольно удачная особенность языка PHP. Сессии росты, 
      очень гибки в использовании. Кстати, есть одна, мало где документированная 
      возможность сессий PHP (доступна начиная с версии 4.0.3) - в сессиях можно 
      хранить не только переменные, но и объекты.Добавление от 
      14.12.2001 С выходом в свет PHP 4.1.0 - работа с сессиями значительно облегчилась. 
      Все переменные сессий стали доступны из глобального массива 
      _SESSION['var_name']. Самое приятное наверное в том, что при присвоении 
      какого-либо значения любому полю массива, переменная с таким же именем 
      автоматически регистрируется, как переменная сессии, на пр: <?
  $_SESSION['counter'] = 12;
  echo $counter;
?>
 выведет на экран броузера число 12. 
 
 |