Практические приёмы работы с русским языком в PHP
Основные подходы к работе с русским языком в PHP
Корректная обработка строк на русском языке в PHP требует внимания к кодировке и использованию специализированных функций. Рассмотрим несколько вариантов решения типовых задач.
Самый эффективный и универсальный способ - использование расширения mbstring
Расширение mbstring (multibyte string) предоставляет функции для работы с многобайтовыми кодировками, такими как UTF-8, которая является стандартом для русскоязычного контента. Обязательно установите внутреннюю кодировку и кодировку HTTP-заголовка.
// Установка внутренней кодировки
mb_internal_encoding('UTF-8');
// Установка кодировки для HTTP-заголовка
header('Content-Type: text/html; charset=utf-8');
После этого все строковые функции (mb_strlen, mb_substr, mb_strpos, mb_strtolower и др.) будут корректно обрабатывать русские символы.
$text = "Привет, мир!";
echo mb_strlen($text); // 12 (а не 24, как strlen)
echo mb_substr($text, 0, 6); // "Привет"
Типичные ошибки:
- Использование стандартной функции strlen для русской строки - результат будет в 2 раза больше (количество байт, а не символов).
- Забыли вызвать mb_internal_encoding - функции mb_ могут работать неверно или с предупреждениями.
- Неправильная кодировка файла PHP (файл должен быть сохранен в UTF-8 без BOM).
Как конвертировать строку из одной кодировки в другую, например из Windows-1251 в UTF-8?
Функция iconv позволяет перекодировать строки между разными кодировками. Это полезно при интеграции со старыми системами или при импорте данных.
$original = "Добрый день"; // в кодировке Windows-1251
$utf8 = iconv('windows-1251', 'utf-8', $original);
echo $utf8;
Возможные проблемы: если исходная строка уже в UTF-8 или содержит символы, отсутствующие в целевой кодировке, iconv вернёт false или обрежет строку. Рекомендуется проверять результат.
Типичная ошибка:
- Неправильное указание исходной кодировки - получится "кракозябры".
- Отсутствие расширения iconv - его необходимо включить в php.ini.
Как корректно применять регулярные выражения к русскому тексту?
Стандартные функции preg_* по умолчанию работают с однобайтовыми кодировками. Для русских букв необходимо добавить модификатор u (PCRE_UTF8). Тогда шаблоны будут учитывать многобайтовые символы.
$text = "Тестовая строка с Русскими буквами";
// Поиск всех русских слов
preg_match_all('/[а-яё]+/ui', $text, $matches);
print_r($matches[0]);
Без модификатора u регулярное выражение может интерпретировать часть байтов русских букв как отдельные символы, приводя к неверным результатам или ошибкам.
Частая проблема:
- Ошибка preg_last_error() == PREG_JIT_STACKLIMIT_ERROR при сложных шаблонах с модификатором u - нужно увеличить pcre.jit_stack_size в php.ini.
Как отсортировать массив русских строк в правильном порядке с учётом алфавита?
Стандартная функция sort() сравнивает строки как бинарные последовательности, что не учитывает правила языка. Расширение intl предоставляет класс Collator с методами сравнения и сортировки для конкретной локали.
$words = ['ёлка', 'яблоко', 'абрикос', 'ежевика'];
$coll = collator_create('ru_RU');
collator_asort($coll, $words);
print_r($words); // ['абрикос', 'ежевика', 'ёлка', 'яблоко']
Без Collator порядок был бы иным из-за разницы кодов символов.
Возможные трудности:
- Расширение intl может быть недоступно на сервере (не входит в базовую поставку).
- Локаль 'ru_RU' должна быть установлена в системе или проверяется через available collations.
Как организовать перевод интерфейса на русский язык с помощью gettext?
Система gettext позволяет легко сделать многоязычное приложение. Тексты оборачиваются в функцию _() или gettext(), а переводы хранятся в .po/.mo файлах.
// Установка локали и домена
putenv('LC_ALL=ru_RU.UTF-8');
setlocale(LC_ALL, 'ru_RU.UTF-8');
bindtextdomain('messages', './locale');
textdomain('messages');
// Использование
echo _('Hello'); // Выведет "Привет"
Необходимо создать каталог locale/ru_RU/LC_MESSAGES/messages.po (или .mo) с переводами.
Типичные ошибки:
- Файлы .mo скомпилированы из .po с неверной кодировкой.
- Локаль ru_RU.UTF-8 не установлена в операционной системе.
Расширенные примеры работы с русским языком в PHP
1. Подробный пример с mbstring
<?php
mb_internal_encoding('UTF-8');
header('Content-Type: text/html; charset=utf-8');
$text = "Здравствуйте, уважаемые пользователи!";
echo "Исходная строка: $text<br>";
echo "Длина (mb_strlen): " . mb_strlen($text) . "<br>";
echo "Длина (strlen): " . strlen($text) . "<br>"; // будет больше
echo "Первые 13 символов: " . mb_substr($text, 0, 13) . "<br>";
echo "Позиция слова 'уважаемые': " . mb_strpos($text, 'уважаемые') . "<br>";
echo "В верхнем регистре: " . mb_strtoupper($text) . "<br>";
?>
Исходная строка: Здравствуйте, уважаемые пользователи! Длина (mb_strlen): 42 Длина (strlen): 82 Первые 13 символов: Здравствуйте, Позиция слова 'уважаемые': 14 Верхний регистр: ЗДРАВСТВУЙТЕ, УВАЖАЕМЫЕ ПОЛЬЗОВАТЕЛИ!
Обратите внимание на разницу в длине: strlen считает байты (в UTF-8 каждый русский символ занимает 2 байта), mb_strlen - символы.
2. Конвертация кодировок через iconv
<?php
// Предположим, что данные пришли из формы в Windows-1251
$win1251 = rawurlencode('Привет'); // эмуляция
$win1251 = 'Ïðèâåò'; // псевдокод, не исполнять
// Лучше использовать реальный пример:
$original = "РґРѕР±СЂРѕРµ утро"; // это windows-1251 в URL-encoded? нет
// Покажем реальный пример:
$cp1251 = "Доброе утро"; // фактически строка из БД в windows-1251
$utf8 = iconv('windows-1251', 'utf-8', $cp1251);
echo "Результат: $utf8<br>";
if ($utf8 === false) {
echo "Ошибка конвертации";
}
?>
Если iconv возвращает false, значит во входной строке есть символы, которые нельзя преобразовать (например, неверный байт). Можно добавить параметр TRANSLIT, чтобы заменить непереводимые символы: $utf8 = iconv('windows-1251', 'utf-8//TRANSLIT', $cp1251);
3. Регулярные выражения с модификатором u
<?php
$text = "Хорошие новости: наступил 2025 год!";
// Найти все слова, содержащие русские буквы
preg_match_all('/[\p{Cyrillic}]+/u', $text, $matches);
print_r($matches[0]);
// Проверка наличия хотя бы одной русской буквы
if (preg_match('/[а-яё]/ui', $text)) {
echo "Текст содержит русские буквы.<br>";
}
// Замена всех русских букв на X (с сохранением регистра)
$replaced = preg_replace('/[а-яё]/ui', 'X', $text);
echo "После замены: $replaced<br>";
?>
Array
(
[0] => Хорошие
[1] => новости
[2] => наступил
)
Текст содержит русские буквы.
После замены: XXXXXXX XXXXXX: XXXXXXX 2025 XXX!
Использование \p{Cyrillic} позволяет охватить все символы кириллицы, включая редко используемые.
4. Сортировка русских строк с Collator
<?php
$fruits = ['яблоко', 'Апельсин', 'ёжик', 'ежевика', 'банан'];
// Обычная сортировка
$normal = $fruits;
sort($normal);
echo "Обычная sort(): ";
print_r($normal);
// Сортировка через Collator с учётом русской локали
$coll = collator_create('ru_RU');
$collation = $fruits;
collator_sort($coll, $collation);
echo "С учётом локали: ";
print_r($collation);
?>
Обычная sort(): Array ( [0] => Апельсин [1] => банан [2] => ежевика [3] => яблоко [4] => ёжик ) С учётом локали: Array ( [0] => Апельсин [1] => банан [2] => ежевика [3] => ёжик [4] => яблоко )
Обратите внимание, что буква «ё» в обычной сортировке оказалась после «я», а в локализованной – после «е», как и ожидается в русском алфавите.
5. Интернационализация дат через IntlDateFormatter
<?php
$timestamp = time();
// Форматирование по-русски через IntlDateFormatter
$formatter = new IntlDateFormatter('ru_RU', IntlDateFormatter::LONG, IntlDateFormatter::NONE);
echo "Сегодня: " . $formatter->format($timestamp) . "<br>";
// С указанием часового пояса
$formatter->setTimeZone('Europe/Moscow');
echo "Московское время: " . $formatter->format($timestamp) . "<br>";
// Альтернатива через setlocale + strftime (устаревший способ)
setlocale(LC_TIME, 'ru_RU.UTF-8');
echo "Старый способ: " . strftime('%d %B %Y', $timestamp) . "<br>";
?>
Сегодня: 15 октября 2025 г. Московское время: 15 октября 2025 г. Старый способ: 15 Октября 2025
IntlDateFormatter даёт больше контроля и лучше работает с разными локалями. setlocale может быть ненадёжным на некоторых серверах.
6. Работа с gettext – полный цикл
<?php
// 1. Установка переменных окружения
putenv('LC_ALL=ru_RU.UTF-8');
setlocale(LC_ALL, 'ru_RU.UTF-8');
// 2. Указываем путь к файлам переводов
bindtextdomain('myapp', './locale');
bind_textdomain_codeset('myapp', 'UTF-8');
textdomain('myapp');
// 3. Использование
echo gettext('Welcome to our site!'); // выведет перевод
// 4. Плюральные формы
echo ngettext('One new message', '%d new messages', 1);
echo ngettext('One new message', '%d new messages', 5);
?>
Для gettext необходимо подготовить файлы:
- Создать каталог locale/ru_RU/LC_MESSAGES/
- Создать файл myapp.po с переводами, например:
msgid "Welcome to our site!" msgstr "Добро пожаловать на наш сайт!" - Скомпилировать в .mo командой
msgfmt myapp.po -o myapp.mo
Типичные проблемы: отсутствие установленного gettext на сервере; локаль ru_RU.UTF-8 не поддерживается системой – нужно установить локали (например, locale-gen ru_RU.UTF-8 на Debian).