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

PHP HTML 標籤屬性過濾類別:白名單、例外規則與忽略標籤靈活控制

     編輯:PHP 相關知識

處理用戶提交的 HTML 內容(如富文本編輯器輸出)時,需移除不安全屬性(onclick、style、onload 等)同時保留必要屬性(href、src、class、id)。本文實作 HtmlAttributeFilter 類別,支援全域白名單、標籤級例外、忽略標籤三層規則,精準控制屬性保留與移除。

核心功能

  • 全域白名單:setAllow(['id', 'class', 'title']),所有標籤通用保留屬性。
  • 標籤例外:setException(['a' => ['href', 'target'], 'img' => ['src', 'alt']]),特定標籤額外允許屬性。
  • 忽略標籤:setIgnore(['script', 'style']),完全跳過處理(保留原樣或由其他機制處理)。
  • 特殊字元轉義:正則替換時自動轉義 Regex 元字元,避免模式錯誤。

類別結構

<?php
class HtmlAttributeFilter {
    private $_str = '';
    private $_allow = [];      // 全域白名單
    private $_exception = [];  // 標籤例外
    private $_ignore = [];     // 忽略標籤

    public function strip($str) {
        $this->_str = $str;
        if (!is_string($this->_str) || strlen($this->_str) === 0) return $this->_str;

        $this->_str = strtolower($this->_str); // 統一小寫處理
        $res = $this->findElements();
        if (is_string($res)) return $res; // 無符合元素直接返回

        $nodes = $this->findAttributes($res);
        $this->removeAttributes($nodes);
        return $this->_str;
    }

    public function setAllow(array $param) { $this->_allow = $param; }
    public function setException(array $param) { $this->_exception = $param; }
    public function setIgnore(array $param) { $this->_ignore = $param; }

    private function findElements() {
        $nodes = [];
        // 比對  結構
        preg_match_all('/<([^ !\/>\\n]+)([^>]*)>/i', $this->_str, $elements);
        foreach ($elements[1] as $idx => $tag) {
            $attrs = $elements[2][$idx];
            if ($attrs && (!is_array($this->_ignore) || !in_array($tag, $this->_ignore))) {
                $nodes[] = [
                    'literal' => $elements[0][$idx],
                    'name' => $tag,
                    'attributes' => $attrs
                ];
            }
        }
        return $nodes ? $nodes : $this->_str;
    }

    private function findAttributes($nodes) {
        foreach ($nodes as &$node) {
            // 比對 attr="value" 或 attr='value' 或 attr=value
            preg_match_all('/([^ =]+)\s*=\s*["\']{0,1}([^"\']*)["\']{0,1}/i', $node['attributes'], $atts);
            $node['attributes'] = [];
            if ($atts[1]) {
                foreach ($atts[1] as $i => $name) {
                    $node['attributes'][] = [
                        'literal' => $atts[0][$i],
                        'name' => $name,
                        'value' => $atts[2][$i]
                    ];
                }
            }
        }
        return $nodes;
    }

    private function removeAttributes($nodes) {
        foreach ($nodes as $node) {
            $new_attrs = '';
            if (is_array($node['attributes'])) {
                foreach ($node['attributes'] as $att) {
                    $keep = (is_array($this->_allow) && in_array($att['name'], $this->_allow)) ||
                            $this->isException($node['name'], $att['name']);
                    if ($keep) {
                        $new_attrs = $this->createAttributes($new_attrs, $att['name'], $att['value']);
                    }
                }
            }
            $replacement = $new_attrs ? "<{$node['name']} $new_attrs>" : "<{$node['name']}>";
            $this->_str = preg_replace('/' . $this->protect($node['literal']) . '/', $replacement, $this->_str);
        }
    }

    private function isException($tag, $attr) {
        return isset($this->_exception[$tag]) && in_array($attr, $this->_exception[$tag]);
    }

    private function createAttributes($str, $name, $value) {
        return $str . ($str ? ' ' : '') . "$name=\"$value\"";
    }

    private function protect($str) {
        $map = ['\\' => '\\\\', '^' => '\\^', '[' => '\\[', '.' => '\\.', '$' => '\\$',
                '{' => '\\{', '*' => '\\*', '(' => '\\(', ')' => '\\)', '|' => '\\|',
                '+' => '\\+', '?' => '\\?', '<' => '\\<', '>' => '\\>'];
        return strtr($str, $map);
    }
}
?>

使用範例

<?php
require 'HtmlAttributeFilter.class.php';

$html = '';

$filter = new HtmlAttributeFilter();
$filter->setAllow(['id', 'class']);           // 全域保留 id, class
$filter->setException([
    'a' => ['href', 'target'],                //  額外允許 href, target
    'img' => ['src', 'alt', 'width', 'height'] //  額外允許 src, alt, width, height
]);
$filter->setIgnore(['script', 'style']);      // 忽略 script/style 標籤

echo '原始:' . htmlspecialchars($html) . '

'; echo '過濾後:' . htmlspecialchars($filter->strip($html));

輸出結果

原始:


過濾後:

規則匹配優先順序

  1. 標籤在 ignore 列表 → 完全跳過,保留原樣。
  2. 屬性在全域 allow 白名單 → 保留。
  3. 屬性在該標籤 exception 例外列表 → 保留。
  4. 其餘屬性 → 移除。

局限性與建議

  • 僅處理屬性,不移除完整標籤(如 `
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved