Сессии в БД и SET NAMES utf8 в 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 буду рад услышать об этом.