Intereting Posts

Разрешение неправильной кодировки символов при отображении результатов базы данных 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 и пытаемся отобразить одни и те же данные, она становится искаженной. В этом конкретном случае мы пытаемся отображать русские символы, а результат – неанглийские, нерусские символы: искаженный беспорядок

Заголовки ответов, которые мы получаем, подтверждают, что тип содержимого – UTF-8:

заголовки ответов

Мы тестировали строки перед отображением с 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 исправляет проблему?

Если вы убедитесь, что обе таблицы и выходная кодировка являются UTF-8, почти единственное, что осталось, это кодирование соединения.

Причиной изменения поведения при обновлении серверов может быть изменение кодировки соединения по умолчанию:

 [mysql] default-character-set=utf8 

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

В любом случае, что произойдет, если вы запустите это из вашего PHP-запроса и выведете результаты. Любые отличия от вывода командной строки?

  SHOW VARIABLES LIKE 'character_set%'; SHOW VARIABLES LIKE 'collation%'; 

Я вижу, вы пробовали это, но синтаксис, который я использую: 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"); 

У меня была аналогичная проблема после обновления 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 = двоичный
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 по умолчанию (без SET NAMES):
character_set_client = latin2
character_set_connection = latin2
character_set_database = utf8
character_set_filesystem = двоичный
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'"); 

Возможно, что-то подобное является причиной вашей проблемы.