**編碼不一致**導致資料在「資料庫 → 連線 → PHP → 瀏覽器」傳輸鏈路中錯誤轉碼。核心三點必須**完全一致**:
-- 建庫時指定
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 建表時指定
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 修改既有庫/表
ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
<?php
// MySQLi 面向物件
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
if ($mysqli->connect_errno) die('連線失敗: ' . $mysqli->connect_error);
// 關鍵:設定連線編碼
$mysqli->set_charset('utf8mb4');
// PDO
$pdo = new PDO('mysql:host=localhost;dbname=db;charset=utf8mb4', 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
// DSN 中 charset=utf8mb4 等同 SET NAMES,PHP 5.3.6+ 支援
?>
舊版寫法(不推薦):`$mysqli->query("SET NAMES utf8mb4");` 或 `mysql_query("SET NAMES utf8");`—— 繞過驅動層,可能導致預處理語句編碼異常。
<?php
// 必須在任何輸出之前
header('Content-Type: text/html; charset=utf-8');
// 或 nginx/Apache 配置預設 charset
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> <!-- HTML5 簡寫 -->
</head>
...
**編輯器儲存時選擇 UTF-8 without BOM**(VS Code、PhpStorm、Notepad++ 皆可設定)。
<?php
// 1. 檢查連線變數
$mysqli->query("SHOW VARIABLES LIKE 'character_set_%'");
// 期望:client, connection, results, database, server 皆為 utf8mb4
// 2. 寫入測試
$mysqli->query("INSERT INTO test (col) VALUES ('中文測試😀')");
// 3. 讀取測試
$result = $mysqli->query("SELECT col FROM test");
$row = $result->fetch_assoc();
echo $row['col']; // 頁面正常顯示「中文測試😀」即成功
?>
| 誤區 | 後果 | 正確做法 |
|---|---|---|
| 只加 `header('charset=utf-8')` 不設連線編碼 | 資料庫存正確,讀出亂碼(連線預設 latin1) | 必須 `set_charset('utf8mb4')` |
| 用 `utf8` 而非 `utf8mb4` | 無法儲存 Emoji、部分生僻字(MySQL utf8 為 utf8mb3) | 全鏈路用 `utf8mb4` |
| 檔案儲存為 ANSI/GBK/UTF-8 with BOM | BOM 導致 `header()` 失效、輸出異常 | 統一 UTF-8 without BOM |
| 資料庫編碼正確但表/欄位仍為 latin1 | 新資料正常,舊資料亂碼 | `ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4` |
| PDO DSN 未加 `charset=utf8mb4` 靠 `SET NAMES` | 預處理語句參數綁定可能編碼錯誤 | DSN 明確指定 charset |
SHOW VARIABLES LIKE 'character_set_%';
/*
character_set_client → 客戶端發送 SQL 的編碼
character_set_connection → 連線層轉換目標編碼
character_set_results → 結果集返回給客戶端的編碼
character_set_database → 當前資料庫預設編碼
character_set_server → 服務器預設編碼
character_set_system → 系統標識符編碼 (固定 utf8)
*/
-- SET NAMES utf8mb4 等同於:
SET character_set_client = utf8mb4;
SET character_set_results = utf8mb4;
SET character_set_connection = utf8mb4;
若這三個變數與資料實際編碼不一致,中間轉換會造成資料損壞(不可逆)。
**「編碼一致性三部曲」**:資料庫 `utf8mb4`、連線 `set_charset('utf8mb4')`、輸出 `header('charset=utf-8')` + 檔案 `UTF-8 without BOM`。缺一不可。現代專案**一律採用 utf8mb4**,棄用 `utf8`/`latin1`,從建庫、連線、輸出全鏈路統一,徹底杜絕中文亂碼。