文档目录
会话管理机制

简介

本技术文档围绕用户会话管理,系统阐述以下方面:

  • 会话存储策略:内存会话、文件会话与数据库会话的实现差异与适用场景。
  • 持久化机制:序列化方式、存储格式与性能优化要点。
  • 并发控制:会话锁定、冲突解决与数据一致性保障。
  • 生命周期管理:创建、更新、销毁与超时处理。
  • 配置与安全:会话 Cookie 硬化、跨域策略与故障恢复。
  • 监控与调试:定位问题与性能调优建议。

项目结构

本项目采用分层与模块化组织,会话相关能力集中在基础设施层与初始化流程中,并通过门面模式对外暴露统一接口;同时保留第三方 SDK 的会话扩展点(文件/SQLite)。

graph TB
A["请求入口<br/>前端/后台/API"] --> B["初始化流程<br/>InitTrait::startSession()"]
B --> C["安全配置加载<br/>security.php"]
B --> D["PHP 会话启动<br/>session_start()"]
D --> E["会话服务封装<br/>Infra\\Session"]
E --> F["业务访问<br/>Facade\\Session"]
G["可选扩展<br/>Lotus PHP Session"] --> H["文件存储"]
G --> I["SQLite 存储"]

图表来源

  • core/init/InitTrait.php:206-259
  • config/security.php:79-85
  • core/infra/session/Session.php:21-321
  • plugin/alipay/sdk/lotusphp_runtime/Session/Session.php:19-46
  • plugin/alipay/sdk/lotusphp_runtime/Session/Store/SessionStoreSqlite.php:16-62

章节来源

  • core/init/InitTrait.php:206-259
  • config/security.php:79-85
  • core/infra/session/Session.php:21-321
  • plugin/alipay/sdk/lotusphp_runtime/Session/Session.php:19-46
  • plugin/alipay/sdk/lotusphp_runtime/Session/Store/SessionStoreSqlite.php:16-62

核心组件

  • 会话服务封装:提供命名空间隔离的 get/set/has/del/clear/push/pull/increment/decrement/forget 以及一次性 flash 消息读写。所有方法在 DOU_ID 未定义时安全降级,避免早期调用异常。
  • 静态门面:通过容器单例将底层会话服务以静态方式暴露,便于在各模块统一使用。
  • 会话启动与安全:在应用初始化阶段读取安全配置,设置 Cookie 属性并启用严格模式,再启动会话。
  • 可选扩展:第三方 Lotus PHP 会话实现支持文件与 SQLite 存储,可通过 session_set_save_handler 接入。

章节来源

  • core/infra/session/Session.php:21-321
  • core/facade/Session.php:23-59
  • core/init/InitTrait.php:206-259
  • plugin/alipay/sdk/lotusphp_runtime/Session/Session.php:19-46

架构总览

下图展示从请求进入、会话启动到读写会话数据的完整链路,以及可选的文件/SQLite 存储扩展。

sequenceDiagram
participant Client as "客户端"
participant Init as "InitTrait"
participant PHP as "PHP 会话引擎"
participant Infra as "Infra\\Session"
participant Facade as "Facade\\Session"
participant Store as "可选存储(文件/SQLite)"
Client->>Init : 发起请求
Init->>Init : 加载安全配置 security.php
Init->>PHP : 设置 Cookie 参数/严格模式
Init->>PHP : session_start()
PHP-->>Store : 根据 handler 选择存储后端
Client->>Facade : 调用会话 API
Facade->>Infra : 转发到具体方法
Infra->>PHP : 读写 $_SESSION[DOU_ID]
PHP-->>Store : 持久化/读取数据
Store-->>PHP : 返回结果
PHP-->>Infra : 返回状态
Infra-->>Facade : 返回数据
Facade-->>Client : 响应

图表来源

  • core/init/InitTrait.php:206-259
  • core/infra/session/Session.php:21-321
  • plugin/alipay/sdk/lotusphp_runtime/Session/Session.php:19-46
  • plugin/alipay/sdk/lotusphp_runtime/Session/Store/SessionStoreSqlite.php:16-62

详细组件分析

会话服务封装(Infra\Session)

  • 命名空间隔离:所有读写基于全局常量 DOU_ID 作为键前缀,避免多端或多站点共享 $_SESSION 导致的数据串扰。
  • 安全降级:当 DOU_ID 未定义时,所有方法直接返回默认值或空操作,确保极早期调用不会抛出异常。
  • 数据结构:以二维数组形式组织,支持二级子键(如 verification/code),并提供数组型便捷方法 arr()。
  • 常用操作:
    • 读取/写入/判断/删除/清空
    • 追加/取出并删除/自增/自减/去重移除
    • Flash 消息:一次性写入与读取,读后即清,适合 PRG 模式下的提示消息。
classDiagram
class Session {
+get(key, default, subKey) mixed
+arr(key) array
+set(key, value, subKey) void
+has(key, subKey) bool
+del(key, subKey) void
+clear() void
+push(key, value) void
+pull(key, default) mixed
+increment(key, by) int
+decrement(key, by) int
+forget(key, value) void
+setFlash(key, value) void
+getFlash(key, default) mixed
+pullAllFlashes() array
}

图表来源

  • core/infra/session/Session.php:21-321

章节来源

  • core/infra/session/Session.php:21-321

静态门面(Facade\Session)

  • 作用:为业务代码提供静态调用方式,内部委托至容器中的 Infra\Session 单例实例。
  • 测试友好:可通过 StaticFacade 替换为 mock,避免触碰真实 $_SESSION。

章节来源

  • core/facade/Session.php:23-59

会话启动与安全(InitTrait::startSession)

  • 安全 Cookie 硬化:
    • httponly:禁止 JS 读取,降低 XSS 窃取风险。
    • secure:跟随 IS_HTTPS 或强制 true/false。
    • samesite:Lax/Strict/None,防御跨站 CSRF。
    • use_strict_mode:拒绝未初始化的外部 sid,防止会话固定攻击。
  • 启动时机:在加载安全配置后、session_start() 之前执行,确保 Cookie 参数生效。
  • 兼容性:对 PHP 7.3+ 与非 7.3+ 版本分别设置 SameSite。
flowchart TD
Start(["开始"]) --> CheckStatus{"是否已启动会话?"}
CheckStatus --> |是| End(["结束"])
CheckStatus --> |否| LoadCfg["加载 security.php 会话配置"]
LoadCfg --> Apply["应用 Cookie 参数/严格模式"]
Apply --> StartSession["session_start()"]
StartSession --> End

图表来源

  • core/init/InitTrait.php:206-259
  • config/security.php:79-85

章节来源

  • core/init/InitTrait.php:206-259
  • config/security.php:79-85

可选扩展:文件与 SQLite 会话存储(Lotus PHP)

  • 文件存储:默认使用 PHP 内置文件处理器,保存路径可配置;适用于单机部署与简单场景。
  • SQLite 存储:通过自定义 store 类实现 open/read/write/destroy/gc,将会话数据持久化到 SQLite 文件,适合需要跨进程共享且轻量级的场景。
  • 集成方式:通过 session_set_save_handler 注册回调,接管 PHP 会话生命周期。
sequenceDiagram
participant App as "应用"
participant Lt as "LtSession"
participant Handler as "session_set_save_handler"
participant Store as "SessionStoreSqlite"
participant DB as "SQLite"
App->>Lt : init()
Lt->>Handler : 注册 open/read/write/destroy/gc
App->>App : session_start()
App->>Handler : read(sessID)
Handler->>Store : read(sessID)
Store->>DB : SELECT session_data WHERE ... AND expires > now
DB-->>Store : 返回数据
Store-->>Handler : 返回数据
Handler-->>App : 返回数据

图表来源

  • plugin/alipay/sdk/lotusphp_runtime/Session/Session.php:19-46
  • plugin/alipay/sdk/lotusphp_runtime/Session/Store/SessionStoreSqlite.php:16-62

章节来源

  • plugin/alipay/sdk/lotusphp_runtime/Session/Session.php:19-46
  • plugin/alipay/sdk/lotusphp_runtime/Session/Store/SessionStoreSqlite.php:16-62

并发控制与一致性

  • 后台任务中的会话释放:在对账兜底触发器中,先关闭会话写锁(session_write_close),再进行耗时操作,避免阻塞后续请求。
  • 文件锁防并发:使用 flock 非阻塞独占锁,保证同一时刻仅一个进程执行对账逻辑,避免重复处理。
  • 会话严格模式:通过 use_strict_mode 拒绝非法 sid,减少会话固定攻击风险。
sequenceDiagram
participant Front as "前台请求"
participant Lottery as "PaymentReconciliationLottery"
participant PHP as "PHP 会话"
participant FS as "文件系统"
Front->>Lottery : tryTrigger()
Lottery->>PHP : session_write_close()
Lottery->>FS : fopen(lockFile) + flock(LOCK_EX|LOCK_NB)
alt 获取锁成功
Lottery->>Lottery : 执行对账任务
else 获取锁失败
Lottery-->>Front : 跳过执行
end

图表来源

  • _'/module/order/front/service/order/PaymentReconciliationLottery.php:114-135
  • core/init/InitTrait.php:206-259

章节来源

  • _'/module/order/front/service/order/PaymentReconciliationLottery.php:114-135
  • core/init/InitTrait.php:206-259

生命周期管理

  • 创建:应用初始化阶段调用 startSession() 完成 Cookie 设置与会话启动。
  • 更新:业务侧通过 Facade\Session 进行 set/push/increment 等操作,底层写入 $_SESSION[DOU_ID]。
  • 销毁:通过 del/clear 或会话过期机制清理;对账等后台任务会显式关闭会话写锁以减少阻塞。
  • 超时:由 PHP 会话 GC 与 SQLite 存储中的 expires 字段共同控制;SQLite 读取时过滤过期记录。

章节来源

  • core/init/InitTrait.php:206-259
  • core/infra/session/Session.php:21-321
  • plugin/alipay/sdk/lotusphp_runtime/Session/Store/SessionStoreSqlite.php:52-62

依赖关系分析

  • 初始化依赖:InitTrait 在启动阶段加载安全配置并启动会话;容器注入 Session 服务实例。
  • 门面依赖:Facade\Session 依赖容器解析出的 Infra\Session 实例。
  • 可选扩展依赖:Lotus PHP 会话扩展通过配置文件与 session_set_save_handler 接入,不改变主流程。
graph LR
IT["InitTrait"] --> CFG["security.php"]
IT --> PHP["PHP 会话"]
IT --> INFRA["Infra\\Session"]
FAC["Facade\\Session"] --> INFRA
EXT["Lotus PHP Session"] --> STORE["文件/SQLite"]

图表来源

  • core/init/InitTrait.php:206-259
  • config/security.php:79-85
  • core/facade/Session.php:23-59
  • plugin/alipay/sdk/lotusphp_runtime/Session/Session.php:19-46

章节来源

  • core/init/InitTrait.php:206-259
  • config/security.php:79-85
  • core/facade/Session.php:23-59
  • plugin/alipay/sdk/lotusphp_runtime/Session/Session.php:19-46

性能考量

  • 存储后端选择:
    • 内存会话(默认 $_SESSION):低延迟、高吞吐,适合单机或无共享需求场景。
    • 文件会话:易于部署,但高并发下文件 IO 可能成为瓶颈。
    • SQLite 会话:跨进程共享,适合小型集群;注意并发写入与 WAL 模式优化。
  • 会话数据大小:避免在会话中存储大对象;必要时拆分到缓存或数据库,并在会话中仅保留引用。
  • 写锁释放:后台任务中及时关闭会话写锁(session_write_close),减少阻塞。
  • GC 与过期:合理设置 gc_maxlifetime,SQLite 存储中利用 expires 字段快速过滤过期记录。

故障排查指南

  • 会话无法启动:检查 security.php 是否存在及 session 配置块是否正确;确认 PHP 版本兼容性与 SameSite 设置。
  • 会话数据丢失:确认 DOU_ID 是否按预期生成;检查 $_SESSION[DOU_ID] 是否被覆盖或清理;验证存储后端(文件/SQLite)权限与路径。
  • 并发冲突:对账等后台任务是否正确使用 flock 与 session_write_close;避免长时间持有会话写锁。
  • 安全告警:确认 use_strict_mode 开启;检查 httponly/secure/samesite 是否符合部署环境。

章节来源

  • core/init/InitTrait.php:206-259
  • config/security.php:79-85
  • _'/module/order/front/service/order/PaymentReconciliationLottery.php:114-135

结论

本项目会话管理以 PHP 原生会话为核心,通过安全配置硬化 Cookie 并启用严格模式,结合 Infra\Session 的命名空间隔离与门面抽象,提供了稳定、易用的会话读写能力。可选的 Lotus PHP 扩展支持文件与 SQLite 存储,满足多样化部署需求。并发控制通过会话写锁释放与文件锁防并发保障一致性。建议在高性能场景优先使用内存会话,并结合合理的 GC 策略与数据瘦身措施提升整体性能。

附录

  • 会话配置项说明(来自 security.php):
    • httponly:是否禁止 JS 读取会话 Cookie。
    • secure:是否仅 HTTPS 下发会话 Cookie。
    • samesite:SameSite 策略(Lax/Strict/None)。
    • use_strict_mode:是否启用严格模式,拒绝未初始化 sid。

章节来源

  • config/security.php:79-85
添加日期:2026-10-05