開啟 magic_quotes_gpc = On 時,ThinkPHP 入庫資料出現雙重反斜線(如 \\'、\\"),導致顯示異常、查詢失敗。
magic_quotes_gpc 自動對 $_GET/POST/COOKIE 加斜線。escape_string() 再次加斜線,造成雙重轉義。
3. 若資料來源非 GPC(如讀取檔案、API 回應),又缺乏首次轉義,導致漏轉義。
在 index.php 最頂端加入:
<?php
if (!get_magic_quotes_gpc()) {
function addslashesDeep($val) {
return is_array($val) ? array_map('addslashesDeep', $val) : addslashes($val);
}
$_POST = array_map('addslashesDeep', $_POST);
$_GET = array_map('addslashesDeep', $_GET);
$_COOKIE = array_map('addslashesDeep', $_COOKIE);
$_REQUEST = array_map('addslashesDeep', $_REQUEST);
}
?>
效果:模擬 magic_quotes_gpc = On 行為,確保所有 GPC 資料「恰好」被轉義一次,後續框架 escape_string() 再轉義即為正確的雙重防護(資料庫層)。
<?php
// ThinkPHP DbMysql.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);
}
缺點:若資料已經過轉義(如方案一處理後),此處 stripslashes 會把正常的轉義移除,導致資料庫層轉義不足;且 mysql_* 函數已棄用。
ThinkPHP 3.2+ / 5.0+ / 6.0+ 預設使用 PDO,完全不需要手動轉義**:
<?php
// ThinkPHP 6.0 範例
Db::table('users')->insert([
'name' => $request->post('name'), // 直接傳入,框架內部用參數綁定
'email' => $request->post('email'),
'bio' => $request->post('bio'),
]);
// 內部實際執行:INSERT INTO users (name,email,bio) VALUES (?,?,?)
// 參數分開傳送,零 SQL Injection 風險,零轉義煩惱
?>
| ThinkPHP 版本 | 資料庫層 | 建議做法 |
|---|---|---|
| 2.x / 3.0 | mysql_* + escape_string | 套用方案一(入口統一處理),並規劃升級 |
| 3.1 / 3.2 | mysqli / PDO 可選 | 強制啟用 PDO,棄用 escape_string |
| 5.0 / 5.1 / 6.0 / 8.0 | PDO 預設 | 直接使用模型/查詢構建器,零轉義煩惱 |
<?php
// 測試腳本
$_POST['test'] = "O'Reilly"; // 含單引號
// 套用方案一後
var_dump($_POST['test']); // O\'Reilly (已轉義一次)
// 入庫
Db::table('test')->insert(['content' => $_POST['test']]);
// 資料庫實際儲存:O'Reilly (正確)
// 讀出顯示:O'Reilly (正確)
?>
雙重轉義本質是「責任不清」:PHP 層、框架層、資料庫層各自為政。**現代最佳實務:入口層統一模擬 GPC 轉義(或關閉 magic_quotes),資料庫層全面改用 PDO 參數綁定**,徹底消除轉義邏輯與 SQL Injection 風險。