PHP LinuxWindowsmacOS

PHP: preg_match возвращает false на тексте с некорректной UTF-8

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

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

preg_match возвращает false на некорректной UTF-8: определите PREG_BAD_UTF8_ERROR, проверьте байты входа и конвертируйте только подтверждённую исходную кодировку.

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

#Когда возникает ошибка

При шаблоне с модификатором /u регулярное выражение PHP ожидает корректную последовательность UTF-8. Если в полученной строке есть недопустимые байты, preg_match() может вернуть false с ошибкой PREG_BAD_UTF8_ERROR. Не путайте false с целым 0: ноль означает, что совпадений нет при корректном выполнении.

#Причины и признаки

Возможная причинаКак узнатьЧто делать
Вход не в UTF-8Данные из старой базы, файла или внешней системы приходят, например, в Windows-1251.mb_check_encoding($text, "UTF-8") возвращает false.Выясните реальную кодировку источника и преобразуйте в UTF-8.
Строка обрезана посередине символаКод режет сырые байты substr() и случайно оставляет половину многобайтного символа.Исходная строка допустима, а обрезанный фрагмент — нет.Измените разбиение на операции с учётом символов или границ UTF-8.
Другой код ошибки PCREШаблон содержит ошибку либо превышен лимит выполнения.preg_last_error() выдаёт не PREG_BAD_UTF8_ERROR.Исправляйте соответствующую проблему, не меняя кодировку вслепую.

#Пошаговая диагностика и устранение

  1. Отличите отсутствие совпадения от ошибкиВ тестовой копии после вызова preg_match() сохраните результат в переменную и проверьте строго: === false означает сбой, === 0 — отсутствие совпадения, === 1 — совпадение. Рядом вызовите preg_last_error() или preg_last_error_msg(), чтобы получить код. Не сравнивайте просто if (!$result), иначе ошибку примете за нормальный ответ.
  2. Убедитесь, что шаблон требует UTF-8Откройте PHP-файл в редакторе, найдите вызов preg_match и проверьте завершающий модификатор u в шаблоне. Для Unicode-категорий, таких как \p{L}, /u обычно нужен. Удаление /u может изменить смысл сопоставления, поэтому не используйте его как обычное исправление некорректной строки.
  3. Определите источник строки и назначенную кодировкуПроследите, откуда взялось значение: файл CSV, HTTP-ответ, поле базы данных. Проверьте метаданные источника, параметры кодировки соединения с БД и действительный формат файла. Название кодировки нельзя достоверно угадать по одному набору байтов; проверка UTF-8 сообщает только допустимость UTF-8.
  4. Проверьте валидность байтов на копии данныхУбедитесь, что в PHP включено расширение mbstring (php -m в терминале CLI, отдельно проверить web-PHP), и вызовите mb_check_encoding($text, "UTF-8"). Если функции нет, не устанавливайте расширение на рабочем сервере без согласования: обратитесь к администратору. Не публикуйте текст, если в нём персональные сведения.
  5. Преобразуйте только подтверждённую старую кодировкуЕсли документы или параметры источника подтверждают Windows-1251, примените mb_convert_encoding($text, "UTF-8", "Windows-1251") в копии данных. Убедитесь, что русские буквы отображаются без замены на «?». Не используйте «автоматическое исправление» и не заменяйте неверные байты пустыми символами без разрешения: это может изменить проверяемое содержимое.
  6. Исправьте место, где повреждается строкаЕсли на входе строка корректна, но после substr, чтения ограниченного числа байтов либо сетевой передачи она стала неверной, найдите точное место обрезки. Для UTF-8 используйте операции с символами, например mb_substr, задав кодировку. Для бинарных данных /u вообще не должен применяться; разделите обработку текста и бинарного потока.
  7. Запустите проверку и верните исходный вариант при сбоеВ отдельном тестовом файле проверьте корректную строку, некорректные байты и строку без совпадений. Убедитесь, что код различает три результата; затем прогоните регрессионные проверки на копии реальных данных. Если преобразование исказило содержимое, откатите исходные байты и уточните кодировку, вместо повторной конвертации уже повреждённого файла.

#Проверяемый пример и команды

PHP
В тестовом скрипте PHP 8.x с UTF-8. Для строки «Привет» ожидается Совпадение и true (при наличии mbstring). Проверку вызывайте сразу после проблемного preg_match, пока другой вызов не изменил состояние PCRE.
<?php
$subject = "Привет";
$found = preg_match('/\p{L}+/u', $subject, $matches);
if ($found === false) {
    throw new RuntimeException('Ошибка PCRE: ' . preg_last_error_msg());
}
echo ($found === 1 ? 'Совпадение' : 'Совпадений нет') . PHP_EOL;
// Дополнительная проверка — только если установлено mbstring:
if (function_exists('mb_check_encoding')) {
    var_export(mb_check_encoding($subject, 'UTF-8'));
    echo PHP_EOL;
}

#Проверка исправления и действия при неудаче

Исправление выполнено, если preg_match для правильного текста возвращает 0 или 1, preg_last_error() равен PREG_NO_ERROR, а некорректные байты обрабатываются явно. Если ошибка повторяется, сохраните только диагностические коды и безопасный небольшой образец байтов для разработчика.

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

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