﻿
<h1 class=p1>cookies</h1>
<table border="0" cellspacing="10">
    <tr valign="top">
        <td>
            <a class=bluelink href="#1" title="Установка cookies" >setcookie()</a>&nbsp;<br>
        </td>
        <td>
            <a class=bluelink href="#2" title="Установка срока годности cookies">time()</a>&nbsp;<br>                   
        </td>
        <td>        
            <a class=bluelink href="#3" title="Установка срока годности cookies">mktime()</a>&nbsp;<br>     
        </td>
    </tr>
</table>
<br>
<br>

<p class=text>Использование сookies удобно как для программистов, так и для пользователей. Пользователи выигрывают за счет того, что им не приходится каждый раз заново вводить информацию о себе, а программистам сookies помогают легко и надежно сохранять информацию о пользователях.</p>
<p class=text><b>Определение</b><i> Cookies - это текстовые строки, хранящиеся на стороне клиента, и содержащие пары "имя-значение", с которыми связан URL, по которому броузер определяет нужно ли посылать cookies на сервер.</i></p>
<a name=1></a>
<h2 class=p1>Установка cookies</h2>
<p class=text>Установка cookies производится с помощью функции <b>setcookie</b>:</p>

<h1 class=p1>setcookie</h1>
<p class=prim><b><i>Синтаксис:</i></b></p>
<blockquote><pre>
  <em class=gr>bool</em> <b>setcookie</b><em class=gr> (</em><b>string name</b> [, <b>string value</b> [, <em class=gr>int</em> <b>expire</b> [, <em class=gr>string</em> <b>path</b>
  [, <em class=gr>string</em><b> domain</b> [, <em class=gr>int</em><b> secure</b>]]]]]<em class=gr>)</em>
</pre></blockquote>
<p class=text>Эта функция имеет следующие аргументы:</p>
<ul>
  <li><b>name</b> - имя устанавливаемого cookie;</li>
  <li><b>value</b> - значение, хранящееся в cookie с именем <b>$name</b>;</li>
  <li><b>expire</b> - время в секундах с начала эпохи, по истечение которого текущий cookie становится недейтвительным;</li>
  <li><b>path</b> - путь, по которому доступен cookie;</li>
  <li><b>domain</b> - домен, из которого доступен cookie;</li>
  <li><b>secure</b> - директива, определяющая, доступен ли cookie не по запросу HTPPS. По умолчанию эта директива имеет значение 0, что означает возможность доступа к cookie по обычному запросу HTTP.</li>
</ul>
<h2 class=p1>Пример простого приложения с cookies</h2>
<p class=text>Давайте создадим простой сценарий, подсчитывающий при помощи cookies количество обращений посетителя к странице.</p>
<p class=text>В cookie с именем counter будет храниться число посещений страницы пользователем:</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  <b>$counter</b>++<em class=gr>;</em>
  <b>setcookie</b><em class=gr>(</em>"counter",<b>$counter</b><em class=gr>);
  echo(</em>"Вы посетили эту страницу <b>$counter</b> раз"<em class=gr>);</em>
<em class=red>?&gt;</em>
</pre></blockquote>
<p class=text>Результат выполнения сценария на рис.:</p>
<img src="images/4.jpg" tppabs="http://site/bookphp/images/4.jpg">
<p class=text>При работе с cookies необходимо учитывать важный момент, заключающийся в том, что cookie надо обязательно устанавливать перед отправкой в броузер каких-либо заголовков, поскольку сами cookies устанавливаются в виде заголовков. Поэтому если установить cookies после какого-либо текста, отправляемого в броузер, то возникнет ошибочная ситуация.</p>
<p class=text>Рассмотрим этот вопрос подробнее, для чего модифицируем код, приведенный в листинге, поместив перед установкой cookie текст:</p>
<blockquote><pre>
  Если здесь поместить текст, то возникнет ошибка, так как
  будет послан заголовок Content-type: text/html. 
<em class=red>&lt;?</em>
  <b>$counter</b>++<em class=gr>;</em>
  <b>setcookie</b><em class=gr>(</em>"counter",<b>$counter</b><em class=gr>);
  echo(</em>"Вы посетили эту страницу <b>$counter</b> раз"<em class=gr>);</em>
<em class=red>?&gt;</em>
</pre></blockquote>
<p class=text>Как видно из рис., при выполнении этого сценария выводится сообщение об ошибке:</p>
<img src="images/5.jpg" tppabs="http://site/bookphp/images/5.jpg">
<p class=text>Заметим, что в этих листингах мы обращаемся к переменной <b>$counter</b>, в которой хранится значение cookie, как к глобальной, что требует наличия включенной директивы <b>register_globals</b>. Если эта директива отключена, то значение, хранящееся в cookie можно получить через глобальные массивы <b>$HTTP_COOKIE_VARS</b>["name"] и <b>$_COOKIE</b>["name"]:</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  <b>$_COOKIE</b>['counter']++<em class=gr>;</em>
  <b>setcookie</b><em class=gr>(</em>"counter",<b>$counter</b><em class=gr>);
  echo</em> 'Вы посетили эту страницу '.<b>$_COOKIE</b>['counter'].' раз'<em class=gr>;</em>
<em class=red>?&gt;</em>
</pre></blockquote>
<p class=text>Поскольку некоторые пользователи отключают cookie в настройках своих браузеров, для корректной работы, в приложение, использующее cookies, необходимо помещать код, проверяющий включены ли cookies у посетителя, и, если нет, то сообщающий ему о необходимости включить cookie:</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  <b>if</b><em class=gr>(</em><b>!$cookie</b><em class=gr>)
  {</em>
    <em class=comnt>/* посылаем заголовок переадресации на страницу,
    с которой будет предпринята попытка установить cookie */</em>
    <b>header</b><em class=gr>(</em>"Location: <b>$PHP_SELF?cookie=1</b>"<em class=gr>);</em>
    <em class=comnt>/* устанавливаем cookie с именем "test" */</em>
    <b>setcookie</b><em class=gr>(</em>"test","1"<em class=gr>);
  }
  else
  {</em>
    <b>if</b><em class=gr>(</em><b>!$test</b><em class=gr>)
    {
      echo(</em>"Для корректной работы приложения необходимо включить cookies"<em class=gr>);
    }
    else
    {</em><em class=comnt>
      /* cookie включены, переходим на нужную страницу */</em>
      <b>header</b><em class=gr>(</em>"Location: http://localhost/test1.php"<em class=gr>);
    }
  }</em>
<em class=red>?&gt;</em>
</pre></blockquote>
<a name=2></a>
<h2 class=p1>Установка срока годности cookies</h2>
<p class=text>По умолчанию cookies устанавливаются на один сеанс работы с броузером, однако можно задать для них более продолжительный срок существования. Это очень удобное и полезное свойство, поскольку в этом случае пользователю не нужно предоставлять свои данные вновь при каждом посещении сайта.</p>
<p class=text>Как уже говорилось, срок годности устанавливается в секундах относительно начала эпохи. В PHP существуют функции <b>time</b> и <b>mktime</b> для работы с датой и временем, позволяющие переводить текущее время в количество секунд с начала эпохи. Функция <b>time</b> просто переводит текущее системное время в количество секунд, прошедших с начала эпохи:</p>

<h1 class=p1>time</h1>
<p class=prim><b><i>Синтаксис:</i></b></p>
<blockquote><pre>
  <b>time</b><em class=gr>();</em>
</pre></blockquote>
<a name=3></a>
<p class=text>Усовершенствованным вариантом функции <b>time</b> является функция <b>mktime</b>:</p>

<h1 class=p1>mktime</h1>
<p class=prim><b><i>Синтаксис:</i></b></p>
<blockquote><pre>
  <em class=gr>int</em><b> mktime</b><em class=gr> (</em>[<em class=gr>int</em><b> hour</b> [, <em class=gr>int</em><b> minute</b> [, <em class=gr>int</em><b> second</b> [, <em class=gr>int</em><b> month</b> [, <em class=gr>int</em>
  <b>day</b> [, <em class=gr>int</em><b> year</b> [, <em class=gr>int</em><b> is_dst</b>]]]]]]]<em class=gr>)</em>
</pre></blockquote>
<p class=text>Аргумент <b>is_dst</b> этой функции определяет, попадает ли эта дата в период летнего времени и может принимать следующие значения:</p>
<ul>
  <li>-1 (По умолчанию. Означает, что свойство не задано);</li>
  <li> 0 (Временной интервал не приходится на период летнего времени);</li>
  <li> 1 (Временной интервал приходится на период летнего времени).</li>
</ul>
<p class=text>Примеры установки сроки годности cookies:</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  <em class=comnt>/* этот cookie действителен в течение 10 мин после создания */</em>
  <b>setcookie</b><em class=gr>(</em>"name", <b>$value</b>, <b>time</b><em class=gr>()</em> + 600<em class=gr>);</em>
  <em class=comnt>/* действие этого cookie прекращается в полночь 25 января 2010 года */</em>
  <b>setcookie</b><em class=gr>(</em>"name", <b>$value</b>, <b>mktime</b><em class=gr>(</em>0,0,0,01,25,2010<em class=gr>));</em>
  <em class=comnt>/* действие этого cookie прекращается в 18.00 25 января 2010 года */</em>
  <b>setcookie</b><em class=gr>(</em>"name", <b>$value</b>, <b>mktime</b><em class=gr>(</em>18,0,0,01,25,2010<em class=gr>));</em>
<em class=red>?&gt;</em>
</pre></blockquote>
<h2 class=p1>Удаление cookie</h2>
<p class=text>Удалить cookie просто. Для этого надо вызвать функцию <b>setcookie</b> и передать ей имя того cookie, который подлежит удалению:</p>
<blockquote><pre>
  <b>setcookie</b><em class=gr>(</em>"name"<em class=gr>);</em>
</pre></blockquote>
<p class=text>Другие установленные cookie при этом не удаляются.</p>
<h2 class=p1>Проблемы безопасности, связанные с cookies</h2>
<p class=text>Иногда в cookies приходится хранить конфиденциальные данные, и в этом случае разработчик должен позаботиться о том, чтобы информация хранящееся в cookie не была передана третьим лицам. Существует несколько методов защиты информации, хранящейся в cookie:</p>
<ul>
  <li>установка области видимости cookies;</li>
  <li>шифрование;</li>
  <li>ограничение доступа для доменов;</li>
  <li>отправка cookies по защищенному запросу.</li>
</ul>
<p class=text>Наилучшим решением является комплексное применение всех этих способов.</p>
<h2 class=p1>Установка области видимости cookie</h2>
<p class=text>Поскольку, по умолчанию, доступ к cookie происходит из корневого каталога, это может создать "дыры" в системе защиты, так как cookies становятся доступными в любом подкаталоге этого каталога. Ограничить доступ к cookies для всех страниц, кроме расположенных в конкретном каталоге, к примеру, /web, можно следующим образом:</p>
<blockquote><pre>
  <b>setcookie</b><em class=gr>(</em>"name", <b>$value</b>, "/web/"<em class=gr>);</em>
</pre></blockquote>
<p class=text>Однако и в этом случае, к примеру, каталоги /web/index.php, /web1/page.html и т. д. будут удовлетворять этому ограничению. Если такое положение также является нежелательным, можно ограничить область видимости cookies до конкретной страницы:</p>
<blockquote><pre>
  <b>setcookie</b><em class=gr>(</em>"name", <b>$value</b>, "/web/index.php"<em class=gr>);</em>
</pre></blockquote>
<p class=text>Однако и такой способ в полной мере не решает проблему, так как в этом случае доступ к информации, содержащейся в cookie, может получить, к примеру, скрипт /web/index.php-script/anti_cookie.php. Поэтому появляется необходимость в шифровании.</p>
<h2 class=p1>Шифрование</h2>
<p class=text>Применить шифрование к cookies можно разными способами, рассмотрим один из них:</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  //<em class=comnt> создаем вектор начального состояния для шифрования</em>
  <b>$vector</b><em class=gr> = </em><b>mcrypt_create_iv</b><em class=gr>(</em><b>mcrypt_get_iv_size</b><em class=gr>(</em><b>MCRYPT_CAST_256</b>, 
                             <b>MCRYPT_MODE_CFB</b><em class=gr>)</em>, <b>MCRYPT_RAND</b><em class=gr>);</em>
  <b>$key</b><em class=gr> = </em>"qwe233jk312jx813893xk312"<em class=gr>;</em> //<em class=comnt> ключ для расшифрования</em>
  <b>$cook_name</b><em class=gr> = </em>"maks"<em class=gr>;</em>
  <b>$cipher</b><em class=gr> = </em><b>mcrypt_encrypt</b><em class=gr>(</em><b>MCRYPT_CAST_256</b>, <b>$key</b>, <b>$cook_name</b>,
                           <b>MCRYPT_MODE_CFB</b>, <b>$vector</b><em class=gr>);</em>
  <b>setcookie</b><em class=gr>(</em>"username", <b>$cipher</b>, "/decrypt.php"<em class=gr>);</em>
<em class=red>?&gt;</em>
</pre></blockquote>
<p class=text>Как видно из листинга 10.13, расшифровка cookie проводится при помощи скрипта  decrypt.php, код которого приведен ниже:</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  //<em class=comnt> вектор начального состояния остается неизменным</em>
  <b>$vector</b><em class=gr> = </em><b>mcrypt_create_iv</b><em class=gr>(</em><b>mcrypt_get_iv_size</b><em class=gr>(</em><b>MCRYPT_CAST_256</b>,
                             <b>MCRYPT_MODE_CFB</b><em class=gr>)</em>, <b>MCRYPT_RAND</b><em class=gr>);</em>
  <b>$key</b><em class=gr> = </em>"qwe233jk312jx813893xk312"<em class=gr>;</em>
  <b>$decrypt_name</b><em class=gr> = </em><b>mcrypt_ decrypt</b><em class=gr>(</em><b>MCRYPT_CAST_256</b>, <b>$key</b>, <b>$username</b>,
                                  <b>MCRYPT_MODE_CFB</b>, <b>$vector</b><em class=gr>);
  echo(</em>"<b>$decrypt_name</b>, мы рады видеть вас на нашей страничке!"<em class=gr>);</em>
<em class=red>?&gt;</em>
</pre></blockquote>
<h2 class=p1>Ограничение доступа для доменов</h2>
<p class=text>Для дополнительной безопасности, список доменов, имеющих доступ к cookies, должен быть ограничен. Это можно сделать при помощи следующего кода:</p>
<blockquote><pre>
  <b>setcookie</b><em class=gr>(</em>"name", <b>$value</b>, "/web/index.php", ".server.com"<em class=gr>);</em>
</pre></blockquote>
<p class=text>При таком ограничении заданной области видимости будут соответствовать домены с именами server.com, myservser.com, php.server.com и т. д., поскольку проверка на допустимость области видимости домена осуществляется по принципу концевого соответствия.</p>
<h2 class=p1>Отправка cookies по защищенному запросу</h2>
<p class=text>Не является излишним для cookie, хранящему секретные данные, разрешить отвечать только на защищенные запросы HTTP, так как в этом случае значительно затрудняется перехват данных, которыми обмениваются клиент и сервер. Для обеспечения защищенного соединения, функции <b>setcookie</b> передается шестой параметр со значением, равным 1:</p>
<blockquote><pre>
  <b>setcookie</b><em class=gr>(</em>"name", <b>$value</b>, <b>time</b><em class=gr>()</em> + 600, "/web/", ".server.com", 1<em class=gr>);</em>
</pre></blockquote>
