2022年3月

近日有客服人员反馈,线上后台管理系统二三十分钟没使用,即时也没没关闭也会自动退出登录,不太符合实际使用场景。
经过观察发现,其实测试线的系统就不会有这种情况发现,同样的代码,只是服务器不同,得出结论是php配置不一致导致。
对比发现,是php.ini的session.gc_maxlifetime 配置的值不同,正式线的是默认值 1440 (24分钟),
调整为86400,(一天)

操作如下

vim /usr/local/php/etc/php.ini
session.gc_maxlifetime = 86400 #设置为1天,也可以根据系统需要调整

调整完php.ini之后需要重启php-fpm生效,
1、如果服务器已经把php-fpm加入到service那么重启很简单

service php-fpm restart

2、如果php-fpm并未加入service,可用以下方法重启

1)ps -ef | grep php-fpm | grep master #获取到 php-fpm主进程的 进程id
2)kill -USR2 进程id  #重启进程

3、如果存在/usr/local/php/var/run/php-fpm.pid 文件,可用直接执行一下命令重启

 kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

重启完php-fpm之后,重新登录后台管理账号,就不会出现几十分钟退出登录的情况

前段经常看同事的接口bug是报这个错:“unserialize() Error at offset 76 of 176 bytes",
然后清理下缓存就不报错了,虽然觉得诡异,但由于事情比较多,也没时间去深究。
今天在处理关于客服系统的问题的时候,也遇到了这个问题,就索性探一探究竟。
首先可以确定的是,报错的地方是在缓存cache()的底层逻辑,背景是客服系统的框架是tp5,
客户系统的框架是tp6;于是对比了下两个版本的cache,
发现tp6的cache在存入、取出缓存的驱动(Driver.php)上做了很大的改动
tp5的存入取出代码如下:

/**
 * 序列化数据
 * @access protected
 * @param  mixed $data
 * @return string
 */
protected function serialize($data)
{
    if (is_scalar($data) || !$this->options['serialize']) {
        return $data;
    }

    $serialize = self::$serialize[0];

    return self::$serialize[2] . $serialize($data);
}

/**
 * 反序列化数据
 * @access protected
 * @param  string $data
 * @return mixed
 */
protected function unserialize($data)
{
    if ($this->options['serialize'] && 0 === strpos($data, self::$serialize[2])) {
        $unserialize = self::$serialize[1];

        return $unserialize(substr($data, self::$serialize[3]));
    } else {
        return $data;
    }
}

$serialize 参数的值

/**
 * 序列化方法
 * @var array
 */
protected static $serialize = ['serialize', 'unserialize', 'think_serialize:', 16];

tp6的存入取出代码如下:

/**
 * 序列化数据
 * @access protected
 * @param mixed $data 缓存数据
 * @return string
 */
protected function serialize($data): string
{
    if (is_numeric($data)) {
        return (string) $data;
    }

    $serialize = $this->options['serialize'][0] ?? "serialize";

    return $serialize($data);
}

/**
 * 反序列化数据
 * @access protected
 * @param string $data 缓存数据
 * @return mixed
 */
protected function unserialize(string $data)
{
    if (is_numeric($data)) {
        return $data;
    }

    $unserialize = $this->options['serialize'][1] ?? "unserialize";

    return $unserialize($data);
}

看到这里,大概就知道为什么在tp6获取cache值的时候会报这个错了。
tp5的存入值是否加serialize序列化是判断传入$data是否是标量is_scalar,
而tp6是判断是否为数值is_numeric,导致两边数据不一致。
知道了原因,解决方法就个显神通了,当前的方式比较粗暴,直接修改底层框架,
在tp6 unserialize的方法里面修改判断是否反序列化的逻辑,代码如下:

    /**
     * 反序列化数据
     * @access protected
     * @param string $data 缓存数据
     * @return mixed
     */
    protected function unserialize(string $data)
    {
        //判断$data是否为序列化字符串,如果不是直接返回不需要反序列化
        if (!preg_match( '/^[asO]:[0-9]+:/s', $data)) {
            return $data;
        }

        $unserialize = $this->options['serialize'][1] ?? "unserialize";

        return $unserialize($data);
    }