中文資料從「資料庫儲存」→「連線傳輸」→「PHP 處理」→「HTML 輸出」→「瀏覽器渲染」,任一環節編碼不符即產生亂碼。
-- 建庫指定 utf8mb4(支援 Emoji、完整 Unicode)
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;
-- 檢查現有表編碼
SHOW CREATE TABLE users;
utf8mb4(MySQL 5.5.3+),而非舊版 utf8(僅支援 BMP 字元)。utf8mb4_unicode_ci(準確排序)或 utf8mb4_general_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,
]);
// 舊版 mysql_* (已棄用)
mysql_query("SET NAMES 'utf8mb4'");
SET NAMES utf8mb4 等同於同時設定 character_set_client、character_set_connection、character_set_results 三個系統變數。
header() 失效、輸出前有隱形字元。<meta charset="utf-8">
<meta charset="utf-8">
header('Content-Type: text/html; charset=utf-8');
| 現象 | 可能原因 | 解決方向 |
|---|---|---|
| (菱形問號) | UTF-8 資料被當成 Latin1/GBK 解碼 | 檢查連線 set_charset、HTML charset |
| (單一問號) | 資料庫欄位編碼不支援該字元(如 utf8 存 Emoji) | 改用 utf8mb4 |
| 鍟斤拷 (亂碼字母) | UTF-8 被雙重編碼或 GBK/Big5 混雜 | 統一全鏈路為 utf8mb4 |
| 正常顯示但存入資料庫變 ?? | 連線編碼錯誤導致寫入時轉換失敗 | 設定 set_charset('utf8mb4') |
<?php
// 若資料庫實際儲存為 latin1 但內容是 utf8 位元組
// 讀出後轉換
$wrong = $row['name']; // 從 latin1 連線讀出
$correct = iconv('latin1', 'utf-8', $wrong);
// 或 mysqli 連線指定 latin1 讀出再轉碼
$mysqli->set_charset('latin1');
$raw = $mysqli->query("SELECT name FROM users")->fetch_assoc()['name'];
$fixed = iconv('latin1', 'utf-8', $raw);
// 更新回資料庫(需 utf8mb4 連線)
$mysqli->set_charset('utf8mb4');
$mysqli->query("UPDATE users SET name = '{$mysqli->real_escape_string($fixed)}' WHERE id = ...");
?>
<?php
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
$mysqli->set_charset('utf8mb4');
echo "資料庫編碼:" . $mysqli->character_set_name() . "\n";
echo "連線編碼:" . $mysqli->get_charset()->collation . "\n";
$vars = ['character_set_client', 'character_set_connection', 'character_set_results', 'character_set_database'];
foreach ($vars as $v) {
$r = $mysqli->query("SHOW VARIABLES LIKE '$v'");
echo "$v: " . $r->fetch_assoc()['Value'] . "\n";
}
?>