本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:7月5日复制的资料/项目架构文档.md。
SoSite 项目架构文档
生成日期:2026-07-02
版本:V3.8.0
项目定位:轻量级 PHP 论坛系统(MVC 架构)
一、目录结构总览
D:\phpstudy_pro\WWW\
├── index.php # 前端控制器(路由入口)
├── config.php # 系统配置(数据库/Session/安全)
├── install_user_groups.php # 用户组权限迁移脚本
├── .htaccess # Apache URL 重写 + 安全规则
│
├── app/ # ★ 核心应用代码
│ ├── init.php # 初始化(自动加载/插件/维护模式)
│ ├── Core/ # 框架核心
│ ├── Controllers/ # 控制器层
│ │ ├── Admin/ # 后台控制器
│ │ └── ... # 前台控制器
│ ├── Models/ # 模型层
│ ├── Helpers/ # 工具类(辅助层)
│ └── Views/ # 视图层(模板文件)
│ ├── layouts/ # 布局模板
│ ├── admin/ # 后台视图
│ ├── home/ forum/ post/ thread/ blog/ ... # 前台视图
│ └── plugins/ # 插件视图
│
├── assets/ # 静态资源
│ ├── css/ # 样式文件
│ │ └── themes/ # 配色主题 CSS
│ ├── js/ # JavaScript
│ ├── fonts/ # 字体文件(FontAwesome)
│ ├── img/emoji/qq/ # QQ 表情
│ ├── themes/ # 完整主题(含模板)
│ │ └── xiuno2/ # xiuno2 主题
│ └── uploads/ # 上传文件目录
│
├── plugins/ # 插件系统
│ ├── daily_checkin/ # 每日签到
│ ├── dev_docs/ # 开发文档
│ ├── docs_link/ # 文档链接
│ ├── friend_links/ # 友情链接
│ ├── post_favorite/ # 帖子收藏
│ ├── qa/ # 问答插件
│ └── plugins_cache.php # 插件缓存
│
├── protected/ # ★ 受保护数据(.htaccess 禁止直访)
│ ├── cache/templates/ # 模板编译缓存
│ ├── backups/ # 数据库备份
│ ├── database/ # 数据库相关
│ │ ├── schema.sql # 完整建表 SQL
│ │ └── init.php # 数据库初始化脚本
│ ├── sessions/ # Session 文件存储
│ ├── install.php # 安装脚本
│ ├── rebuild_runtime.php # 运行时重建
│ ├── settings_cache.php # 设置缓存
│ └── .install_done # 安装完成标记
│
├── *.md # 文档文件
│ ├── 安全审查备忘.md
│ ├── 安全修复计划.md
│ ├── 修复完成测试.md
│ ├── 用户组权限计划.md
│ ├── 用户组和板块权限.md
│ ├── 会话总结_20260701.md
│ ├── 项目档案.md
│ ├── 代码审查报告.md
│ ├── forum代码借鉴总结.md
│ └── SQL一致性迁移计划.md
二、架构分层(MVC)
2.1 请求生命周期
浏览器请求
│
▼
.htaccess (URL 重写 → index.php)
│
▼
index.php (前端控制器)
├── require app/init.php ← 自动加载 / Session / 插件 / 维护模式
├── use app\Core\Router ← 路由注册
├── $router->get/post/any() ← 前台 + 后台 + API 路由
├── Plugin::hook('route_register')
├── $router->dispatch() ← 匹配路由 → 调用 Controller::method()
└── Plugin::hook('route_after_dispatch')
2.2 Core 层(框架核心)
| 文件 | 职责 | 关键方法 |
|---|
Autoloader.php | PSR-4 自动加载 | app\ → app/ 目录;Plugin\ → plugins/ 目录 |
Router.php | 路由解析与分发 | get/post/any/group/dispatch;正则匹配 {param} |
Controller.php | 基类控制器 | view() 渲染 + 安全头 + 公共变量注入;redirect() 防开放重定向;requireLogin/requireAdmin |
Database.php | 数据库连接(MySQL 单例) | getInstance/fetchAll/fetchOne/query/begin/commit/rollback |
Model.php | 基础模型(ORM 封装) | find/all/insert/update/delete/count;sanitizeOrderBy 防注入 |
View.php | 视图渲染器(旧版) | display/include/section/yield/e/getData/timeAgo/icon |
TemplateCompiler.php | 模板编译器 | {标签} → PHP;extend() 布局继承;asset() 静态资源路径 |
2.3 Controller 层
前台 Controllers(app/Controllers/)
| Controller | 路由前缀 | 核心功能 |
|---|
HomeController | / | 首页:最新帖子/博客/分类/标签云/统计 |
ForumController | /forum | 论坛首页 + 版块分类页(权限过滤 + 分页) |
ThreadController | /thread/{id} | 帖子详情/编辑/删除/回复提交 |
PostController | /post/new | 发帖/编辑回帖 |
AuthController | /login /register /logout | 登录/注册/退出 |
ProfileController | /profile | 个人中心 |
MessageController | /message | 站内信(收件箱/发件箱/发信) |
BlogController | /blog | 博客系统(列表/详情/创建/编辑/删除) |
SearchController | /search | 全文搜索(FTS) |
TagsController | /tags /tag/{id} | 标签云/标签帖子列表 |
ThemeController | /theme-settings | 前台主题配色设置 |
ApiController | /api | AJAX 接口(投票/上传/远程图片拉取/验证码) |
后台 Controllers(app/Controllers/Admin/)
所有后台 Controller 继承 BaseController,自动拦截非管理员 + 二次验证。
| Controller | 后台路径 | 核心功能 |
|---|
BaseController | — | 权限拦截(isAdmin + 30分钟二次验证) |
DashboardController | /admin | 控制台首页 |
UserController | /admin/users | 用户列表/编辑/删除(含级联删除) |
GroupController | /admin/groups /admin/permissions | 用户组管理 + 版块权限设置 |
ThreadController | /admin/threads | 帖子管理(批量删除) |
CategoryController | /admin/categories | 版块管理 |
BlogController | /admin/blog-manage /admin/blog-categories | 博客管理 + 博客分类 |
TagController | /admin/tags | 标签管理 |
LevelController | /admin/levels | 等级设置 |
SettingsController | /admin/settings | 站点设置 |
DatabaseController | /admin/database | 数据库备份/优化/转换 |
VerifyController | /admin/verify | 二次密码验证 |
MaintenanceController | /admin/maintenance | 维护工具(缓存/统计重建) |
TrashedController | /admin/trashed | 回收站 |
ThemeController | /admin/themes | 主题管理(上传/切换/CSS编辑) |
PluginController | /admin/plugins | 插件管理(启用/禁用/编辑代码) |
2.4 Model 层
| Model | 表 | 额外方法 |
|---|
User | users | create/updateByAdmin/deleteWithCascade/getAdminCount/incrementPostCount |
Thread | threads | getLatest/getLatestAllowed/getByCategoryPaginated/incrementView/incrementReplyCount/softDelete/countByCategory |
Post | posts | getByThread/countByThread/softDelete |
Category | categories | allOrdered/getThreadCountMap/getPostCountMap |
Message | messages | — |
Setting | settings | — |
Tag | tags | — |
Blog | blogs | getLatest |
BlogCategory | blog_categories | — |
BlogComment | blog_comments | — |
所有 Model 继承 app\Core\Model,提供基础的 CRUD + 参数化查询。
2.5 Helper 层(工具类)
| Helper | 作用域 | 核心功能 |
|---|
Auth | 全局 | 登录态判断 (isLoggedIn/isAdmin);getCurrentUser() 带静态缓存;requireAdmin() 带二次验证 |
Permission | 全局 | 用户组/版块权限检查 (canView/canPost/canReply);getAuthorizedCategoryIds() SQL 层过滤 |
Csrf | 全局 | CSRF Token 生成 + 验证 |
Settings | 全局 | 站点设置 CRUD;在线用户/统计/附件管理 |
Upload | API/后台 | 文件上传(白名单后缀 + MIME 校验) |
Search | 前台 | SQLite FTS 全文搜索同步/查询 |
Content | 前台 | 帖子内容 Base64 编解码 + Markdown 渲染 |
Points | 前台 | 积分系统(奖励/扣减/回复可见) |
Vote | 前台 | 点赞/踩(帖子/回复) |
Tag | 前台 | 标签 CRUD + 帖子标签关联 |
Theme | 全局 | 主题切换/自定义 CSS |
Plugin | 全局 | 插件加载 + 钩子系统 |
Captcha | 前台 | 图形验证码 |
Emoji | 前台 | QQ 表情解析 |
RateLimiter | 全局 | 频率限制 |
RememberMe | 全局 | 自动登录(Cookie Token) |
三、路由系统
3.1 路由格式
$router->get('/post/new', [PostController::class, 'create']); // GET
$router->post('/post/new', [PostController::class, 'create']); // POST
$router->any('/blog/{id}', [BlogController::class, 'show']); // GET+POST
$router->group('/admin', function (Router $r) { ... }); // 分组前缀
路由参数 {id} 自动转换为 $id 传入控制器方法。
3.2 URL 重写(.htaccess)
# 安全目录隔离:app/ includes/ database/ protected/ config/ backups/ → 403
# 静态资源直访:assets/ → 200
# 其他请求:重写到 index.php
四、数据库表结构
4.1 核心表(schema.sql)
| 表 | 用途 | 关键字段 |
|---|
users | 用户 | id, username, password, email, role('user'/'admin'), status('active'/'banned'), points, level, group_id, remember_token |
categories | 论坛版块 | id, name, description, sort_order |
threads | 帖子 | id, category_id, user_id, title, content, view_count, reply_count, is_pinned, deleted_at |
posts | 回复 | id, thread_id, user_id, content, deleted_at |
messages | 站内信 | id, sender_id, receiver_id, subject, content, is_read |
tags | 标签 | id, name |
blogs | 博客 | id, user_id, title, content, category_id |
settings | 系统设置 | key, value |
attachments | 附件 | id, post_id, thread_id, filename, original_name |
4.2 权限相关表(install_user_groups.php 创建)
| 表 | 用途 | 关键字段 |
|---|
user_groups | 用户组定义 | id(1=普通会员,2=VIP,3=版主,4=管理员), name, color, is_default |
category_permissions | 版块权限 | id, category_id, group_id(0=游客), can_view, can_post, can_reply |
users 表额外加字段:group_id INT DEFAULT 1(关联 user_groups.id)
五、安全架构
5.1 多层防御
┌──────────────────────────────────────────────┐
│ 1. Apache 层 │
│ .htaccess: 目录隔离 + 文件限制 │
├──────────────────────────────────────────────┤
│ 2. Application 层 │
│ Router: 404 处理 │
│ Controller::view(): 安全头 + CSRF Token │
├──────────────────────────────────────────────┤
│ 3. 后台权限 │
│ BaseController::__construct(): │
│ isAdmin() + 二次密码验证(30min) │
├──────────────────────────────────────────────┤
│ 4. 权限系统 │
│ Permission::check(): group_id → 版块权限 │
│ 管理员组(group_id=4)跳过所有检查 │
├──────────────────────────────────────────────┤
│ 5. 数据层 │
│ PDO 参数化查询(防 SQL 注入) │
│ Upload: 白名单后缀 + MIME 校验 │
│ Csrf::verifyOrDie(): POST 防跨站 │
├──────────────────────────────────────────────┤
│ 6. Session │
│ 文件存储(非默认路径)+ HttpOnly + SameSite│
└──────────────────────────────────────────────┘
5.2 当前防护措施
- ✅ CSRF Token(全局注入 + POST 校验)
- ✅ X-Content-Type-Options / X-Frame-Options / Referrer-Policy
- ✅ HSTS(HTTPS 时启用)
- ✅ 密码 bcrypt 哈希
- ✅ 后台二次密码验证(30 分钟超时)
- ✅ Session 文件隔离(
protected/sessions/) - ✅ 上传白名单 + MIME 二次校验
- ✅ 开放重定向防护(
Controller::redirect()) - ✅ SQL 参数化查询(PDO prepare)
- ✅ 用户组 + 版块权限检查(Permission Helper)
- ✅ Session Cookie: HttpOnly + SameSite=Lax + Secure 自适应
5.3 已知待修复安全隐患
详见 用户组和板块权限.md,关键项:
- role 与 group_id 未强制绑定(越权提权)
- 管理员自降级保护不完整
- PostController POST 未二次校验版块权限
- ThreadController edit/delete 无版块权限校验
- deleteGroup 不重置 users 表产生孤儿用户
- 游客权限回退一刀切问题
六、视图系统
6.1 模板引擎
基于 TemplateCompiler(自定义 PHP 模板引擎):
- 语法:
<?php $this->section('title'); ?>...<?php $this->endSection(); ?> - 布局继承:
$this->extend('main') → 使用 layouts/main.php - 嵌入:
$this->include('admin/_sidebar', [...]) - 变量输出:
$this->e($var)(自动 htmlspecialchars) - 安全:
CSRF_TOKEN 全局注入到 <script>window.CSRF_TOKEN=...
6.2 后台视图侧边栏导航结构
控制台
├── 站点设置
├── 论坛管理
│ ├── 版块管理
│ ├── 版块权限 ← 用户组权限设置
│ ├── 帖子管理
│ ├── 标签管理
│ └── 回收站
├── 博客设置
│ ├── 博客分类
│ └── 博客管理
├── 用户管理
│ ├── 用户列表
│ ├── 用户组 ← 用户组 CRUD
│ └── 等级设置
├── 数据管理
│ ├── 备份优化
│ └── 维护工具
├── 外观管理
│ └── 主题管理
├── 扩展
│ └── 插件管理
└── 返回前台
6.3 主题系统
- 默认视图:
app/Views/ 目录 - 主题覆盖:
assets/themes/{name}/templates/(同名文件覆盖默认视图) - 配色主题:
assets/css/themes/{name}.css(仅覆盖颜色变量) - 当前支持:xiuno2(含完整模板)、slate_pro、baby_blue 等多个配色
七、插件系统
7.1 架构
- 插件目录:
plugins/{plugin_name}/ - 命名空间:
Plugin\{PluginName}\... → Autoloader 自动加载 - 钩子机制:
Plugin::hook('hook_name', [data]) - 启用/禁用:后台管理
7.2 已注册的钩子
| 钩子名 | 触发位置 | 用途 |
|---|
init_after | app/init.php | 初始化后 |
route_register | index.php | 注册额外路由 |
route_before_dispatch | index.php | 分发前拦截 |
route_after_dispatch | index.php | 分发后清理 |
admin_route_register | index.php | 后台额外路由 |
admin_sidebar_links | _sidebar.php | 后台侧边栏链接 |
controller_view_before | Controller::view() | 视图渲染前 |
thread_create_after | PostController::create() | 发帖后 |
post_create_after | ThreadController::show() | 回复后 |
7.3 已安装插件
| 插件 | 功能 |
|---|
| daily_checkin | 每日签到 |
| friend_links | 友情链接 |
| post_favorite | 帖子收藏 |
| qa | 问答系统(问题/回答/标签) |
| dev_docs | 开发文档 |
八、关键数据流
8.1 帖子浏览权限检查路径
用户访问 /forum/category/{id}
│
▼
ForumController::category($id)
├── Permission::canView($id, $userId ?: null)
│ ├── $userId=null → group_id=0(游客)
│ ├── 无游客权限记录 → 回退 group_id=1(普通会员)
│ ├── group_id=4 → 放行(管理员)
│ └── 查 category_permissions → 有记录/无记录处理
│
└── 有权限 → 显示帖子列表
无权限 → 显示错误页面
8.2 发帖流程
用户访问 /post/new
│
▼
PostController::create() GET
├── requireLogin()
├── Permission::canPost() × 所有版块 → 过滤可见版块列表
└── 渲染发帖表单
│
用户 POST 提交
│
▼
PostController::create() POST
├── Csrf::verifyOrDie()
├── 校验分类存在性
├── ⚠️ 缺少 Permission::canPost() 二次校验(已发现的 bug)
└── INSERT thread + tags + attachments + FTS 同步
8.3 后台用户编辑权限变更流
管理员提交编辑用户
│
▼
AdminUserController::index() POST
├── Csrf::verifyOrDie()
├── 校验 role/email/password
├── 唯一管理员保护(role 和 status)
│ ⚠️ 缺少 group_id 保护(已发现的 bug)
└── User::updateByAdmin() → UPDATE users SET role, group_id, ...
九、Session 与认证
9.1 Session 变量
| 键 | 说明 |
|---|
user_id | 用户 ID |
role | 角色(user / admin) |
admin_verified_at | 后台二次验证时间戳 |
admin_redirect_after_verify | 二次验证后重定向地址 |
9.2 认证流程
- 登录:
AuthController::login() → 验证密码 → 设置 Session → RememberMe Cookie(可选) - 自动登录:
Controller::view() 中 RememberMe::check() → 根据 Cookie Token 恢复 Session - 后台验证:
BaseController 构造时检查 admin_verified_at < 30 分钟 → 跳转 /admin/verify - 退出:
AuthController::logout() → 清 Session + 删 Cookie
十、数据库约定
- 引擎:InnoDB(支持事务 + 外键)
- 字符集:utf8mb4 / utf8mb4_unicode_ci
- 外键:threads/posts/messages 的 user_id 指向 users,带 ON DELETE CASCADE
- 软删除:threads/posts 使用
deleted_at DATETIME DEFAULT NULL,非物理删除 - 权限表:
category_permissions 使用 UNIQUE KEY(category_id, group_id) + upsert 模式
十一、配置环境
| 配置项 | 值 |
|---|
| PHP 版本 | 8.2.9 |
| 数据库 | MySQL |
| Web 服务器 | Apache(带 mod_rewrite) |
| 运行环境 | phpStudy Pro (Windows) |
| Session 存储 | 文件(protected/sessions/) |
| 模板缓存 | 文件(protected/cache/templates/) |
| 附件存储 | assets/uploads/ |