简介
本文件面向开发者,系统化说明 DouPHP 留言板模块的前后台实现与扩展方式。内容覆盖:
- 留言的创建、查询、更新、删除(CRUD)
- 留言审核流程(前台可见性控制、后台已读标记)
- 留言分类管理(当前版本未内置分类字段,提供扩展建议)
- 留言回复功能(主贴与子回复的关系模型)
- GuestbookService 业务逻辑:提交校验、内容过滤、防灌水策略
- 前端交互:显示样式、分页加载、搜索筛选(当前实现与扩展建议)
- 安全与反垃圾:XSS 过滤、验证码、Honeypot、IP 频率限制
- 集成与定制:扩展字段、自定义模板、邮件通知接入
项目结构
留言板模块采用前后端分离的服务层设计:
- 前台控制器负责路由、请求校验、调用服务层并渲染页面
- 前台服务层封装业务规则(列表拼装、插入校验、防灌水、插入数据)
- 后台控制器负责管理操作(列表、阅读、回复、批量动作)
- 后台服务层封装管理业务(分页、已读标记、回复写入、显示切换、批量删除)
- 模型层定义表结构与查询作用域(主贴、可见、回复查找等)
graph TB
FE_Controller["前台控制器<br/>front/controller/guestbook/GuestbookController.php"] --> FE_Service["前台服务<br/>front/service/guestbook/GuestbookService.php"]
FE_Service --> FE_Model["前台模型<br/>front/model/guestbook/Guestbook.php"]
FE_Controller --> FE_View["前台视图<br/>theme/default/guestbook.dwt"]
BE_Controller["后台控制器<br/>admin/controller/guestbook/GuestbookController.php"] --> BE_Service["后台服务<br/>admin/service/guestbook/GuestbookService.php"]
BE_Service --> BE_Model["后台模型<br/>admin/model/guestbook/Guestbook.php"]
BE_Controller --> BE_View["后台视图<br/>admin/view/guestbook.htm"]
图表来源
- front/controller/guestbook/GuestbookController.php:80-143
- front/service/guestbook/GuestbookService.php:38-111
- admin/controller/guestbook/GuestbookController.php:59-137
- admin/service/guestbook/GuestbookService.php:43-170
章节来源
- front/controller/guestbook/GuestbookController.php:80-143
- front/service/guestbook/GuestbookService.php:38-111
- admin/controller/guestbook/GuestbookController.php:59-137
- admin/service/guestbook/GuestbookService.php:43-170
核心组件
- 前台控制器:处理留言列表展示与提交入口,整合 SEO、导航、面包屑、CSRF Token 等
- 前台服务:构建列表数据、校验插入参数、防灌水检查、执行插入并清洗 XSS
- 后台控制器:管理留言列表、阅读页、回复写入、显示隐藏切换、批量删除
- 后台服务:分页查询主贴、读取详情并标记已读、回复写入(XSS 过滤)、切换显示状态、批量删除
- 模型:定义 guestbook 表映射、类型转换、查询作用域(仅主贴、仅可见、默认排序、按父 ID 查回复、按 IP 统计未读主贴数)
章节来源
- front/controller/guestbook/GuestbookController.php:80-143
- front/service/guestbook/GuestbookService.php:38-111
- admin/controller/guestbook/GuestbookController.php:59-137
- admin/service/guestbook/GuestbookService.php:43-170
- admin/model/guestbook/Guestbook.php:27-49
- front/model/guestbook/Guestbook.php:1-200
架构总览
留言系统的核心流程包括:
- 前台提交:表单校验 → 防灌水与验证码 → 业务校验 → 写入数据库 → 返回成功提示
- 前台展示:查询可见主贴 → 分页 → 附带回复内容 → 渲染模板
- 后台管理:列表分页 → 阅读页(标记已读)→ 回复写入 → 显示隐藏切换 → 批量删除
sequenceDiagram
participant U as "用户"
participant FCtrl as "前台控制器"
participant FService as "前台服务"
participant FModel as "前台模型"
participant BService as "后台服务"
participant BModel as "后台模型"
U->>FCtrl : 访问留言列表
FCtrl->>FService : buildListingData(page)
FService->>FModel : whereVisible + whereRoot + applyDefaultOrder + paginate
FModel-->>FService : 分页结果
FService-->>FCtrl : 列表数据+分页
FCtrl-->>U : 渲染 guestbook.dwt
U->>FCtrl : POST 提交留言
FCtrl->>FCtrl : 表单校验/Honeypot/验证码
FCtrl->>FService : validateInsert + isWaterByIp
FService->>FModel : countUnreadRootByIp(ip)
FService-->>FCtrl : 校验结果
FCtrl->>FService : insertRootMessage(data, ip, time)
FService->>FModel : insertRoot(...)
FCtrl-->>U : 成功提示
U->>BService : 后台阅读/回复/切换显示/删除
BService->>BModel : 查询/更新/删除
BModel-->>BService : 结果
BService-->>U : 管理反馈
图表来源
- front/controller/guestbook/GuestbookController.php:80-143
- front/service/guestbook/GuestbookService.php:38-111
- admin/controller/guestbook/GuestbookController.php:59-137
- admin/service/guestbook/GuestbookService.php:43-170
详细组件分析
前台控制器(GuestbookController)
职责:
- 列表页渲染:调用服务获取分页数据,注入 SEO、导航、面包屑、CSRF Token
- 提交处理:表单请求对象校验、Honeypot 与验证码校验、防灌水检查、调用服务插入留言
- 布局变量:统一注入导航与 SEO 信息
关键点:
- 使用 Honeypot 进行反机器人检测
- 根据站点配置决定是否启用验证码
- 基于 IP 的未读主贴数量限制,防止刷屏
章节来源
- front/controller/guestbook/GuestbookController.php:80-143
前台服务(GuestbookService)
职责:
- 列表数据构建:查询可见主贴、分页、附加回复内容与时间
- 防灌水:统计同一 IP 的未读主贴数量,超过阈值拒绝提交
- 插入校验:校验 contact_info 为手机或邮箱之一
- 插入留言:对数据进行 XSS 清洗后写入数据库
关键点:
- 使用 xss()->post() 与 xss()->comment() 进行输入清洗
- 通过模型方法统计未读主贴数,避免重复提交
章节来源
- front/service/guestbook/GuestbookService.php:38-111
前台模型(Guestbook)
职责:
- 定义表名与类型转换
- 提供查询作用域:仅可见、仅主贴、默认排序、按父 ID 查回复、按 IP 统计未读主贴数
关键点:
- whereVisible:仅返回前台可见的留言
- whereRoot:仅返回主贴(reply_id=0)
- findReplyByParentId:根据主贴 ID 查找回复
- countUnreadRootByIp:用于防灌水判断
章节来源
- front/model/guestbook/Guestbook.php:1-200
后台控制器(GuestbookController)
职责:
- 列表页:分页展示主贴,支持翻页
- 阅读页:加载主贴与已有回复,支持 AJAX 标记已读
- 回复:接收表单数据并调用服务写入回复
- 显示切换:切换主贴是否前台显示
- 批量动作:批量删除勾选留言
关键点:
- 将写库操作与 GET 渲染解耦,使用 AJAX 标记已读
- 所有管理操作均记录审计日志
章节来源
- admin/controller/guestbook/GuestbookController.php:59-137
后台服务(GuestbookService)
职责:
- 列表分页:仅主贴,每页 15 条,格式化显示状态与时间
- 阅读页数据:主贴信息与回复内容,格式化时间
- 标记已读:将主贴 if_read 置为 1
- 回复写入:XSS 过滤正文,写入 reply_id 指向主贴的记录
- 显示切换:切换 if_show 并返回状态片段
- 批量删除:使用 IN 条件一次删除多条记录
关键点:
- 使用 xss()->content() 过滤后台回复内容
- 使用审计日志记录管理员操作
章节来源
- admin/service/guestbook/GuestbookService.php:43-170
后台模型(Guestbook)
职责:
- 定义表名与类型转换
- 提供 scopeWhereRoot:仅查询主贴(reply_id=0)
关键点:
- casts 中定义 created_at 为 datetime 格式,便于模板直接输出日期
章节来源
- admin/model/guestbook/Guestbook.php:27-49
表单请求对象(GuestbookInsertFormRequest)
职责:
- 定义前台提交字段的必填与非法字符校验规则
关键点:
- title、contact、content 为必填且不允许非法字符
- contact_info 的“手机或邮箱二选一”校验在服务层完成
章节来源
- _/module/guestbook/front/request/guestbook/GuestbookInsertFormRequest.php:35-42
前端视图与模板
- 前台模板:guestbook.dwt 负责渲染留言列表、分页控件、提交表单
- 后台模板:guestbook.htm 负责管理列表、阅读页、回复表单、批量操作
关键点:
- 前台模板需包含 CSRF Token 与提交地址
- 后台模板需支持 AJAX 标记已读与状态切换
章节来源
- theme/default/guestbook.dwt:1-200
- admin/view/guestbook.htm:1-200
依赖关系分析
- 前台控制器依赖前台服务、验证码、导航、面包屑、SEO 解析器
- 前台服务依赖前台模型、XSS 工具、Check 工具
- 后台控制器依赖后台服务、表单请求对象、审计日志
- 后台服务依赖后台模型、DB、审计日志、XSS 工具
- 模型依赖 ORM Builder/Model 基类与作用域方法
classDiagram
class Front_GuestbookController {
+index(request)
+store(formRequest, request)
+layoutVars()
}
class Front_GuestbookService {
+buildListingData(page)
+validateInsert(post)
+isWaterByIp(ip) bool
+insertRootMessage(data, ip, addTime)
}
class Front_GuestbookModel {
+whereVisible()
+whereRoot()
+applyDefaultOrder()
+paginate(limit, page, route)
+findReplyByParentId(id)
+countUnreadRootByIp(ip) int
}
class Admin_GuestbookController {
+index(request)
+read(request)
+markRead(request)
+reply(formRequest, request)
+showHidden(request)
+action(formRequest)
}
class Admin_GuestbookService {
+buildBookListPaged(page)
+readPageData(id)
+markRead(id)
+reply(data, ip)
+toggleShowHidden(id) string
+action(data)
}
class Admin_GuestbookModel {
+scopeWhereRoot(query)
}
Front_GuestbookController --> Front_GuestbookService : "调用"
Front_GuestbookService --> Front_GuestbookModel : "查询/写入"
Admin_GuestbookController --> Admin_GuestbookService : "调用"
Admin_GuestbookService --> Admin_GuestbookModel : "查询/更新/删除"
图表来源
- front/controller/guestbook/GuestbookController.php:80-143
- front/service/guestbook/GuestbookService.php:38-111
- front/model/guestbook/Guestbook.php:1-200
- admin/controller/guestbook/GuestbookController.php:59-137
- admin/service/guestbook/GuestbookService.php:43-170
- admin/model/guestbook/Guestbook.php:27-49
章节来源
- front/controller/guestbook/GuestbookController.php:80-143
- front/service/guestbook/GuestbookService.php:38-111
- admin/controller/guestbook/GuestbookController.php:59-137
- admin/service/guestbook/GuestbookService.php:43-170
性能考虑
- 列表分页:前台每页 20 条主贴,后台每页 15 条主贴,减少单次查询负载
- 回复查询:在循环内按父 ID 查询回复,注意数据量较大时可考虑批量 JOIN 优化
- 防灌水:基于 IP 的未读主贴计数,避免频繁写入;可结合缓存降低 DB 压力
- XSS 过滤:在服务层集中清洗,避免模板层重复处理
- 审计日志:管理操作记录日志,注意日志表写入性能与归档策略
故障排查指南
常见问题与定位要点:
- 提交失败:检查表单请求对象的必填规则与非法字符校验
- 验证码错误:确认站点配置是否启用验证码,以及验证码会话是否正确
- 防灌水拦截:检查同一 IP 的未读主贴数量是否达到阈值
- 列表为空:确认主贴 if_show 是否为可见状态,以及是否为主贴(reply_id=0)
- 回复未显示:确认回复记录的 reply_id 是否正确指向主贴
- 批量删除无效:检查勾选的 ID 数组是否为空,SQL IN 条件是否有效
章节来源
- _/module/guestbook/front/request/guestbook/GuestbookInsertFormRequest.php:35-42
- front/controller/guestbook/GuestbookController.php:109-143
- front/service/guestbook/GuestbookService.php:71-111
- admin/service/guestbook/GuestbookService.php:145-170
结论
DouPHP 留言板模块通过清晰的前后台分层与服务化设计,实现了安全的留言提交、展示与管理能力。其核心优势包括:
- 严格的数据校验与 XSS 过滤
- 防灌水与验证码机制
- 灵活的分页与回复关联
- 完善的后台管理与审计日志
建议在后续迭代中增强分类管理、搜索筛选、邮件通知与更丰富的反垃圾策略,以提升用户体验与运营效率。
附录
CRUD 操作说明
- 创建:前台提交表单,经校验与清洗后写入主贴记录
- 查询:前台按可见主贴分页查询,附带回复内容;后台按主贴分页查询
- 更新:后台切换显示状态、标记已读、回复写入
- 删除:后台批量删除主贴记录
章节来源
- front/service/guestbook/GuestbookService.php:38-111
- admin/service/guestbook/GuestbookService.php:43-170
留言审核流程
- 前台可见性由 if_show 控制,默认新建主贴可能不可见,需后台切换
- 阅读页加载后通过 AJAX 标记已读,避免 GET 渲染副作用
- 回复写入时进行 XSS 过滤,确保内容安全
章节来源
- admin/service/guestbook/GuestbookService.php:76-137
留言分类管理
- 当前版本未内置分类字段,可在模型中添加 category_id 字段并在查询中增加分类过滤
- 建议在后台添加分类管理界面,并在前台列表页支持按分类筛选
留言回复功能
- 主贴与回复通过 reply_id 关联,主贴 reply_id=0
- 前台列表查询主贴后,按父 ID 查找回复并组装到列表项
- 后台回复写入时设置 reply_id 指向主贴
章节来源
- front/service/guestbook/GuestbookService.php:46-58
- admin/service/guestbook/GuestbookService.php:120-137
前端交互实现
- 显示样式:模板中渲染主贴标题、内容、时间与回复内容
- 分页加载:使用分页器生成链接,支持页码跳转
- 搜索筛选:当前未实现,可在服务层增加搜索条件并在模板中提供搜索表单
章节来源
- theme/default/guestbook.dwt:1-200
开发示例与扩展指南
- 扩展字段:在模型中添加新字段,并在服务层插入/更新逻辑中处理
- 自定义模板:复制 theme/default/guestbook.dwt 到主题目录并修改
- 邮件通知:在服务层插入成功后调用邮件服务发送通知
数据安全与隐私保护
- 输入清洗:使用 xss()->post() 与 xss()->comment() 清洗用户输入
- 验证码:根据站点配置启用验证码,防止自动化提交
- Honeypot:隐藏字段与时序校验,识别机器人行为
- IP 频率限制:基于未读主贴数量限制提交频率
章节来源
- front/controller/guestbook/GuestbookController.php:109-143
- front/service/guestbook/GuestbookService.php:71-111
反垃圾留言策略
- 表单校验:必填字段与非法字符检查
- 验证码:可选启用,提升安全性
- Honeypot:隐藏字段与时序校验
- IP 频率限制:未读主贴数量阈值控制
章节来源
- _/module/guestbook/front/request/guestbook/GuestbookInsertFormRequest.php:35-42
- front/controller/guestbook/GuestbookController.php:109-143
- front/service/guestbook/GuestbookService.php:71-111