我们正在为客户锁定一些库存,锁定库存的表包含将其锁定的会话ID以及有关客户端的其他信息。当会话到期时,我们想要解锁该库存,以便其他人可以购买它。因为我们在表中注册了session_id(),知道它,有没有办法检查会话在PHP中是否仍然有效?
如果我们使用数据库来保持会话,我们可以检查行是否到那里以及最后一个活动是什么时候,在memcached中我们可以找出会话的密钥并检查它,因为文件会话我们可以做同样的事情,找出会话的文件名并检查文件是否存在。
无论你在哪里举行会议,是否有适用于所有地方的东西?
答案 0 :(得分:3)
您无法使用session_id
,session_start
等
这些函数处理请求页面的用户会话。您无法使用它们来处理所有用户的列表。会议很容易。您必须担心用户创建的会话(www-data
)和cli
脚本的相同权限,这些脚本将被执行以查找应解锁的会话 - 会话'文件仅供所有者使用。
另外,会话访问时间已更改,因此每次检查会话时都会更改其时间和影响会话'行为。
如何更轻松地执行锁定
通常锁定货物只需要一段固定的时间,比如20分钟。但是,如果您希望在会话处于活动状态时选择库存,则可以稍微修改现有代码。
last_activity
字段旁边添加一个新字段session_id
(一次简单迁移)NOW
(只需在模型上调用$row->touch()
- docs)。last_activity < NOW - delta
的每一行,其中delta
是会话超时。使用这种方法可以避免处理每个会话驱动程序。
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_id
和session_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)
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