Обработка русского текста в PHP с UTF-8
Работа с кириллицей в PHP: базовые принципы и решения
Наиболее эффективное решение для корректной обработки кириллицы в PHP - использование расширения mbstring (multibyte string). Это расширение предоставляет функции с префиксом mb_, которые корректно работают с многобайтовыми кодировками, включая UTF-8. Рекомендуется установить внутреннюю кодировку скрипта: mb_internal_encoding('UTF-8'); и кодировку HTTP-вывода: mb_http_output('UTF-8');. Также следует в начале скрипта отправлять заголовок header('Content-Type: text/html; charset=utf-8');. Эти меры гарантируют, что все строковые операции будут учитывать символы, а не байты.
<?php
mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');
header('Content-Type: text/html; charset=utf-8');
$text = 'Привет, мир!';
echo mb_strlen($text); // 12 (символов)
echo mb_substr($text, 0, 6); // 'Привет'
?>
Php установить кодировку utf 8 (php: установка кодировки utf-8)
В данном примере mb_strlen возвращает количество символов (12), а не байт (18). mb_substr корректно обрезает строку по границам символов. Это избавляет от проблем, возникающих при использовании обычных strlen и substr.
Типичная ошибка: Использование strpos для поиска подстроки в кириллической строке. Функция оперирует байтами, поэтому позиция может быть неверной. Решение - использовать mb_strpos.
$text = 'Привет, мир!';
$pos = mb_strpos($text, 'мир'); // результат 8 (корректно)
// Обычный strpos вернул бы 12 (смещение в байтах)
Utf 1251 php (php: преобразование utf-8 в 1251)
Как правильно настроить PHP для работы с UTF-8 на сервере?
Помимо кода, необходимо настроить файл php.ini. Установите параметры:
mbstring.language = Russian
mbstring.internal_encoding = UTF-8
mbstring.http_output = UTF-8
mbstring.encoding_translation = On
Php кириллица utf 8 (php: работа с кириллицей и utf-8)
Параметр mbstring.encoding_translation автоматически конвертирует входящие данные из кодировки формы в UTF-8. Также желательно отключить устаревшую директиву mbstring.func_overload (установить 0), чтобы не перегружать стандартные строковые функции.
Проблема: Если сервер не поддерживает расширение mbstring, многие функции будут недоступны. В таком случае можно использовать iconv или библиотеку multibyte вручную, но это менее удобно.
Как определить, что строка содержит кириллицу в UTF-8?
Функция mb_detect_encoding пытается угадать кодировку. Однако её точность ограничена. Для проверки наличия кириллических символов можно использовать регулярное выражение с модификатором u.
$text = 'Тестовая строка';
$pattern = '/[\x{0400}-\x{04FF}]/u';
if (preg_match($pattern, $text)) {
echo 'Содержит кириллицу';
}
Диапазон U+0400 – U+04FF соответствует кириллическим символам. При необходимости можно расширить до U+0500 – U+052F (дополнительная кириллица).
Типичные ошибки: Забывают модификатор u в pattern, из-за чего preg_match работает с байтами и даёт ложные срабатывания. Также некорректно используют диапазоны без фигурных скобок.
Как преобразовать строку из Windows-1251 в UTF-8?
Наиболее надёжный способ - mb_convert_encoding или iconv.
$cp1251 = 'Привет в CP1251';
$utf8 = mb_convert_encoding($cp1251, 'UTF-8', 'Windows-1251');
// или
$utf8 = iconv('Windows-1251', 'UTF-8', $cp1251);
Вторым аргументом указывается целевая кодировка, третьим - исходная. Если исходная кодировка неизвестна, можно попробовать mb_detect_encoding, но это не всегда даёт точный результат.
Ошибка: При использовании iconv без указания исходной кодировки может возникнуть предупреждение Detected an illegal character. В этом случае можно добавить //IGNORE или //TRANSLIT.
$utf8 = iconv('Windows-1251', 'UTF-8//IGNORE', $cp1251);
Как обрезать строку с кириллицей без потери символов?
Используется mb_substr с явным указанием кодировки в третьем параметре.
$text = 'Привет, мир!';
$short = mb_substr($text, 0, 7, 'UTF-8');
echo $short; // 'Привет,'
Параметр length считается в символах, а не в байтах. Если кодировка не указана, используется внутренняя кодировка (заданная mb_internal_encoding).
Проблема: Использование substr обрезает строку по границам байт, что может привести к «разрыву» многобайтового символа и появлению кракозябров. Это типичная ошибка при обработке кириллицы.
Как использовать регулярные выражения с кириллицей?
Регулярные выражения PCRE в PHP поддерживают Unicode, если в шаблоне указан модификатор u (unicode).
$text = 'Вася и Петя';
$result = preg_replace('/[а-я]+/u', '***', $text);
echo $result; // '*** и ***'
Без модификатора u диапазон [а-я] интерпретируется как последовательность байт, что даёт неверный результат.
Ошибка: Если в шаблоне используются Unicode-свойства (например \p{Cyrillic}), модификатор u также обязателен. Иначе preg_match вернёт false или предупреждение.
Как правильно вывести кириллицу в браузер?
Кроме отправки HTTP-заголовка, необходимо указать кодировку в мета-теге HTML. Рекомендуется делать и то, и другое.
header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
...
Если скрипт выполняется в консоли, нужно установить локаль: setlocale(LC_CTYPE, 'ru_RU.UTF-8');.
Типичная ошибка: Заголовок отправлен после какого-либо вывода (пробела, echo). В таком случае он игнорируется. Решение - вызов header() до любого вывода.
Как работать с файлами, имена которых содержат кириллицу?
PHP корректно обрабатывает UTF-8 имена файлов на Linux. На Windows может потребоваться конвертация в кодировку файловой системы (обычно CP1251).
$filename = 'файл.txt';
// На Windows
$filename_win = iconv('UTF-8', 'CP1251', $filename);
$handle = fopen($filename_win, 'w');
Функции basename, dirname, realpath также работают с UTF-8, но на Windows стоит учитывать системную кодировку.
Ошибка: Если на Windows не конвертировать имя файла, fopen может вернуть false. Также кодировка может отличаться в зависимости от локали системы.
Как отправлять электронные письма с кириллицей (utf-8)?
Функция mb_send_mail автоматически кодирует тему и тело письма в UTF-8. В заголовках нужно указать кодировку.
$subject = 'Тема письма';
$message = 'Привет, пользователь!';
$headers = 'From: sender@example.com' . "\r\n";
$headers .= 'Content-Type: text/plain; charset=UTF-8' . "\r\n";
mb_send_mail('user@example.com', $subject, $message, $headers);
Если тема содержит не-ASCII символы, mb_send_mail кодирует её в формат MIME base64 или quoted-printable. Альтернативно можно использовать mail с ручной кодировкой через wordwrap и mb_encode_mimeheader.
Проблема: Если сервер не поддерживает расширение mbstring, mb_send_mail не работает. Тогда применяют mail с мануальным кодированием, что сложнее и чревато ошибками.
Как сортировать кириллические строки?
Для сортировки с учётом национальной локали используется функция strcoll в паре с setlocale.
setlocale(LC_COLLATE, 'ru_RU.UTF-8');
$array = ['Яблоко', 'Апельсин', 'Вишня'];
usort($array, 'strcoll');
print_r($array);
// Результат: ['Апельсин', 'Вишня', 'Яблоко']
Локаль должна быть установлена на сервере. Если нет, сортировка будет по байтам, что для UTF-8 даст неверный порядок.
Ошибка: Если локаль не найдена, setlocale возвращает false и strcoll ведёт себя как strcmp. Перед использованием стоит проверить существование локали командой locale -a.
Как удалить BOM (Byte Order Mark) из UTF-8 строки?
BOM (U+FEFF) может присутствовать в начале файла, сохранённого некоторыми редакторами. Его можно удалить с помощью ltrim с использованием mb_ версии.
$bom = "\xEF\xBB\xBF";
$text = file_get_contents('file_with_bom.txt');
$clean = ltrim($text, $bom);
echo mb_substr($clean, 0, 10);
Но ltrim в обычном виде не поддерживает многобайтовые символы. Лучше использовать mb_substr после проверки первого символа.
if (mb_substr($text, 0, 1) === "\xEF\xBB\xBF") {
$text = mb_substr($text, 1);
}
Более надёжный способ - preg_replace с модификатором u.
Проблема: Если не удалить BOM, при выводе страницы браузер может отображать лишние символы или неправильно интерпретировать кодировку.
Как разбить строку на массив по символу с кириллицей?
Функция mb_split работает как preg_split, но с учётом многобайтовости. Она принимает разделитель (регулярное выражение) и строку.
$string = 'Один,Два,Три';
$array = mb_split(',', $string);
print_r($array);
// ['Один', 'Два', 'Три']
Использование explode для кириллицы возможно только если разделитель однобайтовый (как запятая) и строка не содержит многобайтовых символов в местах разбиения.
Ошибка: preg_split без модификатора u может разбить строку посередине символа. Всегда используйте модификатор u или mb_split.
Расширенные примеры работы с кириллицей в PHP
Обработка CSV файла с кириллицей в разных кодировках
Пример демонстрирует чтение CSV файла с неизвестной кодировкой, автоопределение и конвертацию всех полей в UTF-8 с последующей записью.
function convertCsvToUtf8($filename, $delimiter = ';') {
$rows = [];
$handle = fopen($filename, 'r');
while (($row = fgetcsv($handle, 0, $delimiter)) !== false) {
$convertedRow = [];
foreach ($row as $field) {
$encoding = mb_detect_encoding($field, ['UTF-8', 'Windows-1251', 'KOI8-R']);
if ($encoding && $encoding !== 'UTF-8') {
$field = mb_convert_encoding($field, 'UTF-8', $encoding);
}
$convertedRow[] = $field;
}
$rows[] = $convertedRow;
}
fclose($handle);
return $rows;
}
$data = convertCsvToUtf8('data.csv');
print_r($data[0]);
Array
(
[0] => Имя
[1] => Возраст
[2] => Город
)
Функция mb_detect_encoding пытается определить кодировку каждого поля. Если она не UTF-8, выполняется конвертация. Важно передавать список возможных кодировок в порядке предпочтения.
Отправка письма с вложением в UTF-8 через mb_send_mail
Пример отправляет письмо с текстовым вложением, содержащим кириллицу.
$to = 'user@example.com';
$subject = 'Документ с кириллицей';
$message = 'Основное тело письма';
$attachment = chunk_split(base64_encode('Содержимое файла на кириллице'));
$boundary = md5(time());
$headers = "From: sender@example.com\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";
$body = "--$boundary\r\n";
$body .= "Content-Type: text/plain; charset=UTF-8\r\n";
$body .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
$body .= $message . "\r\n";
$body .= "--$boundary\r\n";
$body .= "Content-Type: text/plain; name=\"file.txt\"\r\n";
$body .= "Content-Transfer-Encoding: base64\r\n";
$body .= "Content-Disposition: attachment\r\n\r\n";
$body .= $attachment . "\r\n";
$body .= "--$boundary--";
mb_send_mail($to, $subject, $body, $headers);
Тема письма кодируется автоматически. Заголовки и вложение строятся вручную с поддержкой UTF-8.
Работа с JSON: кириллические ключи и значения
По умолчанию json_encode экранирует многобайтовые символы. Использование опции JSON_UNESCAPED_UNICODE сохраняет их как есть.
$data = ['имя' => 'Вася', 'фамилия' => 'Петров'];
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
echo $json;
{"имя":"Вася","фамилия":"Петров"}
Без опции JSON_UNESCAPED_UNICODE результат был бы "\u0438\u043c\u044f", что увеличивает размер и усложняет читаемость.
Обработка URL параметров с кириллицей
Кириллические значения в URL необходимо кодировать через urlencode. При получении - декодировать.
$name = 'Привет';
$encoded = urlencode($name);
echo $encoded; // %D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82
// На стороне получателя
$decoded = urldecode('%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82');
echo $decoded; // Привет
В PHP суперглобальные массивы $_GET и $_POST автоматически декодируют параметры, если скрипт настроен на UTF-8.
Сравнение строк с учётом регистра и локали
Для сравнения кириллических строк без учёта регистра используется mb_strcasecmp. Для сортировки по локали - strcoll.
setlocale(LC_COLLATE, 'ru_RU.UTF-8');
$str1 = 'строка';
$str2 = 'СтрОка';
if (mb_strcasecmp($str1, $str2, 'UTF-8') === 0) {
echo 'Равны без учёта регистра';
}
$array = ['Б', 'а', 'я', 'ё'];
usort($array, 'strcoll');
print_r($array);
Равны без учёта регистра
Array
(
[0] => а
[1] => Б
[2] => ё
[3] => я
)
Обратите внимание, что strcoll учитывает локальную сортировку, в которой 'ё' может следовать после 'е' или отдельно, в зависимости от локали.
Конвертация массива строк из Windows-1251 в UTF-8 с помощью iconv
Пример преобразует все строки массива рекурсивно.
function convertArrayToUtf8(array $array, $sourceEncoding = 'Windows-1251') {
$result = [];
foreach ($array as $key => $value) {
if (is_array($value)) {
$result[$key] = convertArrayToUtf8($value, $sourceEncoding);
} else {
$result[$key] = iconv($sourceEncoding, 'UTF-8//IGNORE', $value);
}
}
return $result;
}
$oldData = ['name' => 'Имя', 'items' => ['товар1', 'товар2']];
$newData = convertArrayToUtf8($oldData);
print_r($newData);
Array
(
[name] => Имя
[items] => Array
(
[0] => товар1
[1] => товар2
)
)
Рекурсивная обработка полезна при работе со вложенными данными, например из API или XML.
Использование mb_ereg для замены с кириллицей
mb_ereg_replace - многобайтовый аналог ereg_replace (устаревший), но в современных версиях PHP лучше использовать preg_replace с модификатором u.
$subject = 'Цена: 1000 рублей';
$result = preg_replace('/(\d+)/u', '[[$1]]', $subject);
echo $result; // Цена: [[1000]] рублей
Модификатор u заставляет PCRE интерпретировать строку и шаблон как UTF-8.
Работа с именами файлов в многобайтовой файловой системе
На Linux и macOS имена файлов сохраняются в UTF-8 на уровне системы. Пример поиска всех файлов с кириллицей в имени.
$dir = '/path/to/files';
$files = scandir($dir);
foreach ($files as $file) {
if (preg_match('/[\x{0400}-\x{04FF}]/u', $file)) {
echo $file . PHP_EOL;
}
}
На Windows при сканировании каталога имена могут быть в кодировке, отличной от UTF-8. Рекомендуется использовать функцию mb_convert_encoding для приведения к единой кодировке.
Установка внутренней кодировки и контроль ошибок
Пример проверки, что mbstring включён, и установка кодировки.
if (!extension_loaded('mbstring')) {
die('Расширение mbstring не загружено. Работа с кириллицей будет ограничена.');
}
if (!mb_internal_encoding('UTF-8')) {
die('Не удалось установить внутреннюю кодировку UTF-8.');
}
mb_http_output('UTF-8');
ob_start('mb_output_handler');
header('Content-Type: text/html; charset=utf-8');
Использование ob_start('mb_output_handler') автоматически конвертирует весь вывод в UTF-8, если внутренняя кодировка отличается.