SQL 注入曾是 Web 應用頭號殺手,雖然現代框架內建參數化查詢已大幅降低風險,但理解底層防護機制對維護舊專案、排查漏洞仍具關鍵價值。本文深入剖析 magic_quotes_gpc 的行為差異,並提供一個健壯的通用輸入過濾函數,解決「開啟時重複轉義、關閉時裸奔」的兩難困境。
當 php.ini 中 magic_quotes_gpc = On 時,PHP 自動對 $_GET、$_POST、$_COOKIE 中的單引號(')、雙引號(")、反斜線(\)、NULL 字元加上反斜線轉義。若開發者同時手動調用 addslashes(),將導致雙重轉義,資料庫存入 Tom\'s book,輸出變成 Tom\\'s book,嚴重破壞數據完整性。
反之,若 magic_quotes_gpc = Off 且未手動轉義,單引號直接拼接進 SQL 即構成注入漏洞。
利用 get_magic_quotes_gpc() 動態判斷當前狀態,僅在關閉時補充轉義:
<?php
// 單一變量處理範例
if (!get_magic_quotes_gpc()) {
$_POST['message'] = addslashes($_POST['message']);
}
// 此時 $_POST['message'] 可安全用於 SQL 拼接(建議仍優先用參數化查詢)
?>
實戰中表單欄位往往成十上百,逐個處理不現實。利用 PHP 超全局變量本質為陣列的特性,封裝遞歸過濾函數:
<?php
function quotes($content) {
// 僅在 magic_quotes_gpc 關閉時處理
if (!get_magic_quotes_gpc()) {
if (is_array($content)) {
foreach ($content as $key => $value) {
// 遞歸處理子陣列
$content[$key] = quotes($value);
}
} else {
// 純量值直接轉義
$content = addslashes($content);
}
}
// 開啟時直接返回原值,避免雙重轉義
return $content;
}
// 應用:一鍵淨化所有輸入源
$_GET = quotes($_GET);
$_POST = quotes($_POST);
$_COOKIE = quotes($_COOKIE);
$_REQUEST = quotes($_REQUEST);
?>
php.ini 設定,部署無需修改代碼。name="data[key][sub]"),徹底覆蓋複雜表單結構。magic_quotes_gpc 時近乎零開銷。htmlspecialchars()、trim() 等額外清洗邏輯。🔴 重要:magic_quotes_gpc 自 PHP 5.4 起已棄用並移除。新專案請直接採用 PDO 預處理語句 或框架 ORM 參數綁定,從根源杜絕注入風險。本文方案僅適用於無法升級的舊系統維護期過渡使用。