Значение: строковое Чтение/Запись
Совместимость: WinLE3+, MacIE3+, NN2+, Mozl+, Safaril+
В Web-браузере механизм cookie-значений позволяет хранить небольшие объемы информации о компьютере клиента в довольно безопасной форме. Другими словами, если необходимо получить определенную информацию о клиенте во время загрузки различных HTML-документов (причем эта информация должна использоваться между сеансами запуска браузера), используют механизм cookie. Как правило, cookie применяется для хранения имени пользователя и пароля, который он вводит в соответствующее поле Web-узла, защищенного паролем. При первичном вводе данной информации в CGI-форму, используя Netscape Navigator, программа CGI производит запись информации в файлы cookie, сохраняемые на жестком диске пользователя (обычно после шифрования пароля). В следующий раз, когда пользователь решит перейти на тот же узел, ему не нужно будет опять вводить свои данные. Сервер найдет cookie-файл, сохраненный именно для этого сервера, и извлечет содержащиеся там регистрационное имя и пароль, которые затем будут введены автоматически.
Другие записи cookie сохраняют ссылки пользователя и информацию о предыдущем посещении узла. Ссылки могут включать также стили и размеры шрифта, а при желании пользователя их содержимое будет отображаться внутри набора фреймов. Временное хранение сведений о посещенных ранее документах позволяет вывести на экран выделенные другим цветом изображения рядом с содержимым, которое было изменено со времени последнего посещения пользователем этой страницы, даже если она неоднократно обновлялась. Перед тем как регистрировать "новые" состояния, возникшие с момента последнего посещения пользователем узла, сценарии "выделяют" новую информацию для пользователя.
Некоторые CGI-программы могут как считывать, так и записывать данные на жесткий диск пользователя. Вам необходимо решить, использовать их или нет. Механизм cookie, содержащийся в браузере, не позволяет использовать папки пользователя для всеобщего доступа (или проводить незаконные операции в них). Вместо этого он обеспечивает доступ только к одному определенному текстовому файлу (в NN/Mozilla/Safari) или набору текстовых файлов (в Internet Explorer), которые сохраняются в строго определенном месте жесткого диска пользователя (в зависимости от операционной системы).
Файл cookie представляет собой обычный текстовый файл (но в Netscape Navigator для Macintosh файл Magi с Cookie не текстовый, поэтому пользователи Macintosh могут открыть его только с помощью специальных приложений). Для того чтобы просмотреть cookie-файл, рекомендуется предварительно сделать копию в другой папке и только после этого его открывать. Любое изменение существующего файла может испортить содержащуюся в нем ценную запись, использование которой предоставляет доступ к регулярно посещаемому данным пользователем узлу. Формат данных cookie в Netscape Navigator и Internet Explorer разный, что зависит от разных методик, которые используются в них для регистрации cookie-записей. В файле Netscape Navigator (после нескольких закомментированных строчек, которые предупреждают о недопустимости изменения пользователем файла вручную) приводится текст в виде таблицы. Каждая строка содержит информацию одной записи. На первый взгляд, cookie-файл ничем не отличается от обычной базы данных. В Internet Explorer в cookie-файле сохраняются те же данные, что и в Netscape Navigator, но сами записи представлены в виде списка. Структура этих файлов не имеет особого значения для занесения в них данных, так как оба браузера используют одинаковый синтаксис чтения и записи, применяя свойство document.cookie.
Когда экспериментируют с записями браузера, то нередко возникает соблазн просмотреть cookie-файл после внесения в него новых данных, cookie-файл не будет содержать недавно записанных данных, так как сохранение проводится на диске только после того, как пользователь покидает браузер; и наоборот, cookie-файл может быть загружен в память браузера только при запуске последнего. Когда браузер работает, пользователь может считывать, записывать и удалять данные из cookie-файла. Но результаты его деятельности останутся в оперативной памяти (для ускорения обработки данных); сохранены они будут после завершения текущего сеанса.
Каждая cookie-запись содержит следующие "поля" (не обязательно в таком же порядке).
Заметьте, что записи зависят только от доменов. Другими словами, если запись создается одним доменом, другой домен не сможет считать эту запись, используя обычный cookie-формат. Поэтому совершенно безопасно хранить так называемые невосстанавливаемые пароли (пары имя пользователя-пароль, необходимые для доступа к некоторым узлам со свободной регистрацией) в записях. Кроме того, пароли к узлам, хранящиеся в записях, обычно имеют вид зашифрованных строк. Это усложняет доступ к информации, находящейся в cookie-файле, если компьютер оставлен без присмотра. Таким образом, вычислить личный пароль пользователя оказывается довольно трудно.
Кстати, cookie-запись имеет срок службы. Поскольку в некоторых браузерах количество записей ограниченно (300 в Netscape Navigator), cookie-файл может за несколько лет переполниться. Поэтому, если во время работы браузера планируется сохранять cookie-запись, автор этой записи должен установить срок ее службы. Браузеры автоматически удаляют "просроченные" записи.
Однако не все записи должны создаваться во время работы браузера. Сценарии, в которых используются временные записи, при работе с Web-узлами имеют сходную структуру. Многие коммерческие узлы создают одну или несколько временных cookie-переменных для дальнейшего занесения в них названий тех товаров, которые пользователь намеревается приобрести. Эти элементы содержатся в виде копии в определенной форме. Но после представления этой формы серверу, данные о клиенте, содержащиеся в ней, не будут иметь никакого определенного значения. Следовательно, если сценарий не определяет дату истечения срока службы записи, браузер продолжает записывать новые cookie в свою кэш-память, не занося их в cookie-файл. Когда пользователь покидает браузер, данные cookie исчезают, как это и предполагалось.
Доступ к записям cookie из JavaScript ограничен заданием cookie (с рядом необязательных параметров) и получением данных cookie (но уже без параметров).
Оригинальная объектная модель определяет cookie-записи как свойства документов, но такая формулировка не совсем корректна. При использовании заданного по умолчанию пути для установки cookie (текущая папка документа, при выполнении сценария из которого используется первая cookie-запись) все документы той же папки на том же сервере имеют доступ для записи и чтения к содержащимся там cookie-данным. Преимущество такого расположения состоит в следующем: если есть приложения, представленные несколькими документами, и все они обслуживаются из одной папки, то данные cookie могут использоваться ими совместно. Однако Netscape Navigator и Internet Explorer установили ограничение: 20 cookie-записей для каждого домена; в IE3 задается еще более строгое ограничение для одной записи (одна пара имя-значение) на домен. Если пользователя не устраивают поставленные условия, то ему необходимо найти другой способ записи cookie-данных.
Для записи данных в cookie-файл в JavaScript используется простой оператор, который назначает свойству document. cookie определенное значение. Но форматирование данных является ключевым моментом в осуществлении доступа к записям. Существует определенный синтаксис для переопределения cookie (необязательные элементы заключены в квадратные скобки).
document.cookie = "имяСооkiе = ДанныеСооkiе [; expires = времяФорматаGМТ] [; path=пyть] [; domain=имяДомена] [; secure]"
document.cookie = "userName=Fred";
Если браузер не находит cookie-записи с таким именем в текущем домене, он создает ее автоматически; если запись с таким именем уже существует, браузер просто заменяет ее старые данные новыми. Поиск document. cookie в этом пункте выдает следующую строку.
userName=Fred
Можно пренебречь другими параметрами cookie-записей, в этом случае браузер использует значения по умолчанию, более подробно этот процесс описан в следующем абзаце. Для создания временных cookie (которые не должны сохраняться после выключения браузера) кроме набора имя-значения, обычно больше ничего не используют.
Полный набор такого типа должен быть представлен строкой, не содержащей точек с запятой, просто запятых или символов пробелов. Для того чтобы убрать пробелы между словами, предварительно обработайте значение записи функцией JavaScript escape(), которая переведет пробелы в ASCII-код, равный %20 (примените функцию unescape(), чтобы убедиться в правильности восстановления пробелов в случае возникновения такой необходимости).
Нельзя сохранять массив или объект JavaScript в cookie-записи. С помощью метода Array.join() преобразуйте массив в строку; используйте String.split() для создания этого массива заново после последнего прочтения полученной cookie-записи. Эти два метода доступны в NN3+, Mozillal+ и IE4+.
Устанавливаемая дата срока службы записи должна соответствовать значению времени по Гринвичу (Greenwich Mean Time — GMT). Чтобы вычислить дату истечения срока службы записи, основанную на сегодняшней дате, используйте объект Date, представленный в JavaScript, следующим образом.
var exp = new Date(); var oneYearFromNow = exp.getTime() + (365 * 24 * 60 * 60 * 1000); exp.setTime(oneYearFromNow);
Затем преобразуйте дату в принятый строковый формат GMT.
document.cookie = "userName=Fred; expires=" + exp.toGMTString();
В cookie-файле срок службы и время хранятся как числовые значения (в секундах), но для их установки необходимо использовать формат времени соответственно GMT. cookie-запись можно удалить прежде, чем истечет срок ее службы — установите для данной записи новый срок, уже прошедший относительно текущего времени и даты. Самый безопасный параметр срока хранения приведен ниже.
expires=Thu, Ol-Jan-70 00:00:01 GMT
Отсутствие даты срока службы сообщает браузеру о том, что эта cookie-запись является временной. Таким образом, браузер не записывает ее в cookie-файл, а при следующем запуске этого браузера она не будет существовать в его буфере.
Для cookie-записей, осуществляемых стороной клиента, наиболее удобно принять путь, заданный по умолчанию (в текущей папке). Конечно, можно создать дополнительную копию cookie в другой папке (для другого домена), таким образом, одни и те же данные будут доступны документу, расположенному в другой области Web-узла (или вообще сети).
Для синхронизации cookie-данных с определенным документом (или их группой) браузер определяет домен текущего документа и помещает в cookie-файл записи, соответствующие этому домену. Поэтому, если пользователь собирается просмотреть список всех cookie-данных, содержащихся в свойстве document. cookie, он должен просмотреть все наборы имя-значение, находящиеся в cookie-файле, с именем домена текущего документа. Если пользователь уверен, что документ не будет скопирован на другой сервер в пределах его домена, он может и не использовать параметр domain при сохранении cookie-записей. Автоматическое определение домена текущего документа и занесение его в cookie-файл производится по умолчанию. Необходимо знать, что в формате представления домена должно содержаться по крайней мере две точки.
.mcom.com .hotwired.corn
В противном случае нужно записать полный URL-адрес домена, включая протокол http://.
Если при сохранении cookie-записи параметр SECURE отсутствует, подразумевается, что cookie-данные доступны для любого документа или CGI-программы, которая находится в узле пользователя, определяет другой домен и соответствующий ему путь. В процессе создания cookie-записей на стороне клиента при сохранении cookie этот параметр опускается.
userName = Fred; password = NikL2sPacU;
Другими словами, нельзя обращаться к cookie-записям как к объектам. Необходимо анализировать всю cookie-строку, извлекая данные из нужного набора.
Если пользователь уверен, что в существующем файле содержится только одна cookie-запись (и к этому домену записи больше добавляться не будут), он может извлечь эту запись, используя ее имя. Например, данные cookie-записи, имя которой состоит из семи символов, можно извлечь, используя следующее выражение.
var data = unescape(document.cookie.substring(7,document.cookie.length));Первый параметр метода substring() включает знак = для отделения имени от данных. Целесообразно создать функцию общего назначения, которая сможет управлять одной или несколькими cookie-записями. Далее приводится подобная функция, которую используют в сценариях некоторые разработчики.
function getCookieData(labelName) { var labelLen = labelName.length; //однократное чтение свойства cookie var cookieData = document.cookie; var cLen = cookieData.length; var i = 0; var cEnd; while (i < cLen) { var j = i + labelLen; if (cookieData.substring(i,j) == labelName) { cEnd = cookieData.indexOf(";",j); if (cEnd == -1) { cEnd = cookieData.length; } return unescape(cookieData.substring(j+1, cEnd)); } i++; } return ""; }
При обращении к этой функции имя нужной cookie-записи передается как параметр. Функция анализирует полную строку cookie, обрабатывая ее частями (разделенными точкой с запятой). Таким образом, отбрасываются лишние элементы до тех пор, пока не будет найдено имя требуемой cookie-записи.
Если у вас возникли затруднения с пониманием данного кода, то обратитесь к набору функций, написанных опытным программистом JavaScript и Web-дизайнером Биллом Дортчем (Bill Dortch) из hIdaho Design. Созданные им функции обеспечивают универсальный доступ к cookie-записям, которые можно использовать во всех страницах, управляемых cookie. В листинге представлены cookie-функции Билла; они содержат различные методы предотвращения ошибок в дате, которые могут появиться в некоторых версиях NN2. Вас может смутить большой объем этого листинга, однако не волнуйтесь: большинство строк — простые комментарии.
<html> <head> <title>Cookie Functions</title> </head> <body> <script type="text/javascript"> <!-- начало сценария // // Соок1е_функции — "Night of the Living Cookie" версия (25.07.96) // // Написан: Биллом Дортчем, hIdaho Design < bdortch@hidaho.com > // Следующие функции созданы для работы с существующим доменом // Эта версия выполняет более "жесткое" удаление // cookie-записей. Предыдущие версии устанавливали дату истечения // срока службы записи на одну миллисекунду меньше, чем; // текущее время однако, этот метод не работал в Netscape // Navigator2.02 (хотя он работает как в более ранних, так и // в более поздних версиях этого браузера), так как в // результате его действия появлялись вечно живущие записи- // "призраки", которые никак нельзя было удалить. // Теперь DeleteCookie устанавливает в качестве даты истечения // срока хранения записи самую раннюю дату, пригодную для // использования (первая секунда 1970 года), и на всякий случай // обнуляет ее значение. // Также в этой версии функции DeleteCookie добавлены // необязательные параметры пути и домена. Необходимо указывать // путь и/или домен как при создании, так и при удалении // cookie**, иначе запись не будет удалена. // Функция FixCookieDate должна вызываться только для исправления // ошибок в дате на Мае 2.x. Эта функция должна вызываться *один // раз* после создания объекта Date и перед обращением к // SetCookie. Поскольку ошибка в дате в Маc воздействует на все // даты, а не только на те, которые передаются // в функцию SetCookie, необходимо привыкнуть к тому, что // придется вызывать FixCookieDate при создании каждого // нового объекта: // // var theDate = new Date(); // FixCookieDate (theDate); // // Функция FixCookieDate не работает ни на одной платформе // кроме Мае, поэтому нет необходимости определять платформу // пользователя перед каждым ее вызовом. // В этой версии также проведены некоторые незначительные // усовершенствования. // ** Заметьте, что можно устанавливать несколько записей с одним // и тем же именем, но различными путями. Например: // // SetCookie ("color","red",null."/outer"); // SetCookie ("color","blue",null."/outer/inner"); // // Однако GetCookie не может различить эти два выражения и // возвращает значение первой найденной записи с данным именем. // Поэтому рекомендуется *не* использовать одинаковые имена // для cookie с разными путями. (Имейте в виду, что у каждой // записи *всегда* есть свой путь; если он полностью не // определен, используется путь, установленный документом.) // // История обновления: // // "Toss Your Cookies" версия (22.03.96) // Добавление функции FixCookieDate() для исправления ошибок // в дате в Мае // // "Second Helping" версия (21.01.96) // Функция SetCookie() дополнена путем, доменом и параметрами // безопасности // "Самодельные" функции кодирования/декодирования заменены // на новые // функции escape и unescape в Netscape Navigator // // "Free Cookies " версия (декабрь 95) // За более подробной информацией о значениях cookie параметров // и о cookie пожалуйста, обращайтесь на официальный узел: // http://www.netscape.com/newsref/std/cookie_spec.html // ******************************************************* // "Внутренняя" функция для возвращения декодированного значения // function getCookieVal(offset) { var endstr = document.cookie.indexOf (";", offset); if (endstr == -1) endstr = document.cookie.length; return unescape(document.cookie.substringtoffset, endstr)); } // // Эта функция необходима для исправления ошибок в дате на // Мае 2.x. Вызывайте ее для проверки объекта даты перед // отправкой данных в функцию SetCookie. // ВНИМАНИЕ: Эта функция должна вызываться только *один раз* // для каждого полученного объекта даты! // См. пример в конце листинга. // function FixCookieDate(date) { var base = new Date(0); var skew = base.getTime(); // отсчет времени (Unix) должен начинаться с О if (skew > 0) // везде кроме Mac date.setTime (date.getTime() — skew); } // // Функция предназначена для возвращения значения cookie, // используя параметр "name". // name — строковый объект, содержащий имя cookie. // returns — строковый объект, содержащий значение cookie либо 0, // если таковая запись не существует // function GetCookie(name) { var arg = name + "="; var alen = arg.length; var clen = document.cookie.length; var i = 0; while (i < clen) { var j = i + alen; if (document.cookie.substring(i, j) == arg) return getCookieVal(j); i = document.cookie.indexOf(" ", 1) + 1; if (i ==0) break; } return null; } // // Функция для создания или обновления cookie. // name — строковый объект, содержащий имя cookie. // value — строковый объект, содержащий значение cookie. // Может содержать любой действительный строковый символ. // [expires] — объект Date, содержащий срок службы cookie. // Если таковое отсутствует, удаляет cookie после завершения // сеанса работы браузера. // [path] — строковый объект, указывающий путь-нужной cookie // записи. Если он не указан либо имеет нулевое значение, // использует путь вызванного документа. // [domen] — строковый объект, указывающий домен нужной // cookie-записи. Если он не указан или имеет нулевое значение, // используется домен вызванного документа. // [secure] — булево значение (true / false), определяет // необходимость использования безопасного соединения (HTTPS) // Первые два параметра необходимы. Остальные, если указаны, // то должны быть переданы в порядке, описанном выше. Для того // чтобы зарезервировать поле, не используемое в данный момент, // определите его как нулевое. Например, код для вызова функции // SetCookie с заданными именем, значением и путем, имеет // следующий вид: // SetCookie ("myCookieName", "myCookieValue", null, "/"); // // Заметьте, что перемещение опущенных параметров не требует // метки—заполнителя. Чтобы установить безопасный cookie в // "/myPath", срок службы которого заканчивается после // текущего сеанса, необходимо использовать выражение: // // SetCookie (myCookieVar, cookieValueVar, null, /myPath", null, true); // function SetCookie(name,value,expires,path,domain,secure) { document.cookie = name + "-" + escape (value) + ((expires) ? "; expires=+ expires.toGMTString() : "") + ((path) ? "; path=" + path : "") + ((domain) ? "; domain'" + domain : "") + ((secure) ? "; secure" : ""); } // Функция для удаления cookie. (Устанавливает дату истечения // срока службы записи в начало) // name — строковый объект, содержащий имя cookie. // path — строковый объект, содержащий путь cookie-записи, // которая впоследствии будет удалена. Это должен быть тот же // путь, который использовался при создании cookie, или нулевое // значение, если при создании записи путь не был определен. // domen — строковый объект, который содержит домен cookie, // предназначенный для удаления. Это должен быть тот же домен, // который использовался для создания cookie, или нулевое // значение, если при создании записи домен не был определен. // function DeleteCookie(name,path,domain) { if (GetCookie(name)) { document.cookie = name + "=" + ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + "; expires=Thu, Ol-Jan-70 00:00:01 GMT"; } } // // Примеры: // var expdate = new Date(); FixCookieDate(expdate); // Исправляет ошибки в дате Mac, // используется только один раз для каждого объекта Date! expdate.setTime(expdate.getTime() + (24 * 60 * 60 * 1000)); // 24 от текущего времени SetCookie("ccpath", "http://www.hidaho.coin/colorcenter/", expdate); SetCookie("ccname", "hidaho Design ColorCenter", expdate); SetCookie("tempvar", "Это временная cookie."); SetCookie("ubiquitous","Эта cookie будет работать в любом месте данного домена",null,"/"); SetCookie("paranoid","Эта cookie обеспечивает безопасное соединение",expdate,"/",null,true); SetCookie("goner","Эта cookie должна быть удалена!"); document.write(document.cookie + "<br>"); DeleteCookie("goner"); document.write(document.cookie + "<br>"); document.write("ccpath = " + GetCookie("ccpath") + "<br>"); document.write("ccname — " + GetCookie("ccname") + "<br>"); document.write("tempvar = " + GetCookie("tempvar") + "<br>"); // конец сценария --> </script> </body> </html>
Можно создать узел, для которого потребуется более чем 20 cookie на соответствующий домен. Например, никогда не известно, сколько элементов может загрузить покупатель в потребительскую корзину, находясь на коммерческом узле.
Так как каждая cookie-запись сохраняет данные в виде обычного текста, можно создать собственные текстовые структуры данных для последующего размещения в них записей, состоящих из нескольких частей. (Но не следует забывать о практическом пределе: 2 000 символов на пару имя-значение в пределах максимума (4 000 символов для каждой объединенной cookie-записи домена).) Таким образом определяется символ-разделитель, который не используется ни в одной из cookie-записей. Например, в приложении Decision Helper (глава 55) для разделения нескольких целых чисел, сохраненных в cookie, используется точка.
В случае применения установленного символа-разделителя необходимо написать функции для сбора этих подчиненных "cookie" в одну строку, и наоборот, разделения ее на отдельные записи. Такой путь более длинный, но он обеспечивает постоянство сведений о клиенте.