Introduction
For this tutorial you will learn how you can create your very own secure PHP login system. A login form is what your website's visitors will use to login to your website to access content for logged-in users (such as a profile page).
Content
- 1- Getting started
- 2- Login Form Design
- 3- Database Settings
- 4- Authentification
- 5- Home Page
- 6- Profile Page
- 7- Logout
-
1- Getting started
There are a few steps we need to take before we create our secure login system. We need to set-up our web server environment and make sure we have the required extensions enabled.
1.1. Requirements
If you haven't got a local web server set-up I recommend you download and install XAMPP.
XAMPP is a cross-platform web server package that includes the essentials for back-end developers. It includes PHP, MySQL, Apache, phpMyAdmin, and more. No need to install all the software separately.1.2. What You Will Learn in this Tutorial
Form Design — Design a login form with HTML5 and CSS3. Prepared SQL Queries — How to prepare SQL queries to prevent SQL injection as this will prevent your database from being exposed. Basic Validation — Validating form data that is sent to the server (username and password). Session Management — Initialize sessions and store retrieved database results.1.3. File Structure & Setup
We now need to start our web server and create the files and directories we're going to use for our login system.- Open XAMPP Control Panel
- Next to the Apache module click Start
- Next to the MySQL module click Start
- Navigate to XAMPPs installation folder (C:\xampp)
- Open the htdocs folder
Create the following folders and files:
index.html
— The login form created with HTML5 and CSS3. We don't need to use PHP in this file. Therefore, we can save it as plain HTML.style.css
— The stylesheet (CSS) for our secure login app.authenticate.php
— Authenticate users, connect to the database, validate form data, retrieve database results, and create new sessions.logout.php
— Destroy the logged-in sessions and redirect the user.home.php
— Basic home page for logged-in users.profile.php
— Select the user's account from our MySQL database and populate the account details.
2- Login Form Design
We need a login form for our websites users to interact with and enter their details. We will be using HTML and CSS for this part of the tutorial as PHP will not be necessary on this page.
Edit theindex.html
file with your favorite code editor as we're going to edit this file and add the login form code.
Add the following code:<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Login</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
</head>
<body>
<div class="login">
<h1>Login</h1>
<form action="authenticate.php" method="post">
<label for="username">
<i class="fas fa-user"></i>
</label>
<input type="text" name="username" placeholder="Username" id="username" required>
<label for="password">
<i class="fas fa-lock"></i>
</label>
<input type="password" name="password" placeholder="Password" id="password" required>
<input type="submit" value="Login">
</form>
</div>
</body>
</html>Let's open up our
style.css
file and add the following code:* {
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, ubuntu, cantarell, "fira sans", "droid sans", "helvetica neue", Arial, sans-serif;
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
background-color: #435165;
}
.login {
width: 400px;
background-color: #ffffff;
box-shadow: 0 0 9px 0 rgba(0, 0, 0, 0.3);
margin: 100px auto;
}
.login h1 {
text-align: center;
color: #5b6574;
font-size: 24px;
padding: 20px 0 20px 0;
border-bottom: 1px solid #dee0e4;
}
.login form {
display: flex;
flex-wrap: wrap;
justify-content: center;
padding-top: 20px;
}
.login form label {
display: flex;
justify-content: center;
align-items: center;
width: 50px;
height: 50px;
background-color: #3274d6;
color: #ffffff;
}
.login form input[type="password"], .login form input[type="text"] {
width: 310px;
height: 50px;
border: 1px solid #dee0e4;
margin-bottom: 20px;
padding: 0 15px;
}
.login form input[type="submit"] {
width: 100%;
padding: 15px;
margin-top: 20px;
background-color: #3274d6;
border: 0;
cursor: pointer;
font-weight: bold;
color: #ffffff;
transition: background-color 0.2s;
}
.login form input[type="submit"]:hover {
background-color: #2868c7;
transition: background-color 0.2s;
}We need to include our stylesheet in our index.html file so we must add the following code to the head section:
<link href="style.css" rel="stylesheet" type="text/css">
And now if we refresh the index.html page in our web browser our login form will look more appealing:
Let's narrow down the form so we can get a better understanding on what's going on.
- Form — We need to use both the
action
andpost
attributes. Theaction
attribute will be set to the authentication file. When the form is submitted, the form data will be sent to the authentication file for processing. In addition, themethod
is declared aspost
as this will allow us to process the form data using the POST request method.- Input (text/password) — We need to name our form fields so the server can recognize them. The value of the attribute
name
we can declare asusername
, which we can use to retrieve the post variable in our authentication file to get the data, for example:$_POST['username']
. - Input (submit) — On form submission the data will be sent to our authentication file for processing.
- Input (text/password) — We need to name our form fields so the server can recognize them. The value of the attribute
3- Database Settings
For this part, you will need to access your MySQL database, either using phpMyAdmin or your preferred MySQL database management application.
Follow the below instructions if you're using phpMyAdmin.
- Navigate to: http://localhost/phpmyadmin/
- Click the Databases tab at the top
- Under Create database, type in phplogin in the text box
- Select utf8_general_ci as the collation
- Click Create
You can use your own database name, but for this tutorial, we'll use
securelogin
.What we need now is an
accounts
table as this will store all the accounts (usernames, passwords, emails, etc) that are registered with the system.Click the database on the left side panel (
securelogin
) and execute the following SQL statement:CREATE TABLE IF NOT EXISTS `accounts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
`email` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;INSERT INTO `accounts` (`id`, `username`, `password`, `email`) VALUES (1, 'test', '$2y$10$SfhYIDtn.iOuCW7zfoFLuuZHX6lja4lF4XA4JqNmpiH/.P3zB8JCa', 'test@test.com');
On
phpMyAdmin
this should look like:The above SQL statement code will create the accounts table with the columns
id
,username
,password
, andemail
.The SQL statement will insert a test account with the username:
test
, and the password:test
. The test account will be used for testing purposes to make sure our login system is functioning correctly.
4- Authentification
Now that we have our database setup, we can go ahead and start coding with PHP. We're going to start with the authentication file, which will process and validate the form data that we'll send from our
index.html
file.Edit the
authenticate.php
file and add the following:<?php
session_start();
// Change this to your connection info.
$DATABASE_HOST = 'localhost';
$DATABASE_USER = 'root';
$DATABASE_PASS = '';
$DATABASE_NAME = 'phplogin';
// Try and connect using the info above.
$con = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME);
if ( mysqli_connect_errno() ) {
// If there is an error with the connection, stop the script and display the error.
exit('Failed to connect to MySQL: ' . mysqli_connect_error());
}The first thing we have to do is start the session as this allows us to preserve account details on the server and will be used later on to remember logged-in users.
Connecting to the database is essential. Without it, how can we retrieve and store information related to our users? Therefore, we must make sure to update the variables to reflect our MySQL database credentials.
Add below:
// Now we check if the data from the login form was submitted, isset() will check if the data exists.
if ( !isset($_POST['username'], $_POST['password']) ) {
// Could not get the data that should have been sent.
exit('Please fill both the username and password fields!');
}This will make sure the form data exists, whereas if the user tries to access the file without submitting the form, it will output a simple error.
Add below:
// Prepare our SQL, preparing the SQL statement will prevent SQL injection.
if ($stmt = $con->prepare('SELECT id, password FROM accounts WHERE username = ?')) {
// Bind parameters (s = string, i = int, b = blob, etc), in our case the username is a string so we use "s"
$stmt->bind_param('s', $_POST['username']);
$stmt->execute();
// Store the result so we can check if the account exists in the database.
$stmt->store_result();
$stmt->close();
}
?>This will prepare the SQL statement that will select the
id
andpassword
columns from the accounts table. It will bind theusername
to the SQL statement, execute, and then store the result.After this line:
$stmt->store_result();
Add :
if ($stmt->num_rows > 0) {
$stmt->bind_result($id, $password);
$stmt->fetch();
// Account exists, now we verify the password.
// Note: remember to use password_hash in your registration file to store the hashed passwords.
if (password_verify($_POST['password'], $password)) {
// Verification success! User has logged-in!
// Create sessions, so we know the user is logged in, they basically act like cookies but remember the data on the server.
session_regenerate_id();
$_SESSION['loggedin'] = TRUE;
$_SESSION['name'] = $_POST['username'];
$_SESSION['id'] = $id;
echo 'Welcome ' . $_SESSION['name'] . '!';
} else {
// Incorrect password
echo 'Incorrect username and/or password!';
}
} else {
// Incorrect username
echo 'Incorrect username and/or password!';
}First, we need to check if the query has returned any results. If the
username
doesn't exist in the database then there would be no results.If the username exists, we can bind the results to the variables:
$id
and$password
.Subsequently, we proceed to verify the password with the
password_verify
function. Only passwords that were created with thepassword_hash
function will work.If you don't want to use any password encryption method, you can simply replace the following code:
if (password_verify($_POST['password'], $password)) {
With :
if ($_POST['password'] === $password) {
Upon successful authentication from the user, session variables will be initialized and remembered throughout the entire process. These session variables are stored on the server and in the user's browser as we'll use these variables to determine if the user is logged-in or not, and to associate the session variables with our retrieved MySQL database results.
Now we can test the login system and make sure the authentication works correctly, navigate to
http://localhost/phplogin/index.html
Type in a random username and password, and click the login button, it should output an error that should look like the following:
Don't worry, it's not broke! If we go back to our login form and enter test for both the username and password fields and you get the login successfull
Welcome test!
5- Home Page
The home page will be the first page our users see when they've logged-in. The only way they can access this page is if they're logged-in, whereas if they not they will be redirected back to the login page.
Edit the
home.php
file and add the following code:<?php
// We need to use sessions, so you should always start sessions using the below code.
session_start();
// If the user is not logged in redirect to the login page...
if (!isset($_SESSION['loggedin'])) {
header('Location: index.html');
exit;
}
?>Basically, what happens here is we check if the user is logged in, if they are not we redirect them to the homepage, remember the
$_SESSION['loggedin']
variable we defined in theauthenticate.php
file? This is what we use to determine if users are logged in or not.Now we can add some HTML to our home page. Below the closing tag add the following code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Home Page</title>
<link href="style.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
</head>
<body class="loggedin">
<nav class="navtop">
<div>
<h1>Website Title</h1>
<a href="profile.php"><i class="fas fa-user-circle"></i>Profile</a>
<a href="logout.php"><i class="fas fa-sign-out-alt"></i>Logout</a>
</div>
</nav>
<div class="content">
<h2>Home Page</h2>
<p>Welcome back, <?=$_SESSION['name']?>!</p>
</div>
</body>
</html>As you can see here all we do is create the layout for our home page and greet the user.
The CSS for the home page, add to
style.css
:.navtop {
background-color: #2f3947;
height: 60px;
width: 100%;
border: 0;
}
.navtop div {
display: flex;
margin: 0 auto;
width: 1000px;
height: 100%;
}
.navtop div h1, .navtop div a {
display: inline-flex;
align-items: center;
}
.navtop div h1 {
flex: 1;
font-size: 24px;
padding: 0;
margin: 0;
color: #eaebed;
font-weight: normal;
}
.navtop div a {
padding: 0 20px;
text-decoration: none;
color: #c1c4c8;
font-weight: bold;
}
.navtop div a i {
padding: 2px 8px 0 0;
}
.navtop div a:hover {
color: #eaebed;
}
body.loggedin {
background-color: #f3f4f7;
}
.content {
width: 1000px;
margin: 0 auto;
}
.content h2 {
margin: 0;
padding: 25px 0;
font-size: 22px;
border-bottom: 1px solid #e0e0e3;
color: #4a536e;
}
.content > p, .content > div {
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.1);
margin: 25px 0;
padding: 25px;
background-color: #fff;
}
.content > p table td, .content > div table td {
padding: 5px;
}
.content > p table td:first-child, .content > div table td:first-child {
font-weight: bold;
color: #4a536e;
padding-right: 15px;
}
.content > div p {
padding: 5px;
margin: 0 0 10px 0;
}Now that we have our home page setup we can redirect our users from the
authenticate.php
file, editauthenticate.php
and replace this line of code:echo 'Welcome ' . $_SESSION['name'] . '!';
With:
header('Location: home.php');
If you log-in with the test account you should be redirected to the home page.
6- Profile Page
The profile page will display the account information for the logged-in user.
Edit the
profile.php
file and add the following code:<?php
// We need to use sessions, so you should always start sessions using the below code.
session_start();
// If the user is not logged in redirect to the login page...
if (!isset($_SESSION['loggedin'])) {
header('Location: index.html');
exit;
}
$DATABASE_HOST = 'localhost';
$DATABASE_USER = 'root';
$DATABASE_PASS = '';
$DATABASE_NAME = 'phplogin';
$con = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME);
if (mysqli_connect_errno()) {
exit('Failed to connect to MySQL: ' . mysqli_connect_error());
}
// We don't have the password or email info stored in sessions so instead we can get the results from the database.
$stmt = $con->prepare('SELECT password, email FROM accounts WHERE id = ?');
// In this case we can use the account ID to get the account info.
$stmt->bind_param('i', $_SESSION['id']);
$stmt->execute();
$stmt->bind_result($password, $email);
$stmt->fetch();
$stmt->close();
?>This demonstrates how you can get additional account information from the database, as before with home page we didn't need to connect to the database because we used the session data.
We're going to display all the account information for the user, so we need to get the
password
andemail
fields from the database, we don't need to get theusername
orid
fields because we've them stored in session variables that were created in theauthenticate.php
file.After the closing tag, add the following code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Profile Page</title>
<link href="style.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
</head>
<body class="loggedin">
<nav class="navtop">
<div>
<h1>Website Title</h1>
<a href="profile.php"><i class="fas fa-user-circle"></i>Profile</a>
<a href="logout.php"><i class="fas fa-sign-out-alt"></i>Logout</a>
</div>
</nav>
<div class="content">
<h2>Profile Page</h2>
<div>
<p>Your account details are below:</p>
<table>
<tr>
<td>Username:</td>
<td><?=$_SESSION['name']?></td>
</tr>
<tr>
<td>Password:</td>
<td><?=$password?></td>
</tr>
<tr>
<td>Email:</td>
<td><?=$email?></td>
</tr>
</table>
</div>
</div>
</body>
</html>A simple layout to display account information, if you navigate to
profile.php
this will look like:
6- Logout
Creating the logout script is very simple, all you need to do is destroy the sessions that we created.
Edit the
logout.php
file and add the following code: