Creating a Secure Password Reset System With PHP: Best Practices and Implementation Guide

Creating a Secure Password Reset System With PHP

ডিজিটাল যুগে, ইউজারের অ্যাকাউন্টের integrity এবং confidentiality বজায় রাখার জন্য নিরাপদ এবং নির্ভরযোগ্য password reset mechanisms অত্যন্ত গুরুত্বপূর্ণ। পাসওয়ার্ডগুলি অনলাইন নিরাপত্তার একটি মৌলিক উপাদান, কিন্তু সেগুলি ভুলে যেতে, হারিয়ে যেতে বা হ্যাক হয়ে যেতে পারে৷ এটি মোকাবেলা করার জন্য, বিভিন্ন প্রতিষ্ঠান গুলি এবং ওয়েবসাইটগুলি password reset systems প্রয়োগ করে যা ইউজারদের তাদের অ্যাকাউন্টগুলিতে অ্যাক্সেস পুনরুদ্ধার করার সুযোগ দেয় এবং প্রক্রিয়াটি user-friendly এবং secure উভয়ই নিশ্চিত করে৷

এই আর্টিকেলে, আমরা ইমেল পাঠানোর জন্য একটি powerful PHP library, PHP Mailer ব্যবহার করে একটি secure password reset system ডেভেলপ করব। আমরা একটি robust password reset system এর গুরুত্ব, সিস্টেমের key components এবং আপনার পিএইচপি-ভিত্তিক ওয়েব অ্যাপ্লিকেশনগুলিতে কীভাবে এটি প্রয়োগ করতে হবে তার ধাপে ধাপে নির্দেশাবলী নিয়ে আলোচনা করব।

এই আর্টিকেলের শেষে, আপনি কীভাবে একটি secure এবং user-friendly password reset system তৈরি করবেন সে সম্পর্কে একটি বিস্তৃত ধারণা পাবেন যা ব্যবহারকারীদের সম্ভাব্য নিরাপত্তা হুমকিকে উপেক্ষা করে তাদের অ্যাকাউন্ট পুনরুদ্ধার করার ক্ষমতা দেয়।

Usage Table Structure

এখানে আমরা আমাদের Secure Registration System তৈরির জন্য যে টেবিল তৈরি করেছি , সেটিই ব্যবহার করব। এবং সেই Registration Form দিয়ে রেজিস্টার্ড ইউজারদের কে লগিনের ব্যবস্থা করব। এবং সেই সাথে নতুন করে নিম্নোক্ত password_reset_tokens টেবিলটি তৈরি করব :

CREATE TABLE `password_reset_tokens` (
  `id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `token` varchar(128) NOT NULL,
  `token_created_at` datetime NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

Create db_connection.php File To Configure Connect Database

<?php
// Replace the following values with your actual database credentials
$hostname = 'localhost';
$username = 'WRITE_YOUR_DATABASE_USERNAME';
$password = 'WRITE_YOUR_DATABASE_PASSWORD';
$database = 'WRITE_YOUR_DATABASE_NAME';

try {
    $db = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("Database connection failed: " . $e->getMessage());
}

এই PHP code টি PDO (PHP Data Objects) extension ব্যবহার করে একটি মাইএসকিউএল ডাটাবেসের সাথে একটি সংযোগ স্থাপন করে। এবং সঠিক exception handling সহ database-related errors গুলি পরিচালনা করে।

Install PHPMailer Library

তার আগে জেনে নেওয়া যাক PHPMailer কি ?

“PHPMailer” হল PHP-এর জন্য একটি শক্তিশালী এবং সহজেই ব্যবহারযোগ্য ইমেল লাইব্রেরি যা আপনাকে আপনার ওয়েব অ্যাপ্লিকেশন থেকে সহজে ইমেল বার্তা পাঠাতে দেয়৷ PHPMailer-এর সাহায্যে, আপনি আপনার ব্যবহারকারীর রেজিস্ট্রেশন প্রক্রিয়ার সাথে নির্বিঘ্নে email functionality যুক্ত করতে পারেন, আপনার ইউজাররা গুরুত্বপূর্ণ ইমেল গুলো প্রাপ্তি নিশ্চিত করে, যেমন confirmation messages এবং account verification links.

SMTP সহ বিভিন্ন ইমেল ট্রান্সপোর্ট সাপোর্ট সহ, PHPMailer জনপ্রিয় ইমেল সার্ভিস গুলো যেমন Gmail, Yahoo এবং আপনার নিজস্ব কাস্টম SMTP সার্ভারের মাধ্যমে ইমেল পাঠানোর জন্য একটি চমৎকার পছন্দ। এই লাইব্রেরিটি ইমেল তৈরি এবং পাঠানোর প্রক্রিয়াকে সহজ করে, এবং এটি HTML email content, file attachments এবং inline image গুলির জন্য built-in support প্রদান করে।

আপনার রেজিস্ট্রেশন ফর্মে PHPMailer ব্যবহার করে, আপনি email confirmation এবং verification process কে স্ট্রীমলাইন করতে পারেন, এটি আপনার ইউজারদের তাদের রেজিস্ট্রেশন সম্পূর্ণ করার এবং আপনার প্ল্যাটফর্মের ফীচার গুলি অ্যাক্সেস করার জন্য একটি নিরাপদ এবং কার্যকর উপায় প্রদান করে।

এখানে আমরা , PHPMailer ব্যবহার করে নতুন নিবন্ধিত ইউজারদের confirmation email পাঠাতে ব্যবহার করব। যখন একজন ব্যবহারকারী সাইন আপ করবে , তখন আমরা PHPMailer এর সাহায্যে একটি unique confirmation link সহ একটি ইমেল তৈরি এবং পাঠাব, যা ব্যবহারকারীদের তাদের ইমেল ঠিকানা ভেরিফাই করতে এবং তাদের অ্যাকাউন্ট এক্টিভেট করতে দিবে। এটি আমাদের ব্যবহারকারীর রেজিস্ট্রেশন প্রক্রিয়ার security এবং integrity বাড়াবে।

PHPMailer টি ইনস্টল করতে নিচের Composer command টি আপনার Command Prompt রান করুন :

composer require phpmailer/phpmailer

সবকিছু ঠিকঠাক থাকলে আপনি নিচের মতো একটা রেজাল্ট দেখতে পাবেন :

PHPMailer Registration Success

Create Gmail App Password

আর যেহেতু পুরো বিষয়টা আমরা localhost এ check করব , তাই আমরা আপাতত google mail ব্যবহার করব। আর এর জন্য আমরা নিম্নোক্ত উপায়ে আমাদের Gmail Account এর বিপরীতে একটি App Password তৈরি করব :

  1. Go to your Google Account.
  2. Select Security.
  3. Under “Signing in to Google,” select 2-Step Verification.
  4. At the bottom of the page, select App passwords.
  5. Enter a name that helps you remember where you’ll use the app password.
  6. Select Generate.
  7. To enter the app password, follow the instructions on your screen. The app password is the 16-character code that generates on your device.
  8. Select Done.

Create Database Connection

এবার আমরা db_connection.php ফাইলে ডাটাবেস কানেক্শনের কাজটি করব।

<?php
// Replace the following values with your actual database credentials
$hostname = 'YOUR_DATABASE_HOSTNAME'; //Usually localhost
$username = 'YOUR_DATABASE_USERNAME';
$password = 'YOUR_DATABASE_PASSWORD';
$database = 'YOUR_DATABASE_NAME_HERE';

try {
    $db = new PDO("mysql:host=$hostname;dbname=$database", $username, $password);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("Database connection failed: " . $e->getMessage());
}

এই কোডটি একটি database connection স্থাপনের জন্য একটি সাধারণ প্যাটার্ন এবং একটি PHP অ্যাপ্লিকেশনের মধ্যে ডাটাবেস অপারেশন সম্পাদনের জন্য অত্যন্ত গুরুত্বপূর্ণ। সঠিকভাবে কাজ করার জন্য আপনার প্রকৃত database credentials এর সাথে placeholder মানগুলি প্রতিস্থাপন করা নিশ্চিত করুন৷

Create resetProcess Class

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

require 'vendor/autoload.php'; // Composer autoloader
class resetProcess{
    private $db;
    
    public function __construct($db) {
        $this->db = $db;
    }
    
    public function requestPasswordReset($email) {
        // Check if the email exists in the database
        $user = $this->getUserByEmail($email);
    
        if ($user) {
            // Generate a unique token
            $token = bin2hex(random_bytes(32)); // A 64-character token
    
            // Store the token and timestamp in the database
            if ($this->storePasswordResetToken($user['user_id'], $token)) {
                // Send a password reset email to the user using PHPMailer
                $resetLink = "https://yourdomainname.com/reset_password.php?token=" . urlencode($token);
                $subject = "Password Reset";
                $message = "To reset your password, click the following link: $resetLink";
    
                $emailSent = $this->sendEmail($email, $subject, $message);
    
                if ($emailSent === true) {
                    return 'success'; // Password reset email sent successfully
                } else {
                    return 'email_error'; // Error message from PHPMailer
                }
            } else {
                return 'db_error'; // Token storage failed
            }
        } else {
            return 'not_found'; // Email not found in the system
        }
    }
    
    public function getUserByEmail($email) {
        // Get user data from the database based on email
        $query = "SELECT user_id, name, verified, password FROM users WHERE email = :email";
    
        $stmt = $this->db->prepare($query);
    
        if ($stmt) {
            $stmt->bindParam(':email', $email, PDO::PARAM_STR);
            $stmt->execute();
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            $stmt->closeCursor();
    
            if ($result) {
                return $result;
            }
        }
    
        return null; // No user found or database error
    }


    function sendEmail($recipient, $subject, $message) {
        $mail = new PHPMailer(true);
    
        try {
            $mail->isSMTP();
            $mail->Host = 'smtp.gmail.com'; // Gmail SMTP server
            $mail->SMTPAuth = true;
            $mail->Username = 'masud.eden@gmail.com'; // Your Gmail email address
            $mail->Password = 'zvnjowacspnhbnqo'; // Your Gmail app-specific password
            $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // Use 'tls' or 'ssl'
            $mail->Port = 587; // Use 465 for SSL
    
            $mail->setFrom('masud.eden@gmail.com', 'W3Programmers');
            $mail->addAddress($recipient);
    
            $mail->isHTML(true);
            $mail->Subject = $subject;
            $mail->Body = $message;
    
            $mail->send();
            return true;
        } catch (Exception $e) {
            return $mail->ErrorInfo;
        }
    }    
    private function storePasswordResetToken($user_id, $token) {
        // Store the token and timestamp in the database
        $query = "INSERT INTO password_reset_tokens (user_id, token, token_created_at) VALUES (:user_id, :token, NOW())";
    
        $stmt = $this->db->prepare($query);
    
        if ($stmt) {
            $stmt->bindParam(':user_id', $user_id, PDO::PARAM_STR);
            $stmt->bindParam(':token', $token, PDO::PARAM_STR);
    
            if ($stmt->execute()) {
                return true; // Token stored successfully
            }
        }
    
        return false; // Token storage failed
    }
    

    public function validatePasswordResetToken($token) {
        // Check if the provided token exists in the database
        $query = "SELECT user_id, token, token_created_at FROM password_reset_tokens WHERE token = :token";
        $stmt = $this->db->prepare($query);
    
        if ($stmt) {
            $stmt->bindParam(':token', $token, PDO::PARAM_STR);
            $stmt->execute();
    
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
    
            if ($result) {
                $token_created_at = strtotime($result['token_created_at']);
                $currentTimestamp = time();
                $tokenExpiryTime = $token_created_at + (24 * 60 * 60); // Token expires after 24 hours
    
                if ($currentTimestamp <= $tokenExpiryTime) {
                    // Token is valid
                    return true;
                } else {
                    // Token has expired; delete it from the database
                    $this->deletePasswordResetToken($token);
                }
            }
        }
    
        return false; // Token is invalid or not found
    }
        
    private function deletePasswordResetToken($token) {
        // Remove the expired or invalid token from the database
        $query = "DELETE FROM password_reset_tokens WHERE token = :token";
        $stmt = $this->db->prepare($query);
    
        if ($stmt) {
            $stmt->bindParam(':token', $token, PDO::PARAM_STR);
            $stmt->execute();
        }
    }
    
    public function resetPassword($token, $newPassword) {
        // Validate the token before resetting the password
        if ($this->validatePasswordResetToken($token)) {
            // Generate a new hashed password
            $newHashedPassword = password_hash($newPassword, PASSWORD_BCRYPT);
    
            // Get the user ID associated with the token
            $query = "SELECT user_id FROM password_reset_tokens WHERE token = :token";
            $stmt = $this->db->prepare($query);
    
            if ($stmt) {
                $stmt->bindParam(':token', $token, PDO::PARAM_STR);
                $stmt->execute();
    
                $result = $stmt->fetch(PDO::FETCH_ASSOC);
    
                if ($result) {
                    $user_id = $result['user_id'];
    
                    // Update the user's password in the database
                    $updateQuery = "UPDATE users SET password = :password WHERE user_id = :user_id";
                    $updateStmt = $this->db->prepare($updateQuery);
    
                    if ($updateStmt) {
                        $updateStmt->bindParam(':password', $newHashedPassword, PDO::PARAM_STR);
                        $updateStmt->bindParam(':user_id', $user_id, PDO::PARAM_INT);
    
                        if ($updateStmt->execute()) {
                            // Password reset successful; remove the token from the database
                            $this->deletePasswordResetToken($token);
                            return true;
                        }
                    }
                }
            }
        }
    
        return false; // Password reset failed
    }

}

এই PHP কোডটি একটি resetProcess ক্লাস ডিফাইন করে যা একটি ওয়েব অ্যাপ্লিকেশনের জন্য টোটাল password reset process পরিচালনা করে। এখানে ক্লাসের মধ্যে মূল কাজ গুলোর একটি সংক্ষিপ্ত বিবরণ রয়েছে:

  • ১. Constructor:
    • class constructor resetProcess object ইনিশিয়ালাইজ করে এবং প্যারামিটার হিসাবে একটি ডাটাবেস কানেকশন ($db) গ্রহণ করে।
  • ২. requestPasswordReset($email):
    • এই method টি ইউজারের ইমেলের উপর ভিত্তি করে ইউজারের নিজের জন্য একটি পাসওয়ার্ড রিসেট রিকোয়েস্ট তৈরি করে ।
    • এটি প্রথমে চেক করে যে প্রদত্ত ইমেল ডাটাবেসে বিদ্যমান কিনা।
    • ইমেলটি পাওয়া গেলে, এটি একটি unique token তৈরি করে, এটি ডাটাবেসে সংরক্ষণ করে এবং sendEmail এবং PHPMailer ব্যবহার করে ইউজারকে একটি পাসওয়ার্ড রিসেট ইমেল পাঠায়।
    • মেথডটি প্রসেস করা ফলাফলের উপর ভিত্তি করে ‘success,’ ’email_error,’ ‘db_error,’ বা ‘not_found’ এর মতো বিভিন্ন status messages রিটার্ন করে।
  • ৩. getUserByEmail($email):
    • এই method টি তাদের email address এর উপর ভিত্তি করে ডাটাবেস থেকে ইউজারের ডেটা বের করে।
    • প্রদত্ত ইমেল সহ একজন ইউজার বিদ্যমান কিনা তা পরীক্ষা করতে এটি ব্যবহার করা হয়।
  • ৪. sendEmail($recipient, $subject, $message):
    • এই method টি প্রদত্ত subject এবং message সহ নির্দিষ্ট প্রাপককে একটি ইমেল পাঠাতে PHPMailer ব্যবহার করে।
    • এটি SMTP কনফিগারেশন পরিচালনা করে এবং ইমেলটি সফলভাবে পাঠানো হলে true বা কোনো সমস্যা হলে একটি error message প্রদান করে।
  • ৫. storePasswordResetToken($user_id, $token):
    • এই method টি ডাটাবেসে পাসওয়ার্ড রিসেট টোকেন এবং একটি টাইমস্ট্যাম্প সংরক্ষণ করে।
    • এটি ইউজারের পাসওয়ার্ড পুনরায় সেট করার জন্য একটি লিঙ্ক তৈরি করতে ব্যবহৃত হয়।
  • ৬. validatePasswordResetToken($token):
    • এই method টি পাসওয়ার্ড রিসেট টোকেনের validity পরীক্ষা করে।
    • এটি যাচাই করে যে টোকেনটি ডাটাবেসে বিদ্যমান আছে কি না, expired হয়নি এবং ইউজারের সাথে যুক্ত।
    • Expired বা invalid token ডাটাবেস থেকে ডিলিট করে ফেলবে।
  • ৭. deletePasswordResetToken($token):
    • এই method টি ডাটাবেস থেকে expired বা invalid password reset token রিমুভ করে দেয়।
  • ৮. resetPassword($token, $newPassword):
    • প্রদত্ত টোকেন বৈধ হলে এই method টি ইউজারের পাসওয়ার্ড পুনরায় সেট করে।
    • এটি একটি নতুন হ্যাশ করা পাসওয়ার্ড তৈরি করে, এটি ডাটাবেসে আপডেট করে এবং পাসওয়ার্ড রিসেট সফল হলে টোকেনটি remove করে দেয়।

এই ক্লাসটি একটি PHP-based web application এর মধ্যে একটি secure এবং user-friendly password reset system বাস্তবায়নের জন্য একটি ব্যাপক সমাধান প্রদান করে।

Create forgot_password.html File To Request Password Reset

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Forgot Password</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-6">
                <h2 class="text-center">Forgot Password</h2>
                <form id="forgot-password-form" method="POST">
                    <div class="form-group">
                        <label for="email">Email:</label>
                        <input type="text" class="form-control" id="email" name="email">
                        <div class="invalid-feedback error-message" id="email-error"></div>
                    </div>

                    <button type="submit" class="btn btn-primary">Submit</button>
                </form>

                <div id="forgot-password-message" class="text-danger mt-2"></div>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="scripts.js"></script>
</body>
</html>

এই HTML ফর্মটি password recovery এর জন্য ডিজাইন করা হয়েছে। ইউজাররা তাদের ইমেল এড্রেস ইনপুট করতে পারেন, এবং সাবমিট দেওয়ার পরে, তাদের পাসওয়ার্ড পুনরায় সেট করার জন্য একটি রিকোয়েস্ট পাঠানো হয়। ফর্মটি একটি smooth user experience এর জন্য user-friendly input validation এবং feedback প্রদান করে।

Create scripts.js File to validate Forgot Password Form and communicate with server

$(document).ready(function () {

    function isValidEmail(email) {
        var emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
        return emailRegex.test(email);
    }

    function sanitizeInput(input) {
        // Implement your input sanitization logic here.
        return input.trim();
    }

    $('#email').on('input', function () {
        var email = sanitizeInput($(this).val());

        if (!isValidEmail(email)) {
            $('#email-error').text('Invalid email address').show();
            return;
        } else {
            $('#email-error').hide();
        }

        if (email === '') {
            $('#email-error').text('Email is required').show();
            $(this).addClass('is-invalid');
        } else {
            $('#email-error').hide();
            $(this).removeClass('is-invalid');
        }
    });

    $('#forgot-password-form').submit(function (event) {
        event.preventDefault();

        var email = sanitizeInput($('#email').val());

        if (email === '') {
            $('#email-error').text('Email is required').show();
            $('#email').addClass('is-invalid');
            return;
        } else {
            $('#email-error').hide();
            $('#email').removeClass('is-invalid');
        }

        $.ajax({
            type: 'POST',
            url: 'request_password_reset.php',
            data: {
                email: email
            },
            success: function (response) {
                if (response === 'success') {
                    $('#forgot-password-form')[0].reset();
                    $('.form-control').removeClass('is-invalid');

                    // Escape user-provided data before updating the HTML
                    $('#forgot-password-message').text('A password reset email has been sent.');
                } else if (response === 'not_found') {
                    $('#forgot-password-message').text('Email not found. Please try a different email.');
                    $('#email').addClass('is-invalid');
                } else {
                    $('#forgot-password-message').text('Password reset request failed.');
                    $('#email').addClass('is-invalid');
                }
            }
        });
    });
});

এই জাভাস্ক্রিপ্ট কোডটি “Forgot Password” ফর্মের real-time validation এবং submission handling দেওয়ার জন্য ডিজাইন করা হয়েছে। এটি নিম্নলিখিত ফাঙ্কশনালিটি প্রদান করে:

  • ১. Real-time Email Validation:
    • এটি email field এ ইউজারের দেওয়া email address গুলি Real-time Validation করে৷
    • Invalid email address গুলি error message এবং স্টাইল পরিবর্তন ট্রিগার করে।
  • ২. Form Submission Handling:
    • যখন একজন ইউজার “Submit” এ ক্লিক করলে এটি default form submission হওয়াকে বাধা দেয়।
    • এটি email field টি তে ইমেইল দেওয়া হয়েছে কিনা তা চেক করে এবং সংশ্লিষ্ট validation error গুলি হ্যান্ডেল করে।
    • এটি একটি পাসওয়ার্ড রিসেট প্রক্রিয়া শুরু করার জন্য একটি server-side script (‘request_password_reset.php’) এ একটি asynchronous AJAX request করে।
    • সার্ভার থেকে response এর উপর নির্ভর করে, এটি পেজে যথাযথ messages প্রদর্শন করে, সেটা হবে পারে success, বা email not found অথবা request failure.

Forgot Password Form

সামগ্রিকভাবে, এই কোডটি real-time feedback প্রদান করে এবং “Forgot Password” form submission দেওয়ার কার্যকরী পরিচালনার মাধ্যমে ইউজারের অভিজ্ঞতা বাড়ায়।

Create request_password_reset.php File to handling Server Functionality

<?php

require_once 'db_connection.php';
require_once 'resetProcess.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Initialize the resetPassword class with dependency injection
    $resetPassword = new ResetProcess($db);

    // Use filter_var to sanitize and validate the email address
    $email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);

    // Check if the email is valid
    if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
        // Call the requestPasswordReset method to initiate the password reset process
        $result = $resetPassword->requestPasswordReset($email);

        // Use a switch statement for better readability
        switch ($result) {
            case 'success':
                echo 'success'; // Password reset email sent successfully
                break;
            case 'not_found':
                echo 'not_found'; // Email not found in the system
                break;
            default:
                echo 'failure'; // Password reset request failed
        }
    } else {
        echo 'invalid_email'; // Invalid email format
    }
}
?>

এই PHP script টি password reset process শুরু করার সাথে সম্পর্কিত একটি POST request handling করার জন্য দায়িত্বপ্রাপ্ত । এখানে এর ফাঙ্কশনালিটির একটি সারসংক্ষেপ রয়েছে:

  • ১. এতে প্রয়োজনীয় ফাইল যেমন database connection এর (‘db_connection.php’) এবং ‘resetProcess.php’ ক্লাস ফাইল রয়েছে।
  • ২. যখন একটি POST request রিসিভ হয়, এটি নিম্নলিখিত অ্যাকশন গুলো সম্পাদন করে:
    • একটি প্যারামিটার হিসাবে ডাটাবেস কানেকশন পাস করে ‘resetProcess’ ক্লাসের একটি ইনস্ট্যান্স তৈরি করে।
    • POST ডেটা থেকে ইউজারের email address রিট্রিভ করে।
    • পাসওয়ার্ড রিসেট প্রক্রিয়া শুরু করতে ‘resetProcess’ ক্লাসের ‘requestPasswordReset’ মেথড কল করে।
    • মেথডের ফলাফলের উপর ভিত্তি করে, পাসওয়ার্ড রিসেট ইমেলটি সফলভাবে পাঠানো হলে এটি ‘success’ , যদি সিস্টেমে ইমেলটি পাওয়া না যায় তবে ‘not_found’ বা পাসওয়ার্ড পুনরায় সেট করার অনুরোধ ব্যর্থ হলে ‘failure’ echo হয়।

এই কোডটি পাসওয়ার্ড রিসেট প্রক্রিয়া শুরু করার জন্য একটি ব্যাকএন্ড হ্যান্ডলার হিসাবে কাজ করে এবং রিকোয়েস্টের ফলাফলের উপর প্রতিক্রিয়া প্রদান করে।

password reset email

Create reset_password.php File to reset password based on the token received from email link

<?php
require 'vendor/autoload.php';
require 'db_connection.php';
require 'resetProcess.php';

// Check if the reset password token is present in the query parameters
if (!isset($_GET['token'])) {
    // Redirect the user to an error page or the login page
    header("Location: error_page.php");
    exit;
}

$token = $_GET['token'];

// Initialize the resetPassword class with dependency injection
$resetPassword = new ResetProcess($db);

// Validate the reset password token
if (!$resetPassword->validatePasswordResetToken($token)) {
    // Redirect the user to an error page or the login page
    header("Location: error_page.php");
    exit;
}

// The reset password token is valid; render the reset password form
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Reset Password</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-6">
                <h2 class="text-center">Reset Password</h2>
                <form id="reset-password-form" method="POST">
                    <div class="form-group">
                        <label for="password">New Password:</label>
                        <input type="password" class="form-control" id="password" name="password">
                        <div class="invalid-feedback error-message" id="password-error"></div>
                    </div>

                    <div class="form-group">
                        <label for="confirm-password">Confirm Password:</label>
                        <input type="password" class="form-control" id="confirm-password" name="confirm-password">
                        <div class="invalid-feedback error-message" id="confirm-password-error"></div>
                    </div>

                    <button type="submit" class="btn btn-primary">Reset Password</button>
                </form>

                <div id="reset-password-message" class="mt-2"></div>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="reset_scripts.js"></script>
</body>
</html>

এই HTML কোড একটি “Password Reset ” ফর্ম উপস্থাপন করে। এখানে একটি সংক্ষিপ্ত বিবরণ দেওয়া হলো:

  • ফর্মটি এমন ইউজারদের জন্য ডিজাইন করা হয়েছে যারা তাদের পাসওয়ার্ড রিসেট করতে চান।
  • এটি একটি নতুন পাসওয়ার্ড নেওয়ার জন্য তৈরি করা হয়েছে এবং এটি নিশ্চিত করার জন্য ফিল্ড গুলিতে সঠিক পাসওয়ার্ড দেওয়া হয়েছে ৷
  • Real-time validation প্রয়োগ করা হয়, এবং যদি প্রবেশ করা পাসওয়ার্ডগুলি না মেলে বা ভুলভাবে ফর্ম্যাট করা হয় তবে error message গুলি প্রদর্শিত হয়৷
  • submission এর পরে, ফর্মটি পাসওয়ার্ড রিসেট প্রসেস পরিচালনা করার জন্য একটি POST অনুরোধ পাঠায়।
  • পেজটি একটি message area এর মাধ্যমে পাসওয়ার্ড রিসেট ফলাফলের উপর ইউজারকে ফিডব্যাক প্রদান করে।
  • এতে client-side scripting এর জন্য jQuery অন্তর্ভুক্ত রয়েছে এবং ফর্ম ইন্টারঅ্যাকশন এবং ভ্যালিডেশন গুলি পরিচালনা করার জন্য একটি জাভাস্ক্রিপ্ট ফাইল (‘reset_scripts.js’) ব্যবহার করে।

Create reset_scripts.js File to handle Form Validation, Check Token and communicate with Server

$(document).ready(function () {
    const passwordInput = $('#password');
    const confirmPasswordInput = $('#confirm-password');
    const passwordError = $('#password-error');
    const confirmPasswordError = $('#confirm-password-error');
    const resetPasswordForm = $('#reset-password-form');

    passwordInput.on('input', function () {
        validatePassword();
    });

    confirmPasswordInput.on('input', function () {
        validateConfirmPassword();
    });

    resetPasswordForm.submit(function (event) {
        event.preventDefault();

        validatePassword();
        validateConfirmPassword();

        if (passwordError.is(':visible') || confirmPasswordError.is(':visible')) {
            return;
        }

        var password = passwordInput.val();
        var confirmPassword = confirmPasswordInput.val();
        var token = window.location.search.split('=')[1];

        $.ajax({
            type: 'POST',
            url: 'process_reset_password.php',
            data: {
                password: password,
                token: token
            },
            success: function (response) {
                if (response === 'success') {
                    resetPasswordForm[0].reset();
                    $('.form-control').removeClass('is-invalid');

                    $('#reset-password-message').html('Password has been reset successfully.');

                    setTimeout(function () {
                        window.location.href = 'LoginForm.html';
                    }, 3000);
                } else if (response === 'expired') {
                    $('#reset-password-message').html('This password reset link has expired.');
                } else {
                    $('#reset-password-message').html('Password reset failed.');
                }
            }
        });
    });

    function validatePassword() {
        var password = passwordInput.val();

        if (password.trim() === '') {
            passwordError.html('Password is required').show();
            passwordInput.addClass('is-invalid');
        } else {
            passwordError.hide();
            passwordInput.removeClass('is-invalid');
        }
    }

    function validateConfirmPassword() {
        var password = passwordInput.val();
        var confirmPassword = confirmPasswordInput.val();

        if (confirmPassword.trim() === '') {
            confirmPasswordError.html('Confirm Password is required').show();
            confirmPasswordInput.addClass('is-invalid');
        } else if (password !== confirmPassword) {
            confirmPasswordError.html('Passwords do not match').show();
            confirmPasswordInput.addClass('is-invalid');
        } else {
            confirmPasswordError.hide();
            confirmPasswordInput.removeClass('is-invalid');
        }
    }
});

এই জাভাস্ক্রিপ্ট কোড একটি “Reset Password” ফর্মের জন্য রিয়েল-টাইম ভ্যালিডেশন প্রদান করে এবং এটির সাবমিশন পরিচালনা করে। এখানে একটি ব্রেকডাউন দেওয়া হলো :

  • Password এবং confirm password field গুলির জন্য Real-time validation প্রয়োগ করা হয়। তারা empty কিনা এবং পাসওয়ার্ড মেলে কিনা তা চেক করে। ভ্যালিডেশন সমস্যা থাকলে Error messages দেখানো হয়।
  • একটি AJAX রিকোয়েস্টের মাধ্যমে এটি পরিচালনা করার জন্য (events.preventDefault() ব্যবহার করে) ফর্ম জমা দেওয়া আটকানো হয়।
  • এটি URL থেকে টোকেন বের করে (যেমন, ‘https://yourdomain.com/reset_password.php?token=…’ থেকে)।
  • এটি নতুন পাসওয়ার্ড এবং টোকেন সহ ‘process_reset_password.php’-এ একটি POST রিকোয়েস্ট পাঠায়।
  • success callback function রেসপন্স গুলো প্রসেস করে এবং ইউজারকে রেসপন্স প্রদান করে।
  • যদি response ‘success’ হয়, তবে এটি ফর্মটি পুনরায় সেট করে, ভ্যালিডেশন ক্লাসগুলি রিমুভ করে দেয় এবং একটি success message প্রদর্শন করে৷ এটি 3 সেকেন্ড পরে একটি success page এ রিডাইরেক্ট করে।
  • যদি response টি ‘expired’ হয়ে থাকে তবে এটি নির্দেশ করে যে password reset link has expired.
  • যদি রেসপন্স ‘success’ না হয় বা ‘expired’ হয় তবে এটি একটি সাধারণ failure message দেখায়।
    • Reset Password Form

      Create process_reset_password.php File to save new Password

      <?php
      // Include necessary files and classes
      require 'vendor/autoload.php'; // Include Composer autoload
      require 'db_connection.php'; // Include your database connection file
      require 'resetProcess.php'; // Include your resetPasswordClass
      
      if ($_SERVER['REQUEST_METHOD'] === 'POST') {
          // Initialize the resetPassword class
          $resetPassword = new resetProcess($db);
      
          // Get the password and token from the POST data
          $password = $_POST['password'];
          $token = $_POST['token'];
      
          // Validate the token and check if it has expired
          $tokenIsValid = $resetPassword->validatePasswordResetToken($token);
      
          if ($tokenIsValid === true) {
              // Reset the password
              $passwordResetSuccess = $resetPassword->resetPassword($token, $password);
      
              if ($passwordResetSuccess === true) {
                  echo 'success'; // Password reset successful
              } else {
                  echo 'failure'; // Password reset failed
              }
          } else {
              echo 'expired'; // Token has expired
          }
      }
      ?>
      
      • ১. এই PHP code টি password reset process হ্যান্ডেল করে যখন একজন ইউজার তাদের ইমেলে একটি রিসেট লিঙ্কে ক্লিক করেন। এখানে এটা কিভাবে কাজ করে:
        • এতে প্রয়োজনীয় ফাইল গুলো include করা হয়েছে।
        • এটি HTTP request method টি POST কিনা তা পরীক্ষা করে, এটি নির্দেশ করে যে এটি ফর্ম ডেটা প্রসেস করছে৷
      • ২. POST request handling এর মধ্যে:
        • এটি resetProcess ক্লাসের একটি ইনস্ট্যান্স ইনিশিয়ালাইজ করে এবং ডাটাবেস সংযোগ পাস করে।
        • এটি POST ডেটা থেকে নতুন পাসওয়ার্ড এবং টোকেন রিট্রিভ করে।
      • ৩. তারপরে, এটি নিম্নলিখিত অ্যাকশন গুলি সম্পাদন করে:
        • এটি টোকেনটি যাচাই করে এবং পরীক্ষা করে যে এটি resetProcess ক্লাস থেকে validatePasswordResetToken Method ব্যবহার করে মেয়াদ শেষ হয়ে গেছে কিনা।
        • টোকেনটি বৈধ এবং expired না হলে, এটি একই ক্লাস থেকে resetPassword method ব্যবহার করে ইউজারের পাসওয়ার্ড পুনরায় সেট করার চেষ্টা করে।
        • পাসওয়ার্ড রিসেট সফল হলে, এটি পাসওয়ার্ড রিসেট করা হয়েছে তা নির্দেশ করতে ‘success’ echo করে।
        • পাসওয়ার্ড রিসেট কোনো কারণে ব্যর্থ হলে, এটি ‘failure’ echo করে নির্দেশ করে যে প্রক্রিয়াটি সফল হয়নি।
        • যদি টোকেনটি expired হয়ে যায়, তাহলে reset link expired হয়ে গেছে তা জানানোর জন্য এটি ‘expired’ echo করে।

      আমি মাসুদ আলম, বাংলাদেশের ৩৬ তম Zend Certified Engineer । ২০০৯ সালে কম্পিউটার সাইন্স থেকে বেচেলর ডিগ্রী অর্জন করি। দীর্ঘ ১৫ বছর আমি Winux Soft, SSL Wireless, IBCS-PRIMAX, Max Group, Canadian International Development Agency (CIDA), Care Bangladesh, World Vision, Hellen Keller, Amarbebsha Ltd সহ বিভিন্ন দেশি বিদেশী কোম্পানিতে ডেটা সাইন্স, মেশিন লার্নিং, বিগ ডেটা, ওয়েব ডেভেলপমেন্ট এবং সফটওয়্যার ডেভেলপমেন্ট এর উপর বিভিন্ন লিডিং পজিশন এ চাকরি এবং প্রজেক্ট লিড করি। এছাড়াও বাংলাদেশের ১৮৫ জন জেন্ড সার্টিফাইড ইঞ্জিনিয়ার এর মধ্যে ১২০ এরও অধিক ছাত্র আমার হাতে জেন্ড সার্টিফাইড ইঞ্জিনিয়ার হয়েছেন। বর্তমানে w3programmers ট্রেনিং ইনস্টিটিউট এ PHP এর উপর Professional এবং Advance Zend Certified PHP -8.2 Engineering, Laravel Mastering Course with ReactJS, Python Beginning To Advance with Blockchain, Machine Learning and Data Science, Professional WordPress Plugin Development Beginning to Advance কোর্স করাই। আর অবসর সময়ে w3programmers.com এ ওয়েব টেকনোলজি নিয়ে লেখালেখি করি।

Leave a Reply