UTF-8 亂碼是 PHP 開發最常見坑。本文從 HTTP 響應頭、PHP 檔案編碼、BOM 標記、MySQL 連線、附件下載檔名五個維度,給出完整排查與修復清單。
// 放在所有輸出之前(包括空白、HTML)
header('Content-Type: text/html; charset=UTF-8');
等同於 Apache AddDefaultCharset UTF-8 或 php.ini: default_charset = "UTF-8"(PHP 5.6+ 預設)。
檢查方法:file -i your.php 輸出 text/x-php; charset=utf-8
UTF-8 BOM = EF BB BF 三字節** 會被 PHP 視為輸出內容,導致:
session_start() 失敗:Cannot send session cache limiter - headers already sentheader()、setcookie() 失效移除方法:
find . -name "*.php" -exec sed -i '1s/^\xEF\xBB\xBF//' {} \;$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
]);
utf8(實為 utf8mb3,僅 3 字節)mysql_query("SET NAMES UTF8") 改為 SET NAMES utf8mb4$filename = '中文報表.xlsx';
$encoded = rawurlencode($filename); // RFC 5987 標準
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header("Content-Disposition: attachment; filename*=UTF-8''{$encoded}");
header('Content-Length: ' . filesize($filepath));
readfile($filepath);
舊瀏覽器兼容:
$ua = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/MSIE|Trident/', $ua)) {
$filename = iconv('UTF-8', 'GBK', $filename); // IE 老版本
header("Content-Disposition: attachment; filename=\"$filename\"");
} else {
header("Content-Disposition: attachment; filename*=UTF-8''{$encoded}");
}
function utf8_substr($str, $len) {
return mb_substr($str, 0, $len, 'UTF-8');
}
// 或通用函數
function msubstr($str, $start, $len, $charset = 'UTF-8', $suffix = true) {
$slice = mb_substr($str, $start, $len, $charset);
return $suffix && mb_strlen($str, $charset) > $len ? $slice . '...' : $slice;
}
header('Content-Type: text/html; charset=UTF-8') 在最頂部SET NAMES utf8mb4,表欄位 utf8mb4_unicode_ci<meta charset="UTF-8"> + accept-charset="UTF-8"iconv/mb_convert_encoding 來源/目標編碼正確filename*=UTF-8'' 格式json_encode($data, JSON_UNESCAPED_UNICODE)| 誤區 | 正確做法 |
|---|---|
以為 meta charset 就夠了 | HTTP Header 優先級高於 meta,必須雙重保險 |
用 utf8_encode/decode 處理中文 | 僅適用 ISO-8859-1 ↔ UTF-8,中文需 iconv/mb_convert_encoding |
| 忽略 BOM 導致 session 失效 | 全專案掃描移除 BOM,編輯器設定預設無 BOM |