首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

深度解析:為何推薦 mysqli_set_charset 而非 SET NAMES 設定 MySQL 字符集

     編輯:MySQL 資料庫相關知識

核心差異一覽

SET NAMES utf8 僅告知 Server 三個會話變量:character_set_client、character_set_connection、character_set_results 均為 utf8。但 mysqli_set_charset() 除執行 SET NAMES 外,關鍵多了一步:更新客戶端結構體 MYSQL->charset 指針。

源碼層面證明

PHP mysqli_set_charset 實現

PHP_FUNCTION(mysqli_set_charset) {
    // ... 參數解析 ...
    if (mysql_set_character_set(mysql->mysql, cs_name)) {
        RETURN_FALSE;
    }
    RETURN_TRUE;
}

C API mysql_set_character_set 內部邏輯

int mysql_set_character_set(MYSQL *mysql, const char *cs_name) {
    // ... 獲取字符集資訊 cs ...
    sprintf(buff, "SET NAMES %s", cs_name);
    if (!mysql_real_query(mysql, buff, strlen(buff))) {
        mysql->charset = cs;   // ★ 關鍵:更新客戶端 charset 指針
    }
    // ...
}

為何這一步至關重要?

mysql_real_escape_string() 在處理多字節字符(如 GBK 中低位字節為 0x5c 即反斜槓)時,依賴 mysql->charset 判斷當前字符集。若僅執行 SET NAMES,mysql->charset 仍為預設 latin1,導致轉義錯誤,產生經典「5c 問題」。

實測驗證

<?php
$db = mysql_connect('localhost:3737', 'root', '123456');
mysql_select_db("test");
$a = "\x91\x5c"; // "慭" 的 GBK 編碼,低位 0x5c = \

var_dump(addslashes($a));                    // string(3) "慭\"
var_dump(mysql_real_escape_string($a, $db)); // string(3) "慭\"  錯誤
mysql_query("set names gbk");
var_dump(mysql_real_escape_string($a, $db)); // string(3) "慭\"  仍錯誤
mysql_set_charset("gbk");
var_dump(mysql_real_escape_string($a, $db)); // string(2) "慭"   正確
?>

結論

  • PHP ≥ 5.0.5 / MySQL ≥ 4.1 環境下,務必使用 mysqli_set_charset() 或 PDO::MYSQL_ATTR_INIT_COMMAND;
  • 避免直接執行 SET NAMES,除非隨後手動同步客戶端 charset 結構(不可行)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved