Чому ваші кириличні (або хінді) літери перетворюються на "Привет" і як це виправити назавжди
\n\nВи коли-небудь відкривали свій PHP-сайт і замість "Привіт, світ!" бачили щось на кшталт Привет, РјРёСЂ!? Якщо так — вітаю, ви зіткнулися з класичною проблемою UTF-8 all the way through. Це ситуація, коли кодування десь ламається на шляху від бази даних до браузера, і в цьому винні всі, але ніхто не хоче брати на себе відповідальність.
На Stack Overflow це питання зібрало тисячі переглядів і сотні відповідей. І це правильно. Навіть досвідчені розробники іноді плутаються в налаштуваннях кодування. У цьому підручнику ми крок за кроком розберемо рецепт, як подружити PHP, MySQL і браузер, щоб UTF-8 працював скрізь і завжди. Жодної магії — лише правильні налаштування.
\n\nКрок 1. База даних: основа вашого кодування
\n\nВсе починається з бази даних. Якщо у вашому MySQL дані зберігаються в latin1 або cp1251, а ви намагаєтеся відобразити їх у UTF-8 — отримаєте абракадабру (кракозябри). Але навіть якщо база даних у UTF-8, є нюанс: старе кодування utf8 у MySQL не підтримує емодзі та деякі рідкісні китайські ієрогліфи. Рішення — utf8mb4.
1.1. Створення таблиць із правильним кодуванням
\n\nПри створенні нової таблиці завжди вказуйте:
\n\nCREATE TABLE articles (\n id INT AUTO_INCREMENT PRIMARY KEY,\n title VARCHAR(255) NOT NULL,\n content TEXT NOT NULL\n) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\nАбо встановіть кодування за замовчуванням для всієї бази даних:
\n\nALTER DATABASE your_database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\nВажливо: utf8mb4_unicode_ci — це collation (правило порівняння). Воно правильно обробляє всі символи Unicode. Якщо вам не потрібне сортування в різних мовах, підійде utf8mb4_general_ci.
1.2. Конвертація існуючих таблиць
\n\nЯкщо у вас уже є дані в іншому кодуванні, спочатку конвертуйте їх:
\n\nALTER TABLE articles CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\nАле будьте обережні: якщо в таблиці раніше були дані в latin1, вони можуть перетворитися на подвійне кодування (наприклад, Привет). У цьому випадку спочатку потрібно перевести стовпець у binary, а потім у utf8mb4. Це окрема історія, але для простоти припустимо, що ви починаєте з нуля.
Крок 2. PHP-підключення до бази даних: налаштування PDO
\n\nУ сучасному PHP ви використовуєте PDO (або mysqli). Ось важливий момент: після підключення до бази даних потрібно явно вказати кодування. Інакше PHP спілкуватиметься з MySQL у кодуванні за замовчуванням (часто latin1).
\n\n2.1. Правильний рядок підключення PDO
\n\n$host = 'localhost';\n$dbname = 'your_database';\n$username = 'root';\n$password = '';\n\n$dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";\n\n$options = [\n PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,\n PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,\n PDO::ATTR_EMULATE_PREPARES => false,\n];\n\ntry {\n $pdo = new PDO($dsn, $username, $password, $options);\n} catch (PDOException $e) {\n echo "Connection failed: " . $e->getMessage();\n}\n\nЗверніть увагу на charset=utf8mb4 у DSN. Це змушує PHP і MySQL домовитися про кодування на рівні з'єднання.
2.2. Альтернативний спосіб (якщо DSN не працює)
\n\nІноді старі версії PHP або сервера не зчитують charset із DSN. Тоді після підключення додайте:
\n\n$pdo->exec("SET NAMES 'utf8mb4'");\n\nАле перший спосіб кращий — він чистіший і сучасніший.
\n\nКрок 3. HTTP-заголовки та HTML: скажіть браузеру правду
\n\nНавіть якщо база даних і PHP працюють у UTF-8, браузер може вирішити, що