文档目录
留言板系统

简介

本文件面向开发者,系统化说明 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
添加日期:2026-10-05