PHP ≤ 5.3 時代,magic_quotes_gpc = On 會自動對 $_GET/POST/COOKIE 進行 addslashes 轉義(單引號→\', 雙引號→\", 反斜槓→\\, NULL→\0)。目的是防止 SQL 注入,但帶來嚴重問題:
addslashes 導致 \\' 入庫PHP 5.4 已移除,現代代碼不應依賴此特性。
| 函數 | 作用 | 適用場景 |
|---|---|---|
addslashes($str) | 預定義字符前加反斜槓:\' \" \\ \0 | 構建 SQL 字符串字面量 (不推薦,見下文) |
stripslashes($str) | 移除反斜槓轉義 (成對移除) | 修正 magic_quotes 污染的數據 |
| magic_quotes_gpc | 寫入時 addslashes | 讀出時 stripslashes | 結果 |
|---|---|---|---|
| On | 否 | 否 | ✅ 正常 (系統已轉義) |
| On | 是 | 否 | ❌ 雙重轉義:數據庫存 \\' |
| On | 是 | 是 | ✅ 正常 (抵消) |
| Off | 否 | 否 | ❌ 注入風險 / 語法錯誤 |
| Off | 是 | 否 | ✅ 正常 |
| Off | 是 | 是 | ❌ 過度清洗:合法 \ 被移除 |
<?php
// ❌ 過時:手動拼接 SQL (即使用 addslashes 也不安全:編碼、二進制、邊界情況)
$sql = "INSERT INTO users (name) VALUES ('" . addslashes($name) . "')";
// ✅ 正確:PDO 預處理 (參數化查詢)
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'user', 'pass');
$stmt = $pdo->prepare('INSERT INTO users (name) VALUES (?)');
$stmt->execute([$name]); // 驅動層自動處理轉義、類型、編碼
// ✅ 正確:MySQLi 預處理
$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$stmt = $mysqli->prepare('INSERT INTO users (name) VALUES (?)');
$stmt->bind_param('s', $name);
$stmt->execute();
escapeshellarg 更好)、LDAP 過濾器、正則模式字面量stripslashes 還原<?php
/**
* 寫入前統一處理 (兼容 magic_quotes On/Off)
*/
function cleanInput(string $str): string {
// 1. 若 magic_quotes 開啟,先還原
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
// 2. 統一加斜槓 (用於舊式拼接 SQL)
return addslashes($str);
}
/**
* 讀出後統一處理
*/
function cleanOutput(string $str): string {
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
return stripslashes($str);
}
return $str;
}
// 使用
$name = cleanInput($_POST['name']);
// ... 入庫 ...
$name = cleanOutput($row['name']);
// ... 輸出 ...
str_replace("'", "''", $str) 替代 addslashes — 僅處理單引號,漏掉 \ " \0,且編碼相關漏洞 (GBK 多字節注入)。addslashes 能防所有注入 — 不能 (邊界: 多字節編碼、二進制數據、未加引號的數值注入)。addslashes — 導致反斜槓指數增長。magic_quotes_gpc 是歷史錯誤,已被移除,新代碼假設 Off。addslashes 不是防注入銀彈,僅用於字符串字面量構建。htmlspecialchars,JS 用 json_encode,Shell 用 escapeshellarg — 按上下文轉義,而非通用加斜槓。