首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 輸入資料轉義處理終極指南:magic_quotes 歷史包袱、addslashes/stripslashes 最佳實踐與現代防禦策略

     編輯:PHP 相關知識

PHP 輸入資料轉義處理終極指南:magic_quotes 歷史包袱、addslashes/stripslashes 最佳實踐與現代防禦策略

PHP 早期引入 magic_quotes_gpc 自動轉義 GET/POST/COOKIE 資料,試圖防止 SQL 注入,卻因「雙重轉義」、「非資料庫場景污染」、「版本不一致」造成無數災難。PHP 5.4 徹底移除此特性。本文系統梳理轉義演進史,詳解 addslashes/stripslashes 正確用法,並確立現代 PHP 防禦鐵律:棄用轉義,擁抱預處理語句。

歷史回顧:magic_quotes 三大設定

設定影響範圍可執行期修改預設值備註
magic_quotes_gpcGET/POST/COOKIE否 (PHP_INI_PERDIR)On (≤5.3)自動為 ', ", \, NUL 加反斜線
magic_quotes_runtime外部資料來源 (DB、檔案、fopen 等)是Off已移除
magic_quotes_sybase覆蓋 gpc,單引號轉為 '' 而非 \'否Off已移除

核心函數機制

  • addslashes($str):在 ' " \ NUL 前加反斜線。不感知字元編碼,多位元組字元 (如 GBK 中文) 可能破壞字元結構 (經典 0x5c 尾字節問題)。
  • stripslashes($str):移除 addslashes() 加入的反斜線。
  • get_magic_quotes_gpc():PHP 5.4+ 已移除,呼叫直接報錯。

WordPress 3.6+ 實作參考:wp_slash() 深度解析

function wp_slash($value) {
    if (is_array($value)) {
        foreach ($value as $k => $v) {
            // 遞歸處理多維陣列
            $value[$k] = is_array($v) ? wp_slash($v) : addslashes($v);
        }
    } else {
        $value = addslashes($value);
    }
    return $value;
}

設計意圖:為 WordPress 核心 API (期望已轉義資料) 準備資料,**非用於直接進入 SQL 查詢**。

相容性處理:偵測並修正 magic_quotes 遺毒 (PHP 5.3 及以下舊專案)

if (!function_exists('get_magic_quotes_gpc') || !get_magic_quotes_gpc()) {
    // magic_quotes 關閉或函數不存在 (PHP 5.4+):手動轉義 (僅用於老舊 mysql_* API)
    foreach (['_COOKIE', '_POST', '_GET'] as $v) {
        foreach ($$v as $kk => $vv) {
            // 跳過以 _ 開頭的鍵 (如 _token, _method)
            if ($kk[0] !== '_') {
                $$v[$kk] = addslashes($vv);
            }
        }
    }
} else {
    // magic_quotes 開啟:資料已被自動轉義,若再手動 addslashes 會雙重轉義
    // 輸出顯示時需 stripslashes() 還原
}

資料庫操作:轉義 vs 預處理 —— 終極對決

維度addslashes / mysql_real_escape_stringPDO / MySQLi 預處理語句
原理字串轉義拼接 SQLSQL 解析與資料分離,參數綁定
編碼安全依賴連線字元集設定,易出錯驅動層處理編碼,徹底免疫
效能每次查詢皆解析 SQL可重複執行,優化器複用執行計畫
防注入邊緣案例可繞過 (多位元組、編碼)理論上 100% 防注入
適用場景極舊專案維護、無法用預處理的 DDL所有現代專案強制標準

現代 PHP 專案標準作法 (PDO 範例)

<?php
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", 'user', 'pass', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false, // 關鍵:使用真實預處理
]);

$stmt = $pdo->prepare("INSERT INTO users (username, email) VALUES (?, ?)");
$stmt->execute([$_POST['username'], $_POST['email']]); // 參數自動綁定,零轉義

// 查詢
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ? AND status = ?");
$stmt->execute([$id, 1]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

輸出端防禦:XSS 防護才是重點

資料入庫不轉義 (存原始資料),輸出到 HTML 時才轉義:

  • htmlspecialchars($str, ENT_QUOTES, 'UTF-8'):防 XSS 黃金標準。
  • 模板引擎 (Blade {{ $var }}, Twig {{ var|e }}) 預設自動轉義。
  • JavaScript/JSON/CSS/URL 語境需對應專用編碼函數。

檔案/儲存場景:stripslashes 還原陷阱

若歷史資料已被雙重轉義儲存 (如 <img alt=\\"\\" ...>):

  1. 讀取時 stripslashes() 還原一次。
  2. 若仍有殘留反斜線,可能需多次或配合正則清洗。
  3. 根治:匯出資料、清洗乾淨、重新匯入,並改用預處理寫入。

總結:三條鐵律

  1. 入庫零轉義:永遠使用 PDO/MySQLi 預處理語句,拒絕 addslashes、mysql_real_escape_string、mysqli_escape_string。
  2. 輸出按語境編碼:HTML 用 htmlspecialchars,JS 用 json_encode,URL 用 urlencode,Shell 用 escapeshellarg。
  3. 清理歷史包袱:檢測 magic_quotes 狀態,統一資料流向,重構舊代碼移除所有手動轉義邏輯。

轉義是上世紀的產物,預處理才是當代 PHP 開發者的專業徽章。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved