Кодировка UTF-8: как настроить сайт и убрать кракозябры
Кракозябры появляются, когда разные части сайта читают одни байты по-разному. Проверьте файл, HTTP-заголовок, HTML, соединение с базой и таблицу.
Сначала сохраните копию данных, затем исправляйте уровни по порядку. Команды помогут настроить UTF-8 в HTML, PHP, Apache, Nginx и MySQL, а также открыть CSV в Excel.
- Что такое UTF-8 и почему появляются «кракозябры»
- Как узнать текущую кодировку
- Кодировка в HTML
- Сохранение файлов в UTF-8 без BOM
- Кодировка в PHP и HTTP-заголовке
- Кодировка Apache и Nginx
- Кодировка соединения PHP с MySQL
- Резервная копия перед миграцией MySQL
- Как поменять кодировку базы и таблиц MySQL
- Настройки сервера MySQL и MariaDB
- Двойная кодировка: как починить испорченные данные
- Ошибки при переводе сайта на UTF-8
- Как открыть CSV в UTF-8 в Excel
- Порядок действий при переносе сайта
Что такое UTF-8 и почему появляются «кракозябры»
Unicode назначает символам уникальные номера. UTF-8 записывает эти номера последовательностями байтов, которые читают программы.
UTF-8 использует от 1 до 4 байтов на кодовую точку. Первые 128 символов ASCII занимают по одному байту, а старший бит такого байта равен 0. Русские буквы занимают по 2 байта: их номера попадают в диапазон двухбайтовых последовательностей UTF-8.
Все уровни цепочки должны согласованно обрабатывать текст: файл → сервер → HTML → соединение с БД → таблица. Для страницы используют UTF-8, а для полного Unicode в MySQL и MariaDB – utf8mb4.

| Как выглядит поломка | Вероятная причина |
|---|---|
| пр и похожие последовательности | Байты UTF-8 прочитаны как Windows-1252 или Latin-1. Ошибочное чтение через Windows-1251 дает другие последовательности, часто с «Р» и «С». |
| ???? | Программа заменила символы вопросительными знаками при записи или преобразовании. |
| Ромб с вопросом – � | Декодер получил недопустимую последовательность байтов. Например, файл Windows-1251 прочитали как UTF-8. |
Вопросительные знаки часто означают потерю исходных байтов. Новый заголовок не восстановит такой текст. Если «Ð¿Ñ€» уже хранится в базе, исправляйте данные на копии.
Как узнать текущую кодировку
Сравните пять уровней цепочки: файл, ответ сервера, HTML, соединение PHP и таблицу. Один правильный результат не доказывает, что остальные уровни настроены так же.
Заголовок HTTP в DevTools
Откройте инструменты разработчика браузера и выберите раздел Network. Перезагрузите страницу, выберите запрос HTML-документа и найдите в заголовках ответа Content-Type.
Content-Type: text/html; charset=utf-8Проверяйте документ страницы: у изображений и скриптов другие типы содержимого. Параметр charset должен совпадать с фактическими байтами файла.
Проверка через curl
Откройте терминал и подставьте адрес страницы:
curl -I https://example.com/
curl -sS -D - -o /dev/null https://example.com/В Windows используйте устройство NUL:
curl.exe -sS -D - -o NUL https://example.com/При перенаправлении проверьте конечный адрес. Промежуточный ответ может содержать другие заголовки.
Файл и база данных
Откройте файл в Visual Studio Code или Notepad++. Кодировка отображается в строке состояния редактора. Сравните русский текст с исходной копией.
SHOW VARIABLES LIKE 'character_set%';
SHOW CREATE TABLE users;Выполняйте SQL-команды в клиенте, подключенном к нужной базе. Замените users именем своей таблицы.
Запросы показывают настройки соединения и таблицы. Если испорчены только записи из БД, начинайте с соединения и таблицы. Если ломается весь текст, сначала проверьте файл и HTTP-заголовок.
Кодировка в HTML
Укажите UTF-8 в документе и в ответе сервера. Метатег не перекодирует исходные байты, поэтому сначала сохраните файл правильно.
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Страница на русском языке</title>
</head>
<body>
<p>Проверка русского текста</p>
</body>
</html>Поставьте <meta charset="utf-8"> первой строкой внутри head. Элемент с объявлением кодировки должен целиком находиться в первых 1024 байтах документа. Это правило описывает спецификация HTML.
HTTP-заголовок главнее метатега. Если сервер присылает charset=windows-1251, исправьте серверную настройку. Атрибут charset у ссылки устарел и не задает кодировку HTML-документа.
После сохранения откройте страницу и сравните метатег с заголовком ответа в DevTools.
Сохранение файлов в UTF-8 без BOM
Выберите редактор, в котором виден исходный русский текст. Сначала откройте файл в правильной исходной кодировке, затем сохраните его в UTF-8 без BOM.
Visual Studio Code
Откройте файл и нажмите обозначение кодировки в строке состояния. Если текст испорчен, выберите повторное открытие с исходной кодировкой Windows-1251 или другой известной кодировкой.
Когда русский текст читается правильно, выберите сохранение в UTF-8 без BOM. Закройте файл, откройте его снова и сравните несколько строк.
Notepad++
Откройте меню управления кодировками. Сначала задайте правильную интерпретацию исходных байтов, затем выполните преобразование файла в UTF-8 без BOM и сохраните копию.
Смена интерпретации меняет способ чтения байтов. Преобразование при сохранении меняет сами байты. Если сохранить уже неверно прочитанный текст, ошибка закрепится.
BOM может находиться в подключаемом PHP-файле, а пробел – перед открывающим тегом PHP. Эти байты попадут в ответ раньше HTTP-заголовка, поэтому header() может сообщить об ошибке «headers already sent».
Кодировка в PHP и HTTP-заголовке
PHP задает заголовок динамической страницы до любого вывода. Значение по умолчанию задает активный php.ini.
<?php
header('Content-Type: text/html; charset=utf-8');В конфигурации задайте кодировку явно:
default_charset = "UTF-8"В Linux типичные пути к конфигурации PHP выглядят так:
/etc/php.ini
/etc/php/<версия>/apache2/php.ini
/etc/php/<версия>/fpm/php.ini
/etc/php/<версия>/cli/php.ini
/etc/php/php.iniЗамените <версия> именем каталога установленной версии PHP. Файл из каталога cli относится к терминалу. Для сайта нужен файл Apache-модуля или PHP-FPM.
В Windows-сборках OpenServer, XAMPP и Laragon активный файл можно определить через сам сайт. Этот способ также подходит для Linux и исключает правку чужого php.ini.
- Создайте файл
encoding-check.phpв корне своего сайта, рядом с его входным PHP-файлом. - Сохраните в нем следующий код в UTF-8 без BOM.
<?php
header('Content-Type: text/plain; charset=utf-8');
echo 'php.ini: ', php_ini_loaded_file() ?: 'не загружен', PHP_EOL;
echo 'default_charset: ', ini_get('default_charset'), PHP_EOL;- Откройте файл в браузере через адрес своего сайта. Например, для сайта
https://example.com/адрес будет таким:
https://example.com/encoding-check.php- Скопируйте полный путь после
php.ini:и откройте именно этот файл в редакторе. - Измените существующий параметр
default_charsetна"UTF-8"и сохраните конфигурацию. - Перезапустите PHP или веб-сервер средствами вашей сборки.
- Обновите диагностическую страницу. Строка
default_charset:должна содержатьUTF-8. - Удалите
encoding-check.phpпосле проверки.
Если PHP сообщает «не загружен», задайте заголовок непосредственно через header(). Этот вызов задает кодировку ответа без изменения php.ini. Затем откройте обычную страницу сайта и проверьте ее Content-Type.
Кодировка Apache и Nginx
Выберите конфигурацию сайта, который формирует ответ. Перед изменением сохраните копию файла, после изменения проверьте конфигурацию и заголовок страницы.
Apache
В Apache директива AddDefaultCharset задает кодировку по умолчанию для текстовых ответов. Для одного сайта добавьте ее в .htaccess в корне проекта:
AddDefaultCharset UTF-8Сервер должен разрешать эту директиву в .htaccess. Если настройка не применяется, добавьте ее в конфигурацию виртуального хоста.
Типичные полные пути в Linux:
/etc/apache2/apache2.conf
/etc/apache2/sites-available/000-default.conf
/etc/httpd/conf/httpd.conf
/etc/httpd/conf.d/Для Debian и Ubuntu файл нужного виртуального хоста обычно находится в /etc/apache2/sites-available/. Для RHEL-подобных систем ищите виртуальный хост в /etc/httpd/conf.d/. Добавьте директиву внутрь нужного VirtualHost.
apachectl -S
apachectl configtest
sudo apachectl gracefulКоманда configtest должна завершиться без ошибок. После перечитывания конфигурации откройте страницу и проверьте charset=utf-8.
Nginx
Основной конфигурационный файл Nginx обычно расположен здесь:
/etc/nginx/nginx.conf
/etc/nginx/sites-available/default
/etc/nginx/sites-enabled/
/etc/nginx/conf.d/Найдите активный блок server командой:
sudo nginx -TВнутри нужного блока добавьте:
charset utf-8;Директива описана в документации Nginx. Проверьте и перечитайте конфигурацию:
sudo nginx -t
sudo nginx -s reloadСтраница должна снова открыться, а ее ответ должен содержать charset=utf-8. При ошибке верните сохраненную копию и повторите проверку.
Кодировка соединения PHP с MySQL
Таблица может хранить текст правильно, а PHP получать его через другое соединение. Задайте кодировку сразу после подключения и прочитайте переменные тем же соединением.
mysqli
Задайте кодировку функцией mysqli_set_charset() до выполнения запросов приложения:
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$link = mysqli_connect('localhost', 'user', 'password', 'site');
mysqli_set_charset($link, 'utf8mb4');В объектном стиле используйте метод:
$mysqli->set_charset('utf8mb4');$result = mysqli_query($link,
'SELECT @@character_set_client AS client,
@@character_set_connection AS connection_charset,
@@character_set_results AS results_charset');
var_export(mysqli_fetch_assoc($result));Во всех трех полях должно быть utf8mb4. После проверки удалите диагностический вывод.
PDO
Передайте кодировку в строке подключения:
<?php
$dsn = 'mysql:host=localhost;dbname=site;charset=utf8mb4';
$pdo = new PDO($dsn, 'user', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);Синтаксис параметров описан в документации PDO_MYSQL. Получите значение через тот же объект:
echo $pdo->query('SELECT @@character_set_connection')->fetchColumn();Используйте set_charset() или параметр charset в DSN. Отдельный SET NAMES не сообщает клиентской библиотеке mysqli кодировку для mysqli_real_escape_string().
WordPress
В файле wp-config.php в каталоге установки WordPress задайте:
define('DB_CHARSET', 'utf8mb4');Не добавляйте вторую константу с таким именем. Смена настройки не преобразует уже сохраненные строки.
Резервная копия перед миграцией MySQL
Порядок переноса такой: копия, тестовая база, таблицы, соединение приложения, проверка чтения и записи. Не преобразуйте рабочие данные без отдельного дампа.
Остановите запись приложения на время создания согласованной копии. В терминале выполните:
mysqldump --default-character-set=utf8mb4 -u user -p site > site-backup.sqlЗамените user и site своими значениями. Пароль программа запросит отдельно. Храните дамп вне публичного каталога сайта.
В SQL-клиенте создайте отдельную тестовую базу:
CREATE DATABASE `site_test`
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;Затем в терминале восстановите дамп в эту базу:
mysql --default-character-set=utf8mb4 -u user -p site_test < site-backup.sqlСравните количество строк и несколько известных текстов с исходной базой. Восстановление должно завершиться без ошибок. Если дамп содержит процедуры, события или другие объекты приложения, включите их в план резервного копирования.
Как поменять кодировку базы и таблиц MySQL
Команда для базы меняет значение по умолчанию только для новых таблиц. Существующие таблицы нужно преобразовать отдельно.
ALTER DATABASE `site_test`
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;ALTER TABLE `site_test`.`users`
CONVERT TO CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;Замените users именем таблицы. Выполните команду для каждой таблицы, затем посмотрите структуру:
SHOW CREATE TABLE `site_test`.`users`;
SHOW FULL COLUMNS FROM `site_test`.`users`;Проверьте кодировку текстовых столбцов, сопоставления и сохранность известных строк. Сама команда CONVERT предполагает, что исходная кодировка столбца описывает его байты правильно. Для уже испорченных данных сначала разберите цепочку ошибочных преобразований.
На старых конфигурациях индекс для VARCHAR(255) может превысить допустимую длину. Переход на utf8mb4 увеличивает максимальный размер символа до 4 байт, поэтому сначала проверьте формат таблицы и индекс. Не сокращайте уникальный индекс без проверки требований приложения.
В MySQL 8 кодировка по умолчанию – utf8mb4, а сопоставление по умолчанию – utf8mb4_0900_ai_ci. В командах этой инструкции сопоставление задано явно. В MySQL имя utf8 служит устаревшим алиасом utf8mb3, который не хранит символы, требующие 4 байта.
Справочные сведения есть в документации MySQL и MariaDB.
Настройки сервера MySQL и MariaDB
Серверные параметры задают значения по умолчанию. Они не преобразуют существующие таблицы и не заменяют настройку PHP-соединения.
В Debian и Ubuntu типичные файлы находятся здесь:
/etc/mysql/my.cnf
/etc/mysql/mysql.conf.d/mysqld.cnf
/etc/mysql/mariadb.conf.d/50-server.cnfВ RHEL-подобных системах используйте:
/etc/my.cnf
/etc/my.cnf.d/Список путей конфигурации установленного сервера показывает команда:
mysqld --verbose --helpВ Windows запускайте ее из каталога серверной программы вашей сборки. Вывод перечисляет файлы, которые программа читает при запуске. Если процесс запущен с параметром --defaults-file, используйте указанный в нем файл.
В серверной и клиентской секциях укажите:
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
[client]
default-character-set = utf8mb4После изменения перезапустите сервер базы, откройте новое соединение и выполните:
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';Проверьте character_set_server и collation_server. Они должны содержать utf8mb4 и utf8mb4_unicode_ci соответственно. Затем проверьте чтение и запись через приложение.
Чтобы увидеть версию и действующие серверные значения в MySQL или MariaDB, выполните:
SELECT VERSION() AS server_version,
@@GLOBAL.character_set_server AS server_charset,
@@GLOBAL.collation_server AS server_collation;Результат описывает ваш сервер с учетом его конфигурации. Явные параметры соединения и таблиц сохраняйте независимо от серверных значений.
Двойная кодировка: как починить испорченные данные
Если «Ð¿Ñ€» хранится прямо в поле, настройка браузера не исправит запись. Восстановите копию базы в тестовую среду и посмотрите байты:
SELECT id, name, HEX(name)
FROM users
LIMIT 10;Для цепочки, где UTF-8 ошибочно прочитали как latin1 и сохранили результат в UTF-8, сначала получите исправленный вариант только чтением:
SELECT id,
name AS original_name,
CONVERT(
CAST(CONVERT(name USING latin1) AS BINARY)
USING utf8mb4
) AS repaired_name
FROM users
LIMIT 20;
SHOW WARNINGS;Сравните результат с известным исходным текстом. Проверьте поврежденные и правильные строки. Если появляются предупреждения или меняются правильные значения, не применяйте запрос ко всему столбцу.
Повреждение через Windows-1251 требует другой обратной последовательности. Переносите исправления по проверенным идентификаторам и с готовым откатом. Буквальные вопросительные знаки конвертация не восстановит.
Ошибки при переводе сайта на UTF-8
Проверьте границы между компонентами, если кракозябры остаются:
- BOM в PHP-файле. Проверьте основной файл и подключения перед вызовом
header(). - Нет кодировки соединения. Настройте mysqli или PDO и прочитайте переменные через это соединение.
- Изменена только база.
ALTER DATABASEне преобразует существующие таблицы. - Дамп загружен другой кодировкой клиента. Используйте одинаковый параметр при экспорте и импорте.
- HTTP противоречит meta. Исправьте заголовок сервера, потому что он главнее метатега.
- Файл только переобъявлен. Метатег не меняет байты файла Windows-1251.
- Таблица осталась в utf8mb3. Кириллица работает, но часть символов Unicode не сохраняется.
Сравните одну известную строку в файле, HTTP-ответе и таблице. Затем прочитайте ее через соединение приложения: разница покажет место сбоя.
Как открыть CSV в UTF-8 в Excel
Excel открывает CSV в UTF-8 обычным способом, если файл сохранен с BOM. Если после двойного щелчка появляются кракозябры, подготовьте отдельную копию файла:
- Откройте копию CSV в VS Code или Notepad++.
- Задайте правильную исходную кодировку. Русские слова должны читаться без искажений до сохранения.
- Сохраните копию в UTF-8 с BOM.
- Откройте сохраненную копию в Excel двойным щелчком.
- Сравните русские заголовки и несколько значений с исходным текстом.
Если текст остался испорченным, вернитесь к исходному CSV. Повторно откройте его в редакторе с правильной исходной кодировкой. Сохранение кракозябр в UTF-8 закрепляет ошибку.
BOM в этом способе нужен для распознавания CSV в Excel. Для PHP-файлов BOM не используйте. Исходный CSV храните отдельно, чтобы можно было повторить преобразование.
Порядок действий при переносе сайта
Каждый шаг проверяйте до перехода к следующему. Исходный дамп храните отдельно от промежуточных копий.
- Скопируйте файлы и создайте согласованный дамп базы при остановленной записи.
- Восстановите дамп в тестовую базу и сравните количество строк.
- Преобразуйте существующие таблицы в
utf8mb4. Проверьте структуру, индексы и текстовые поля. - Задайте
utf8mb4в соединении PHP и прочитайте переменные через него. - Сохраните исходники в UTF-8 без BOM и откройте несколько файлов повторно.
- Согласуйте метатег HTML и HTTP-заголовок. Посмотрите ответ в DevTools или через
curl. - Запишите тестовую строку с кириллицей и эмодзи. Прочитайте ее через приложение и SQL-клиент.
- Повторите проверенный перенос на рабочем сайте со свежей резервной копией.
Если после шага появились ошибки, остановите перенос и восстановите исходную копию. Не продолжайте преобразования поверх непонятного повреждения.
Популярное за неделю
- Как создать сайт самому в 2026: 4 способа + пошаговая инструкция 34 мин чтения
- Лучшие конструкторы для создания сайтов — плюсы, минусы и сравнения 22 мин чтения
- Форма авторизации на HTML и CSS: код входа и регистрации 8 мин чтения
- Как сделать отступ в HTML: табуляция и margin 3 мин чтения
- Как посмотреть исходный HTML-код страницы в браузере 4 мин чтения
- Как редактировать html файл в Chrome 1 мин чтения
Комментарии