插件系统与开发指南

Clara 插件体系完整规范:目录结构、plugin.php 写法、生命周期、164 个钩子点全景、内置插件说明与开发指南。

06 · 插件系统

核心实现:[app/Core/Plugin.php](../app/Core/Plugin.php) + [app/Core/Hook.php](../app/Core/Hook.php)。插件目录:[content/plugins/](../content/plugins/)。

系统共预留 164 个钩子(61 个业务事件 fire + 103 个数据/视图插槽 filter;2026-10-01 源码普查校准),按四层体系组织:

层类型数量用途
业务事件层`Hook::fire`(action)61写操作完成后通知插件(发帖/回帖/交易/签到/后台管理……),只通知不改数据
数据管线层`Hook::filter`6数据流经插件链式加工(正文渲染/页面标题/通知链接/头像 HTML/货币类型名/首页轮询指纹)
前台视图插槽层`Hook::filter`82在前台各页面位置注入 HTML
后台视图插槽层`Hook::filter`15在后台页面位置注入 HTML

1. 插件规范

content/plugins/{目录名}/          # 目录名:字母数字开头,可含 - _,≤50 字符
├── plugin.php                    # 主文件(必需)
├── install.php                   # 启用时执行(建表/初始化,可选;需幂等——禁用后再启用会重复执行)
├── uninstall.php                 # 卸载前执行(清表,可选)
└── views/                        # 插件视图(View::renderFile 渲染,可选)

plugin.php 结构:

<?php
/* 防直接 HTTP 访问(必须) */
if (!defined('BASE_PATH')) {
    exit;
}

/*
Plugin Name: 插件名称
Plugin URI: https://example.com
Description: 插件描述
Version: 1.0.0
Author: 作者
*/

/* 在此注册钩子(文件被 include 时执行) */
Hook::on('thread_created', function ($data) {
    // ...
});

/* 文件末尾 return 配置声明(后台「插件中心 → 配置」自动渲染表单) */
return array(
    'config' => array(
        'some_key' => array(
            'label' => '配置项名',
            'type'  => 'text',           // text / textarea / select 等
            'default' => '默认值',
            // 'options' => array(...)   // select 用
        ),
    ),
    // 'admin_url' => 'ai-reply',        // 可选:声明后「配置」按钮直达该前台路由
);

要点:

  • 元信息解析(`Plugin::parseMeta`):扫描全部块注释,取含 `Plugin Name` 的那个;行首 `*` 可有可无(兼容 WordPress 格式);键名小写下划线化。
  • 防重复 include(`Plugin::loadFile` 的 `$loadedFiles` 请求级缓存):boot 与 configDef 共用一次 include,防止插件内全局函数重复声明致命错误——在插件里声明全局函数是安全的。
  • 数据约定:自建表必须以 `plugin_{目录名}_` 为前缀;配置读写用 `Plugin::config($dir, $defaults)` / `Plugin::saveConfig($dir, $data)`(存 settings 表 `plugin_config_{目录}` 键)。

2. 插件生命周期

操作入口行为
启用后台插件中心 → `Plugin::activate($dir)`执行 install.php → 写 `enabled_plugins` → 写 `installed_plugins`(此后显示卸载按钮)→ 初始化默认配置(已有不覆盖)
禁用`Plugin::deactivate($dir)`仅移出启用列表;数据/配置保留,重新启用即恢复
卸载`Plugin::uninstall($dir)`先禁用 → 移除 installed 标记 → 执行 uninstall.php(清插件表)→ 删除配置键;插件文件目录保留(手动删除)
每请求bootstrap → `Plugin::boot()`include 所有已启用插件的 plugin.php(注册钩子);目录被删则跳过

安全边界:`Plugin::all()` 列表扫描只读源码不执行——未启用插件代码永不运行;boot/loadFile 异常全部捕获写 `storage/logs/plugin_error_Ymd.log`。

3. 钩子点全景(164 个 · 2026-10-01 源码普查校准)

3.0 钩子机制

Hook::on($name, $callback, $priority = 10);   // 注册(Hook::register 为别名)
Hook::fire($name, $data);                     // action:依次执行回调,忽略返回值,返回原始 $data
Hook::filter($name, $value, $data = null);    // filter:链式加工,返回最终值
Hook::has($name); Hook::clear($name);         // 查询 / 清空(测试用)
  • 优先级:第三参 `$priority` 越小越先执行(默认 10),同优先级按注册顺序。
  • 异常隔离:所有回调在 try/catch 中执行,插件抛错只记 `storage/logs/plugin_error_Ymd.log`,不影响主流程。
  • filter 回调签名:`function ($value, $data)`;核心未传上下文时回调只收到 `$value`($data 参数务必给默认值,如 `function ($html, $thread = null)`)。
  • fire 回调签名:`function ($data)`,$data 为关联数组。

3.1 业务事件层(action,61 个)

系统与路由(2)

钩子触发点载荷($data)现有消费者
`routes_register`bootstrap.php,前台路由加载后`$router`rank(注册 /rank 页)、api\_hub
`admin_routes_register`admin\_routes.php,后台路由加载后、通配之前`$router`ai\_reply、api\_hub、ai\_writer(各注册自管面板路由)

账户与资料(9)

钩子触发点载荷($data)现有消费者
`user_registered`注册成功`array(id, username, email)`—
`user_login`登录成功(含记住我自动登录、2FA 二次验证)`array(user, remember)`—
`user_login_failed`登录失败(密码错误/账号锁定等)`array(login, ip)`—
`user_logout`退出登录`array(user)`—
`profile_updated`用户中心保存资料`array(user_id, data)`—
`avatar_updated`用户中心上传新头像`array(user_id, url)`—
`password_changed`修改密码成功`array(user_id)`—
`user_followed`关注用户`array(user_id, target_id)`—
`user_unfollowed`取消关注`array(user_id, target_id)`—

主题与互动(14)

钩子触发点载荷($data)现有消费者
`thread_created`发帖成功(前台发帖 / 后台发布 / ai\_writer 代发,三处均触发)前台:`array(id, user_id, forum_id, title)`;后台与 ai\_writer 额外携带 `thread_id`(同 id)、`content`ai\_reply(主题级回复)、rank(活跃分)
`thread_updated`主题编辑保存后`array(thread 合并后数据, editor_id)`—
`thread_deleted`主题删除:前台软删(仅状态实际变化时一次);后台删除带 `permanent=true``array(thread, operator_id[, permanent])`—
`thread_moderated`版务操作(置顶/加精/关闭/隐藏)后`array(thread, field, column, value, operator_id)`—
`thread_liked`点赞/取消点赞主题(两个状态共用)`array(thread_id, user_id, liked)`—
`thread_favorited`收藏/取消收藏主题`array(thread_id, user_id, favorited)`—
`post_created`回帖成功(含 AI 回帖)`array(id, thread_id, user_id, content)`ai\_reply(楼层级回应)、rank
`post_deleted`回复删除后`array(post, operator_id)`—
`post_liked`楼层点赞/取消`array(post_id, thread_id, user_id, liked)`—
`poll_voted`投票提交成功`array(poll_id, thread_id, user_id, option_ids)`—
`bounty_accepted`悬赏采纳最佳答案`array(thread, post, amount, currency_id, operator_id)`—
`bounty_refunded`取消悬赏、托管款退回`array(thread, amount, currency_id, operator_id)`—
`thread_purchased`购买付费主题成功`array(thread, buyer_id, price, currency_id)`—
`thread_viewed`帖子被浏览(与 views 计数同语义:会话去重 1 小时后触发,插件无需自行防刷新;游客 user\_id=0;v2026.09.06)`array(thread_id, user_id, forum_id)`—

附件(2)

钩子触发点载荷($data)现有消费者
`attachment_uploaded`上传附件:`type=file` 文件模式与 `type=link` 网盘模式共用同一钩子名,插件按 `type` 分流`array(attachment_id, type, user_id, url, price)`—
`attachment_bought`付费附件购买成功`array(attachment, buyer_id, price, currency_id)`—

财富与交易(5)

钩子触发点载荷($data)现有消费者
`currency_changed`全站货币变动统一出口(currency\_change() 内部,覆盖签到/悬赏/附件/商城/卡密/邀请等全部记账点;事务提交后触发——监听器异常不影响已落账数据,也不可再回滚余额)`array(user_id, currency_id, amount, type, note, balance)`—
`gift_sent`送礼成功(帖内礼物与用户礼物共用)`array(from_user_id, to_user_id, thread_id, gift, price)`—
`member_purchased`购买会员成功`array(membership, user_id, price)`—
`frame_purchased`购买头像框成功`array(frame, user_id, price, expire_at)`—
`card_redeemed`充值卡兑换成功`array(card, user_id)`—

签到(2)

钩子触发点载荷($data)现有消费者
`checkin_done`每日签到成功`array(user_id, streak, total)`rank
`checkin_repaired`补签成功`array(user_id, date, cost, streak)`—

通知与私信(3)

钩子触发点载荷($data)现有消费者
`notification_sent`notify() 发送通知(合并进已有未读时 `merged=true`,新发为 `false`)`array(uid, type, title, content, link, merged)`—
`pm_sent`私信投递成功(新会话与会话内回复共用 deliver 统一出口)`array(conv_id, from_id, to_id)`—
`pm_deleted`私信会话删除(仅本人侧隐藏,对方不受影响;v2026.09.06)`array(conv, user_id)`—

设计边界:通知中心的已读/删除(NotificationController::read/delete)不设事件——纯用户对本人通知的管理操作,无对外语义,插件监听无实际价值;如需通知联动,监听 `notification_sent` 即可。

后台管理(18)

钩子触发点载荷($data)现有消费者
`user_edited`后台编辑用户保存`array(user_id, old, new, operator_id)`—
`user_muted`后台禁言用户`array(user_id, until, reason, operator_id)`—
`user_unmuted`后台解除禁言`array(user_id, operator_id)`—
`user_banned`后台封禁账号`array(user_id, operator_id)`—
`user_unbanned`后台解封账号`array(user_id, operator_id)`—
`user_group_changed`后台变更用户组`array(user_id, old_group_id, group_id, operator_id)`—
`forum_saved`后台保存版块(新建/编辑)`array(forum_id, data, operator_id)`—
`forum_deleted`后台删除版块`array(forum, operator_id)`—
`group_saved`后台保存用户组`array(group_id, data, operator_id)`—
`group_deleted`后台删除用户组`array(group, operator_id)`—
`ip_ban_added`后台新增 IP 封禁`array(ip, reason, expires_at, operator_id)`—
`ip_ban_updated`后台更新 IP 封禁配置`array(ip, reason, expires_at, operator_id)`—
`ip_ban_removed`后台解封 IP`array(ip, operator_id)`—
`settings_saved`后台系统设置保存(含分组名与该组键列表)`array(tab, keys, operator_id)`—
`mail_batch_sent`后台邮件群发完成`array(subject, to, ok, fail, operator_id)`—
`admin_threads_batch`后台帖子批量操作(删除/隐藏/恢复/移动等)`array(act, ids, affected, operator_id)`—
`report_submitted`用户提交举报(前台)`array(type, target_id, reporter_id, reason)`—
`report_handled`后台举报处理完成`array(report, operator_id)`—

插件生命周期(3)

钩子触发点载荷($data)现有消费者
`plugin_activated`插件启用成功`array(dir, operator_id)`—
`plugin_deactivated`插件禁用`array(dir, operator_id)`—
`plugin_uninstalled`插件卸载完成`array(dir, operator_id)`—

版块关注与举报(3,v2026.09-10 补录)

钩子触发点载荷($data)现有消费者
`forum_followed`ForumController@followToggle 关注成功`array('user_id', 'forum_id')`关注通知类插件
`forum_unfollowed`ForumController@followToggle 取消关注`array('user_id', 'forum_id')`同
`report_cleared`AdminReportsController@clearPost 批量清空举报`array('status', 'count', 'operator_id')`举报清理联动插件

3.2 数据管线层(filter,6 个)

核心数据流的统一出口,回调 `function ($value, $data)`,必须 return 加工后的值。

钩子位置$value上下文 $data典型用途
`content_format`helpers.php `md_render()` 返回处(所有帖文/签名/个人简介渲染的唯一出口)渲染后的 HTML`array('raw' => 原始文本)`插件自定义标签(如 `[mytag]…[/mytag]`)、内容水印、外链转跳转页
`page_title`layout.php 页面标题当前页面标题串不传按页面动态追加标题后缀
`notification_link`helpers.php `notify()` 入口通知跳转链接`array(uid, type, title)`改写通知落地页(如积分任务通知跳插件页)
`avatar_html`helpers.php `avatar_html()`头像 `<img>` HTML`array(user, size)`头像挂件、VIP 边框
`currency_type_name`helpers.php `currency_type_name()`流水类型中文名不传(返回值匹配)注册插件货币流水类型的中文显示名
`home_sync_sig`HomeController 首页轮询接口 `/home/sync` 指纹轮询指纹串不传并入插件状态指纹,驱动已打开的首页自动刷新(仅首页有此钩子)
/* 示例:自定义内容标签(在 md_render 之后、输出之前生效) */
Hook::on('content_format', function ($html, $data = null) {
    return str_replace('[hr]', '<hr class="my-hr">', $html);
});

3.3 前台视图插槽层(filter,82 个)

回调接收并返回 HTML 串(视图用 `<?= Hook::filter(...) ?>` 直接输出)。输出前必须自行 e() 转义来源数据。

全站布局(layout.php,15 个)

钩子位置上下文 $data典型用途
`layout_head``</head>` 前—注入 CSS/JS/meta(每页生效)
`layout_body_start``<body>` 顶部—全站浮层/顶部公告条
`layout_body_end``</body>` 前(晚于核心脚本)—底部 DOM/脚本
`nav_links`顶部导航—加导航链接(用 `class="nav-link"` 保持样式)
`nav_logo_after`品牌 Logo/站名链接后—站点徽标/内测标注(只能放非交互内联元素,禁嵌套链接)
`nav_tools_before`顶栏工具区前(搜索/通知/头像之前)—顶栏工具类入口
`nav_search_after`顶栏搜索框后—搜索增强/快捷入口
`user_menu_links`用户下拉菜单`array(user)`我的订单/我的商店等菜单项
`main_area_before` / `main_area_after`主内容区顶/底—全站横幅;三栏主题左栏挂载点
`footer_links`页脚—页脚链接
`side_nav_links` / `side_nav_bottom`左侧吸附导航(后台开侧导航时)—侧导航链接与底部卡片(`nav_links` 原样并入)
`lq_links` / `lq_bottom`左侧快捷导航卡(partials/left-quick-nav.php)—快捷导航卡专用追加位(与顶部导航共用 `nav_menu_*` 开关)

三栏主题接入模式:核心不提供固定左栏 DOM,由主题插件组合实现——`main_area_before` 输出 `<div class="plugin-left-col">` + `layout_head` 注入栅格 CSS(把 `.main-area` 改为 grid 三栏/两栏)+ `layout_body_end` 注入交互 JS。改核心布局零侵入,多主题插件可共存按启用互斥。

登录 / 注册(6 个)

钩子位置上下文 $data
`login_form_before` / `login_form_after`登录页顶/底—
`login_form_fields`登录表单内附加字段—
`register_form_before` / `register_form_after`注册页顶/底—
`register_form_fields`注册表单内附加字段—

首页(home.php,5 个)

钩子位置上下文 $data
`home_content_before`首页主体顶部—
`home_hero_after`统计横幅之下、版块列表之上—
`home_left_top` / `home_left_bottom`三栏布局左栏顶/底—
`home_main_bottom`三栏布局中栏底—

侧栏(首页/版块/帖子三处共用 + 语义化卡片锚点,12 个)

\| 钩子 | 上下文 $data |
\| --- |
\| `sidebar_top` / `sidebar_mid` / `sidebar_bottom`(mid = 首页热门主题后 / 版块页版块信息卡后 / 主题页作者卡后;home.php 不带上下文;forum.php 传 `$forum`;thread.php 传 `$thread`) |
\| 语义化卡片锚点(2026-09-10 补全,对齐 XiunoX「每张原生卡片后留缝」):首页 `sidebar_hot_after`(热门主题卡后)/ `sidebar_newuser_after`(新成员卡后)/ `sidebar_friendlink_after`(友链卡后);版块页 `sidebar_foruminfo_after`(版块信息卡后)/ `sidebar_mods_after`(版主卡后,无版主不渲染);帖子页 `sidebar_author_after`(作者卡后)/ `sidebar_related_after`(相关主题卡后,无相关帖不渲染)/ `sidebar_latest_after`(本版最新回复卡后)/ `sidebar_forummini_after`(版块迷你卡后)。ctx 与所在页侧栏钩子一致;卡片被条件隐藏时对应缝不渲染 |

版块页(forum.php,6 个)

钩子位置上下文 $data
`forum_content_before` / `forum_content_after`版块页顶/底(两种布局均生效)`$forum`
`forum_threads_before`主题列表卡内顶部`array(forum, filter, cat_id)`
`forum_threads_after`主题列表卡内底部`array(forum, filter, threads)`
`forum_left_top` / `forum_left_bottom`三栏布局左栏顶/底—

帖子详情页(thread.php,10 个)

钩子位置上下文 $data
`thread_head_after`标题/标签区与正文之间`$thread`
`thread_content_before` / `thread_content_after`正文前/后`$thread`(现有消费者:thread\_visitors)
`thread_actions_extra`主楼操作条内(点赞/收藏/分享按钮追加,与楼层 `post_actions_extra` 对称)`$thread`
`post_author_extra`每层楼作者名附加徽章`$p` 楼层行
`post_actions_extra`每层楼操作按钮区`$p`
`post_floor_extra`每层楼操作条下附加内容`$p`
`reply_form_before`回复表单前`$thread`
`thread_left_top` / `thread_left_bottom`三栏布局左栏顶/底—

发帖 / 编辑页(thread-new\.php + thread-edit.php 共用,2 个)

钩子位置上下文 $data
`post_form_before` / `post_form_after`表单上/下方发帖 `array(forum)`;编辑 `array(forum, thread)`

编辑器(partials/editor.php,前后台共用,2 个)

钩子位置上下文 $data
`editor_toolbar_buttons`工具栏按钮区`array(canUpload, editorId)`
`editor_after`编辑器下方附加区`array(canUpload, editorId)`

列表行(partials/thread-row\.php,1 个)

钩子位置上下文 $data
`thread_row_extra`主题行内附加信息(首页/版块/用户主页列表共用)`$t` 主题行

用户主页(user.php,3 个)

钩子位置上下文 $data
`user_profile_header_after`主页头部之下`$u`
`user_profile_tabs`tab 栏尾(链接用 `?tab=xxx#profile-tabs` 防跳页顶)`$u`
`user_profile_tab_content`tab 面板区首(插件自判 `$data['tab']` 渲染面板)`array(tab, user)`

用户中心(uc.php,3 个)

钩子位置上下文 $data
`uc_nav_links`中心导航尾`$me`
`uc_content_before`内容区顶部(每页生效)`array(tab, me)`
`uc_tab_content`主区首(插件自判 `$data['tab']` 渲染整页)`array(tab, me)`

搜索 / 标签 / 签到 / 商城 / 礼物页(8 个)

钩子位置上下文 $data
`search_content_before` / `search_content_after`搜索页顶/底`array(q)` / `array(q, total)`
`tag_content_before` / `tag_content_after`标签页顶/底`array(tag)`
`checkin_content_before`签到页顶部`array(streak)`
`shop_content_before` / `shop_hero_after`商城页顶部 / 横幅下—
`gifts_content_before`礼物墙页顶部—

私信页(pm-inbox.php + pm-view.php 共用,2 个;v2026.09.06)

钩子位置上下文 $data
`pm_content_before` / `pm_content_after`私信页顶/底(两页共用)收件箱不传;会话页传 `array(conv, partner)`

插件自定义 tab 页模式(`uc_tab_content` / `user_profile_tab_content`):插件注册路由渲染页面骨架,或在钩子里输出面板——内置 tab 为 if/elseif 链且无 else 兜底,插件 tab(如 `shop`)不命中任何内置分支,仅插件内容渲染;tab 链接用 `?tab=xxx`(user 主页需带 `#profile-tabs` 锚点)。

应用中心(apps.php,2 个;v2026.09 补录)

钩子位置上下文 $data
`app_cards`应用中心功能卡片区(与 `nav_links` 同挂,结构化:icon/name/desc/url)`$cards`(数组)
`apps_content_after`应用中心页底部`$html`

专题页(topic.php / topics.php,5 个;v2026.09 补录)

钩子位置上下文 $data
`topic_content_before` / `topic_content_after`专题页顶/底(详情与总览共用,载荷含 null 兼容)`array('topic' => $topic 或 null)`
`topic_main_bottom`专题详情主区底部`$html`
`topic_sidebar_top` / `topic_sidebar_bottom`专题详情侧栏顶/底`$html`

3.4 后台视图插槽层(filter,15 个)

回调接收并返回 HTML 串,仅在后台页面生效;后台只加载 admin.css(样式需自带 `<style>` 内联或经 `admin_head` 注入,不能依赖 app.css)。

布局(admin/layout.php,6 个)

钩子位置上下文 $data
`admin_head``</head>` 前—
`admin_body_start``<body>` 起始—
`admin_body_end``</body>` 前(晚于核心脚本)—
`admin_nav_links`侧栏菜单尾(自组 `.nav-group` 结构)`array(module)` 当前模块
`admin_content_before` / `admin_content_after`内容区顶/底(每页生效)`array(module)`

注意:核心侧栏菜单按多级管理组模块授权自动过滤(`Auth::adminModules()`),但插件经 `admin_nav_links` 输出的菜单项不会被自动过滤——插件需自行调用 `Auth::adminModules()` 判断(返回 null=全权限,否则为模块名数组)再决定是否输出。

各管理页(9 个)

钩子位置上下文 $data
`admin_dashboard_stats_after`仪表盘统计卡下方`array(stats)`
`admin_dashboard_content_after`仪表盘页尾`array(stats, env)`
`admin_settings_tabs`系统设置页 tab 栏尾`array(tab)`
`admin_settings_panels`系统设置页面板区(配套 tabs 加的页签)`array(tab)`
`admin_user_edit_sections`用户编辑页底部区块`$u`
`admin_group_form_after`用户组编辑页表单下方`$group`(新建时 null)
`admin_thread_row_actions`帖子列表行操作区`$t` 行数据
`admin_thread_form_after`帖子发布/编辑页表单下方`array(context: new/edit[, thread])`
`admin_tools_items_before`系统工具列表前置项(自组 `.tool-item` 表单)—

集成系统设置页模式(`admin_settings_tabs` + `admin_settings_panels` 配对使用):

/* 1. tab 栏尾加页签链接 */
Hook::on('admin_settings_tabs', function ($html, $data = null) {
    return $html . '<a class="tab-btn ' . (($data['tab'] ?? '') === 'myplug' ? 'is-active' : '') . '"'
        . ' href="' . aurl('settings?tab=myplug') . '">我的插件</a>';
});

/* 2. 对应 tab 渲染面板 */
Hook::on('admin_settings_panels', function ($html, $data = null) {
    if (($data['tab'] ?? '') !== 'myplug') {
        return $html;   /* 非本插件 tab 直接返回 */
    }
    return $html . '<form method="post" action="' . url('myplug-save.html') . '">'
        . csrf_field() . ' /* 表单字段 */ </form>';
});

关键约束:面板表单必须提交到插件自有路由(经 `routes_register` 注册)——核心 `settings/save` 端点有 `$keys[$tab]` 白名单,只接受内置 tab 的固定键名,插件的 POST 字段会被丢弃。自有路由内自行做 `Auth::isAdmin()` + `Csrf::check()` 后 `Plugin::saveConfig()`。

4. 内置插件(17 个)

4.1 ai\_reply — AI 智能回复(v1.4.1,答案风格对齐 GEO 问答工厂:结论前置 + 分段展开)

源码:[content/plugins/ai\_reply/plugin.php](../content/plugins/ai_reply/plugin.php)。OpenAI 兼容多提供商自动回帖。

  • 触发机制(事件驱动):`thread_created`(新主题触发)+ `post_created`(用户回帖时挂其楼层下针对性回应);@机器人强制触发;判定规则:机器人身份排除、版块白名单、用户组、关键词、`reply_all`(默认开)/`reply_to_bot`、每日限额、每主题上限 `thread_max`、每对话上限 `conv_max`。
  • 上下文感知:`ctx_thread_len` 帖子正文字符数(0=仅标题);`ctx_history` 沿 `reply_post_id` 回溯楼层链(0-10 层,含 AI 自身发言)——用户 B 回复 A 时 AI 可见 A→B 脉络。输入侧保留 `[em]url[/em]` 完整表情标签给 AI;输出侧修复 URL 前缀(补 `/` 或 `http` 开头为 `/assets/gif/xxx`)确保 `md_render()` 解析为表情图。
  • 生成参数:`temperature` / `max_tokens` 注入请求 payload(max\_tokens=0 不传);`answer_max` 清理长度。
  • 四策略轮询:顺序 / 随机 / 故障转移(failover)/ 并发竞速;提供商连续失败自动熔断、到期自动恢复。
  • 回复延迟:`delay` 0-300 秒模拟人工(shutdown 后 sleep,锁持有期间防重复)。
  • AI 标识:`ai_tag` 回复末尾 `<!--AI_TAG-->标识文本` 注释锚点,前台 `ai_tag_extract()` 提取渲染为动态徽章(紫色渐变 + 流光描边 + 图标呼吸)。
  • 敏感词:内置约 240 词默认表(赌博色情/毒品暴恐/诈骗引流/辱骂/账号证件收购/荐股暴富等类别,避开日常用词防误伤);命中整条不发记 fail;用户可增删(上限 20000 字符)。
  • 数据表:`plugin_ai_reply_providers`(提供商)、`plugin_ai_reply_logs`(调用日志:触发源/请求/回答/状态/耗时)。
  • 后台面板:声明 `admin_url` → `admin.php/ai-reply` 五标签面板(基本/提供商/触发规则/敏感词/日志统计),日志面板支持 retry 一键重新生成(删原记录同步重跑 worker)与筛选计数(全部/成功/失败各状态数量)。
  • 配置迁移:`reply_all_migrated` / `prompt_migrated` / `sw_migrated` 一次性 marker(旧默认值精确匹配才替换,用户自定义不动)。

4.2 site\_rank — 社区排行榜(v1.0.0)

源码:[content/plugins/site\_rank/plugin.php](../content/plugins/site_rank/plugin.php)。`routes_register` 注册 `/rank` 页面,`nav_links` 注入顶部导航「排行」入口(可配置隐藏)。

  • 三榜 × 三周期:热门主题(点赞×3 + 回复×2 + 浏览÷10 加权)/ 活跃用户(周期内主题 + 回复合计)/ 财富榜(按配置货币余额);主题与用户榜支持近 7 天 / 近 30 天 / 累计周期切换。
  • 权限口径:热门主题榜按当前访客可见版块过滤(`visible_forum_ids()`),缓存键含版块集合指纹(md5)——不同权限各自缓存互不污染,多数访客共享同一份。
  • 缓存:`Cache::remember('sr_*', 600)` 十分钟缓存;核心「系统工具 → 清理缓存」可整体失效。每榜条数(10-100)与财富榜货币在插件配置调整(模式一声明)。
  • 无自建表:纯查询侧聚合(threads/posts/user\_currency),无累计分表,卸载零残留。

4.3 thread\_visitors — 帖子访客(v1.0.1)

`thread_content_after` 挂载点输出最近浏览该帖的会员头像列表;仅记录登录用户浏览(`plugin_thread_visitors` 表),按时间倒序,定期清理;标题/显示数量/清理周期可配置。

4.4 ai\_writer — AI 智能写作(v1.5.5)

AI 标题池 + 文章生成 + 定时发布(参考 Typecho AIExcerpt 融合设计)。核心机制:

  • 标题池(`plugin_ai_writer_titles`):AI 按主题批量生成标题(去重:池内 + threads 表 + 批内 + 敏感词)或手工批量导入;状态机 pending → preview/published/failed,preview 状态可在面板查看渲染后的暂存正文并一键发布/重新生成;筛选栏计数联动(状态 chips 计数跟随版块+分类筛选、版块/分类下拉各选项显示当前口径数量)。
  • 标题缺陷过滤(`ai_writer_title_defects()`,生成期解析与体检共用的单一规则源):元话语(对排除清单的评论:「不要重复」「已覆盖」「已存在」「已有+引号」「给定列表」等)、提示词回声(AI 把指令文本原样当标题输出)、结构化残渣(行尾 `" Count.` 类英文残留)、纯括号片段(整条被一对括号包裹)、长引文复述、截断(逗号/顿号结尾)、列表前缀残留、冒号结尾、句中句号、过短/过长、无中文——每条规则按真实标题语料校准边界防误杀;缺陷行在计数前丢弃不消耗请求配额。
  • 生成 prompt 构造:主题为主指令、排除清单只约束「不要重复或近似改写」(措辞刻意避免「含义角度完全不同」——同主题多次生成时会与「紧扣主题」自相矛盾导致跑题);清单尾部重申主题压制模型重尾漂移;自定义模板丢失 `{topic}` 占位符时守卫性补上(防纯静默跑题)。排除清单为该版块现有全部标题(最近 300 条,prompt 注入最近 100 条)。
  • 标题池体检(`ai_writer_pool_checkup()`):pool 页「开始体检」同步只读扫描(范围跟随版块筛选),筛出两类问题供勾选清理(复用 titles-batch 端点)——①疑似无效(缺陷规则 + 复述池内标题精确检测);②重复/相似分组(SQL 精确查重盲区):规范化(去标点符号+小写)完全相同 / 仅数字差异(「10 个技巧」vs「12 个技巧」)/ 二 gram 倒排阻断 + similar\_text ≥ 80% 高度相似,DSU 并查集合并分组;无效与完全重复冗余项默认勾选,相似组人工判断。
  • 异步生成任务(v1.5.2+,`plugin_ai_writer_jobs`):「AI 批量生成标题」「立即生成」「预览」均为异步入队 + `titles-progress` 端点轮询进度(2 秒),可离开页面后台继续,刷新自动恢复进度显示。可中断续跑看护模式(应对 FPM `request_terminate_timeout` 杀长循环):worker 全程持独立任务锁(`storage/cache/ai_writer_job.lock`,与调度锁分离)+ 单次预算 90 秒到点退出(任务保持 running),轮询/懒调度/cron 三处看护「running 且锁空闲」即重新拉起,排除清单等上下文从 DB 重建断点续跑。完成语义按实际入库数计(请求量 = 缺口 + 5 余量,入库硬上限 = 缺口);连续 3 块零新增判定主题穷尽收尾。
  • 发布任务(`plugin_ai_writer_tasks`):每任务独立版块 + 子分类(v1.5:指定则只消费该分类标题)+ 机器人 UID(发帖数计入该账号、不暴露管理员身份)+ interval(≥300 秒)/daily(HH:MM)双频率 + 每次篇数(1-5)+ 任务级 model/温度/max\_tokens/提示词覆盖。
  • 子分类支持(v1.5,schema v4):titles/tasks/jobs 三表补 category\_id(自愈迁移);生成/导入表单与任务表单均为版块→子分类联动下拉(catsMap JSON + data-aw-forum/data-aw-cat 通用绑定);标题池列表显示分类徽章、筛选栏加分类下拉(归属校验:cat 必须属于所选版块);一键清空尊重 cat 筛选;发布时 threads.category\_id 取自标题池行(列就绪才写)。
  • 调度:三通道共用一把文件锁(`storage/cache/ai_writer.lock`)——① 前台懒调度(`register_shutdown_function` + 55 秒节流 + 先 `session_write_close` 释放会话锁 + `fastcgi_finish_request`,零配置);② 独立 `cron.php`(CLI / Webcron + cron\_key 校验);③ 后台手动操作走异步任务机制。单次调度受时间预算(max\_run\_sec)与任务数(max\_tasks)约束,防止刷版。
  • AI 调用:直接读 ai\_reply 的 `plugin_ai_reply_providers` 表(无独立提供商配置),自带 4 策略调用层(order/random/failover 粘滞/race 并发竞速)与熔断记账(写回该表);超时取 max(本插件设置, 提供商 timeout) 防提供商面板短超时卡死长 prompt;全部失败时聚合各提供商具体错误(名称+原因)返回 job error 与日志;表不存在时优雅降级并提示。
  • 发布副作用:完整复刻 ThreadController::store —— forums/users 计数、normalize\_tags、可选机器人经验(默认不发)、关注者通知(限 100)、`Hook::fire('thread_created')`;ai\_reply 启用且机器人 UID 不一致时面板预警防两个 AI 互怼。
  • 内容管线:AI 末行输出 `<!--TAGS-->标签` 自动打标(与池内预设标签合并)、正文 H1 提取替换标题、代码围栏剥壳、max\_chars 截断、约 120 词内置敏感词表双重拦截(入池前 + 发布前);AI 输出清洗用多字节安全 trim(`ai_writer_trim`,preg\_replace /u 实现——PHP trim 的字符列表参数按字节处理,含中文标点会截坏多字节字符触发 SQL 1366),入库前 `mb_check_encoding` 防代理截断。
  • 统计看板:`plugin_ai_writer_logs` 全量记录(action=title/article/publish、Token 出入、耗时、触发源 lazy/cron/manual/preview),看板含任务/发帖/Token 今日·近 7·30 天·累计卡片与 14 天成功失败趋势图;生成日志筛选 chips 带各状态计数。

4.5 api\_hub — API 工具箱(v1.0.2)

独立 API 聚合页面(移植自 Xiuno 版 chuan\_api\_hub 插件,全面重构并修复其缺陷)。前台 `/api-hub`(导航入口 `nav_links`),后台自定义面板 `admin.php/api-hub`(admin\_url 声明直达)。

  • 23 个解析服务(`ah_services()`,按 group 分组:video 短视频 14 / image 图文集 3 / music 音乐 4 / world 海外 2):抖音、快手、小红书、微信视频号、微视、头条、微博、最右、皮皮虾、皮皮搞笑、B站、AcFun、虎牙、即梦、知乎、千问、豆包、汽水音乐、酷我、网易云(支持纯数字 ID)、QQ 音乐、TikTok、YouTube。每服务独立开关 + 独立 API URL 覆盖;上游统一 api.nycnm.cn + apikey。
  • 规范化引擎(`ah_normalize`):上游 JSON 递归收集媒体 URL(key 名语义 + 扩展名双重判定,`ah_collect_urls`),统一输出作者/头像/标题/封面/视频数组/图片数组/互动数据/清晰度/时长;特殊平台适配(wxsph/zhihujx/qianwen/jimengai)。协议相对地址 `//xxx` 自动补全 https(原版直接丢弃)。
  • 计费:多货币按次收费(`cost_cid` 下拉选择 + `cost_num`,0=免费),失败不扣费;余额预检 + `currency_change`(type=api\_hub)双保险;每日限额按用户按接口计成功次数(0=不限)。
  • 防盗链处理(修复原版缺陷):前台所有 `img`/`video` 带 `referrerpolicy="no-referrer"`、`a` 带 `rel="noreferrer noopener"`——上游 CDN 的 Referer 白名单校验不再 403;视频提供内嵌播放器(多视频可切换源)、每个资源带「复制直链 / 新窗口」按钮、图集支持一键复制全部图片直链。
  • 前台 UI(ah- 前缀 + 站点 CSS 变量):接口搜索 + 分组 chips 联合过滤、今日次数徽章实时刷新、余额实时刷新、最近解析(管理员看全站);游客可浏览、解析需登录(need\_login JSON 跳登录)。
  • 后台面板:统计卡(累计/今日全站/启用数/开关)+ 基本设置 + 按分组的接口配置(批量启停/地址展开)+ 全站解析记录表(30 条)与按天数/全部清理(claraConfirm)。
  • 数据表:`plugin_api_hub_log`(user\_id/service/input\_url/title/result\_url/cover\_url/cost\_cid/cost\_num/created\_at,InnoDB)。今日次数用单条 GROUP BY(原版逐接口 COUNT);表存在性请求级缓存(原版每请求 CREATE TABLE)。

4.6 member\_wall — 首页会员墙(v1.0.0)

源码:[content/plugins/member\_wall/plugin.php](../content/plugins/member_wall/plugin.php)。首页会员墙:推荐 / 最新 / 活跃 / 财富四榜展示,支持付费上墙(行锁 + 事务购买,官方并发安全范例);`Cron::register('member_wall/refresh')` 定时刷新榜单缓存;`home_sync_sig` 并入状态指纹驱动首页自动刷新。标准插件范本(skill 的 data-patterns 以它为并发/缓存/通知迁移示例)。

4.7 ad\_self — 广告位自助投放(v1.7.0)

源码:[content/plugins/ad\_self/plugin.php](../content/plugins/ad_self/plugin.php)。广告位自助购买:积分按天/周/月/年购买首页与内容区广告位,支持审核、续费、到期重新投放、草稿修改与到期自动下架。

  • 坑位容量制:每插槽 N 个坑位(1-10),pending + active + 未到期均占坑,坑满不再出招租占位;购买走「提交前快速失败 + 事务内 settings 行锁权威复查」防并发超卖。
  • 分型渲染:图片广告整幅堆叠在上、文字广告收 `auto-fill minmax(150px,1fr)` 栅格在下、空坑渲染招租占位、`shuffle` 零 JS 公平曝光;合规角标「广告」。
  • 选位组合拳:正文流通栏位(home\_hero\_after / forum\_content\_before / thread\_content\_after)+ 侧栏三页位(按页分发)+ 通栏/全文模式复刻布局判定兜底——任何布局任何设备付费广告都可见。
  • 数据表:`plugin_ad_slots`(广告位)、`plugin_ad_orders`(投放订单)。

4.8 lottery — 幸运抽奖(v1.3.0)

源码:[content/plugins/lottery/plugin.php](../content/plugins/lottery/plugin.php)。三合一抽奖:帖子回帖抽奖(预扣/三种开奖模式)+ 侧边栏概率抽奖 + 转盘抽奖(conic-gradient 扇区角宽 ∝ 真实概率,prefers-reduced-motion 三件套降级)。服务端权威判定 + 前端纯动画落格:结果永远在 POST 接口事务内产生(行锁/限额/扣费同核心口径),扇区签名 md5 防「渲染页 → 点击」窗口期改奖池落错格;奖品可独立指定货币,含中奖通知与后台管理。五张自建表(threads/participants/slots/draws/winners)。

4.9 ks\_exam — 入站考试(v1.0.0)

源码:[content/plugins/ks\_exam/plugin.php](../content/plugins/ks_exam/plugin.php)。新人入站考试:通过考试自动解锁互动权限并授予专属头衔,自带技术通识题库、随机组卷与防作弊机制。权限锁定插件的「入口体验层」范例:layout\_head 隐藏入口 + layout\_body\_end toast 守卫 + 页面插槽兜底三层(服务端权限位仍是最终防线;toast 类型是 `err` 不是 `error`)。六张自建表。

4.10 geo\_qa\_factory — GEO 问答工厂(v1.0.0)

源码:[content/plugins/geo\_qa\_factory/plugin.php](../content/plugins/geo_qa_factory/plugin.php)。AI 批量生产「悬赏提问 + 最佳答案」问答对:输入主题 → AI 生成草稿(`plugin_geo_qa_factory_queue`)→ 人工审核 → 一键发布并采纳(复刻悬赏帖语义)→ 自动进入 `/answers` 问答池与 llms-full.txt。`Cron::register('geo_qa_factory/gen')` 每日自动生成;后台经 `admin_routes_register` 注册 `/admin.php/geo-qf` 面板(admin\_nav\_links 注入导航)。与 ai\_reply 站点知识库共享事实源,两条 GEO 内容产线互补。

4.11 brand\_landing — 品牌落地页(v1.0.0)

源码:[content/plugins/brand\_landing/plugin.php](../content/plugins/brand_landing/plugin.php)。系统介绍落地页:实时数据展示本站功能特性与最新动态,滚动入场动画 + IntersectionObserver 数字计数(服务端直出真实值保 SEO,prefers-reduced-motion 全跳过)。插件独立全屏页范例:不套 layout.php 自写完整 `<!DOCTYPE html>`,主题跟随复刻核心判定链(访客 cookie > theme\_auto\_current() 时段自动 > 后台默认),CSS 变量引自 app.css。

4.12 quick\_reply — 快速回帖(v1.1.0)

源码:[content/plugins/quick\_reply/plugin.php](../content/plugins/quick_reply/plugin.php)。楼层一键快捷回复:免验证码用户点击即回帖;需验证码用户组点击短语填入回复框(输码后正常发表),防灌水与禁言/头像校验对齐核心回帖链路。

4.13 copy\_tail — 复制保护小尾巴(v1.0.0)

源码:[content/plugins/copy\_tail/plugin.php](../content/plugins/copy_tail/plugin.php)。复制帖子内容自动追加来源小尾巴(站点/标题/链接/时间)并弹窗提示,防止无署名搬运。

4.14 mourning — 黑白哀悼模式(v1.3.0)

源码:[content/plugins/mourning/plugin.php](../content/plugins/mourning/plugin.php)。国家哀悼日/重大事故悼念场合一键开启全站黑白模式:纯 CSS 滤镜实现前台灰度显示(后台保持彩色),支持自动生效日期(每年重复/一次性),过零点自动恢复,普通刷新即生效。

4.15 pet\_garden — 论坛萌宠

源码:[content/plugins/pet\_garden/plugin.php](../content/plugins/pet_garden/plugin.php)。萌宠养成互动:用户领养宠物、喂养升级,侧栏萌宠榜展示(全站排行),社区趣味玩法类插件。

4.16 sync\_platform — 外站同步

源码:[content/plugins/sync\_platform/plugin.php](../content/plugins/sync_platform/plugin.php)。帖子一键同步到外站平台:公众号(官方 API)+ CSDN(模拟登录),文章多平台分发,扩大内容触达面。

4.17 geo\_check — GEO 检测

源码:[content/plugins/geo\_check/plugin.php](../content/plugins/geo_check/plugin.php)。单篇帖子的 GEO 可视化体检:收录状态、爬虫访问、推送记录、结构化数据逐项检测,与核心「GEO 每日体检」互补(全站体检在核心,单篇诊断在此插件)。

5. 插件开发指南

5.1 最小可用插件

<?php
// content/plugins/hello/plugin.php
if (!defined('BASE_PATH')) {
    exit;
}

/*
Plugin Name: Hello
Description: 在帖子正文后追加一句问候
Version: 1.0.0
Author: Me
*/

Hook::on('thread_content_after', function ($html, $thread = null) {
    return $html . '<div class="hello-box">感谢阅读「' . e($thread['title'] ?? '') . '」</div>';
});

启用:后台「插件中心 → 启用」即生效(无需重启,每请求 boot 加载)。

5.2 带配置与自建表

  • `install.php` 中用 `Db::q()` 建表(表名 `Db::t('plugin_hello_items')`,自动带前缀);`uninstall.php` 中 `DROP TABLE`。
  • `plugin.php` 末尾 `return array('config' => array(...))` 声明配置 → 插件中心出现「配置」按钮(`AdminPluginsController::settings` 通用表单)。按钮仅启用后显示,配置端点校验启用状态(未启用插件的主文件不得被 include 执行)。
  • 读配置:`Plugin::config('hello', array('k' => '默认值'))`。

5.3 自定义后台面板

return array(
    'admin_url' => 'hello-admin',   // 「配置」按钮直达 url('admin.php/hello-admin')
);

Hook::on('admin_routes_register', function ($router) {
    $router->any('/admin.php/hello-admin', function () {
        Auth::boot();
        if (!Auth::isAdmin()) {
            abort_page(403, '无权限');
        }
        if (Request::isPost()) {
            Csrf::check();
            // 保存配置 Plugin::saveConfig('hello', $_POST)
        }
        $content = View::renderFile(BASE_PATH . '/content/plugins/hello/views/admin.php', array(
            'cfg' => Plugin::config('hello'),
        ));
        echo View::render('admin/layout', array('pageTitle' => 'Hello 设置', 'content' => $content));
    });
});

注意:插件后台路由必须自行做 `Auth::isAdmin()` + `Csrf::check()`(核心守卫不覆盖插件路由);且必须注册在 `admin_routes_register` 钩子内(先于通配路由匹配)。

5.4 核心公共设施:Cache 缓存与 Cron 计划任务(v2026.09.06)

插件需要的两类通用能力已抽入核心,不要再自造轮子(参照 member_wall 迁移:删掉自有的 `mw_cache_get/set/purge` 约 30 行,改 `Cache::remember` 一行式,行为不变)。

缓存([app/Core/Cache.php](../app/Core/Cache.php))——榜单、热点数据、外部接口响应等:

/* 读缓存,未命中查库并回写 5 分钟(最常用) */
$rows = Cache::remember('mw_rank_new_0', 300, function () {
    return Db::all('SELECT ...');
});

/* 配置变更时主动失效(不等 TTL 自然过期) */
Cache::forget('mw_rank_new_0');
  • 键约定:加插件前缀防冲突(如 `mw_`、`aw_`);只含 `[A-Za-z0-9_.-]`(其余字符自动转下划线)。
  • `remember` 的空值也算命中(防空穿透:查询失败返回空数组也被缓存,不会每次打穿到库);需区分「未命中」用 `Cache::get($key) === null`。
  • 后台「系统工具 → 清理缓存」会一并清掉(`*.cache` 后缀约定)。

计划任务([app/Core/Cron.php](../app/Core/Cron.php))——定时刷新、清理、汇总等:

/* plugin.php 顶层注册(boot 阶段即生效) */
Cron::register('member_wall/refresh', '会员墙榜单刷新', 300, function () {
    foreach (array('new', 'active', 'rich') as $t) {
        Cache::forget('mw_rank_' . $t . '_0');
    }
    return '已刷新 3 个榜单';   /* 返回摘要,后台「系统工具→计划任务」展示 */
});
  • 任务名全局唯一,建议 `插件目录/功能`;间隔 ≥60 秒。
  • 触发零配置:前台有访问即自动驱动(懒触发);低流量站可在服务器配置 cron 每分钟请求 `/cron.html?key=密钥` 精准触发(密钥在后台系统工具页)。
  • 任务体要求幂等(锁超时或进程被杀后下次触发会重跑);异常自动记录为失败,不连坐其他任务。
  • 依赖 `cron_runs` 表(数据库升级建);未升级时任务静默跳过,站点不受影响。
  • 特例说明:ai_writer 因需要「用户自定义间隔 + 每日定点 + 批次断点续跑看护」等超出固定间隔模型的能力,保留自有调度不迁移;简单定时需求一律用核心 Cron。

5.5 界面文案 i18n(v2026.09.15 起)

核心 i18n 机制详见 [02-核心框架.md](02-核心框架.md) Lang 章节(源串即键:zh-cn 直通,未收录回退中文永不空文案)。插件接入零门槛——照常写中文,输出层包 `t()`:

/* PHP 侧(视图/控制器输出) */
echo t('已复制 ') . $n . t(' 条');
echo t('奖励 %s 金币', array($amount));   /* 占位符 sprintf 语法 */
/* JS 侧(fetch 回包后的提示等):查 window.CLARA_I18N,zh-cn 空表回退原文 */
claraToast(T('购买成功'));

两大禁忌(违者 fatal,生产事故沉淀):

  1. 编译期常量位置禁调 t()——`static $x = array(...t()...)` / `const` / 类属性默认值 / 参数默认值皆编译级 fatal。static 用惰性初始化(`= null` + `if (=== null)` 填充)
  2. plugin.php 顶级代码禁调 t()——加载期 `setting()` 未定义,t() → `Lang::boot()` 即 fatal。`Cron::register` 的 `$label` 传中文字面量(后台任务列表展示期自动 `t()` 翻译),其余顶级 t() 移入函数/闭包体内

补译(可选增强,不补也不破功能):新串在 `content/lang/en.php` + `zh-tw.php` 同键补条目(键 = 中文源串逐字符一致;占位符序列/换行数/首尾空格守恒);仅 JS 用的串另加入 `content/lang/js-keys.php` 清单(JS 翻译表按此清单裁剪注入,不整包内联)。

5.6 开发注意事项

  1. 插件 PHP 文件必须加 `BASE_PATH` 防护头,防直接 HTTP 访问。
  2. 页面级样式用内联 `<style>` 随输出渲染,类名统一加插件前缀(如 `tv-`),复用 `app.css` 的 CSS 变量(`--bd`/`--soft-2`/`--tx-2`/`--radius-s`/`--ac`)保证主题一致。后台插槽输出的内容不能依赖 app.css(后台只加载 admin.css)。
  3. 插件抛错会被 Hook 捕获记日志,但不要在回调里做致命假设(如未判空直接用 `$thread['x']`)。
  4. 钩子回调签名:filter 型为 `function ($value, $data)`(`$data` 可能不传,需默认值);fire 型为 `function ($data)`。
  5. 多 tab 共用一个 save 端点的插件面板:保存时按表单 hidden 标识分支构造 `$new`,只更新本页字段,否则未提交字段会经 `array_merge` 默认值洗掉另一 tab 的配置。
  6. 监听 `thread_created` 时以 `id` 键为主(前台/后台/ai\_writer 三处触发均已对齐;`thread_id`/`content` 仅后台与 ai\_writer 额外携带,勿作必需字段依赖)。
  7. 动作型钩子(点赞/收藏等)携带状态布尔(`liked`/`favorited`),监听方需区分正向与取消操作,避免重复记账。
  8. 建表与手写 SQL 避开 MySQL 保留字:列名撞保留字(如 `explain`、`order`、`group`、`key`)会直接 1064 语法错误导致 install.php 中断(真实案例:ks_exam 首版 `explain` 列)。`Db::insert/update` 等封装会自动反引号列名,但手写 SQL(建表 DDL、SELECT 列清单)必须自己加反引号(`` `explain` ``),或干脆换列名(如 `tip`)。

本文档随系统发布维护;如发现与当前版本不符,欢迎到社区反馈。