Coding a registration system with email verification using php and mysql

Updated: 26-Feb-2024 / Tags: PHP and MYSQL / Views: 3253 - Author: George

Introduction

Welcome to our guide on building a secure login and registration system with email verification using PHP and MySQL. In this tutorial, we'll show you how to create a robust authentication system that ensures the safety of user accounts while providing a seamless user experience.

Key points covered in this article:

  1. Creating PHP functions for user registration, login, password reset, and email verification
  2. Setting up MySQL database tables to securely store user information.
  3. Integrating PHPMailer for seamless email verification.
  4. Using MySQL prepared statements to securely import data into the database
  5. Designing intuitive HTML forms for user interaction.
  6. Applying CSS styling to enhance the visual appeal of the interface.

Live Demo

Explore our live demo to experience firsthand how our secure login and registration system with email verification functions. Test the email verification and forgot password features using your real email address.

Don't worry your email will not be shared or stored, in fact it will be deleted after a few days or so. Every field has a secure validation, so treat the live demo as a real registration process.

Project's folder

To start our project you need to create the below files and folders.

/--projects-folder
  |-- PHPMailer/
  |-- config.php
  |-- functions.php		
  |-- index.php		
  |-- login.php
  |-- forgot-password.php
  |-- auth.php
  |-- account.php
  |-- styles.css
  • Download the PHPMailer Library

    We will use the PHPMailer library to send forgot password and verification emails. So download it from GitHub and insert the extracted folder into your project's directory. Download PHPMailer Library

    PHPMailer is a popular and versatile email-sending library for PHP. It provides a simple and flexible way to send email messages from PHP scripts, supporting various features such as HTML content, file attachments, SMTP authentication, and more. With PHPMailer, developers can easily integrate email functionality into their web applications, ensuring reliable and efficient delivery of emails.

  • Create the Following Files

    config.php: This file will be used to define the login details for your MySQL server as well as the email account to be used with the PHPMailer library.

    functions.php: This file will contain all the necessary PHP functions required for the application to function.

    index.php: This is our starting page and will contain the register form.

    login.php: This page will host the login form.

    forgot-password.php: This page will contain a form with an email field, allowing users to input their email to reset their password.

    auth.php: This page will verify the user's email using the 6-digit code they received during the registration process.

    account.php: After a successful login process the user will be redirected to this page.

    styles.css: Lastly, we have a stylesheet to organize and style our application's layout.

Creating the Database

Let's start coding our application by creating the database.

php my admin image of a users table
  1. Begin by creating a database, using any preferred name. You will need to reference this database name in the 'config.php' file.
  2. Within the database, create a table named 'users' with six columns.
  3. Set the first column's name to 'id', its type to 'int', and designate it as the primary index with auto-increment enabled.
  4. For the second column, name it 'email' and set its type to 'varchar' with a length of 255 characters.
  5. In the third column we set the name to 'username', and the type to 'varchar' with a length of 20 characters.
  6. The fourth column should be named 'password' with a type of 'varchar' and a length of 255 characters. We will hash the password before we insert it in the password filed.
  7. Create a column named 'email_status'. Set its type to 'enum' and provide two arguments: 'pending' and 'verified'. Set the default value of the 'email_status' field to 'pending'. This field will initially have a value of 'pending' when the user registers and will change to 'verified' once the user successfully verifies their email.

  8. Finally, add a column named 'verification_code' with a type of 'varchar' and a length of 6 characters."

    And Our database is now set up and awaits the PHP code for connection.

The Config file

In the 'config.php' file, we will define the MySQL server's login details as well as the login details for the email account to be used with the PHPMailer library.

<?php 
	session_start();
	define('SERVER', 'localhost');
	define('USERNAME', 'mysql-username');
	define('PASSWORD', 'mysql-password');
	define('DATABASE', 'the-database-name-you-created');

// PHPMailer settings. --------------------------------------
/**
 *  Set your smtp server like `mail.domain.com`
 *  or `smtp.mailserver.com`.
 *  Example: If you want to send emails through Gmail 
 *  the syntax is `smtp.gmail.com`.
 *  If you you want to send emails from your website 
 *  the syntax is `mail.your-domain.com`.
 */
	define('MAIL_HOST', 'mail.your-domain.com');
	
/**
 *  Set the email address that you use to log-in 
 *  to your email account.
 *  Note: The email address has to belong to the above MAIL_HOST.
 */	
	define('MAIL_USERNAME', 'your-mail@your-domain.com');

/**
 *  Set the password you use to log-in to the above email account.
 *  Important!! If you use Gmail as your MAIL_HOST you have 
 *  to turn on 2 factor authentication and create an App password 
 *  and use it here instead of your password. 
 */	
	define('MAIL_PASSWORD', 'Your-domain's-email-password);

// Those values are used from the PHPMailer library 
// in the passwordReset(), and sendMessage() functions, 
// in the functions.php file.

// Global variables ----------------------------------------

/**  
 *  We define the website's name in a constant so we can use 
 *  it anywhere in the application.
 *  The WEBSITE_NAME is used in the password-recovery.php file.
 *  Change the value to your website's name. 
 */ 
	define('WEBSITE_NAME', 'Digitalfox-tutorials');
	
/**	
 *  We define the website's URL so we can use it anywhere 
 *  in the application.
 *  The WEBSITE_URL is used in the password-recovery.php file.
 */	
	define('WEBSITE_URL', 'https://digitalfox-tutorials.com');
	

The Functions php file

In the 'functions.php' file we have all the code that we need to make our login and register application functional.

Scroll at the end of the file for a detailed explanation.

<?php 
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;

require 'PHPMailer-master/src/Exception.php';
require 'PHPMailer-master/src/PHPMailer.php';
require 'PHPMailer-master/src/SMTP.php';

require "config.php";

function dbConnect(){
	$mysqli = new mysqli(SERVER, USERNAME, PASSWORD, DATABASE);
	if($mysqli->connect_errno != 0){
		return FALSE;
	}else{
		return $mysqli;
	}
}

function register($email, $username, $password, $confirm_password){
	$mysqli = dbConnect();
	if($mysqli == false){
		return false;
	}

	$args = [
		"email" => $email,
		"username" => $username,
		"password" => $password,
		"confirm-password" => $confirm_password
	];

	$args = array_map(function($value){
		return trim($value);
	}, $args);
	
	foreach ($args as $value) {
		if(empty($value)){
			return "All fields are required";
		}
	}

	foreach ($args as $value) {
		if(preg_match("/([<|>])/", $value)){
			return "<> characters are not allowed";
		}
	}

	$args = array_map(function($value){
		return htmlspecialchars($value);
	}, $args);
	if(!filter_var($args["email"], FILTER_VALIDATE_EMAIL)){
		return "Email is not valid";
	}

	if(mb_strlen($args["username"]) > 20){
		return "The username must be under 20 characters";
	}

	if(mb_strlen($args["password"]) > 20){
		return "The password must be under 20 characters";
	}

	if($args["password"] != $args["confirm-password"]){
		return "Passwords don't match";
	}

	// Get the stored data from the users table.
	$result_set = $mysqli->query("SELECT * FROM users");
	$data = array();
	while($row = $result_set->fetch_assoc()){
		array_push($data, $row);
	}

	foreach ($data as $value) {
		if($args["email"] == $value["email"]){
			return "Email already exists";
		}
	}
	
	foreach ($data as $value) {
		if($args["username"] == $value["username"]){
			return "Username already exists";
		}
	}

	$verification_code = createVerificationCode($data);
	if(!sendVerificationCode($args["email"], $verification_code)){
		return "Error sending verification code. Please try again";
	}

	$hashed_password = 
		password_hash($args["password"], PASSWORD_DEFAULT);
	
	$stmt = 
		$mysqli->prepare(
			"INSERT INTO users
			(email, username, password, verification_code)
			VALUES(?,?,?,?)"
		);

	$stmt->bind_param(
		"sssi", $args["email"], 
		$args["username"], $hashed_password, $verification_code
	);

	$stmt->execute();
	
	if($stmt->affected_rows != 1){
		return "An error occurred. Please try again";
	}else{
		$_SESSION['email'] = $args["email"];
		$_SESSION['verification-code'] = $verification_code;
		header("Location: auth.php");
		exit();
	}
}

function createVerificationCode($database_data){
	$str = "0123456789";
	$random = str_shuffle($str);
	$verification_code = substr($random, 0, 6);
	
	$codes = array_map(
		fn($value) => $value["verification_code"], $database_data
	);

	if(in_array($verification_code, $codes)){
		return createVerificationCode($database_data);
	}else{
		return $verification_code;
	}
}

function sendVerificationCode($email, $verification_code){
	$mail = new PHPMailer(true);

	$mail->isSMTP();
	$mail->Host = MAIL_HOST;
	$mail->SMTPAuth = true;
	$mail->Username = MAIL_USERNAME;
	$mail->Password = MAIL_PASSWORD;
	$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
	$mail->Port = 587;

    // Recipients
    $mail->setFrom(MAIL_USERNAME, WEBSITE_NAME);
    $mail->addAddress($email);	
   
    $mail->Subject = 'Email verification';
    $mail->Body = 
    	"Please use the 6 digits code to verify your email:
    	{$verification_code}";

    if(!$mail->send()){
    	return "Email not send. Please try again";
    }else{
    	return true;
    }
}

function verifyEmail($verification_code){
	$mysqli = dbConnect();
	if($mysqli == false){
		return false;
	}

	if(trim($verification_code) == ""){
		return "Please enter the 6 digits code";
	}

	if(!preg_match("/^\d{6}$/", $verification_code)){
		return "The string expects a 6 digits number";
	}

	$res = $mysqli->query(
		"SELECT verification_code FROM users 
		WHERE verification_code = '$verification_code'"
	);

	if($res->num_rows != 1){
		return "Wrong verification code";
	}else{
		$update = $mysqli->query(
			"UPDATE users SET email_status = 'verified' 
			WHERE verification_code = '$verification_code'
		");

		if($mysqli->affected_rows != 1){
			return "something went wrong. Please try again";
		}else{
			header("Location: login.php");
			exit();
		}
	}
}

function login($username, $password){
	$mysqli = dbConnect();
	if(!$mysqli){
		return false;
	}

	$username = trim($username);
	$password = trim($password);

	if($username == "" || $password == ""){
		return "Both fields are required";
	}

	$sql = "SELECT * FROM users WHERE username = ?";
	$stmt = $mysqli->prepare($sql);
	$stmt->bind_param("s", $username);
	$stmt->execute();
	$result = $stmt->get_result();
	$data = $result->fetch_assoc();
	if($data == NULL){
		return "Wrong username or password";
	}

	if($data["email_status"] == "pending"){
		// we need those session in the auth.php page.
		// First to access the page, and second as arguments 
		// if the user clicks on resend code. 
		$_SESSION['email'] = $data["email"];
		$_SESSION['verification-code'] = $data["verification_code"];

		sendVerificationCode(
			$data["email"], $data["verification_code"]
		);
		
		header("location: auth.php");
		exit();
	}

	if(password_verify($password, $data["password"]) == FALSE){
		return "Wrong username or password";
	}else{
		$_SESSION["user"] = $username;
		header("location: account.php");
		exit();
	}
}

function passwordReset($email){
	$mysqli = dbConnect();
	if(!$mysqli){
		return false;
	}
	$email = trim($email);

	if(!filter_var($email, FILTER_VALIDATE_EMAIL)){
		return "Email is not valid";
	}

	$stmt = $mysqli->prepare(
		"SELECT email FROM users WHERE email = ?"
	);
	
	$stmt->bind_param("s", $email);
	$stmt->execute();
	
	$result = $stmt->get_result();
	$data = $result->fetch_assoc();
	
	if($data == NULL){
		return "Email doesn't exist in the database";
	}

	$str = 
		"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
		abcefghijklmnopqrstuvwxyz";

	$password_length = 7;
	$shuffled_str = str_shuffle($str);
	$new_pass = substr($shuffled_str, 0, $password_length);

	$mail = new PHPMailer(true);
	$mail->isSMTP();
	$mail->Host = MAIL_HOST;
	$mail->SMTPAuth = true;
	$mail->Username = MAIL_USERNAME;
	$mail->Password = MAIL_PASSWORD;
	$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
	$mail->Port = 587; 

	// Recipients
	$mail->setFrom(MAIL_USERNAME, WEBSITE_NAME);
	$mail->addAddress($email);	
	
	$mail->Subject = 'Password Recovery';
	$mail->Body = 
		"You can log in with your new password : {$new_pass}";

	if(!$mail->send()){
		return "Email not send. Please try again";
	}else{
		$hashed_password = 
			password_hash($new_pass, PASSWORD_DEFAULT);

		$stmt = 
			$mysqli->prepare(
				"UPDATE users SET password = ? WHERE email = ?"
			);

		$stmt->bind_param("ss", $hashed_password, $email);
		$stmt->execute();

		if($stmt->affected_rows != 1){
			return "There was a connection error, please try again.";
		}else{
			return "success";
		}			
	}
}

function logout(){
	session_destroy();
	header("location: login.php");
	exit();
}
	

Let's explain the code and the functions.

  • Configuring the PHPMailer Library:

    use PHPMailer\PHPMailer\Exception;
    use PHPMailer\PHPMailer\PHPMailer;
    use PHPMailer\PHPMailer\SMTP;
     
    require 'PHPMailer-master/src/Exception.php';
    require 'PHPMailer-master/src/PHPMailer.php';
    require 'PHPMailer-master/src/SMTP.php';
    
    require "config.php";
    			

    The use statements import the Exception class, which handles exceptions thrown by PHPMailer, the PHPMailer class responsible for sending emails, and the SMTP protocol for SMTP functionality.

    The require statements, gives as access to those classes so we can use them in our functions.

    Also we require the 'config.php' file to access the constants that we have defined there.

    The use and require statements for PHPMailer must be included at the top of the file.

  • Connect to the Database:

    function dbConnect(){
    	$mysqli = new mysqli(SERVER, USERNAME, PASSWORD, DATABASE);
    	if($mysqli->connect_errno != 0){
    		return FALSE;
    	}else{
    		return $mysqli;
    	}
    }
    			

    This function, 'dbConnect', initiates the database connection. It begins by creating a new instance of the MySQLi class, utilizing the constants from the config.php file SERVER, USERNAME, PASSWORD, and DATABASE for the server address, username, password, and database name respectively.

    Next, it checks if the connection was successful. If the connect_errno property of the MySQLi instance is not equal to 0, indicating an error occurred during connection, the function returns FALSE, indicating a failed connection attempt.

    However, if the connection is successful, the function returns the MySQLi instance, allowing it to be used for executing database queries and operations.

  • Register the User

    function register($email, $username, $password, $confirm_password)
    {
      // Establish a database connection
      $mysqli = dbConnect();
    
      // Check if connection failed
      if($mysqli == false){
        return false; // Return false if connection failed
      }
    
      // Sanitize and validate input data
      $args = [
        "email" => $email,
        "username" => $username,
        "password" => $password,
        "confirm-password" => $confirm_password
      ];
    
      // Trim whitespace from input values
      $args = array_map(function($value){
    		return trim($value);
      }, $args);
      
      // Check if any fields are empty
      foreach ($args as $value) {
    		if(empty($value)){
    		    return "All fields are required";
    		}
      }
    
      // Check if input contains disallowed characters
      foreach ($args as $value) {
    		if(preg_match("/([<|>])/", $value)){
    			return "<> characters are not allowed";
    		}
      }
    
      // Sanitize input data
      $args = array_map(function($value){
      	return htmlspecialchars($value);
      }, $args);
    
      // Validate email format
      if(!filter_var($args["email"], FILTER_VALIDATE_EMAIL)){
      	return "Email is not valid";
      }
    
      // Check if username length is within limits
      if(mb_strlen($args["username"]) > 20){
      	return "The username must be under 20 characters";
      }
    
      // Check if password length is within limits
      if(mb_strlen($args["password"]) > 20){
      	return "The password must be under 20 characters";
      }
    
      // Check if password matches confirm password
      if($args["password"] != $args["confirm-password"]){
      	return "Passwords don't match";
      }
    
      // Get existing data from the users table
      $result_set = $mysqli->query("SELECT * FROM users");
      $data = array();
      while($row = $result_set->fetch_assoc()){
      	array_push($data, $row);
      }
    
      // Check if email already exists
      foreach ($data as $value) {
    		if($args["email"] == $value["email"]){
    			return "Email already exists";
    		}
      }
      
      // Check if username already exists
      foreach ($data as $value) {
    		if($args["username"] == $value["username"]){
    			return "Username already exists";
    		}
      }
    
      // Generate verification code
      $verification_code = createVerificationCode($data);
      
      // Attempt to send verification code
      if(!sendVerificationCode($args["email"], $verification_code)){
    		return "Error sending verification code. Please try again";
      }
    
      // Hash the password
      $hashed_password = 
      	password_hash($args["password"], PASSWORD_DEFAULT);
      
      // Prepare and execute SQL statement to insert 
      // user data into database
      $stmt = $mysqli->prepare(
    		"INSERT INTO users 
    		(email, username, password, verification_code)
    		VALUES(?,?,?,?)"
      );
      // Bind parameters to the prepared statement
      $stmt->bind_param(
    		// Define parameter types: 's' for string, 'i' for integer
    		"sssi", 
    		$args["email"],  // Bind email to first placeholder
    		$args["username"],  // Bind username to second placeholder
    		$hashed_password,  // Bind hashed password
    		$verification_code  // Bind verification code
      );
      
      // Execute the prepared statement
      $stmt->execute();
      
      // Check if insertion was successful
      if($stmt->affected_rows != 1){
      	return "An error occurred. Please try again";
      }else{
    		// Set session variables
    		$_SESSION['email'] = $args["email"];
    		$_SESSION['verification-code'] = $verification_code;
    		
    		// Redirect user to authentication page
    		return header("Location: auth.php");
      }
    }
    			

    This function, named register, is responsible for handling the registration process.

    This register function takes four parameters: $email, $username, $password, and $confirm_password.

    First, it establishes a database connection using the dbConnect function. If the connection fails, it returns false.

    Next, it sanitizes and validates the input data. It trims whitespace from the input values and checks if any fields are empty. It also ensures that no input contains characters '<' or '>', which could be indicative of potential security vulnerabilities.

    After validating the input, it checks the validity of the email address format using PHP's FILTER_VALIDATE_EMAIL filter. It also checks if the length of the username and password is within acceptable limits.

    Then, it compares the password with the confirm password to ensure they match.

    Following that, it queries the database to check if the email or username already exists in the database. If a match is found, it returns an error message accordingly.

    If all checks pass, it generates a verification code and attempts to send it to the provided email address using the sendVerificationCode function.

    If sending the verification code is successful, it hashes the password using PHP's password_hash function and prepares an SQL statement to insert the user's information into the database.

    After executing the SQL statement, it checks if the insertion was successful. If successful, it sets session variables for email and verification code, then redirects the user to the authentication page (auth.php). Otherwise, it returns an error message.

  • Creating the Verification Code

    function createVerificationCode($database_data){
    	// Define a string containing digits from 0 to 9						
    	$str = "0123456789";
    
    	// Shuffle the string to generate a random order of digits
    	$random = str_shuffle($str);
    
    	// Extract the first 6 characters of the shuffled string 
    	// to create a 6-digit verification code
    	$verification_code = substr($random, 0, 6);
    
    	// Extract existing verification codes from database data
    	$codes = array_map(
    	  fn($value) => $value["verification_code"], $database_data
    	);
    
    	// Check if the generated verification code already 
    	// exists in the database
    	if(in_array($verification_code, $codes)){
       
        // If the code already exists, recursively call 
        // the function to generate a new code	
    		return createVerificationCode($database_data);
    	}else{
    		// If the code does not exist in the database, 
    		// return the generated code
    	  return $verification_code;
    	}
    }
    			

    This function, createVerificationCode, is responsible for generating a unique verification code for user registration

    It starts by defining a string containing digits from 0 to 9. Then, it shuffles the string to create a random order of digits. From the shuffled string, it extracts the first 6 characters to form a 6-digit verification code.

    Next, it extracts existing verification codes from the provided $database_data array. This array contains verification codes retrieved from the database.

    The function then checks if the generated verification code already exists in the database. If it does, it recursively calls itself to generate a new code until a unique code is obtained.

    Once a unique verification code is generated, it returns the code to the calling function.

  • Send the Verification code

    function sendVerificationCode($email, $verification_code){
    	// Create a new instance of PHPMailer
    	$mail = new PHPMailer(true);
    
    	// Configure PHPMailer for SMTP 
    	$mail->isSMTP();
    	$mail->Host = MAIL_HOST;
    	$mail->SMTPAuth = true;
    	$mail->Username = MAIL_USERNAME;
    	$mail->Password = MAIL_PASSWORD;
    	$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    	$mail->Port = 587;
    
      // Set email sender and recipient
      $mail->setFrom(MAIL_USERNAME, WEBSITE_NAME);
      $mail->addAddress($email);	
     
    	// Set email subject and body 
      $mail->Subject = 'Email verification';
      $mail->Body = 
      	"Please use the 6 digits code to verify your email:
      	{$verification_code}";
    
    	// Send the email  	
      if(!$mail->send()){
      	// If email sending fails, return error message
      	return "Email not send. Please try again";
      }else{
      	// If email sending is successful, return true
      	return true;
      }
    }
    			

    This function, sendVerificationCode, is responsible for sending a verification code to a provided email address.

    First, it creates a new instance of the PHPMailer class.

    Then, it configures PHPMailer for SMTP usage, setting the SMTP host, authentication credentials, encryption method, and port.

    Next, it sets the sender and recipient of the email, using the website's email address as the sender and the provided email address as the recipient.

    After that, it sets the subject of the email to 'Email verification' and constructs the body of the email, including the verification code provided as part of the message.

    Finally, it attempts to send the email. If the sending process fails, it returns an error message. Otherwise, if the email is sent successfully, it returns true.

  • Verifying the Users Email

    function verifyEmail($verification_code){
    	// Establish a database connection
    	$mysqli = dbConnect();
    
    	// Check if connection failed
    	if($mysqli == false){
    		return false;
    	}
    
    	// Check if verification code is empty
    	if(trim($verification_code) == ""){
    		return "Please enter the 6 digits code";
    	}
    
    	// Validating the format of the verification code
    	if(!preg_match("/^\d{6}$/", $verification_code)){
    		return "The string expects a 6 digits number";
    	}
    
    	// Query the database to check if the verification code exists
    	$res = $mysqli->query(
    		"SELECT verification_code FROM users 
    		WHERE verification_code = '$verification_code'"
    	);
    
    	// Check if the verification code exists in the database
    	if($res->num_rows != 1){
    		return "Wrong verification code";
    	}else{
    		// If verification code exists, update the 
    		// email status to 'verified'
    		$update = $mysqli->query(
    			"UPDATE users SET email_status = 'verified' 
    			WHERE verification_code = '$verification_code'
    		");
    
    		// Check if the update was successful
    		if($mysqli->affected_rows != 1){
    			return "something went wrong. Please try again";
    		}else{
    			// If update was successful redirect to login page
    			header("Location: login.php");
    			exit();
    		}
    	}
    }
    			

    This function, verifyEmail, is responsible for verifying an email using a provided verification code.

    First, it establishes a connection to the database using the dbConnect function. If the connection fails, it returns false.

    Next, it checks if the provided verification code is empty or not. If it's empty, it returns an error message prompting the user to enter the 6-digit code.

    Then, it validates the format of the verification code using a regular expression. If the code doesn't match the expected format of 6 digits, it returns an error message.

    After that, it queries the database to check if the verification code exists. If the code doesn't exist in the database, it returns an error message indicating a wrong verification code.

    If the verification code exists in the database, it updates the email_status of the user to 'verified'. It then checks if the update was successful. If the update fails, it returns an error message indicating that something went wrong.

    Finally, if the update was successful, it redirects the user to the login page.

    This function ensures that the email verification process is completed securely and accurately.

  • Log the User In

    function login($username, $password){
    	// Establish a database connection
    	$mysqli = dbConnect();
    	if(!$mysqli){
    		// Return false if database connection fails
    		return false;
    	}
    
    	// Trim username and password
    	$username = trim($username);
    	$password = trim($password);
    
    	// Check if username or password is empty
    	if($username == "" || $password == ""){
    		// Return error message if username or password is empty
    		return "Both fields are required";
    	}
    
    	// Prepare SQL query to select user data by username
    	$sql = "SELECT * FROM users WHERE username = ?";
    	$stmt = $mysqli->prepare($sql);
    	$stmt->bind_param("s", $username);
    	$stmt->execute();
    	$result = $stmt->get_result();
    	$data = $result->fetch_assoc();
    
    	// Check if user with provided username exists
    	if($data == NULL){
    		return "Wrong username or password";
    	}
    
    	// Check if user's email status is pending
    	if($data["email_status"] == "pending"){
    		
    		// Set session variables for email and verification code
    		$_SESSION['email'] = $data["email"];
    		$_SESSION['verification-code'] = $data["verification_code"];
    
    		// Send verification code to user's email
    		sendVerificationCode(
    			$data["email"], $data["verification_code"]
    		);
    		
    		// Redirect user to authentication page
    		header("location: auth.php");
    		exit();
    	}
    
    	// Verify password
    	if(password_verify($password, $data["password"]) == FALSE){
    		// Return error message if password is incorrect
    		return "Wrong username or password";
    	}else{
    		// Set session variable for user
    		$_SESSION["user"] = $username;
    		// Redirect the user to account.php page
    		header("location: account.php");
    		exit();
    	}
    }		

    This function, login, is responsible for the login process.

    First, it establishes a connection to the database using the dbConnect function. If the connection fails, it returns false.

    Next, it trims the username and password to remove any leading or trailing white space.

    Then, it checks if the username or password is empty. If either field is empty, it returns an error message indicating that both fields are required.

    After that, it prepares an SQL statement to select user data based on the provided username. It executes the statement and retrieves the result.

    If no user data is retrieved (indicating that the provided username does not exist), it returns an error message indicating a wrong username or password.

    If the user's email status is 'pending', it sets session variables for the user's email and verification code, sends a verification code to the user's email, and redirects the user to the authentication page.

    If the user's email status is not 'pending', it verifies the password using PHP's password_verify function. If the password is incorrect, it returns an error message indicating a wrong username or password.

    If the password is correct, it sets a session variable for the user and redirects the user to the account page.

    This function ensures that users can securely log in and access their accounts.

  • Reset the User Password

    function passwordReset($email){
    	// Establish a database connection			
    	$mysqli = dbConnect();
    	if(!$mysqli){
    		// Return false if database connection fails
    		return false;
    	}
    
    	// Trim and validate email address
    	$email = trim($email);
    
    	if(!filter_var($email, FILTER_VALIDATE_EMAIL)){
    		// Return error message if email is not valid
    		return "Email is not valid";
    	}
    
    	// Query the database to select user by email
    	$stmt = $mysqli->prepare(
    		"SELECT email FROM users WHERE email = ?"
    	);
    	$stmt->bind_param("s", $email);
    	$stmt->execute();
    	$result = $stmt->get_result();
    	$data = $result->fetch_assoc();
    	
    	// Check if email exists in the database
    	if($data == NULL){
    		// Return error message if email does not exist
    		return "Email doesn't exist in the database";
    	}
    
    	// Generate a new random password
    	$str = 
    		"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
    		abcefghijklmnopqrstuvwxyz";
    
    	$password_length = 7;
    	$shuffled_str = str_shuffle($str);
    	$new_pass = substr($shuffled_str, 0, $password_length);
    
    	// Create a new instance of PHPMailer
    	$mail = new PHPMailer(true);
    	$mail->isSMTP();
    	$mail->Host = MAIL_HOST;
    	$mail->SMTPAuth = true;
    	$mail->Username = MAIL_USERNAME;
    	$mail->Password = MAIL_PASSWORD;
    	$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    	$mail->Port = 587; 
    
    	// Set email sender and recipient
    	$mail->setFrom(MAIL_USERNAME, WEBSITE_NAME);
    	$mail->addAddress($email);	
    	
    	Set email subject and body with the new password
    	$mail->Subject = 'Password Recovery';
    	$mail->Body = 
    		"You can log in with your new password : {$new_pass}";
    
    	// Send the email
    	if(!$mail->send()){
    		// Return error message if email sending fails
    		return "Email not send. Please try again";
    	}else{
    		// Hash the password
    		$hashed_password = 
    			password_hash($new_pass, PASSWORD_DEFAULT);
    
    		// Query the database to update the password 
    		$stmt = 
    			$mysqli->prepare(
    				"UPDATE users SET password = ? WHERE email = ?"
    			);
    		$stmt->bind_param("ss", $hashed_password, $email);
    		$stmt->execute();
    
    		// Check if password update was successful
    		if($stmt->affected_rows != 1){
    			// Return error message if password update fails
    			return "There was a connection error, please try again.";
    		}else{
    			// Return "success" if password reset is successful
    			return "success";
    		}			
    	}
    }
    			

    This function, passwordReset, facilitates the process of resetting a user's password.

    First, it establishes a connection to the database using the dbConnect function. If the connection fails, it returns false.

    Next, it trims and validates the provided email address. If the email address is not valid, it returns an error message indicating that the email is not valid.

    Then, it prepares an SQL statement to select a user by their email address. It executes the statement and retrieves the result.

    If the provided email address does not exist in the database, it returns an error message indicating that the email doesn't exist in the database.

    If the email address exists, it generates a new random password of length 7 characters.

    Next, it configures PHPMailer for SMTP usage, sets the sender and recipient of the email, and constructs the email subject and body with the new password.

    After that, it attempts to send the email. If the email sending fails, it returns an error message indicating that the email was not sent.

    If the email is successfully sent, it hashes the new password and prepares an SQL statement to update the user's password in the database.

    It then executes the SQL statement to update the password. If the password update is successful, it returns "success". Otherwise, it returns an error message indicating a connection error.

    This function ensures that users can securely reset their passwords and regain access to their accounts.

  • Logout the User

    function logout(){
    	session_destroy();
    	header("location: login.php");
    	exit();
    }
    			

    The function destroys the user session, and redirects the user back to the login page.

    And we are done with the functions.php file. Now we are going to create all the form elements in their respective page.

The Index Page

In the index.php file we are going to have the register form.

<?php require "functions.php" ?>
<?php 
	if(isset($_POST['register'])){
		$response = register(
			$_POST['email'], $_POST['username'], 
			$_POST['password'], $_POST['confirm-password']
		);
	}
?>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" 
		content="width=device-width, initial-scale=1.0">
	 
	<link rel="stylesheet" href="styles.css">
	<title>Register page</title>
</head>
<body>
	<form action="" method="post" autocomplete="off">
		<h2>Register form</h2>
		<p class="info">
			Please fill out the form to create your account.
		</p>

		<label>Email</label>
		<input type="text" name="email" 
			value="<?php echo @$_POST['email'] ?>">
		
		<label>Username</label>
		<input type="text" name="username" 
			value="<?php echo @$_POST['username'] ?>">
	
		<label>Password</label>
		<input type="text" name="password" 
			value="<?php echo @$_POST['password'] ?>">

		<label>Confirm Password</label>
		<input type="text" name="confirm-password" 
			value="<?php echo @$_POST['confirm-password'] ?>">
	
		<button type="submit" name="register">Register</button>

		<p class="forgot-password">
			<a href="login.php">Already have an account?</a>
		</p>
		<p class="error"><?php echo @$response ?></p>		
	</form>

</body>
</html>
	

Let's break down the code in the index.php file.

  • Fetch the Post Request

    <?php require "functions.php" ?>
    <?php 
    	if(isset($_POST['register'])){
    		$response = register(
    			$_POST['email'], $_POST['username'], 
    			$_POST['password'], $_POST['confirm-password']
    		);
    	}
    ?>
    			

    First we require the functions.php file so we have access to the functions that we wrote there.

    Following that, an if statement checks if the 'register' key exists in the $_POST superglobal array. If it does, it calls the 'register' function, passing in the values submitted through the registration form: email, username, password, and confirm-password.

    The result of the registration attempt is stored in the variable '$response', which may contain a success message or an error message returned by the 'register' function.

  • The Register Form

    <form action="" method="post">
    	<h2>Register form</h2>
    	<p class="info">
    		Please fill out the form to create your account.
    	</p>
    
    	<label>Email</label>
    	<input type="text" name="email" 
    		value="<?php echo @$_POST['email'] ?>">
    
    	<label>Username</label>
    	<input type="text" name="username" 
    		value="<?php echo @$_POST['username'] ?>">
    
    	<label>Password</label>
    	<input type="text" name="password" 
    		value="<?php echo @$_POST['password'] ?>">
    
    	<label>Confirm Password</label>
    	<input type="text" name="confirm-password" 
    		value="<?php echo @$_POST['confirm-password'] ?>">
    
    	<button type="submit" name="register">Register</button>
    
    	<p class="forgot-password">
    		<a href="login.php">Already have an account?</a>
    	</p>
    	<p class="error"><?php echo @$response ?></p>		
    </form>
    			

    This HTML form is used for user registration. It has the 'action' attribute set to an empty string, indicating that the form submits data to the same page it's on. The 'method' attribute is set to 'post', indicating that form data is sent via the HTTP POST method.

    The form includes input fields for email, username, password, and confirm password. Each input field is accompanied by a <label> element, providing a description of the field. The 'value' attribute of each input field is populated with PHP code (<?php echo @$_POST['field_name'] ?>), allowing for the pre-population of form fields with previously submitted values (in case of form submission errors).

    At the end of the form, there's a <button> element with the name 'register', indicating submission of the form for registration. Below the button, there's a <p> element with the class 'forgot-password', containing a link to the login page in case the user already has an account.

    Lastly, there's a <p> element with the class 'error', which displays any error message returned by the PHP code after form submission. The error message is echoed using PHP (<?php echo @$response ?>).

The Login Page

<?php require "functions.php" ?>
<?php 
	if(isset($_POST['login'])){
		$response = login($_POST['username'], $_POST['password']);
	}
?>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" 
		content="width=device-width, initial-scale=1.0">

	<link rel="stylesheet" href="styles.css">
	<title>Login page</title>
</head>
<body>
	<form action="" method="post">
		<h2>Login form</h2>
		<p class="info">
			Please enter your username and password to log-in.
		</p>

		<label>Username</label>
		<input type="text" name="username" 
			value="<?php echo @$_POST['username'] ?>">
	
		<label>Password</label>
		<input type="text" name="password" 
			value="<?php echo @$_POST['password'] ?>">
	
		<button type="submit" name="login">Login</button>
		<p class="forgot-password">
			<a href="forgot-password.php">Forgot your password?</a>
		</p>
		<p class="create-account">
			<a href="index.php">Create an account</a>
		</p>
		<p class="error"><?php echo @$response ?></p>		
	</form>

</body>
</html>
	

Let's explain the code that we have in the login.php page.

  • Fetching the POST Request

    <?php require "functions.php" ?>
    <?php 
    	if(isset($_POST['login'])){
    		$response = login($_POST['username'], $_POST['password']);
    	}
    ?>
    			

    Again we require the functions.php file.

    Following that, an if statement checks if the 'login' key exists in the $_POST superglobal array. If it does, it calls the 'login' function, passing in the values submitted through the login form: username and password.

    The result of the login attempt is stored in the variable '$response', which may contain a success message or an error message returned by the 'login' function.

  • The Login Form

    <form action="" method="post">
    	<h2>Login form</h2>
    	<p class="info">
    		Please enter your username and password to log-in.
    	</p>
    
    	<label>Username</label>
    	<input type="text" name="username" 
    		value="<?php echo @$_POST['username'] ?>">
    
    	<label>Password</label>
    	<input type="text" name="password" 
    		value="<?php echo @$_POST['password'] ?>">
    
    	<button type="submit" name="login">Login</button>
    	
    	<p class="forgot-password">
    		<a href="forgot-password.php">Forgot your password?</a>
    	</p>
    	
    	<p class="create-account">
    		<a href="index.php">Create an account</a>
    	</p>
    	
    	<p class="error"><?php echo @$response ?></p>		
    </form>
    			

    This HTML form is used for user login. It has the 'action' attribute set to an empty string, indicating that the form submits data to the same page it's on. The 'method' attribute is set to 'post', indicating that form data is sent via the HTTP POST method

    The form includes input fields for username and password. Each input field is accompanied by a label element, providing a description of the field. The 'value' attribute of each input field is populated with PHP code (<?php echo @$_POST['field_name'] ?>), allowing for the pre-population of form fields with previously submitted values (in case of form submission errors).

    At the end of the form, there's a button element with the name 'login', indicating submission of the form for login. Below the button, there's a p element with the class 'forgot-password', containing a link to the 'forgot-password.php' page for password recovery.

    Additionally, there's a p element with the class 'create-account', containing a link to the 'index.php' page for creating a new account.

    Lastly, there's a p element with the class 'error', which displays any error message returned by the PHP code after form submission. The error message is echoed using PHP (<?php echo @$response ?>)

The Forgot Password Page

<?php require "functions.php" ?>
<?php 
	if(isset($_POST['send-email'])){
		$response = passwordReset($_POST['email']);
	}
?>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" 
		content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" href="styles.css">
	<title>Password reset</title>
</head>
<body>

	<form action="" method="post">
		<h2>Password reset</h2>
		<p class="info">
			Please enter your email so we can send you a new password.
		</p>

		<label>Email</label>
		<input type="text" name="email" 
			value="<?php echo @$_POST['email'] ?>">
		
		<button type="submit" name="send-email">Send</button>

	
		<?php 
			if(@$response == "success"){
				?>
					<p class="success">
						Please go to your email account and use 
						your new password.
					</p>
				<?php
			}else{
				?>
					<p class="error"><?php echo @$response; ?></p>
				<?php
			}
		?>		

		<p class="forgot-password">
			<a href="login.php">Back to login page</a>
		</p>
	</form>

</body>
</html>
	

Let's break the code down.

  • Fetching the POST Request

    <?php require "functions.php" ?>
    <?php 
    	if(isset($_POST['send-email'])){
    		$response = passwordReset($_POST['email']);
    	}
    ?>
    			

    Again as we did in the previous pages we require the functions.php file, and we are checking if there is a $_POST['send-email'] superglobal variable. If the condition is true we call the passwordReset function and pass in as an argument the submitted email ($_POST['email']).

  • The Send Email Form

    <form action="" method="post">
    	<h2>Password reset</h2>
    	<p class="info">
    		Please enter your email so we can send you a new password.
    	</p>
    
    	<label>Email</label>
    	<input type="text" name="email" 
    		value="<?php echo @$_POST['email'] ?>">
    	
    	<button type="submit" name="send-email">Send</button>
    
    	<?php 
    		if(@$response == "success"){
    			?>
    				<p class="success">
    					Please go to your email account and use 
    					your new password.
    				</p>
    			<?php
    		}else{
    			?>
    				<p class="error"><?php echo @$response; ?></p>
    			<?php
    		}
    	?>		
    
    	<p class="forgot-password">
    		<a href="login.php">Back to login page</a>
    	</p>
    </form>
    			

    This HTML form is used for password reset. It has the 'action' attribute set to an empty string, indicating that the form submits data to the same page it's on. The 'method' attribute is set to 'post', indicating that form data is sent via the HTTP POST method.

    The form includes an input field for email. The input field is accompanied by a label element, providing a description of the field. The 'value' attribute of the input field is populated with PHP code (<?php echo @$_POST['email'] ?>), allowing for the pre-population of the form field with a previously submitted email address (in case of form submission errors).

    At the end of the form, there's a button element with the name 'send-email', indicating submission of the form to send a new password.

    Additionally, there's PHP code embedded within the form to handle the response after form submission. If the response is 'success', indicating that the email with the new password was successfully sent, it displays a success message. Otherwise, it displays an error message.

    Below the response message, there's a p element with the class 'forgot-password', containing a link to the 'login.php' page to go back to the login page.

The Email Verification Page

<?php require "functions.php" ?>
<?php
	if(!isset($_SESSION['verification-code'])){
		header("Location: login.php");
		exit(); 	
	} 
	if(isset($_POST['verify'])){
		$response = verifyEmail($_POST['verification-code']);
	}
	if(isset($_GET['resend-verification-code'])){
		if(sendVerificationCode(
			$_SESSION['email'], $_SESSION['verification-code']))
		{
			$success = 
				"Please go to your email account and 
				copy the 6 digits code";
		}else{
			$response = "Something went wrong, please try again";
		}
	}
?>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" 
		content="width=device-width, initial-scale=1.0">

	<link rel="stylesheet" href="styles.css">
	<title>Email verification</title>
</head>
<body>
	<form action="" method="post">
		<h2>Email verification</h2>

		<p class="info">
			Please go to your email account and type in the 
			field below the	<strong>6 digits verification 
			code</strong> that you received.	
		</p>

		<p class="info">
			After we verify your email you will be redirected 
			to the login page	to log in to your account.
		</p>

		<label>Verification code</label>
		<input type="text" name="verification-code">
		
		<button type="submit" name="verify">Verify</button>

		<p class="resend-code">
			<a href="?resend-verification-code">
				Resend verifivation code
			</a>
		</p>
		
		<p class="error"><?php echo @$response ?></p>
		<p class="success"><?php echo @$success ?></p>		
	</form>

</body>
</html>
	

Let's explain the code above.

  • Fetching the POST and GET Request

    <?php
    	if(!isset($_SESSION['verification-code'])){
    		header("Location: login.php");
    		exit(); 	
    	} 
    	if(isset($_POST['verify'])){
    		$response = verifyEmail($_POST['verification-code']);
    	}
    	if(isset($_GET['resend-verification-code'])){
    		if(sendVerificationCode(
    			$_SESSION['email'], $_SESSION['verification-code']))
    		{
    			$success = 
    				"Please go to your email account and copy 
    				the 6 digits code";
    		}else{
    			$response = "Something went wrong, please try again";
    		}
    	}
    ?>
    			

    If the verification code session variable ($_SESSION['verification-code']) is not set, the user is redirected to the login page using the header() function, and the script execution is terminated with exit(). This ensures that the user cannot access the current page without a verification code.

    Next, if the 'verify' key exists in the $_POST superglobal array, indicating that the verification form has been submitted, the 'verifyEmail' function is called with the verification code submitted through the form ($_POST['verification-code']). The result of the verification attempt is stored in the variable '$response'.

    Additionally, if the 'resend-verification-code' key exists in the $_GET superglobal array, it indicates that the user wants to resend the verification code. In this case, the 'sendVerificationCode' function is called with the email address and verification code stored in session variables ($_SESSION['email'] and $_SESSION['verification-code']). If the verification code is successfully resent, the '$success' variable is set to a success message instructing the user to check their email for the code. If there's an error sending the code, the '$response' variable is set to an error message.

  • The Email Verification Form

    <form action="" method="post">
    	<h2>Email verification</h2>
    
    	<p class="info">
    		Please go to your email account and type in the 
    		field below the	<strong>6 digits verification 
    		code</strong> that you received.	
    	</p>
    
    	<p class="info">
    		After we verify your email you will be redirected 
    		to the login page	to log in to your account.
    	</p>
    
    	<label>Verification code</label>
    	<input type="text" name="verification-code">
    	
    	<button type="submit" name="verify">Verify</button>
    
    	<p class="resend-code">
    		<a href="?resend-verification-code">
    			Resend verifivation code
    		</a>
    	</p>
    	
    	<p class="error"><?php echo @$response ?></p>
    	<p class="success"><?php echo @$success ?></p>		
    </form>
    			

    This HTML form is used for email verification. It has the 'action' attribute set to an empty string, indicating that the form submits data to the same page it's on. The 'method' attribute is set to 'post', indicating that form data is sent via the HTTP POST method

    Inside the form, there is an h2 element displaying 'Email verification', providing a heading for the email verification section. Below the heading, there are two p elements with the class 'info', which provide instructions to the user. The first paragraph instructs the user to enter the 6-digit verification code received in their email. The second paragraph informs the user that after email verification, they will be redirected to the login page.

    The form includes an input field for the verification code. The input field is accompanied by a label element, providing a description of the field.

    At the end of the form, there's a button element with the name 'verify', indicating submission of the form for verification.

    Additionally, there's a p element with the class 'resend-code', containing a link to resend the verification code. The link is generated using a query parameter '?resend-verification-code', which triggers the resend action.

    Below the form, there are p elements with the class 'error' and 'success', which display any error or success messages returned by the PHP code after form submission. The error message is echoed using PHP (<?php echo @$response ?>), and the success message is echoed using PHP (<?php echo @$success ?>).

The User Account Page

<?php require "functions.php" ?>
<?php 
	if(!isset($_SESSION['user'])){
		header("Location: login.php");
		exit();
	}
	if(isset($_GET['logout'])){
		logout();
	}
?>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" 
		content="width=device-width, initial-scale=1.0">
	
	<link rel="stylesheet" href="styles.css">
	<title>User account</title>
</head>
<body>

	<div class="page">
		<div class="top-bar">
			<h2>Welcome <?php echo @$_SESSION['user'] ?></h2>
			<a href="?logout">Logout</a>
		</div>
	</div>

</body>
</html>
	

Let's explain the code in the account.php page

  • Securing the Page

    if(!isset($_SESSION['user'])){
    	header("Location: login.php");
    	exit();
    }
    if(isset($_GET['logout'])){
    	logout();
    }
    			

    First we check if the user is loged-in. If NOT we send them back to the login.php page. This way we secure the access of the page if a user is not loged-in.

    Next if the user clikcs on the logout link that we have further down in the HTML code, we call the logout function.

  • Welcome and Logout the User

    <div class="page">
    	<div class="top-bar">
    		<h2>Welcome <?php echo @$_SESSION['user'] ?></h2>
    		<a href="?logout">Logout</a>
    	</div>
    </div>	
    			

    In the code above we welcome the user in the account page by displaying the user's username that the login function stores in the ( $_SESSION['user'] ) when the user logs in.

    After that we have a link that sends a GET request to the same page that holds a logout key (?logout) to log out the user.

    And we are done. We have created all the pages we need. Last we have the CSS file.

The CSS file

Lastly, we have the CSS code. Copy the code and paste it into the styles.css file to apply the layout and styling to the pages and form elements.

*{
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}

body{
	font-family: sans-serif;
	min-height: 100%;
	color: #555;
	background-color: #fff;
}

form{
	max-width: 400px;
	margin: 50px auto;
	border:  thin solid #e4e4e4;
	padding: 20px;
	box-shadow: 0 5px 5px rgba(0, 0, 0, 0.2);
}

form h2{
	margin-bottom: 10px;
}

form .info{
	margin-bottom: 20px;
	line-height: 24px;
}

form label{
	display: block;
	margin-bottom: 10px;
	padding-left: 5px;
}

form input, form textarea{
	display: block;
	width:  100%;
	padding: 10px;	
	margin-bottom: 10px;
	font-size: 16px;
	border:  thin solid #e4e4e4;
	margin-bottom: 30px;
}

form select{
	display: block;
	width:  100%;
	margin-bottom: 10px;
	padding: 10px;
	font-size: 16px;
	border:  thin solid #e4e4e4;
	background-color: white;
	color: #555;
}

form input:focus
{
	outline: none;
}

form input::placeholder{
	font-size: 16px;
}

form button{
	background: #32749a;
	color: white;
	border: none;	
	padding: 15px;
	width:  100%;
	font-size: 17px;
	margin-top: 20px;
	cursor: pointer;
}

form button:hover{
	filter: brightness(1.4);
}

form button:active{
	background-color: green;
}

form .forgot-password, form .resend-code, form .have-account{
	margin-top: 30px;
}

form a{
	color: #1f7498;
}

form a:hover{
	text-decoration: none;
}

form .create-account{
	margin-top: 15px;
}

.error{
	margin-top: 30px;
	color: #af0c0c;
}

.success{
	margin-top: 30px;
	color: green;
	line-height: 26px;
}

.page{
	max-width: 900px;
	margin: 30px auto 0 auto;
	padding: 20px;
}

.top-bar{
	display: flex;
	justify-content: space-between;
	align-items: center;
	border-bottom: thin solid #d4d4d4;
	padding-bottom: 20px;
}

.top-bar a{
	background: #32749a;
	color: white;
	text-decoration: none;
	padding: 8px 35px;
	font-size: 17px;
}

.top-bar a:hover{
	filter: brightness(1.4);
}

.top-bar a:active{
	background-color: green;
}

.content{
	margin-top: 100px;
}

.content h3{
	margin-bottom: 20px;
}

.content p{
	line-height: 26px;	
	margin-bottom: 50px;
}	

Summary

In this tutorial, we demonstrated how to build a secure login and registration system with email verification using PHP and MySQL. The system includes robust validation measures to ensure the security of user data.

Key components of the system include PHP functions for user registration, login, and password reset, along with MySQL database tables for storing user information securely. We also designed intuitive HTML forms for user interaction and applied CSS styling to enhance the visual appeal of the interface.

Additionally, we integrated PHPMailer to handle email verification seamlessly. Users receive verification codes via email, which they can use to confirm their email addresses and gain access to their accounts securely.

Throughout the tutorial, we emphasized best practices for building a secure authentication system, ensuring that user data is protected against potential security threats.

Source code

If you feel like avoiding all the copying and pasting, you can buy me a coffee and get the source code in a zip file. Get the source code

Buy me a coffee

If you like to say thanks, you can buy me a coffee.

Buy me a coffee with paypal