Creating a basic log-in system

While building a website network like that of ZumGuy, there are certain elements and applications one will find oneself creating over and over. One of these is a simple PHP-based login system, and to save myself some time I have come up with a modular file I can simply copy-paste wherever it is needed.

What does ‘logged in’ mean?

One thing to be clear about before we begin is what it actually maens to be ‘Logged in’ to a website.
In most cases it simply means that the user has an open session with the server, and in that session is an identifier (like their user ID from the site’s dabase) which allows the website to know who they are and give them a personalised and, hopefully, pleasant experience.

The $_SESSION superglobal

First off, superglobals are built-in system variables that are always available in all scopes – that means you can access them inside functions the same way as outside them. Read more on Superglobals in the PHP Manual.
Furthermore, the $_SESSION superglobal is available across all documents, once the session has been started. In order to access the session you must use the session_start() function, which will access an existing session or create a new one if necessary. Be sure to use this function before any content (including whitespace) is sent to the client, or you’ll get a ‘Headers already sent’ error.

The code

There are three parts to writing a login script.
Firstly, the form: the user is shown this the first time they arrive on the page and if they make a mistake in filling it in (say, they mistyped the password).
Next, the validation script: when the form is submitted, you must check the username and password and, if all is correct, log the user in.
Last but not least, you must make sure users that aren’t logged in can’t see content for registered users only and prevent logged in users from trying to register or log in again.

Oddly enough, I usually find myself programming these three parts in reverse order.

Part three: nudging users in the right direction

So: part three requires us to add a bit of code to all pages that require the user to be logged in. We simply check if the user is logged in and, if he isn’t, redirect him to the login page:

<?php
session_start(); # Start the session
if (!isset($_SESSION['user'])) { # If the user isn't logged in, redirect them
        header('Location: login.php');
        exit();
}
?>

On the other hand, on pages like the login page and the registration page, we need to do the opposite – if users are already logged in, then we redirect them to, say, their account page:

<?php
session_start(); # Start the session
if (isset($_SESSION['user'])) { # If the user is already logged in, redirect them
        header('Location: account.php');
        exit();
}
?>

In both cases, we must start the session first, in order to be able to access the $_SESSION superglobal.

Part two: the validation script

This is really the main part of the login process. I have filled the code with comments to make it more comprehensible:

<?php
redirect = 'account.php'; # Default redirection address if (isset(_POST['submitted'])) { # Only check their login data if they have actually submitted the form
        user = pass = FALSE; # Flag variables

        # Check for username and password values
        if (isset(_POST['user']) && (_POST['user'] !== '')) {
                        user = trim(_POST['user']);
        }
        if (isset(_POST['p4ss']) && (_POST['p4ss'] !== '')) {
                        pass = trim(_POST['p4ss']);
        }

        if (user && pass) { # If both username and password were provided
                        # Here, I'm using the email as username and I'm assuming that the password is stored with a sha1 encryption.
                        q = "SELECT user_id AS id FROM users WHERE email='user' AND pass=SHA1('p')";  # Adapt the query if necessary                         r = @mysqli_query(dbc, q); # Run the query

                        if (@mysqli_num_rows(r) == 1) { # A match was made.                                         # Fetch the user's information:                                         user = mysqli_fetch_array(r, MYSQLI_ASSOC);                                         # Log the user in:                                         _SESSION['user'] = user['id'];                                          # Clear and close the databese connection:                                         mysqli_free_result(r);
                                        mysqli_close(dbc);                                          # Take the user to the next page:                                         header('Location: ' . redirect);
                                        exit(); # Quit the script.

                        } else { # No match was made.
                                        # Notify the user of the error. I usually also give them a link to the registration form
                                        echo '<p class="error">Either there was a mistake in the form or you haven\'t registered yet. <a href="registration.php">Register here.</a></p>';
                        }

        } else { # Either the username or the password were missing
                        echo '<p class="error">Please fill in the whole form!</p>';
        }

}
?>

If you’re wondering where $_POST[‘submitted’] came from, read the next part!

Part one: the form

This is really a fairly basic HTML form, but there’s two points worth noting: the use we make of PHP’s ternary operator to make the form sticky and, more importantly, the hidden form input which we use to check whether the user has submitted the form – by checking if the $_POST[‘submitted’] variable is set.

<form action="#" method="POST">

    <legend for="user">Username: </legend>
    <input type="text" id="user" name="email" size="50" maxlength="120" <?php echo (isset(email)) ? 'value="' . email . '"' : ''; # Make the form sticky ?> /><br />

    <legend for="p4ss">Password: </legend> <input type="password" id="p4ss" name="p4ss" size="50" maxlength="120" /><br />
    <input type="submit" value=" Log in! " />
    <input type="hidden" name="submitted" value="TRUE" /><!-- This hidden form input allows us, in the PHP, to check if the form was submitted - ->

</form>

Useful Links

  • More on PHP superglobals: http://php.net/manual/en/language.variables.superglobals.php
  • More on the session_start function: http://php.net/manual/en/function.session-start.php