Кракозябры вместо текста - кодировки файлов, базы и обмена
Ищем, где ломается кодировка: файлы шаблона, база и соединение, импорт из файла, письма и выгрузки, и приводим проект к одной кодировке.
Что нужно знать заранее
У проекта одна кодировка на всё: файлы, база, соединение с базой и ответ браузеру. Кракозябры появляются там, где одно из звеньев цепочки выбивается из общего правила.
Современные проекты живут в универсальной кодировке, а старые - в однобайтовой. Смешивать их в одном проекте нельзя: перекодировка на каждом шаге рано или поздно теряет часть символов текста.
Чинить кодировку надо у источника данных, а не в месте их показа. Замена символов при выводе выглядит как решение ровно до первого поиска или сравнения строк в базе.
Шаги
- Узнать кодировку сайта из настроек языка и сверить её с кодировкой файлов.
- Проверить кодировку таблиц базы и кодировку соединения с ней прямо из кода.
- Определить кодировку входящего файла до импорта и перекодировать его при чтении.
- Проверить кодировку писем и выгрузок отдельно: у них свои собственные настройки.
- Привести все звенья к одной кодировке и повторить проверку на копии.
Решение
Смотрим кодировку сайта и файлов:
grep -rn 'CHARSET' /home/bitrix/www/bitrix/php_interface/dbconn.php | headfile -I /home/bitrix/www/local/templates/main/header.php # ожидаем charset=utf-8# файл шаблона в другой кодировке ломает всю страницу целикомКодировка сайта задана в настройках языка, а файлы обязаны ей соответствовать. Один файл, сохранённый чужим редактором, портит страницу целиком, и обычно это именно недавно правленый файл.
Проверяем базу и соединение:
SELECT DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATAWHERE SCHEMA_NAME = DATABASE();SHOW VARIABLES LIKE 'character_set_%'; -- кодировка соединения и клиента-- расхождение кодировок таблиц и соединения даёт кракозябры при выборкеКодировка соединения важна не меньше кодировки таблиц. Данные могут лежать правильно, а ломаться уже при чтении, и это самый неприятный случай: в базе всё хорошо, а на витрине мусор.
Определяем кодировку входящего файла:
$content = file_get_contents($path);$encoding = mb_detect_encoding($content, ['UTF-8', 'Windows-1251'], true);printf("файл в кодировке %s\n", $encoding ?: 'не определена');// прайс поставщика приходит в однобайтовой кодировке чаще, чем в универсальнойПерекодируем при чтении, а не после записи:
if ($encoding && $encoding !== 'UTF-8') { $content = mb_convert_encoding($content, 'UTF-8', $encoding); // один раз, на входе}// перекодировка уже сохранённых данных - отдельная операция с резервной копиейПерекодировка на входе - единственный дешёвый вариант. Данные, записанные в неверной кодировке, чинятся уже миграцией с копией базы, а не одной строчкой в шаблоне.
Проверяем выгрузку в таблицу:
$out = mb_convert_encoding($csv, 'Windows-1251', 'UTF-8'); // для старых версий Excelfile_put_contents($file, $out);// либо оставляют универсальную кодировку и добавляют метку порядка байтовВыгрузка для таблиц - отдельная история со своими правилами. Старые версии табличных редакторов открывают файл в системной кодировке, поэтому его либо перекодируют, либо помечают специальной меткой в начале файла.
Типичные проблемы
Вся страница превратилась в мусор после правки шаблона.
Файл сохранён редактором разработчика в другой, не принятой на проекте кодировке. Кодировку файла проверяют командой определения типа и пересохраняют его правильно.
В базе данные верные, а на витрине кракозябры.
Кодировка соединения с базой отличается от кодировки самих таблиц проекта. Настройку соединения проверяют системными переменными на самом сервере базы данных.
После импорта прайса названия товаров испорчены.
Файл поставщика пришёл в однобайтовой кодировке, а прочитан кодом как универсальный. Кодировку определяют автоматически и перекодируют содержимое прямо при чтении файла.
Выгрузка открывается в таблице нечитаемой.
Табличный редактор открывает такой файл в системной кодировке операционной системы. Файл перекодируют под этот редактор либо добавляют в начало метку порядка байтов.
Часть символов пропала после ремонта кодировки.
Данные перекодировали дважды либо исходили из неверно определённой исходной кодировки. Перед такой правкой снимают копию базы и проверяют результат на ней.
Частые вопросы
Как понять, в какой кодировке работает сайт?
По настройкам языка сайта и по файлу подключения к базе. Оба места должны говорить одно и то же, иначе разбор начинается именно с них.
Можно ли перевести старый сайт в универсальную кодировку?
Можно, но это отдельный проект: файлы, база, обмены и выгрузки переводят вместе. На копии такой перевод проверяют полностью, включая обмен с учётной системой.
Почему кракозябры только в письмах?
У писем своя кодировка и свои заголовки, задаваемые почтовым событием. Проверяют шаблон письма и настройки почтовых событий отдельно от сайта.
Помогает ли замена символов при выводе?
Нет, это маскировка: поиск и сравнение строк всё равно работают с испорченными данными. Чинят источник, а не место показа.
Что делать с файлом неизвестной кодировки?
Определить её автоматически по содержимому и перекодировать при чтении. Если определение не сработало, кодировку уточняют у отправителя файла.
Смежное
- Ошибки сервера и базы - оглавление подтемы
- Illegal mix of collations: разные кодировки таблиц и соединения - разбор ошибки базы про кодировки
- Импорт каталога из файла: CSV, повторный запуск, свои поля - типовой источник чужих кодировок
- Выгрузка в Excel из кода: библиотека, объём, отдача файла - кодировка выгрузки для таблиц
- Прайс поставщика по расписанию: сопоставление, наценка, защита - файлы поставщиков и их кодировки
- Не удалось обнаружить код вызова компонента: разбор причин - кодировка страницы и редактор
- Сервер и поиск - устройство сервера целиком
- Перевод проекта на UTF-8: файлы, база, настройки - когда кодировку меняют проектом целиком