Home > OS >  PHP, MySQL, PDO - Create a Login System with Sessions
PHP, MySQL, PDO - Create a Login System with Sessions

Time:03-31

I want to build a login system in PHP. There are 5 files:

  1. db.php contains database utilities.
  2. user.php for login and logout functions.
  3. login.php is login page.
  4. index.php is the main page.
  5. logout.php is a page that logs users out and redirects to login.php.

The login part seems to work as expected (by checking the database, omitted here), but the redirection from login.php to index.php doesn't seem to work. The same login page appears again.

But when I remove this part in index.php:

// Must be logged in first
if (!isset($_SESSION['username'])) {
    gotoPage('login.php');
}

it redirects successfully, and then the logout fails.

Also, if a user logs out and clicks the undo button in the browser, it takes him to the main page (index.php) which he is not supposed to see after logging out.

I don't know what exactly is preventing the redirection and the logout. Any help (or advice) is appreciated.

Note: I've looked at similar questions on SO, none of the answers provided solved the issue.


db.php content:

<?php
function getDBInstance() : PDO
{
    static $dbInstance;
    if (!$dbInstance) {
        return new PDO(
            'mysql:host=localhost;dbname=DummyUserAccounts;charset=UTF8',
            'dummyuser',
            '...',
            [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
        );
    }
    return $dbInstance;
}

function register_user(string $firstname, string $lastname, string $username, string $password): bool
{
    // PROC_USER_ADD inserts one user into the User table.
    $query = 'CALL PROC_USER_ADD(:firstname, :lastname, :username, :password)';

    $statement = getDBInstance()->prepare($query);

    $statement->bindValue(':firstname', $firstname, PDO::PARAM_STR);
    $statement->bindValue(':lastname', $lastname, PDO::PARAM_STR);
    $statement->bindValue(':username', $username, PDO::PARAM_STR);
    $statement->bindValue(':password', password_hash($password, PASSWORD_BCRYPT), PDO::PARAM_STR);

    return $statement->execute();
}
?>

user.php content:

<?php
require 'db.php';

function sanitize($field)
{
    $field = trim($field);
    $field = stripslashes($field);
    $field = htmlspecialchars($field);
    return $field;
}

function gotoPage(string $page) : void
{
    header('Location: ' . $page);
    exit;
}

function loginUser(string $username, string $password) : bool
{    
    // Search for the user in the database
    $queryString = 'SELECT username, password FROM user WHERE username = :username';
    $statement = getDBInstance()->prepare($queryString);
    $statement->bindValue(':username', $username, PDO::PARAM_STR);
    $statement->execute();
    $user = $statement->fetch(PDO::FETCH_ASSOC);

    // Successful login?
    if ($user && password_verify($password, $user['password'])) {
        // Create a new Session ID
        session_start();

        // Write session data
        $_SESSION['username'] = $username;

        return true;
    }

    return false;
}

function logoutCurrentUser() : void
{    
    if (isset($_SESSION['username'])) {
        unset($_SESSION['username']);
        session_destroy();
        gotoPage('login.php');
    }
}
?>

login.php content:

<?php
require 'user.php';

// Can't login twice.
if (isset($_SESSION['username'])) {
    gotoPage('index.php');
}

$errorMessage = "";

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    // Check for empty fields
    if (empty($_POST['username']) || empty($_POST['password'])) {
        $errorMessage = "Both Username and Password are required!";
    } else {
        // Sanitize fields
        $username = sanitize($_POST['username']);
        $password = sanitize($_POST['password']);

        // Login user
        if (!loginUser($username, $password)) {
            $errorMessage = "Invalid username and/or password.";
        } else {
            gotoPage('index.php');
        }
    }
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>

<body>
    <form action="login.php" method="post">
        <div>
            <label>Username</label>
            <input type="text" name="username">
        </div>
        <div>
            <label>Password</label>
            <input type="password" name="password">
        </div>
        <div>
            <button type="submit">Login</button>
        </div>
        <div>
            <span style="color:red"><?php echo $errorMessage ?></span>
        </div>
    </form>
</body>
</html>

index.php content:

<?php
require 'user.php';

// Must be logged in first
if (!isset($_SESSION['username'])) {
    gotoPage('login.php');
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>Main Page</title>
</head>

<body>
    <nav>
        <a href="logout.php">Logout</a>
    </nav>

    <!--Main page goes here-->
</body>
</html>

logout.php content:

<?php
require 'user.php';

logoutCurrentUser();
gotoPage('login.php');
?>

CodePudding user response:

You will need session_start() on every page that you want to access $_SESSION variables. login.php does not have session_start(), so isset($_SESSION) will always return false.

  • Related