По некоторым данным термин Cookie появился в те времена, когда зарождалась знаменитая UNIX, где для обмена данными применялись так называемые "квитанции" (token, ticket), и некоторые из них, имеющие определенные ключевые значения, назывались Magic Cookies. В дальнейшем Cookie служили для решения определенных проблем спецификации. Основная проблема описанного протокола — непостоянное соединение между клиентом и сервером, то есть при передаче данных по HTTP посылается отдельный запрос для каждого документа. Cookie — небольшой информационный блок, который при загрузке сайта передается клиентскому браузеру, и благодаря компьютеру пользователя частично решает возникшие затруднения. Данная информация обычно хранится некоторое время (от одной сессии до нескольких месяцев) и передается серверу с каждым запросом как часть HTTP-заголовка. Если материал сохраняется продолжительное время, то обычно в виде файла cookie.txt, расположенного в рабочей директории той папки, в которой находится установленный браузер. Эмуляция сессии по HTTP-протоколу с помощью cookie вкратце выглядит так: при первом запросе документа выдается определенное значение cookie, которое при каждом повторном запросе считывается из HTTP_COOKIE и соответствующим образом обрабатывается.
Возможности использования
Сами cookie ничего не делают, так как представляют собой блок текстовой информации. Однако сервер, считывая полученную из них информацию и анализируя ее, может совершать те или иные действия. Пример повседневного их использования — авторизация доступа к различным e-mail и другим серверам. В этом случае в cookie сохраняется (иногда только в течение сессии, но иногда и более длительное время) имя пользователя и пароль, что позволяет юзеру не вводить их при повторном обращении к сервису или документу. Достаточно часто возможности cookie приспосабливают к оформлению заказов в онлайн-магазинах. В этом случае сервер "записывает" в cookie информацию о выбранных покупателем товарах и оформляет покупку сразу нескольких единиц. Благодаря cookie можно персонализировать сообщения и целые web-страницы. Другая важная особенность сервиса — применение его функций для получения различных статистических данных, учета их использования, сведений о баннерной активности и т. п.
Мифология
В недалеком прошлом велось много разговоров о вредоносности cookie. Утверждали, будто с их помощью без ведома и согласия пользователя на его диск записывается какая-то информация. Некоторые заявляли, что благодаря функциям cookie даже можно считать любую информацию с машины. Действительно, можно выяснить, какой браузер вы используете, и на основе полученной сервером информации направить пользователей Explorer’а на одну страницу, а Netscape — на другую. Но в этом и подобных алгоритмах cookie применяет формы взаимодействия не только и не столько с машиной, сколько с пользователем посредством машины. То есть фактически, заполняя web-формы, вы параллельно формируете определенные cookie, которые и будут играть определяющую роль в последующих обращениях к сайту или документу. В любом случае, все современные версии браузеров контролируют прием и могут запретить cookie.
Держите браузер
Netscape Navigator одним из первых начал поддерживать cookie, в этом же ряду надо вспомнить и Internet Explorer. По поводу остальных браузеров что-либо сказать определенное затрудняюсь, так как "лично" с ними не сталкивался.
Способ применения
В работе с cookie можно использовать Perl/CGI, Java Script, МЕТА-тэги HTML. Мы рассмотрим, как выставить cookie c помощью JS и MЕТА-тэгов.
Тем, у кого имущество ограничивается маленьким сайтом и небольшим количеством web-страниц, проще всего вставить cookie — включить в раздел <HEAD>…</HEAD> соответствующий тэг:
<META HTTP-EQUIV="Set-Cookie" CONTENT="NAME=value; EXPIRES=date; DOMAIN=domain_name; PATH=path; SECURE">
Минимальное описание поля Set-Cookie HTTP заголовка:
Set-Cookie: NAME=VALUE
Где:
? NAME=VALUE — строка буквенно-цифровых символов, исключающая использование запятых, двоеточий, пробелов и переводов строки. NAME — имя cookie, VALUE — значение;
? expires=DATE — время, до котрого следует хранить cookie, в формате "expires=Monday, DD-Mon-YYYY HH:MM:SS GMT". Если этот атрибут не указан, то cookie сохраняется в течение одного сеанса до закрытия браузера;
? domain=DOMAIN_NAME — домен, для которого значение cookie действительно. Например, при указании "domain=beloffcenter.net", значение cookie будет действительно и для домена www.beloffcenter.net, и для beloffcenter.net. Данный атрибут действителен для доменов com, edu, org, net, gov, mil, int, firm, shop,web,info. Если он опущен, то по умолчанию используется доменное имя сервера, на котором задали значение cookie;
? path=PATH — данный атрибут устанавливает подмножество документов, для которых действительно значение cookie. Например, указание "path=/price" приведет к тому, что значение cookie окажется действительным для множества документов в директории /price, /prices и файлов в текущем каталоге с именами типа price.htm и prices.htm. Для того, чтобы cookie отсылались при каждом запросе к серверу, укажите корневой каталог сервера "path=/". Если этот атрибут не зафиксирован, то значение cookie распространяется только на документы в той же директории, что и документ, в котором было установлено значение cookie;
? secure — если стоит данный маркер, то информация cookie пересылается только через HTTPS (HTTP с использованием SSL — Secure Socket Level) в защищенном режиме. Если его нет, то информация пересылается обычным способом.
Можно установить несколько cookie одновременно, для этого необходимо повторить установочный тэг для каждого из них:
<META HTTP-EQUIV="Set-Cookie" CONTENT="NAME=value; EXPIRES=date; DOMAIN=domain_name; PATH=path; SECURE">
<META HTTP-EQUIV="Set-Cookie" CONTENT="NAME=value; EXPIRES=date; DOMAIN=domain_name; PATH=path; SECURE">
В случае если cookie принимает новое значение при уже имеющемся в браузере, причем с совпадающими параметрами NAME, domain и path, то старое значение заменяется новым. В остальных случаях новые добавляются к старым. Использование expires не гарантирует сохранность cookie в течение заданного периода времени, поскольку клиентский браузер может удалить запись из-за нехватки выделенного места или по другим причинам. Браузеры имеют следующие ограничения для cookies: всего может храниться до 300 значений; каждый cookie не должен превышать 4 Кб; с одного сервера или домена может храниться до 20 значений. В случае кэширования документов, например, proxy-сервером, поле Set-cookie HTTP заголовка никогда не кэшируется. Если proxy-сервер принимает ответ, содержащий поле Set-cookie в заголовке, предполагается, что поле доходит до клиента вне зависимости от кода возврата Not Modified или OK. Соответственно, если клиентский запрос содержит в заголовке Cookie, то он должен дойти до сервера, даже если жестко установлен параметр If-modified-since.
Пример. Управление документами с ограниченным сроком годности
Браузер запрашивает документ и принимает от сервера в ответ:
Set-Cookie: NAME=beloffcenter.net; path=/;
expires=Wednesday, 10-Jan-01 23:59:59 GMT
// Когда браузер запрашивает URL с путем "/" на этом сервере, он посылает ему
Cookie: NAME=beloffcenter.net
//Браузер запрашивает документ и принимает от сервера в ответ:
Set-Cookie: NUM_ONE=Link_1; path=/
// Когда браузер запрашивает URL с путем "/" на этом сервере, он посылает серверу уже два значения cookie:
Cookie: NAME=beloffcenter.net;
NUM_ONE=Link_1
// Сервер установил еще одно значение cookie, на этот раз с другой областью действия:
Set-Cookie: NUM_TWO=EXPORT; path=/shop
// Теперь браузер, запрашивая URL с путем "/" на этом сервере, посылает лишь два значения cookie:
Cookie: NAME=beloffcenter.net;
NUM_ONE=Link_1
// и лишь при запросе браузером документов с путем "/shop" на этом сервере посылаются все три значения cookie:
Cookie: NAME=beloffcenter.net;
NUM_ONE=Link_1 ; NUM_TWO=EXPORT
// После закрытия браузера в файле cookies.txt останется только одно значение cookie:
NAME=beloffcenter.net
поскольку только для него установлен срок годности — 10 января 2001 года. Все остальные значения не будут сохранены.
Значения cоokie можно задавать также с помощью JavaScript. К сожалению, некоторые браузеры (кроме IE и NN) не поддерживают такой способ работы с cookie.
При использовании JS для работы с cookie применяются следующие значения:
// name — имя cookie
// value — значение cookie
// expires — дата окончания действия cookie
(по умолчанию — до конца сессии)
// path — путь, для которого cookie действительно
(по умолчанию — документ, в котором значение было
установлено)
// domain — домен, для которого cookie действительно
(по умолчанию — домен, в котором значение было
установлено)
// secure — логическое значение, показывающее требуется ли защищенная передача значения cookie
Ниже представлен практический пример cookie на JS (с описанием функций) для организации персонализированных web-страниц. Вы можете в "Блокноте" записать данный скрипт, сохранить его в html-формате и поэкспериментировать с ним.
<SCRIPT LANGUAGE="JavaScript1.1">
// Здесь указана версия 1.1, но более старшие также поддерживаются.
// Функция: создает cookie для документа document, с названием name и
// необязательными признаками hours, path, domain, secure
function Cookie(document, name, hours, path, domain, secure)
{
// Обратите внимание: все определенные названия объектов всегда начинаются с "$",
// для того чтобы отличать их от значений, которые будут записаны в cookie.
this.$document = document;
this.$name = name;
if (hours)
this.$expiration = new Date((new Date()).getTime() + hours*240);
else this.$expiration = null;
if (path) this.$path = path; else this.$path = null;
if (domain) this.$domain = domain; else this.$domain = null;
if (secure) this.$secure = true; else this.$secure = false;
}
// Эта функция сохраняет Cookie
{
// Вначале, производится запрос к существующим cookie,
// определяются их свойства
var cookieval = "";
for(var prop in this) {
// Игнорируются свойства с названиями, отличными от запрашиваемых
if ((prop.charAt(0) == '$') || ((typeof this[prop]) == 'function'))
continue;
if (cookieval != "") cookieval += '&';
cookieval += prop + ':' + escape(this[prop]);
}
// Теперь, когда у нас есть значения cookie, собираем их вместе в одном
// файле, который включает название, признаки и другие необходимые атрибуты
var cookie = this.$name + '=' + cookieval;
if (this.$expiration)
cookie += '; expires=' + this.$expiration.toGMTString();
if (this.$path) cookie += '; path=' + this.$path;
if (this.$domain) cookie += '; domain=' + this.$domain;
if (this.$secure) cookie += '; secure';
// Теперь записывается cookie, устанавливаются свойства Document.cookie
this.$document.cookie = cookie;
}
// Эта функция записывает метод работы Cookie
{
// Сначала, запрашивается список всех cookie, которые
// принадлежит этому документу.
// Это делается, путем чтения значений cookie.
var allcookies = this.$document.cookie;
if (allcookies == "") return false;
// Запрашиваются только указанные cookie из общего списка
var start = allcookies.indexOf(this.$name + '=');
if (start == -1) return false; // cookie не определено для данной страницы.
start += this.$name.length + 1; // поиск названия и соответствующей записи.
var end = allcookies.indexOf(';', start);
if (end == -1) end = allcookies.length;
var cookieval = allcookies.substring(start, end);
// Теперь, когда мы определили значения данного cookie, редактируем его —
// чтобы изменить индивидуальные атрибуты
//(названия и значения)
var a = cookieval.split('&');
for(var i=0; i < a.length; i++)
a[i] = a[i].split(':');
// Теперь у нас имеется подготовленный cookie, в который
// записываются все необходимые названия и значения.
for(var i = 0; i < a.length; i++) {
this[a[i][0]] = unescape(a[i][1]);
}
}
// Эта функция записывает Cookie
{
var cookie;
cookie = this.$name + '=';
if (this.$path) cookie += '; path=' + this.$path;
if (this.$domain) cookie += '; domain=' + this.$domain;
cookie += '; expires=Tue, 02-Jan-2001 00:00:00 GMT';
this.$document.cookie = cookie;
}
// Создается прототип cookie, который можно
// использовать в виде своеобразного шаблона для описания функций
new Cookie();
Cookie.prototype.store = _Cookie_store;
Cookie.prototype.load = _Cookie_load;
Cookie.prototype.remove = _Cookie_remove;
//===========
// Верхняя часть кода определяет JSclass Cookie.
// Нижняя часть использует этот JSclass.
//===========
// Создаем cookie, которое будет использоваться для данной страницы.
// В этом примере мы указываем path=/, чтобы использовать cookie для всех
// запрашиваемых документов из указанной директории. Поэтому, cookie должен
// иметь уникальное имя, отличное от других названий.
// Обратите внимание: мы устанавливаем срок действия cookie 10 дней.
var visitordata = new Cookie(document, "name_color_count_state", 240);
// Сначала пробуем прочитать данные, записанные в имеющихся cookie.
// Если cookie не определено, либо не содержит данных, мы запрашиваем
// информацию у пользователя
if (!visitordata.load() || !visitordata.name || !visitordata.color) {
visitordata.name = prompt("Как Вас зовут:", "");
visitordata.color = prompt("Выберите любимый цвет:", "");
// данная функция позволяет пользователю выбрать цвет текста.
// Цвет надо указывать только на английском языке: red, black, green etc.
}
// Выясняем, сколько раз данный пользователь посещал эту страницу:
if (visitordata.visits == null) visitordata.visits = 0;
visitordata.visits++;
// Записываем значения cookie, даже если они уже были записаны, так что
// срок действия будет повторно установлен на 10 дней от момента последнего
// посещения, а счетчик продолжать учитывать количество посещений
visitordata.store();
// Теперь мы можем прочитать переменные
document.write('<FONT SIZE=7 COLOR="' + visitordata.color + '">' +
'Добро пожаловать, ' + visitordata.name + '! Я рад приветствовать Вас
на этой странице. Успехов Вам в изучении cookie.' +
'</FONT>' +
'<P>Вы посетили эту страницу ' + visitordata.visits + ' раз(а).');
</SCRIPT>
// Данная функция аналогична кнопке RESET и позволяет стереть
// регистрационные данные cookie (имя пользователя и выбранный цвет)
<FORM>
<INPUT TYPE="button" VALUE="Forget My Name" onClick="visitordata.remove();">
</FORM>
Приведенный здесь пример можно взять за основу для создания собственных моделей cookie