Cookies: с ними нужно быть внимательным

cookiesОднажды на проекте случлось странное с функционалом. Выясняя причину наткнулся на очень много кода, который работает с кукисами. Но вот только работает код неправильно.

Вообще чем кукиса характеризуется:

  • имя
  • значение
  • путь
  • время истечения
  • домен
  • секурность

Здесь и далее нас будет интересовать домен, поскольку именно он является причиной множества странный и часто трудноуловимых багов.

Возьмем пример https://github.com/RussianPenguin/blogSamples/blob/master/cookies.php и запустим его на локальном сервере пхп (примем за аксиому то, что у нас домен localhost.localdomain резолвится на локалхост).

Пример cookie.php на локальном сервереТеперь зайдем в браузер по нашему скрипту

Cookies.php в firebugВидно, что скрипт выставляет две кукисы для одного и того же домена.

Стандарт предписывает, что кукиса с точкой перед именем домена и без точки доступна в пределах всех поддоменов, а точка оставлена лишь для совместимости с более ранними браузерами.

Казалось бы, мы ставим кукисы на одном и том же домене. Кстати, вот код:

// Конфигурация (домен на котором запускаем)  
$domain = 'localhost.localdomain';  
$cookieName = 'test';

setcookie($cookieName, 'empty host', 3600+time(), '/');  
setcookie($cookieName, 'host: ' . $domain, 3600+time(), '/', $domain);

тут я оставил конфигурацию домена руками так как запуск сервера идет на нестандартном порту.

Так вот. Думалось, что браузер должен поставить одну печеньку и в ней должно быть значение, которое передано последним.

Но нет. Если хидер установки кукиса содержит домен, то кукису будет присвоено имя домена с точкой в начале. А если имени домена не указывать, то кукис будет поставлен на текущий домен без точки в начале.

И когда мы попытаемся считать на стороне клиента (или сервера) наш поставленый кукис, то какой из них вернется - это уже немного рандом (хотя нет, все зависит от того, в какой последовательности печеньки ставились).

И то же самое происходит на клиенте: если мы при установки кукиса указываем домен, то браузер поставит кукис на домен с точкой в начале, а если не укажем, то без точки.

Попробуем прописать в тестовом скрипте какое-то значение для печеньки, но не указывать домен. А потом нажмем кнопку “поставить кукис”.

cookies.php после setCookieЧто мы видим? А видим мы то, что браузер считал значение для текущего домена (первое) и перезаписал его новым. Которое мы выбрали. А второй кукис до перезагрузки остался нетронутым. Круто. А значит нажмем “прочитать печеньку” и увидим наше новое значение.

Однако если мы так думаем, то ошибаемся.

cookies.php getCookieДаже FireCookie что-то показывает - это не значит, что значение печенья поменялось.

Огнелись ничего не поставил.

Но как только мы домен укажем при установке

cookie.php - правильный результатТак сразу все работает как надо - устанавливается значение и при нажатии на кнопку “прочитать” мы его получаем.

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

Учтите, что если вы заходите повторить этот эксперимент, то на доменах верхнего уровня подобное не работает. Т.е. если мы будем использовать localhost, то подобное поведение не воспроизведется.

Категории: Разработка