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

Discuz! 5 代碼高亮與可運行代碼插件實作教學

     編輯:PHP 綜合知識

功能概覽

本插件為 Discuz! 5.0 論壇擴展兩項實用功能:

  1. [php] 標籤:PHP 程式碼語法高亮顯示 (基於 highlight_string())
  2. [runcode] 標籤:HTML/JS 代碼客戶端即時運行、複製、另存

安裝僅需修改兩個核心檔案,無需資料庫變更,相容性極佳。

安裝步驟

第一步:擴展 JavaScript 功能 (include/common.js)

尋找現有 copycode() 函數結尾,於其後新增三個函數:

// 執行 HTML/JS 代碼 (新視窗開啟)
function runCode(obj) {
    var win = window.open('', '_blank', '');
    win.document.open('text/html', 'replace');
    win.document.writeln(obj.value);
    win.document.close();
}

// 複製代碼到剪貼簿
function copycode(obj) {
    var rng = document.body.createTextRange();
    rng.moveToElementText(obj);
    rng.scrollIntoView();
    rng.select();
    rng.execCommand("Copy");
    rng.collapse(false);
}

// 另存代碼為檔案 (IE 專用 execCommand)
function saveCode(obj) {
    var win = window.open('', '_blank', 'top=10000');
    win.document.open('text/html', 'replace');
    win.document.writeln(obj.value);
    win.document.execCommand('saveas', '', 'code.htm');
    win.close();
}
注意:createTextRange/execCommand 為 IE 專有 API,現代瀏覽器建議改用 navigator.clipboard.writeText() 與 Blob + URL.createObjectURL() 實現跨瀏覽器相容。

第二步:擴展 Discuz! 代碼解析器 (include/discuzcode.func.php)

尋找 $discuzcodes['codecount']++ 所在行 (約第 110 行),在其後新增兩個解析函數:

// --------- [runcode] HTML 代碼運行 ---------
function runcodedisp($code) {
    global $discuzcodes;
    $discuzcodes['pcodecount']++;
    
    // 清理代碼:移除首尾換行、轉義 HTML 實體、還原引號
    $code = htmlspecialchars(str_replace('\\"', '"', preg_replace("/^[\n\r]*(.+?)[\n\r]*$/is", "\\1", $code)));
    
    $cid = $discuzcodes['codecount'];
    $discuzcodes['codehtml'][$discuzcodes['pcodecount']] = 
        "

" . "
" . " " . " " . " " . " 提示:您可以先修改部分代碼再運行" . "

"; $discuzcodes['codecount']++; return "[\tDISCUZ_CODE_{$discuzcodes['pcodecount']}\t]"; } // --------- [php] PHP 代碼高亮 --------- function phpcodedisp($code) { global $discuzcodes; $discuzcodes['pcodecount']++; // 確保代碼包含 PHP 標籤,才能正確高亮 $addedTags = false; if (!strpos($code, "
" . "" . "PHP代碼如下:
" . "
{$buffer}

"; $discuzcodes['codecount']++; return "[\tDISCUZ_CODE_{$discuzcodes['pcodecount']}\t]"; }

第三步:註冊正則替換規則 (同檔案,續修)

尋找現有的 preg_replace 代碼區塊:

$message = preg_replace("/\s*\[code\](.+?)\[\/code\]\s*/ies", "codedisp('\\1')", $message);

在其下方新增:

// --------- runcode ----------
$message = preg_replace("/\s*\[runcode\](.+?)\[\/runcode\]\s*/ies", "runcodedisp('\\1')", $message);
// --------- php ----------
$message = preg_replace("/\s*\[php\](.+?)\[\/php\]\s*/ies", "phpcodedisp('\\1')", $message);

使用範例

PHP 代碼高亮

[php]
function hello($name) {
    return "Hello, " . $name . "!";
}
echo hello("Discuz!");
[/php]

渲染後將顯示帶行號、關鍵字著色的代碼區塊,並提供下方「複製PHP代碼」按鈕。

HTML/JS 即時運行

[runcode]
<html>
<body>
  <h1>Hello, Discuz!</h1>
  <button onclick="alert('按鈕可互動')">點我</button>
  <script>console.log('JS 執行正常')</script>
</body>
</html>
[/runcode]

渲染後顯示可編輯的 <textarea>,點擊「運行代碼」即在新分頁呈現執行結果,支援即時修改預覽。

技術細節深度解析

關鍵點實作邏輯潛在風險與改進
PHP 高亮核心highlight_string() 內建函數,輸出內聯 CSS 樣式輸出 HTML 結構固定,難以自定義主題;建議改用 GeSHi 或 highlight.js (前端渲染)
代碼清理策略移除首尾空白、還原轉義引號、補全 PHP 標籤正則 /^[\n\r]*(.+?)[\n\r]*$/is 若代碼含多行字串可能誤判;建議用 trim() 替代
XSS 防護htmlspecialchars() 轉義 runcode 內容運行時 document.writeln 直接寫入用戶代碼,若論壇允許非信任用戶發文,**極高風險** (存儲型 XSS)。生產環境**必須**加入 CSP、iframe 沙箱、或僅限管理員使用
瀏覽器相容execCommand('Copy/SaveAs') 僅 IE/舊 Edge 支援現代化請參考 Clipboard API 與 File System Access API
效能考量/e 修飾符 (PREG_REPLACE_EVAL) 在 PHP 5.5+ 棄用、7.2+ 移除**重大問題**:Discuz! 5 時代用 PHP 4/5.2,若移植至 PHP 7/8 必須改用 preg_replace_callback()

現代化重構建議 (PHP 8 + Discuz! X)

<?php
// 使用 preg_replace_callback 替代 /e
$message = preg_replace_callback(
    "/\s*\[php\](.+?)\[\/php\]\s*/is",
    function ($matches) {
        return phpcodedisp($matches[1]);
    },
    $message
);

// PHP 8.2+ 建議:改用前端高亮 (highlight.js)
// 後端僅輸出 
...
// 前端引入 highlight.js 自動著色,零後端負擔、支援 190+ 語言、主題豐富

總結

這個插件展示了 Discuz! 代碼解析器的擴展機制:正則捕獲 → 回調處理 → 佔位符替換 → 二次渲染。雖然具體實作帶有時代特徵 (IE 專用 API、/e 修飾符、內建高亮),但其**架構思想**在現代論壇開發中依然適用。若您維護舊版 Discuz!,可直接套用;若開發新專案,建議採用**前端高亮 + CSP 隔離 + 現代 Clipboard API** 的組合方案。

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