富文本編輯器輸出、第三方內容嵌入、爬蟲資料清洗,常需精準控制 HTML 標籤屬性:保留 src、alt、href 等安全屬性,移除 onclick、style、onload 等 XSS 風險屬性。本文提供正則進階模式、常見場景現成模式、完整淨化管線,並對比 strip_tags()、HTMLPurifier 適用邊界。
// 保留 src,移除 img 標籤其他所有屬性
$html = preg_replace('/\s(?!src\b)[a-zA-Z-]+=(["\']).*?\1/iu', '', $html);
// 保留 src 和 alt
$html = preg_replace('/\s(?!src\b|alt\b)[a-zA-Z-]+=(["\']).*?\1/iu', '', $html);
// 通用函式:保留 $allow 陣列屬性
function keepAttributes(string $html, array $allow): string
{
$pattern = '/\s(?!' . implode('|', array_map('preg_quote', $allow)) . '\b)[a-zA-Z-]+=(["\']).*?\1/iu';
return preg_replace($pattern, '', $html);
}
// 用法:keepAttributes($html, ['src', 'alt', 'title', 'href']);
$dangerous = ['on\w+', 'style', 'action', 'background', 'dynsrc', 'lowsrc'];
$pattern = '/\s(' . implode('|', $dangerous) . ')\s*=\s*(["\']).*?\2/iu';
$html = preg_replace($pattern, '', $html);
//→ $html = preg_replace('/<([a-z]+)\s[^>]*>/i', '<$1>', $html);
function purifyHtml(string $html): string
{
$search = [
// 移除 script 及內容
"''si",
// 移除 HTML 註解
"''si",
// 移除所有標籤屬性(若需保留請用上方 keepAttributes)
"'<([a-z]+)\s[^>]*>'i",
// 移除多餘空白
"'([\r\n])[\s]+'",
// 實體還原(視需求決定是否保留)
"'&(quot|#34);'i", "'&(amp|#38);'i",
"'&(lt|#60);'i", "'&(gt|#62);'i",
"'&(nbsp|#160);'i",
];
$replace = [
'', '', '<$1>', "\\1", '"', '&', '<', '>', ' '
];
return preg_replace($search, $replace, $html);
}
$html = ''; $clean = keepAttributes($html, ['src', 'alt', 'width', 'height']); // 結果:
$html = '連結'; $clean = keepAttributes($html, ['href', 'title', 'target']); // 結果:連結
$html = '內容'; $clean = preg_replace('/\s(on\w+|style)\s*=\s*(["\']).*?\2/iu', '', $html); // 結果:內容
i:大小寫不敏感(HTML 屬性不分大小寫)u:UTF-8 模式(正確處理中文屬性值)s:單行模式(. 匹配換行,配合 .*? 跨行匹配內容)| 誤區 | 風險 | 正確做法 |
|---|---|---|
| 用正則解析任意 HTML | 巢狀、破損、編碼導致漏洞 | 簡單屬性過濾用正則;複雜結構用 DOMDocument + HTMLPurifier |
| 單一正則處理所有標籤 | 難以維護、效能差 | 分標籤類型處理,或用白名單機制 |
| 忽略雙引號/單引號/無引號屬性值 | 繞過過濾 | 模式支援 (["\']).*?\1 或 [^\s>]+ |
| 過濾後未編碼輸出 | 殘留 XSS | 輸出前 htmlspecialchars() 或模板引擎自動轉義 |
DOMDocument + DOMXPath:原生、無依賴、精準操作節點屬性。masterminds/html5-php:HTML5 解析器,配合選取器移除屬性。DOMPurify:雙端同步淨化,防禦深度最大化。正則過濾 HTML 屬性屬於「輕量級防護」,適用於結構可控、標籤有限、效能敏感的場景(如編輯器儲存前預處理、API 回應快速清洗)。面對非受信任、結構複雜、高風險內容,務必使用 HTMLPurifier 或 DOMDocument 白名單淨化。掌握本文模式庫,能覆蓋 80% 日常屬性控制需求,剩下 20% 交給專業淨化庫。