萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP UBB 代碼解析器:BBCode 轉 HTML 完整實作 (支援巢狀、屬性、XSS 防護)

核心解析器架構

<?php
function ubb(string $string): string {
    // 階段一:正則替換 (含屬性、巢狀結構)
    $searchRegex = [
        // [quote]...[/quote]
        '/\s*\[quote\][\n\r]*(.+?)[\n\r]*\[\/quote\]\s*/is' => 
            '

  Quote:
\1

', // [box=#color]...[/box] '/\[box=([#0-9A-F]{6}|[a-z]+)\][\n\r]*(.+?)[\n\r]*\[\/box\]/is' => '
$title\2
', // [url]https://...[/url] 自動連結 '/\[url\][\s]*(www\.|https?://|ftp://|gopher://|news://|telnet://|rtsp://|mms://){1}([^\[\"\']+?)[\s]*\[\/url\]/ie' => "cuturl('\1\2')", // [url=...]text[/url] '/\[url=www\.([^\[\"\']+?)\](.+?)\[\/url\]/is' => '\2', '/\[url=(https?|ftp|gopher|news|telnet|rtsp|mms)://([^\[\"\']+?)\](.+?)\[\/url\]/is' => '\3', // [email]...[/email] '/\[email\][\s]*([A-Za-z0-9-_.]+)@([A-Za-z0-9-_]+\.[A-Za-z0-9-_.]+)[\s]*\[\/email\]/i' => '\1@\2', '/\[email=([A-Za-z0-9-_.]+)@([A-Za-z0-9-_]+\.[A-Za-z0-9-_.]+)\](.+?)\[\/email\]/is' => '\3', // 文字樣式 '/\[color=([^\[\]]+?)\]/i' => '', '/\[size=([^\[\]]+?)\]/i' => '', '/\[font=([^\[\]]+?)\]/i' => '', '/\[align=([^\[\]]+?)\]/i' => '

', '/\[center\]/i' => '

', // 多媒體 '/\[swf\][\s]*([^\[\]]+?)[\s]*\[\/swf\]/ies' => "bbcodeurl('\1', ' Flash: %s ')", '/\[img\][\s]*([^\[\]]+?)[\s]*\[\/img\]/ies' => "bbcodeurl('\1', 'screen.width*0.7){this.resized=true;this.width=screen.width*0.7;this.alt=\'Click to open\';}\" onmouseover=\"if(this.resized)this.style.cursor=\'pointer\'\" onclick=\"if(this.resized){window.open(\'%s\');}\">')", '/\[img=(\d{1,3})[x|,](\d{1,3})\][\s]*([^\[\]]+?)[\s]*\[\/img\]/ies' => "bbcodeurl('\3', '')", ]; // 階段二:簡單標籤直接替換 $searchStr = ['[/color]', '[/size]', '[/font]', '[/align]', '[b]', '[/b]', '[i]', '[/i]', '[u]', '[/u]', '[list]', '[list=1]', '[list=a]', '[list=A]', '[*]', '[/list]', '[/center]']; $replaceStr = ['', '', '', '

', '', '', '', '', '', '', '
    ', '
      ', '
        ', '
          ', '
        1. ', '
', '

']; // 執行替換:先正則後字串 $string = str_replace($searchStr, $replaceStr, preg_replace(array_keys($searchRegex), array_values($searchRegex), $string)); return $string; } // 輔助函數:URL 連結生成與 XSS 過濾 function bbcodeurl(string $url, string $tags): string { if (!preg_match('/<.+?>/s', $url)) { // 非 HTML 標籤 if (!in_array(strtolower(substr($url, 0, 6)), ['http:/', 'ftp://', 'rtsp:/', 'mms://'])) { $url = 'https://' . $url; } return str_replace('submit', '', sprintf($tags, $url, $url)); } return ' ' . $url; // 含 HTML 標籤視為不安全,僅顯示 } function cuturl(string $url): string { $len = 65; $link = ''; if (strlen($url) > $len) { $url = substr($url, 0, intval($len * 0.5)) . ' ... ' . substr($url, -intval($len * 0.3)); } return $link . $url . ''; } ?>

安全性關鍵點分析

風險原始碼處理建議加強
XSS 注入bbcodeurl() 檢測 `<...>` 標籤拒絕處理輸出前統一 htmlspecialchars(),採用 CSP 標頭
巢狀標籤錯誤正則貪婪匹配可能導致跨區塊改用狀態機/遞迴下降解析器 (如 s9e/TextFormatter)
屬性注入色碼/尺寸/字體未白名單驗證屬性值嚴格驗證:color 限 hex/關鍵字、size 限 1-7
效能災難大量 /e 修飾符 (PHP 7 移除) + 複雜正則預編譯模板、快取編譯結果、避免 preg_replace_callback 重複編譯

現代化重構方向

  1. 採用 s9e/TextFormatter 或 BBCode\Parser (Composer 套件),支援巢狀、安全屬性、可擴充標籤。
  2. 編譯階段產出 AST,渲染階段輸出 HTML,分離關注點。
  3. 整合 HTMLPurifier 做最終輸出清洗。
  4. 編輯器前端改用 CKEditor/TinyMCE 直接輸出 HTML,後端僅做 Purify,棄用 BBCode。
copyright © 萬盛學電腦網 all rights reserved