Разрешение неправильной кодировки символов при отображении результатов базы данных MySQL после обновления до PHP 5.3
Описание проблемы
После обновления PHP на нашем сервере разработки с 5.2 до 5.3 мы сталкиваемся с проблемой, когда данные, запрошенные из нашей базы данных и отображаемые на веб-странице, показывают неправильное кодирование при попытке отображать русские символы.
Окружающая среда
- Dev OS: Debian GNU/Linux 6.0
- Dev PHP: 5.3.5-0.dotdeb.1
- Live MySQL: Распространение 5.1.49
Подробнее
В PHP 5.3 клиентская библиотека по умолчанию для взаимодействия с базами данных MySQL изменилась с libmysql на mysqlnd, что, по-видимому, было причиной проблемы, с которой мы сталкиваемся.
Мы подключаемся к базе данных со следующим кодом:
$conn = mysql_pconnect('database.hostname', 'database_user', 'database_password');
$mysql_select_db('database', $conn);
Данные, хранящиеся в нашей базе данных, кодируются кодировкой UTF-8. Подключение к базе данных через клиент командной строки и выполняемые запросы подтверждает, что данные не повреждены и правильно закодированы. Однако, когда мы запрашиваем базу данных в PHP и пытаемся отобразить одни и те же данные, она становится искаженной. В этом конкретном случае мы пытаемся отображать русские символы, а результат - неанглийские, нерусские символы:
![garbled mess]()
Полученные заголовки ответов подтверждают, что тип содержимого UTF-8:
![response headers]()
Мы тестировали строки перед отображением mb_detect_encoding в строгом режиме, а mb_check_encoding и сказали, что строка была строкой UTF-8 перед ее отображением. Мы также использовали mysql_client_encoding для проверки клиентской кодировки, а также указывает, что набор символов - UTF-8.
При проведении исследований мы обнаружили несколько рекомендаций, чтобы попытаться обойти эту проблему:
header("Content-type: text/html; charset=utf-8");
mysql_set_charset('utf8');
mysql_query("SET SESSION character_set_results = 'UTF8'");
mysql_query('SET NAMES UTF8', $conn);
Мы даже попробовали utf8_encode:
utf8_encode($string);
Однако ни одно из этих решений не работало.
Запустив опции, мы обновили MySQL в нашей системе разработки до версии 5.1.55. После этого обновления все отображается правильно, когда мы подключались к нашей базе данных разработки. Конечно, он продолжает отображаться некорректно, когда мы подключаемся к нашей активной базе данных.
В идеале мы хотели бы решить эту проблему без обновления MySQL на наших производственных серверах, если мы не сможем проверить точную причину, по которой это не работает, и почему обновление исправит его. Как решить эту проблему без обновления MySQL? В качестве альтернативы, почему обновление MySQL исправляет проблему?
Ответы
Ответ 1
Если вы убедились, что обе таблицы и выходная кодировка являются UTF-8, почти единственное, что осталось, это кодирование соединения.
Причиной изменения поведения при обновлении серверов может быть изменение кодировки соединения по умолчанию:
[mysql]
default-character-set=utf8
Однако я не вижу изменений в кодировке по умолчанию между версиями, поэтому, если это были совершенно новые установки, я не вижу этого.
В любом случае, что произойдет, если вы запустите это из вашего PHP-запроса и выведете результаты. Любые отличия от вывода командной строки?
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
Ответ 2
Я вижу, вы пробовали это, но синтаксис, который я использую: mysql_query ( "SET NAMES utf8" ). Ваш синтаксис может быть правильным, я никогда раньше этого не видел.
Пример:
// connect to database stuff
$Connection = mysql_connect($server, $username, $password)
or die ("Error connecting to server");
// connect to database stuff
$db = mysql_select_db($database, $Connection)
or die ("Error selecting database");
mysql_query("SET NAMES utf8");
Ответ 3
У меня была аналогичная проблема после обновления PHP с 5.2.3 до 5.3.5 (5.3.5-Win32-VC6-x86), MySQL 5.0.41 (не обновлено). Я думаю, что причина - небольшая разница между версиями PHP.
PHP 5.2.3 по умолчанию (без SET NAMES):
character_set_client = latin1
character_set_connection = latin1
character_set_database = utf8
character_set_filesystem = binary
character_set_results = latin1
character_set_server = latin2
character_set_system = utf8
collation_connection = latin1_swedish_ci
collation_database = utf8_polish_ci
collation_server = latin2_general_ci
PHP 5.3.5 default (без SET NAMES):
character_set_client = latin2
character_set_connection = latin2
character_set_database = utf8
character_set_filesystem = binary
character_set_results = latin2
character_set_server = latin2
character_set_system = utf8
collation_connection = latin2_general_ci
collation_database = utf8_polish_ci
collation_server = latin2_general_ci
Я добавил данные в базу данных в PHP 5.2.3 по умолчанию (без SET NAMES), поэтому теперь, чтобы правильно отобразить его, я должен прочитать его, используя:
$pdo -> query("SET NAMES 'latin1'");
Возможно, что-то подобное является причиной вашей проблемы.