PHP 專案中文亂碼雖常見,但核心原理一致:編碼在產生、傳輸、儲存、顯示四個環節必須完全一致。本文系統梳理字符集基礎、資料庫編碼、HTTP Header/Meta/Apache 優先級、PHP 設定,並提供定位技巧與解決清單。
現代系統核心層多以 Unicode 處理,邊界處(資料庫、HTTP、檔案)做編碼轉換。
// PHP 連接資料庫後立即執行
mysql_query("SET NAMES utf8"); // 或 mysqli_set_charset($link, 'utf8')
// 對應網頁 charset=utf-8
// 若網頁 charset=gb2312,則 SET NAMES gb2312
CHARSET=utf8mb4(支援 Emoji)。latin1 (ISO-8859-1) 儲存中文,會導致雙位元組拆分、查詢錯誤。header("Content-Type: text/html; charset=utf-8") —— PHP 函式發送 HTTP Header,瀏覽器**強制遵守**。AddDefaultCharset utf-8 —— Apache httpd.conf 設定,等同於給每個回應加 Header。<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> —— HTML Meta 標籤,屬於文件內容,**優先級最低**,若前兩者存在將被忽略。建議:每個 PHP 檔案頂部呼叫 header(...),確保跨伺服器部署不受 Apache 設定影響。
; 建議註釋掉,讓瀏覽器依頁面 charset 自動判斷 ; default_charset = "gb2312"
強制設定會導致多語言共存時編碼衝突。
echo bin2hex($str) 或 var_dump(unpack('H*', $str)),觀察位元組變化。"aa啊 aa?@aa"(中英混雜、含特殊符號)作為測試資料。| 場景 | 解決方法 |
|---|---|
| 資料庫讀出亂碼 | 連接後 SET NAMES 對應charset;表/欄位 charset 一致 |
| 頁面顯示亂碼 | PHP header() 強制宣告;檢查 Apache AddDefaultCharset |
| 表單提交亂碼 | 頁面 <form accept-charset="utf-8">;PHP 接收端 mb_convert_encoding |
| 檔案讀寫亂碼 | 確認檔案實際編碼;PHP mb_detect_encoding + iconv 轉換 |
| JSON API 亂碼 | 回應 Header Content-Type: application/json; charset=utf-8;json_encode($data, JSON_UNESCAPED_UNICODE) |
// 自動偵測並轉為 UTF-8
function to_utf8($str) {
$enc = mb_detect_encoding($str, ['UTF-8', 'GBK', 'GB2312', 'BIG5']);
return $enc !== 'UTF-8' ? iconv($enc, 'UTF-8//IGNORE', $str) : $str;
}
中文編碼問題本質是「編碼不一致」。堅持 **UTF-8 全鏈路**(資料庫、連接、PHP、HTML、JS、CSS、檔案),並在 PHP 入口統一發送 header(),即可從根源消除 99% 的亂碼。