title: PHP Session regenerate ID destroys session for some user
body: <p>I have a working Session management on my platform which I programmed in PHP.</p>
  
  <p>For security reasons I want to regenerate the Session ID at least when a user logs in successfully and if possible with each request to prevent session fixation.</p>
  
  <p>The login part looks like this if the login credentials are correct. If they are not correct or the user has not entered anything yet I do not start a session and as far as I know one old value for the session id is used</p>
  
  <pre><code>session_set_cookie_params(1800, "/", $domain, true, true);
  session_start();
  session_regenerate_id(true);
  </code></pre>
  
  <p>Each time I make another request to the server and it checks wether my session is valid I call</p>
  
  <pre><code>session_regenerate_id(true);
  </code></pre>
  
  <p>I check for a valid session with this code:</p>
  
  <pre><code>$domain = $_SERVER["HTTP_HOST"];
  
  if(session_status() != PHP_SESSION_ACTIVE)
  {   
      session_set_cookie_params(0, "/", $domain, true, true);
      session_start();
  }
  
  //Check if session has expired
  $now = time();
  if(isset($_SESSION["discard_after"]) &amp;&amp; $now &gt; $_SESSION["discard_after"])
  {
      session_unset();
      session_destroy();
      header("Location: https://".$domain."/login.php");
      die();
  }
  
  session_regenerate_id(true);
  
  $_SESSION["discard_after"] = $now + 120;
  
  if ((!isset($_SESSION["loggedin"]) || !$_SESSION["loggedin"]) &amp;&amp;
      basename($_SERVER["PHP_SELF"]) != "login.php")
  {
      header("Location: https://".$domain."/login.php");
      die();
  }
  </code></pre>
  
  <p>I monitored this with Burp and confirmed, that the session id changes when I log in successfully. The session ID also changes when I navigate through the site without any problem and just the way I want to.</p>
  
  <p>However this behaviour is not consitent. I have some user who enter the correct credentials (I know this because of the logs) but have no valid session and can not cross the login page to the home page.</p>
  
  <p>I also have the strange case that one has to log in twice (both times correct credentials) befor a valid session is set. This happens to me unpredictable as well as to other users. I could not see yet when this happens and when not, only that the login should have worked.</p>
  
  <p>Some information about the setup. I have a Ubuntu 14.04 vServer with Apache2 and PHP 5.X. On the client side I use the latest version of Firefox and Chrome on Windows 7 64x. One user who can not login at all even though the credentials are correct and the code above is definitly executed is using Chrome on Windows 7 64x as well (I have no more information regarding this).</p>
  
  <p>I know for sure that the problem is the <code>session_regenerate_id(true);</code> function because if I comment this line out everything works fine but this solution is not satisfactory to me. I also tried a PC from which I certainly never entered the website befor and there everything also works.</p>
  
  <p>I can not see what causes this and the PHP man page did not really help me there. Especially the not determinstic behaviour confuses me.</p>
  
  <p>I might not answer until tomorrow but I will value all useful answers and comments.</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>This is the entire login sequence without unneccessary stuff that is not executed in my scenario or definitly unimportant. I never output anything befor.</p>
  
  <pre><code>if($_SERVER["REQUEST_METHOD"] == "POST" &amp;&amp; isset($_POST["inputEmail"],
      $_POST["inputPassword"]) &amp;&amp; $_POST["inputEmail"] !== "" &amp;&amp;
      $_POST["inputPassword"] !== "")
  {
      $domain = $_SERVER["HTTP_HOST"];
  
      $passwordHash = hash("sha256", $_POST["inputPassword"]."somesecretsalt");
  
      //Own function which definitly works
      $connection = connectToDB("standard");
  
      //Get usernames and passwordhashes for checking
      $query_getUser = "SELECT id, firstname, lastname, email,
      passwordhash FROM user WHERE email = ?;";
      if($stmt = mysqli_prepare($connection, $query_getUser))
      {
          mysqli_stmt_bind_param($stmt, "s", $_POST["inputEmail"]);
          mysqli_stmt_execute($stmt);
          $userRAW = mysqli_stmt_get_result($stmt);
          mysqli_stmt_close($stmt);
      }
  
      if(mysqli_num_rows($userRAW) == 1)
      {
          //State: User exists
          $dataset = mysqli_fetch_array($userRAW, MYSQLI_ASSOC);
          $now = time();
  
          //This is the crucial part which is definitly executed because the
          // log entry in the following if clause is executed
          session_set_cookie_params(1800, "/", $domain, true, true);
          session_start();
          session_regenerate_id(true);
  
          if($dataset["passwordhash"] === $passwordHash)
          {
              //State: User exists, correct password
  
              $_SESSION["loggedin"] = true;
              $_SESSION["id"] = $dataset["id"];
              $_SESSION["email"] = $dataset["email"];
              $_SESSION["name"] = $dataset["firstname"]." ".$dataset["lastname"];
  
              $comment = $_SESSION["name"]." (ID:".$dataset["id"].") has logged in";
              writeToLog("Login success   ", $comment, __LINE__);
  
              if ($_SERVER["SERVER_PROTOCOL"] == "HTTP/1.1")
              {
                  if(php_sapi_name() == "cgi")
                  {
                      header("Status: 303 See Other");
                  }
                  else
                  {
                      header("HTTP/1.1 303 See Other");
                  }
              }
  
              header("Location: https://".$domain."/index.php");
              mysqli_close($connection);
              die();
          }
      }
  
      mysqli_close($connection);
  }
  </code></pre>