avatar

mdo

Hello

  • 首页
  • 知识库
  • 归档
  • 标签
  • 关于
主页 完美地解决 TP3 老系统数据的平滑读取
文章

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

发表于 13天前 更新于 13天前
作者 mdo
11~15 分钟 阅读

为了彻底、完美地解决 TP3 老系统数据的平滑读取,必须解决两个核心痛点:

  1. TP3 的盲猜反序列化机制(标量存原样,数组/对象存原生 serialize,同时兼容 json)。

  2. TP3 与 TP6 的缓存前缀(Prefix)不一致。

以下是为你量身定制的终极落地解决方案,通过自定义 TP6 驱动和平滑迁移中间件两步,既能保障新系统无缝读取旧数据,又能保障新写入的数据不破坏老系统。


第一步:在 TP6 中创建“1:1 完美平替”驱动

这个自定义驱动直接继承 TP6 的 Redis 驱动,但重写了底层的 serialize 和 unserialize 方法,使其行为与 TP3 保持 100% 互通。

新建文件:app/common/cache/driver/Tp3CompatibleRedis.php

php

<?php
namespace app\common\cache\driver;

use think\cache\driver\Redis;

/**
 * 专门用于 1:1 兼容 TP3 读写行为的 Redis 驱动
 */
class Tp3CompatibleRedis extends Redis
{
    /**
     * 写入数据:严格模拟 TP3 行为
     * - 标量(字符串/数字/布尔值)直接存原样,绝不包裹序列化
     * - 数组或对象采用 PHP 原生 serialize
     */
    protected function serialize($data): string
    {
        if (is_scalar($data)) {
            return (string)$data; 
        }
        return serialize($data); 
    }

    /**
     * 读取数据:严格模拟 TP3 盲猜反序列化
     * - 优先尝试原生反序列化
     * - 其次尝试 JSON 解码
     * - 失败则作为普通字符串原样返回
     */
    protected function unserialize(string $data)
    {
        // 1. 尝试原生反序列化
        $unserializeData = @unserialize($data);
        if ($unserializeData !== false || $data === 'b:0;') {
            return $unserializeData;
        }

        // 2. 尝试 JSON 解码(兼容TP3中部分手动存json的魔改数据)
        $jsonData = json_decode($data, true);
        if (json_last_error() === JSON_ERROR_NONE && !is_numeric($data)) {
            return $jsonData;
        }

        // 3. 兜底:说明老系统当年存的就是纯字符串/Token,直接原样返回
        return $data;
    }
}

请谨慎使用此类代码。


第二步:精准配置 TP6 缓存(对齐前缀)

打开 TP6 的 config/cache.php,将 redis 驱动指向你刚才创建的兼容类。最关键的是:前缀(prefix)必须与 TP3 保持完全一致!

php

return [
    'default' => 'redis',
    'stores'  => [
        'redis' => [
            // 1. 指向刚刚创建的兼容驱动类
            'type'       => \app\common\cache\driver\Tp3CompatibleRedis::class,
            'host'       => '127.0.0.1',
            'port'       => 6379,
            'password'   => '',
            'select'     => 0,
            // 2. 注意:关闭 TP6 内置的序列化配置,交由我们重写的类自主处理
            'serialize'  => [], 
            // 3. 【致命关键】必须对齐 TP3 的 C('DATA_CACHE_PREFIX') 
            // 如果老系统没配前缀,这里必须留空字符串 ''
            'prefix'     => '', 
            'expire'     => 0,
        ],
    ],
];

请谨慎使用此类代码。


第三步:重构你的 unsession 助手函数

有了上面两步的底层铺垫,你在 TP6 里重构旧系统的 unsession 函数就变得极其轻量且安全了。在 app/common.php 中这样重写:

php

<?php
// app/common.php

use think\facade\Cache;

if (!function_exists('unsession')) {
    /**
     * 兼容老系统的 unsession 函数
     * @param string|null $key 旧系统传入的 SessionKey 或 Token
     * @return bool
     */
    function unsession(?string $key = null): bool
    {
        if (empty($key)) {
            return false;
        }

        // 此时 Cache 已经完全兼容了 TP3 的读写和前缀规则
        // 如果需要先读取老数据做业务校验:
        $oldData = Cache::get($key); 
        
        if ($oldData) {
            // 执行你的清理或强退日志记录...
            
            // 彻底从 Redis 中销毁该会话/数据
            return Cache::delete($key);
        }

        return false;
    }
}

请谨慎使用此类代码。


💡 平滑迁移的终极防坑校验

  1. 核对 TP3 的真实 Key 值
    在老系统(TP3)中运行一次
    M()->execute() 或找个地方打印 echo C('DATA_CACHE_PREFIX');。如果老系统输出了 tp3_,那么 TP6 的 'prefix' 必须写 tp3_。如果老系统没有配,TP6 必须写 ''。两边只要有一点点对不上,新系统就相当于在读空气。

  2. 避免在代码里手动拼 think: 前缀
    TP6 官方默认文档和很多教程喜欢在代码里手动拼
    think:。既然是彻底兼容老系统,请在新系统(TP6)的业务代码中,统一使用老系统的 Key 命名规范。

  3. 老系统的 session_id() 怎么拿?
    如果老系统的
    unsession 依赖于原生的 PHPSESSID,在 TP6 中请通过 $request->cookie('PHPSESSID')或者是通过前端 Header 传参获取,绝不要再调用原生的 session_id(),因为 TP6 默认是不启动原生 Session 容器的。

技术
许可协议:  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 的存储介质。当进行全局

下一篇

thinkphp3 redis序列化和反序列化

上一篇

最近更新

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

热门标签

API CodeGeex Gitkraken Management Manticore Premiere Sublime Swoole ThinkPHP ThinkPHP5

目录

©2026 mdo. 保留部分权利。