简介
本章节面向DouPHP后台的“数据库备份”功能,说明其全量备份的实现原理、分卷导出机制、压缩打包策略、恢复流程、错误处理与审计日志。同时给出存储路径、命名规范、下载方式等运维要点,并明确当前版本对“增量备份”的支持情况与替代方案。
项目结构
备份能力由控制器、服务层、路由与视图共同实现:
- 路由定义:声明 backup 相关接口(备份、导入、下载、删除、恢复列表)。
- 控制器:接收请求参数,调用服务完成具体操作,统一返回消息与跳转。
- 服务:实现表清单构建、SQL 分卷导出、ZIP 打包、导入执行、删除与流式下载、安全校验等。
- 视图:展示可备份的表清单、备份设置(文件名、分卷大小)、恢复文件列表与操作入口。
graph TB
A["浏览器/管理员"] --> B["路由: admin/route/backup.php"]
B --> C["控制器: BackupController"]
C --> D["服务: BackupService"]
D --> E["数据库: DB::query / DB::fnExecute"]
D --> F["文件系统: storage/backup/*"]
D --> G["Zip 工具: Zip::create / Zip::extract"]
核心组件
- 路由组:将 backup 模块下的 index/restore/backup/import/down/destroy 映射到控制器方法。
- 控制器:提供备份首页、执行备份、恢复列表、导入 SQL、删除备份、下载备份等入口。
- 服务:封装备份/恢复的核心逻辑,包括表清单、分卷导出、ZIP 打包、导入执行、删除与下载、安全校验。
- 视图:展示表清单、备份选项、恢复文件列表与操作按钮。
架构总览
备份与恢复的整体交互如下:
sequenceDiagram
participant U as "管理员"
participant R as "路由"
participant C as "BackupController"
participant S as "BackupService"
participant DB as "数据库"
participant FS as "storage/backup"
participant Z as "Zip 工具"
U->>R : 访问备份页面
R->>C : GET /backup/index
C->>S : buildTableList(前缀)
S->>DB : SHOW TABLE STATUS LIKE '前缀%'
DB-->>S : 表清单
S-->>C : 表清单+总大小
C-->>U : 渲染备份表单
U->>R : POST /backup/backup (选择表、文件名、分卷大小)
R->>C : backup()
C->>S : runBackup(前缀, 请求参数)
S->>DB : 逐表导出结构与数据(LIMIT 分页)
DB-->>S : SQL片段
S->>FS : 写入分卷 .sql
alt 需要打包资源
S->>Z : create(zip, [sql..., images])
Z-->>S : 成功/失败
end
S-->>C : 结果(继续/完成)
C-->>U : 提示与跳转(续传或完成)
详细组件分析
备份控制器(BackupController)
- 职责:组织页面变量、转发请求到服务、统一响应消息与跳转。
- 关键流程:
- 备份首页:获取表清单与总大小,生成默认文件名。
- 执行备份:读取请求参数(act、tables、vol_size、filename、asset 等),调用服务执行分卷备份。
- 恢复列表:列出 storage/backup 下的可用备份文件(含多分卷合并显示)。
- 导入 SQL:按 volid 顺序执行分卷导入。
- 删除备份:二次确认后删除主文件及同前缀分卷。
- 下载备份:流式输出二进制内容供浏览器下载。
备份服务(BackupService)
- 表清单构建:查询 INFORMATION_SCHEMA 风格的表状态,统计数据长度与索引长度,计算总大小。
- 分卷导出:
- 以 LIMIT offset, size 的方式分页读取每表数据,拼接 INSERT 语句。
- 当累计 SQL 文本达到分卷阈值时,落盘为分卷文件,并记录下一轮起始行偏移。
- 支持“仅SQL”和“SQL+images资源”两种模式;后者在完成后打包为 ZIP。
- 导入执行:
- 若为 ZIP,先解压至站点根目录,再定位对应 SQL 文件。
- 按 volid 顺序执行分卷 SQL,直至全部导入完成。
- 删除与下载:
- 删除时清理主文件与同前缀分卷,并记录审计日志。
- 下载采用流式读取,避免大文件内存占用。
- 安全校验:
- 严格校验备份文件名,防止目录穿越与非法扩展名。
- 解压 ZIP 时限定白名单条目(仅允许 storage/backup/*.sql 与 images/**),并拒绝危险扩展名。
flowchart TD
Start(["开始"]) --> CheckName["校验备份文件名合法性"]
CheckName --> |非法| Err["抛出异常并返回错误页"]
CheckName --> |合法| LoadTables["加载待备份表清单"]
LoadTables --> LoopTables{"遍历表"}
LoopTables --> Dump["导出表结构+数据(LIMIT分页)"]
Dump --> Accumulate{"累计SQL是否达到分卷阈值?"}
Accumulate --> |是| WriteVol["写入分卷.sql"]
Accumulate --> |否| NextRow["更新startfrom偏移"]
NextRow --> LoopTables
WriteVol --> LoopTables
LoopTables --> |完成| PostProcess{"是否打包资源?"}
PostProcess --> |是| ZipCreate["Zip::create(sqls, images)"]
PostProcess --> |否| Done["完成"]
ZipCreate --> Done
路由与视图
- 路由:将 backup 模块的多个动作映射到控制器方法,支持 GET/ANY/DELETE。
- 视图:
- 备份页:展示表清单、勾选框、分卷大小输入框、文件名输入框,以及“备份”和“备份并打包资源”两个提交入口。
- 恢复页:列出 storage/backup 下的备份文件(含多分卷数量提示)、文件大小、创建时间,并提供还原、下载、删除操作。
依赖关系分析
- 控制器依赖服务:通过构造函数注入 BackupService。
- 服务依赖:
- 数据库:使用 DB 门面进行表清单查询、字符集设置、SQL 执行。
- 文件系统:读写 storage/backup 目录,生成/删除分卷文件。
- Zip 工具:打包 SQL 与 images 目录,或解压 ZIP 包。
- 配置:读取站点前缀、版本等信息用于头部注释。
- 审计:记录备份、恢复、删除操作的审计日志。
classDiagram
class BackupController {
+index()
+backup(request)
+restore()
+import(request)
+destroy(request)
+down(request)
}
class BackupService {
+buildTableList(prefix)
+runBackup(prefix, req)
+runImport(req)
+runDelete(req, post)
+streamDownload(req)
-sqlDumptable(table, vol_size, startfrom, currsize)
-globVolumeFiles(filename, ext)
-isBackupFile(filename)
}
class DB {
+query(sql)
+version()
+charset()
+fnExecute(sql)
}
class Zip {
+create(zipfile, filelist, root_path)
+extract(zipfile, root_path, allow_rules, denied_ext)
}
class FileHelper {
+extension(name)
+filename(name)
+buildFileListByTime(files)
}
class Audit {
+writeAdminLog(admin_id, action, status, msg, tag)
}
BackupController --> BackupService : "调用"
BackupService --> DB : "查询/执行"
BackupService --> Zip : "打包/解压"
BackupService --> FileHelper : "文件信息"
BackupService --> Audit : "写日志"
性能与容量规划
- 分卷大小:默认 2048KB,可根据服务器 PHP 上传限制与磁盘空间调整。服务会参考 upload_max_filesize 做上限保护。
- 内存占用:采用 LIMIT 分页读取数据,避免一次性加载整表。
- I/O 压力:大表导出会产生多次 SELECT 与多次文件写入,建议在低峰期执行。
- 打包体积:选择“包含资源”会额外打包 images 目录,显著增大 ZIP 体积,按需开启。
- 并发控制:建议串行执行备份任务,避免与业务高峰冲突。
故障排查指南
- 无法写入备份目录:检查 storage/backup 是否存在且可写。
- 文件名不合法:确保文件名不含路径分隔符、盘符、空字节与“..”,扩展名必须为 sql 或 zip。
- 导入失败:确认 ZIP 已正确解压,SQL 分卷完整并按序执行;关注 MySQL 严格模式下的零日期与 NULL 值处理。
- 下载异常:检查 Content-Type 与 Content-Length 是否正确设置。
- 审计日志:备份、恢复、删除操作均会写入管理后台审计日志,便于追踪。
结论
DouPHP 的数据库备份功能提供了稳定的全量备份能力,支持分卷导出与可选的资源打包,具备完善的恢复流程与安全校验。对于生产环境,建议结合外部调度器实现定时备份,并配合异地存储策略保障数据安全。当前版本未内置增量备份机制,可通过外部工具或数据库特性实现增量同步。
附录:定时备份与增量备份说明
定时备份(推荐做法)
- 使用系统级任务调度(如 Linux cron)定期触发备份脚本或 HTTP 接口。
- 示例思路:
- 编写一个 CLI 脚本,调用框架入口并访问备份接口,或使用框架提供的命令行能力(如有)。
- 在 cron 中设定周期(例如每日凌晨),并记录执行日志。
- 注意事项:
- 避开业务高峰期。
- 合理设置超时与重试策略。
- 备份完成后清理本地临时分卷文件(服务已完成自动清理)。
增量备份(当前版本说明)
- 当前实现为全量备份:每次备份都会导出所选表的完整结构与数据。
- 如需增量备份,可采用以下替代方案:
- 使用数据库原生工具(如 mysqldump 的 binlog 或 xtrabackup)实现增量/差异备份。
- 基于 binlog 解析变更事件,将增量变更应用到目标库。
- 结合对象存储(如 OSS/S3)保存历史备份,保留策略按天/周/月归档。
备份文件命名规范与存储路径
- 存储路径:storage/backup/
- 命名规则:
- 单卷:文件名.sql
- 多卷:文件名_1.sql、文件名_2.sql……
- 打包资源:文件名.zip(内含所有分卷 SQL 与 images 目录)
- 默认文件名:以日期+时间形式生成,也可手动指定;支持 AUTO 前缀自动命名。
验证备份完整性与可恢复性
- 完整性校验:
- 检查 ZIP 包内是否包含预期数量的 SQL 分卷与 images 目录。
- 校验 SQL 文件头部的版本信息与时间戳是否一致。
- 可恢复性测试:
- 在测试环境导入备份文件,验证表结构与数据是否完整。
- 重点关注日期时间列的 NULL 与零日期处理是否符合预期。
- 回滚预案:
- 恢复前务必备份当前数据库。
- 恢复后核对关键业务数据与关联附件。