title: PHP: session_start() called 'simultaneously' in multiple tabs creates multiple sessions
body: <p>I've stumbled across an interesting problem. A site I'm working on has, at the moment, three pages: login.php and welcome.php and ajax.php. They all call session_start() at the top of their code. Login.php checks the $_SESSION[] variables to see if someone is logged in; if not, it gets their name/pwd, contacts ajax.php to check the name/pwd, and logs them in by setting the appropriate $_SESSION[] vars. Welcome.php looks for the appropriate $_SESSION[] vars and displays a welcome message to the user - if they're not set, it asks the user to please login. Typical behaviour, and if used in a typical fashion it works perfectly.</p>
  
  <p>However, if you bookmark login.php and welcome.php as a set of tabs (e.g., in Firefox) and then open them both at the <em>same time</em>, something odd happens. Perhaps because session_start() is called twice at the exact same time (checked by using error_log()), two separate sessions are created (checked with session_id()). Whichever session_start() happens to be called "last" (although same timestamp) is the session that remains. This causes trouble in the following scenario: login.php's session_start() is called <em>before</em> welcome.php's session_start() is called.</p>
  
  <p>In this situation, the session created in login.php continues to exist in that page as long as it's not refreshed. However, when it contacts ajax.php to check name/pwd details, and ajax.php calls session_start(), it retrieves the session created by welcome.php, which has nothing whatsoever in the $_SESSION[] variable, making the whole thing fail. So if login.php calls session_start() first, I have to figure out a way to prevent welcome.php's session_start() from creating a new one. Note: The calling order is not consistent, and everything obviously works fine as long as login.php's session_start() is called last (which I can't control).</p>
  
  <p>Ideally, there would be some way for the second file to notice that the first file is <em>in the process of creating the session</em>, so it shouldn't create it's own (but only for welcome.php).</p>
  
  <p>This MUST be a problem that others have dealt with, but I have been completely unable to find any mention of it on these here interwebs. Any help would be greatly appreciated.</p>
  
  <p><strong><em>EDIT1: Here are the files needed to reproduce the problem:</em></strong></p>
  
  <p>LOGIN.PHP</p>
  
  <pre><code>&lt;?php
  session_start();
  error_log("login.php, session id: ".session_id());
  $_SESSION['user'] = "EleventyOne"
  ?&gt;
  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
  &lt;meta charset='utf-8'&gt;
  &lt;title&gt;multiple session bug - login&lt;/title&gt;
  
  &lt;script src='jquery-1.9.1.js'&gt;&lt;/script&gt;
  &lt;script&gt;
  
      $(document).ready(function() {
          $.ajax({
                  url : 'ajax.php',
                  data : { 'func' : 'check_login' },
                  dataType : 'json',
                  type : 'GET',
                  timeout : 10000
              })
          .done(function(data,textStatus,jqXHR){
              alert("Done: "+data.status);
          })
          .fail(function(jqXHR,textStatus,errorThrown) {                    
              alert("Failed: " + textStatus + "(" + errorThrown + ")");
          });
      }); // end ready
  
  &lt;/script&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>WELCOME.PHP:</p>
  
  <pre><code>&lt;?php
  session_start();
  error_log("welcome.php, session id: ".session_id());
  $message = "";
  
  if ( isset($_SESSION['user']) ) {
      $message = "Hello, ".$_SESSION['user'];
  }
  else {
      $message = "Please login!";
  }
  ?&gt;
  
  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
  &lt;meta charset='utf-8'&gt;
  &lt;title&gt;multiple session bug - welcome&lt;/title&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
  &lt;div&gt;
  &lt;?php echo $message; ?&gt;
  &lt;/div&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>AJAX.PHP:</p>
  
  <pre><code>&lt;?php
  session_start();
  error_log("ajax.php, session id: ".session_id());
  
  // ignoring $_GET[] here, as superfluous to the point...
  
  if ( isset($_SESSION['user']) ) {
  
      // check the database for that user...
      // ...
  
      // return status
      $ret['status'] = "ok";
      echo json_encode($ret);
      exit;
  }
  else {
      // return failed status
      $ret['status'] = "broken session";
      echo json_encode($ret);
      exit;
  }
  ?&gt;
  
  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
  &lt;meta charset='utf-8'&gt;
  &lt;title&gt;multiple session bug - ajax&lt;/title&gt;
  
  &lt;script src='_js/jquery-1.9.1.js'&gt;&lt;/script&gt;
  &lt;script&gt;
  
      $(document).ready(function() {
      }); // end ready
  
  &lt;/script&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>If you load login.php, open a new tab and load welcome.php, here's the error_log file you get (everything is fine):</p>
  
  <pre><code>[27-Jun-2013 18:39:40 UTC] login.php, session id: skofpr8g0tg81aqohnkahv3vk5
  [27-Jun-2013 18:39:40 UTC] ajax.php, session id: skofpr8g0tg81aqohnkahv3vk5
  [27-Jun-2013 18:39:44 UTC] welcome.php, session id: skofpr8g0tg81aqohnkahv3vk5
  </code></pre>
  
  <p>If you bookmark login.php and welcome.php as a set of tabs, close your browser, re-open it, and open both tabs at the same time, you will get one of two error_log files, depending on which session_start is called first.</p>
  
  <p>This one works, as login.php's session_start() persists for ajax.php. So ajax.php reports status of "ok":</p>
  
  <pre><code>[27-Jun-2013 18:40:39 UTC] welcome.php, session id: 6q2q96lhhoaqqhj214gs3gos36
  [27-Jun-2013 18:40:39 UTC] login.php, session id: j8eaa5mtfsla9q3q80qt03kvt7
  [27-Jun-2013 18:40:39 UTC] ajax.php, session id: j8eaa5mtfsla9q3q80qt03kvt7
  </code></pre>
  
  <p>This one doesn't work, as welcome.php's session_start() persists for ajax.php, so ajax.php reports "broken session":</p>
  
  <pre><code>[27-Jun-2013 18:40:18 UTC] login.php, session id: s4b7jo41jpg1ubbe8at7c5qr35
  [27-Jun-2013 18:40:18 UTC] welcome.php, session id: freu86sn3edc3fuoc2pn875o90
  [27-Jun-2013 18:40:18 UTC] ajax.php, session id: freu86sn3edc3fuoc2pn875o90
  </code></pre>