Кодировка UTF-8 в PHP: практическое применение и тонкости
Настройка charset UTF-8 в PHP: варианты и рекомендации
Как обеспечить корректную работу с UTF-8 на всех этапах обработки данных в PHP?
Наиболее полное и рекомендуемое решение - задать кодировку UTF-8 на всех уровнях: в HTTP-заголовках, в самом скрипте, в соединении с базой данных и в файлах. Это позволяет избежать большинства проблем с отображением и обработкой многобайтовых символов.
// Устанавливаем внутреннюю кодировку и HTTP-вывод
mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');
// Отправляем заголовок Content-Type
header('Content-Type: text/html; charset=utf-8');
// Если сессия - также кодировка
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
Php charset utf 8 (charset utf-8 в php)
Типичные ошибки:
- Забыли вызвать
mb_internal_encoding- функцииstrlen,substrработают неверно. - Не задан заголовок Content-Type - браузер может интерпретировать страницу в другой кодировке.
- В php.ini не включено расширение mbstring - все mb_* функции недоступны.
Решение:
Проверить наличие расширения, настроить php.ini:
; php.ini
extension=mbstring
; или в Windows: extension=php_mbstring.dll
; Также можно указать значения по умолчанию
mbstring.internal_encoding = UTF-8
mbstring.http_output = UTF-8
Что делать, если нет возможности менять php.ini или расширение mbstring отключено?
Можно обойтись только HTTP-заголовками и функциями iconv для преобразования строк. Однако такой подход менее удобен, так как отсутствуют специализированные многобайтовые функции.
// Альтернатива без mbstring
header('Content-Type: text/html; charset=utf-8');
// Для работы с подстроками используем iconv_substr вместо mb_substr
$string = 'Привет, мир!';
// iconv_substr - если нужен только срез
$sub = iconv_substr($string, 0, 6, 'UTF-8');
echo $sub; // 'Привет'
Проблема: iconv может не поддерживать все необходимые операции (например, замену в строке).
Решение: Установка mbstring через пакетный менеджер или сборка PHP с поддержкой многобайтовых строк.
Как настроить соединение с базой данных MySQL на UTF-8?
При использовании PDO:
$dsn = 'mysql:host=localhost;dbname=test;charset=utf8';
$pdo = new PDO($dsn, 'user', 'password');
$pdo->exec('SET NAMES utf8'); // дополнительная страховка
Для mysqli:
$mysqli = new mysqli('localhost', 'user', 'password', 'test');
$mysqli->set_charset('utf8');
Ошибка: использование SET NAMES utf8 без соответствующей кодировки в DSN может привести к двойной конвертации.
Решение: Применять charset=utf8 в DSN или set_charset - они эквивалентны.
Как обрабатывать JSON с UTF-8 в PHP?
Функции json_encode и json_decode корректно работают с UTF-8, если входные строки уже в UTF-8. Необходимо убедиться, что данные закодированы в UTF-8 до вызова.
$data = ['name' => 'Иван', 'city' => 'Москва'];
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
echo $json; // {"name":"Иван","city":"Москва"}
Проблема: Если исходные строки не UTF-8, JSON будет некорректным или вызовет ошибку.
Решение: Перед кодированием преобразовывать данные в UTF-8 с помощью iconv или mb_convert_encoding.
Как обрабатывать файлы и сохранять их в UTF-8 без BOM?
При записи в файл используйте fwrite с предварительным преобразованием строки в UTF-8. Для чтения можно проверить BOM и удалить его.
// Удаление BOM при чтении
$content = file_get_contents($file);
$bom = pack('H*','EFBBBF');
if (strncmp($content, $bom, 3) === 0) {
$content = substr($content, 3);
}
Ошибка: BOM может вызывать проблемы при обработке JSON или XML.
Решение: Сохранять файлы всегда в UTF-8 без BOM (например, в редакторе выбирать опцию UTF-8 without BOM).
Расширенные примеры работы с UTF-8 в PHP
Приведённые ниже примеры показывают типовые ситуации и продвинутые приёмы.
1. Многобайтовые строковые функции
$text = 'Привет, мир!';
// Длина в байтах и символах
echo strlen($text) . '\n'; // 19 (количество байт)
echo mb_strlen($text, 'UTF-8') . '\n'; // 12 (количество символов)
// Подстрока
echo substr($text, 0, 6) . '\n'; // 'Приве' (обрезано некорректно)
echo mb_substr($text, 0, 6, 'UTF-8') . '\n'; // 'Привет'
// Поиск позиции
echo strpos($text, 'мир') . '\n'; // 11 (байтовая позиция)
echo mb_strpos($text, 'мир', 0, 'UTF-8') . '\n'; // 7 (символьная)
19 12 Приве Привет 11 7
2. Регулярные выражения с Unicode
$text = 'Привет, мир!';
// Поиск всех буквенных символов
preg_match_all('/\p{L}+/u', $text, $matches);
print_r($matches[0]);
// Результат: Array ( [0] => Привет [1] => мир )
// Удаление знаков препинания
$clean = preg_replace('/\p{P}/u', '', $text);
echo $clean; // 'Привет мир'
Array
(
[0] => Привет
[1] => мир
)
Привет мир
3. Преобразование кодировок из windows-1251 в UTF-8
$text = 'Привет';
$cp1251 = iconv('UTF-8', 'windows-1251//IGNORE', $text);
// или
$cp1251 = mb_convert_encoding($text, 'windows-1251', 'UTF-8');
// Обратно
$utf8 = iconv('windows-1251', 'UTF-8//IGNORE', $cp1251);
echo $utf8; // 'Привет'
4. Проверка валидности UTF-8 строки
function is_valid_utf8($string) {
return mb_check_encoding($string, 'UTF-8');
}
$good = 'Привет';
$bad = "\xff\xfe"; // некорректная последовательность
echo is_valid_utf8($good) ? 'valid' : 'invalid'; // valid
echo is_valid_utf8($bad) ? 'valid' : 'invalid'; // invalid
valid invalid
5. Работа с массивом строк: сортировка и преобразование
$names = ['Иван', 'Анна', 'Борис'];
// Сортировка с учётом локали (зависит от локали системы)
setlocale(LC_COLLATE, 'ru_RU.UTF-8');
usort($names, 'strcoll');
print_r($names); // ['Анна', 'Борис', 'Иван']
// Преобразование всех ключей массива в UTF-8 (рекурсивно)
function utf8ize($mixed) {
if (is_array($mixed)) {
return array_map('utf8ize', $mixed);
} else if (is_string($mixed)) {
return mb_convert_encoding($mixed, 'UTF-8', mb_detect_encoding($mixed, 'UTF-8, windows-1251, ISO-8859-1', true));
}
return $mixed;
}
$data = ['name' => 'Привет'];
$converted = utf8ize($data);
Array
(
[0] => Анна
[1] => Борис
[2] => Иван
)
6. Чтение файла с неизвестной кодировкой и конвертация
$content = file_get_contents('somefile.txt');
$detect = mb_detect_encoding($content, 'UTF-8, windows-1251, KOI8-R', true);
if ($detect && $detect !== 'UTF-8') {
$content = mb_convert_encoding($content, 'UTF-8', $detect);
}
echo $content;
7. Отправка email с UTF-8 заголовками
$subject = 'Привет из PHP';
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/plain; charset=utf-8' . "\r\n";
$headers .= 'From: sender@example.com' . "\r\n";
// Кодирование темы по RFC 2047
$subject = '=?UTF-8?B?' . base64_encode($subject) . '?=';
mail('user@example.com', $subject, 'Тело письма', $headers);
8. Защита от ошибок при использовании mb_* функций
// Проверка доступности расширения
if (!extension_loaded('mbstring')) {
// fallback на iconv или самостоятельные реализации
}
// Для совместимости с PHP < 5.4 можно определить свою версию mb_strlen
if (!function_exists('mb_strlen')) {
function mb_strlen($string, $encoding = 'UTF-8') {
return strlen(iconv($encoding, 'UTF-16', $string)) / 2;
}
}