DEV Community

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

Posted on

2

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

Reinvent your career. Join DEV.

It takes one minute and is worth it for your career.

Get started

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

👥 Ideal for solo developers, teams, and cross-company projects

Learn more

👋 Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay