在 PHP 開發中,資料庫亂碼是困擾許多開發者的經典問題。當資料庫、資料表、連線編碼與 PHP 腳本編碼不一致時,中文資料就會顯示為亂碼。本文將系統梳理亂碼產生的根本原因,並提供徹底解決的最佳實踐。
解決亂碼的鐵律只有一條:資料庫儲存編碼、資料表編碼、連線編碼、PHP 腳本檔案編碼、HTML 頁面編碼這五者必須完全一致。建議統一採用 UTF-8(或 utf8mb4),避免使用 GBK、BIG5 等舊編碼。
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;
PDO 方式(推薦):
$dsn = "mysql:host=localhost;dbname=mydb;charset=utf8mb4";
$pdo = new PDO($dsn, 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
mysqli 方式:
$mysqli = new mysqli('localhost', 'user', 'pass', 'mydb');
$mysqli->set_charset('utf8mb4');
舊版 mysql_* 函數(已棄用):
mysql_query("SET NAMES 'utf8mb4'"); // 必須在查詢前執行
使用編輯器(VS Code、PhpStorm、Sublime Text 等)將所有 .php 檔案另存為「UTF-8 無 BOM」編碼。BOM 會導致輸出檔頭干擾 HTTP 標頭。
<meta charset="UTF-8">
// 或 HTTP 標頭
header('Content-Type: text/html; charset=UTF-8');
原始碼片段:
$fileName = "qtgz/qtgongzi.txt";
$fContent = file($fileName);
foreach ($fContent as $a_content) {
list($QT_sfz, $QT_xm, $QT_bz, $QT_je) = explode(",", $a_content);
// 直接寫入資料庫
$query = "INSERT INTO qita (...) VALUES ('$QT_sfz', '$QT_xm', ...)";
$rst = $aa->excu($query);
}
問題分析:文字檔編碼可能為 GBK/BIG5,而資料庫為 UTF-8,直接寫入會導致亂碼。
解決方案:在寫入前偵測並轉換編碼:
// 假設文字檔為 GBK
$QT_xm = mb_convert_encoding($QT_xm, 'UTF-8', 'GBK');
// 或使用 iconv
$QT_xm = iconv('GBK', 'UTF-8//IGNORE', $QT_xm);
若專案中混用多個資料庫連線(如主庫、從庫、快取庫),每一條連線都必須執行 `SET NAMES utf8mb4` 或對應的 `set_charset()`。漏掉任何一條連線都會導致該連線下的查詢亂碼。
utf8 實為 utf8mb3,不支援 Emoji 與生僻字,請一律使用 utf8mb4。utf8mb4_unicode_ci(準確排序)或 utf8mb4_general_ci(速度略快)。default_charset = "UTF-8" 確保內部編碼一致。CONVERT TO CHARACTER SET 重建資料表。遵循「全鏈路 UTF-8」原則,配合上述檢查清單,即可徹底告別 PHP MySQL 亂碼困擾。