ThinkPHP 早期版本(2.x/3.x)在 magic_quotes_gpc = On 環境下,極易出現資料庫寫入雙重反斜線(\\'、\\")的問題。根因在於框架未判斷 PHP 內建轉義即自行再次 addslashes,導致「PHP 自動轉義 + 框架手動轉義」雙重處理。本文深入剖析機制,提供三種徹底解決方案,並說明為何某些常見修法不可取。
現象: 表單提交「O'Reilly」入庫變成「O\\'Reilly」,前台顯示帶反斜線。
環境: PHP 5.3 以下且 php.ini 設定 magic_quotes_gpc = On(PHP 5.4+ 已移除此特性)。
流程:
$_GET/POST/COOKIE 執行 addslashes(單引號變 \')。escape_string() 再次執行 addslashes / mysql_real_escape_string。\' → \\',資料庫存入雙重反斜線。在 index.php 最早期(引入框架前)插入:
<?php
if (get_magic_quotes_gpc()) {
function stripslashes_deep($val) {
return is_array($val) ? array_map('stripslashes_deep', $val) : stripslashes($val);
}
$_GET = array_map('stripslashes_deep', $_GET);
$_POST = array_map('stripslashes_deep', $_POST);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
$_REQUEST= array_map('stripslashes_deep', $_REQUEST);
}
// 之後框架內部再按需 escape,邏輯統一
?>
優點: 徹底還原原始資料,框架後續統一處理,不侵入核心類,升級無痛。
注意: 必須在 define('APP_PATH') 之前、任何框架代碼執行前。
escape_string() 為「先去再加」(次推薦)編輯 ThinkPHP/Lib/Think/Db/Driver/Mysql.class.php(或對應驅動):
public function escape_string($str) {
// 關鍵:無論來源,先移除現有反斜線,再按資料庫規則轉義
$str = stripslashes($str);
if ($this->_linkID) {
return mysql_real_escape_string($str, $this->_linkID);
}
return mysql_escape_string($str); // 舊版 fallback
}
優點: 集中在資料庫層解決,不影響其他元件。
缺點: 修改核心檔,升級覆蓋;若專案使用 PDO/mysqli 驅動需同步修改對應類。
修改 php.ini:
magic_quotes_gpc = Off
magic_quotes_runtime = Off
magic_quotes_sybase = Off
或在 .htaccess / .user.ini:
php_flag magic_quotes_gpc Off
優點: 移除 PHP 層面干擾,框架邏輯單純化。
缺點: 共享主機可能無權限;舊專案若依賴 magic_quotes 可能產生注入風險(需全站檢查)。
常見錯誤寫法:
// 錯誤示範
public function escape_string($str) {
if (get_magic_quotes_gpc()) return $str; // 危險!
return mysql_real_escape_string($str);
}
反例: 若資料來源為 file_get_contents()、資料庫讀取、API 回傳等非 GPC 來源,magic_quotes_gpc 不會處理,導致這些資料「漏逃脫」,造成 SQL 注入隱患。
正確原則: 統一輸入 → 統一清洗 → 統一轉義,勿依賴來源判斷。
magic_quotes_gpc,問題自然消失。總結: 雙重轉義本質是「多層轉義邏輯疊加」。最穩健做法是入口統一 stripslashes,框架統一 escape/預處理。若擁有伺服器控制權,關閉 magic_quotes_gpc 為一勞永逸之計。