Как стать автором
Обновить

Решение проблемы с кодировкой данных из MySQL в Symfony

Время на прочтение3 мин
Количество просмотров5.2K
Сразу хочу сказать, что в Symfony и Doctrine я новичок и с подобного рода проблемой именно при использовании Symfony столкнулся впервые, но думаю, что и мой опыт может быть кому-то полезен при решении аналогичных или схожих задач.

Предыстория:


Довелось мне не так давно выкладывать некий проект на Symfony2 на хост площадку, но, как это довольно часто бывает, на живом сервере приложение работать отказалось, и включив debug, я увидел уведомление примерно следующего плана:

Twig_Error_Runtime: An exception has been thrown during the rendering of a template
(«Warning: htmlspecialchars() [function.htmlspecialchars]: Invalid multibyte sequence in argument in
/.../app/cache/prod/classes.php line ...») in "..." at line ...


Причина этой ошибки кроется в том, что Twig по умолчанию экранирует всякий вывод, в том числе и с помощью функции htmlspecialchars(), которая в данном случае спотыкается о некую Invalid multibyte sequence. И решив, что было бы неплохо посмотреть эту самую Invalid multibyte sequence, я пропустил в шаблоне вывод соответствующих переменных через фильтр raw, примерно вот так:
{{ sometext|raw }}
Выяснилось, что кириллические текстовые данные из базы почему-то приходят в кодировке cp1251, хотя кодировка импортированной базы, таблиц и соотв. полей, из которых взяты значения была utf8. В phpMyAdmin, который был мне предоставлен хостером, на вкладке «Variables» моё внимание привлекли следующие значения параметров конфигурации mysql сервера:
init connect      SET NAMES cp1251
collation database      cp1251_general_ci
collation      servercp1251_general_ci
...

Проблема:


Очевидно, что причина была именно в init connect, который при соединении выполнял SET NAMES cp1251, потому все значения передавались в приложение как cp1251.
SET NAMES
Напомню, что SET NAMES определяет кодировку в которой клиент отправляет данные на сервер а также кодировку, в которой сервер отправляет обратный ответ клиенту.


Подобного рода проблемы обычно решаются довольно просто — сразу после коннекта к базе в своём приложении выполняем запрос или группу запросов типа:
SET CHARACTER SET UTF8;
SET NAMES UTF8;

Но, как по мне, всякий лишний запрос к базе — это вообще не комильфо, да и «костыли» в коде фреймворка тоже. Поэтому поначалу я попытался решить вопрос через техподдержку.
Ребята из техподдержки хост-компании рассказали мне, что перенести базу на сервер, сконфигурированный под utf8 они не могут, т.к. все сервера у них работают с одинаковой конфигурацией на cp1251, а менять настройки сервера из-за одного проекта никто не будет, т.к.
изменения коснуться всех баз на этом сервере (я их прекрасно понимаю). Но проблему нужно было как-то решать…

Решение:


Однако, решение на Symfony оказалось довольно изящным, что и послужило поводом к написанию данной статьи.
На помощь мне пришёл крохотный EventListener, который я повесил на событие postConnect.

Для его создания нужно внести в файле app/config/config.yml (если используется YAML) в разделе «services» запись вида:
services:
    onconnect.listener:
        class: Dev\SomeBundle\EventListener\OnConnect
        tags:
             - { name: doctrine.event_listener, event: postConnect }


Теперь в нашем Bundle, нужно создать файл listener'a, который соответствует заданному в конфигурации выше namespace (Dev\SomeBundle\EventListener\OnConnect).
т.е. Ложим в папку Dev/SomeBundle/EventListener файл OnConnect.php следующего содержания:

<?php
//file src/Dev/SomeBundle/EventListener/OnConnect.php

namespace Dev\SomeBundle\EventListener;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\ORM\EntityManager;

class OnConnect
{
	public function postConnect( $event )
	{
		$conn = $event->getConnection();
		$conn->executeQuery("SET NAMES UTF8");
	}
}


В моём случае проблема с кодровкой была полностью устранена, и к тому же, мне не пришлось вставлять какие-либо «хаки» в doctrine или код фреймворка. Механизм прослушивания событий широко применяется в Symfony для решения самых различных задач. В описанном выше примере использовался Symfony 2.2.0 (Standard Edition).

Выводы:


  1. Обращайте внимание на пареметры настройки MySQL сервера, — некоторые сервера по умолчанию могут работать с другой кодировкой.
  2. Если у вас нет возможности настроить MySQL сервер должным образом, можно воспользоваться приёмом, описанным выше.
Теги:
Хабы:
Всего голосов 6: ↑2 и ↓4-2
Комментарии4

Публикации

Истории

Работа

PHP программист
148 вакансий

Ближайшие события