Лекция

Тема: «Работа с датами в PHP. Сессии и cookie»

План.

1. Работа с датами в PHP

2. Получение текущего времени и даты в PHP

3. Преобразование формата даты и времени в PHP

4. Преобразование даты и времени в формат timestamp

5. Проверка корректности даты в PHP

6. Функция strtotime

7. Добавление и вычитание дат

8. Сессии в PHP

9. Примеры решения задач по сессиям

10. Cookies в PHP

11. Примеры решения задач на cookie

 

1. Работа с датами в PHP

 

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

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

В PHP работа с датой сталкивается с Unix Timestamp. Здесь время хранится целым числом. Исчисление времени начинается с 1 января 1970 года. Поэтому, например, дата и время 11.12.2014 19:40:00, будет представлено числом 1418316000. Эта цифра показывает, сколько секунд прошло с нулевой даты 1 января 1970 года, названой Эпохой Unix (эпохой зарождения Unix).

 

2. Получение текущего времени и даты в PHP

 

Для получения текущего времени сервера используется функция

time()

которая возвращает значение времени в формате unix timestamp. Функция возвращает количество секунд, прошедших с начала Эпохи Unix (c 1 января 1970 00:00:00 GMT) до текущего времени.

Функция не предназначена для вывода результата в виде даты или времени, а используется совместно с другими функциями.

Пример использования функции в «чистом виде»:

 

$now = time(); // метка текущей даты

echo $now; // выведет что-то в виде 1601207917 – вывод текущего времени в формате unix timestamp, соответствующего дате и времени 27.09.2020 14:58:00

$nextWeek = time() + (7 * 24 * 60 * 60); // к текущему времени добавит 7 дней; 24 часа; 60 минут; 60 секунд

echo $nextWeek; // выведет что-то в виде 1601812717

 

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

 

3. Преобразование формата даты и времени в PHP

 

Функция getdate()

Простейший механизм, позволяющий преобразовать числовое значение даты на более понятные значения, предоставляется функцией:

getdate(количество секунд)

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

 

seconds           секунды (0-59)

minutes           минуты (0-59)

hours              часы (0-23)

mday              день месяца (1-31)

wday               день недели (0-6), начиная с воскресенья

mon                месяц (1-12)

year                год

yday                день года (0-365)

weekday         название дня недели (например, Monday)

month             название месяца (например, January)

0                      количество секунд, прошедших с начала Эпохи Unix

 

Полученный массив, позволяет вывести значения нужном виде:

 

$date = 1418372345; // исходное дата и время 12.12.2014 11:19:05

$date_mas = getdate($date);

echo $date_mas['mday'] . ' . ' . $date_mas['mon'] . ' . ' . $date_mas['year']; // 12.12.2014

 

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

 

<?php

  $datetime = getdate();

  echo $datetime['year'];

?>

 

В результате, Вы увидите текущий год 2020-ый.

 

Функция date()

Так же для преобразования формата даты и времени можно воспользоваться функцией:

date(формат вывода [, дата])

 

Она предназначена для получения текущей даты unix timestamp в нужном формате. Вторым параметром функции можно задать ту дату, с КОТОРОЙ будет производиться работа. Он необязательный, поэтому, если его не указать, будет использоваться текущая дата и время.

Формат задается следующими значениями:

a          "до" и "после" полудня: "am" или "pm"

A         "до" и "после" полудня заглавными буквами: "AM" или "PM"

d          день месяца 2 цифрами (если меньше 10, на первом месте ноль) (от 01 до 31)

D         день недели 3 буквами. Например, "Mon" (понедельник)

j           день месяца, 1-2 цифры без начальных нулей (от 1 до 31)

F         название месяца. Например, "January"

h          час, 12-часовой формат (от 01 до 12)

H         час, 24-часовой формат (от 00 до 23)

g          час, 12-часовой формат без нулей (от 1 до 12)

G         час, 24-часовой формат без нулей (от 0 до 23)

i           минуты (от 00 до 59)

I         (заглавная i)   1, если действует переход на летнее время, иначе 0

L         1, если год високосный, или 0 если не високосный

B         время в формате Интернет-времени (альтернативной системы отсчета времени суток) (от 000 до 999)

T         временная зона компьютера. Например, MDT

l          (строчная L)  день недели. Например, "Monday"

m         месяц, две цифры с нулями (от 01 до 12)

n          месяц, одна-две цифры без нулей (от 1 до 12)

M        сокращенное наименование месяца. Например, "Jan"

t           число дней в указанном месяце (от 28 до 31)

s          секунды (от 0 до 59)

S          англоязычный порядковый суффикс числа из двух букв ("st", "nd", "rd" или "th")

U         целое число секунд, прошедших с момента начала эпохи UNIX

y          год, цифровой, 2 цифры (14)

Y         год, цифровой, 4 цифры (2014)

z          порядковое число дня в году (от 0 до 365)

Z         смешение временной зоны в секундах (от -43200 до 43200)

N         порядковый номер дня недели от 1 (понедельник) до 7 (воскресенье) в соответствии со стандартом ISO-8601, (добавлен в версии PHP 5.1.0)

w         порядковый номер дня недели от 0 (воскресенье) до 6 (суббота)

W        порядковый номер недели года в соответствии со стандартом ISO-8601; недели начинаются с понедельника (добавлено в версии PHP 4.1.0)

o          номер года в соответствии со стандартом ISO-8601. Имеет то же значение, что и Y, кроме случая, когда номер недели ISO (W) принадлежит предыдущему или следующему году; тогда будет использован год этой недели. (добавлен в версии PHP 5.1.0)

e          код шкалы временной зоны. Например: UTC, GMT, Atlantic/Azores (добавлен в версии PHP 5.1.0)

O         разница с временем по Гринвичу, в часах. Например: +0200

P         разница с временем по Гринвичу с двоеточием между часами и минутами. Например: +02:00 (добавлено в версии PHP 5.1.3)

c          дата в формате стандарта ISO 8601. Например, 2014-12-12T15:19:21+00:00 (добавлено в PHP 5)

r          дата в формате » RFC 2822. Например: Thu, 21 Dec 2000 16:01:07 +0200

U         количество секунд, прошедших с начала Эпохи Unix (The Unix Epoch, 1 января 1970 00:00:00 GMT)

 

Примеры по работе с date:

 

<?php

            //Все примеры показаны для даты 27.09.2020 в 15:11:59, воскресенье

            echo date('Y'); //вернет '2020'

            echo date('y'); //вернет '20'

            echo date('m'); //вернет '09' - номер месяца

            echo date('M'); //вернет 'Sep' - название месяца (September)

            echo date('d'); //вернет '27' - номер дня в месяце

            echo date('w'); //вернет '0' - воскресенье

            echo date('H'); //вернет '15' - часы по 24 часовому формату

            echo date('h'); //вернет '03' - часы по 12 часовому формату

            echo date('i'); //вернет '11' - минуты

            echo date('s'); //вернет '59' - секунды

            echo date('d-m-Y'); //вернет '27-09-2020'

            echo date('d.m.y'); //вернет '27.09.20'

            echo date('H:i:s d.m.Y'); //вернет '15:11:59 27.09.2020'

?>

 

C помощью функции date можно получить много полезных данных о дате. Например:

 

$date = 1600369998; // исходное дата и время 17.09.2020 22:13:18

echo date('d.m.Y', $date); // 17.09.2020 (дата)

echo date('H:i:s', $date); // 22:13:18 (время)

echo date('H:i', $date); // 22:13 (время)

echo date('t', $date); // 30 (число дней в месяце)

echo date('z', $date); // 260 (порядковый номер дня в году)

echo date('l dS \of F Y h:i:s A', $date); // Thursday 17th of September 2020 10:13:18 PM

 

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

 

echo date('Сегодня z-й день Y-го года', $date); // Сегодня 260-й день 2020-го года

 

Пример: вывести текущую дату и дату, которая должна быть ровно через неделю

 

$now = time();  //задание текущей даты в формате timestamp

//определение даты, которая будет через неделю, в формате timestamp

$nextWeek = time() + (7 * 24 * 60 * 60);

//вывод текущей даты – 1 способ

echo 'Сейчас: '. date('Y-m-d') ."\n";

//вывод текущей даты – 2 способ

echo 'Сейчас: '. date('Y-m-d', $now) ."\n";

//вывод даты следующей недели

echo 'Следующая неделя: '. date('Y-m-d', $nextWeek) ."\n";

 

4. Преобразование даты и времени в формат timestamp

 

Для обратного преобразования даты из стандартного формата в числовое значение timestamp применяется функция mktime.

Функция mktime работает аналогично функции time, но, в отличие от нее, принимает параметры:

mktime(час, минута, секунда, месяц, день, год)

(обратите внимание на то, что месяц и день переставлены местами)

 

Функция mktime() возвращает значение времени Unix, соответствующую дате и времени, заданным аргументами. Например:

<?php

            //Функция вернет timestamp для 31 января 2020 года, 12 часов, 43 минуты, 59 секунд

     echo mktime(12, 43, 59, 1, 31, 2020);

?>

 

Следует внимательно относится к порядку аргументов функции: часы, минуты, секунды, месяц, день, год.

Кроме простого формирования значения даты в timestamp, функцию mktime() можно использовать для арифметических вычислений с датами. Для этого просто можно ввести необходимые аргументы. Например, если указать 14 месяц, то в итоговом значении, месяц будет 2-й, а значение года увеличится на единицу:

 

//задание значений для дня, месяца и года

$my_day = 6;

$my_month = 11;

$my_year = 2020;

//изменение даты, прибавив к месяцу 5

$new_date = mktime(0, 0, 0, $my_month + 5, $my_day, $my_year);

echo date('d.m.Y', $new_date); // вывод новой даты 06.04.2021

 

Аналогично можно поступать и с другими параметрами.

Параметры у функции mktime можно опускать с конца. Если мы не напишем год (последний параметр), то автоматически возьмется текущий год, если не напишем еще и день (предпоследний параметр), то возьмется текущий день и текущий год. И так далее:

<?php

     //Функция вернет timestamp для 31 января текущего года, 12 часов, 43 минуты, 59 секунд:

     echo mktime(12, 43, 59, 1, 31);

 

            //Функция вернет timestamp для текущего дня января текущего года, 12 часов, 43 минуты, 59 секунд:

     echo mktime(12, 43, 59, 1);

 

     //Функция вернет timestamp текущего дня, текущего месяца, текущего года, 12 часов, 43 минуты, 59 секунд:

            echo mktime(12, 43, 59);

?>

 

Пример. Найти разницу в секундах между текущим моментом времени и полуднем (12 часов, 0 минут, 0 секунд) 1-го февраля (февраль – это месяц номер 2) 2000 года:

 

<?php

            /* Функция time() вернет текущий момент времени в формате timestamp,

            а mktime - за заданную дату.

            Отнимем результаты друг от друга и получим разницу в секундах:

            */

     echo time() - mktime(12, 0, 0, 2, 1, 2000);

?>

 

Полученная разница в секундах будет выглядеть так: 651804002 (обновите страницу и это число поменяется).

Пример.

 

<?php

     echo date('d-m-Y', mktime(0, 0, 0, 12, 29, 13)); //вернет '29-12-2013'

?>

 

Этим можно воспользоваться, чтобы узнать номер дня недели за определенную дату – просто передадим ее вторым параметром с помощью функции mktime, а первым параметром поставим управляющий символ 'w':

 

<?php

            //Узнаем какой день недели был 29-12-2013:

            echo date('w', mktime(0, 0, 0, 12, 29, 13)); //вернет '0' - воскресенье

?>

 

5. Проверка корректности даты в PHP

 

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

checkdate(int month, int day, int year)

 

Возвращает true если дата, заданная аргументами, является правильной; иначе возвращает false. Дата считается правильной, если:

- год в диапазоне от 1 до 32767;

- месяц в диапазоне от 1 до 12;

- день для заданного месяца с учетом высокосного года указаны правильно.

 

Пример проверки даты:

$my_day = 32;

$my_month = 12;

$my_year = 2014;

if (!checkdate($my_month, $my_day, $my_year))

     echo 'Ошибка: дата указана некорректно';

 

6. Функция strtotime

 

Функция strtotime - это аналог функции mktime (тоже возвращает timestamp), только в отличие от нее принимает дату в более свободном формате.

 

К примеру, ей можно передать строку '2025-12-31' и функция сама разберет, где тут год, где месяц, а где день, и вернет эту дату в формате timestamp.

 

Что можно делать еще: можно написать так – strtotime('now') - и мы получим текущий момент времени, или так – strtotime('next Monday') – и мы получим следующий понедельник (Monday по-английски 'понедельник').

 

Примеры работы:

 

<?php

     echo strtotime("now");   //выведет время в формате timestamp (например, 1601410373)

     echo strtotime("10 September 2000");   //выведет 968529600

     echo strtotime("+1 day");    //добавит 1 день к текущему

     echo strtotime("+1 week");   //добавит 1 неделю к текущей дате

     echo strtotime("+1 week 2 days 4 hours 2 seconds"); //добавит 1 неделю 2дня 4 часа и 2 секунды к текущей дате

     echo strtotime("next Thursday");  //определит дату следующего четверга

     echo strtotime("last Monday");    //определит дату предыдущего понедельника

?>

 

Следующий код вернет дату предыдущего понедельника в формате дд.мм.гггг:

 

<?php

     echo date('d-m-Y', strtotime("last Monday"));

?>

 

7. Добавление и вычитание дат

 

Чтобы отнять или прибавить к дате определенный промежуток времени, следует пользоваться комбинацией из трех функций: date_create – она подготавливает дату к работе (дата должна быть в формате год-месяц-день) создавая так называемый объект дата, с которым производятся дальнейшие манипуляции, date_modify – она прибавляет или отнимает, date_format – она выводит получившуюся дату в заданном формате.

 

Пример. Создадим объект с датой за 2025 год, 12 месяц, 31 день, затем прибавим к ней 1 день и выведем в формате 'день.месяц.год'

 

<?php

     $date = date_create('2025-12-31');

     date_modify($date, '1 day');

     echo date_format($date, 'd.m.Y');

?>

 

Результат выполнения кода: 01.01.2026

 

Пример. Создадим объект с датой за 2025 год, 12 месяц, 31 день, затем прибавим к ней 3 дня и выведем в формате 'день.месяц.год'

 

<?php

     $date = date_create('2025-12-31');

     date_modify($date, '3 days');

     echo date_format($date, 'd.m.Y');

?>

 

Результат выполнения кода: 03.01.2026

 

Пример. Создадим объект с датой за 2025 год, 12 месяц, 31 день, затем прибавим к ней 3 дня и 1 месяц и выведем в формате 'день.месяц.год'

 

<?php

     $date = date_create('2025-12-31');

     date_modify($date, '3 days 1 month');

     echo date_format($date, 'd.m.Y');

?>

Результат выполнения кода: 03.02.2026

 

Пример. Создадим объект с датой за 2025 год, 1 месяц, 1 день, затем отнимем от нее 1 день и выведем в формате 'день.месяц.год'

 

<?php

     $date = date_create('2025-01-01');

     date_modify($date, '-1 day');

     echo date_format($date, 'd.m.Y');

?>

Результат выполнения кода: 31.12.2024

8. Сессии в PHP

 

Сессии и cookies предназначены для хранения сведений о пользователях при переходах между несколькими страницами. При использовании сессий данные сохраняются во временных файлах на сервере. Файлы с cookies хранятся на компьютере пользователя, и по запросу отсылаются браузером серверу.

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

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

При работе с сессиями различают следующие этапы:

§  открытие сессии

§  регистрация переменных сессии и их использование

§  закрытие сессии

 

Открытие сессии

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

Синтаксис:

session_start();

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

 

Регистрация переменных сессии

Сеансовые переменные всегда регистрируются в ассоциативном массиве $_SESSION.

 

$_SESSION['username'] = "maksim";

 

Выше приведенная команда означает, что в сессию записано имя пользователя "maksim". И обращение к переменной сессии осуществляется в виде: $_SESSION['username'].

Для корректной работы приложения необходимо проверять, установлены ли переменные сессии. Такую проверку можно сделать при помощи функций isset или empty:

При использовании ассоциативного массива $_SESSION нужно напрямую проверять элементы массива:

 

//если существует переменная сессии username

if(isset($_SESSION['username']))

или

//если не пуста переменная сессии username

if(!empty($_SESSION['username']))

 

Закрытие сессии

После завершения работы с сессией нужно вызвать функцию session_destroy(). Она уничтожает все данные, связанные с текущей сессией. Данная функция не удаляет какие-либо глобальные переменные, связанные с сессией и не удаляет сессионные cookie. Чтобы вновь использовать переменные сессии, следует вызвать session_start().

 

Пример простой сессии

Рассмотрим пример простой сессии, работающей с тремя страницами. При посещении пользователем первой страницы открывается сессия и регистрируется переменная $username:

 

<?

  session_start();

  $_SESSION['username'] = "maksim";

  echo "Привет, ".$_SESSION["username"]."<br>";

  echo "<a href='page2.php'>На следующую страницу</a>";

?>

 

Результат работы этого сценария показан на рисунке:

 

Image

 

После этого, пользователь нажимает на ссылку и попадает на страницу page2.php, код которой приведен в ниже:

 

<?

  session_start();

  echo $_SESSION["username"]." , ты пришел на другую страницу этого сайта!<br>";

  echo "<a href='page3.php'>На следующую страницу</a>";

?>

 

Результат работы этого скрипта показан на рисунке:

 

Image

 

При нажатии на ссылку, пользователь попадает на страницу page3.php, при этом происходит разрегистрация сеансовой переменной и уничтожение сессии. Соответствующий код реализации:

 

<?

  session_start();

  unset($_SESSION["username"]); // разрегистрировали переменную

  echo "Привет, ".$_SESSION["username"];

   // теперь имя пользователя уже не выводится

  session_destroy(); // разрушаем сессию

?>

 

Как видно из рисунка, после разрегистрации сеансовой переменной значение массива $_SESSION["username"] уже недоступно:

 

Image

 

9. Примеры решения задач по сессиям

 

Пример 1. Сделайте две страницы: index.php и hello.php. При заходе на index.php спросите с помощью формы имя пользователя, запишите его в сессию. При заходе на hello.php поприветствуйте пользователя фразой "Привет, %Имя%!".

 

Страница index.php:

<?php

            //Если форма была отправлена и имя не пустое:

     if (!empty($_REQUEST['username'])) {

          session_start(); //стартуем сессию

          $_SESSION['username'] = $_REQUEST['username']; //пишем в сессию

     }

?>

 

<form action="" method="GET">

     <input type="text" name="username">

     <input type="submit">

</form>

 

Страница hello.php:

<?php

     session_start(); //стартуем сессию

     //Если есть данные в сессии об имени пользователя:

     if (!empty($_SESSION['username'])) {

          echo $_SESSION['username']; //выведем имя на экран

     }

?>

 

Пример 2. Спросите у пользователя телефон с помощью формы. Затем сделайте так, чтобы в другой форме (поля: имя, фамилия, телефон) при ее открытии поле телефон было автоматически заполнено.

 

Спрашиваем телефон:

<?php

            //Если форма была отправлена и телефон не пустой:

     if (!empty($_REQUEST['phone'])) {

          session_start(); //стартуем сессию

          $_SESSION['phone'] = $_REQUEST['phone']; //пишем телефон в сессию

     }

?>

 

<form action="" method="GET">

     <input type="text" name="phone">

     <input type="submit">

</form>

 

Другая форма:

<?php

     session_start(); //стартуем сессию

     //Если телефон есть в сессии - запишем его в переменную $phone:

     if(!empty($_SESSION['phone']))

          $phone = $_SESSION['phone'];

     else

          $phone = '';

?>

 

<form action="" method="GET">

     <input type="text" name="name">

     <input type="text" name="surname">

            <!-- Заполним атрибут value переменной $phone: -->

     <input type="text" name="phone" value="<?php echo $phone ?>">

 

     <input type="submit">

</form>

 

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

 

<?php

     session_start(); //стартуем сессию

//если пустая сессия

if (empty($_SESSION['kol_update']))

//записываем в сессию значение 0, что означает 0 раз обновлялась страница

$_SESSION['kol_update']=0;

else //если сессия непустая

//наращиваем значение – счетчик числа обновлений страницы

$_SESSION['kol_update']++;

//выводим текст с количеством обновлений на странице

echo 'Количество обновлений страницы = '.$_SESSION['kol_update'];

?>

 

Пример 4. Запишите в сессию время захода пользователя на сайт. При обновлении страницы выводите сколько минут и секунд назад пользователь зашел на сайт.

 

<?php

session_start(); //стартуем сессию

//если сессия пустая

if (empty($_SESSION['seconds']))

//устанавливаем сессии текущее время

$_SESSION['seconds']=time();

else //если сессия существует

{

            //вычисляем разницу между текущим временем и временем захода пользователя на сайт

$s=time()-$_SESSION['seconds'];

//если количество секунд больше, чем 60

     if ($s>=60)

          {

                                    //считаем количество минут

                                    //округляем количество минут в меньшую сторону

$m=floor($s/60);

//вычисляем количество секунд

              $s=$s-$m*60;

              echo 'Вы зашли '. $m. ' минут '. $s. ' секунд назад';

          }

          else echo 'Вы зашли '. $s. ' секунд назад';

}

?>

 

10. Cookies в PHP

 

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

Cookies – это текстовые строки, хранящиеся на стороне клиента, и содержащие пары "имя-значение", с которыми связан URL, по которому браузер определяет, нужно ли посылать cookies на сервер.

Откуда возник термин "cookie" никто достоверно не знает, хотя считается, что во времена зарождения Unix-систем где-то использовалось словосочетание Magic Cookies. Имелись в виду "квитанции" (token, ticket), которыми обменивались программы.

Cookie является решением одной из наследственных проблем HTTP протокола (HyperText Transfer Protocol). Эта проблема заключается в непостоянстве соединения между клиентом и сервером, т.е. для каждого документа (или файла) при передаче по HTTP протоколу посылается отдельный запрос. Включение cookie в HTTP протокол дало частичное решение этой проблемы. Иначе говоря, транзакция завершается после того, как браузер сделал запрос, а сервер выдал соответствующий ответ. Сразу после этого сервер "забывает" о пользователе и каждый следующий запрос того же пользователя считает новым пользователем.

Используя cookie, можно эмулировать сессию по HTTP протоколу. Коротко принцип эмуляции сессии таков: на первом запросе выдается соответствующее значение cookie, а при каждом последующем запросе это значение читается из переменной окружения HTTP_COOKIE и соответствующим образом обрабатывается.

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

 

Установка cookies

Установка cookies производится с помощью функции setcookie().

Синтаксис:

  setcookie (string name[, string value[, int expire [, string path[, string domain[, int secure]]]]])

Эта функция имеет следующие аргументы:

·         name — имя устанавливаемого cookie;

·         value — значение, хранящееся в cookie с именем $name;

·         expire — время в секундах с начала эпохи, по истечение которого текущий cookie становится недействительным;

·         path — путь, по которому доступен cookie;

·         domain — домен, из которого доступен cookie;

·         secure — директива, определяющая, доступен ли cookie не по запросу HTPPS. По умолчанию эта директива имеет значение 0, что означает возможность доступа к cookie по обычному запросу HTTP.

 

Пример простого приложения с cookies

Создадим простой сценарий, подсчитывающий при помощи cookies количество обращений посетителя к странице.

В cookie с именем counter будет храниться число посещений страницы пользователем:

 

<?

  $counter++;

  setcookie("counter", $counter);

  echo "Вы посетили эту страницу ".$counter." раз";

?>

 

Результат выполнения сценария на рисунке:

 

Image

 

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

Рассмотрим этот вопрос подробнее, для чего модифицируем код, приведенный в листинге, поместив перед установкой cookie текст:

<p>

Если здесь поместить текст, то возникнет ошибка, так как

будет послан заголовок Content-type: text/html.

</p>

<?php

  $counter++;

  setcookie("counter",$counter);

  echo "Вы посетили эту страницу ".$counter." раз";

?>

 

При выполнении этого сценария выводится сообщение об ошибке:

 

Image

 

Заметим, что в этих листингах мы обращаемся к переменной $counter, в которой хранится значение cookie, как к глобальной. Значение, хранящееся в cookie можно получить через глобальные массивы $HTTP_COOKIE_VARS["name"] и $_COOKIE["name"]:

 

<?php

  $_COOKIE["counter"]++;

  setcookie("counter",$counter);

  echo "Вы посетили эту страницу ".$_COOKIE["counter"]." раз";

?>

 

Поскольку некоторые пользователи отключают cookie в настройках своих браузеров, для корректной работы, в приложение, использующее cookies, необходимо помещать код, проверяющий включены ли cookies у посетителя, и, если нет, то сообщающий ему о необходимости включить cookie:

 

<?php

if ( !isset($_GET["cookie"]) )

{

//устанавливаем cookie с именем "test"

setcookie ( "test", "1" );

//передаем через заголовки значение get-параметра cookie=1

header ( "Location: ".$_SERVER["PHP_SELF"]."?cookie=1" );

}

else

{

if ( !isset($_COOKIE["test"]) )

{

echo "<p>Для корректной работы приложения необходимо включить cookies</p>";

echo "<a href='".$_SERVER["PHP_SELF"]."'>Продолжить</a>";

}

else

{

// cookie включены, переходим на нужную страницу

header ( "Location: http://localhost/shop.php" );

}

}

?>

 

Установка срока годности cookies

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

Как уже говорилось, срок годности устанавливается в секундах относительно начала эпохи Unix. В PHP существуют функции time и mktime для работы с датой и временем, позволяющие переводить текущее время в количество секунд с начала эпохи.

Примеры установки сроки годности cookies:

 

<?

  // этот cookie действителен в течение 10 мин после создания

  setcookie("name", $value, time() + 60*10);

  // действие этого cookie прекращается в полночь 25 января 2022 года

  setcookie("name", $value, mktime(0,0,0,01,25,2022));

  // действие этого cookie прекращается в 18.00 25 января 2022 года

  setcookie("name", $value, mktime(18,0,0,01,25,2022));

?>

 

Удаление cookie

Для этого надо вызвать функцию setcookie и передать ей имя того cookie, который подлежит удалению:

setcookie("name");

 

Другие установленные cookie при этом не удаляются.

 

Проблемы безопасности, связанные с cookies

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

·         установка области видимости cookies;

·         шифрование;

·         ограничение доступа для доменов;

·         отправка cookies по защищенному запросу.

Наилучшим решением является комплексное применение всех этих способов.

 

Установка области видимости cookie

Поскольку, по умолчанию, доступ к cookie происходит из корневого каталога, это может создать "дыры" в системе защиты, так как cookie становятся доступными в любом подкаталоге этого каталога. Ограничить доступ к cookie для всех страниц, кроме расположенных в конкретном каталоге, к примеру, /web/, можно следующим образом:

 

setcookie("name", $value, "/web/");

 

Однако и в этом случае, к примеру, каталоги /web/index.php, /web1/page.html и т. д. будут удовлетворять этому ограничению. Если такое положение также является нежелательным, можно ограничить область видимости cookie до конкретной страницы:

 

setcookie("name", $value, "/web/index.php");

 

Однако и такой способ в полной мере не решает проблему, так как в этом случае доступ к информации, содержащейся в cookie, может получить, к примеру, скрипт /web/index.php-script/anti_cookie.php. Поэтому появляется необходимость в шифровании.

 

Шифрование

Применить шифрование к cookie можно разными способами, рассмотрим один из них:

 

<?php

  // создаем вектор начального состояния для шифрования

  $vector = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_CAST_256,

                             MCRYPT_MODE_CFB), MCRYPT_RAND);

  $key = "qwe233jk312jx813893xk312"; // ключ для расшифрования

  $cook_name = "maks";

  $cipher = mcrypt_encrypt(MCRYPT_CAST_256, $key, $cook_name,

                           MCRYPT_MODE_CFB, $vector);

  setcookie("username", $cipher, "/decrypt.php");

?>

 

Как видно из листинга, расшифровка cookie проводится при помощи скрипта decrypt.php, код которого приведен ниже:

 

<?

  // вектор начального состояния остается неизменным

  $vector = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_CAST_256,

                             MCRYPT_MODE_CFB), MCRYPT_RAND);

  $key = "qwe233jk312jx813893xk312";

  $decrypt_name = mcrypt_ decrypt(MCRYPT_CAST_256, $key, $username,

                                  MCRYPT_MODE_CFB, $vector);

  echo $decrypt_name.", мы рады видеть вас на нашей страничке!";

?>

 

Ограничение доступа для доменов

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

 

setcookie("name", $value, "/web/index.php", ".server.com");

 

При таком ограничении заданной области видимости будут соответствовать домены с именами server.com, myservser.com, php.server.com и т. д., поскольку проверка на допустимость области видимости домена осуществляется по принципу концевого соответствия.

 

Отправка cookies по защищенному запросу

Не является излишним для cookie, хранящему секретные данные, разрешить отвечать только на защищенные запросы HTTP, так как в этом случае значительно затрудняется перехват данных, которыми обмениваются клиент и сервер. Для обеспечения защищенного соединения, функции setcookie передается шестой параметр со значением, равным 1:

 

setcookie("name", $value, time() + 60*10, "/web/", ".server.com", 1);

 

Ограничения

Клиент (браузер) имеет следующие ограничения для cookies:

·         всего может храниться до 300 значений cookies

·         каждый cookie не может превышать 4Кбайт

·         с одного сервера или домена может храниться до 20 значений cookie

Если ограничение 300 или 20 превышается, то удаляется первая по времени запись. При превышении лимита объема в 4Кбайт корректность значения cookie страдает – отрезается кусок записи (с начала этой записи) равный превышению объема.

В случае кэширования документов, например, proxy-сервером, поле Set-cookie HTTP заголовка никогда не кэшируется.

Если proxy-сервер принимает ответ, содержащий поле Set-cookie в заголовке, предполагается, что поле доходит до клиента вне зависимости от кода возврата 304 (Not Modified) или 200 (OK). Соответственно, если клиентский запрос содержит в заголовке Cookie, то он должен дойти до сервера, даже если жестко установлен параметр If-modified-since.