中文亂碼是 PHP 開發最常見的坑,本文系統梳理五大成因與對應解決方案,建立完整的 UTF-8 編碼鏈路。
SET NAMES utf8mb4<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> <!-- HTML5 簡潔寫法 -->
<!-- 舊版相容 -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<?php
// PHP 入口檔案最頂端
header("Content-Type: text/html; charset=utf-8");
重要:PHP 檔案本身必須以 UTF-8 無 BOM 格式儲存(編輯器另存新檔選 UTF-8)。
-- 建立資料庫指定 utf8mb4
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 建立資料表指定 utf8mb4
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 修改既有資料表/欄位
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE users MODIFY name VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
推薦使用 utf8mb4 而非 utf8:支援 Emoji 與完整 Unicode 字元(utf8 僅支援 BMP 平面)。
// mysqli 物件導向
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
$mysqli->set_charset('utf8mb4'); // 關鍵!
// PDO(推薦)
$pdo = new PDO('mysql:host=localhost;dbname=db;charset=utf8mb4', 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
// 旧式 mysql_* 函式(已棄用,僅供參考)
mysql_connect('localhost', 'user', 'pass');
mysql_select_db('db');
mysql_query("SET NAMES utf8mb4");
// 檢查連線字元集
$mysqli->query("SHOW VARIABLES LIKE 'character_set_%'");
// 應顯示 client, connection, results, database 皆為 utf8mb4
| 檢查點 | 正確值 |
|---|---|
| HTML meta charset | utf-8 |
| PHP header Content-Type | text/html; charset=utf-8 |
| PHP 檔案儲存編碼 | UTF-8 無 BOM |
| 資料庫預設字元集 | utf8mb4 |
| 資料表/欄位字元集 | utf8mb4 |
| 連線字元集 (SET NAMES) | utf8mb4 |
| PDO DSN charset 參數 | charset=utf8mb4 |
SET NAMES utf8 就夠了 → 必須是 utf8mb4mysql_* 函式且未執行 SET NAMES建立「UTF-8 全鏈路」是根治中文亂碼的唯一正解:檔案編碼 → HTML 輸出 → PHP header → 連線字元集 → 資料庫/資料表/欄位,層層把關。