MSSQL 預設使用 GBK/CP936(中文版 Windows)或 Latin1 儲存中文,而現代 Web 應用採用 UTF-8。編碼鏈路任一環節不一致即產生亂碼:
資料庫儲存編碼 → 驅動傳輸編碼 → PHP 內部編碼 → HTTP 輸出編碼 → 瀏覽器渲染編碼
<?php
$dsn = "sqlsrv:Server=192.168.1.100;Database=mydb;CharacterSet=UTF-8";
$pdo = new PDO($dsn, 'sa', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
// 驅動自動將 GBK/CP936 轉為 UTF-8,PHP 端直接拿正確字串
$stmt = $pdo->query("SELECT name FROM users");
while ($row = $stmt->fetch()) {
echo $row['name']; // 正常顯示中文
}
?>
關鍵:DSN 加上 CharacterSet=UTF-8,驅動層處理轉碼,最乾淨。
; php.ini
mssql.charset = "UTF-8" ; PHP 5.3+ 支援
; 或舊版
mssql.charset = "GBK" ; 強制驅動以 GBK 讀取,PHP 再自行 iconv
重啟 php-fpm/Apache。缺點:PHP 7.0 移除 mssql 擴展,非長久之計。
<?php
// 假設資料庫實際編碼為 GBK
$row = mssql_fetch_assoc($result);
$name = iconv('GBK', 'UTF-8//IGNORE', $row['name']);
// 或
$name = mb_convert_encoding($row['name'], 'UTF-8', 'GBK');
適用:無法更換驅動、無法改 php.ini 的舊專案維護期。
<?php
$conn = new COM("ADODB.Connection", NULL, CP_UTF8); // CP_UTF8 = 65001
$conn->Open("Driver={SQL Server};Server=192.168.1.100;Database=mydb;UID=sa;PWD=pass;");
$rs = $conn->Execute("SELECT name FROM users");
while (!$rs->EOF) {
echo $rs->Fields['name']->Value; // 已為 UTF-8
$rs->MoveNext();
}
$rs->Close();
$conn->Close();
?>
將舊 varchar/text 改為 nvarchar/ntext (Unicode UCS-2),配合驅動 CharacterSet=UTF-8,徹底消除編碼轉換問題:
ALTER TABLE users ALTER COLUMN name NVARCHAR(100);
優點:儲存層即為 Unicode,支援多國語言,避免 GBK/Big5 衝突。
| 層級 | 檢查項目 | 正確設定 |
|---|---|---|
| 資料庫 | 欄位型別 | 優先 NVARCHAR/NTEXT |
| 資料庫 | 排序規則 | Chinese_PRC_CI_AS 或 Chinese_PRC_CS_AS |
| 驅動 | DSN 字元集 | CharacterSet=UTF-8 (sqlsrv/PDO_SQLSRV) |
| PHP | 內部編碼 | mb_internal_encoding('UTF-8'); |
| PHP | 輸出標頭 | header('Content-Type: text/html; charset=UTF-8'); |
| HTML | Meta 標籤 | <meta charset="UTF-8"> |
| 檔案 | 原始碼編碼 | 編輯器儲存為 UTF-8 無 BOM |
SET NAMES UTF8 對 MSSQL 有效。事實:這是 MySQL 指令,MSSQL 無此語法。CONVERT(VARCHAR(MAX), col) 解決亂碼。事實:這只是型別轉換,若排序規則不支援中文,轉換後仍會丟字。iconv('UTF-8','GBK',$str) 寫入。事實:雙向轉碼極易造成資料損壞,應在驅動層統一處理。sqlsrv/PDO_SQLSRV,DSN 加 CharacterSet=UTF-8。NVARCHAR,清洗現有資料。mssql、COM、ODBC 等舊技術,全面標準化於 PDO_SQLSRV。MSSQL 中文亂碼本質是「編碼鏈路斷裂」。現代解法:**驅動層統一轉碼 (CharacterSet=UTF-8) + 資料庫層採用 Unicode (NVARCHAR) + 全鏈路 UTF-8**。一次設定,永久解決,拒絕在業務代碼中散落 iconv。