Building a Secure PHP MySQL Signup/Login Website with Email Verification

Creating a secure signup/login system is essential for any web application that involves user authentication. In this article, I'll guide you through building a PHP MySQL login/signup website with email verification. I'll focus on security best practices, including password encryption using PHP's built-in functions.

I'll also include instructions for using Gmail to send verification emails. We'll assume you are using XAMPP for the local server.

Configure a Local Development Environment

Make sure you have a local server environment set up on your machine. You can use tools like XAMPP, WampServer, MAMP, or similar depending on your operating system.

Step 1. Set Up XAMPP

Download and install XAMPP.
Start Apache and MySQL from the XAMPP control panel.

Step 2. Set Up a MySQL Database

Open phpMyAdmin (http://localhost/phpmyadmin/) and create a new database. Let's call it secure_login.

CREATE DATABASE IF NOT EXISTS secure_login;
USE secure_login;

CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(50) NOT NULL,
    password VARCHAR(255) NOT NULL,
    is_verified BOOLEAN NOT NULL DEFAULT 0,
    verification_code VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Note: Replace placeholders like secure_login with your desired database name.

Step 3. PHP Mailer Library

To send emails through your Gmail account using PHP and MySQL on a local host, you'll need to use an email library like PHPMailer or Swift Mailer, as Gmail's SMTP server requires authentication and encryption. 

Download and include the PHPMailer library in your project. You can download it from the GitHub repository.

https://github.com/PHPMailer/PHPMailer

Step 4. Create a Database Connection File

Create a file named db_connect.php to handle the database connection. This file will be included in other scripts:

<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "secure_login";

$conn = new mysqli($servername, $username, $password, $dbname);

if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
?>

Replace placeholders like localhost, root, "", and verification with your actual database credentials.

Step 5. Create HTML Forms (index.php)

Create a simple HTML form in index.php for user registration and login:

<html>
<head>
    <title>Login/Signup</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            background-color: #f5f5f5;
            margin: 0;
            padding: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100vh;
        }

        form {
            background-color: #fff;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            padding: 20px;
            max-width: 400px;
            width: 100%;
            text-align: center;
        }

        label {
            display: block;
            margin: 10px 0 5px;
            color: #333;
            font-weight: bold;
        }

        input {
            width: 100%;
            padding: 10px;
            margin-bottom: 15px;
            box-sizing: border-box;
            border: 1px solid #ccc;
            border-radius: 4px;
        }

        button {
            background-color: #4caf50;
            color: #fff;
            padding: 10px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
        }

        button:hover {
            background-color: #45a049;
        }
    </style>
</head>
<body>

<!-- Registration Form -->
<form action="register.php" method="post">
    <h2>Register</h2>
    <label for="username">Username:</label>
    <input type="text" name="username" required>
    <label for="email">Email:</label>
    <input type="email" name="email" required>
    <label for="password">Password:</label>
    <input type="password" name="password" required>
    <button type="submit">Register</button>
</form>

<!-- Login Form -->
<form action="login.php" method="post">
    <h2>Login</h2>
    <label for="email">Email:</label>
    <input type="email" name="email" required>
    <label for="password">Password:</label>
    <input type="password" name="password" required>
    <button type="submit">Login</button>
</form>

</body>
</html>

Step 6. PHP Registration Script (register.php)

Create a PHP script (register.php) to handle user registration and email verification:

<?php
require_once 'db_connect.php';

require_once("PHPMailer-master/src/PHPMailer.php");
require_once("PHPMailer-master/src/SMTP.php");
require_once("PHPMailer-master/src/Exception.php");

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $username = $_POST["username"];
    $email = $_POST["email"];
    $password = password_hash($_POST["password"], PASSWORD_DEFAULT);
    $verificationCode = bin2hex(random_bytes(16));

    $stmt = $conn->prepare("INSERT INTO users (username, email, password, verification_code) VALUES (?, ?, ?, ?)");
    
    if (!$stmt) {
        die("Error in statement preparation: " . $conn->error);
    }

    $stmt->bind_param("ssss", $username, $email, $password, $verificationCode);

    if ($stmt->execute()) {
        $verificationLink = "http://localhost/secure_login/verify.php?code=$verificationCode";
        
        // Send verification email using Gmail
        $mail = new PHPMailer(true);
        try {

            $mail->SMTPOptions = array(
                'ssl' => array(
                    'verify_peer' => false,
                    'verify_peer_name' => false,
                    'allow_self_signed' => true,
                ),
            );
            
            $mail->isSMTP();
            $mail->Host       = 'smtp.gmail.com';
            $mail->SMTPAuth   = true;
            $mail->Username   = 'your gamil address';
            $mail->Password   = 'your App Password'; // Replace with your App Password
            $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // or ENCRYPTION_SSL
            $mail->Port       = 587; // or 465 for SSL

            $mail->setFrom('your gamil address', 'Kisorjan');
            $mail->addAddress($email);

            $mail->isHTML(true);
            $mail->Subject = 'Email Verification';
            $mail->Body    = "Click the link below to verify your email: <a href='$verificationLink'>$verificationLink</a>";

            $mail->send();
            echo "Registration successful. Please check your email for verification.";
        } catch (Exception $e) {
            echo "Error sending verification email: {$mail->ErrorInfo}";
        }
    } else {
        echo "Error in registration: " . $stmt->error;
    }

    $stmt->close();
    $conn->close();
}
?>

Please replace placeholder values like [email protected] and your_gmail_password with your actual Gmail credentials. Additionally, consider enabling "Less secure app access" in your Gmail account settings for this to work.

Before May 30, 2022, from your Google account security settings “Less secure app access” had to be turned on to send emails using PHPMailer. Since the “Less secure apps” feature that allows third-party software and devices to sign in to your Gmail account is no longer supported by Google you can choose the other more secure options available.

2-Step Verification

If 2-step verification is enabled for your Gmail account and you wish to use it with PHPMailer as well, you will need to create an App password to continue by following these Google instructions. It is a 16-digit passcode, which you should put as a value to $mail->Password.

Remember, using real email and password in code is not recommended for production applications. Instead, use environment variables or configuration files to store sensitive information securely.

Step 7. Email Verification Script (verify.php)

Create a PHP script (verify.php) to handle email verification:

<?php
require_once 'db_connect.php';

if (isset($_GET["code"])) {
    $verificationCode = $_GET["code"];

    $stmt = $conn->prepare("UPDATE users SET is_verified = 1 WHERE verification_code = ?");

    if (!$stmt) {
        die("Error in statement preparation: " . $conn->error);
    }

    $stmt->bind_param("s", $verificationCode);

    if ($stmt->execute()) {
        echo "Email verified successfully. You can now login.";
    } else {
        echo "Error in email verification: " . $stmt->error;
    }

    $stmt->close();
    $conn->close();
} else {
    echo "Invalid verification code.";
}
?>

Step 8. PHP Login Script (login.php)

Create a PHP script (login.php) to handle user login:

<?php
session_start();
require_once 'db_connect.php';

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $email = $_POST["email"];
    $password = $_POST["password"];

    $stmt = $conn->prepare("SELECT id, username, password, is_verified FROM users WHERE email = ?");
    $stmt->bind_param("s", $email);
    $stmt->execute();
    $stmt->bind_result($id, $username, $hashedPassword, $isVerified);
    $stmt->fetch();
    $stmt->close();

    if ($isVerified && password_verify($password, $hashedPassword)) {
        $_SESSION['user_id'] = $id;
        $_SESSION['username'] = $username;
        header("Location: dashboard.php");
        exit();
    } else {
        echo "Invalid login credentials or unverified account.";
    }

    $conn->close();
}
?>

Step 9. Create a Dashboard (dashboard.php)

Create a simple dashboard page (dashboard.php) that only authenticated users can access:

<?php
session_start();
if (!isset($_SESSION['user_id'])) {
    header("Location: index.php");
    exit();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard</title>
</head>
<body>
    <!-- Dashboard content goes here -->
</body>
</html>

Conclusion

By following these steps, you've created a PHP MySQL login/signup website with email verification, incorporating secure password encryption practices. Always stay informed about the latest security best practices, and consider additional measures such as HTTPS, session management, and input validation to enhance the security of your web application.

Please note that this is a simplified example, and for a production-level system, you should implement additional security measures, and error handling, and consider using a framework that provides built-in security features.

If you have any questions, please enter them in the comment box.


Similar Articles