Работа с cookie в PHP

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

Любой веб-сценарий, к примеру, PHP-скрипт, как правило, выполняется доли секунды, возвращая информацию веб-серверу для дальнейшей отправки. После завершения работы сценария все данные, созданные в оперативной памяти в процессе его работы, уничтожаются. Иногда эти данные терять нельзя. Допустим, на главной странице сайта есть HTML-форма с предложением выбрать предпочтительный цвет фона. Далее, на всех страницах используется выбранный пользователем цвет. Значение цвета — это то, что в контексте данной задачи можно хранить при помощи cookie.

Для дальнейшего понимания функционирования механизма cookie в PHP вам необходимо ознакомиться со статьей "Интерпретатор PHP. Основы, принципы функционирования", в особенности, где затрагивается понятие так называемого "первого вывода". Итак, задействовать механизм можно на этапе формирования HTTP-ответа на запрос. Для того, чтобы указать веб-клиенту сохранить у себя какой-то параметр в HTTP-ответ добавляется заголовок Set-Cookie со значением вида name=value (имя параметра, значение параметра), например:

Set-Cookie: myname=john

Таких заголовков может быть несколько, если необходимо сохранить более одного параметра. При получении HTTP-ответа веб-браузер проверяет наличие заголовков Set-Cookie и, если таковые имеются, сохраняет их значения в своих внутренних служебных файлах. Куки по умолчанию привязываются к домену сайта. При подготовке HTTP-запроса веб-браузер проверяет, есть ли у него в наличии сохраненные куки, привязанные к домену, к которому выполняется запрос. При наличии в HTTP-запрос добавляется заголовок

Cookie: name=value

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

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

Set-Cookie: name=value; expires=date

Где date — дата и время, когда браузеру следует удалить данную куки, например:

Set-Cookie: myname=john; expires=Fri, 01-Apr-2011 23:59:59 GMT

Обратите внимание на формат атрибута expires.

При помощи атрибута path можно ограничить область действия куки. По умолчанию куки применяются ко всем запросам данного домена, что соответствует значению path=/. Если, допустим, задать path=/doc/, то куки будут применяться только к запросам к директории /doc/, а также всем ее поддиректориям и документам, например, /doc/images/. Пример с атрибутом path:

Set-Cookie: myname=john; expires=Fri, 01-Apr-2011 23:59:59 GMT; path=/

Можно также переопределить привязку к домену при помощи атрибута domain. По умолчанию куки привязывается к домену документа, запрос которого инициализировал создание куки. Если указать .domain.ru, то куки будет распространяться на запросы к домену domain.ru, а также ко всем его поддоменам. Можно ограничить действие конкретным поддоменом, например www.domain.ru. Пример с использованием атрибутов expires, path и domain:

Set-Cookie: myname=john; expires=Fri, 01-Apr-2011 23:59:59 GMT; path=/; domain=.domain.ru

Настало время разобраться, как работать с куки в PHP. Для установки куки существует PHP-функция setcookie:

bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )

Большинство параметров функции необязательные. Разберемся на реальном примере (предложенная ранее страница с выбором цвета фона):

<?php
 
  $colors = array('зеленый' => '#090', 'синий' => '#009', 'красный' => '#900');
  $bgcolor = '#fff'; // Цвет фона по умолчанию (белый). Цвет будет взят из куки, если соответствующая куки будет существовать (реализуем позже)
 
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">  
  <head> 
    <title>Возможность выбора фона страницы</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <style type="text/css">
      body { background: <?php echo $bgcolor; ?>; }
    </style>
  </head>  
  <body>
    <form method="get" action="<?php echo $_SERVER['PHP_SELF']; ?>">
      <table>
        <tr>
          <td>Желаемый фон:</td>
          <td>
            <select name="bgcolor">
<?php
 
  foreach($colors as $key => $value)
  {
    //--Определяем, какой из цветов выбран пользователем (если выбран)
    $selected_attr = ($bgcolor == $value) ? ' selected="selected"' : '';
    echo '              <option value="' . $value . '"' . $selected_attr .'>' . $key . '</option>'. "\n";
  }
 
?>
            </select>
          </td>
        </tr>
      </table>
      <input type="submit" value="Выбрать" />
    </form>
  </body>
</html>

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

<?php
 
  $colors = array('зеленый' => '#090', 'синий' => '#009', 'красный' => '#900');
  $bgcolor = '#fff'; // Цвет фона по умолчанию (белый). Цвет будет взят из куки, если соответствующая куки будет существовать (реализуем в следующем примере)
 
  //--Проверяем, был ли передан GET-параметр bgcolor и имеется ли он в нашем массиве. А то, знаете ли, могут передать мало ли чего, а нам потом расхлебывать ;)
  if ( isset($_GET['bgcolor']) && in_array($_GET['bgcolor'], $colors) )
  {
     $bgcolor = $_GET['bgcolor']; //--Это будет наш новый фон для страницы
     setcookie('bgcolor', $bgcolor); //--Сохраняем значение цвета фона в куки. Подробности ниже в статье
  }
 
?>

Обработчик получает значение выбранного пользователем цвета и сохраняет его в куки при помощи PHP-функции setcookie. Функция setcookie добавит в формирующийся HTTP-ответ заголовок Set-Cookie с нашей куки. Ее, как и функцию header, можно использовать только до вывода, то есть, как можно выше в коде.

Отлично, куки мы сохранили. Теперь нужно их использовать. Над обработчиком добавим код получения значения цвета фона из куки, если оно там хранится:

if ( isset($_COOKIE['bgcolor']) && in_array($_COOKIE['bgcolor'], $colors) )
{
    $bgcolor = $_COOKIE['bgcolor'];
}

Все очень просто. Если вместе с запросом скрипта были отправлены какие-либо куки, PHP помещает их в глобальный массив $_COOKIE. Таким образом, работа с принятыми куки ничем не отличается от, скажем, работы с принятыми GET или POST-параметрами. Полный листинг скрипта:

<?php
 
  $colors = array('зеленый' => '#090', 'синий' => '#009', 'красный' => '#900');
  $bgcolor = '#fff'; // Цвет фона по умолчанию (белый)
 
  //--Проверяем, есть ли уже сохраненный в куки bgcolor (также проверяем на корректность, т.к. куки легко подменить)
  if ( isset($_COOKIE['bgcolor']) && in_array($_COOKIE['bgcolor'], $colors) )
  {
      //--Если есть, используем сохраненное значение
      $bgcolor = $_COOKIE['bgcolor'];
  }
 
  //--Проверяем, был ли передан GET-параметр bgcolor и имеется ли он в нашем массиве. А то, знаете ли, могут передать мало ли чего, а нам потом расхлебывать ;)
  if ( isset($_GET['bgcolor']) && in_array($_GET['bgcolor'], $colors) )
  {
     $bgcolor = $_GET['bgcolor']; //--Это будет наш новый фон для страницы
     setcookie('bgcolor', $bgcolor); //--Сохраняем значение цвета фона в куки
  }
 
?>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">  
  <head> 
    <title>Возможность выбора фона страницы</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <style type="text/css">
      body { background: <?php echo $bgcolor; ?>; }
    </style>
  </head>  
  <body>
    <form method="get" action="<?php echo $_SERVER['PHP_SELF']; ?>">
      <table>
        <tr>
          <td>Желаемый фон:</td>
          <td>
            <select name="bgcolor">
<?php
 
  foreach($colors as $key => $value)
  {
    //--Определяем, какой из цветов выбран пользователем (если выбран)
    $selected_attr = ($bgcolor == $value) ? ' selected="selected"' : '';
    echo '              <option value="' . $value . '"' . $selected_attr .'>' . $key . '</option>'. "\n";
  }
 
?>
            </select>
          </td>
        </tr>
      </table>
      <input type="submit" value="Выбрать" />
    </form>
  </body>
</html>

Вникните в работу скрипта, если есть вопросы — welcome в комментарии. Цвет фона сохраняется в так называемую временную куки, которая при закрытии браузера будет удалена. Давайте используем постоянную куки, для этого необходимо в функции setcookie определить третий параметр — время удаления куки, который будет преобразован в атрибут expires HTTP-заголовка Set-Cookie. В параметре указывается отметка времени в Unix формате. Чаще всего для формирования такой отметки используют PHP-функцию time(), которая возвращает текущее время в Unix формате, прибавляя к ней количество секунд, по истечении которых куки должна быть удалена. Например, time()+3600 — удалить куки через час. Сделаем нашу куки активной одну неделю:

setcookie('bgcolor', $bgcolor, time()+3600*24*7); //--Сохраняем значение цвета фона в куки

Все, теперь выбранный цвет фона сайт "помнит" даже после закрытия браузера. Кстати, чтобы удалить куки достаточно указать в качестве expire прошедшую дату, например time()-3600. Не забывайте просматривать HTTP-заголовки при тестировании примеров.

Комментарии

Оставить комментарий »

 
DarkGrek
4 сентября 2011, 22:19
#1
 

thx брат!!!

Михаил
21 ноября 2011, 0:23
#2
 

В теге FORM
1. Метод GET используется по умолчанию. Его можно не указывать?
2. Я правильно понимаю, что если не указать значение для ACTION, то значения формы отправятся на ту же страницу, где находится форма(т.е. на эту же страницу)? Можно ли тогда не указывать ACTION в тех случаях, когда обработчик находится на этой же странице?

Михаил
21 ноября 2011, 1:03
#3
 

Да в общем то все понятно, но с трудом. И когда думаешь, что тебе придется написать такой вот скрипт самому(с нуля) - впадаешь в уныние =) Видимо тут нужен опыт...

Михаил
21 ноября 2011, 1:05
#4
 

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

Joker-jar
21 ноября 2011, 1:43
#5
 

Метод GET используется по умолчанию. Его можно не указывать?

Если не указать, будет, действительно, работать метод GET. При явном указании гарантированно не возникнет вопросов у валидатора, без указания надо проверять при конкретном doctype.

Я правильно понимаю, что если не указать значение для ACTION, то значения формы отправятся на ту же страницу, где находится форма(т.е. на эту же страницу)

Да, все верно. Можно не указывать, опять же, надо проверять валидатором.

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

Это, скорей всего, стиль кода. Глаза режет из-за того, что здесь перемешан PHP и HTML код. В боевых условиях я этого никогда не делаю, чуть позже я напишу о таком замечательном механизме как шаблонизация. Просто использовать шаблонизатор при описании совершенно другой темы не совсем логично.

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

Михаил
21 ноября 2011, 8:29
#6
 

Да, было бы здорово, если бы вы в одном из уроков описали шиблонизацию. А еще Smarty... если конечно используете.

Joker-jar
21 ноября 2011, 9:33
#7
 

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

В одном из следующих статей я и расскажу, как создать такой простенький шаблонизатор.

Михаил
25 декабря 2011, 16:05
#8
 

Кстати, чтобы удалить куки достаточно указать в качестве expire прошедшую дату, например time()-3600

Можно так. А можно просто установить одноименное куки без вторых и третьих параметров. т.е. setcookie('имя'); Официально эта команда означает "стереть куки с таким-то именем".

DarkAdmin
13 мая 2012, 22:08
#9
 

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

Joker-jar
14 мая 2012, 1:16
#10
 

DarkAdmin, если что, можете задать вопрос здесь.

Оставить комментарий

Ваше имя
 
Ваш e-mail
 
Комментарий