title: How to find out that session has expired in PHP?
body: <p>I'm trying to improve the session management for web applications. My major issue is the session expiration and how to deal with it. For that I'd like to find out if the session is still available or not. I'm using the default file based sessions (PHP 7.1, Apache 2.4, Fedora/RHEL) and it is cookie based.</p>
  
  <p>What I've found out is that the session GC gets executed when <a href="http://php.net/manual/en/function.session-start.php" rel="nofollow noreferrer"><code>session_start()</code></a> is called. It is not with the begin or end of the script execution, it happens with this function. What seems odd to me is that if <code>session_start()</code> and the GC consider the session as expired and want to delete the corresponding session file, $_SESSION gets populated regularly first, then the file will be deleted. That's surprising.</p>
  
  <p>With that behaviour only the next following request leads to an empty $_SESSION. I would expect this with the call before - the one that deletes the file. So if I'd like to know whether the session has expired in the current request I would have to check if the session file still exists after the <code>session_start()</code> call. That seems strange to me. </p>
  
  <p><strong>Are there any other or better ways to check that a session has expired than looking into the file system?</strong> </p>
  
  <p>I thought I could just check if $_SESSION is empty to determine that the session was renewed - but that is obviously not possible.</p>
  
  <hr>
  
  <p><strong>Update:</strong> I've found the following bug reports dealing with the issue: <a href="https://bugs.php.net/bug.php?id=35479" rel="nofollow noreferrer">this</a> and <a href="https://bugs.php.net/bug.php?id=35602" rel="nofollow noreferrer">that</a>. There's also a <a href="https://stackoverflow.com/a/3429016/57091">SO entry</a> about the expiration problem. Current PHP source: <a href="http://%20github.com/php/php-src/blob/master/ext/session/session.c#L1490" rel="nofollow noreferrer"><code>php_session_start</code></a> calls <a href="https://github.com/php/php-src/blob/master/ext/session/session.c#L1600" rel="nofollow noreferrer"><code>php_session_initialize</code></a> calls <a href="https://github.com/php/php-src/blob/master/ext/session/session.c#L449" rel="nofollow noreferrer"><code>php_session_gc</code></a>.</p>
  
  <hr>
  
  <p>You may want to play with this script (unreal settings are just for testing purposes):</p>
  
  <pre><code>ini_set('session.gc_maxlifetime', 2); // Session gets expired after 2 seconds
  ini_set('session.gc_divisor',     1); // Delete expired session files immediately
  ini_set('session.save_path',      '/some/safe/path/for/testing'); // Must be accessible for the server
  //ini_set('session.use_strict_mode', true); // Uncomment if the id should be renewed, what makes no difference here
  
  echo "Session files before session_start call&lt;br&gt;";
  listSessionFiles();
  
  session_start();
  
  echo "Session files after session_start call&lt;br&gt;";
  listSessionFiles();
  
  echo "&lt;hr&gt;";
  
  echo "Session id: "      . session_id() . "&lt;br&gt;";
  echo "Session content: " . print_r($_SESSION, true);
  $_SESSION['x'] = time(); // Populate the session with something 
  
  
  function listSessionFiles() {
      echo "&lt;ul&gt;";
      $none = true;
      $dir  = dir(ini_get('session.save_path'));        
      while ($entry = $dir-&gt;read()) {
          if (preg_match('/^sess_/', $entry)) {
              echo "&lt;li&gt;" . $entry . "&lt;/li&gt;";
              $none = false;
          }
      }
      $dir-&gt;close();
      if ($none) echo "&lt;li&gt;None&lt;/li&gt;";
      echo "&lt;/ul&gt;";
  }
  </code></pre>
  
  <p>Just reload the page some times. Wait at least more than two seconds. Otherwise the session does not expire.</p>