Xiuno BBS 后台管理面板详解
# Xiuno BBS 后台管理面板详解
> 本文由人工智能辅助编写。本文档详细讲解了 Xiuno BBS 4.0 后台管理面板的架构、功能模块、安全机制与插件扩展点,适合需要理解后台运作原理的开发者阅读。
---
## 一、概述
Xiuno BBS 的后台管理面板是整个论坛系统的控制中枢,站点管理员通过它完成站点配置、版块管理、用户管理、主题批量操作、插件管理等核心运维工作。后台入口位于站点根目录下的 `admin/` 目录,通过 `http://your-domain.com/admin/` 访问。
与前台一样,后台遵循 Xiuno BBS 一贯的「过程式 + 扁平化」设计哲学——没有复杂的框架抽象,没有 MVC 的层层嵌套,路由是 `switch-case`,逻辑是直来直去的 `if-else`,视图是原生的 PHP HTML 混编。这种设计让后台代码极度易读,也让插件开发者可以轻松地通过 Hook 机制注入自己的功能。
---
## 二、启动流程:从请求到页面
理解后台的第一步是理解它的启动流程。后台的入口文件是 `admin/index.php`,但它并不是一个完全独立的系统——它巧妙地复用了前台的核心初始化逻辑。
### 2.1 入口文件 admin/index.php
```
admin/index.php
├── 定义 ADMIN_PATH 常量(admin/ 目录的绝对路径)
├── 定义 MESSAGE_HTM_PATH 常量(后台专用消息模板路径)
├── 定义 SKIP_ROUTE = TRUE(跳过前台路由)
├── include '../index.php'(复用前台初始化:数据库连接、缓存、全局变量等)
├── 加载后台语言包(lang/zh-cn/bbs_admin.php)
├── 加载 admin.func.php(后台专用函数)
├── 加载 menu.conf.php(后台菜单配置)
└── 加载 index.inc.php(权限检查 + 路由分发)
```
关键点在于 `SKIP_ROUTE = TRUE`。这个常量告诉前台的 `index.inc.php`:"不要执行前台的路由逻辑,我只是借用你的初始化能力"。这样后台就自动拥有了 `$db`、`$cache`、`$conf`、`$user`、`$gid` 等全局变量,而无需重复编写数据库连接和缓存初始化代码。
### 2.2 权限检查 admin/index.inc.php
初始化完成后,进入 `admin/index.inc.php`,这里执行两项关键的安全检查:
**1. 管理组检查**
```php
if($gid != 1) {
setcookie('bbs_sid', '', $time - 86400);
http_location(url('../user-login'));
}
```
只有 `gid == 1`(管理员组)的用户才能进入后台。非管理员会被直接踢回前台登录页。注意这里的设计哲学:对于越权访问,不需要友好提示,直接重定向——因为越权访问默认被视为黑客企图。
**2. 管理员令牌检查**
```php
admin_token_check();
```
即使你是管理员,也必须持有有效的 `bbs_admin_token` 令牌。这个令牌机制是后台安全的第二道防线,我们将在下一节详细讲解。
> **注意**:当 `DEBUG >= 3` 时(本地调试模式),这两项检查都会被跳过,方便开发者在本地调试后台功能。
### 2.3 路由分发
权限检查通过后,`admin/index.inc.php` 通过 `switch-case` 将请求分发到对应的路由文件:
```php
$route = param(0, 'index');
switch ($route) {
case 'index': include _include(ADMIN_PATH.'route/index.php'); break;
case 'setting': include _include(ADMIN_PATH.'route/setting.php'); break;
case 'forum': include _include(ADMIN_PATH.'route/forum.php'); break;
case 'group': include _include(ADMIN_PATH.'route/group.php'); break;
case 'other': include _include(ADMIN_PATH.'route/other.php'); break;
case 'user': include _include(ADMIN_PATH.'route/user.php'); break;
case 'thread': include _include(ADMIN_PATH.'route/thread.php'); break;
case 'plugin': include _include(ADMIN_PATH.'route/plugin.php'); break;
default: include _include(ADMIN_PATH.'route/index.php'); break;
}
```
URL 格式遵循 Xiuno BBS 的统一规则:`admin/?route-action-param1-param2.htm`。例如:
| URL | 路由文件 | 功能 |
|-----|---------|------|
| `admin/?setting-base.htm` | route/setting.php | 基本设置 |
| `admin/?forum-list.htm` | route/forum.php | 版块列表 |
| `admin/?user-list-username-张三-1.htm` | route/user.php | 搜索用户"张三" |
| `admin/?plugin-install-xn_qq_login.htm` | route/plugin.php | 安装插件 |
每个路由文件内部再通过 `param(1)` 获取 `$action` 参数,进一步细分到具体的操作(列表、编辑、删除等)。
> **插件扩展点**:路由分发的 `switch-case` 中预留了 `admin_index_route_case_start`、`admin_index_route_case_end`、`admin_index_route_case_default` 三个 Hook 点,插件可以通过它们添加自定义的后台路由。
---
## 三、安全机制:管理员令牌系统
后台的安全是重中之重。Xiuno BBS 采用了「二次验证 + 令牌轮换」的双重安全机制,定义在 `admin/admin.func.php` 中。
### 3.1 登录验证(二次密码)
管理员即使已经登录了前台,进入后台时仍需要再次输入密码:
```php
if(md5($password.$user['salt']) != $user['password']) {
xn_log('password error. uid:'.$user['uid'], 'admin_login_error');
message('password', lang('password_incorrect'));
}
admin_token_set();
```
密码验证通过后,调用 `admin_token_set()` 生成并设置管理员令牌。
### 3.2 令牌的生成与验证
令牌的生成逻辑:
```php
function admin_token_set() {
$key = md5((XN_ADMIN_BIND_IP ? $longip : '').$useragent_md5.xn_key());
$s = "$longip\t$time";
$admin_token = xn_encrypt($s, $key);
setcookie('bbs_admin_token', $admin_token, $time + 3600, '', '', 0, TRUE);
}
```
令牌的组成要素:
| 要素 | 说明 |
|------|------|
| IP 地址 | 可选,取决于 `admin_bind_ip` 配置 |
| User-Agent 的 MD5 | 防止令牌被跨浏览器使用 |
| xn_key() | 站点唯一密钥,基于 `auth_key` 生成 |
| 时间戳 | 用于判断令牌是否过期 |
令牌的验证逻辑:
```php
function admin_token_check() {
$admin_token = param('bbs_admin_token');
if(empty($admin_token)) {
// 没有令牌,跳转到登录页
$_REQUEST[0] = 'index';
$_REQUEST[1] = 'login';
} else {
$s = xn_decrypt($admin_token, $key);
// 解密失败 → 令牌无效
if(empty($s)) { /* 清除令牌,报错 */ }
// 超过 3600 秒 → 令牌过期
if($time - $_time > 3600) { /* 清除令牌,报错 */ }
// 超过 1800 秒 → 自动续期
if($time - $_time > 1800) { admin_token_set(); }
}
}
```
这套机制的核心设计:
- **1 小时强制过期**:后台操作超过 1 小时未活动,自动退出,需要重新输入密码
- **半小时自动续期**:只要在半小时内有操作,令牌就会自动续期,避免频繁重新登录
- **IP 绑定(可选)**:通过 `conf.php` 中的 `admin_bind_ip` 配置,可以要求令牌必须从同一 IP 使用
- **HttpOnly Cookie**:令牌 Cookie 设置了 `httponly = TRUE`,JavaScript 无法读取,防止 XSS 窃取
### 3.3 退出登录
```php
admin_token_clean(); // 清除令牌 Cookie
message(0, jump(lang('logout_successfully'), './'));
```
---
## 四、菜单系统
后台的导航菜单定义在 `admin/menu.conf.php` 中,采用数组配置的方式,结构清晰:
```php
return array(
'setting' => array(
'url' => url('setting-base'),
'text' => lang('setting'), // "设置"
'icon' => 'icon-cog',
'tab' => array(
'base' => array('url'=>url('setting-base'), 'text'=>lang('admin_setting_base')),
'smtp' => array('url'=>url('setting-smtp'), 'text'=>lang('admin_setting_smtp')),
)
),
'forum' => array( ... ),
'thread' => array( ... ),
'user' => array( ... ),
'other' => array( ... ),
'plugin' => array( ... ),
);
```
### 菜单层级结构
后台菜单分为两级:
**一级菜单(导航栏)**:显示在页面顶部的导航栏中,每个一级菜单项包含 `url`、`text`、`icon` 三个属性。
**二级菜单(Tab 切换)**:部分一级菜单下有 `tab` 子数组,在页面内容区顶部以按钮组的形式展示,用于在同一模块内切换不同的功能页面。
| 一级菜单 | 图标 | 二级 Tab | 说明 |
|---------|------|---------|------|
| 设置 | icon-cog | 基本设置 / SMTP 设置 | 站点全局配置 |
| 版块 | icon-comment | (无) | 版块管理,直接进入版块列表 |
| 主题 | icon-comment | 主题批量管理 | 主题搜索与批量操作 |
| 用户 | icon-user | 用户列表 / 用户组 / 创建用户 | 用户与用户组管理 |
| 其他 | icon-wrench | 清理缓存 | 系统维护工具 |
| 插件 | icon-cogs | 本地插件 | 插件管理 |
导航栏的渲染在 `admin/view/htm/header_nav.inc.htm` 中完成:
```php
后台
$v) { ?>
```
Tab 的渲染使用 `admin_tab_active()` 辅助函数,生成 Bootstrap 风格的按钮组:
```php
function admin_tab_active($arr, $active) {
$s = '';
foreach ($arr as $k=>$v) {
$s .= ''.$v['text'].'';
}
return $s;
}
```
> **插件扩展**:菜单配置在加载时经过 `_include()` 函数处理,这意味着插件可以通过 Overwrite 机制覆盖 `menu.conf.php`,从而添加自定义的菜单项。同时,`admin_index_menu_after` Hook 点允许插件在菜单加载后动态修改菜单内容。
---
## 五、功能模块详解
### 5.1 后台首页(Dashboard)
**路由**:`admin/?index.htm` 或 `admin/?index-login.htm`
**路由文件**:`admin/route/index.php`
**视图文件**:`admin/view/htm/index.htm`、`admin/view/htm/index_login.htm`
后台首页是管理员进入后台后看到的第一个页面,展示站点运行状态和服务器信息。
#### 5.1.1 登录页面
当管理员首次进入后台或令牌过期时,会显示登录页面。登录页面设计简洁——只有一个密码输入框:
```
┌─────────────────────────────┐
│ 管理登陆 │
│ │
│ 为了您的安全,请再次输入 │
│ 账户密码: │
│ ┌───────────────────────┐ │
│ │ 🔒 [密码输入框] │ │
│ └───────────────────────┘ │
│ ┌───────────────────────┐ │
│ │ 登 录 │ │
│ └───────────────────────┘ │
└─────────────────────────────┘
```
密码在前端通过 MD5 加密后传输(`postdata.password = $.md5(postdata.password)`),服务端再与数据库中的密码比对。
#### 5.1.2 首页信息展示
登录成功后,首页展示三个信息卡片:
**卡片一:站点统计信息**
| 统计项 | 数据来源 |
|--------|---------|
| 主题数 | `thread_count()` |
| 回帖数 | `post_count()` |
| 用户数 | `user_count()` |
| 附件数 | `attach_count()` |
| 磁盘剩余空间 | `disk_free_space()` |
| 在线人数 | `$runtime['onlines']` |
**卡片二:服务器信息**
| 信息项 | 获取方式 |
|--------|---------|
| 操作系统 | `PHP_OS` |
| Web Server | `$_SERVER['SERVER_SOFTWARE']` |
| PHP 版本 | `PHP_VERSION` |
| 数据库版本 | `$db->version()` |
| POST 最大值 | `ini_get('post_max_size')` |
| 上传最大值 | `ini_get('upload_max_filesize')` |
| 内存限制 | `ini_get('memory_limit')` |
| 客户端/服务端 IP | `$_SERVER['REMOTE_ADDR']` / `$_SERVER['SERVER_ADDR']` |
还提供了一个 `[PHPINFO]` 链接,可以直接查看完整的 PHP 配置信息。
**卡片三:开发团队信息**
展示 Xiuno BBS 的官方站点、GitHub 仓库和致谢信息。
> **版本检查**:首页底部会调用 `get_last_version()` 函数,每 24 小时向官方服务器检查一次是否有新版本可用。
---
### 5.2 站点设置
**路由**:`admin/?setting-base.htm`、`admin/?setting-smtp.htm`
**路由文件**:`admin/route/setting.php`
**视图文件**:`admin/view/htm/setting_base.htm`、`admin/view/htm/setting_smtp.htm`
站点设置分为两个 Tab:基本设置和 SMTP 设置。
#### 5.2.1 基本设置
基本设置页面允许管理员配置站点的核心参数,所有配置项都保存在 `conf/conf.php` 文件中:
| 配置项 | 字段名 | 类型 | 说明 |
|--------|--------|------|------|
| 站点名称 | `sitename` | 文本 | 显示在浏览器标题栏和首页 |
| 站点介绍 | `sitebrief` | 文本域 | 支持 HTML,显示在首页底部 |
| 站点访问限制 | `runlevel` | 单选 | 0-5 共 6 个等级 |
| 开启用户注册 | `user_create_on` | 是/否 | 控制是否允许新用户注册 |
| 开启注册邮箱验证 | `user_create_email_on` | 是/否 | 注册时是否需要邮箱验证 |
| 开启找回密码 | `user_resetpw_on` | 是/否 | 是否允许用户通过邮箱找回密码 |
| 语言 | `lang` | 下拉 | zh-cn / zh-tw / en-us / ru-ru / th-th |
| 开启伪静态 | `url_rewrite_on` | 是/否 | URL 美化,需配合服务器配置 |
| 开启CDN | `cdn_on` | 是/否 | 静态资源是否使用 CDN |
| 主题列表每页条数 | `pagesize` | 数字 | 主题列表的分页大小 |
| 回复列表每页条数 | `postlist_pagesize` | 数字 | 回复列表的分页大小 |
**运行级别(runlevel)详解**:
| 级别 | 含义 |
|------|------|
| 0 | 完全关闭,只有管理员可以访问 |
| 1 | 仅管理员可访问 |
| 2 | 仅登录用户可访问 |
| 3 | 仅登录用户可发帖 |
| 4 | 仅注册用户可发帖 |
| 5 | 完全开放 |
**配置保存机制**:
设置保存使用 `file_replace_var()` 函数,这个函数会读取 `conf/conf.php` 文件,替换其中对应的变量值,然后写回文件。这是一种非常轻量的配置管理方式——不需要数据库,直接操作 PHP 文件。
```php
$replace = array(
'sitename' => $sitename,
'sitebrief' => $sitebrief,
'runlevel' => $runlevel,
// ...
);
file_replace_var(APP_PATH.'conf/conf.php', $replace);
```
#### 5.2.2 SMTP 设置
SMTP 设置页面管理邮件发送服务器的配置,用于用户注册验证和密码找回功能。配置保存在 `conf/smtp.conf.php` 中,以数组形式存储:
```php
return array(
0 => array(
'email' => 'noreply@example.com',
'host' => 'smtp.example.com',
'port' => 465,
'user' => 'noreply@example.com',
'pass' => 'password',
),
// 可以配置多个 SMTP 服务器
);
```
页面采用动态表格的形式,支持添加和删除 SMTP 服务器条目。每个条目包含邮箱地址、SMTP 主机、端口、用户名和密码五个字段。
---
### 5.3 版块管理
**路由**:`admin/?forum-list.htm`、`admin/?forum-update-{fid}.htm`、`admin/?forum-delete-{fid}.htm`
**路由文件**:`admin/route/forum.php`
**视图文件**:`admin/view/htm/forum_list.htm`、`admin/view/htm/forum_update.htm`
版块管理是后台最核心的功能之一,负责论坛版块的增删改查和权限配置。
#### 5.3.1 版块列表
版块列表页面以表格形式展示所有版块,支持内联编辑:
```
┌──────┬──────┬──────────┬────────┬──────┬──────┬──────┐
│ 版块ID│ 图标 │ 上传图标 │ 名称 │ 排序 │ 编辑 │ 删除 │
├──────┼──────┼──────────┼────────┼──────┼──────┼──────┤
│ 1 │ 📁 │ [选择文件]│ 默认版块│ 0 │ 编辑 │ 删除 │
│ 2 │ 📁 │ [选择文件]│ 技术交流│ 1 │ 编辑 │ 删除 │
└──────┴──────┴──────────┴────────┴──────┴──────┴──────┘
[+ 增加一行]
[确认提交]
```
**关键设计特点**:
1. **批量编辑模式**:所有版块信息在同一张表单中,修改后一次性提交保存。新增版块通过点击「增加一行」按钮,克隆最后一行并清空值。
2. **图标上传**:版块图标采用 Base64 编码方式上传。前端使用 `jform.base64_encode_file()` 将文件转为 Base64 字符串,后端解码后保存为 `upload/forum/{fid}.png`。
3. **系统保留版块**:`fid = 1` 的版块是系统保留版块,不允许删除。代码中通过 `$system_forum = array(1)` 来标记。
4. **安全删除检查**:删除版块前会检查该版块下是否还有主题,以及是否存在子版块。只有清空主题和子版块后才能删除。
5. **缓存更新**:每次版块变更后,都会调用 `forum_list_cache_delete()` 清除版块列表缓存,确保前台显示的数据是最新的。
#### 5.3.2 版块编辑
点击版块列表中的「编辑」按钮,进入版块详情编辑页面:
| 字段 | 类型 | 说明 |
|------|------|------|
| 版块名称 | 文本 | 版块的显示名称 |
| 排序 | 数字 | 显示顺序,数字越大越靠前 |
| 简介 | 文本域 | 版块简介,支持 HTML |
| 公告 | 文本域 | 版块公告,支持 HTML |
| 版主 | 文本 | 逗号分隔的用户名,最多 10 个 |
| 用户权限 | 复选框组 | 是否开启权限控制 |
**版块权限控制**:
当「用户权限」开关打开时,会展开一个权限矩阵表格,为每个用户组设置该版块的访问权限:
```
┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ 全选 │ 用户组 │ 允许看帖 │ 发主题 │ 回帖 │ 上传/下载 │
├──────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ ☐ │ 管理员组 │ ☑☑☑☑☑ │ ☑☑☑☑☑ │ ☑☑☑☑☑ │ ☑☑☑☑☑ │
│ ☐ │ 超级版主 │ ☑☑☑☑☑ │ ☑☑☑☑☑ │ ☑☑☑☑☑ │ ☑☑☑☑☑ │
│ ☐ │ 会员 │ ☑☑☐☑☑ │ ☑☐☑☑☑ │ ☑☐☑☑☑ │ ☑☐☑☑☑ │
└──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘
```
权限数据存储在 `bbs_forum_access` 表中,以 `(fid, gid)` 为联合主键。当 `accesson = 0` 时,该版块使用用户组的默认权限;当 `accesson = 1` 时,使用 `bbs_forum_access` 表中的自定义权限。
**版主设置**:版主通过用户名输入,后端使用 `user_names_to_ids()` 函数将用户名转换为 UID 存储在 `moduids` 字段中。
---
### 5.4 主题批量管理
**路由**:`admin/?thread-list.htm`、`admin/?thread-scan.htm`、`admin/?thread-operation-{op}.htm`、`admin/?thread-found-{page}.htm`
**路由文件**:`admin/route/thread.php`
**视图文件**:`admin/view/htm/thread_list.htm`、`admin/view/htm/thread_found.htm`
主题批量管理是后台中技术实现最复杂的模块,它采用了一种「扫描-收集-操作」的三阶段架构来处理大量主题的批量操作。
#### 5.4.1 三阶段架构
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 阶段一 │ │ 阶段二 │ │ 阶段三 │
│ 扫描 │ ──→ │ 查看 │ ──→ │ 操作 │
│ (scan) │ │ (found) │ │ (operation) │
│ │ │ │ │ │
│ 按条件搜索 │ │ 分页查看 │ │ 批量删除/ │
│ 全表主题 │ │ 搜索结果 │ │ 关闭/打开 │
└─────────────┘ └─────────────┘ └─────────────┘
↓ ↓ ↓
符合条件的 tid 从队列中读取 tid 逐批操作 tid
存入 Session 队列 展示主题列表 返回操作结果
```
**为什么需要这种架构?**
论坛的主题数量可能非常大(数十万甚至百万级),直接一次性查询和操作会导致内存溢出或超时。三阶段架构将大任务拆分为小批次,每次只处理 100 条记录,通过 AJAX 逐页扫描,前端显示进度条。
#### 5.4.2 搜索条件
管理员可以设置以下搜索条件来筛选主题:
| 条件 | 参数名 | 说明 |
|------|--------|------|
| 版块 | `fid` | 按版块筛选,0 表示所有版块 |
| 关键词 | `keyword` | 模糊匹配主题标题 |
| 开始时间 | `create_date_start` | 主题创建时间的起始 |
| 结束时间 | `create_date_end` | 主题创建时间的截止 |
| 发帖 IP | `userip` | 精确匹配发帖者 IP |
| UID/用户名 | `uid` | 按用户筛选,支持用户名自动转 UID |
搜索过程是 AJAX 驱动的:前端逐页发送请求,后端每页扫描 100 条记录,将符合条件的 `tid` 存入 Session 队列,同时返回本页找到的 `tid` 数组。前端汇总显示进度。
#### 5.4.3 批量操作
搜索完成后,管理员可以对搜索结果执行三种操作:
| 操作 | URL | 效果 |
|------|-----|------|
| 关闭 | `thread-operation-close` | 将主题标记为关闭,禁止回帖和编辑 |
| 打开 | `thread-operation-open` | 将关闭的主题重新打开 |
| 删除 | `thread-operation-delete` | 彻底删除主题及其所有回帖和附件 |
操作也是分批执行的,每次从 Session 队列中弹出 100 个 `tid` 逐个处理,前端显示操作进度。
#### 5.4.4 查看搜索结果
点击「点击查看」链接,可以在新页面中分页浏览搜索到的主题列表。这个页面复用了前台的 `thread_list.inc.htm` 模板来渲染主题列表。
---
### 5.5 用户管理
**路由**:`admin/?user-list.htm`、`admin/?user-create.htm`、`admin/?user-update-{uid}.htm`、`admin/?user-delete.htm`
**路由文件**:`admin/route/user.php`
**视图文件**:`admin/view/htm/user_list.htm`、`admin/view/htm/user_create.htm`、`admin/view/htm/user_update.htm`
用户管理模块提供用户列表、搜索、创建、编辑和删除功能。
#### 5.5.1 用户列表与搜索
用户列表页面顶部有搜索栏,支持以下搜索维度:
| 搜索类型 | 说明 |
|---------|------|
| UID | 精确匹配用户 ID |
| 用户名 | 精确匹配用户名 |
| 邮箱 | 精确匹配邮箱 |
| 用户组 | 按用户组 ID 筛选 |
| 注册 IP | 精确匹配注册时的 IP 地址 |
搜索结果以表格形式展示,每页 20 条记录,包含用户 ID、邮箱、用户名、用户组、注册时间、注册 IP 等信息。注册 IP 显示为可点击链接,点击后跳转到 IP 查询页面。
列表中每行有一个复选框,勾选后可以批量删除用户。但管理员账户(gid == 1)不允许直接删除。
#### 5.5.2 创建用户
管理员可以在后台直接创建新用户,需要填写:
| 字段 | 验证规则 |
|------|---------|
| 邮箱 | 必填,格式验证,唯一性检查 |
| 用户名 | 必填,格式验证,唯一性检查 |
| 密码 | 必填 |
| 用户组 | 下拉选择,从 `bbs_group` 表获取 |
密码存储采用双重 MD5 加盐:`md5(md5($password).$salt)`,其中 `$salt` 是 16 位随机字符串。
#### 5.5.3 编辑用户
编辑用户页面与创建用户类似,但密码字段为空表示不修改密码。编辑时会进行差异比较(`array_diff_value()`),只有实际发生变化的字段才会被更新,减少不必要的数据库写入。
---
### 5.6 用户组管理
**路由**:`admin/?group-list.htm`、`admin/?group-update-{gid}.htm`
**路由文件**:`admin/route/group.php`
**视图文件**:`admin/view/htm/group_list.htm`、`admin/view/htm/group_update.htm`
用户组管理虽然从 URL 上看属于 `group` 路由,但在菜单系统中被归入「用户」菜单下,作为其二级 Tab 之一。
#### 5.6.1 用户组列表
与版块列表类似,用户组列表也采用表格内联编辑的模式:
```
┌──────────┬──────────┬──────────┬──────────┬──────┬──────┐
│ 用户组ID │ 用户组名 │ 起始积分 │ 结束积分 │ 编辑 │ 删除 │
├──────────┼──────────┼──────────┼──────────┼──────┼──────┤
│ 0 │ 游客组 │ 0 │ 0 │ 编辑 │ - │
│ 1 │ 管理员组 │ 0 │ 0 │ 编辑 │ - │
│ 2 │ 超级版主 │ 0 │ 0 │ 编辑 │ - │
│ 101 │ 会员 │ 0 │ 99999 │ 编辑 │ 删除 │
└──────────┴──────────┴──────────┴──────────┴──────┴──────┘
```
系统预设了 8 个不可删除的用户组(gid: 0, 1, 2, 3, 4, 5, 6, 7, 101),它们是系统正常运行的基础。管理员可以添加自定义用户组(gid >= 102)。
#### 5.6.2 用户组权限编辑
用户组编辑页面包含两组权限:
**基础权限(所有用户组都有)**:
| 权限 | 字段 | 说明 |
|------|------|------|
| 允许访问 | `allowread` | 是否可以浏览论坛 |
| 发主题 | `allowthread` | 是否可以发布主题 |
| 回帖 | `allowpost` | 是否可以回复主题 |
| 上传附件 | `allowattach` | 是否可以上传附件 |
| 下载附件 | `allowdown` | 是否可以下载附件 |
**管理权限(仅 gid 1-5 的管理组有)**:
| 权限 | 字段 | 说明 |
|------|------|------|
| 置顶 | `allowtop` | 是否可以置顶主题 |
| 编辑 | `allowupdate` | 是否可以编辑他人帖子 |
| 删除 | `allowdelete` | 是否可以删除他人帖子 |
| 移动 | `allowmove` | 是否可以移动主题到其他版块 |
| 禁止用户 | `allowbanuser` | 是否可以封禁用户 |
| 删除用户 | `allowdeleteuser` | 是否可以删除用户 |
| 查看用户信息 | `allowviewip` | 是否可以查看用户的 IP 等敏感信息 |
> **权限系统的局限**:Xiuno BBS 的用户权限系统相对简单,只有全局级别的用户组权限和版块级别的访问权限两层。没有细粒度的权限控制(如按版块设置管理权限),这也是为什么很多插件需要自行实现权限管理的原因。
---
### 5.7 其他管理(清理缓存)
**路由**:`admin/?other-cache.htm`
**路由文件**:`admin/route/other.php`
**视图文件**:`admin/view/htm/other_cache.htm`
「其他管理」模块目前只有一个功能:清理缓存。提供两个选项:
| 选项 | 操作 | 说明 |
|------|------|------|
| 清理临时目录 | `rmdir_recusive($conf['tmp_path'], 1)` | 清空 `tmp/` 目录下的临时文件 |
| 清理缓存 | `cache_truncate()` | 清空所有缓存数据 |
缓存清理后,`$runtime` 变量也会被置空,确保下次请求时重新从数据库加载最新的运行时数据。
> **插件扩展**:`other` 路由预留了多个 Hook 点,插件可以在此模块下添加自己的维护工具页面。
---
### 5.8 插件管理
**路由**:`admin/?plugin-local.htm`、`admin/?plugin-read-{dir}.htm`、`admin/?plugin-install-{dir}.htm` 等
**路由文件**:`admin/route/plugin.php`
**视图文件**:`admin/view/htm/plugin_list.htm`、`admin/view/htm/plugin_read.htm`
插件管理是后台中最复杂的模块,涉及插件的下载、安装、启用、禁用、卸载、升级等完整生命周期管理。
#### 5.8.1 插件生命周期
```
下载 ──→ 安装 ──→ 启用 ←──→ 禁用 ──→ 卸载
↑ │
└────── 升级 ────────┘
```
| 操作 | URL 格式 | 说明 |
|------|---------|------|
| 本地列表 | `plugin-local` | 查看已下载的插件 |
| 插件详情 | `plugin-read-{dir}` | 查看插件信息和操作按钮 |
| 下载 | `plugin-download-{dir}` | 从官方服务器下载插件 |
| 安装 | `plugin-install-{dir}` | 安装插件(执行 Hook 注册等) |
| 启用 | `plugin-enable-{dir}` | 启用已安装的插件 |
| 禁用 | `plugin-disable-{dir}` | 禁用已启用的插件 |
| 卸载 | `plugin-unstall-{dir}` | 卸载插件(清理 Hook 注册等) |
| 升级 | `plugin-upgrade-{dir}` | 升级到新版本 |
| 设置 | `plugin-setting-{dir}` | 打开插件的设置页面 |
#### 5.8.2 插件列表
插件列表页面展示所有插件,每个插件显示图标、名称、版本号、目录名、作者、价格、简介以及操作按钮。操作按钮根据插件状态动态显示:
| 插件状态 | 可用操作 |
|---------|---------|
| 已下载未安装 | 安装 |
| 已安装已启用 | 设置 / 禁用 / 卸载 |
| 已安装已禁用 | 启用 / 卸载 |
| 有新版本 | 更新 |
#### 5.8.3 插件安装流程
安装一个插件涉及以下步骤:
1. **插件锁检查**:`plugin_lock_start()` 确保同一时间只有一个插件任务在执行
2. **存在性检查**:`plugin_check_exists($dir)` 确认插件目录存在
3. **依赖检查**:`plugin_check_dependency($dir, 'install')` 检查该插件依赖的其他插件是否已安装
4. **执行安装**:`plugin_install($dir)` 注册 Hook 点、Overwrite 文件等
5. **执行安装脚本**:如果插件有 `install.php`,则执行它(用于创建数据表等)
6. **同类插件互斥**:自动卸载同类型的已安装插件(例如安装新主题时自动卸载旧主题)
7. **释放插件锁**:`plugin_lock_end()`
#### 5.8.4 付费插件购买流程
对于收费插件,系统集成了微信扫码支付流程:
1. 管理员点击「购买」按钮,进入插件详情页
2. 页面显示微信支付二维码
3. 前端每 5 秒轮询 `plugin-is_bought` 接口检查是否支付成功
4. 支付成功后自动跳转到下载页面
#### 5.8.5 插件依赖管理
Xiuno BBS 的插件系统支持依赖关系声明。安装时检查前置依赖,卸载时检查反向依赖:
- **安装时**:如果插件 A 依赖插件 B,而插件 B 未安装,则安装会被拒绝,并提示需要先安装依赖
- **卸载时**:如果插件 A 被插件 B 依赖,则卸载插件 A 会被拒绝,并提示有其他插件依赖它
---
## 六、视图层架构
后台的视图层采用 PHP 原生模板,基于 Bootstrap 4 构建,结构清晰。
### 6.1 模板组织
```
admin/view/htm/
├── header.inc.htm ← 全局头部(HTML + 导航栏 + 开始)
├── header_nav.inc.htm ← 导航栏组件
├── footer.inc.htm ← 全局底部( + 页脚 + JS 引用 + )
├── message.htm ← 消息提示页
├── index.htm ← 后台首页
├── index_login.htm ← 登录页
├── setting_base.htm ← 基本设置
├── setting_smtp.htm ← SMTP 设置
├── forum_list.htm ← 版块列表
├── forum_update.htm ← 版块编辑
├── thread_list.htm ← 主题批量管理
├── thread_found.htm ← 搜索结果
├── user_list.htm ← 用户列表
├── user_create.htm ← 创建用户
├── user_update.htm ← 编辑用户
├── group_list.htm ← 用户组列表
├── group_update.htm ← 用户组编辑
├── other_cache.htm ← 清理缓存
├── plugin_list.htm ← 插件列表
└── plugin_read.htm ← 插件详情
```
每个页面模板都遵循相同的结构:
```php
```
### 6.2 前端技术栈
| 技术 | 用途 |
|------|------|
| Bootstrap 4 | UI 框架,提供栅格、卡片、表单、按钮等组件 |
| jQuery 3.5.1 | DOM 操作和 AJAX 请求 |
| Popper.js | Bootstrap 的定位引擎 |
| xiuno.min.js | Xiuno 自定义的 jQuery 扩展(表单序列化、AJAX 封装等) |
| bootstrap-plugin.min.js | Bootstrap 插件增强 |
| async.min.js | 异步流程控制(用于主题批量操作的逐页扫描) |
| form.js | 表单处理(Base64 文件编码、表单重置等) |
| md5.js | 前端密码 MD5 加密(仅登录页使用) |
| jquery.qrcode.min.js | 二维码生成(仅插件购买页使用) |
### 6.3 AJAX 交互模式
后台几乎所有的表单提交都使用 AJAX,遵循统一的交互模式:
```javascript
jform.on('submit', function() {
jform.reset(); // 清除之前的错误提示
jsubmit.button('loading'); // 按钮显示"提交中..."
var postdata = jform.serialize(); // 序列化表单数据
$.xpost(jform.attr('action'), postdata, function(code, message) {
if(code == 0) {
$.alert(message); // 成功提示
jsubmit.text(message).delay(3000).location(); // 延迟跳转
} else {
alert(message); // 错误提示
jsubmit.button('reset'); // 重置按钮
}
});
return false;
});
```
`$.xpost()` 是 Xiuno 封装的 AJAX POST 方法,它会自动处理 CSRF 令牌和 JSON 响应解析。
### 6.4 导航栏高亮
每个页面在底部的 `