Loosing Session

Hi Experts,

I am starting a new application and trying to check if the user is logged in before letting them view the page. The exception to this is of course if they are on the login page..I have many files, includes, and I am using MVC, but I will try to post here wjat is relevant

Login form:
<?php 
$page_title = 'Welcome, Please Login...';
$isLoginPage = TRUE;
require_once 'utilities/general_includes.php'; //General-purpose includes.

$error = '';
$message = '';

if (isset($_GET['type'])){
    if ($_GET['type'] == 'err') $error = $_GET['msg'];
    else $message = $_GET['msg'];
}


show_header();
?>

    <!--content-->
    <form name="frm" id="frm" autocomplete="off" method="post" action="login/?action=login"
              onSubmit="return checkRequired();">
        
        <fieldset>  
            <label for="txtUser" class="required" >User Name:</label>
            <input type="text" name="txtUser" id="txtUser" class="required"><br><br>
            
            <label for="txtPassword" class="required">Password:</label>
            <input type="password" name="txtPassword" id="txtPassword" 
                   maxlength="255" class="required"><br><br> 
            
            <label>&nbsp;</label>
            <input type="submit" id="btnLogin" value="Login" class="button">
            
         </fieldset>
            
        </form>

    <!--Place where appropriate-->
    <?php require_once 'utilities/messages.php'; ?> 

<script type="text/javascript">
    
    function checkRequired(){
        var uid = frm.txtUser.value;
        var pwd = frm.txtPassword.value;
        
        if ((uid === '') || (pwd === '')) {
            alert ('All fields are mandatory.');
            return false;
        }
        return true;
    }
    
</script>
    
<?php    
show_footer();
?>

Open in new window


utilities/general_includes.php
<?php 
session_start();
//This include file includes all general-purpose includes.

if (!isset($isLoginPage)){
    $isLoginPage = FALSE;
}

require_once 'configuration.php';
require_once 'checkSecurity.php';
require_once 'database.php';
require_once 'page_setup.php';
?>

Open in new window


login/index.php (Controller)
<?php

//This is the controller file for the current module.

require_once 'login.php';

$action = 'list'; //<-DEFAULT ACTION

//Get Action

if (isset($_GET['action'])){
    $action = $_GET['action'];
}
else if (isset($_POST['action'])){
    $action = $_POST['action'];
}

if ($action == 'login') {
    $isLoginPage = 1;
}

require_once '../utilities/general_includes.php'; //General-purpose includes.

$error = '';
$message = '';
    
        echo '<br> from login isLogin = '. $isLoginPage;
        echo '<br> from login sess = ' . $_SESSION['sess_id'];
        
switch ($action){
    
    case 'login':
        
        $user = $_POST['txtUser'];
        $password = $_POST['txtPassword'];
        $login_status = Login::verify_login($user, $password);
    
        if ($login_status == 'admin') {
            header('Location: index.php?action=list');
        } 
        else if ($login_status == 'rs') {
            header('Location: ../dispatch');
        } 
        else if ($login_status == 'no_cookies') {
            header('Location: ../?type=err&msg=Cookies must be enabled in your browser');
        }
        else {
            header('Location: ../?type=err&msg=User Id / Password combination not found.');
        }
        
        break;
        
    case 'logout':
        
        Login::logout();
        header('Location: ../?type=info&msg=Session successfully ended.');
        break;
    
    case 'list':

        $users = Login::get_login_list();
        
        $page_title = 'User List';
        $message = 'Select a user to change their password.';        
        include 'view_list.php';
        
        break;
    
    case 'pw_change':
        
        $uid = $_GET['user'];
        $user = Login::get_login($uid);
        
        $uid = $user['user'];
        $pwSha = $user['password'];
        
        $page_title = 'Change Login Password';
        include 'view_password-change.php';
        
        break;
    
    case 'pw_save':
        
        $uid = $_POST['txtUser'];
        $pwOld = $_POST['txtPWold'];
        $pwSha = $_POST['hidPWold'];
        $pwNew = $_POST['txtPWnew1'];
        
        if (sha1($pwOld) != $pwSha) {
            $error = 'Old Password does not match database. <br> <br>'
                    . 'Please try again.';
            
            $page_title = 'Change Login Password';
            include 'view_password-change.php';

            break;   
        }
        else{
            Login::set_password($uid, $pwNew);
            $message = 'Password Successfully Changed.';
            
           $users = Login::get_login_list();
           include 'view_list.php';
        }
        
        break;
        
    case 'pw_cancel':
        
        $users = Login::get_login_list();
        $message = 'Password change cancelled.';
        include 'view_list.php';
        break;
}
?>

Open in new window


login/login.php (Model)
<?php //This is the model file for the current module.

class Login {
 
    public static function verify_login($login_user, $password){
        
        //destroy previous session
        self::logout();
        
        $user = self::get_login($login_user);
        if (count($user) == 0) return 'no_user';
        
        if (sha1($password) != $user['password']) return 'wrong password';
        
        //login success, start session
        global $env;
                
        $lifetime = 60 * 60 * 24; // 24h in seconds
        session_set_cookie_params($lifetime, '/', $env['domain'], TRUE, FALSE);
        
        if (session_start() == FALSE) return 'no_cookies';

        $_SESSION['sess_id'] = session_id();
        
        echo 'login sess = ' . $_SESSION['sess_id'];
                
        if (($login_user == 'reservations') || ($login_user == 'aleks')) {
            return 'rs';
        }
        else {
            return 'admin';
        }  
        
    }
    
    public static function logout() {

        //Destroy Session
        $_SESSION = array();
        if (isset($_SESSION['sess_id'])) session_destroy();

        //Delete Sess cookie
        $name = session_name();
        $expire = strtotime('-1 year');
        $params = session_get_cookie_params();
        $path = $params['path'];
        $domain = $params['domain'];
        $secure = $params['secure'];
        $httponly = $params['httponly'];

        setcookie($name, '', $expire, $path, $domain, $secure, $httponly);

    }

    public static function get_login($user){
        $db = Database::getDB();
        
        $query = 'SELECT * FROM logins '
               . 'WHERE user = :user';
        
        $statement = $db->prepare($query);
            $statement->bindValue(':user', $user);
        $statement->execute();
        $result = $statement->fetch();
        $statement->closeCursor();
        return $result;       
    }

    public static function get_login_list() {
        $db = Database::getDB();
        
        $query = 'SELECT login_id, user FROM logins '
                . 'WHERE show_user = 1 '
                . 'ORDER By user';
        
        $statement = $db->prepare($query);
        $statement->execute();
        $result = $statement->fetchAll();
        $statement->closeCursor();
        return $result;
    }
    
    public static function set_password($user, $newPassword){
        $db = Database::getDB();
        
        $newPassword = sha1($newPassword);
        
        $query = 'UPDATE logins '
               . 'SET password = :pw '
               . 'WHERE user = :user'; 
      
          $statement = $db->prepare($query);
            $statement->bindValue(':pw', $newPassword);
            $statement->bindValue(':user', $user);
        $statement->execute();
        $statement->closeCursor();
    }
    
}
?>

Open in new window


Finally, utilities/checkSecurity.php
<?php 

    //go to SSL (IIS and Linux)    
    if (($_SERVER['HTTPS'] == 'off') || (!isset($_SERVER['HTTPS']))) {
        $url = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        header("Location: " . $url);
    }
    
//Login Check
echo '<br> check sec sess = ' . $_SESSION['sess_id']; 
echo '<br> isLoginPage = ' . ($isLoginPage == TRUE);
 
 
    if ($isLoginPage == FALSE) {
               
        if (!isset($_SESSION['sess_id']) || ($_SESSION['sess_id'] == '')){
            echo '<br><br>not logged in';
            /*header('Location:' . $env['url'] . '/?type=err&msg=Must Login First.');
            exit();*/
        }
        
    //Referrer Check
    
        $referrer = $_SERVER['HTTP_REFERER'];
        $protocol_pos = strpos($referrer, '://') + 3;
        
        $ref_domain = substr($referrer, $protocol_pos);
        
        $domain_end = strpos($ref_domain, '/');
        $ref_domain = substr($ref_domain, 0, $domain_end);
        
        if ($ref_domain != $env['domain']){
            
            Login::logout();      
            header('Location:' . $env['url'] . '/?type=err&msg=Referrer Check Failed.');
        }
    }
?>

Open in new window


The problem is even after successful login, even when I get to the url ...//login/index.php?action=list I get the following output:


Notice: Undefined index: sess_id in C:\inetpub\wwwroot\CSS_Reservations\utilities\checkSecurity.php on line 10

check sec sess =
isLoginPage =

not logged in
from login isLogin =
Notice: Undefined index: sess_id in C:\inetpub\wwwroot\CSS_Reservations\login\index.php on line 28

from login sess =

from login sess = is coming from my Controller after I successfully login.

I know this is a lot, but when I break it down it works, but its some logical error that I cannot figure out.

My only suspicion is that I am using session_start(); a part of my general_includes.php, but on the other hand I feel that ok.

I have been at this whole day, so any help will be greatly appreciated.
APD TorontoSoftware DeveloperAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Dave BaldwinFixer of ProblemsCommented:
session_start() Must be at the top of every page that is part of the session.  It is what identifies the current session and thus $_SESSION variables.  Above, I only see it in 'utilities/general_includes.php'.  That would work Only if that is included at the top of every addressable page.  That includes all pages that are loaded as the main page whether they are 'seen' in the browser or not.  

And you can include session_start() more than once if you have a reason because the first thing it does is to check to see if there is already a session running.  If there is, it uses that.

http://php.net/manual/en/function.session-start.php
0
APD TorontoSoftware DeveloperAuthor Commented:
So, the general_includes.php OR session_start(); must be first?
0
Dave BaldwinFixer of ProblemsCommented:
session_start() or a file that includes it at the top.  session_start() is what sets up the session each time.  Without it, you can't access the $_SESSION variables that were set on previous pages.

Note also that since session_start() sets a cookie, it must come before there is any output to the browser.  Even a blank space will prevent sending any more headers which is where the cookie is sent.
0
Bootstrap 4: Exploring New Features

Learn how to use and navigate the new features included in Bootstrap 4, the most popular HTML, CSS, and JavaScript framework for developing responsive, mobile-first websites.

APD TorontoSoftware DeveloperAuthor Commented:
I made some tweaks and made sure to have my general includes file, before any html output, and in my gen includes, my first 2 lines are

<?
session_start();

Separately, I'm doing

 echo '<br> check sec server sess = ' . session_id();

and I noticed that sometimes the outputted value changes.  Further, in FF, I see multiple cookies created from my localhost.  Both of these facts prove I'm loosing my session, but why?

Lastly, on my login page, which I'm not returning until logging out, Ihave

    Login::logout(); //destroy previous sessions.
    $lifetime = 60 * 60 * 24; // 24h in seconds
    session_set_cookie_params($lifetime, '/', $env['domain'], TRUE, FALSE);
    session_start();
    $_SESSION['sess_id'] = '';

So I'm making sure that I'm starting out with a fresh session, then that session is good for 24h, or until I logout.  So, in the meantime session_id() should always produce the same value, but it doesn't. Why?
0
Dave BaldwinFixer of ProblemsCommented:
Standard PHP sessions are good until there is 1440 seconds / 24 minutes of no activity from the browser to the server.  Sessions are deleted from inactivity some time after that.  It is not a precise interval.  And the cookie lifetime does Not set the session timeout.  This page http://php.net/manual/en/session.configuration.php lists the session parameters found in 'php.ini'.  Look for session.gc_maxlifetime.

If you are on shared hosting and you try to extend the session.gc_maxlifetime , you will find that the shortest timeout 'wins' because the garbage cleanup is done for all sessions at the same time.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
APD TorontoSoftware DeveloperAuthor Commented:
I'm on a cloud server, but more so, this is happening on my localhost and there is >1min of inactivity.

Can this be happening of using header('Location: ...'); or changing the URL Manually (for testing purposes), but both within my localhost?

If I solely rely on cookies, and access the cookie at each page load, will I run into performance issues?
0
APD TorontoSoftware DeveloperAuthor Commented:
As well, does php code overwrite php.ini?

For example, phpInfo() hows session.cookie_lifetime as 0, but my code sets it to 24h... who wins?
0
Dave BaldwinFixer of ProblemsCommented:
The PHP doc pages show what can and can not be changed in PHP code.  Not everything can be.  Cookies are sent with the page request and set in the corresponding page response.  They will have no effect on your site performance.  As for 'session.cookie_lifetime', you should probably leave that at 0 which is the normal setting for session cookies from all languages and web servers.  That makes them expire when the browser is completely shut down.  

If you are looking for a "user session" in your application, that has to be a different thing.  PHP sessions are used to identify $_SESSION variables on the server.  Trying to use them for much of anything else will just cause you a lot of frustration because you will find out over and over again that they are not doing what you want.  But they work very well for their intended purpose.
0
Dave BaldwinFixer of ProblemsCommented:
One other thing I forgot to mention.  There are things that do not work in 'localhost'.  Chrome will not set a cookie for 'localhost' because it is ambiguous and Chrome considers it a security risk.  Most of the time I do not use 'localhost'.  I use either the IP address of the machine on my intranet or the domain name on the internet.  There are a couple of exceptions with functions / programs that are designed to work Only on 'localhost' to prevent them from being accessed from 'outside'.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.