如何判断会话是不是处于活动状态? [复制]

Posted

技术标签:

【中文标题】如何判断会话是不是处于活动状态? [复制]【英文标题】:How to tell if a session is active? [duplicate]如何判断会话是否处于活动状态? [复制] 【发布时间】:2011-04-16 20:18:10 【问题描述】:

根据请求,您可以通过几种不同的方式判断会话是否已启动,例如:

$isSessionActive = (session_id() != "");

或者:

$isSessionActive = defined('SID');

但是,如果您启动会话,然后关闭它,这两种方法都会失败; session_id() 将返回前一个会话的 ID,而 SID 将被定义。同样,此时调用session_start() 将生成E_NOTICE,如果您已经有一个活动会话。有没有一种健全的方法来检查会话当前是否处于活动状态,而不必求助于输出缓冲、闭嘴操作符 (@session_start()) 或其他与 hacky 一样的东西?

编辑:我写了一个补丁来尝试将此功能包含在 PHP 中:http://bugs.php.net/bug.php?id=52982

编辑 2011 年 8 月 29 日:PHP 5.4 添加了新功能以解决此问题:"Expose session status via new function, session_status"

// as of 8/29/2011
$isSessionActive = (session_status() == php_SESSION_ACTIVE);

编辑 12/5/11:session_status() 在 PHP 手册上。

【问题讨论】:

这可能有点骇人听闻:session_is_active(),但至少我发现了一些东西。无论如何感谢您的错误报告,很高兴看到这个问题在 5.4 中得到解决。 关于 5.4 的添加仍然是一个相关的问题,因为我刚刚推到 5.3 的盒子,发现 session_status() 不见了! 这很奇怪,因为它确实存在于我的 5.4 版本中。你是说你用的是5.3还是5.4?它是自定义的还是预构建的 PHP 二进制文件?在phpinfo(),你有“会话”部分吗?在行动:codepad.viper-7.com/PiZmcw 【参考方案1】:

查看对原始问题的修改;基本上,PHP 5.4 及更高版本现在有一个名为session_status() 的函数来解决这个问题!

"Expose session status via new function, session_status" (SVN Revision 315745)

如果您在 PHP 5.4 之前的版本中需要此功能,请参阅hakre's answer。

【讨论】:

【参考方案2】:

您需要检查多个位置以验证会话是否处于活动状态:

1- cookie 存在且未过期 2- 底层会话存储机制(文件系统或数据库)有一条匹配cookie的记录。

【讨论】:

我认为您误解了目标/意图。 也许是的。我更习惯于处理具有自定义功能的会话。最好将会话封装到一个类中,以便在调用析构函数或调用 session_write_closed 成员函数时更新该类中的布尔标志,显示是否处于活动状态。 这是为了避免Notice: A session had already been started - ignoring session_start()。这个错误有更多关于用例的信息:bugs.php.net/bug.php?id=52982【参考方案3】:

我通过在各种会话创建/关闭/销毁函数周围添加几个包装函数来解决这个问题。基本上:

function open_session() 
     session_start();
     $_SESSION['is_open'] = TRUE;


function close_session() 
   session_write_close();
   $_SESSION['is_open'] = FALSE;


function destroy_session() 
   session_destroy();
   $_SESSION['is_open'] = FALSE;


function session_is_open() 
   return($_SESSION['is_open']);

Hackish,但完成了我所需要的。

【讨论】:

嗯,这也是我选择的解决方案...替代方案可能是实现一个会话写入处理程序,该处理程序修改一个内部标志,然后您可以检查它,但这会有点打败了它自己的目的,因为它必须在一开始就被定义。 在 session_close 函数中有一个杂散的大括号,它需要是一个分号。所以不会让我编辑,因为没有足够的字符需要编辑。 ://【参考方案4】:

这是一个很好的替代品,当您迁移到 5.4 时不会破坏任何东西:

if(!function_exists('session_status'))
    function session_active()
        return defined('SID');   
    
else
    function session_active()
        return (session_status() == PHP_SESSION_ACTIVE);   
            

【讨论】:

正如我在最初的问题中所说,这是一个不充分的解决方案;如果您先调用session_start(),然后再调用session_write_close(),那么即使会话未打开,也会调用defined("SID") === true。这种技术只能确定会话是否在请求周期内启动——而不能确定一个会话当前是否打开。它可能适用于某些用例,但不能替代 session_status()【参考方案5】:

我也遇到了这个问题,$_SESSION 中的设置不适合我。对于 PHP 5.3.8:

    如果任何会话已随请求启动,define('SID') 将返回 FALSE,并且 $_SESSION 未设置。 这与session_id() 是否用于设置会话ID 无关。 在第一个session_start() 之后,定义了SID,并将$_SESSION 设置为一个空数组。 session_destroy() 确实取消了 session_id() 的设置,那么它是一个空字符串。 SID 将保持定义(并设置为之前的值,可能是一个空字符串)。 $_SESSION 保持不变。下次调用 session_start 时,它将被重置/填充。

在这些状态下,尤其是当session_id() 可以在其间调用以设置下一个 会话的ID 时,不可能通过SID$_SESSION 安全地确定会话状态和session_id()

“尝试”session_start()(例如@)可能并没有真正的帮助,因为这会改变会话状态并改变$_SESSION 的内容(如果 cookie 是不是请求的一部分)。这不适合我的情况。

在运行测试时,我遇到了这样的行为,即当会话处于活动状态时,您无法尝试更改 session.serialize_handler 的 ini 设置,即使您将其设置为相同的值也是如此。 session.use_trans_sidDocs 也是如此,它更轻量级。这导致我使用以下功能:

/**
 * @return bool
 */
function session_is_active()

    $setting = 'session.use_trans_sid';
    $current = ini_get($setting);
    if (FALSE === $current)
    
        throw new UnexpectedValueException(sprintf('Setting %s does not exists.', $setting));
    
    $result = @ini_set($setting, $current); 
    return $result !== $current;

据我所知,该错误仅检查活动会话状态(未禁用),因此禁用会话时不应返回误报。

为了让这个函数与 PHP 5.2 兼容,需要稍作修改:

/**
 * @return bool
 */
function session_is_active()

    $setting = 'session.use_trans_sid';
    $current = ini_get($setting);
    if (FALSE === $current)
    
        throw new UnexpectedValueException(sprintf('Setting %s does not exists.', $setting));
    
    $testate = "mix$current$current";
    $old = @ini_set($setting, $testate);
    $peek = @ini_set($setting, $current);
    $result = $peek === $current || $peek === FALSE;
    return $result;

一些sandbox。

【讨论】:

虽然这仍然有点“hacky”,但您的技术给我留下了深刻的印象。我的想法是问题的某些属性可以用来推断(例如您在这里所做的事情),我只是无法找到它们。非常好! 另外,沙箱是您的网站吗?操作码分析很不错。 不,那不是我的网站,但我也喜欢它。 :) 现在我不确定该 hack 是否适用于 PHP 5.1(我可能需要它)。 @Salathe 非常友善,并根据各种 PHP 5.1 版本 (gist.github.com/1265615#gistfile1.txt) 测量例程,看起来对向后兼容非常有用。【参考方案6】:

Ken,如果会话被破坏,$_SESSION 数组应该不可用......或者至少,你的值应该是未设置的。因此,理论上(未经测试)您应该能够检查数组中的值以了解当前是否设置了任何内容。

【讨论】:

session_destroy()session_write_close() 未设置 $_SESSION【参考方案7】:

以下代码只为我转储一个 session_id(),而不是两个

session_start();
echo session_id();
session_destroy();
echo session_id();

如果您仍然遇到困难,您可以尝试创建一个变量来检查,当您销毁会话时您会销毁该变量。

session_start();
$_SESSION['intialized'] = 'This will not print';
$_SESSION = array(); // Unset all variables
session_destroy();
echo $_SESSION['initialized']; // No output

【讨论】:

但是如果你使用 session_write_close(),会话已经关闭,但是 $_SESSION 数据仍然存在,我认为这就是 OP 的意思......你如何检查会话文件本身是否还在使用吗? 是的,您基本上发布了与我相同的解决方案,在关闭它之前设置一个变量(以任何方式)并检查该变量...

以上是关于如何判断会话是不是处于活动状态? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何判断浏览器/选项卡是不是处于活动状态[重复]

如何判断颤振应用程序是不是在android中处于活动状态

检测会话当前是不是处于活动状态并加入而不是开始新的会话

检查 sessionid 已知的 PHP 会话是不是处于活动状态

Android究竟是如何判断是不是在线的?

检查 Android 中的 *** 连接是不是处于活动状态并显示消息? [复制]