Comment

PHP লগিন সিস্টেম (Login System)

PHP ইমেল যাচাইকরণ (Email verification)

Estimated reading: 6 minutes 13 views Contributors

সারাংশ: এই টিউটোরিয়ালে, আপনি শিখবেন কিভাবে একটি অ্যাক্টিভেশন লিঙ্ক ব্যবহার করে নিরাপদে নতুন অ্যাকাউন্টের ইমেল ঠিকানা যাচাই করতে হয়।

নতুন অ্যাকাউন্টের জন্য PHP ইমেল যাচাইকরণের ভূমিকা

আগের টিউটোরিয়ালে, আপনি শিখেছেন কীভাবে একটি নিবন্ধন ফর্ম তৈরি করতে হয় যা ব্যবহারকারীদের অ্যাকাউন্টের জন্য নিবন্ধন করতে দেয়। এবং আপনি কীভাবে একটি লগইন ফর্ম তৈরি করবেন তাও শিখেছেন যা ব্যবহারকারীদের সাইন ইন করতে ব্যবহারকারীর নাম এবং পাসওয়ার্ড ব্যবহার করতে সক্ষম করবে৷

ব্যবহারকারীরা যখন নতুন অ্যাকাউন্টের জন্য নিবন্ধন করেন, তখন তারা তাদের ইমেল ঠিকানাগুলি প্রবেশ করেন৷ যাইহোক, ব্যবহারকারীরা যে কোনও ইমেল ঠিকানা লিখতে পারেন কারণ সিস্টেমটি ইমেল যাচাই করে না।

ব্যবহারকারীদের ইমেল ঠিকানা যাচাই করতে, আপনি এই ইমেল ঠিকানাগুলিতে একটি যাচাইকরণ ইমেল পাঠাতে পারেন এবং ব্যবহারকারীদের তাদের ইমেলগুলি খুলতে এবং একটি সক্রিয়করণ লিঙ্কে ক্লিক করার জন্য অনুরোধ করতে পারেন।

এটি করার জন্য, ব্যবহারকারীরা অ্যাকাউন্ট নিবন্ধন করার সময় আপনি নিম্নলিখিত পদক্ষেপগুলি অনুসরণ করুন:

  • একটি অনন্য অ্যাক্টিভেশন কোড তৈরি করুন এবং একটি মেয়াদ শেষ হওয়ার সময় সেট করুন, যেমন, একদিন ৷
  • ডাটাবেসে ব্যবহারকারীর রেকর্ড সংরক্ষণ করুন এবং ব্যবহারকারীর স্থিতি নিষ্ক্রিয় হিসাবে চিহ্নিত করুন। এছাড়াও, অ্যাক্টিভেশন কোড এবং মেয়াদ শেষ হওয়ার সময় হ্যাশ সংরক্ষণ করুন।
  • ব্যবহারকারীর ইমেল ঠিকানায় সক্রিয়করণ লিঙ্ক সহ একটি ইমেল পাঠান। সক্রিয়করণ লিঙ্কটিতে ইমেল ঠিকানা এবং সক্রিয়করণ কোড থাকবে, যেমন, https://app.com/activate.php?email=email&activation_code=abcd
  • ব্যবহারকারীকে ইমেলের মাধ্যমে অ্যাকাউন্ট সক্রিয় করতে জানান।

অ্যাক্টিভেশন কোড হ্যাশ করা নিশ্চিত করে যে শুধুমাত্র যে ব্যবহারকারীর ইমেল ঠিকানার মালিক তারাই অ্যাকাউন্টটি সক্রিয় করতে পারে, অন্য কেউ নয়, এমনকি অ্যাডমিনও, যারা ডাটাবেস অ্যাক্সেস করতে পারে।

ব্যবহারকারীরা অ্যাকাউন্ট সক্রিয় না করে থাকলে, তারা লগ ইন করতে পারবে না।

যখন ব্যবহারকারীরা ইমেলে অ্যাক্টিভেশন লিঙ্কে ক্লিক করেন, তখন আপনাকে নিম্নলিখিত পদক্ষেপগুলি সম্পাদন করতে হবে:

  • ইমেল এবং অ্যাক্টিভেশন কোড স্যানিটাইজ করুন এবং যাচাই করুন।
  • ইমেল ঠিকানা সহ নিষ্ক্রিয় ব্যবহারকারী খুঁজুন। কোনো ব্যবহারকারীর রেকর্ড না থাকলে, নিবন্ধন ফর্মে পুনঃনির্দেশ করুন।
  • যদি একটি ব্যবহারকারীর রেকর্ড বিদ্যমান থাকে এবং অ্যাক্টিভেশন কোডের মেয়াদ শেষ হয়ে যায়, তাহলে ডাটাবেস থেকে ব্যবহারকারীর রেকর্ড মুছে দিন এবং নিবন্ধন ফর্মে পুনঃনির্দেশ করুন।
  • অন্যথায়, ডাটাবেসে সংরক্ষিত অ্যাক্টিভেশন কোডের হ্যাশের সাথে অ্যাক্টিভেশন কোডের সাথে ম্যাচ করুন। যদি তারা মিলে যায়, ব্যবহারকারীর রেকর্ডটিকে সক্রিয় হিসাবে চিহ্নিত করুন এবং লগইন পৃষ্ঠায় পুনঃনির্দেশ করুন ৷

ব্যবহারকারীদের টেবিল পুনরায় তৈরি করুন

প্রথমে, প্রমাণীকরণ ডাটাবেস থেকে ব্যবহারকারীর টেবিলটি ড্রপ করুন:

DROP TABLE users;

দ্বিতীয়ত, নতুন কলাম সক্রিয়, activation_code, activation_at, activation_expiry সহ ব্যবহারকারীর টেবিল তৈরি করুন:

CREATE TABLE users
(
    id                int auto_increment PRIMARY KEY,
    username          varchar(25)  NOT NULL,
    email             varchar(255) NOT NULL,
    password          varchar(255) NOT NULL,
    is_admin          tinyint(1)   NOT NULL DEFAULT 0,
    active            tinyint(1)            DEFAULT 0,
    activation_code   varchar(255) NOT NULL,
    activation_expiry datetime     NOT NULL,
    activated_at      datetime              DEFAULT NULL,
    created_at        timestamp    NOT NULL DEFAULT current_timestamp(),
    updated_at        datetime              DEFAULT current_timestamp() ON UPDATE current_timestamp()

);

নিম্নলিখিত নতুন কলামগুলির অর্থ ব্যাখ্যা করে।

সক্রিয় কলামের মান ডিফল্ট 0। এর মানে হল যে ব্যবহারকারীরা অ্যাকাউন্টের জন্য নিবন্ধন করেন কিন্তু তাদের ইমেল ঠিকানা যাচাই করেননি তারা ডিফল্টরূপে নিষ্ক্রিয় হবে।

অ্যাক্টিভেশন_কোড কলাম অ্যাক্টিভেশন কোডের হ্যাশ সংরক্ষণ করবে। পাসওয়ার্ড_হ্যাশ() ফাংশন দ্বারা প্রত্যাবর্তিত স্ট্রিং সংরক্ষণ করার জন্য এর দৈর্ঘ্য যথেষ্ট হওয়া উচিত।

এটি লক্ষ্য করা গুরুত্বপূর্ণ যে হ্যাশটি কেটে ফেলা হবে যদি অ্যাক্টিভেশন_কোড কলামের যথেষ্ট লম্বা আকার না থাকে। এটি পাসওয়ার্ড_verify() ফাংশনটিকে হ্যাশের সাথে অ্যাক্টিভেশন কোডের সাথে মেলে ফেলতে ব্যর্থ হবে।

অ্যাক্টিভেশন_এক্সপায়ারি কলাম মেয়াদ শেষ হওয়ার আগে অ্যাক্টিভেশন কোড ব্যবহার করার মেয়াদ সঞ্চয় করে। মেয়াদ শেষ হওয়ার সময় নিশ্চিত করে যে অ্যাক্টিভেশন কোডটি ব্যবহার করা যাবে না যদি মেয়াদ শেষ হওয়ার পরে ইমেল ঠিকানাটি আপস করা হয়।

activated_at কলাম ব্যবহারকারীরা তাদের অ্যাকাউন্ট সক্রিয় করার তারিখ এবং সময় সংরক্ষণ করে।

প্রকল্প কাঠামো

ইমেল যাচাইকরণ ফাংশন যোগ করার আগে চলুন বর্তমান প্রকল্প কাঠামো পর্যালোচনা করা যাক:

├── config
|  ├── app.php
|  └── database.php
├── public
|  ├── index.php
|  ├── login.php
|  ├── logout.php
|  └── register.php
└── src
    ├── auth.php
    ├── bootstrap.php
    ├── inc
    |  ├── footer.php
    |  └── header.php
    ├── libs
    |  ├── connection.php
    |  ├── filter.php
    |  ├── flash.php
    |  ├── helpers.php
    |  ├── sanitization.php
    |  └── validation.php
    ├── login.php
    └── register.php

auth.php ফাইলের ফাংশন পরিবর্তন করুন

নিম্নলিখিতটি register_user() ফাংশনে অ্যাক্টিভেশন কোড এবং মেয়াদ শেষ হওয়ার পরামিতি যোগ করে। ডিফল্টরূপে, মেয়াদ শেষ হওয়ার সময় একদিন (1 * 24 * 60 * 60)।

function register_user(string $email, string $username, string $password, string $activation_code, int $expiry = 1 * 24  * 60 * 60, bool $is_admin = false): bool
{
    $sql = 'INSERT INTO users(username, email, password, is_admin, activation_code, activation_expiry)
            VALUES(:username, :email, :password, :is_admin, :activation_code,:activation_expiry)';

    $statement = db()->prepare($sql);

    $statement->bindValue(':username', $username);
    $statement->bindValue(':email', $email);
    $statement->bindValue(':password', password_hash($password, PASSWORD_BCRYPT));
    $statement->bindValue(':is_admin', (int)$is_admin, PDO::PARAM_INT);
    $statement->bindValue(':activation_code', password_hash($activation_code, PASSWORD_DEFAULT));
    $statement->bindValue(':activation_expiry', date('Y-m-d H:i:s',  time() + $expiry));

    return $statement->execute();
}

register_user() ফাংশন পাসওয়ার্ড_হ্যাশ() ফাংশন ব্যবহার করে অ্যাক্টিভেশন কোড হ্যাশ করে।

find_user_by_username() ফাংশন ফলাফলে সক্রিয় কলাম অন্তর্ভুক্ত করে:

function find_user_by_username(string $username)
{
    $sql = 'SELECT username, password, active, email
            FROM users
            WHERE username=:username';

    $statement = db()->prepare($sql);
    $statement->bindValue(':username', $username);
    $statement->execute();

    return $statement->fetch(PDO::FETCH_ASSOC);
}

নিম্নলিখিত একটি নতুন ফাংশন is_user_active() সংজ্ঞায়িত করে যা ব্যবহারকারী সক্রিয় থাকলে সত্য ফেরত দেয়:

function is_user_active($user)
{
    return (int)$user['active'] === 1;
}

লগইন() ফাংশন শুধুমাত্র সক্রিয় ব্যবহারকারীদের সাইন ইন করার অনুমতি দেবে:

function login(string $username, string $password): bool
{
    $user = find_user_by_username($username);

    if ($user && is_user_active($user) && password_verify($password, $user['password'])) {
        // prevent session fixation attack
        session_regenerate_id();

        // set username in the session
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['username'] = $user['username'];

        return true;
    }

    return false;
}

ইমেল যাচাইকরণের সাথে ডিল করে এমন ফাংশনগুলি সংজ্ঞায়িত করুন

আমরা auth.php ফাইলে ইমেল যাচাইকরণের সাথে সম্পর্কিত ফাংশনগুলি যুক্ত করব।

প্রথমে, কনফিগার ফোল্ডারে একটি নতুন ফাইল app.php তৈরি করুন এবং নিম্নলিখিত ধ্রুবকগুলি সংজ্ঞায়িত করুন:

<?php

const APP_URL = 'http://localhost/auth';
const SENDER_EMAIL_ADDRESS = 'no-reply@email.com';

আমরা ব্যবহারকারীদের সক্রিয়করণ ইমেল পাঠানোর জন্য এই ধ্রুবকগুলি ব্যবহার করব। এই ধ্রুবকগুলি ব্যবহার করতে, আপনাকে bootstrap.php ফাইলে app.php ফাইলটি অন্তর্ভুক্ত করতে হবে:

<?php

session_start();
require_once __DIR__ . '/../config/app.php';
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/libs/helpers.php';
require_once __DIR__ . '/libs/flash.php';
require_once __DIR__ . '/libs/sanitization.php';
require_once __DIR__ . '/libs/validation.php';
require_once __DIR__ . '/libs/filter.php';
require_once __DIR__ . '/libs/connection.php';
require_once __DIR__ . '/auth.php';

দ্বিতীয়ত, একটি ফাংশন সংজ্ঞায়িত করুন যা একটি অনন্যভাবে র্যান্ডম অ্যাক্টিভেশন কোড তৈরি করে:

function generate_activation_code(): string
{
    return bin2hex(random_bytes(16));
}

তৃতীয়ত, একটি ফাংশন সংজ্ঞায়িত করুন যা একটি সক্রিয়করণ লিঙ্ক সহ একটি ইমেল যাচাইকরণ পাঠায়।

function send_activation_email(string $email, string $activation_code): void
{
    // create the activation link
    $activation_link = APP_URL . "/activate.php?email=$email&activation_code=$activation_code";

    // set email subject & body
    $subject = 'Please activate your account';
    $message = <<<MESSAGE
            Hi,
            Please click the following link to activate your account:
            $activation_link
            MESSAGE;
    // email header
    $header = "From:" . SENDER_EMAIL_ADDRESS;

    // send the email
    mail($email, $subject, nl2br($message), $header);

}

ধরুন অ্যাপটির URL হল http://localhost/auth, অ্যাক্টিভেশন ইউআরএলটি এরকম দেখাবে:

http://localhost/auth/activate.php?email=john@phptutorial.net&activation_code=e01e5c9a028d58d888ff2555b971c882

send_activation_email() ফাংশনটি ইমেল পাঠানোর জন্য অন্তর্নির্মিত mail() ফাংশন ব্যবহার করে।

চতুর্থ, একটি ফাংশন সংজ্ঞায়িত করুন যা আইডি এবং স্থিতি দ্বারা ব্যবহারকারীকে মুছে দেয়। ডিফল্টরূপে, এটি আইডি দ্বারা একটি নিষ্ক্রিয় ব্যবহারকারীকে মুছে দেয়।

function delete_user_by_id(int $id, int $active = 0)
{
    $sql = 'DELETE FROM users
            WHERE id =:id and active=:active';

    $statement = db()->prepare($sql);
    $statement->bindValue(':id', $id, PDO::PARAM_INT);
    $statement->bindValue(':active', $active, PDO::PARAM_INT);

    return $statement->execute();
}

পঞ্চম, একটি ফাংশন সংজ্ঞায়িত করুন যা একটি ইমেল এবং অ্যাক্টিভেশন কোড দ্বারা একটি অযাচাইকৃত ব্যবহারকারীকে খুঁজে পায়। যদি অ্যাক্টিভেশন কোডের মেয়াদ শেষ হয়ে যায়, ফাংশনটি delete_user_by_id() ফাংশনে কল করে ব্যবহারকারীর রেকর্ডও মুছে দেয়।

function find_unverified_user(string $activation_code, string $email)
{

    $sql = 'SELECT id, activation_code, activation_expiry < now() as expired
            FROM users
            WHERE active = 0 AND email=:email';

    $statement = db()->prepare($sql);

    $statement->bindValue(':email', $email);
    $statement->execute();

    $user = $statement->fetch(PDO::FETCH_ASSOC);

    if ($user) {
        // already expired, delete the in active user with expired activation code
        if ((int)$user['expired'] === 1) {
            delete_user_by_id($user['id']);
            return null;
        }
        // verify the password
        if (password_verify($activation_code, $user['activation_code'])) {
            return $user;
        }
    }

    return null;
}

function find_unverified_user(string $activation_code, string $email)
{

$sql = 'SELECT id, activation_code, activation_expiry < now() as expired
        FROM users
        WHERE active = 0 AND email=:email';

$statement = db()->prepare($sql);

$statement->bindValue(':email', $email);
$statement->execute();

$user = $statement->fetch(PDO::FETCH_ASSOC);

if ($user) {
    // already expired, delete the in active user with expired activation code
    if ((int)$user['expired'] === 1) {
        delete_user_by_id($user['id']);
        return null;
    }
    // verify the password
    if (password_verify($activation_code, $user['activation_code'])) {
        return $user;
    }
}

return null;

ষষ্ঠ, একটি নতুন activate_user() ফাংশন সংজ্ঞায়িত করুন যা একটি আইডি দ্বারা ব্যবহারকারীকে সক্রিয় করে:

function activate_user(int $user_id): bool
{
    $sql = 'UPDATE users
            SET active = 1,
                activated_at = CURRENT_TIMESTAMP
            WHERE id=:id';

    $statement = db()->prepare($sql);
    $statement->bindValue(':id', $user_id, PDO::PARAM_INT);

    return $statement->execute();
}

register.php পৃষ্ঠা পরিবর্তন করুন

src/register.php-এর ইমেল যাচাইকরণ লজিক পরিচালনা করার জন্য যুক্তি যুক্ত করতে হবে।

<?php

if (is_user_logged_in()) {
    redirect_to('index.php');
}

$errors = [];
$inputs = [];

if (is_post_request()) {
    $fields = [
        'username' => 'string | required | alphanumeric | between: 3, 25 | unique: users, username',
        'email' => 'email | required | email | unique: users, email',
        'password' => 'string | required | secure',
        'password2' => 'string | required | same: password',
        'agree' => 'string | required'
    ];

    // custom messages
    $messages = [
        'password2' => [
            'required' => 'Please enter the password again',
            'same' => 'The password does not match'
        ],
        'agree' => [
            'required' => 'You need to agree to the term of services to register'
        ]
    ];

    [$inputs, $errors] = filter($_POST, $fields, $messages);

    if ($errors) {
        redirect_with('register.php', [
            'inputs' => escape_html($inputs),
            'errors' => $errors
        ]);
    }

    $activation_code = generate_activation_code();

    if (register_user($inputs['email'], $inputs['username'], $inputs['password'], $activation_code)) {

        // send the activation email
        send_activation_email($inputs['email'], $activation_code);

        redirect_with_message(
            'login.php',
            'Please check your email to activate your account before signing in'
        );
    }

} else if (is_get_request()) {
    [$errors, $inputs] = session_flash('errors', 'inputs');
}

কিভাবে এটা কাজ করে.

প্রথমে, একটি অ্যাক্টিভেশন কোড তৈরি করুন:

$activation_code = generate_activation_code();

দ্বিতীয়ত, সক্রিয়করণ কোড দিয়ে ব্যবহারকারীকে নিবন্ধন করুন:

register_user($inputs['email'], $inputs['username'], $inputs['password'], $activation_code)

তৃতীয়ত, send_activation_email() ফাংশনে কল করে ব্যবহারকারীর ইমেল ঠিকানায় একটি ইমেল পাঠান:

send_activation_email($inputs['email'], $activation_code);

অবশেষে, ব্যবহারকারীকে লগইন পৃষ্ঠায় পুনঃনির্দেশিত করুন এবং একটি ফ্ল্যাশ বার্তা দেখান যা ব্যবহারকারীকে ইমেলের মাধ্যমে অ্যাকাউন্টটি সক্রিয় করার অনুরোধ করে:

redirect_with_message(
    'login.php',
    'Please check your email to activate your account before signing in'
);

activate.php পৃষ্ঠা তৈরি করুন

ব্যবহারকারীদের নিবন্ধনের পরে তাদের অ্যাকাউন্টগুলি সক্রিয় করার অনুমতি দেওয়ার জন্য, আপনি সর্বজনীন ফোল্ডারে একটি নতুন activate.php পৃষ্ঠা তৈরি করতে পারেন এবং নিম্নলিখিত পৃষ্ঠাটি ব্যবহার করতে পারেন:

<?php

require __DIR__ . '/../src/bootstrap.php';

if (is_get_request()) {

    // sanitize the email & activation code
    [$inputs, $errors] = filter($_GET, [
        'email' => 'string | required | email',
        'activation_code' => 'string | required'
    ]);

    if (!$errors) {

        $user = find_unverified_user($inputs['activation_code'], $inputs['email']);

        // if user exists and activate the user successfully
        if ($user && activate_user($user['id'])) {
            redirect_with_message(
                'login.php',
                'You account has been activated successfully. Please login here.'
            );
        }
    }
}

// redirect to the register page in other cases
redirect_with_message(
    'register.php',
    'The activation link is not valid, please register again.',
    FLASH_ERROR
);

activate.php কিভাবে কাজ করে।

প্রথমে, ইমেল এবং অ্যাক্টিভেশন কোড স্যানিটাইজ করুন এবং যাচাই করুন:

[$inputs, $errors] = filter($_GET, [
    'email' => 'string | required | email',
    'activation_code' => 'string | required'
]);

দ্বিতীয়ত, কোনো বৈধতা ত্রুটি না থাকলে ইমেল এবং যাচাইকরণ কোডের উপর ভিত্তি করে অযাচাইকৃত ব্যবহারকারী খুঁজুন। Find_unverified_user() এছাড়াও যাচাই না করা ব্যবহারকারীকে মুছে ফেলবে যদি মেয়াদ শেষ হয়ে যায়।

$user = find_unverified_user($inputs['activation_code'], $inputs['email']);

তৃতীয়ত, ব্যবহারকারীকে সক্রিয় করুন এবং login.php পৃষ্ঠায় পুনঃনির্দেশ করুন:

if ($user && activate_user($user['id'])) {
    redirect_with_message(
        'login.php',
        'You account has been activated successfully. Please login here.'
    );
}

সবশেষে, কোনো ত্রুটি থাকলে registration.php-এ পুনঃনির্দেশ করুন:

redirect_with_message(
    'register.php',
    'The activation link is not valid, please register again.',
    FLASH_ERROR
);

এই টিউটোরিয়ালে, আপনি শিখেছেন কিভাবে পিএইচপি-তে ব্যবহারকারীর অ্যাকাউন্টের জন্য ইমেল যাচাইকরণ বাস্তবায়ন করতে হয়।

Leave a Comment

Share this Doc

PHP ইমেল যাচাইকরণ (Email verification)

Or copy link

CONTENTS

Subscribe

×
Cancel