title: What determines session inactivity for the server side of a web application (PHP)
body: <p><strong>Issue</strong>: Common sense would tell me that anything that actively interacts with the session would constitute session activity and would reset the inactivity timer that determines session timeout and destruction.  That has not been my experience.  I am trying to determine whether I have a fundamental misunderstanding in the way that sessions work or I have an esoteric bug in my code that is causing me to question the fundamentals of PHP sessions.</p>
  
  <p><strong>Context:</strong> I am implementing persistent logins for users of my web application.  I've been trying to figure out what determines session inactivity/timeout for several days now, to no avail.  I have scoured Stack Overflow and the internet at large (including most of the PHP documentation on sessions), and I still feel like I'm poking at this thing with a stick.</p>
  
  <p>As far as I can tell, "Remember me" cookies, cross-referenced with database entries for user look-ups, are the preferred method of keeping users logged in to an application over periods of inactivity and the closing of their logged-in browser instance.  I accept that, and I believe I know how to do it (there is a lot of good information online about the myriad approaches for this).</p>
  
  <p>However, I initially tried to shortcut the moderate amount of work entailed in this approach by simply tweaking some session config parameters, namely: <code>cookie_lifetime</code> and <code>gc_maxlifetime</code>.  I expected that increasing these parameters would increase the amount of time it took for the session to timeout, but that was not the case.  I set both parameters to 1 year, and the session still timed out after about 40 minutes (which is also weird; everything I've discovered online indicates that 24 minutes is the default timeout).</p>
  
  <p>Next, I tried to sidestep the inactivity thing altogether, and I added a "heartbeat" ajax request that pinged the server every 10 minutes, regenerating the session id and arbitrarily modifying a session key/value store.  That experiment yielded the same 40 minute timeout result, with the ajax call consistently failing on its 4th call.</p>
  
  <p>Here's some [simplified] code in case I'm looking in the wrong places for the source of my issue:</p>
  
  <pre><code>/* initialize_session.php (called at the beginning of every php file) */
  $heartbeat_timer = 60 * 10; // 10 minutes.
  if(session_id() == '' || !isset($_SESSION)){
    # Some of these are already the defaults, but I'm being explicit to avoid ambiguity.
    $session_params = array(
      # Ensure that session file persists beyond heartbeat for keeping alive.
      "gc_maxlifetime" =&gt; $heartbeat_timer + 60,
      "cookie_lifetime" =&gt; 0,
      "cookie_path" =&gt; "/",
      "cookie_domain" =&gt; "shhhh.com",
      "use_strict_mode" =&gt; TRUE,
      "cookie_secure" =&gt; TRUE,
      "cookie_httponly" =&gt; TRUE,
      "use_cookies" =&gt; TRUE,
      "use_only_cookies" =&gt; TRUE,
    );
    session_start($session_params);
  }
  
  
  /* any_page.php (html page where "inactivity" &amp; timeout occur) */
  &lt;?php require_once __DIR__ . "/initialize_session.php"; ?&gt;
  &lt;body&gt;
    blah blah blah
    &lt;script&gt;
      setInterval(function(){
        $.ajax({
          "url": "keep_alive.php",
          "type": "POST",
          "error": function(xhr, text_status, error_thrown){
            // Log error stuff (incidentally, not helpful).
          }
        });
      }, 600000/* 10 minutes in msec */);
    &lt;/script&gt;
  &lt;/body&gt;
  
  
  /* keep_alive.php (arbitrary session modification to trick app into thinking I'm active) */
  require_once __DIR__ . "/initialize_session.php";
  session_regenerate_id(TRUE);
  $_SESSION["last_heartbeat"] = time();
  </code></pre>
  
  <p>It may be worth noting that both the server file store for the session file and the client cookie for the session id are correctly updating per the regenerated session id every 10 minutes.  The ajax interval just starts to fail on the 4th request (as I said, consistent with session inactivity timeout prior to all  of the experimentation).</p>