PHP:如何检测会话是否已自动过期?

[英]PHP: how to detect if a session has expired automatically?


When a session expiration time is defined, is it possible to call an event listener when it expires?

定义会话到期时间时,是否可以在事件监听器到期时调用它?

If it is not possible, is it possible to run a cron job to check if a session has expired?

如果不可能,是否可以运行cron作业来检查会话是否已过期?

NOTE: I'm interested in a server solution. I'm talking about the case there is a session expiration time defined, and the session finishes automatically because that period expired.

注意:我对服务器解决方案感兴趣。我在谈论定义了会话到期时间的情况,并且会话因为该期限到期而自动结束。

12 个解决方案

#1


10  

is it possible to call an event listener when it expires?

可以在事件监听器到期时调用它吗?

The short answer is NO

最简洁的答案是不

There are a few oddities people tend to ignore about sessions. With the default handler, the session does not expire when gc_maxlifetime ends - this is just the time at which the data becomes eligible for automatic deletion. There is no action by the owner of the session which triggers the subsequent removal of the session - its a side effect of someone else's session.

人们往往会忽略一些关于会话的奇怪之处。使用默认处理程序时,会话在gc_maxlifetime结束时不会过期 - 这只是数据符合自动删除条件的时间。会话所有者没有动作会触发随后的会话删除 - 这是其他人会话的副作用。

When session_write_close() is called (either explicitly, or implicitly by the code ending), if the random number generator, tweaked by the relevant gc settings throws the right number then PHP will go looking for data past its TTL and remove it. If you want to trigger an action at this point, then you need to break the default handler and apply your own. That means you not only have to provide a mechanism for identifying and removing sessions but also a way of deciding whether your handler should kick in and how many sessions it should delete - you don't want a runaway process killing your server.

当调用session_write_close()时(显式或隐式地通过代码结束),如果随机数生成器(通过相关gc设置调整)会抛出正确的数字,那么PHP将继续寻找超过其TTL的数据并将其删除。如果您想在此时触发操作,则需要中断默认处理程序并应用自己的操作。这意味着您不仅需要提供一种识别和删除会话的机制,还需要一种方法来决定您的处理程序是否应该启动以及它应该删除多少个会话 - 您不希望失控的进程杀死您的服务器。

In Ubuntu, session.gc_probability = 0, and it is a cron job which carries out the function of removing stale data files.

在Ubuntu中,session.gc_probability = 0,它是一个执行删除陈旧数据文件功能的cron作业。

A very important piece of information missing from your question is the reason for deleting the session.

您的问题中缺少的一条非常重要的信息是删除会话的原因。

If you want to prevent sensitive data from persisting on the filesystem, then a better solution is to encrypt the data using a key stored (only) in another client side cookie. That way you completely eliminate the storage of unprotected data on your server. (note that suhosin's encrypted sessions use a key derived from data about the client and a static key stored on the same host - this is significantly less secure than a randomly generated key). Here's one I prepared earlier.

如果要防止敏感数据在文件系统上持久存在,那么更好的解决方案是使用另一个客户端cookie中存储的密钥(仅)来加密数据。这样您就可以完全消除服务器上未受保护数据的存储。 (请注意,suhosin的加密会话使用从客户端数据派生的密钥和存储在同一主机上的静态密钥 - 这比随机生成的密钥安全性低得多)。这是我之前准备的。

If you merely want to prevent access after the gc_maxlifetime has expired, you should consider a custom session handler which treats a stale session as missing. i.e. it doesn't really logout at expiry, but any subsequent requests can no longer be associated with the session. The security layer in the Stackable session handler examples implements such a control.

如果您只想在gc_maxlifetime过期后阻止访问,则应考虑将自定义会话处理程序视为缺失的自定义会话处理程序。即它在到期时并未真正注销,但任何后续请求都不能再与会话相关联。 Stackable会话处理程序示例中的安全层实现了这样的控制。

OTOH if you want to use data from within the session in your event listener, then that's a different story - you certainly won't be able to use either Suhosin's or my encryption for the data. But a further complication is that the (default) format for the data is different from that used elsewhere. You need to use session_encode() and session_decode(). The former will only read data from the $_SESSION array so eavesdropping on sessions requires some careful subversion of session_id() and session_start(). session_decode() however will happily convert anything you throw at it.

OTOH如果你想在事件监听器中使用会话中的数据,那么这是一个不同的故事 - 你肯定无法使用Suhosin或我的加密数据。但更复杂的是,数据的(默认)格式与其他地方使用的格式不同。您需要使用session_encode()和session_decode()。前者只会从$ _SESSION数组中读取数据,因此对会话的窃听需要对session_id()和session_start()进行一些小心的颠覆。然而,session_decode()会愉快地转换你抛出的任何东西。

In recent versions of PHP you can specify a different function pair to use for serialization/deserialization.

在PHP的最新版本中,您可以指定用于序列化/反序列化的不同函数对。

It is vitally important to consider the potential impact of __wakeup() methods when considering a session garbage collector which is going to read the data in the session files. Related to this is a requirement that the process which handles such garbage collection runs under the same uid as the original PHP process which created the session data (otherwise you have a privilege escalation backdoor). But if the session storage substrate is file-based then that would need to be the case anyway.

在考虑将要读取会话文件中的数据的会话垃圾收集器时,考虑__wakeup()方法的潜在影响至关重要。与此相关的是要求处理此类垃圾收集的进程在与创建会话数据的原始PHP进程相同的uid下运行(否则您具有权限提升后门)。但是,如果会话存储基板是基于文件的,那么无论如何都需要这样。

There are implementations of session data deserializer written in languages other than PHP which would provide protection against __wakeup() attacks (try Google) although that might be overkill to solve the problem and they are probably not being actively maintained. If this is a concern then a more appropriate solution might be to use the WDDX (xml) serializer and use a conventional XML parser to read the data back in your GC engine.

会话数据解串器的实现是用PHP以外的语言编写的,可以防止__wakeup()攻击(试试谷歌),虽然这可能有点过头来解决问题并且它们可能没有被主动维护。如果这是一个问题,那么更合适的解决方案可能是使用WDDX(xml)序列化程序并使用传统的XML解析器来读取GC引擎中的数据。

If you are using the native handler for normal reading and writing of the data but want to implement your own garbage collector then you're going to need code to map the session_id to a file path. If you follow the link I gave to the PHP classes above, you'll see pure PHP implementation of several session handlers, including ones which are compatible with the native handler.

如果您使用本机处理程序来正常读取和写入数据但想要实现自己的垃圾收集器,那么您将需要代码将session_id映射到文件路径。如果您按照我给上面的PHP类的链接,您将看到几个会话处理程序的纯PHP实现,包括与本机处理程序兼容的那些。

But I would strongly encourage you to exhaust every other avenue for solving whatever the underlying problem is before choosing to read back session data at the time of deletion.

但是我强烈建议你在选择在删除时回读会话数据之前用尽所有其他途径解决任何潜在问题。

#2


3  

It sounds like you want to wipe out the session at a given time on the server side. What you will want to do is define your own custom session handler and put the session data in a system you fully control. So, let's say you move your session handling into a database. Now all your session data is fully within your control. Below is an abbreviated custom session handler

听起来你想要在服务器端的给定时间消灭会话。您要做的是定义自己的自定义会话处理程序,并将会话数据放在您完全控制的系统中。所以,假设您将会话处理移动到数据库中。现在,您的所有会话数据都完全在您的控制之内。下面是一个缩写的自定义会话处理程序

class Sessions implements \SessionHandlerInterface {
    /**
     * Write Session Data
     * @param string $id Session ID to delete
     * @param string $data Data to write into the session
     */
    public function write($id, $data) {
        $time = time() + 3600; // 1 hour for the sake of example
        $sql = 'REPLACE INTO your_session_table
                SET session_id = ?,
                    data = ?,
                    expires = ?';
        $this->db->query($sql);
        $prep = $this->db->prepare($sql);
        $prep->bind_param('ssi', $id, $data, $time);
        $prep->execute();
    }
}

What you can do here is you can run your own cleanup script here. Now, I would suggest you use an intermediate memory store (memcached, Redis, etc) so you don't HAVE to load from the DB every time. You'll want to clean that out when you run your cleanup script (i.e pull all the sessions about to expire and remove from cache). But a simple SQL statement here (run on, say, a 5 minute cron job) cleans out sessions on demand

你在这里可以做的是你可以在这里运行自己的清理脚本。现在,我建议您使用中间存储器(memcached,Redis等),这样您就不必每次都从DB加载。在运行清理脚本时,您需要清除它(即拉出所有会话即将过期并从缓存中删除)。但是这里的一个简单的SQL语句(例如,运行5分钟的cron作业)可以按需清除会话

 DELETE FROM your_session_table
 WHERE expires < now();

#3


3  

I'm making a couple of assumptions here.

我在这里做了几个假设。

I'm assuming, for whatever reason, you want to be able to track the expired session cold, that is, no supplementary tracking of session data via a database or a second 'hidden' session that acts as a structure to determine when a pseudo-session has expired and acting appropriately.

我假设,无论出于何种原因,您希望能够跟踪过期的会话冷,即,没有通过数据库或第二个“隐藏”会话补充跟踪会话数据,该会话充当确定何时伪的结构 - 激情已经过期并且行动恰当。

I'm also assuming that hack attempts on your session aren't important at this point. Man-in-the-middle and XSS attacks can capture session ID's and plug them into your system and it would be hard to detect.

我还假设你的会话上的黑客攻击在这一点上并不重要。中间人和XSS攻击可以捕获会话ID并将其插入您的系统,并且很难检测到。

This sort of thing is handled by session cookies in php by default. I'm also assuming that your session identification and session start are also handled by cookies.

这种事情默认由php中的会话cookie处理。我还假设您的会话标识和会话开始也由cookie处理。

There's almost no way of doing this 'live', which is to say, keep a socket open to the server to detect the moment the session expires. PHP was not designed to work that way; the security issues are expansive. As well, if you're allowing someone to access your server remotely through a secure channel, why are you bothering with sessions in the first place?

几乎没有办法做这个'实时',也就是说,保持套接字打开服务器以检测会话到期的时刻。 PHP不是为那种方式工作而设计的;安全问题是广泛的。同样,如果您允许某人通过安全通道远程访问您的服务器,为什么您首先要打扰会话?

$sessionCookie = 'myPHPSessCookieName';
$isSessionExpired = false;

if (isset($_COOKIE[$sessionCookie])) {
  // check cookie expiry time to show warnings / near expiry behaviours
} else {
  // handle missing cookie / session
  $isSessionExpired = true;
}

define('SESSION_EXPIRED', $isSessionExpired);    
session_start(['name' => $sessionCookie]);

Checking for the cookie has to happen prior to starting the session otherwise you run the risk of giving yourself a false positive.

检查cookie必须在开始会话之前进行,否则你可能会给自己一个误报。

[edit: javascript solution]

[编辑:javascript解决方案]

If you wish to produce a behaviour that simulates a socket, javascript can do this. The client's browser will ping the server with AJAX requests to check the status of their session, and once it detects that it is expired, you can induce a behaviour of your choice. Note: javascript in its current state is fundamentally insecure. All of the data and security related work ought to be done by the server if at all possible.

如果您希望生成模拟套接字的行为,javascript可以执行此操作。客户端的浏览器将使用AJAX请求ping服务器以检查其会话的状态,一旦检测到它已过期,您就可以引发您选择的行为。注意:javascript在当前状态下基本上是不安全的。如果可能的话,所有与数据和安全相关的工作都应由服务器完成。

client.php:

<script>
  $(function(){
    var messageElem = $('#selectorForDisplayElementHere');
    var timeoutID = null;

    var checkSession = function(){
      $
        .ajax({/* your ajax params: url, data, dataType, method etc. */})
        .then(function(response){
          messageElem.html(response.html);
          if (response.stop === 1) { 
            clearTimeout(timeoutID);
          }
        });
    };

    var timeoutID = setInterval(checkSession, 5000); // Every 5 seconds
  });
</script>

ajax.php:

$response = ['html' => '', 'stop' => 0];

if (SESSION_EXPIRED) {
  $response ['html'] = '<b>Your session has expired. Please log in again.</b>';
  $response['stop'] = 1;
}

echo(json_encode($response));

This is a very simple handling system that can be readily enhanced with all sorts of functionality. It uses the ubiquitous jQuery library and standard php and html/javascript functionality.

这是一个非常简单的处理系统,可以通过各种功能轻松增强。它使用无处不在的jQuery库和标准的php和html / javascript功能。

#4


2  

You could store the connection time somewhere (table,...) so you can see since when the user was connected and do a regular check (cron or service) to see if the date has passed a specific duration (5 minutes,...)

您可以将连接时间存储在某个地方(表格,...),这样您就可以看到自用户何时连接并定期检查(cron或服务)以查看日期是否已经过了特定的持续时间(5分钟,... 。)

But if you want to warn the user (loss of document,...) you might want to do a Javascript window.setTimeout on client side.

但是如果你想警告用户(丢失文件,......)你可能想在客户端做一个Javascript window.setTimeout。

#5


2  

Set initial session on one page.

在一个页面上设置初始会话。

example: Login.php

<?php
session_start();
if(...){
   // success
   $_SESSION['logged_time'] = time();
}
?>

now check the session expired or not in another page

现在检查会话是否已过期或不在另一页面中

example: Index.php

<?php
   session_start();
   $login_session_duration = 60; // 1 minute 

   if($_SESSION['logged_time']){
      if(((time() - $_SESSION['logged_time']) > $login_session_duration)){ 
         echo 'session expired';
         // session will be exired after 1 minutes
      }else{
         echo 'session alive';
      }
   }
?>

#6


2  

Each time you send http request to server then check the session expiration time. if session is valid do your stuff, other wise redirect where you want.

每次向服务器发送http请求,然后检查会话到期时间。如果会话有效,请做你的事情,其他明智的重定向你想要的地方。

Or

You can do one thing to save your time. Create a method which checks current session validity and call it in your http request.

你可以做一件事来节省你的时间。创建一个检查当前会话有效性的方法,并在您的http请求中调用它。

#7


2  

I think what you are looking for may be here: Access active sessions in PHP

我认为您正在寻找的可能是:在PHP中访问活动会话

Summarized you would have to create your own session handler. That's the server side.

总结一下,您必须创建自己的会话处理程序。这是服务器端。

If you want to add client side alerts you could store the session expiration time limit used in a javascript timer. If there is only x minutes left pop up a message (maybe with a countdown) displaying to the user "Your session will time out in: (show timer here)."

如果要添加客户端警报,可以存储javascript计时器中使用的会话到期时间限制。如果只剩下x分钟,则会弹出一条消息(可能带有倒计时),向用户显示“您的会话将超时:(此处显示计时器)”。

#8


2  

You can also use this :)

你也可以用这个:)

<? 
session_start();

$time = 3600; // Set expire time with secends.
// Star session here 
if (isset($_SESSION['time']) && (time() - $_SESSION['time']) > $time) {
   // Your Code Here to logout
   header('location: /auth/logout');
   exit();
} else {
  $_SESSION['time'] = time();
 }

#9


1  

Well very simple way to do is

非常简单的方法是

get current_time

$current_time=time();

get session expire time which is set in ini file.

获取在ini文件中设置的会话过期时间。

$maxlifetime = ini_get("session.gc_maxlifetime");

Use this value in javascript/query and when time is expire by mannual calculation use a alert to notify user or write script u wish to do.

在javascript / query中使用此值,当时间到期时,通过手动计算使用警报来通知用户或编写您希望执行的脚本。

OR

You can store these dates in separate cookie variable:

您可以将这些日期存储在单独的cookie变量中:

session_expire=1525357483057

But user can change this variable.

但是用户可以更改此变量。

#10


0  

Try checking it against session_cache_expire() if it is zero then your session has ended. Would probably have to be implemented on your action handler. This does not set your session on the server, only solves the problem of your clients browser knowing when it will expire, which is serving as your auto detect...

尝试对session_cache_expire()进行检查,如果它为零则会话结束。可能必须在您的操作处理程序上实现。这不会在服务器上设置会话,只能解决客户端浏览器知道何时到期的问题,这可以作为您的自动检测...

http://php.net/manual/en/function.session-cache-expire.php

#11


-1  

We can use the session variable that you have defined.

我们可以使用您定义的会话变量。

if(isset($_SESSION['variable'])){
    //do something
}

example:

if(isset($_SESSION['name'])){
    echo "Session has not expired"; 
}

#12


-1  

What you would do is run a jQuery AJAX request on a timed interval to check if the session is expired and when it does you can send the users to a logout.

你要做的是在一个定时间隔运行一个jQuery AJAX请求来检查会话是否过期,什么时候你可以发送用户注销。

Ajax Code

var checkSession;
function SessionCheck(){
     var str="sessionCheck=true";
     jQuery.ajax({
                   type:"POST",
                   URL:"sessionCheck.php"
                   data: str,
                   success: function(res){
                        if(res==1){
                            //do session expired logic here
                        }
                   }
                });
    }
sessions = setInterval(SessionCheck, 1000); //This will run the SessionCheck function every second

PHP Code

session_start();
$data = $_SESSION["sessionVariable"];
if($data == ''){
    echo "1";
}
else{
    echo "0";
}

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2016/12/15/83d274ef5f26b15a16e3813bbeb6b1db.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com