Avatar ·

UTF-8 на всём пути: как настроить PHP, MySQL и веб-сервер для корректной работы с кириллицей и Юникодом

Всем привет! Я начинающий PHP-разработчик, и у меня уже голова идёт кругом от проблем с кодировками. Сайт написан на PHP, база данных MySQL, сервер Apache. Всё вроде бы работает, но стоит пользователю ввести русские буквы в форму — начинается ад: в базе данных сохраняются кракозябры, вроде «РџСЂРёРІРµС‚», а при выводе на страницу — вопросительные знаки или пустые квадратики. Пробовал ставить в HTML-шапке `` — не помогло. Пробовал в PHP писать `header('Content-Type: text/html; charset=utf-8');` — тоже не панацея. В MySQL у таблиц стоит `utf8_general_ci`, но данные всё равно портятся. Вот пример моего кода: ```php query("INSERT INTO users (name) VALUES ('$name')"); // Выводим $result = $db->query("SELECT name FROM users"); while ($row = $result->fetch_assoc()) { echo $row['name']; } ?> ``` В чём проблема? Я слышал про «UTF-8 all the way through», но не понимаю, что это значит на практике. Какие настройки нужно сделать в PHP, MySQL и Apache, чтобы кириллица работала везде — от формы ввода до вывода на экран? Буду благодарен за пошаговое руководство для чайников! <<>>

Полное руководство по настройке UTF-8 в PHP, MySQL и Apache

Проблема, с которой вы столкнулись, классическая для начинающих разработчиков. Суть фразы «UTF-8 all the way through» (или «Юникод на всём пути») в том, что кодировка UTF-8 должна быть установлена на каждом этапе обработки данных: от браузера пользователя до базы данных и обратно. Если хотя бы один этап работает в другой кодировке (например, Windows-1251 или Latin1), данные искажаются.

Вот пошаговая инструкция, как исправить ситуацию раз и навсегда.

1. Настройка HTML-страницы

Убедитесь, что в <head> вашего HTML-шаблона указана правильная мета-информация:

<meta charset="UTF-8">

Или, если вы используете XHTML:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

2. Настройка PHP

В начале каждого PHP-скрипта (или в общем файле конфигурации) добавьте:

<?php
// Отправляем правильный HTTP-заголовок
header('Content-Type: text/html; charset=UTF-8');

// Устанавливаем внутреннюю кодировку для многобайтовых строк
mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');

// Если используете функции вроде substr(), strpos() — используйте их mb_* версии
?>

3. Настройка соединения с MySQL

Это самая частая ошибка. После подключения к БД, но до выполнения любых запросов, установите кодировку соединения:

<?php
$db = new mysqli('localhost', 'user', 'pass', 'mydb');

// Проверяем соединение
if ($db->connect_error) {
    die('Ошибка подключения: ' . $db->connect_error);
}

// Устанавливаем кодировку соединения UTF-8
$db->set_charset('utf8mb4'); // ВАЖНО: используйте utf8mb4, а не utf8!
// Или через запрос:
// $db->query("SET NAMES 'utf8mb4'");
?>

Почему utf8mb4? Потому что стандартный utf8 в MySQL поддерживает только 3 байта на символ (не хватает для эмодзи и некоторых редких иероглифов). utf8mb4 — полная 4-байтовая версия UTF-8.

4. Настройка базы данных и таблиц

При создании базы данных и таблиц используйте правильную кодировку и сравнение:

CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Если таблицы уже существуют, их можно изменить:

ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

5. Настройка Apache (веб-сервера)

В файле .htaccess или в конфигурации виртуального хоста добавьте:

AddDefaultCharset UTF-8

Или в PHP-файлах:

php_value default_charset UTF-8

6. Ваш исправленный код

<?php
header('Content-Type: text/html; charset=UTF-8');
mb_internal_encoding('UTF-8');

$db = new mysqli('localhost', 'user', 'pass', 'mydb');
if ($db->connect_error) {
    die('Ошибка: ' . $db->connect_error);
}

// Ключевая строка:
$db->set_charset('utf8mb4');

$name = $_POST['name']; // В реальном проекте — экранируйте!
$stmt = $db->prepare("INSERT INTO users (name) VALUES (?)");
$stmt->bind_param('s', $name);
$stmt->execute();

$result = $db->query("SELECT name FROM users");
while ($row = $result->fetch_assoc()) {
    echo htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8');
}
?>

Что ещё проверить?

  • Редактор кода: Убедитесь, что ваш PHP-файл сохранён в кодировке UTF-8 (без BOM). В VS Code, PhpStorm, Sublime это настраивается внизу окна.
  • Формы: У форм тоже должен быть атрибут accept-charset="UTF-8" (хотя современные браузеры по умолчанию используют кодировку страницы).
  • JSON: При работе с JSON используйте json_encode($data, JSON_UNESCAPED_UNICODE).
  • Файлы: Если читаете/пишете файлы, используйте fopen() с указанием кодировки или file_get_contents().

После этих настроек русские буквы, эмодзи и любые символы Юникода будут корректно проходить весь путь: браузер → PHP → MySQL → PHP → браузер.

<<>>

Альтернативный подход: использование PDO и глобальных настроек

Если вы предпочитаете PDO вместо mysqli, вот как настроить UTF-8 в этом случае:

<?php
header('Content-Type: text/html; charset=UTF-8');

$dsn = 'mysql:host=localhost;dbname=mydb;charset=utf8mb4';
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8mb4'"
];

try {
    $db = new PDO($dsn, 'user', 'pass', $options);
} catch (PDOException $e) {
    die('Ошибка подключения: ' . $e->getMessage());
}

// Теперь все запросы будут в UTF-8
$name = $_POST['name'];
$stmt = $db->prepare("INSERT INTO users (name) VALUES (?)");
$stmt->execute([$name]);

$result = $db->query("SELECT name FROM users");
foreach ($result as $row) {
    echo htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8');
}
?>

Также рекомендую проверить php.ini — там можно установить глобальные значения:

default_charset = "UTF-8"
mbstring.internal_encoding = UTF-8
mbstring.http_output = UTF-8
mbstring.func_overload = 0

И не забывайте про htmlspecialchars() при выводе данных — это защитит от XSS-атак и гарантирует правильное отображение спецсимволов.