PHP 两个站点造成的SESSION混乱

前言

在做某个需求时,将 token 存在了 SESSION 里,然而呢,SESSION 是存在 Redis 里的。在检查这个 token 是否正确时,却发现,时而正确,时而错误。

检查了从 SESSION 里取出的值,发现里面的内容会有几率的不同。

于是,查看了 Redis 里的值,发现是存在,并且正确的。查看了 /var/lib/php/sessions 里的值,发现是存在,并且错误的。与之前打出的值一样,这,我懵逼了。

于是漫长的 BUG 之路开始了。

原因

检查了很久,还是不知原因,便请来了华仔(技术牛人)。

一开始,我们的方向是:因为配置的问题,导致 Redis 读的库混乱了。检查之后发现,配置没有任何问题。

然后想到了,我的所有站点都在一个系统里,是不是因为其他站点引起的。试验之后发现,果不其然。

当访问了另外一个从文件读取 SESSION 的站点之后,主站点就会取到两种 Redis

于是我就怀疑,是 PHP-FPM 的问题,请求结束后,SESSION 并没有被销毁。

验证

在主站点的入口文件里,写了一段代码,主要是测试 SESSION 是否有被关闭。

<?php
// ...
$status = session_status();
switch ($status) {
    case PHP_SESSION_ACTIVE:
        echo 'session is active';
        break;

    case PHP_SESSION_NONE:
    case PHP_SESSION_DISABLED:
        echo 'session is not active';
        break;
}
exit();
// ...

检测发现,有几率出现 'session is active' 的情况。这说明了,次站点的请求结束后,并没有关闭 SESSION 。 华仔看了一下源码,也证实了这件事情。

最终在 PHP 的官网上看到了这个:

既然问题已经出现,那么,如何解决呢。

解决

次站点在响应给出之前,先关闭 SESSION,使用 session_write_close() 方法。

同时,主站点在初始化 SESSION 时,可以先关闭 SESSION 再开启,实现如下。

<?php
// ...
$status = session_status();
switch ($status) {
    case PHP_SESSION_ACTIVE:
        session_write_close();
        session_start();
        break;

    case PHP_SESSION_NONE:
    case PHP_SESSION_DISABLED:
        session_start();
        break;
}
exit();
// ...

这个时候,就可以去自定义会话管理了,无论是存在 RedisMemcache 或者 database 里都可以。

总结

很多问题,在多数情况下,是不会出现的。只有做多,才会错多。

然而,错并不可怕,发现并将其改正就好。

-- EOF --
本文转载自IMJCW
原文链接:PHP 两个站点造成的SESSION混乱

推荐阅读更多精彩内容