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

时间:2017-02-17 03:50:06

标签: php session laravel-5.3

我们正在为客户锁定一些库存,锁定库存的表包含将其锁定的会话ID以及有关客户端的其他信息。当会话到期时,我们想要解锁该库存,以便其他人可以购买它。因为我们在表中注册了session_id(),知道它,有没有办法检查会话在PHP中是否仍然有效?

如果我们使用数据库来保持会话,我们可以检查行是否到那里以及最后一个活动是什么时候,在memcached中我们可以找出会话的密钥并检查它,因为文件会话我们可以做同样的事情,找出会话的文件名并检查文件是否存在。

无论你在哪里举行会议,是否有适用于所有地方的东西?

9 个答案:

答案 0 :(得分:3)

您无法使用session_idsession_start

这些函数处理请求页面的用户会话。您无法使用它们来处理所有用户的列表。会议很容易。您必须担心用户创建的会话(www-data)和cli脚本的相同权限,这些脚本将被执行以查找应解锁的会话 - 会话'文件仅供所有者使用。

另外,会话访问时间已更改,因此每次检查会话时都会更改其时间和影响会话'行为。

如何更轻松地执行锁定

通常锁定货物只需要一段固定的时间,比如20分钟。但是,如果您希望在会话处于活动状态时选择库存,则可以稍微修改现有代码。

  1. last_activity字段旁边添加一个新字段session_id(一次简单迁移)
  2. 每个请求都会将其更新为NOW(只需在模型上调用$row->touch() - docs)。
  3. 创建一个crontab任务,删除last_activity < NOW - delta的每一行,其中delta是会话超时。
  4. 使用这种方法可以避免处理每个会话驱动程序。

    P.S。您可能希望确保在一段时间read this question之后会话已经死亡。如果此作业由垃圾收集器完成,则会话生存期可能会有所不同。

答案 1 :(得分:3)

总之,您在询问PHP中是否存在访问任何会话的通用方法。虽然问题中的用例似乎是合理的,但能够做到你所建议的影响会带来巨大的安全风险。

这就是为什么PHP中的内置会话功能可以帮助您完成所需的操作。

理论上,您可以使用inbuilt PHP session functions指定特定会话ID并查找它们。我刚做了一些简单的测试而没有取得多大成功。只有一个内置功能可用于加载会话&#39; session_start&#39;需要重复调​​用。该手册明确指出这不会起作用:

  

从PHP 4.3.3开始,在先前启动会话之后调用session_start()将导致级别E_NOTICE的错误。此外,第二个会话开始将被忽略。

可能仍然可以解决这个问题,可能还有分叉或其他聪明的小提琴。但是您的代码将以一种模糊的方式工作,这可能会破坏未来的PHP更新或可能干扰现有的实时会话。

最好的解决方案是编写一个特定于正在使用的会话处理程序的工具,该工具允许对会话进行只读访问。问题中的场景甚至不需要访问会话数据,只需要用于计算到期时间的时间戳信息。

对于&#39;文件&#39;会话处理。可以使用ini_get('session.save_path');发现会话文件存储的路径。检查脚本可能需要使用与Web服务器相同的权限运行才能访问此位置。

脚本需要按计划频繁运行,以检查过期的会话并从库存中删除锁定。

答案 2 :(得分:3)

您可以实际使用session_idsession_start来实现此目的。

$ids = [
            '135b29ef958a23418f2a804474787305', // active session
            '135b29ef958a23418f2a804474787306', // inactive session
            '135b29ef958a23418f2a804474787305', // active session
        ];

foreach($ids as $id)
{
    session_id($id);
    session_start(); 

    $status = isset($_SESSION['logged_in']); 

    print( ($status ? 1 : 0) . PHP_EOL);
    session_abort();
}

检查是否存在始终设置的会话变量。确保这不是新创建的会话。

您必须检查这是否不会重置会话中的生命周期计数器。在我的系统上,它不会影响生命周期,直到会话中的某些内容发生变化

使用session_abort更新

修改以循环并检查多个会话ID

答案 3 :(得分:3)

会话文件夹中存在检查会话:

echo ini_get('session.save_path');

例如在我的文件夹会话ID文件中:

sess_l75lm4ktlhvlu566n8i6do8k71

设置会话参数(例如):

ini_set('session.cookie_lifetime',100)

session_destroy()之后;文件已从会话文件夹中删除:

        if (file_exists($sessionfile)) {
        echo "exists";
    }else{
        echo "not exist"
    }

或者您可以在关闭浏览器并解锁产品(firefox测试)时发送js请求:

    <script type="text/javascript">
    // alert(document.cookie);

    window.onbeforeunload = function () {
    return "Do you really want to close?";
    };
    window.onunload = function () {
    return "Do you really want to close?";
    };

    $(window).on('beforeunload', function(){ alert ('Send post to unlock product')});
    $(window).unload( function () { alert("'Send post to unlock product'"); } );
</script>

答案 4 :(得分:2)

您可以在您的函数中放入代码,该代码会注销用户,该代码应该处理与该会话相关的清单的解锁。

答案 5 :(得分:2)

关闭浏览器窗口会触发事件beforeunload,这只能由Javascript处理。您可以为该事件放入一个Javascript事件处理程序,这会使AJAX回调到该站点,就像这样(给出jQuery示例):

$(window).bind("beforeunload", function() { 
    $.ajax({
        url: "http://example.com/destroySession.php"
    });
});

回调该站点可能是针对一个页面,该页面根据用户的sessionID解锁库存项目,之后调用PHP命令session_destroy()。例如:

<?php

// Load your config bootstrap / etc.

session_start();

// Unlock target inventory items

session_destroy();

?>

答案 6 :(得分:2)

PHP v5.4及更高版本可以使用

session_status ,也许这就是原因。

您可以尝试 session_id

session_id()返回当前会话的会话ID或空字符串(&#34;&#34;),如果没有当前会话(不存在当前会话ID)。< / p>

答案 7 :(得分:2)

您可以做的是在每个用户会话中保留一个标志(例如,last_activity),以检查您的会话是否处于活动状态,并确定是否解锁该项目或将其锁定。 这对我有用:

ul li:nth-child(n+4){display:none;}

注意:我不确定这是否适用于不同的系统。它可能取决于你的php会话设置。

意见:会话用于特定功能。我认为在属于不同用户的会话之间切换不是会话的目的。无论如何,在您为库存实施锁定解决方案之前,我建议您使用此解决方法。

如果你只依赖会话是否已经过期,请检查你的会话设置(session.gc_maxlifetime,session.gc_probability&amp; session.gc_divisor),这也可以helpful

答案 8 :(得分:1)

// correct way
$id = 'abc';
session_id($id);
session_start();
$isActive = (session_status() === PHP_SESSION_ACTIVE);
session_write_close();
var_dump($isActive);

// tricky way (root required)
$id = 'abc';
$isActive = false;
$sessionTimeout = (int)ini_get('session.gc_maxlifetime');
$rdi = new RecursiveDirectoryIterator(session_save_path(), FilesystemIterator::SKIP_DOTS);
$rii = new RecursiveIteratorIterator($rdi);
$ri = new RegexIterator($rii, preg_quote("/sess_$id/"), RegexIterator::MATCH);
/**
 * @var $fileInfo SplFileInfo
 */
foreach ($ri as $fileInfo) {
    $expiredAt = $fileInfo->getMTime() + $sessionTimeout;
    $isActive = $expiredAt > time();
    if ($isActive) {
        break;
    } 
}
var_dump($isActive);

通常,要将会话ID存储在DB中而不是将会话保存在那里 - 这是个坏主意。

查看http://php.net/manual/en/function.session-set-save-handler.php

根据您的个人资料,您知道yii。 有一个很好的实施例子:

https://github.com/yiisoft/yii2/blob/master/framework/web/DbSession.php

https://github.com/yiisoft/yii2/blob/master/framework/web/Session.php#L97

https://github.com/yiisoft/yii2/blob/master/framework/web/Session.php#L148