MySQL 亂碼本質上是 字符集不匹配:Client、Connection、Server、Database、Table、Column、Results 任一環節編碼不一致即會導致存入/讀出錯誤。
在建立連線後、執行任何 SQL 前,立即執行:
$link = mysqli_connect($host, $user, $pass, $db);
mysqli_set_charset($link, 'utf8mb4'); // 推薦:支援 emoji、完整 Unicode
// 或舊版相容
mysqli_query($link, "SET NAMES 'utf8mb4'");
// mysqli_query($link, "SET CHARACTER SET utf8mb4");
// mysqli_query($link, "SET CHARACTER_SET_RESULTS=utf8mb4");
SET NAMES utf8mb4 等同於同時設定:
character_set_clientcharacter_set_connectioncharacter_set_results-- 建庫指定
CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 建表指定
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 修改現有表
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 僅修改預設,不轉換現有資料
ALTER TABLE users DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
<meta charset="utf-8"> 或 header('Content-Type: text/html; charset=utf-8')<form accept-charset="utf-8">mysqli_set_charset($link, 'utf8mb4')-- 匯出(指定編碼)
mysqldump -u root -p --default-character-set=utf8mb4 dbname > backup.sql
-- 匯入(指定編碼)
mysql -u root -p --default-character-set=utf8mb4 dbname < backup.sql
避免使用 mysql -u root -p dbname < backup.sql 依賴預設編碼,不同版本預設值不同(MySQL 4.x latin1、5.x utf8、8.0 utf8mb4)。
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4'
skip-character-set-client-handshake = TRUE # 強制忽略客戶端字符集聲明
修改後需重啟 MySQL 服務生效。
| 誤區 | 正確做法 |
|---|---|
以為 utf8 就是完整 Unicode | MySQL utf8 僅支援 BMP(3 字節),需用 utf8mb4 支援 4 字節字符 |
| 只設定資料庫編碼,忽略連線編碼 | 連線編碼 最高優先級,必須 SET NAMES |
| PHP 檔案編碼為 ANSI/GBK | 統一使用 UTF-8 無 BOM |
| 匯入 SQL 檔未指定編碼 | mysqldump/mysql 皆加 --default-character-set |
SHOW VARIABLES LIKE 'character_set%'; 所有 *_client/connection/results/database/server 為 utf8mb4SHOW CREATE TABLE users; 是否為 utf8mb4SELECT HEX(name) FROM users WHERE id=1;