DEV Community

Cover image for PHP crash course : Simple User Authentication System
MD ARIFUL HAQUE
MD ARIFUL HAQUE

Posted on

PHP crash course : Simple User Authentication System

A basic user registration and login system built with PHP, HTML, jQuery, AJAX, JSON, Bootstrap, CSS, and MySQL. This project demonstrates a simple yet secure way to handle user authentication, including registration, login, and session management.

Topics: php, mysql, ajax, json, bootstrap, jquery, css, user authentication, user registration, user-login, session management

Step-by-Step Solution

1. Directory Structure

simple-user-authentication-system/
│
├── backend/
│   └── index.php
│
├── assets/
│   ├── css/
│   │   └── style.css
│   └── js/
│       └── script.js
│
├── db/
│   └── database.sql
│
├── includes/
│   ├── config.sample.php
│   ├── db.php
│   ├── login.php
│   ├── logout.php
│   └── register.php
│
├── src/
│   ├── login.php
│   ├── logout.php
│   └── register.php
│
├── index.html
├── register.html
├── login.html
├── README.md
└── .gitignore
Enter fullscreen mode Exit fullscreen mode

2. Database Schema

db/database.sql:

CREATE TABLE `users` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `username` varchar(50) NOT NULL,
   `email` VARCHAR(100) NOT NULL UNIQUE,
   `password` varchar(255) NOT NULL,
   `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
   PRIMARY KEY (`id`),
   UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Enter fullscreen mode Exit fullscreen mode

3. Configuration File

Configuration settings (include/config.sample.php)

<?php
// Database configuration
define('DB_HOST', 'localhost'); // Database host
define('DB_NAME', 'user_authentication'); // Database name
define('DB_USER', 'root'); // Change if necessary
define('DB_PASS', ''); // Change if necessary
?>
Enter fullscreen mode Exit fullscreen mode

4. Configure the Database Connection

Establishing database connection (include/db.php)

<?php
include 'db.php';

// Database configuration
$dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME;
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

// Create a new PDO instance
try {
    $pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Set error mode to exception
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage(); // Display error message if connection fails
}
?>
Enter fullscreen mode Exit fullscreen mode

5. HTML and PHP Structure

HTML Structure (index.html)

home

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Home</title>
   <link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<div class="wrapper">
   <h1>Welcome, Guest!</h1>
   <a href="login.html">Login</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;<a href="register.html">Sign up</a>
</div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Registration User Structure (register.html)

register

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Sign Up</title>
   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
   <link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<div class="wrapper">
   <h2>Sign Up</h2>
   <p>Please fill this form to create an account.</p>
   <span class="message"></span>
   <form id="registerForm">
      <div class="form-group">
         <label>Username</label>
         <input type="text" name="username" class="form-control">
         <span class="help-block username"></span>
      </div>
      <div class="form-group">
         <label for="email">Email:</label>
         <input type="email" class="form-control" id="email" name="email">
         <span class="help-block email"></span>
      </div>
      <div class="form-group">
         <label>Password</label>
         <input type="password" name="password" class="form-control">
         <span class="help-block password"></span>
      </div>
      <div class="form-group">
         <label>Confirm Password</label>
         <input type="password" name="confirm_password" class="form-control">
         <span class="help-block confirm_password"></span>
      </div>
      <div class="form-group">
         <input type="submit" class="btn btn-primary" value="Submit">
      </div>
      <p>Already have an account? <a href="login.html">Login here</a>.</p>
   </form>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="assets/js/script.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

(src/register.php)

<?php

require_once '../include/register.php';

$username = $password = $confirm_password= $email = "";
$response = [];
$response['status'] = true;
if($_SERVER["REQUEST_METHOD"] == "POST") {

    if(empty(trim($_POST["username"]))) {
        $response['status'] = false;
        $response['field'] = 'username';
        $response['message'] = "Please enter a username.";
    } elseif(empty(trim($_POST["email"]))) {
        $response['status'] = false;
        $response['field'] = 'email';
        $response['message'] = "Please enter a email.";
    } elseif(empty(trim($_POST["password"]))) {
        $response['status'] = false;
        $response['field'] = 'password';
        $response['message'] = "Please enter a password.";
    } elseif(strlen(trim($_POST["password"])) < 6) {
        $response['status'] = false;
        $response['field'] = 'password';
        $response['message'] = "Password must have at least 6 characters.";
    } elseif(empty(trim($_POST["confirm_password"]))) {
        $response['status'] = false;
        $response['field'] = 'confirm_password';
        $response['message'] = "Please confirm password.";
    } elseif(trim($_POST["password"]) != trim($_POST["confirm_password"])) {
        $response['status'] = false;
        $response['field'] = 'confirm_password';
        $response['message'] = "Password did not match.";
    }else {
        $username = trim($_POST["username"]);
        $email = trim($_POST["email"]);
        $password = trim($_POST["password"]);
        $confirm_password = trim($_POST["confirm_password"]);
        $password_hash = password_hash($password, PASSWORD_DEFAULT);
        $response = register_user($username, $email, $password_hash);
    }

}
echo json_encode($response);
?>
Enter fullscreen mode Exit fullscreen mode

(include/register.php)

<?php
require_once 'db.php';
/**
 * @param $username
 * @param $email
 * @param $password
 * @return array
 */
function register_user($username, $email, $password) {
    global $pdo;
    $response = [];
    $response['status'] = true;
    // Check if the username already exists
    $sql = "SELECT id FROM users WHERE username = :username OR email = :email";
    if($stmt = $pdo->prepare($sql)) {
        $stmt->bindParam(":username", $username, PDO::PARAM_STR);
        $stmt->bindParam(":email", $email, PDO::PARAM_STR);
        if($stmt->execute()) {
            if($stmt->rowCount() == 1) {
                $response['status'] = false;
                $response['message'] = "Username or email already exists.";
            } else {
                // Username is available, so insert the new user
                $sql = "INSERT INTO users (username, email, password) VALUES (:username, :email, :password)";
                if($stmt = $pdo->prepare($sql)) {
                    // Bind variables to the prepared statement
                    $stmt->bindParam(":username", $username, PDO::PARAM_STR);
                    $stmt->bindParam(":email", $email, PDO::PARAM_STR);
                    $stmt->bindParam(":password", $password, PDO::PARAM_STR);

                    // Attempt to execute the prepared statement
                    if($stmt->execute()) {
                        $response['message'] = "Registration successful!";
                    } else {
                        $response['status'] = false;
                        $response['message'] = "Something went wrong. Please try again later.";
                    }
                }else{
                    $response['status'] = false;
                    $response['message'] = 'Registration failed. Please try again.';
                }
            }
        } else {
            $response['status'] = false;
            $response['message'] = "Oops! Something went wrong. Please try again later.";
        }
    }
    unset($stmt);
    unset($pdo);
    return $response;
}
Enter fullscreen mode Exit fullscreen mode

Login User Structure (index.html)

login

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Home</title>
   <link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<div class="wrapper">
   <h1>Welcome, Guest!</h1>
   <a href="login.html">Login</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;<a href="register.html">Sign up</a>
</div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

(src/login.php)

<?php
require_once '../include/login.php';

$result = [];
if($_SERVER["REQUEST_METHOD"] == "POST") {
    $username = trim($_POST['username']);
    $password = trim($_POST['password']);

    // Check for empty fields
    if (empty($username) || empty($password)) {
        $response['status'] = false;
        $response['message'] = 'Please fill in all fields.';
    } else {
        $result = login_user($username, $password);
    }
    echo json_encode($result);
}
?>

?>
Enter fullscreen mode Exit fullscreen mode

(include/login.php)

<?php
<?php
require_once 'db.php';
/**
 * @param $username
 * @param $password
 * @return array
 */
function login_user($username, $password) {
    global $pdo;
    $response = array();
    $sql = "SELECT id, username, password FROM users WHERE username = :username";
    if($stmt = $pdo->prepare($sql)) {
        $stmt->bindParam(":username", $username, PDO::PARAM_STR);
        if($stmt->execute()) {
            if($stmt->rowCount() == 1) {
                if($row = $stmt->fetch()) {
                    $id = $row["id"];
                    $username = $row["username"];
                    $hashed_password = $row["password"];
                    if(password_verify($password, $hashed_password)) {
                        // Password is correct, start a new session
                        session_start();
                        $_SESSION["loggedin"] = true;
                        $_SESSION["id"] = $id;
                        $_SESSION["username"] = $username;

                        $response['status'] = true;
                        $response['message'] = 'Login successful!';
                    } else {
                        $response['status'] = false;
                        $response['message'] = 'The password you entered was not valid.';
                    }
                }
            } else {
                $response['status'] = false;
                $response['message'] = 'No account found with that username.';
            }
        } else {
            $response['status'] = false;
            $response['message'] = 'Oops! Something went wrong. Please try again later.';
        }
    }
    unset($stmt);
    unset($pdo);
    return $response;
}

Enter fullscreen mode Exit fullscreen mode

After Login User Structure (backend/index.php)

after-login

<?php
session_start();
if (!isset($_SESSION['username'])) {
    header('Location: ../index.html');
    exit();
}
?>
Enter fullscreen mode Exit fullscreen mode
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Home</title>
   <link rel="stylesheet" href="../assets/css/style.css">
</head>
<body>
<div class="wrapper">
   <h1>Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?>!</h1>
   <a href="../src/logout.php">Logout</a>
</div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Logout (src/logout.php)

<?php
require_once '../include/logout.php';
logout_user();
?>
Enter fullscreen mode Exit fullscreen mode

(include/logout.php)

<?php
require_once 'db.php';
/**
 * @return void
 */
function logout_user() {
    session_start();
    $_SESSION = array();
    session_destroy();
    header("location: ../backend/index.php");
    exit;
}

Enter fullscreen mode Exit fullscreen mode

6. JavaScript and AJAX

AJAX Handling (assets/js/script.js)

$(document).ready(function() {
   $('.help-block').hide();
   $("#registerForm").submit(function(event) {
      event.preventDefault();
      $('.help-block').hide();
      $.ajax({
         url: "src/register.php",
         type: "post",
         dataType: 'json',
         data: $(this).serialize(),
         success: function(response) {
            if(response.status === false){
               if(response.field){
                  $('.' + response.field).show();
                  $('.' + response.field).html(response.message);
               }else{
                  $('.message').html(response.message);
               }
            }else{
               $('#registerForm')[0].reset();
               $('#registerForm').hide();
               $('h2').hide();
               $('p').html(response.message + ' <a href="login.html">Please Login here</a>');
               //window.location.href = 'index.html';
            }
         }
      });
   });

   $("#loginForm").submit(function(event) {
      event.preventDefault();
      $.ajax({
         url: "src/login.php",
         type: "post",
         dataType: 'json',
         data: $(this).serialize(),
         success: function(response) {
            if (response.status === true) {
               window.location.href = 'backend/index.php';
            }
         }
      });
   });
});
Enter fullscreen mode Exit fullscreen mode

7. Stylesheet (assets/css/style.css)

body {
    font: 14px sans-serif;
}
.wrapper {
    width: 350px;
    padding: 20px;
    margin: 0 auto;
}
.help-block {
    color: red;
}
Enter fullscreen mode Exit fullscreen mode

Documentation and Comments

Each part of the code has been commented to explain what it does:

  • include/config.php: Contains the database connection configuration.
  • include/register.php: Contains helper functions for registering, logging in, and logging out users.
  • include/login.php: Contains helper functions for registering, logging in, and logging out users.
  • include/logout.php: Contains helper functions for registering, logging in, and logging out users.
  • src/register.php: Handles user registration, including form validation and submission via AJAX.
  • src/login.php: Handles user login, including form validation and submission via AJAX.
  • src/logout.php: Handles user logout.
  • assets/css/style.css: Contains basic styles for the pages.
  • assets/js/script.js: Contains the jQuery AJAX functions for handling form submissions.

This project setup and code should help you create a basic user authentication system.

Connecting Links

If you found this series helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

If you want more helpful content like this, feel free to follow me:

Source Code

Top comments (0)