0

I know there are quite a few posts about this topic but none of them have fixed my issue.

I have WAMP server running on my windows computer. I've created a login system that is able to set PHP sessions and verify that they are working while on the page that they were created. Once I change to a different page, either by typing in the URL or a javascript function I lose the session.

Here is my test.php that logs a user in

  require_once('config.php');

  $user = new User();
  $result = $user->login('email@gmail.com', 'mysecretpassword');
  echo $result;
  echo '</br>';
  $result = $user->isLoggedIn();
  echo $result;

This is the function that actually logs the user in

public function login($email, $password) {

  // Hash Password
  $password = $this->hashPassword($password);

  // Check if email and password match
  $query = "SELECT id, confirm_email FROM users WHERE email = ? AND password = ?";

  $a_bind_params = array($email, $password);
  $a_param_types = array('s','s');
  $results = $this->db->select($query, $a_bind_params, $a_param_types);

  // If we didnt get a result then email/password must be wrong
  if(count($results) == 0) return 1;

  // Now check that they verrified their email
  if($results[0]['confirm_email'] == 'N') return 2;

  // User is real and everything is good

  // Update login Date
  $a_bind_params = array(date('Y-m-d H:i:s'), $results[0]['id']);
  $a_param_types = array('s','s');
  $query = "UPDATE users SET login_at = ? WHERE id = ?";

  // There was a problem updating their login table so just fail the login
  if(!$this->db->update($query, $a_bind_params, $a_param_types)) return 3;

  // Login user
  Session::set("user_id", $results[0]['id']);
  session_regenerate_id(true);
  Session::set("login_fingerprint", $this->_generateLoginString ());

  return 0;
}

Here is the function that checks if the user is logged in

  // Checks if user is logged in
  public function isLoggedIn() {
      //if $_SESSION['user_id'] is not set return false
      if(Session::get("user_id") == null)
           return false;

      $loginString  = $this->_generateLoginString();
      $currentString = Session::get("login_fingerprint");
      if($currentString != null && $currentString == $loginString)
          return true;
      else  {
         //destroy session, it is probably stolen by someone
         $this->logout();
         return false;
      }
  }

Here is the Session function that creates a session

  public static function startSession() {
      ini_set('session.use_only_cookies', true);

      $cookieParams = session_get_cookie_params();
      session_set_cookie_params(
          $cookieParams["lifetime"],
          $cookieParams["path"],
          $cookieParams["domain"],
          SESSION_SECURE,
          SESSION_HTTP_ONLY
       );

      session_start();
      session_regenerate_id(true);
  }

These are the function that set/get the user session

  public static function set($key, $value) {
      $_SESSION[$key] = $value;
  }

  public static function get($key, $default = null) {
      if(isset($_SESSION[$key]))
          return $_SESSION[$key];
      else
          return $default;
  }

Finally this is my config.php file that actually calls session_start() and include some constants

// REQUIRE ALL FILES
require_once("ClassSession.php");
require_once("ClassDatabase.php");
require_once("ClassUser.php");
Session::startSession();

If I navigate to another page called test.php

include "config.php";
$user = new User();
if($user->isLoggedIn()) echo 'logged in';
else 'Not logged in';

The session is lost and the user is not logged in anymore.

I've checked my sessions.save_path in PHP.ini and have checked the wamp64/temp folder and my sessions are being stored in there. I am also calling session_start() on every page because I am including config.php on both the test pages. Not sure why I am losing my sessions.

EDIT

I forgot to mention what is actually happening. When I login the user I look up their user_id from the database and store that into $_SESSION['user_id']. When I access $_SESSION[user_id] from the page that logged the user in I get back the correct value. However, when I change to another page $_SESSION['user_id'] is null.

UPDATE

session_regenerate_id(true) is not the problem.

Here are my Session settings when printing php_info() enter image description here

Gary Holiday
  • 3,297
  • 3
  • 31
  • 72

4 Answers4

5
session_set_cookie_params(
      $cookieParams["lifetime"],
      $cookieParams["path"],
      $cookieParams["domain"],
      SESSION_SECURE,
      SESSION_HTTP_ONLY
   );

Check values here. What is SESSION_SECURE const value? Maybe you are restricting cookie usage to https only and your site is on http.

Andrew
  • 1,858
  • 13
  • 15
  • 1
    I must wait 11 hours to award the bounty. But this has fixed my issue. Thanks for actually reading through my post and finding the problem. – Gary Holiday Jun 11 '16 at 16:51
1

I just wrote a very basic PHP code to give you an idea how this can be quickly built. You should change the parameters, use mysqli or PDO or ORM whichever you like but the basic idea remains the same. Use secure cookies, follow the best practices to hide what needs to be secured.

Create a php file call it functions.php and paste the following code in it

<?php

    session_start();

function createsessions($email, $password, $loginId)
{
    //Add additional member to Session array as per requirement
    //session_register();

    $_SESSION["email"] = $email;
    $_SESSION["password"] = $password;
    $_SESSION["loginId"] = $loginId;

    //Add additional member to cookie array as per requirement
    setcookie("loginEmail", $_SESSION['loginEmail'], time() + 31536000, "/", ".example.com", 0, true);
    setcookie("password", $_SESSION['password'], time() + 31536000, "/", ".example.com", 0, true);
    setcookie("loginId", $_SESSION['loginId'], time() + 31536000, "/", ".example.com", 0, true);


}

#Authenticate User
function confirmUser($email_address, $password)
{

    if (mysql_num_rows(mysql_query("select * from TABLE where email ='" . $email_address . "' and password =MD5('" . $password . "')"))) {
        $loginstatus = 1; //account exists, login
        return $loginstatus;
    } else {
        $loginstatus = 0; // Incorrect Credentials
        return $loginstatus;
    }
}


#Function to check login status
function checkLoggedin()
{
    if (isset($_SESSION['email']) && isset($_SESSION['password']))
        return true;
    elseif (isset($_COOKIE['email']) && isset($_COOKIE['password'])) {
        if (confirmUser($_COOKIE['email'], $_COOKIE['password'])) {
            $sql_id = mysql_query("select id, email, password from TABLE where email ='" . $_COOKIE['email'] . "' and password ='" . $_COOKIE['password'] . "'");
            $sql_array = mysql_fetch_row($sql_id);

            #Register Session & Cookies Variables
            $loginId = $sql_array[0];
            $email = $sql_array[1];
            $password = $sql_array[2];

            //Clear all sessions and cookies first
            clearsessionscookies();

            createsessions($email, $password, $loginId);

            return true;
        } else {

            clearsessionscookies();
            return false;
        }
    } else
        return false;
}


#Logout and clear session and cookies data
function clearsessionscookies()
{
    unset($_SESSION['email']);
    unset($_SESSION['password']);
    unset($_SESSION['loginId']);


    setcookie("PHPSESSID", null, time() - 31536000, "/", ".example.com", 0);
    setcookie("email", null, time() - 31536000, "/", ".example.com", 0);
    setcookie("password", null, time() - 31536000, "/", ".example.com", 0);
    setcookie("loginId", null, time() - 31536000, "/", ".example.com", 0);

    session_unset();
    session_destroy();
    ob_end_flush();

}
?>

createsessions() and clearsessionscookies() helps in handling session creation and deletion. Replace example.com to your cookie domain.

From your HTML Page, make an AJAX Call to a function and put the following code in it

<?php
#AJAX Call to this function
function checkLogin()
{

    // Don't forget to protect against MySQL injection
    $user_email = mysql_real_escape_string($_POST['emailaddress']);
    $password = mysql_real_escape_string($_POST['password']);

    if ($user_email == '' || $password == '') {
        echo "Invalid email address or password. Please try again.";
        $hasError = true;
    }

    $loginstatus = confirmUser($user_email, $password);

    if ($loginstatus == 0) {
        echo "Invalid ID or password. Please try again.";
        $hasError = true;
    } else // Login Now
    {
        if ($hasError != true) {

            #Get User Details In Session
            $sql_id = mysql_query("select loginId, email, password from TABLE where email ='" . $user_email . "' and password =MD5('" . $password . "')");
            $sql_array = mysql_fetch_row($sql_id);


            #Register Session & Cookies Variables
            $loginId = $sql_array[0];
            $email = $sql_array[1];
            $password = $sql_array[2];


            //Create Fresh sessions and cookies
            createsessions($email, $password, $loginId);

            //Redirect to Dashboard or wherever you want the customer to go post authentication
        }
    }
}

?>

I have purposely kept the LoginID so you can specifically handle the particular record for referencing with other tables you might have associated with the user table.

I hope this will work and help you keep the user logged in for the specified period in the cookie.

Ashish Nayyar
  • 560
  • 3
  • 10
0

Your problem could be

session_regenerate_id(true);

This is going to delete your session and update it with a new session id and you are going to lose the association with any session data for the old session id.

From the docs for the parameter to this function.

delete_old_session

Whether to delete the old associated session file or not.

Community
  • 1
  • 1
phreakv6
  • 2,135
  • 1
  • 9
  • 11
  • [session_regenerate_id](http://php.net/manual/en/function.session-regenerate-id.php) Under the description it states _"session_regenerate_id() will replace the current session id with a new one, and keep the current session information."_ The Session information is not lost. – Gary Holiday Jun 09 '16 at 05:02
  • Yes but you are using `delete_old_session=true` which will delete old session data. – phreakv6 Jun 09 '16 at 05:04
  • Yes delete the old sessions data. The data has been transferred to the new session file. – Gary Holiday Jun 09 '16 at 05:09
  • Hmm my bad. Have you tried peeking into the Request headers to see if the browser is sending back the session id in the cookie? – phreakv6 Jun 09 '16 at 05:13
0

You said config.php calls session_start(); however I see you are using ini_set(use.cookie, true)

That is wrong and causing your issue.

rojobo
  • 476
  • 4
  • 16
  • How is that wrong and causing my error? [This link](http://stackoverflow.com/questions/3517350/session-hijacking-and-php) states that using `ini_set('session.use_only_cookies',1);` is recommended – Gary Holiday Jun 11 '16 at 15:54