PHP 5 的流讀取函數(file_get_contents()、fopen() 等)默認使用 UTF-8 編碼讀取流數據。讀取 GB2312/GBK 編碼文件時,若不指定編碼,PHP 會嘗試按 UTF-8 解析,導致中文亂碼。
// ❌ 低效且不穩定
$content = file_get_contents($file);
$content = iconv('UTF-8', 'GB2312', $content); // 實際經歷:流→UTF-8→GB2312 兩次轉換
缺點:依賴 iconv 擴展;實際發生雙重轉換;無法處理無 BOM 或編碼聲明錯誤的文件。
PHP 文檔明確指出:可通過 stream_default_encoding() 或 自定義流上下文 指定編碼。前者 PHP 6+ 支持,現行版本採用後者。
// 設置流編碼為 GB2312(文件流用 'file',HTTP 流用 'http')
$opts = array(
'file' => array(
'encoding' => 'gb2312'
)
);
$context = stream_context_create($opts);
// 讀取時傳入上下文
$content = file_get_contents($filename, FILE_TEXT, $context);
$opts = array(
'http' => array(
'method' => 'GET',
'header' => "Accept-Charset: gb2312, utf-8;q=0.7\r\n",
'encoding' => 'gb2312' // 強制按 GB2312 解碼響應體
)
);
$context = stream_context_create($opts);
$content = file_get_contents('https://example.com/gbk-page.html', false, $context);
當編碼未知時,推薦流程:
Content-Type 中的 charset<meta charset=...> 或 <meta http-equiv="Content-Type">mb_detect_encoding() 或 Encoding::detect()(第三方庫)檢測| 場景 | 推薦方案 |
|---|---|
| 本地已知編碼文件 | stream_context 指定 encoding 參數 |
| 遠程 HTTP 頁面 | 優先響應頭,回退 meta 標簽,最後自動檢測 |
| 批量處理混合編碼 | 封裝統一讀取類,內部集成檢測+上下文創建邏輯 |
| 大文件流式處理 | fopen + stream_filter_append('convert.iconv.GB2312/UTF-8') |
// 快速驗證編碼是否正確
echo mb_check_encoding($content, 'UTF-8') ? 'UTF-8 OK' : '編碼異常';
// 或檢查是否包含預期中文
echo strpos($content, '預期中文') !== false ? '內容正常' : '可能亂碼';