文档目录
存储架构设计

引言

本仓库围绕 storage/ 目录进行“三层语义化”重构:将运行时状态、可重建缓存与安装域严格分离,使升级路径、安装流程与应用侧读写点具备一致且可回退的契约。目标不是简单移动文件,而是通过 install/、upgrade/、_update/ 三程序同批同步,确保旧站升级后按新路径运行;同时为 cache/state/install 三类数据建立清晰的职责边界与迁移策略。

项目结构

storage/ 的目标布局由 chat.md 明确定义,核心原则如下:

  • cache/:硬承诺整目录随时可删,访问后自动重建。包含模板编译缓存、JS 世代标记、路由清单、云连通检查与更新数节流等。
  • state/:运行时状态,删除有后果,任何清理永不碰。包含安装锁、后台快捷入口、对账锁、限流计数器等。
  • install/:安装域,输入(package)→ 过程(session)→ 产出(records)。模块包下载解压工作区、云安装会话、已安装模块清单均归位于此。
  • watermark/log/backup/:保持不变,继续承载用户资产、日志与 SQL 备份。
graph TB
A["storage/"] --> B["cache/"]
A --> C["state/"]
A --> D["install/"]
A --> E["watermark/"]
A --> F["log/"]
A --> G["backup/"]
B --> B1["template/{admin,front}/"]
B --> B2["js/generation.txt"]
B --> B3["route/manifest.cache"]
B --> B4["cloud/connect_check.json"]
B --> B5["cloud/update_number.txt"]
B --> B6["tmp/"]
C --> C1["admin_dir.php"]
C --> C2["cdkey.php"]
C --> C3["install.lock"]
C --> C4["quick.start.dou"]
C --> C5["payment_reconcile.lock"]
C --> C6["throttle/"]
D --> D1["package/"]
D --> D2["session/"]
D --> D3["records/"]

图示来源

  • chat.md:8-39

章节来源

  • chat.md:8-39

核心组件

围绕 storage/ 语义改造,关键代码落点集中在以下组件:

  • 安装锁服务:负责写入新位置并兼容旧位置判定链。
  • 限流中间件与存储:默认限流目录迁移至 state/throttle。
  • 后台首页服务:构建系统信息、云连通检查缓存、快速开始项读取与清理。
  • 路由清单持久化:路由 manifest 缓存迁移到 cache/route/manifest.cache。
  • 卸载清理脚本:remove.install.php 中安装锁路径与保留策略对齐新骨架。

章节来源

  • install/service/InstallLockService.php:21-74
  • core/foundation/middleware/AbstractThrottleMiddleware.php:24-126
  • admin/service/index/IndexService.php:101-138
  • admin/service/index/IndexService.php:195-221
  • admin/service/index/IndexService.php:318-358
  • core/web/routing/RouteManifest.php:231-241
  • _'/tool/remove.install.php:325-329

架构总览

从请求生命周期看,storage/ 三类数据在不同阶段被访问:

  • 启动早期:bootstrap 与 InstallLockService 判断是否已安装,决定是否需要强制进入安装向导。
  • 请求处理期:限流中间件基于 state/throttle 做计数器读写;路由清单从 cache/route/manifest.cache 加载或重建。
  • 后台管理期:IndexService 读取 quick.start.dou、写入云连通检查缓存、清理临时脚本;卸载脚本按新骨架保留 state/ 整体。
sequenceDiagram
participant Client as "客户端"
participant Router as "路由层"
participant Lock as "安装锁服务"
participant Throttle as "限流中间件"
participant Manifest as "路由清单"
participant Admin as "后台首页服务"
Client->>Router : "发起请求"
Router->>Lock : "isLocked() 三级判定"
alt 已锁定
Router-->>Client : "强制走安装向导"
else 未锁定
Router->>Throttle : "store() 取 state/throttle/"
Throttle-->>Router : "限流结果"
Router->>Manifest : "ensureBuilt()/diskCacheFile()"
Manifest-->>Router : "返回条目或重建缓存"
Router->>Admin : "后台页面渲染"
Admin-->>Client : "返回响应"
end

图示来源

  • install/service/InstallLockService.php:47-57
  • core/foundation/middleware/AbstractThrottleMiddleware.php:118-126
  • core/web/routing/RouteManifest.php:145-157
  • core/web/routing/RouteManifest.php:231-241

详细组件分析

安装锁服务:InstallLockService

  • 写入位置:始终写入 storage/state/install.lock。
  • 判定链:三级兼容(state → storage 根 → data),任一存在即视为已安装。
  • 作用:Router 在每次请求开始时检查 isLocked(),已锁定则强制走 LockController;FinishService::finalize() 在安装成功后写入安装锁。
classDiagram
class InstallLockService {
-string lockFile
+__construct()
+lockFile() string
+isLocked() bool
+lock() bool
}

图示来源

  • install/service/InstallLockService.php:21-74

章节来源

  • install/service/InstallLockService.php:21-74

限流中间件与限流存储:AbstractThrottleMiddleware

  • 默认 store 路径:security.throttle.store 配置优先,否则使用 STORAGE_PATH . 'state/throttle/'。
  • 行为:对敏感端点按 module.action.ip 键计数限流;超限拒绝并返回 retryAfter。
  • 演进:从旧 data/cache/throttle/ 迁移至 state/throttle/,保持限流计数器的幂等自维护。
flowchart TD
Start(["handle()"]) --> ReadConfig["读取 security.throttle.store"]
ReadConfig --> DefaultDir{"配置为空?"}
DefaultDir --> |是| UseState["使用 state/throttle/"]
DefaultDir --> |否| UseConfig["使用配置目录"]
UseState --> Store["创建 ThrottleStore"]
UseConfig --> Store
Store --> TooMany{"tooMany(key,max,window)?"}
TooMany --> |是| Reject["reject(retryAfter)"]
TooMany --> |否| Hit["hit(key,window)"]
Reject --> End(["结束"])
Hit --> Next["next()"]
Next --> End

图示来源

  • core/foundation/middleware/AbstractThrottleMiddleware.php:60-84
  • core/foundation/middleware/AbstractThrottleMiddleware.php:118-126

章节来源

  • core/foundation/middleware/AbstractThrottleMiddleware.php:24-126

后台首页服务:IndexService

  • buildSysInfo:兜底清理 admin_dirrelocate* 临时脚本;build_date 采用三级回退(state/install.lock → storage/install.lock → data/install.lock)。
  • checkCloudConnectStatus:云连通检查结果缓存到 cache/cloud/connect_check.json,写入前递归 mkdir。
  • clearQuickStartFlag / buildQuickStartItems:读取与清理 quick.start.dou,兼容 state/ 与 storage 根两处候选。
flowchart TD
A["buildSysInfo()"] --> CleanTmp["清理 cache/tmp/admin_dir_relocate_*.php"]
CleanTmp --> BuildDate["三级回退读取 install.lock 修改时间"]
BuildDate --> CloudCheck["checkCloudConnectStatus()"]
CloudCheck --> CacheDir["mkdir(cache/cloud/)"]
CacheDir --> WriteCache["写入 connect_check.json"]
WriteCache --> Return["返回系统信息"]

图示来源

  • admin/service/index/IndexService.php:101-138
  • admin/service/index/IndexService.php:195-221
  • admin/service/index/IndexService.php:318-358

章节来源

  • admin/service/index/IndexService.php:101-138
  • admin/service/index/IndexService.php:195-221
  • admin/service/index/IndexService.php:318-358

路由清单持久化:RouteManifest

  • diskCacheFile:返回 storage/cache/route/manifest.cache。
  • ensureBuilt:优先读磁盘缓存(指纹校验),未命中则重建并写回。
  • writeDiskCache:先递归 mkdir 再原子写入。
flowchart TD
Start(["ensureBuilt()"]) --> CheckMem{"内存缓存已构建?"}
CheckMem --> |是| Return["直接返回"]
CheckMem --> |否| ReadDisk["readDiskCache()"]
ReadDisk --> Hit{"命中缓存?"}
Hit --> |是| SetEntries["设置 entries/nameIndex"]
Hit --> |否| Build["builder.build()"]
Build --> WriteDisk["writeDiskCache()"]
WriteDisk --> SetEntries
SetEntries --> Return

图示来源

  • core/web/routing/RouteManifest.php:145-157
  • core/web/routing/RouteManifest.php:231-241

章节来源

  • core/web/routing/RouteManifest.php:145-157
  • core/web/routing/RouteManifest.php:231-241

卸载清理脚本:remove.install.php

  • installLockFile:指向 storage/state/install.lock,与 storage 清理解耦。
  • 保留策略:state/ 整体保留(含 install.lock、install/records/<非删除模块>、cache/template 空目录、log/、watermark/),payment_reconcile.lock 随 state/ 整体保留。
flowchart TD
A["remove.install.php"] --> DefineLock["定义 $installLockFile = 'storage/state/install.lock'"]
DefineLock --> KeepStrategy["白名单保留 state/ 整体"]
KeepStrategy --> ExcludeList["排除 install.lock 重复删除"]
ExcludeList --> Walk["枚举 storage 实况"]
Walk --> Delete["按白名单批删除"]

图示来源

  • _'/tool/remove.install.php:325-329
  • _'/tool/remove.install.php:1193-1222

章节来源

  • _'/tool/remove.install.php:325-329
  • _'/tool/remove.install.php:1193-1222

依赖关系分析

  • InstallLockService 依赖 ROOT_PATH 常量与文件系统 API,提供 isLocked()/lock() 能力供 Router 与 FinishService 调用。
  • AbstractThrottleMiddleware 依赖 Config 与 ThrottleStore,默认落盘目录为 state/throttle/。
  • IndexService 依赖 FileHelper、Config、CloudApi、Client,负责后台首页数据装配与缓存写入。
  • RouteManifest 依赖 RouteManifestBuilder,负责路由清单的构建与持久化。
  • remove.install.php 作为 CLI/Web 工具脚本,依赖全局 ROOT_PATH 与通用文件操作函数,遵循新的 storage 骨架。
graph LR
Router["Router"] --> Lock["InstallLockService"]
Middleware["AbstractThrottleMiddleware"] --> Store["ThrottleStore"]
Admin["IndexService"] --> Cloud["CloudApi/Client"]
Manifest["RouteManifest"] --> Builder["RouteManifestBuilder"]
Tool["remove.install.php"] --> State["state/ 保留策略"]

图示来源

  • install/service/InstallLockService.php:21-74
  • core/foundation/middleware/AbstractThrottleMiddleware.php:118-126
  • admin/service/index/IndexService.php:195-221
  • core/web/routing/RouteManifest.php:145-157
  • _'/tool/remove.install.php:325-329

章节来源

  • install/service/InstallLockService.php:21-74
  • core/foundation/middleware/AbstractThrottleMiddleware.php:118-126
  • admin/service/index/IndexService.php:195-221
  • core/web/routing/RouteManifest.php:145-157
  • _'/tool/remove.install.php:325-329

性能与可维护性

  • 可重建缓存(cache/):允许整目录删除,避免脏数据导致异常;首次访问自动重建,降低运维成本。
  • 运行时状态(state/):不纳入常规清理,保证安装锁、限流计数器等关键状态的稳定性。
  • 安装域(install/):将模块包、会话、记录集中管理,便于升级脚本幂等搬迁与卸载回滚。
  • 三级判定链:多处只读点(如 bootstrap、IndexService)采用 state → storage 根 → data 的回退逻辑,提升升级平滑度。
  • 幂等迁移:upgrade_2.0.php 两份拷贝需逐字一致,确保手动升级与云更新路径统一。

故障排查指南

  • 安装锁误判:若站点被误判为「未安装」,检查 storage/state/install.lock、storage/install.lock、data/install.lock 是否存在;InstallLockService::isLocked() 任一存在即视为已安装。
  • 限流失效:确认 security.throttle.store 是否指向 state/throttle/;若自定义目录不存在,中间件会创建 ThrottleStore 实例但不会自动创建父目录,需确保目录权限与存在性。
  • 云连通检查失败:查看 cache/cloud/connect_check.json 是否可写;IndexService::checkCloudConnectStatus() 会在写入前递归 mkdir,但仍需确保父目录存在且可写。
  • 路由清单未生效:检查 cache/route/manifest.cache 是否可读;RouteManifest::ensureBuilt() 会在指纹不符时重建缓存,必要时清理该文件触发重建。
  • 卸载残留:remove.install.php 会保留 state/ 整体,若发现 install.lock 仍影响卸载流程,确认其路径是否为 storage/state/install.lock,并按脚本逻辑执行预览/应用模式。

章节来源

  • install/service/InstallLockService.php:47-57
  • core/foundation/middleware/AbstractThrottleMiddleware.php:118-126
  • admin/service/index/IndexService.php:195-221
  • core/web/routing/RouteManifest.php:145-157
  • _'/tool/remove.install.php:325-329

结论

本次 storage/ 语义化改造以三层职责划分为核心:cache 可删、state 不碰、install 归位。通过 install/、upgrade/、_update/ 三程序同批同步,以及应用侧读写点的全面迁移,确保旧站升级后按新路径稳定运行。关键实现包括安装锁三级判定、限流目录迁移、路由清单缓存重定位、后台首页缓存与临时脚本治理,以及卸载脚本对新骨架的适配。发布时应注意新建子目录的防遍历保护与 index.html 放置,并在升级前后验证关键落点的路径一致性。

添加日期:2026-10-05