在某些情况下,我想取消已打开会话的用户的呼叫。
我使用session_start
来确保已登录的用户一次只能执行一个请求,并且效果很好。但是所有后续通话都将无限期地阻塞,直到所有先前通话都通过为止,在某些情况下(例如行为不当),这是不令人满意的。
通常,我知道所有阻塞调用都会为您提供一个超时参数。 start_session是否有类似的内容?
或者是本着session_opened_by_other_script
的精神,我可以在致电session_start
之前打电话吗?
答案 0 :(得分:0)
现在,我的解决方案是使用exec shell脚本检查会话文件上是否已锁定。 我不建议使用不完全了解它的任何人。
基本上,它尝试使用flock
在会话文件上锁定指定的超时值。如果失败,则存在408请求超时。 (或429个请求,如果有的话)
要使其正常工作,您需要...
请注意,这不是原子。仍然有可能多个请求最终在session_start中等待。但这应该是罕见的事件。大多数电话应该被正确取消,这是我的议程。
class Session {
static public function openWhenClosed() {
if (session_status() == PHP_SESSION_NONE) {
$sessionId = session_id();
if ($sessionId == null)
$sessionId = $_COOKIE[session_name()];
if ($sessionId != null) {
$sessFile = session_save_path()."/sess_".$sessionId;
if (file_exists($sessFile)) {
$timeout = 30; //How long to try to get hold of the session
$fd = 9; //File descriptor to use to try locking the session file.
/*
* This 'trick' is not atomic!!
* After exec returned and session_start() is called there is a time window
* where it can happen that other waiting calls get a successful lock and also
* proceed and get then blocked by session_start(). The longer the sleep value
* the less likely this is to happen. But also the longer the extra delay
* for the call
*/
$sleep = "0.01"; //10ms
//Check if session file is already locked by trying to get a lock on it.
//If it is, try again for $timeout seconds every $sleep seconds
exec("
exec $fd>>$sessFile;
while [ \$SECONDS -lt $timeout ]; do
flock -n $fd;
if [ \$? -eq 0 ]; then exit 0; fi;
sleep $sleep;
done;
exit 1;
", $null, $timedOut);
if ($timedOut) {
http_response_code(408); //408: Request Timeout. Or even better 429 if your apache supports it
die("Request canceled because another request is still running");
}
}
}
session_start();
}
}
}
其他想法:
flock -w <timeout>
很诱人,但那样的话远不止这些
等待在线呼叫将设法使用exec
至
start_session
获得锁定并最终阻塞
session_start
wget
命令来更可靠地进行测试。microtime()
调用自己在您的环境中进行测试