PHP:如何检查session_start是否会阻塞或使其超时

时间:2019-03-07 12:18:03

标签: php session

在某些情况下,我想取消已打开会话的用户的呼叫。 我使用session_start来确保已登录的用户一次只能执行一个请求,并且效果很好。但是所有后续通话都将无限期地阻塞,直到所有先前通话都通过为止,在某些情况下(例如行为不当),这是不令人满意的。

通常,我知道所有阻塞调用都会为您提供一个超时参数。 start_session是否有类似的内容?

或者是本着session_opened_by_other_script的精神,我可以在致电session_start之前打电话吗?

1 个答案:

答案 0 :(得分:0)

现在,我的解决方案是使用exec shell脚本检查会话文件上是否已锁定。 我不建议使用不完全了解它的任何人。

基本上,它尝试使用flock在会话文件上锁定指定的超时值。如果失败,则存在408请求超时。 (或429个请求,如果有的话)

要使其正常工作,您需要...

  1. 了解当时的会话ID
  2. 进行基于文件的会话

请注意,这不是原子。仍然有可能多个请求最终在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();
        }
    }
}

其他想法:

  1. 使用flock -w <timeout>很诱人,但那样的话远不止这些 等待在线呼叫将设法使用execstart_session获得锁定并最终阻塞 session_start
  2. 如果使用浏览器进行测试,请注意,大多数浏览器都会执行命令查询并重用有限数量的connectiosn。因此,他们不会在其他人完成之前开始发送您的请求。如果您不知道这一点,可能会导致看似奇怪的结果。您可以使用几个并行的wget命令来更可靠地进行测试。
  3. 我不建议为正常的浏览器请求激活此功能。如2)所述,在大多数情况下,浏览器已经对此进行了处理。我只是用它来保护我的API免受那些在发送下一个请求之前不等待答案的恶意实现。
  4. 在我的测试中,对于我的整体负载而言,性能影响可以忽略不计。但我建议您使用microtime()调用自己在您的环境中进行测试