json_encode() возвращает false: Malformed UTF-8 characters

  • Обновлено
  • Чтение ≈ 4 минуты

Краткий ответ

Отдельно отличайте невалидные последовательности UTF-8 от обычного экранирования кириллицы в JSON: запись вида \u041f сама по себе не свидетельствует об ошибке и корректно декодируется.

В этой статье
  1. Симптомы, область применения и причины
  2. Безопасная диагностика и пошаговое исправление
  3. Как проверить результат и что делать дальше

#Симптомы, область применения и причины

PHP json_encode отказывается преобразовать строку с неверной последовательностью UTF-8, часто после чтения старой базы CP1251 или обработки двоичных данных. Диагностика источника байтов, исправление кодировки и безопасные параметры JSON. Отдельно отличайте невалидные последовательности UTF-8 от обычного экранирования кириллицы в JSON: запись вида \u041f сама по себе не свидетельствует об ошибке и корректно декодируется.

Возможная причинаКак узнатьЧто делать
Данные пришли из другой кодировкиСтрока CP1251, ISO-8859-1 или бинарные байты передаются как UTF-8.json_last_error_msg() сообщает Malformed UTF-8; сбой на конкретной записи.Определить кодировку источника и преобразовать однократно.
База/подключение использует неодинаковые настройкиСервер хранит данные в одном представлении, а соединение отдаёт их в другом.Ошибки возникают на полях отдельных старых записей; новые строки работают.Проверить кодировку колонок и клиентского соединения, исправить импорт в тестовой копии.
Массив содержит не текст, а бинарный файлИзображение или произвольные байты попали в структуру json_encode как строка.Сбой зависит от файла; база текстовых полей в порядке.Передавать файл отдельно либо в явном двоичном представлении.

#Безопасная диагностика и пошаговое исправление

  1. Подтвердите именно ошибку кодировкиВ тестовом месте сразу после неудачного json_encode($data) проверьте, действительно ли возвращено false; затем вызовите json_last_error() и json_last_error_msg(). Не публикуйте сами данные, поскольку они могут содержать персональные сведения. Если там ошибка глубины или рекурсивной структуры, действия по смене кодировки не подходят.
  2. Переменная $data — данные вашей программы, а не готовое содержимое для копирования
    PHP
    Переменная $data — данные вашей программы, а не готовое содержимое для копирования. Код только для закрытой диагностики.
    <?php
    $result = json_encode($data);
    if ($result === false) {
        error_log('JSON code='.json_last_error().'; message='.json_last_error_msg());
    }
  1. Найдите конкретное поле с неверными байтамиНа тестовой копии проверьте входящие строки через mb_check_encoding($value, "UTF-8"), если установлено расширение mbstring. Для массива проверяйте вложенные текстовые значения отдельно в контролируемом обходе, без записи исходных полей в общий лог. При ошибке фиксируйте техническое имя поля и идентификатор тестовой записи, а не её текст. Не применяйте функции к файлам изображения как к строкам UTF-8.
  2. Требуется расширение mbstring
    PHP
    Требуется расширение mbstring. Переменная $value — конкретное проверяемое поле; не логируйте его содержимое.
    <?php
    if (is_string($value) && !mb_check_encoding($value, 'UTF-8')) {
        error_log('Invalid UTF-8 in validated text field');
    }
  1. Уточните происхождение данных и первоначальную кодировкуПосмотрите, откуда пришла строка: CSV-файл, форма, API, таблица MySQL, старый архив. Известная кодировка источника важнее автоматического угадывания. Если файл записан в Windows-1251, преобразуйте его при импорте с явным указанием CP1251 и сохраните копию исходных байтов. Не преобразовывайте один и тот же текст дважды: так можно получить нечитаемые символы, хотя JSON начнёт формироваться.
  1. Проверьте соединение с базой, а не только столбецУ MySQL проверьте кодировку базы, таблицы, колонок и клиентского соединения. В приложении с PDO MySQL используйте согласованный charset=utf8mb4 в DSN при подключении (для поддерживаемой конфигурации). Прежде чем переводить существующие поля, сделайте резервную копию базы и проверку нескольких исходных записей. Глобальная команда перевода всех таблиц без анализа фактических байтов может испортить данные.
  1. Преобразуйте только подтверждённые строкиЕсли установлено, что конкретная строка действительно CP1251, примените к ней mb_convert_encoding($value, "UTF-8", "Windows-1251") при импорте или в отдельной миграции. Сравните русские буквы с оригиналом до и после. Если исходная кодировка неизвестна, остановитесь и получите исходный файл или описание поставщика; использование автоматического определения для массового исправления опасно.
  2. Переменная $legacyText — именно текст исходной Windows-1251
    PHP
    Переменная $legacyText — именно текст исходной Windows-1251. JSON_THROW_ON_ERROR требует обработки JsonException в реальном приложении.
    <?php
    // ТОЛЬКО если источник достоверно имеет кодировку Windows-1251:
    $utf8 = mb_convert_encoding($legacyText, 'UTF-8', 'Windows-1251');
    $json = json_encode(['text' => $utf8], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
  1. Не используйте подмену битых символов как исправление хранилищаФлаги JSON_INVALID_UTF8_SUBSTITUTE и JSON_INVALID_UTF8_IGNORE позволяют получить JSON даже с повреждённой строкой, но первый заменяет символы, а второй теряет байты. Применяйте их только по согласованной политике приложения, где допустима потеря части текста, и записывайте факт очистки без исходных персональных данных. Не считайте это восстановлением правильной кодировки.
  1. Проверьте итоговый JSON и откатите неудачный импортПроверьте, что json_encode теперь возвращает строку, JSON повторно декодируется, а кириллица читается без потерь. Прогоните несколько старых и новых записей; если старые буквы искажены, верните тестовую копию из резервной копии и исправьте сам процесс импорта. Не меняйте колонку базы наугад, пока не выяснено, какие байты там реально находятся.

#Как проверить результат и что делать дальше

Успех — ошибочный текстовый элемент получает настоящую UTF-8 последовательность, json_encode создаёт корректный JSON и после декодирования сохраняется читаемый текст. Если ошибка остаётся, проверьте остальные поля и не переводите двоичные значения как кириллицу.

Так эту ошибку тоже называют

Источники и обновления

Последнее обновление статьи: 2 ноября 2026. Версии программ и интерфейсы меняются — если шаги не совпадают с вашей версией, сверяйтесь с документацией производителя.