Secure Login and Registration in PHP using Prepared Statements Tutorial

Introduction

In this tutorial, you will learn the basics and best practices to create a Secure Login and Registration in PHP. This tutorial provides sample snippets that demonstrate a secure login and registration feature in PHP using Prepared Statements. The main goal of this article is to provide the students or those programmers who are new to PHP Language a reference to learn with.

Why do we need to secure our Web Application Login and Registration?

We must secure our site's login and registration feature and functionality to prevent malicious hackers to ruin or get access to our site's data. Doing so, your end-users will trust also your site for using it because it protects their data especially if they are storing sensible or personal data and information on your site.

How can we Create a Secure Login and Registration using PHP?

There are a lot of ways and techniques to create a secure login and registration feature for sites. One of the most common nowadays is, developers create a 2 Factor Authentication or oAuth, Here, I will only show you or teach you the best practice to create a basic one using the PHP Prepared Statements and sanitizing the data.

Getting Started

Kindly download a virtual server software such as the XAMPP/WAMP on your local machine to run our PHP scripts and for the MySQL Database. After successful installation of the software make sure that your Apache and MySQL are already started or running on your local machine.

Creating the Database

Create a new database and name it "sample_db". If you are using XAMPP/WAMP, browse http://localhost/phpmyadmin in your preferred browser to create a database. After that run or execute the following MySQL Script to create the `users` table in your newly created database.

  1. CREATE TABLE `user_tbl` (
  2.   `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  3.   `first_name` varchar(250) NOT NULL,
  4.   `middle_name` varchar(250) NOT NULL,
  5.   `last_name` varchar(250) NOT NULL,
  6.   `username` text NOT NULL,
  7.   `password` text NOT NULL
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Creating the Database Connection

The following snippet is the PHP Script that connects your site to the database. Save the script as "db-connect.php" in your source code folder.

  1. <?php
  2. // Server Name
  3. $host = "localhost";
  4. // Database Username
  5. $username = "root";
  6. // Database Password
  7. $password = "";
  8. // Database Name
  9. $db_name = "sample_db";
  10.  
  11. // Create Connection
  12. $conn = new mysqli($host, $username, $password, $db_name);
  13.  
  14. // Check if database connection failed then do die
  15. if(!$conn){
  16.     die("Database connection failed.");
  17. }
  18. ?>

Creating the Authentication

The following snippet is a PHP script that contains the code to authenticate the user if he/she is allowed to load the current page. This code prevents the users to access the main page without logging in to the site. Save the script as "auth.php".

  1. <?php
  2. $_self =  $_SERVER['PHP_SELF'];
  3.  
  4. if(preg_match_all("/login\.php/", $_self) || preg_match_all("/register\.php/", $_self)){
  5.     // Check if page is in login or registration page
  6.     if(isset($_SESSION['id']) && !empty($_SESSION['id'])){
  7.         header('location: index.php');
  8.     }
  9. }else{
  10.     // Check if not in login or registration page
  11.     if(!isset($_SESSION['id']) || (isset($_SESSION['id']) && empty($_SESSION['id']))){
  12.         header('location: login.php');
  13.     }
  14. }
  15. ?>

Creating the Registration

Here is the sample snippet for creating a Registration Page for your site. It contains HTML and PHP Scripts for the page interface and the registration form of the site. This file also contains the code for processing or saving the new user information to the database. Save the file as "register.php"

  1. <?php
  2. include "db-connect.php";
  3. require_once("auth.php");
  4.  
  5. if($_SERVER['REQUEST_METHOD'] == "POST"){
  6.    $fname = addslashes($conn->real_escape_string($_POST['first_name']));
  7.     $mname = addslashes($conn->real_escape_string($_POST['middle_name']));
  8.     $lname = addslashes($conn->real_escape_string($_POST['last_name']));
  9.     $uname = addslashes($conn->real_escape_string($_POST['username']));
  10.     $password = password_hash($_POST['password'], PASSWORD_DEFAULT);
  11.     // Check username duplication
  12.     $check = $conn->query("SELECT id FROM `user_tbl` where `username` = '{$uname}'")->num_rows;
  13.     if($check > 0){
  14.         $err = "Username is already taken!";
  15.     }else{
  16.         $sql = "INSERT INTO `user_tbl` (`first_name`, `middle_name`, `last_name`, `username`, `password`) VALUES (?, ?, ?, ?, ?)";
  17.         $stmt = $conn->prepare($sql);
  18.         $stmt->bind_param("sssss", $fname, $mname, $lname, $uname, $password);
  19.         $stmt->execute();
  20.         if($stmt->affected_rows > 0){
  21.             $success = "Account has been created succesfully. <a href='login.php'>Login Now!</a>";
  22.             $_SESSION['success_msg'] = $success;
  23.             header('location: register.php');
  24.             unset($_POST);
  25.             exit;
  26.         }else{
  27.             $err = "Creating your account has been failed for some reason!";
  28.         }
  29.     }
  30. }
  31. ?>
  32. <!DOCTYPE html>
  33. <html lang="en">
  34.     <meta charset="UTF-8">
  35.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  36.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  37.     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
  38.     <title>Registration - Secure Login and Registration</title>
  39.     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.min.js" integrity="sha384-ODmDIVzN+pFdexxHEHFBQH3/9/vQ9uori45z4JjnFsRydbmQbmL5t1tQ0culUzyK" crossorigin="anonymous"></script>
  40.     <style>
  41.         html, body {
  42.             min-height:100%;
  43.             width: 100%
  44.         }
  45.     </style>
  46. </head>
  47. <body class="bg-primary bg-opcaity-75 bg-gradient">
  48.     <div class="container my-5 py-4">
  49.         <h2 class="text-center text-light">Create New Account</h2>
  50.         <div class="col-lg-5 mx-auto">
  51.             <hr class="border-light" height="2px">
  52.             <div class="card rounded-0">
  53.                 <div class="card-body rounded-0">
  54.                     <div class="container-fluid">
  55.                         <form id="registration-form" action="" method="POST">
  56.                             <div class="mb-3">
  57.                                 <label for="first_name"><b>First Name</b> <span class="text-danger">*</span></label>
  58.                                 <input type="text" class="form-control rounded-0" id="first_name" name="first_name" required="required" value="<?= isset($_POST['first_name']) ? $_POST['first_name'] : '' ?>" placeholder="John">
  59.                             </div>
  60.                             <div class="mb-3">
  61.                                 <label for="middle_name"><b>Middle Name</b></label>
  62.                                 <input type="text" class="form-control rounded-0" id="middle_name" name="middle_name" value="<?= isset($_POST['middle_name']) ? $_POST['middle_name'] : '' ?>" placeholder="(optional))">
  63.                             </div>
  64.                             <div class="mb-3">
  65.                                 <label for="last_name"><b>Last Name</b> <span class="text-danger">*</span></label>
  66.                                 <input type="text" class="form-control rounded-0" id="last_name" name="last_name" required="required" value="<?= isset($_POST['last_name']) ? $_POST['last_name'] : '' ?>" placeholder="Smith">
  67.                             </div>
  68.                             <div class="mb-3">
  69.                                 <label for="username"><b>Username</b></label>
  70.                                 <input type="text" class="form-control rounded-0" id="username" name="username" required="required" value="<?= isset($_POST['username']) ? $_POST['username'] : '' ?>" placeholder="myusername">
  71.                             </div>
  72.                             <div class="mb-3">
  73.                                 <label for="password"><b>Password</b></label>
  74.                                 <input type="password" class="form-control rounded-0" id="password" name="password" required="required" placeholder="********">
  75.                             </div>
  76.                             <?php if(isset($_SESSION['success_msg']) && !empty($_SESSION['success_msg'])): ?>
  77.                                 <div class="alert alert-success">
  78.                                     <?= $_SESSION['success_msg'] ?>
  79.                                 </div>
  80.                                 <?php unset($_SESSION['success_msg']); ?>
  81.                             <?php else: ?>
  82.                             <p class="text-center">
  83.                                 <a href="login.php">Already have an account? Login here</a>
  84.                             </p>
  85.                             <?php endif; ?>
  86.                             <?php if(isset($err) && !empty($err)): ?>
  87.                                 <div class="alert alert-danger">
  88.                                     <?= $err ?>
  89.                                 </div>
  90.                             <?php endif; ?>
  91.                         </form>
  92.                     </div>
  93.                 </div>
  94.                 <div class="card-footer text-center">
  95.                     <button class="btn btn-primary rounded-0" form="registration-form">Create Account</button>
  96.                 </div>
  97.             </div>
  98.         </div>
  99.     </div>
  100. <?php
  101. $conn->close();
  102. ?>
  103. </body>
  104. </html>

Result

PHP - Registration

Creating the Login

The next snippet is the Login Page scripts that consist also of HTML and PHP Scripts. It contains the elements of the page interface of the login form. Save the file as "login.php".

  1. <?php
  2. include "db-connect.php";
  3. require_once("auth.php");
  4. // Process Login
  5. if($_SERVER['REQUEST_METHOD'] == "POST"){
  6.    // username
  7.    $uname = addslashes($conn->real_escape_string($_POST['username']));
  8.     // Check user if Exist
  9.     $sql = "SELECT * FROM `user_tbl` where `username` = ?";
  10.     $stmt = $conn->prepare($sql);
  11.     $stmt->bind_param("s", $uname);
  12.     $stmt->execute();
  13.     $result = $stmt->get_result();
  14.    if($result->num_rows > 0){
  15.     // If user data exist
  16.     $details = $result->fetch_assoc();
  17.     // verify given password
  18.     $password_verify = password_verify($_POST['password'], $details['password']);
  19.     if($password_verify){
  20.         // Save user details on session
  21.         foreach($details as $k => $v){
  22.             $_SESSION[$k] = $v;
  23.         }
  24.         header('location: index.php');
  25.     }else{
  26.         // If Password does not match
  27.         $err = "Invalid match of username and password.";
  28.     }
  29.    }else{
  30.         // If User details does not exist
  31.     $err = "Invalid username.";
  32.    }
  33.    
  34. }
  35. ?>
  36. <!DOCTYPE html>
  37. <html lang="en">
  38.     <meta charset="UTF-8">
  39.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  40.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  41.     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
  42.     <title>Login - Secure Login and Registration</title>
  43.     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.min.js" integrity="sha384-ODmDIVzN+pFdexxHEHFBQH3/9/vQ9uori45z4JjnFsRydbmQbmL5t1tQ0culUzyK" crossorigin="anonymous"></script>
  44.     <style>
  45.         html, body{
  46.             height:100%;
  47.             width:100%;
  48.             margin:unset;
  49.         }
  50.     </style>
  51. </head>
  52. <body class="bg-primary bg-opcaity-75 bg-gradient">
  53.     <div class="container my-auto d-flex flex-column align-items-center justify-content-center h-100">
  54.         <h2 class="text-center text-light">Login Page</h2>
  55.         <hr>
  56.         <div class="col-lg-5 mx-auto">
  57.             <div class="card rounded-0">
  58.                 <div class="card-body rounded-0">
  59.                     <div class="container-fluid">
  60.                         <form id="login-form" action="" method="POST">
  61.                             <div class="mb-3">
  62.                                 <label for="username"><b>Username</b></label>
  63.                                 <input type="text" class="form-control  rounded-0" id="username" name="username" required="required" value="<?= isset($_POST['username']) ? $_POST['username'] : '' ?>" placeholder="myusername">
  64.                             </div>
  65.                             <div class="mb-3">
  66.                                 <label for="password"><b>Password</b></label>
  67.                                 <input type="password" class="form-control  rounded-0" id="password" name="password" required="required" placeholder="********">
  68.                             </div>
  69.                             <?php if(isset($err) && !empty($err)): ?>
  70.                                 <div class="alert alert-danger">
  71.                                     <?= $err ?>
  72.                                 </div>
  73.                             <?php endif; ?>
  74.                             <p class="text-center">
  75.                                 <a href="register.php">Create a New Account</a>
  76.                             </p>
  77.                         </form>
  78.                     </div>
  79.                 </div>
  80.                 <div class="card-footer text-center">
  81.                     <button class="btn btn-primary rounded-0" form="login-form">Login</button>
  82.                 </div>
  83.             </div>
  84.         </div>
  85.     </div>
  86. <?php
  87. $conn->close();
  88. ?>
  89. </body>
  90. </html>

Result

PHP - Login

Creating the Main Page

Here's a sample snippet of the main page for the logged-in users. The page displays the information of the user except for the password. Save the file as "index.php".

  1. <?php
  2. include "db-connect.php";
  3. require_once("auth.php");
  4. ?>
  5. <!DOCTYPE html>
  6. <html lang="en">
  7.     <meta charset="UTF-8">
  8.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  9.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  10.     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
  11.     <title>Home - Secure Login and Registration</title>
  12.     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.min.js" integrity="sha384-ODmDIVzN+pFdexxHEHFBQH3/9/vQ9uori45z4JjnFsRydbmQbmL5t1tQ0culUzyK" crossorigin="anonymous"></script>
  13.     <style>
  14.         html, body{
  15.             height:100%;
  16.             width:100%;
  17.             margin:unset;
  18.         }
  19.     </style>
  20. </head>
  21. <body class="bg-primary bg-opcaity-75 bg-gradient">
  22.     <div class="container h-100 d-flex flex-column align-items-center justify-content-center">
  23.         <div class="col-6 mb-3">
  24.             <h1 class="text-center text-light fw-bolder">PHP Secure Login and Registration</h1>
  25.             <hr class="border-light">
  26.         </div>
  27.         <div class="col-lg-5">
  28.             <div class="card rounded-0">
  29.                 <div class="card-body rounded-0">
  30.                     <div class="container-fluid">
  31.                         <h3 class="text-center">Welcome!</h3>
  32.                         <hr>
  33.                         <h4>Your Account Details:</h4>
  34.                         <dl>
  35.                             <dt>First Name</dt>
  36.                             <dd class="ps-4"><?= $_SESSION['first_name'] ?></dd>
  37.                             <dt>Middle Name</dt>
  38.                             <dd class="ps-4"><?= $_SESSION['middle_name'] ?></dd>
  39.                             <dt>Last Name</dt>
  40.                             <dd class="ps-4"><?= $_SESSION['last_name'] ?></dd>
  41.                             <dt>Username</dt>
  42.                             <dd class="ps-4"><?= $_SESSION['username'] ?></dd>
  43.                         </dl>
  44.                     </div>
  45.                     <div class="d-grid mt-3">
  46.                         <a href="logout.php" class="btn btn-sm btn-danger bg-gradient rounded-0">Logout</a>
  47.                     </div>
  48.                 </div>
  49.             </div>
  50.        </div>
  51.     </div>
  52. <?php
  53. $conn->close();
  54. ?>
  55. </body>
  56. </html>

Result

PHP - Main

Creating the Logout Script

Here's the snippet for destroying the session of the logged-in user. It is a PHP Script that unsets or destroys the current user session. Save the file as "logout.php".

  1. <?php
  2. header('location: login.php');
  3. ?>

DEMO VIDEO

That's it! You can now test the sample application that demonstrates our goal for this tutorial which is a site that contains a secure login and registration feature. If you found or encountered any errors on your end, please review you changes or modifications you've made and try to differentiate them from the codes I provided above. You can also download the working source code I created for this tutorial. The download button is located below this article.

That is the end of this tutorial. I hope this will help you with what you are looking for and that you'll find this useful for your future PHP Projects. Explore more on this website for more Tutorials and Free Source Codes.

Happy Coding :)

Add new comment