Русский текст и UTF-8 в PHP: настройка функций регистра и кодировки
Работа с русскими символами в PHP (кодировка UTF-8)
При обработке текстов на кириллице в PHP необходимо учитывать, что стандартные строковые функции (strlen, substr, strtolower и другие) ориентированы на однобайтовые кодировки. Для корректной работы с многобайтовыми символами, в частности русскими буквами в кодировке UTF-8, требуется использование специальных расширений. В этой статье рассматриваются основные подходы и их практические применения.
Основное решение: расширение mb_string (Multibyte String)
Набор функций mb_* предоставляет полноценную поддержку многобайтовых кодировок. Главное преимущество - все операции выполняются с учётом кодировки, заданной через mb_internal_encoding или передаваемой параметром. Это единственный способ гарантировать правильное поведение при работе с русским текстом.
Как правильно настроить PHP для работы с UTF-8 и русскими символами?
<?php
// Устанавливаем внутреннюю кодировку UTF-8
mb_internal_encoding('UTF-8');
// Теперь функции mb_* будут использовать UTF-8 по умолчанию
$text = 'Привет, мир!';
echo mb_strlen($text); // 13 (количество символов)
echo strlen($text); // 19 (количество байт)
?>
Php русские символы (работа с русскими символами в php (кодировка utf-8))
Установка кодировки через mb_internal_encoding или параметр encoding в каждом вызове обязательна. Без этого mb_strlen может вернуть неверное значение.
Типичные ошибки:
- Забыли установить внутреннюю кодировку - функции mb_* используют ISO-8859-1, что приводит к разбиению русских букв на байты.
- Смешивание mb_* и обычных функций на одной строке - например, substr после mb_strlen даёт некорректный результат.
- Отсутствие расширения mb_string на сервере - необходимо установить или использовать альтернативы.
Цель: обработка строк любой длины и регистра, безопасное обрезание, поиск, замена. Используется в CMS, форумах, системах управления контентом.
Как работать с русскими строками, если расширение mb_string недоступно?
Расширение iconv предоставляет функции iconv_strlen, iconv_substr, iconv_strpos. Они также корректно обрабатывают многобайтовые строки, но имеют ограниченный функционал (нет mb_strtolower и т.д.).
<?php
$text = 'Здравствуйте!';
echo iconv_strlen($text, 'UTF-8'); // 13
echo iconv_substr($text, 0, 6, 'UTF-8'); // Здравс
?>
Проблемы iconv: на разных системах возможны расхождения в обработке невалидных последовательностей; отсутствие функций для перевода регистра. Для приведения регистра придётся использовать mb_convert_case из mb_string или писать собственную таблицу преобразования.
Цель: лёгкая альтернатива при базовых операциях, когда mb_string не установлено.
Как искать русские символы с помощью регулярных выражений?
Модификатор u в регулярных выражениях включает режим UTF-8. Это позволяет корректно сопоставлять кириллические классы, например [а-яё].
<?php
$text = 'Ёлка и яблоко';
// Поиск всех русских букв
preg_match_all('/[а-яё]/iu', $text, $matches);
print_r($matches[0]);
?>
Результат содержит каждую букву отдельно. Без модификатора u символы ё и другие могут не распознаваться.
Ошибки: забывают модификатор u - тогда и (байты) считаются за символы; неправильно составленный диапазон [а-я] не включает букву ё, нужно явно добавлять [а-яё] или использовать свойство \p{Cyrillic}.
Цель: валидация ввода, замена подстрок, разбор текста.
Как безопасно сравнивать русские строки без учёта регистра?
Функция strcasecmp работает с байтами и не учитывает многобайтовость. Для корректного сравнения нужно перевести обе строки в один регистр через mb_strtolower и сравнить через ===.
<?php
$str1 = 'Привет';
$str2 = 'ПРИВЕТ';
if (mb_strtolower($str1) === mb_strtolower($str2)) {
echo 'Строки равны';
}
?>
Типичная ошибка: использование strcasecmp напрямую - для русских символов он сравнивает байты, поэтому 'А' и 'а' (разные байты) будут признаны неравными. Кроме того, нужно учитывать locale - mb_strtolower использует кодировку, но не локаль, поэтому проблем не возникает.
Цель: поиск, сортировка, проверка совпадений.
Как преобразовывать кодировку текста из одной в другую (например, CP1251 в UTF-8)?
Функция mb_convert_encoding (или iconv) позволяет перекодировать строки. Это часто требуется при импорте данных из старых систем.
<?php
$cp1251 = file_get_contents('old.txt'); // файл в Windows-1251
$utf8 = mb_convert_encoding($cp1251, 'UTF-8', 'CP1251');
file_put_contents('new.txt', $utf8);
?>
Проблемы: неверное указание исходной кодировки ведёт к кракозябрам; при наличии смешанной кодировки (часть строк уже UTF-8) лучше сначала определить её через mb_detect_encoding с порядком приоритетов.
Цель: интеграция унаследованных данных, работа с внешними API.
Расширенные примеры работы с русскими символами
Пример 1: поиск позиции подстроки с учётом UTF-8
Функция mb_strpos корректно находит первое вхождение подстроки, считая символы, а не байты. В отличие от strpos, которая для русских символов возвращает смещение в байтах.
<?php
mb_internal_encoding('UTF-8');
$text = 'Привет, как дела? Привет!';
$pos = mb_strpos($text, 'Привет');
echo 'Первое вхождение на позиции: ' . $pos; // 0
$pos2 = mb_strpos($text, 'Привет', 10);
echo 'Второе вхождение на позиции: ' . $pos2; // 17
?>
Первое вхождение на позиции: 0 Второе вхождение на позиции: 17
Если использовать strpos, для первого вхождения результат будет 0 (повезло), а для второго - 24 (байтовый сдвиг, не совпадает с символьным).
Пример 2: перевод регистра для всего текста с mb_convert_case
mb_convert_case позволяет установить разный тип преобразования: MB_CASE_UPPER, MB_CASE_LOWER, MB_CASE_TITLE (каждое слово с заглавной).
<?php
$text = 'привет, МИР! ёлка';
echo mb_convert_case($text, MB_CASE_TITLE, 'UTF-8'); // Привет, Мир! Ёлка
// Для сравнения strtoupper выдаст искажённый результат
?>
Привет, Мир! Ёлка
Обратите внимание, что буква 'ё' корректно преобразуется в 'Ё'. Обычная strtoupper этого не делает.
Пример 3: замена всех вхождений русских букв с регулярным выражением и модификатором u
Использование preg_replace с модификатором u для замены всех гласных на звёздочки.
<?php
$text = 'Привет, как дела?';
$pattern = '/[аеёиоуыэюя]/iu';
$replaced = preg_replace($pattern, '*', $text);
echo $replaced;
?>
Пр*в*т, к*к д*л*?
Без модификатора u замена прошла бы только по однобайтовым символам, что привело бы к повреждению UTF-8 последовательности.
Пример 4: работа с JSON и русскими строками
json_encode автоматически экранирует многобайтовые символы в \uXXXX, если не задать опцию JSON_UNESCAPED_UNICODE. Для хранения читаемого UTF-8 в JSON нужно её указать.
<?php
$data = ['name' => 'Иван', 'city' => 'Москва'];
echo json_encode($data, JSON_UNESCAPED_UNICODE);
// vs стандартное поведение
?>
{"name":"Иван","city":"Москва"}
Без опции результат: {"name":"\u0418\u0432\u0430\u043d","city":"\u041c\u043e\u0441\u043a\u0432\u0430"}. Это менее читаемо, но занимает больше места. Проблема возникает при декодировании, если кодировка исходной строки не UTF-8 - json_decode может вернуть null или искажённые данные.