Сессии в БД и SET NAMES utf8 в Zend Framework

// Октябрь 13th, 2010 // Doctrine, MySQL, PHP, Zend Framework, Веб-разработка

Zend Framework очень хорош, на нём удобно строить большие системы, но уж очень он неповоротлив. У нас в системе есть несколько утилит, который вызываются через AJAX-запрос после загрузки страницы и делают что-нибудь полезное. Например, есть утилита которая подгружает варианты автодополнения при поиске по сайту, еще есть утилита, которая обновляет статусы пользователей (онлайн-офлайн) на странице. Вот с последней сегодня приключилась большая проблема.

После прохождения авторизации и обновления страницы пользователя выкидывало с сайта (система переставала его узнавать). Мы начали исследовать, в чём же дело. Оказалось, что виновником всему был AJAX-запрос на утилиту обновления статусов. Я отключил его и всё сработало как надо. Дальше стали копаться в утилите. Хранение сессий у нас осуществляется в БД, при этом мы используем Zend_Session_SaveHandler_DbTable, который реализует это поведение. Утилиты также должны цеплять сессию пользователя. Но сегодня они начали её ломать. Вместо сериализованного объекта Zend_Auth в сессию писались первые N вимволов строки. В результате длительного копания я выяснил, что это происходит из-за выполнения запроса SET NAMES ‘utf8’.Выключаю — работает, включаю — не работает. Вообщем мы оказались перед выбором — либо сессии, либо текст в нормальной кодировке. Стоит добавить, что кодировка нам была также нужна, как и сессии, т.к. например в одной из утилит возвращаются названия городов, на языке пользователя.Сессия ун нас хранилась в таблице вот такой структуры:

CREATE TABLE IF NOT EXISTS `session` (
`id` char(32) NOT NULL DEFAULT »,
`modified` int(20) DEFAULT NULL,
`lifetime` int(20) DEFAULT NULL,
`data` varchar(4096) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT CHARSET=utf8;

После того, как мы поняли, что дело в кодировке начались изыскания, пробовали менять движок БД. Он у нас был memory, сменили на myisam, innoDB — всё безрезультатно. Кодировка поля и таблицы была естественно такая, какая нужно —  utf8_general_ci. Потом играясь с типом поля попробовали varbinary (4096) и это помогло. Теперь таблица приобрела такой вид:

CREATE TABLE IF NOT EXISTS `session` (
`id` char(32) NOT NULL DEFAULT »,
`modified` int(20) DEFAULT NULL,
`lifetime` int(20) DEFAULT NULL,
`data` varbinary(4096) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT CHARSET=utf8;

После этого и сессии стали цепляться, и текст мы получали из этого поля в правильной кодировке. Если кто-нибудь знает причины столь странного поведения MySQL буду рад услышать об этом.

Share

Спасибо!


Если вам помогла статья, или вы хотите поддержать мои исследования и блог - вот лучший способ сделать это:


Комментировать