avatar

mdo

Hello

  • 首页
  • 知识库
  • 归档
  • 标签
  • 关于
主页 让 TP6 的 Session 组件重新接管控制权
文章

让 TP6 的 Session 组件重新接管控制权

发表于 2026-06-24 更新于 2026-06- 25
作者 mdo
11~14 分钟 阅读

我们需要让 TP6 的 Session 组件重新接管控制权,同时强行将其配置到 Redis 2号库,并在入口处拦截并纠正 APP 带来的 26 位 Token,最后同步写到 6号库。

请严格按照以下步骤进行调整,无需修改你现有的 session() 读写业务代码:

第一步:恢复 TP6 的 Session 中间件

打开全局中间件配置文件 app/middleware.php。
确保将之前注释掉的这行代码恢复启用(如果本来就是启用的,请保持原样):

php

\think\middleware\SessionInit::class,

请谨慎使用此类代码。

第二步:修改 TP6 的 Session 配置文件

打开 config/session.php,删除或注释掉原有的配置,完全替换为以下内容。这会引导 session() 函数直连 Redis 2号库,并自动从 POST 参数中寻找 token:

php

return [
    // 使用 Redis 驱动
    'type'           => 'redis',
    // 缓存前缀(如果你希望 Redis 中的键名直接是 32 位 Token,可以留空 '')
    'prefix'         => '',
    // Session 有效期(秒)
    'expire'         => 1440,
    // 关键配置:告诉 TP6 优先从 POST/GET 请求中的 'token' 字段来读取 session_id
    'var_session_id' => 'token',
    
    // Redis 连接参数
    'host'           => '127.0.0.1',
    'port'           => 6379,
    'password'       => '', // 如果有密码请填写
    'select'         => 2,  // 强制指定存入 2 号数据库
    'timeout'        => 0,
    'persistent'     => false,
];

请谨慎使用此类代码。

第三步:在基类控制器中做「32位清洗」与「6号库同步」

由于 TP6 的中间件在进入控制器之前就已经运行完毕,此时框架已经根据 APP 传过来的 token 进行了初始化。

我们需要在 BaseController(或专供 APP 调用的公共基类)的 initialize() 方法中,对初始化结果进行检查。如果发现是 26 位,直接废弃并重新生成 32 位,然后写入 6 号库:

php

namespace app\controller;

use think\App;
use think\exception\HttpResponseException;

class BaseController
{
    protected $app;
    protected $request;

    public function __construct(App $app)
    {
        $this->app     = $app;
        $this->request = $this->app->request;
        $this->initialize();
    }

    protected function initialize()
    {
        // 1. 获取 TP6 框架当前识别到的 session_id
        $sessionId = $this->request->session()->getId();

        // 2. 【核心清洗】如果长度不是 32 位,或者格式不对(比如 APP 传过来的 26 位旧 Token)
        if (strlen($sessionId) !== 32 || !preg_match('/^[a-f0-9A-Za-z]{32}$/', $sessionId)) {
            // 强行生成一个绝对标准的 32 位 16 进制字符串
            $new32Id = bin2hex(random_bytes(16));
            
            // 强制将当前请求的 Session ID 切换为这个全新的 32 位 ID
            $this->request->session()->setId($new32Id);
            
            // 重新初始化一次 Session 数据,确保新 ID 立即在 2 号库生效
            $this->request->session()->init();
            
            $sessionId = $new32Id;
        }

        // 3. 【同步写入】此时 $sessionId 100% 是 32 位,直接同步到 6 号库
        $this->syncToOnlineStats($sessionId);
    }

    /**
     * 同步在线状态到 6 号库
     */
    protected function syncToOnlineStats($sessionId)
    {
        try {
            $redisDb6 = new \Redis();
            $redisDb6->connect('127.0.0.1', 6379);
            $redisDb6->select(6); // 切换到 6 号库
            
            // 保持键名与 2 号库的 32 位 ID 绝对一致
            $onlineKey = "app_online:" . $sessionId; 
            
            // 写入 6 号库并设置过期时间(例如 15 分钟)
            $redisDb6->setex($onlineKey, 900, time()); 
        } catch (\Exception $e) {
            trace('6号库在线统计写入失败: ' . $e->getMessage(), 'error');
        }
    }

    /**
     * 统一的接口返回方法
     */
    protected function apiReturn($data = [], $msg = 'success', $code = 200)
    {
        // 这里必须用 return 显式输出,或者像之前一样抛出 HttpResponseException
        $response = json([
            'code'  => $code,
            'msg'   => $msg,
            'data'  => $data,
            // 关键:永远向 APP 返回当前框架生效的、写进双库的 32 位 Token
            'token' => $this->request->session()->getId() 
        ]);
        
        throw new HttpResponseException($response);
    }
}

请谨慎使用此类代码。

🏆 这样改造后的最终状态:

  1. 零业务代码修改:你散落在项目各处的 session('user_id')、session('info', $data) 助手函数完全不需要动,它们会照常工作。

  2. 数据绝对对齐:

    • 2 号库中存储的键名将变成纯 32 位(或带有你在 config/session.php 中指定的 prefix 前缀)。

    • 6 号库中存储的键名也同步变成了 app_online:32位Token。

    • APP 客户端接收到的也是 32 位,下次 POST 传回来的也是 32 位,系统进入良性循环。

技术
许可协议:  CC BY 4.0
分享

相关文章

7月 26, 2026

完美地解决 TP3 老系统数据的平滑读取

为了彻底、完美地解决 TP3 老系统数据的平滑读取,必须解决两个核心痛点: TP3 的盲猜反序列化机制(标量存原样,数组/对象存原生 serialize,同时兼容 json)。 TP3 与 TP6 的缓存前缀(Prefix)不一致。 以下是为你量身定制的终极落地解决方案,通

7月 26, 2026

thinkphp3 redis序列化和反序列化

在老系统重构迁移至 ThinkPHP 6 (TP6) 的过程中,ThinkPHP 3 (TP3) 的 Redis 序列化历史遗留问题是最核心的连环坑之一。 TP3 的 S('key', $value) 缓存方法和底层 Redis 驱动,在存储非字符串(如数组、对象)时,有一套独特的序列化行为。如果不

7月 24, 2026

Table 空间极易发生哈希冲突并溢出

既然你没有在业务中主动调用 Room,只使用了全局广播,那么这个问题就非常明确了:即使你不用房间功能,think-swoole 只要开启了 WebSocket,底层就会强行初始化并注入一个名为 Room 的驱动组件。 [1] 框架底层默认使用 table 类型来作为 Room 的存储介质。当进行全局

下一篇

Redis 缓存余额 + 前端异步局部刷新 + 提供手动刷新按钮

上一篇

Session 文件冲突

最近更新

  • 完美地解决 TP3 老系统数据的平滑读取
  • thinkphp3 redis序列化和反序列化
  • Table 空间极易发生哈希冲突并溢出
  • 将监控程序直接跑在云端
  • AI 驱动型 Facebook 群组关键词监控 Chrome 浏览器插件

热门标签

API CodeGeex Gitkraken Management Manticore Premiere Sublime Swoole ThinkPHP ThinkPHP5

目录

©2026 mdo. 保留部分权利。