萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

mysqli_set_charset vs SET NAMES:字元集設定的關鍵差異與安全性分析

字元集設定的兩條路徑:SET NAMES vs mysqli_set_charset

兩者都能設定 character_set_client、character_set_connection、character_set_results,但 **mysqli_set_charset 額外更新客戶端結構體 charset 指標,影響 mysql_real_escape_string 安全性**。

SET NAMES 作用機制

SET NAMES utf8;
-- 等價於:
SET character_set_client = utf8;
SET character_set_connection = utf8;
SET character_set_results = utf8;

⚠️ **缺陷**:僅修改 Session 變數,**不更新 PHP mysqli 客戶端結構體**,導致 mysqli_real_escape_string() 仍使用舊字元集判斷多位元組字元,造成 **SQL 注入風險**(特別是 GBK/Big5 等多位元組編碼)。

mysqli_set_charset 內部實作 (libmysql/client.c)

int mysql_set_character_set(MYSQL *mysql, const char *cs_name) {
  // 1. 執行 SET NAMES
  sprintf(buff, "SET NAMES %s", cs_name);
  mysql_real_query(mysql, buff, strlen(buff));
  // 2. 關鍵:更新客戶端結構體 charset 指標
  mysql->charset = cs;  // 指向 charset_info_st 結構
}

實測驗證:GBK 編碼下的 SQL 注入風險

對比總結表

特性SET NAMESmysqli_set_charset
設定 Session 字元集✅✅
更新客戶端 charset 結構體❌✅
影響 mysqli_real_escape_string❌ (危險)✅ (安全)
PDO 等效方法SET NAMESPDO::MYSQL_ATTR_INIT_COMMAND 或 DSN charset=utf8
持久連線行為每次查詢需重設連線池內自動保持

最佳實務建議

  1. PHP mysqli: 連線建立後**立即**呼叫 $mysqli->set_charset('utf8mb4')
  2. PDO: DSN 加入 charset=utf8mb4 (PHP 5.3.6+)
  3. 避免 直接執行 SET NAMES 作為唯一設定手段
  4. 資料庫層:my.cnf 設定 character-set-server=utf8mb4、collation-server=utf8mb4_unicode_ci

核心結論: mysqli_set_charset 是**唯一正確**的 PHP 客戶端字元集設定方式,它同步更新 Session 變數與客戶端內部狀態,保障 real_escape_string 正確處理多位元組字元,防禦 SQL 注入。

copyright © 萬盛學電腦網 all rights reserved