如何在 30 分钟后使 PHP 会话过期?
Posted
技术标签:
【中文标题】如何在 30 分钟后使 PHP 会话过期?【英文标题】:How do I expire a PHP session after 30 minutes? 【发布时间】:2010-10-05 22:26:57 【问题描述】:我需要将会话保持 30 分钟,然后将其销毁。
【问题讨论】:
请注意,至少有两个设置对于设置会话时间至关重要,也许三个。两个肯定很重要的是 session.gc_maxlifetime 和 session.cookie_lifetime (其中 0 与某个长数字不同)。为了完全、100% 确定允许长时间,可能还需要设置 session.save_path,因为在默认情况下存储会话文件的 /tmp 目录上由操作系统控制的清理时间不同。 我不明白你为什么要让会话过期。如果您担心用户在未注销的情况下离开他的计算机,并且未经授权的用户接管了他的计算机,那么您网站上的会话到期不会阻止劫持者访问受害者磁盘上的文件。 @Gqqnbig:不是每个会话都是因为你在这里间接建议的原因而设置的 【参考方案1】:这里可以设置时间
$lifespan = 1800;
ini_set('session.gc_maxlifetime', $lifespan); //default life time
【讨论】:
【参考方案2】:这让我大开眼界,克里斯托弗·克莱默 (Christopher Kramer) 在 2014 年在 https://www.php.net/manual/en/session.configuration.php#115842
在 debian(基于)系统上,在运行时更改 session.gc_maxlifetime 没有实际效果。 Debian 通过设置 session.gc_probability=0 来禁用 PHP 自己的垃圾收集器。相反,它每 30 分钟运行一次 cronjob(参见 /etc/cron.d/php5)来清理旧会话。这个 cronjob 基本上会查看您的 php.ini 并使用 session.gc_maxlifetime 的值来决定要清理哪些会话(请参阅 /usr/lib/php5/maxlifetime)。 [...]
【讨论】:
【参考方案3】:对于初学者来说,PHP 处理会话的方式非常混乱。这可能会通过概述会话的工作原理来帮助他们: how sessions work(custom-session-handlers)
【讨论】:
【参考方案4】:只需存储当前时间,如果通过比较超过 30 分钟,则销毁当前会话。
【讨论】:
【参考方案5】:您可以直接使用数据库作为替代方案。我使用一个 DB 函数来做这件事,我称之为 chk_lgn。
检查登录检查以查看它们是否已登录,并在此过程中将检查的日期时间戳设置为用户数据库行/列中的最后一次活动。
我也在那里检查时间。这暂时适用于我,因为我对每个页面都使用此功能。
附:我见过的没有人提出过纯数据库解决方案。
【讨论】:
【参考方案6】:使用本课程 30 分钟
class Session
public static function init()
ini_set('session.gc_maxlifetime', 1800) ;
session_start();
public static function set($key, $val)
$_SESSION[$key] =$val;
public static function get($key)
if(isset($_SESSION[$key]))
return $_SESSION[$key];
else
return false;
public static function checkSession()
self::init();
if(self::get("adminlogin")==false)
self::destroy();
header("Location:login.php");
public static function checkLogin()
self::init();
if(self::get("adminlogin")==true)
header("Location:index.php");
public static function destroy()
session_destroy();
header("Location:login.php");
【讨论】:
【参考方案7】:PHP 会话在 30 分钟内到期的简单方法。
注意:如果您想更改时间,只需将 30 更改为您想要的时间,不要更改 * 60:这将给出分钟。
以分钟为单位:(30 * 60) 以天为单位: (n * 24 * 60 * 60 ) n = 天数
登录.php
<?php
session_start();
?>
<html>
<form name="form1" method="post">
<table>
<tr>
<td>Username</td>
<td><input type="text" name="text"></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" name="pwd"></td>
</tr>
<tr>
<td><input type="submit" value="SignIn" name="submit"></td>
</tr>
</table>
</form>
</html>
<?php
if (isset($_POST['submit']))
$v1 = "FirstUser";
$v2 = "MyPassword";
$v3 = $_POST['text'];
$v4 = $_POST['pwd'];
if ($v1 == $v3 && $v2 == $v4)
$_SESSION['luser'] = $v1;
$_SESSION['start'] = time(); // Taking now logged in time.
// Ending a session in 30 minutes from the starting time.
$_SESSION['expire'] = $_SESSION['start'] + (30 * 60);
header('Location: http://localhost/somefolder/homepage.php');
else
echo "Please enter the username or password again!";
?>
主页.php
<?php
session_start();
if (!isset($_SESSION['luser']))
echo "Please Login again";
echo "<a href='http://localhost/somefolder/login.php'>Click Here to Login</a>";
else
$now = time(); // Checking the time now when home page starts.
if ($now > $_SESSION['expire'])
session_destroy();
echo "Your session has expired! <a href='http://localhost/somefolder/login.php'>Login here</a>";
else //Starting this else one [else1]
?>
<!-- From here all HTML coding can be done -->
<html>
Welcome
<?php
echo $_SESSION['luser'];
echo "<a href='http://localhost/somefolder/logout.php'>Log out</a>";
?>
</html>
<?php
?>
LogOut.php
<?php
session_start();
session_destroy();
header('Location: http://localhost/somefolder/login.php');
?>
【讨论】:
在这个 MVC 成为常态的时代,将逻辑和表示结合起来是不明智的。 也许我遗漏了一些关于会话的基本知识,但如果会话每 30 分钟被操作系统销毁一次,这有什么好处? @stillstanding 为自己说话[微笑] 我认为 MVC 是可憎的。 即使项目很小,只有一个程序员,MVC 是个好主意吗?我觉得我应该在 MVC 模型中制作自己的项目(或解决问题然后制作 MVC),但是由于缺乏 MVC 经验,它只是成为一个心理障碍“我如何制作这个 MVC?”并且分散了对需要解决方案的初始目标/问题的注意力。 @bsosca 和这里的许多人一样,您应该花更多时间担心问题的解决方案并让 OP 弄清楚这一点,而不是劫持一个问题来提出您认为有效的观点;-) 【参考方案8】:使用时间戳...
<?php
if (!isset($_SESSION))
$session = session_start();
if ($session && !isset($_SESSION['login_time']))
if ($session == 1)
$_SESSION['login_time']=time();
echo "Login :".$_SESSION['login_time'];
echo "<br>";
$_SESSION['idle_time']=$_SESSION['login_time']+20;
echo "Session Idle :".$_SESSION['idle_time'];
echo "<br>";
else
$_SESSION['login_time']="";
else
if (time()>$_SESSION['idle_time'])
echo "Session Idle :".$_SESSION['idle_time'];
echo "<br>";
echo "Current :".time();
echo "<br>";
echo "Session Time Out";
session_destroy();
session_unset();
else
echo "Logged In<br>";
?>
我已使用 20 秒使会话过期。
如果您需要 30 分钟,请添加 1800(以秒为单位的 30 分钟)...
【讨论】:
【参考方案9】:使用session_set_cookie_params
funciton 进行此操作。
在session_start()
调用之前必须调用这个函数。
试试这个:
$lifetime = strtotime('+30 minutes', 0);
session_set_cookie_params($lifetime);
session_start();
查看更多:http://php.net/manual/function.session-set-cookie-params.php
【讨论】:
【参考方案10】:请在每个页面中加载的包含文件中使用以下代码块。
$expiry = 1800 ;//session expiry required after 30 mins
if (isset($_SESSION['LAST']) && (time() - $_SESSION['LAST'] > $expiry))
session_unset();
session_destroy();
$_SESSION['LAST'] = time();
【讨论】:
【参考方案11】:嗯,我明白上面的答案是正确的,但它们是在应用程序级别,我们为什么不简单地使用.htaccess
文件来设置过期时间?
<IfModule mod_php5.c>
#Session timeout
php_value session.cookie_lifetime 1800
php_value session.gc_maxlifetime 1800
</IfModule>
【讨论】:
这个方法每次进入页面都会更新session?【参考方案12】:在会话中存储时间戳
<?php
$user = $_POST['user_name'];
$pass = $_POST['user_pass'];
require ('db_connection.php');
// Hey, always escape input if necessary!
$result = mysql_query(sprintf("SELECT * FROM accounts WHERE user_Name='%s' AND user_Pass='%s'", mysql_real_escape_string($user), mysql_real_escape_string($pass));
if( mysql_num_rows( $result ) > 0)
$array = mysql_fetch_assoc($result);
session_start();
$_SESSION['user_id'] = $user;
$_SESSION['login_time'] = time();
header("Location:loggedin.php");
else
header("Location:login.php");
?>
现在,检查时间戳是否在允许的时间窗口内(1800 秒是 30 分钟)
<?php
session_start();
if( !isset( $_SESSION['user_id'] ) || time() - $_SESSION['login_time'] > 1800)
header("Location:login.php");
else
// uncomment the next line to refresh the session, so it will expire after thirteen minutes of inactivity, and not thirteen minutes after login
//$_SESSION['login_time'] = time();
echo ( "this session is ". $_SESSION['user_id'] );
//show rest of the page and all other content
?>
【讨论】:
【参考方案13】:您应该实现自己的会话超时。其他人提到的两个选项(session.gc_maxlifetime 和session.cookie_lifetime)都不可靠。我会解释原因。
第一:
session.gc_maxlifetimesession.gc_maxlifetime 指定在多少秒后数据将被视为“垃圾”并被清理。垃圾收集发生在会话开始期间。
但垃圾收集器仅以session.gc_probability 除以session.gc_divisor 的概率启动。并且使用这些选项的默认值(分别为 1 和 100),机会只有 1%。
好吧,您可以简单地调整这些值,以便更频繁地启动垃圾收集器。但是当垃圾收集器启动时,它会检查每个注册会话的有效性。这是成本密集型的。
此外,当使用 PHP 的默认 session.save_handler 文件时,会话数据存储在 session.save_path 指定路径中的文件中。使用该会话处理程序,会话数据的年龄是根据文件的最后修改日期而不是最后访问日期计算的:
注意:如果您使用默认的基于文件的会话处理程序,您的文件系统必须跟踪访问时间 (atime)。 Windows FAT 不支持,因此如果您遇到 FAT 文件系统或任何其他时间跟踪不可用的文件系统,您将不得不想出另一种方法来处理垃圾收集您的会话。从 PHP 4.2.3 开始,它使用 mtime(修改日期)而不是 atime。因此,您不会遇到时间跟踪不可用的文件系统问题。
因此,还可能会出现会话数据文件被删除而会话本身仍然被认为是有效的情况,因为会话数据最近没有更新。
第二个:
session.cookie_lifetimesession.cookie_lifetime 指定发送到浏览器的 cookie 的生命周期(以秒为单位)。 […]
是的,没错。这只会影响 cookie 的生命周期,并且会话本身可能仍然有效。但是使会话无效是服务器的任务,而不是客户端的任务。所以这没有任何帮助。事实上,将 session.cookie_lifetime 设置为 0
会使会话的 cookie 成为真正的 session cookie,它只在浏览器关闭之前有效。
结论/最佳解决方案:
最好的解决方案是实现您自己的会话超时。使用一个简单的时间戳来表示最后一个活动(即请求)的时间,并在每个请求中更新它:
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800))
// last request was more than 30 minutes ago
session_unset(); // unset $_SESSION variable for the run-time
session_destroy(); // destroy session data in storage
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
使用每个请求更新会话数据也会更改会话文件的修改日期,以便垃圾收集器不会过早删除会话。
您还可以使用额外的时间戳定期重新生成会话 ID,以避免像session fixation 这样的会话受到攻击:
if (!isset($_SESSION['CREATED']))
$_SESSION['CREATED'] = time();
else if (time() - $_SESSION['CREATED'] > 1800)
// session started more than 30 minutes ago
session_regenerate_id(true); // change session ID for the current session and invalidate old session ID
$_SESSION['CREATED'] = time(); // update creation time
注意事项:
session.gc_maxlifetime
至少应等于此自定义过期处理程序的生命周期(本例中为 1800);
如果您想在活动 30 分钟后而不是自开始 30 分钟后使会话过期,您还需要使用带有过期时间的setcookie
time()+60*30
以保持会话 cookie 处于活动状态。
【讨论】:
如果你想检查“非活动时间”,你怎么能改变这个?换句话说,用户登录,只要他们继续使用该网站,它就不会将他们注销。但是,如果它们在 30 分钟内处于非活动状态,它会注销它们吗? @Metropolis:使用类似于$_SESSION['CREATED']
的$_SESSION['LAST_ACTIVITY']
之类的东西,您可以在其中存储用户最后一次活动的时间,但在每次请求时更新该值。现在,如果该时间与当前时间的差大于 1800 秒,则会话未使用超过 30 分钟。
@Metropolis: session_unset
与 $_SESSION = array()
相同。
@Gumbo - 我有点困惑,您不应该将您的代码与ini_set('session.gc-maxlifetime', 1800)
结合使用吗?否则,您的会话信息可能会在您的会话仍然有效时被破坏,至少如果 ini 设置是标准的 24 分钟。还是我错过了什么?
@jeron:是的,你应该这样做。但请注意,如果使用会话保存处理程序files
,session.gc_maxlifetime 取决于文件的最后修改日期。所以 session.gc_maxlifetime 应该至少等于这个自定义过期处理程序的生命周期。【参考方案14】:
这篇文章展示了几种控制会话超时的方法:http://bytes.com/topic/php/insights/889606-setting-timeout-php-sessions
恕我直言,第二个选项是一个不错的解决方案:
<?php
/***
* Starts a session with a specific timeout and a specific GC probability.
* @param int $timeout The number of seconds until it should time out.
* @param int $probability The probablity, in int percentage, that the garbage
* collection routine will be triggered right now.
* @param strint $cookie_domain The domain path for the cookie.
*/
function session_start_timeout($timeout=5, $probability=100, $cookie_domain='/')
// Set the max lifetime
ini_set("session.gc_maxlifetime", $timeout);
// Set the session cookie to timout
ini_set("session.cookie_lifetime", $timeout);
// Change the save path. Sessions stored in teh same path
// all share the same lifetime; the lowest lifetime will be
// used for all. Therefore, for this to work, the session
// must be stored in a directory where only sessions sharing
// it's lifetime are. Best to just dynamically create on.
$seperator = strstr(strtoupper(substr(PHP_OS, 0, 3)), "WIN") ? "\\" : "/";
$path = ini_get("session.save_path") . $seperator . "session_" . $timeout . "sec";
if(!file_exists($path))
if(!mkdir($path, 600))
trigger_error("Failed to create session save path directory '$path'. Check permissions.", E_USER_ERROR);
ini_set("session.save_path", $path);
// Set the chance to trigger the garbage collection.
ini_set("session.gc_probability", $probability);
ini_set("session.gc_divisor", 100); // Should always be 100
// Start the session!
session_start();
// Renew the time left until this session times out.
// If you skip this, the session will time out based
// on the time when it was created, rather than when
// it was last used.
if(isset($_COOKIE[session_name()]))
setcookie(session_name(), $_COOKIE[session_name()], time() + $timeout, $cookie_domain);
【讨论】:
【参考方案15】:使用如下函数实际上很容易。它使用数据库表名 'sessions' 和字段 'id' 和 'time'。
每当用户再次访问您的站点或服务时,您应该调用此函数来检查其返回值是否为 TRUE。如果为 FALSE,则用户已过期,会话将被销毁(注意:此函数使用数据库类来连接和查询数据库,当然您也可以在函数中执行此操作或类似的操作):
function session_timeout_ok()
global $db;
$timeout = SESSION_TIMEOUT; //const, e.g. 6 * 60 for 6 minutes
$ok = false;
$session_id = session_id();
$sql = "SELECT time FROM sessions WHERE session_id = '".$session_id."'";
$rows = $db->query($sql);
if ($rows === false)
//Timestamp could not be read
$ok = FALSE;
else
//Timestamp was read succesfully
if (count($rows) > 0)
$zeile = $rows[0];
$time_past = $zeile['time'];
if ( $timeout + $time_past < time() )
//Time has expired
session_destroy();
$sql = "DELETE FROM sessions WHERE session_id = '" . $session_id . "'";
$affected = $db -> query($sql);
$ok = FALSE;
else
//Time is okay
$ok = TRUE;
$sql = "UPDATE sessions SET time='" . time() . "' WHERE session_id = '" . $session_id . "'";
$erg = $db -> query($sql);
if ($erg == false)
//DB error
else
//Session is new, write it to database table sessions
$sql = "INSERT INTO sessions(session_id,time) VALUES ('".$session_id."','".time()."')";
$res = $db->query($sql);
if ($res === FALSE)
//Database error
$ok = false;
$ok = true;
return $ok;
return $ok;
【讨论】:
【参考方案16】:if (isSet($_SESSION['started']))
if((mktime() - $_SESSION['started'] - 60*30) > 0)
//Logout, destroy session, etc.
else
$_SESSION['started'] = mktime();
【讨论】:
【参考方案17】:这是为了在设定的时间后注销用户吗?在注册时设置会话创建时间(或到期时间),然后检查每个页面加载是否可以处理。
例如:
$_SESSION['example'] = array('foo' => 'bar', 'registered' => time());
// later
if ((time() - $_SESSION['example']['registered']) > (60 * 30))
unset($_SESSION['example']);
编辑:不过我感觉你的意思是别的。
您可以使用session.gc_maxlifetime
ini 设置在某个生命周期后取消会话:
编辑: ini_set('session.gc_maxlifetime', 60*30);
【讨论】:
session.gc-maxlifetime 可能是最好的选择。 会话 cookie 生命周期存在一些问题,最值得注意的是,它依赖于客户端来强制执行。 cookie 生命周期允许客户端清理无用/过期的 cookie,不要与任何与安全相关的内容混淆。以上是关于如何在 30 分钟后使 PHP 会话过期?的主要内容,如果未能解决你的问题,请参考以下文章