How can i stop an AJAX call keeping a PHP Session alive

I have an authentication system on my site using CakePHP. It uses PHP Sessions for this.

What i have in place is an AJAX call (within a setInterval running every minute) to a function which checks if the user is still logged in. If it returns false, then the Javascript takes the current URL and attempts to redirect them, which in turn redirects them to the login page. In theory this works because it actively asks the user to re-login instead of holding a stale session which will just ask them to login as soon as they click something. My problem is that my AJAX call is keeping the session alive. So never get logged out (which we don't want)

Is there ANYTHING i can do within CakePHP or any other methods i can use to stop this happening?

Answers:

Answer

Add &ajax= (anything) to the query string when you're checking for the validity of the session.

Then, alter your PHP session code:

session_start();
if(!isset($_GET["ajax"])) $_SESSION["lastactivity"] = time();
if(now() - $_SESSION["lastactivity"] > 3600){ //3600 seconds
    header("Location: login.php?url="+urlencode(str_replace("&ajax=", "", $_SERVER["REQUEST_URI"])));
    //Example:
    // Location: login.php?url=/sensible/secret.php?mode=show&hide=nothing
    exit;
}
Answer

The AJAX ping you've described is most commonly used for just that - keeping a session alive. The very fact that you've accessed your application while the session is active is refreshing it.

You could do one of the following:

  • have a fixed-length session e.g. 30 minutes, after which it would always expire (not sure if that's a good idea) and keep the ping
  • change the logic so that you don't ping at all, and when the session expires and the user either navigates to a new page or performs an AJAX session, the server returns the appropriate status code and/or redirects the user to the login page.

I'd go with the 2nd option.

Answer

Obvious ways of doing this would be:

  1. don't call session_start() in your Ajax end point
  2. implement your own session handler with a backdoor which allows you to skip the write part (e.g. based on the state of a global variable or the current URL)

As an ugly hack, you could try calling session_id('dummy'); or change the session handler after calling session_start() in the Ajax end point.

Answer

As I mentioned in the comment you can create a javascript file with following contents and call this file in all your pages

setTimeout("checkSession()",1800000);
function checkSession(){
     //alert("Your session has expired due to inactivity. You will be logged out");
     window.location.reload();//or window.location="logoutAction";
}
Answer

I don't think you'll be able to rely on the Auth session alone for this.

What I would do is create a new field on the user table to track last activity, something like last_activity as a mysql timestamp. Then in your AppController::beforeFilter(), set this field to be updated with the current datetime (so it will happen with every request), but set it to skip this if it's your pinging action that is making the request (you can check $this->here or maybe even add your own param for other actions too).

Your Ajax ping obviously just reads this field, and if greater than x amount of minutes ago, you log out the user.

Answer

This doesn't exactly answer the question you're asking but I see it as a best practice I thought I would share.

setInterval() does not actually behave as you'd expect it to. It does not mean that your code will be executed every minute, it only ensures that your code will be added to the queue every minute.

The problem with this is that the timer code may not finish execution before the code is added to the queue again. The result would be that the timer code is run multiple times in a row, with no amount of time between them. Fortunately, JavaScript engines are smart enough to avoid this issue. When using setInterval(), timer code is added to the queue only if there are no other instances of the timer code already in the queue. This ensures that the time between additions of the timer code to the queue is, at a minimum, the specified interval.

The downside to this regulation of repeating timers is twofold: (1) intervals may be skipped, and (2) intervals may be smaller than expected between multiple timer-code executions... -N. Zakas, Professional JavaScript for Web Developers

The way around this is to format your timer code like this:

setTimeout( function() {

       // code to be run

       setTimeout( arguments.callee, *interval* );

}, *interval* );

note: arguments.callee cannot be used in strict mode.

Answer

Here I have derived a solution for detect whether session was alive or not.

No need of any overheads.. We can detect and redirect the session time out on normal http requests. Where as in ajax, we should have to treat it differently, with some logic.

# step 1 ( in server side)

In php side. First create an authentication function that should have to call this authontication in first line of the all the page.

Best to add this auth() function in config.php file or auth.php file and include in all the php file after the session creation.

include 'config/auth.php';

// in auth.php file copy and past the following lines 

      function auth() {
        if (!isset($_SESSION['USER_ID'])) {
        //  checking whether the request is ajax or not. Ajax requests are xml http request 
            if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
               // set a status code manually. 418 is unused http code
                header("HTTP/1.0 418 Session Timeout", TRUE);
               //  return or send a json response with status string and location to redirect
                echo json_encode(array(
                    "status" => "time_out",
                    "location" => BASE_URL . "login.php?message=Session Timeout! Please log in and Try again.",
                ));
                exit;
            }
       // whether the request is normal http request do the redirection from the server side
            if (basename($_SERVER['PHP_SELF']) != 'login.php') {
                header("Location:" . BASE_URL . "login.php");
            }
        } }

# step 2 ( in client side )

Here I use jQuery create a js file that must call in all the html( template ) pages in the project.

Best to include in commen header or footer

create an ajax settings

$.ajaxSetup({
    statusCode: {
        418: function (respose) {
            // $.parseJSON() can avoid by specifying dataType:"json" in ajax parameters
            var jsonObject = $.parseJSON(respose.responseText);
            if (jsonObject.status == "time_out") {
                window.location = jsonObject.location;
            }
        }
    }
});

Have a good day...

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.