SET NAMES utf8 僅告知 Server 三個會話變量:character_set_client、character_set_connection、character_set_results 均為 utf8。但 mysqli_set_charset() 除執行 SET NAMES 外,關鍵多了一步:更新客戶端結構體 MYSQL->charset 指針。
PHP_FUNCTION(mysqli_set_charset) {
// ... 參數解析 ...
if (mysql_set_character_set(mysql->mysql, cs_name)) {
RETURN_FALSE;
}
RETURN_TRUE;
}
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) "慭" 正確
?>
mysqli_set_charset() 或 PDO::MYSQL_ATTR_INIT_COMMAND;SET NAMES,除非隨後手動同步客戶端 charset 結構(不可行)。