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

Discuz! 插件開發實戰:自動隱藏帖子內容、支援多模式/預覽/指定版塊/遊客限制的完整實現

     編輯:PHP 綜合知識

需求背景:論壇「回帖可見」自動化

傳統 `[hide]` 標籤需發帖者手動包裹,易忘、繁瑣。本插件實現 **發帖即自動隱藏**,支援:

  • 🎯 **兩種隱藏模式**:僅隱藏主題帖 (一樓) / 隱藏全樓層 (含回覆)
  • 👁 **可預覽字節數**:露出前 N 字誘導回覆
  • 🏷 **版塊白名單/黑名單**:精準控制生效範圍
  • 👤 **遊客限制**:未登入僅可預覽,引導註冊/登入
  • 🛡 **相容干擾碼、代碼截斷修復、公告/短訊排除**

架構設計:掛點最小化、零資料庫變更、配置檔驅動


// 配置檔:source/plugin/kj_hide/config.inc.php
return [
    'enable' => true,              // 總開關
    'mode' => 1,                   // 1=僅主題帖 2=全樓層 3=主題帖+回覆(非作者可見) 4=遊客預覽
    'preview_length' => 200,       // 預覽字節 (0=不預覽)
    'allow_forums' => [],          // 白名單版塊 fid 陣列,空=全站
    'deny_forums' => [],           // 黑名單版塊 fid 陣列
    'exclude_announce' => true,    // 排除公告/置頂
    'fix_truncate' => 1,           // 代碼截斷修復模式 1=移至 BBCode 解析前 2=不修復
];

核心掛點修改 (Discuz! X 系列通用)

1. viewthread.php — 傳遞 `first` 參數給 `discuzcode()`


// 找到 discuzcode() 呼叫處,在參數末尾新增 $post['first']
// DZ X3.4 範例 (約第 300 行)
$post['message'] = discuzcode($post['message'], $post['smileyoff'], $post['bbcodeoff'],
    $post['htmlon'], $forum['allowsmilies'], $forum['allowbbcode'],
    ($forum['allowimgcode'] && $showimages ? 1 : 0), $forum['allowhtml'],
    ($forum['jammer'] && $post['authorid'] != $discuz_uid ? 1 : 0),
    $pid, $post['authorid'], $post['first']); // ← 新增第 11 參數

2. source/function/function_discuzcode.php — 擴展簽名並實現邏輯

// 1. 函數簽名新增 $first = 0
function discuzcode($message, $smileyoff, $bbcodeoff, $htmlon = 0,
    $allowsmilies = 1, $allowbbcode = 1, $allowimgcode = 1, $allowhtml = 0,
    $jammer = 0, $pid = 0, $authorid = 0, $first = 0) {

// 2. 全域變數引入插件配置
global $_G, $hide_config; // $hide_config 由 plugin 初始化載入
if (empty($hide_config)) {
    require_once libfile('plugin/kj_hide', 'config'); // 載入 config.inc.php
    $hide_config = kj_hide_config();
}

// 3. 核心邏輯:判斷是否需自動隱藏
$need_hide = false;
if ($hide_config['enable']) {
    $fid = $_G['fid'];
    // 版塊過濾
    if ($hide_config['allow_forums'] && !in_array($fid, $hide_config['allow_forums'])) $need_hide = false;
    elseif ($hide_config['deny_forums'] && in_array($fid, $hide_config['deny_forums'])) $need_hide = false;
    else {
        // 模式判斷
        switch ($hide_config['mode']) {
            case 1: $need_hide = (bool)$first; break;                    // 僅主題帖
            case 2: $need_hide = true; break;                            // 全部
            case 3: $need_hide = $first || $authorid != $_G['uid']; break; // 主題帖 + 非作者回覆
            case 4: $need_hide = !$_G['uid']; break;                     // 遊客模式
        }
    }
}

// 4. 執行隱藏/預覽
if ($need_hide) {
    $preview = $hide_config['preview_length'];
    $msg_len = strlen($message);

    if ($preview > 0 && $preview < $msg_len) {
        // 產生預覽片段 (避開 BBCode 標籤截斷)
        $preview_text = dhtmlspecialchars(cutstr($message, $preview));
        $message = $preview_text . '

' . lang('plugin/kj_hide', 'hide_reply_hidden') . ''; } else { // 完全隱藏 $message = '' . lang('plugin/kj_hide', 'hide_reply_hidden') . ''; } // 作者/版主/回覆過用戶:顯示原文 $is_author = ($authorid == $_G['uid']); $is_mod = $_G['forum']['ismoderator']; $has_replied = false; if (!$is_author && !$is_mod) { $query = DB::query("SELECT pid FROM " . DB::table('forum_post') . " WHERE tid='{$_G['tid']}' AND authorid='{$_G['uid']}' LIMIT 1"); $has_replied = DB::result($query, 0); } if ($is_author || $is_mod || $has_replied) { $message = $original_message; // 需在前面備份 $original_message = $message; } } // 5. 原有 [hide] 標籤處理邏輯保持不變 (放在自動隱藏之後) if (!in_array($parsetype, [1,2]) && preg_match("/\[hide=?\d*\].+?\[\/hide\]/is", $message)) { // ... 原有 creditshide 處理 ... }

3. 語言包:source/language/lang_plugin_kj_hide.php

<?php
$lang = [
    'hide_reply' => '該內容已被隱藏,回覆本帖後可查看。',
    'hide_reply_hidden' => '內容已隱藏,回覆後可見。',
    'hide_limit' => '遊客只能預覽部分內容,完整內容請 登錄 或 註冊。',
];

代碼截斷修復:兩種策略

問題:`cutstr()` 在 BBCode 標籤中間截斷 (如 `[url=...`、`[quote]`),導致頁面結構破壞。

  • 策略 1 (推薦,`fix_truncate=1`):將自動隱藏邏輯**移至 BBCode 解析之前** (`discuzcode` 函數開頭),此時 `$message` 仍為純文本 + 原始 BBCode,截斷後殘留的未閉合標籤會被後續解析器**自動修正或轉義顯示**,不破壞結構。
  • 策略 2 (`fix_truncate=2`):解析後截斷,需自行實現標籤平衡補全 (複雜、易遺漏),不推薦。

安裝部署步驟

  1. 建立目錄 `source/plugin/kj_hide/`
  2. 放入 `config.inc.php`、`discuzcode.php` (含修改後的 `discuzcode` 函數)、`lang_plugin_kj_hide.php`
  3. 修改 `source/module/forum/viewthread.php` 掛點 (或用插件系統的 `hook/viewthread_post_bottom` 注入 `$post['first']` 參數,免改核心)
  4. 後台 → 應用 → 插件 → 安裝「開卷工作室自動隱藏帖子」
  5. 配置版塊白名單/模式/預覽長度

升級相容性說明

Discuz! 版本掛點差異注意事項
X3.0 - X3.4`viewthread.php` 直接呼叫 `discuzcode()`直接修改參數列
X3.5+引入 `hook/viewthread_post_bottom`建議用 Hook 注入 `$post['first']`,免改核心,升級無痛
X2.5 / 7.2函數簽名參數順序不同對照原始 `discuzcode` 簽名調整,原理相同

效能與安全考量

  • ⚡ **單次查詢優化**:`has_replied` 查詢加 `LIMIT 1`、索引 `(tid, authorid)` 命中。
  • 🛡 **XSS 防護**:預覽片段經 `dhtmlspecialchars()` 轉義,隱藏提示語言包輸出。
  • 🔒 **權限檢查**:版主 (`$_G['forum']['ismoderator']`)、作者 (`$authorid == $_G['uid']`) 直接穿透。
  • 🧩 **衝突預防**:插件配置前綴 `kj_hide_`,語言包 `plugin/kj_hide`,避免與其他插件衝突。

擴展靈感:從「隱藏」到「權限經濟」

  • 💰 **積分解鎖**:回覆扣積分、或支付積分查看 (整合 `creditshide` 邏輯)。
  • 👑 **用戶組權限**:VIP 免回覆可見、遊客完全不可見。
  • 📊 **數據埋點**:記錄 `hide_view`、`hide_unlock` 事件,分析內容吸引力與轉化率。
  • 🤖 **AI 內容審核**:隱藏前自動掃描敏感詞、廣告鏈接,違規直接拦截不入庫。

這個插件雖小,卻完整展示了 **Discuz! 插件開發的核心模式**:掛點注入 → 配置驅動 → 語言包國際化 → 核心邏輯隔離 → 相容性分層 → 安全效能雙顧。掌握此模式,你就能為任何 Discuz! 論壇快速交付高質量功能擴展。

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