首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

PHP 讀寫 MySQL 亂碼終極解決:字符集三層協商機制與最佳實踐配置

     編輯:MySQL 綜合教學

亂碼本質:Client → Connection → Server → Results 四層編碼不一致

MySQL 字符集流向:


PHP腳本(UTF-8) → client → connection → Server(存儲GBK) → connection → results → PHP顯示(UTF-8)

任一環節不匹配即產生亂碼。Discuz UTF-8 頁面卻用 GBK 存儲的秘密在於顯式設置三層字符集變量。

根因定位:三個關鍵 Session 變量

變量含義設置建議 (PHP UTF-8 + DB GBK)
character_set_client客戶端發送 SQL 的編碼utf8 (PHP 發送 UTF-8 SQL)
character_set_connectionServer 接收後轉換的目標編碼gbk (轉為 GBK 存儲/操作)
character_set_results查詢結果返回給客戶端的編碼utf8 (結果轉回 UTF-8 給 PHP)

終極解決方案:連接建立後立即執行


// PDO 方式
$pdo = new PDO("mysql:host=localhost;dbname=test", 'user', 'pass');
$pdo->exec("SET character_set_client = utf8");
$pdo->exec("SET character_set_connection = gbk");
$pdo->exec("SET character_set_results = utf8");

// mysqli 方式
$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$mysqli->query("SET character_set_client = utf8");
$mysqli->query("SET character_set_connection = gbk");
$mysqli->query("SET character_set_results = utf8");

// 封裝為連接初始化方法
function initCharset($pdo) {
  $pdo->exec("SET NAMES utf8");  // 僅當 DB 也為 UTF-8 時使用
  // 異構編碼必須分別設置上述三條
}

為什麼 SET NAMES utf8 不夠?

SET NAMES utf8 等同於同時設置上述三變量為 utf8。若資料庫實際存儲為 GBK,會導致「寫入時 UTF-8 → GBK 轉碼錯誤」或「讀出時 GBK → UTF-8 雙重轉碼」。

資料庫/表/欄位字符集定義


CREATE DATABASE `test` DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;
CREATE TABLE `t` (
  `name` VARCHAR(20) CHARACTER SET gbk COLLATE gbk_chinese_ci
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

優勢:CHAR(20) 可存 20 個漢字(而非 20/2 或 20/3 字節),LENGTH() 返回字節數,業務邏輯按字符計數更直觀。

避坑清單

  1. PHP 源文件保存為 UTF-8 無 BOM。
  2. HTML <meta charset="utf-8">、HTTP Header Content-Type: text/html; charset=utf-8。
  3. 資料庫連接類(PDO/mysqli)統一封裝初始化字符集,不要依賴 my.cnf 默認值(跨環境不一致)。
  4. 遷移數據時,用 iconv 或 mb_convert_encoding 批量轉碼,驗證 HEX(col) 確認存儲正確。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved