轉義相關配置指令
| 指令 | 範圍 | 說明 | 狀態 |
magic_quotes_gpc | GPC (GET/POST/COOKIE) | 自動轉義單雙引號、反斜線、NULL | PHP 5.4 移除 |
magic_quotes_runtime | 運行時數據源(文件、資料庫等) | 自動轉義外部輸入數據 | PHP 5.3 棄用,5.4 移除 |
magic_quotes_sybase | 單引號轉義模式 | On: '' | Off: \' | PHP 5.3 棄用,5.4 移除 |
核心轉義函數對比
| 函數 | 用途 | 轉義字符集 | 反轉義函數 | 適用場景 |
addslashes() | 通用字符串轉義 | ' " \ NULL | stripslashes() | 歷史代碼兼容、非資料庫場景 |
mysqli_real_escape_string() | MySQL 專用 | \x00 \n \r \ ' " \x1a | 無(參數化查詢無需反轉義) | 舊式 mysqli 非預處理查詢 |
pg_escape_string() | PostgreSQL 專用 | 單引號、反斜線、NULL 等 | pg_unescape_bytea() | PostgreSQL 字符串查詢 |
addcslashes() | C 風格轉義 | 自定義字符範圍 + \0 \a \b \f \n \r \t \v | stripcslashes() | 生成 C/JS 代碼、正則模式構建 |
htmlspecialchars() | HTML 實體編碼(防 XSS) | & " ' < > | htmlspecialchars_decode() | **輸出到 HTML 頁面的所有動態內容** |
htmlentities() | 全部字符實體化 | 所有有實體對應的字符 | html_entity_decode() | 需完整實體化的導出/交換場景 |
關鍵最佳實踐
1. 統一關閉 Magic Quotes(PHP < 5.3)
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
@set_magic_quotes_runtime(0); // 運行時
}
// 無法通過代碼關閉 magic_quotes_gpc,需在 php.ini 設定
// 生產環境建議統一開啟 gpc,代碼層檢測處理
2. GPC 統一轉義入口(兼容 gpc on/off)
if (!get_magic_quotes_gpc()) {
$_GET = deep_addslashes($_GET);
$_POST = deep_addslashes($_POST);
$_COOKIE = deep_addslashes($_COOKIE);
$_FILES = deep_addslashes($_FILES);
}
function deep_addslashes($data, $force = 1) {
if (is_array($data)) {
foreach ($data as $key => $val) {
unset($data[$key]);
$data[addslashes($key)] = deep_addslashes($val, $force); // 鍵值同步轉義
}
} else {
$data = addslashes($data);
}
return $data;
}
3. 拒絕 mysql_escape_string / mysql_real_escape_string(已棄用)
- 僅針對 MySQL,移植性差。
- 需建立資料庫連接後才能使用,無法在早期輸入驗證階段調用。
- 字符集依賴連接字符集,易發生編碼導致的注入繞過。
替代方案:全面採用 PDO / mysqli 預處理語句,參數綁定自動處理轉義,徹底分離代碼與數據。
4. 輸出端防 XSS:統一 htmlspecialchars
function h($str, $flags = ENT_QUOTES | ENT_SUBSTITUTE, $encoding = 'UTF-8') {
return htmlspecialchars($str, $flags, $encoding);
}
// 模板中統一使用:= h($user_input) ?>
ENT_QUOTES:同時轉義單雙引號,防屬性注入。
ENT_SUBSTITUTE:無效編碼替換為 Unicode 替換字符,防編碼攻擊。
- 指定
UTF-8 避免字符集推斷錯誤。
PHP 字符串字面量轉義規則補充
| 定界符 | 支援轉義序列 |
單引號 '...' | \' \\ |
雙引號 "..." | \n \r \t \\ \$ \" \[0-7]{1,3} \x[0-9A-Fa-f]{1,2} |
Heredoc <<<EOT | 同雙引號,無需轉義引號 |
Nowdoc <<<'EOT' | **無任何轉義**,同單引號 |
特殊字符處理實例
// NULL 字符處理
$str = "abc\x00def"; // 或 "abc\0def"
echo strlen($str); // 7 (含 NULL)
$str = str_replace("\x00", '', $str); // 移除 NULL
// 八進制/十六進制字面量
$octal = "\0\01\02\3\7\10\011\08\8"; // \08 不合法,解析為 \0 + "8"
$hex = "\x0\x1\x2\x3\x7\x8\x9\x10\x11\xff";
總結建議
- 輸入端:關閉 Magic Quotes,使用預處理語句(PDO/mysqli)綁定參數,**完全不需要手動轉義**。
- 存儲端:原始數據入庫,不做任何 HTML 實體化(保持數據純淨)。
- 輸出端:根據上下文編碼——HTML 用
htmlspecialchars、JS 用 json_encode、URL 用 urlencode、Shell 用 escapeshellarg。
- 遷移檢查清單:
- 移除所有
addslashes/mysql_real_escape_string 調用
- 檢查
magic_quotes_gpc 依賴邏輯
- 統一模板輸出函數為
h()
- 啟用
default_charset = UTF-8
遵循「輸入驗證、存儲原始、輸出編碼」三原則,可消除 99% 的轉義相關安全隱患與亂碼問題。