Create a secure login area using PHP
Published on February 24th, 2024If you’re looking to have anyone log into your website, PHP is a great way to code this yourself securely.
In this post, I’ll take you through creating a basic user authentication system using PHP. To keep things simple initially, I’ll store the user information (username and password) in the script. Once you’ve got this working, you should consider adding code to lookup the user information from a database (where you should store a hash of the password, rather than the password itself), this will make the script scalable for any secure login areas you need.
Creating the login page
Let’s start with a very basic HTML page that uses a form to post our users login information to us. We’ll evolve this page through this post.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Login Page</title>
</head>
<body>
<form method="post">
<input type="text" placeholder="username" name="usrnme" />
<input type="password" placeholder="password" name="passwd"/>
<input type="submit" value="login">
</form>
</body>
</html>
This extremely basic HTML page will now act as the first version of our login page. You’ll obviously want to make this fit the design of your site, once setup.
Note that there is no form action attribute, this is because, by default your browser will submit to the input page (back to itself). This means, we can configure the username/password check into the same page, to warn users when they’ve failed to input information correctly.
It’s also worth noting that I’ve set the form method to “post”. This is important, as the alternative (“get”) displays the input information (including the password) in the address bar, and would therefore be recorded in the browsers history, and be visible to anyone between your device and the server (e.g. your internet service provider). You should therefore stick with the “post” form method therefore for login pages.
Checking the username and password
At the start, I mentioned that this post will keep things simple, and lookup a password that is stored within the script itself. I would strongly recommend you consider using a database to store user information rather than storing it in a script, even if its only one user today, it will give flexibility to your site, may increase security, and allows you to reuse your work on other projects that may need many users.
So, we’ve now got a basic login page which posts the username (as “usrnme”) and password (as “passwd”) to the login page again. So now we can add some PHP to check the entered username and password. This is added to the start of our login page, so it runs before the form is loaded.
<?php
// Start a PHP session - This must be the first thing in your script
session_start();
// Check if the browser is already logged in - if so, send to the default page for a logged in user
if (isset($_SESSION['usr_logged_in'])) {
include ("loggedin.htm");
exit();
}
// Check for posted username and password variables
// (i.e. Has the user submitted the form, rather than just arrived at this login page for the first time)
if (isset($_POST['usrnme']) && isset($_POST['passwd'])) {
// ------------------------
// Script Improvement - In this position you should consider a database lookup to gather user information for the provided username ("usrnme"). To keep things simple, in this example to keep things simple for tutorial purposes, the user information is hard-coded below. If you choose to hard-code user data, do not include the actual password, just include the hash. For demonstration purposes the hash is calculated below, this should only be done at the time of user creation to avoid hard-coding the password into a script, which would be retrieved by a hacker:
$correctusr="admin";
$correctpwdhashed=password_hash("letmein",PASSWORD_DEFAULT);
// ------------------------
// Check the username and password provided are correct
// I choose to drop the username to lowercase to avoid case-sensitive issues
if (strtolower($correctusr) == strtolower($_POST['usrnme'])){
//Correct Username, therefore check the password
if (password_verify($_POST['passwd'], $correctpwdhashed)) {
// The username and password are both correct
// Set a session variable so further pages know this user is already authenticated
$_SESSION['usr_logged_in'] = strtolower($usrnme);
// After login we move to the default page for logged in users
include ("loggedin.htm");
exit();
}else{
// Incorrect Password - don't declare it was just the password that was incorrect, as this could help a hacker
$error="Error: You entered an invalid username/password";
}
}else{
// Incorrect Username - don't declare it was the username that was incorrect, as this could help a hacker (use the same error message as incorrect password therefore)
$error="Error: You entered an invalid username/password";
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Login Page</title>
</head>
<body>
<?php
if (isset($error)){
echo("<div>".$error."</div>");
}
?>
<form method="post">
<input type="text" placeholder="username" name="usrnme" />
<input type="password" placeholder="password" name="passwd"/>
<input type="submit" value="login">
</form>
</body>
</html>
Essentially the above is the same as before, with two pieces of PHP added. The first checks the posted information for valid user information, setting a session variable and passing the user to the logged in area if valid, or setting the $error variable if not. The second then sits within the HTML, and displays an extra row, with the error message, if set.
What the first piece of PHP also does is check whether the user is already logged in (by checking if the session variable is in-fact already set). This might occur when a user returns to a bookmarked page, or uses the back button. In these cases, we forward them back to the logged in page, so they don’t have to re-login (not essential, but this improves the user experience).
Note that the first code line is “session_start();”, this is vital, as any lines appearing before it (including blank lines) can result in the page headers being set, which results in an error like the below. This can be avoided by ensuring the “session_start();” is the first line of code in the file.
Warning: session_start() [function.session-start]: Cannot send session cookie – headers already sent by (output started at /home/exampledomain/public_html/login.php:29) in /home/exampledomain/public_html/login.php on line 15
This is an amazingly common PHP error, and yet is easily avoided. just start the file with a PHP open tag (“<?php”), and carriage return, and then your session_start command.
Keep checking
In the example above, we sent the user to another page once logged in (loggedin.htm), and logically the user may have multiple pages available to them as a logged in user. So we need to verify that users aren’t accessing these pages directly. We also need to be able to identify the user once at these pages (in-case personalised content is required. Well this isn’t too painful as we used a session variable to store the username once correctly logged in.
Session variables can only be set by the server, so this is much safer than any Javascript login method… scarily employed on some smaller sites that don’t realise its a client-side language and hence open to easy abuse.
Here’s an example page that might feature in our logged in area:
<?php
// Start a PHP session - This must be the first thing you do
session_start();
// Check if user is already logged in - if not, send to login page
if (isset($_SESSION['usr_logged_in'])) {
include ("login.htm");
exit();
}
?>
<html>
<head>
<title>Members Area</title>
</head>
<body>
Welcome <?php echo($_SESSION['usr_logged_in']); ?> to the logged in area!
</body>
</html>
You’ll notice, this page is almost identical to the top of the login page, as it once again opens the session, and reviews the session variable. This time however, we’re looking to see if the session variable has not been set.
If $_SESSION[‘usr_logged_in’] is set then we have a logged in user, and can display the page. If not, we return them to the login page, to login. The beauty of using the username as the variable content is that it can now be used to lookup user specific information to be displayed. You could, of course, use a separate session variable for storing the username, or any other piece of information you wanted to make available to each page (e.g. account number, real name etc..).
Log Out / Log Off function
PHP Sessions do expire, but it is good practice, and better security for your users, if you provide a logout/logoff option.
As we are using the session variable $_SESSION[‘usr_logged_in’] to check for a users logon status, we simply need to unset this variable to log them off. A second option (best option if you don’t need the session for any other purpose) is to unset all session variables and destroy the session compeltely. Either way, we need to remember to open the PHP session first so we have access to it.
Our final script therefore looks something like this (logout.php):
<?php
// Start a PHP session - This must be the first thing you do
session_start();
// Option 1: Unset the session variable you're using (if it exists)
// This option is best if you need the session for anything else (unlikely)
if (isset($_SESSION['usr_logged_in'])) {
unset($_SESSION['usr_logged_in']);
}
// Option 2: unset all session variables in a single command, then destroy the session itself
session_unset();
session_destroy();
// Return the now logged-off user to the login page
include ("login.htm");
exit();
?>