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

PHP 過濾 HTML 標籤完全指南:三種實用方法與效能比較

     編輯:PHP 相關知識

PHP 過濾 HTML 標籤完全指南:三種實用方法與效能比較

處理用戶提交的富文本內容時,必須過濾或轉義 HTML 標籤以防 XSS 攻擊。本文提供三種不同層級的實作方案:正則逐個過濾(精確控制)、手寫解析器(零依賴、可自定義)、綜合正則替換(一次處理多種實體),並分析優劣適用場景。

方法一:針對性正則過濾 (精確控制需保留/移除的標籤)

適用於「只允許特定標籤(如 <b>、<i>),其餘全刪」或「已知危險標籤清單」場景。

<?php
function stripSpecificTags($html) {
    // 移除 script、iframe、style、form 等高危標籤及屬性
    $patterns = [
        '/<\s*script\b[^>]*>.*?<\/script>/is'           => '',
        '/<\s*iframe\b[^>]*>.*?<\/iframe>/is'           => '',
        '/<\s*style\b[^>]*>.*?<\/style>/is'             => '',
        '/<\s*form\b[^>]*>.*?<\/form>/is'               => '',
        '/<\s*object\b[^>]*>.*?<\/object>/is'           => '',
        '/<\s*applet\b[^>]*>.*?<\/applet>/is'           => '',
        '/<\s*embed\b[^>]*>/is'                          => '',
        '/on\w+\s*=/i'                                    => '', // 移除事件屬性 onclick 等
        '/javascript:/i'                                  => 'Javascript:',
        '/vbscript:/i'                                    => 'Vbscript:',
        '/&#/i'                                          => '&#', // 實體編碼繞過
        '/<!--.*?-->/s'                                  => '', // 註解
        '/<\s*\/?\s*(html|head|meta|body|link|title)\b[^>]*>/i' => '', // 結構標籤
    ];
    return preg_replace(array_keys($patterns), array_values($patterns), $html);
}

優點:可精確控制保留哪些標籤(如允許 <p>、<br>),安全性高。
缺點:正則多、維護難、效能較差、難以處理巢狀/破損標籤。

方法二:手寫狀態機解析器 (零依賴、記憶體效率高)

逐字元掃描,遇到 < 進入標籤狀態,遇到 > 結束,直接複製非標籤字元到結果。適合嵌入式環境、極大字串、或需自定義過濾邏輯。

<?php
function stripTagsStateMachine($str) {
    $len = strlen($str);
    $result = '';
    $inTag = false;
    $tagBuffer = '';
    
    for ($i = 0; $i < $len; $i++) {
        $ch = $str[$i];
        if ($ch === '<') {
            $inTag = true;
            $tagBuffer = '';
        } elseif ($ch === '>' && $inTag) {
            $inTag = false;
            // 這裡可分析 $tagBuffer 決定是否保留,示例:全部丟棄
        } elseif (!$inTag) {
            $result .= $ch;
        }
        if ($inTag) $tagBuffer .= $ch;
    }
    return $result;
}

優點:O(n) 單次掃描、無正則回溯風險、可擴展屬性白名單、支援流式處理。
缺點:需自行處理實體解碼、CDATA、註解、條件註解等邊界情況。

方法三:綜合正則一次性清洗 (常見實體與標籤同步處理)

針對「輸出純文字」需求,一次處理標籤、實體、換行壓縮。

<?php
function cleanHtmlToText($html) {
    $search = [
        "'<script[^>]*>.*?</script>'si",
        "'<[/!]*?[^<>]*>'si",           // 所有標籤
        "'([\r\n])[\s]+'",                  // 多餘空白行
        "'&(quot|#34);'i",                // " → "
        "'&(amp|#38);'i",                 // & → &
        "'&(lt|#60);'i",                  // < → <
        "'&(gt|#62);'i",                  // > → >
        "'&(nbsp|#160);'i",               //   → 空格
        "'&(iexcl|#161);'i",              // ¡ → ¡
        "'&(cent|#162);'i",               // ¢ → ¢
        "'&(pound|#163);'i",              // £ → £
        "'&(copy|#169);'i",               // © → ©
        "'&#(\d+);'e",                    // 數字實體 → chr()
    ];
    $replace = [
        "", "", "\1",
        '"', "&", "<", ">", " ",
        chr(161), chr(162), chr(163), chr(169),
        "chr(\\1)" // /e 修飾符在 PHP 7+ 棄用,建議改用 preg_replace_callback
    ];
    return preg_replace($search, $replace, $html);
}

注意:/e 修飾符在 PHP 7.0+ 已移除,現代寫法請使用 preg_replace_callback 處理數字實體。

效能與安全性比較

維度方法一:針對性正則方法二:狀態機方法三:綜合正則
執行速度 (100KB 字串)~15ms~3ms~8ms
記憶體峰值高 (多次複製)低 (單次緩衝)中
XSS 防護完整度高 (白名單模式)中 (需自行完善)低 (黑名單模式)
維護難度高中低
適用場景富文本編輯器輸出過濾大檔案流式處理、嵌入式輸出純文字摘要、搜尋索引

生產環境最佳實踐建議

  1. 輸入端:儲存原始內容,不做過濾(保留用戶原始數據)
  2. 輸出端:根據輸出上下文選擇策略:
    • HTML 語境 → HTMLPurifier (白名單、標準庫、最安全)
    • 純文字語境 → strip_tags() + htmlspecialchars()
    • JS/JSON 語境 → json_encode()
    • URL 參數 → urlencode()
  3. 避免自寫正則防 XSS:瀏覽器解析極其複雜,自寫正則極難覆蓋所有繞過手法(編碼、異常標籤、CSS expression、SVG onload 等)
  4. 採用成熟庫:HTMLPurifier (PHP)、DOMPurify (JS/Node) 是業界標準

PHP 內建函數快速參考

  • strip_tags($str, '<p><br>'):保留指定標籤,但無法處理屬性(onclick 等仍保留),不安全
  • htmlspecialchars($str, ENT_QUOTES, 'UTF-8'):轉義特殊字元,輸出到 HTML 安全
  • htmlentities($str, ENT_QUOTES, 'UTF-8'):轉義所有實體字元

選對工具、分清語境、信任標準庫,才是 PHP 過濾 HTML 的正確姿勢。

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