Kotchasan Framework Documentation

Kotchasan Framework Documentation

Authentication and Security Management

EN 05 Feb 2026 06:50

Authentication and Security Management

Kotchasan Framework provides a comprehensive authentication and security management system that supports multiple authentication methods and protects against various security threats.

Table of Contents

  1. Login Class - Login Management
  2. Password Class - Password and Encryption Management
  3. Session Class - Session Management
  4. JWT Middleware - JWT Authentication
  5. AuthFactory - Authentication Factory
  6. CSRF Protection
  7. Real-world Usage Examples

Login Class - Login Management

Using Login Class

use Kotchasan\Login;
use Kotchasan\Http\Request;

// Create Login instance
$request = new Request();
$login = Login::create($request);

// Check login status
$user = Login::isMember();
if ($user) {
    echo "User: " . $user['username'];
} else {
    echo "Not logged in";
}

// Check Admin privileges
$admin = Login::isAdmin();
if ($admin) {
    echo "Has Admin privileges";
}

Setting up Login System

class CustomLogin extends Login
{
    /**
     * Check login credentials against database
     */
    public function checkLogin($loginParams)
    {
        // Check username
        $user = $this->db()
            ->select()
            ->from('users')
            ->where(['username', $loginParams['username']])
            ->first();

        if (!$user) {
            self::$login_input = 'username';
            return 'User not found';
        }

        // Check password
        if (!password_verify($loginParams['password'], $user->password)) {
            self::$login_input = 'password';
            return 'Invalid password';
        }

        // Check user status
        if ($user->status == 0) {
            return 'Account is suspended';
        }

        // Update last login information
        $this->db()->update('users')
            ->set([
                'last_login' => date('Y-m-d H:i:s'),
                'login_ip' => $_SERVER['REMOTE_ADDR']
            ])
            ->where(['id', $user->id])
            ->execute();

        // Return user information
        return [
            'id' => $user->id,
            'username' => $user->username,
            'email' => $user->email,
            'name' => $user->name,
            'status' => $user->status,
            'permissions' => explode(',', $user->permissions)
        ];
    }

    /**
     * Logout functionality
     */
    public function logout(Request $request)
    {
        // Clear session data
        $key = static::sessionKey();
        unset($_SESSION[$key]);

        // Clear remember me cookie if exists
        if (isset($_COOKIE['remember_me'])) {
            setcookie('remember_me', '', time() - 3600, '/');
        }

        // Log logout activity
        $this->logActivity('logout');

        self::$login_message = 'Logout successful';
        self::$login_params = [];
    }

    /**
     * Password reset functionality
     */
    public function forgot(Request $request)
    {
        $email = $request->post('email')->email();

        if (empty($email)) {
            self::$login_message = 'Please enter email address';
            return;
        }

        // Check email in system
        $user = $this->db()
            ->select()
            ->from('users')
            ->where(['email', $email])
            ->first();

        if (!$user) {
            self::$login_message = 'Email not found in system';
            return;
        }

        // Generate reset token
        $resetToken = Password::uniqid(32);
        $expiry = date('Y-m-d H:i:s', strtotime('+1 hour'));

        // Save reset token
        $this->db()->update('users')
            ->set([
                'reset_token' => $resetToken,
                'reset_expires' => $expiry
            ])
            ->where(['id', $user->id])
            ->execute();

        // Send reset email
        $this->sendResetEmail($user, $resetToken);

        self::$login_message = 'Password reset link sent to your email';
    }
}

Permission Checking

// Check specific permissions
$user = Login::isMember();
$hasPermission = Login::checkStatus($user, [1, 2, 3]); // Allowed statuses

// Usage in Controller
class AdminController
{
    public function index()
    {
        // Check Admin privileges
        $admin = Login::isAdmin();
        if (!$admin) {
            // Redirect to login page
            header('Location: /login');
            exit;
        }

        // Show Admin page
        return $this->view->render('admin/dashboard', [
            'user' => $admin
        ]);
    }

    public function users()
    {
        // Check specific permissions
        $user = Login::isMember();
        if (!Login::checkStatus($user, [1, 2])) { // Admin and Manager
            throw new \Exception('Access denied');
        }

        // Show user list
        return $this->userService->getUsers();
    }
}

Password Class - Password and Encryption Management

Data Encryption and Decryption

use Kotchasan\Password;

// Data encryption
$data = "secret data";
$secretKey = "my-secret-key";
$encrypted = Password::encode($data, $secretKey);

// Data decryption
try {
    $decrypted = Password::decode($encrypted, $secretKey);
    echo $decrypted; // "secret data"
} catch (Exception $e) {
    echo "Decryption failed: " . $e->getMessage();
}

// Password hashing
$password = "user-password123";
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);

// Password verification
if (password_verify($password, $hashedPassword)) {
    echo "Password is correct";
}

Token Generation and API Signature

// Generate unique ID
$shortId = Password::uniqid(8);     // 8 characters
$longId = Password::uniqid(32);     // 32 characters
$defaultId = Password::uniqid();    // 13 characters (default)

// Generate API signature
$apiParams = [
    'user_id' => 123,
    'action' => 'get_data',
    'timestamp' => time()
];
$apiSecret = 'api-secret-key';
$signature = Password::generateSign($apiParams, $apiSecret);

// Validate API signature
function validateApiSignature($params, $receivedSignature, $secret)
{
    $expectedSignature = Password::generateSign($params, $secret);
    return hash_equals($expectedSignature, $receivedSignature);
}

Real-world Usage

class UserService
{
    /**
     * Create new user account
     */
    public function createUser($userData)
    {
        // Hash password
        $userData['password'] = password_hash($userData['password'], PASSWORD_DEFAULT);

        // Generate activation token
        $userData['activation_token'] = Password::uniqid(32);
        $userData['created_at'] = date('Y-m-d H:i:s');

        // Save new user
        $userId = $this->db()->insert('users')->values($userData)->execute();

        // Send activation email
        $this->sendActivationEmail($userData);

        return $userId;
    }

    /**
     * Change password
     */
    public function changePassword($userId, $oldPassword, $newPassword)
    {
        // Get user data
        $user = $this->db()->select()->from('users')->where(['id', $userId])->first();

        // Verify old password
        if (!password_verify($oldPassword, $user->password)) {
            throw new \Exception('Old password is incorrect');
        }

        // Check new password strength
        if (strlen($newPassword) < 8) {
            throw new \Exception('Password must be at least 8 characters');
        }

        // Hash new password
        $hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);

        // Update password
        $this->db()->update('users')
            ->set(['password' => $hashedPassword, 'password_changed_at' => date('Y-m-d H:i:s')])
            ->where(['id', $userId])
            ->execute();

        return true;
    }
}

Session Class - Session Management

Database-based Session Setup

use Kotchasan\Session;

// Use database-based sessions
$session = new Session();

// Create session table
$session->createTable();

// Set session handler
session_set_save_handler(
    [$session, '_open'],
    [$session, '_close'],
    [$session, '_read'],
    [$session, '_write'],
    [$session, '_destroy'],
    [$session, '_gc']
);

// Start session
session_start();

Session Usage

// Store data in session
$session = new Session();
$session->setSession('user_id', 123);
$session->setSession('username', 'john_doe');
$session->setSession('cart', ['item1', 'item2']);

// Retrieve data from session
$userId = $session->session('user_id');
$username = $session->session('username', 'anonymous');
$cart = $session->session('cart', []);

// Standard usage
$_SESSION['custom_data'] = 'some value';
$customData = $_SESSION['custom_data'] ?? 'default';

Secure Session Configuration

// Secure session settings
ini_set('session.use_only_cookies', 1);
ini_set('session.use_strict_mode', 1);
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1); // HTTPS only
ini_set('session.cookie_samesite', 'Lax');

// Session cookie parameters
session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'domain' => '',
    'secure' => true,    // HTTPS only
    'httponly' => true,  // XSS protection
    'samesite' => 'Lax'  // CSRF protection
]);

// Regenerate session ID
function regenerateSessionId()
{
    if (session_status() === PHP_SESSION_ACTIVE) {
        session_regenerate_id(true);
    }
}

// Check session expiration
$maxLifetime = 360; // 0)
{
    if (isset($_SESSION['last_activity'])) {
        if (time() - $_SESSION['last_activity'] > $maxLifetime) {
            session_destroy();
            return false;
        }
    }
    $_SESSION['last_activity'] = time();
    return true;
}

JWT Middleware - JWT Authentication

Using JWT Middleware

use Kotchasan\Http\Middleware\JwtMiddleware;

// Create JWT Middleware
$secretKey = 'your-secret-key-here';
$jwtMiddleware = new JwtMiddleware($secretKey);

// Set options
$options = [
    'algorithm' => 'HS256',
    'tokenParam' => 'token',    // Accept token from query parameter
    'required' => true          // Token is required
];
$jwtMiddleware = new JwtMiddleware($secretKey, $options);

// Usage in Controller
class ApiController
{
    public function getData(Request $request)
    {
        $jwt = new JwtMiddleware('secret-key');
        $response = $jwt->handle($request);

        if ($response instanceof Response) {
            // Invalid token
            return $response;
        }

        // Get user data from token
        $userId = $request->getAttribute('authenticated_user');
        $payload = $request->getAttribute('jwt_payload');

        return [
            'user_id' => $userId,
            'data' => $this->getUserData($userId)
        ];
    }
}

Creating and Validating JWT Tokens

// Create JWT Token
$jwt = new JwtMiddleware('secret-key');

// Create token with user ID
$token = $jwt->generateToken(123, 3600); // user ID = 123, expires in 1 hour

// Create token with custom payload
$payload = [
    'user_id' => 123,
    'username' => 'john_doe',
    'role' => 'admin',
    'permissions' => ['read', 'write', 'delete']
];
$token = $jwt->generateToken($payload, 7200); // expires in 2 hours

// Decode JWT Token
try {
    $decoded = $jwt->decodeToken($token);
    echo "User ID: " . $decoded['sub'];
    echo "Expires: " . date('Y-m-d H:i:s', $decoded['exp']);
} catch (Exception $e) {
    echo "Invalid token: " . $e->getMessage();
}

Using JWT in API System

class AuthApiController
{
    /**
     * Login and create JWT token
     */
    public function login(Request $request)
    {
        $username = $request->post('username')->username();
        $password = $request->post('password')->password();

        // Validate login credentials
        $user = $this->validateLogin($username, $password);
        if (!$user) {
            return Response::makeUnauthorized(['error' => 'Invalid credentials']);
        }

        // Create JWT token
        $jwt = new JwtMiddleware(self::$cfg->jwt_secret);
        $payload = [
            'sub' => $user['id'],
            'username' => $user['username'],
            'role' => $user['role'],
            'iat' => time(),
            'exp' => time() + 3600 // expires in 1 hour
        ];

        $accessToken = $jwt->generateToken($payload);
        $refreshToken = Password::uniqid(40);

        // Save refresh token
        $this->saveRefreshToken($user['id'], $refreshToken);

        return Response::makeOk([
            'access_token' => $accessToken,
            'refresh_token' => $refreshToken,
            'token_type' => 'Bearer',
            'expires_in' => 3600
        ]);
    }

    /**
     * Refresh JWT token
     */
    public function refreshToken(Request $request)
    {
        $refreshToken = $request->post('refresh_token')->toString();

        // Validate refresh token
        $user = $this->validateRefreshToken($refreshToken);
        if (!$user) {
            return Response::makeUnauthorized(['error' => 'Invalid refresh token']);
        }

        // Create new access token
        $jwt = new JwtMiddleware(self::$cfg->jwt_secret);
        $newAccessToken = $jwt->generateToken([
            'sub' => $user['id'],
            'username' => $user['username'],
            'role' => $user['role']
        ], 3600);

        // Create new refresh token
        $newRefreshToken = Password::uniqid(40);
        $this->updateRefreshToken($user['id'], $newRefreshToken);

        return Response::makeOk([
            'access_token' => $newAccessToken,
            'refresh_token' => $newRefreshToken,
            'token_type' => 'Bearer',
            'expires_in' => 3600
        ]);
    }
}

AuthFactory - Authentication Factory

Using AuthFactory

use Kotchasan\Http\Auth\AuthFactory;

// Password management
$password = 'user-password123';
$hashedPassword = AuthFactory::hashPassword($password);
$isValid = AuthFactory::verifyPassword($password, $hashedPassword);

// Generate random token
$token = AuthFactory::generateToken(32); // 32 characters
$shortToken = AuthFactory::generateToken(16); // 16 characters

// Create and validate JWT token
$payload = ['user_id' => 123, 'role' => 'admin'];
$secretKey = 'jwt-secret-key';
$jwtToken = AuthFactory::createJwtToken($payload, $secretKey);
$decodedPayload = AuthFactory::validateJwtToken($jwtToken, $secretKey);

Creating Authentication Middleware

// Basic Authentication
$basicAuth = AuthFactory::createBasicAuth(function($username, $password) {
    // Validate username and password
    return $this->validateUser($username, $password);
}, 'Admin Area');

// JWT Authentication
$jwtAuth = AuthFactory::createJwtAuth('secret-key', 'HS256');

// Bearer Token Authentication
$bearerAuth = AuthFactory::createBearerTokenAuth(function($token) {
    // Validate bearer token
    return $this->validateBearerToken($token);
});

// Digest Authentication
$digestAuth = AuthFactory::createDigestAuth(function($username) {
    // Return password hash for username
    return $this->getUserPasswordHash($username);
}, 'Secure Area');

// Authorization (Role-based)
$authorization = AuthFactory::createAuthorization(['admin', 'manager']);

Secure Hash Comparison

// Secure hash comparison preventing timing attacks
$hash1 = hash('sha256', 'data1');
$hash2 = hash('sha256', 'data2');

// Insecure way
if ($hash1 === $hash2) {
    // Vulnerable to timing attacks
}

// Secure way
if (AuthFactory::compareHashes($hash1, $hash2)) {
    // Protected against timing attacks
}

CSRF Protection

Using CSRF Protection

// Generate CSRF token
$csrfToken = AuthFactory::generateCsrfToken();
$customToken = AuthFactory::generateCsrfToken('custom_csrf_key');

// Validate CSRF token
$isValid = AuthFactory::validateCsrfToken($_POST['csrf_token']);
$customIsValid = AuthFactory::validateCsrfToken($_POST['custom_token'], 'custom_csrf_key');

// Use in forms
echo '<input type="hidden" name="csrf_token" value="' . htmlspecialchars($csrfToken) . '">';

CSRF Protection in Controllers

class FormController
{
    public function showForm()
    {
        // Generate CSRF token for form
        $csrfToken = AuthFactory::generateCsrfToken();

        return $this->view->render('form', [
            'csrf_token' => $csrfToken
        ]);
    }

    public function processForm(Request $request)
    {
        // Validate CSRF token
        $token = $request->post('csrf_token')->toString();
        if (!AuthFactory::validateCsrfToken($token)) {
            return Response::makeForbidden(['error' => 'Invalid CSRF token']);
        }

        // Process form
        $data = [
            'name' => $request->post('name')->toString(),
            'email' => $request->post('email')->email()
        ];

        $result = $this->processData($data);

        return Response::makeOk(['message' => 'Form processed successfully']);
    }
}

CSRF Protection for APIs

class ApiCsrfController
{
    /**
     * Get CSRF token for SPA/AJAX
     */
    public function getCsrfToken(Request $request)
    {
        $token = AuthFactory::generateCsrfToken('api_csrf_token');

        return Response::makeOk([
            'csrf_token' => $token,
            'expires_in' => 3600
        ]);
    }

    /*
     * Validate CSRF token in API calls
     */
    public function validateApiCsrf(Request $request)
    {
        $token = $request->getHeaderLine('X-CSRF-Token')
               ?: $request->post('csrf_token')->toString();

        if (!AuthFactory::validateCsrfToken($token, 'api_csrf_token')) {
            return Response::makeForbidden([
                'error' => 'CSRF token validation failed',
                'code' => 'INVALID_CSRF_TOKEN'
            ]);
        }

        return null; // Validation passed
    }
}

Real-world Usage Examples

Comprehensive Authentication System

use Kotchasan\Database;

class AuthenticationSystem
{
    private $db;
    private $jwtSecret;

    public function __construct()
    {
        $this->db = Kotchasan\Database::create();
        $this->jwtSecret = Config::get('jwt_secret');
    }

    /**
     * Comprehensive login system
     */
    public function login(Request $request)
    {
        try {
            // Validate CSRF token
            $csrfToken = $request->post('csrf_token')->toString();
            if (!AuthFactory::validateCsrfToken($csrfToken)) {
                return $this->errorResponse('Invalid CSRF token', 403);
            }

            // Check rate limiting
            $clientIp = $request->server('REMOTE_ADDR');
            if (!$this->checkRateLimit($clientIp, 'login', 5, 300)) {
                return $this->errorResponse('Too many login attempts', 429);
            }

            $username = $request->post('username')->username();
            $password = $request->post('password')->password();
            $rememberMe = $request->post('remember_me')->toBool();

            // Validate credentials
            $user = $this->validateCredentials($username, $password);
            if (!$user) {
                $this->logFailedLogin($username, $clientIp);
                return $this->errorResponse('Invalid credentials', 401);
            }

            // Check account status
            if ($user['status'] !== 'active') {
                return $this->errorResponse('Account is not active', 403);
            }

            // Create session
            session_regenerate_id(true);
            $_SESSION['user'] = [
                'id' => $user['id'],
                'username' => $user['username'],
                'role' => $user['role'],
                'login_time' => time()
            ];

            // Create JWT token
            $jwtToken = null;
            if ($request->post('api_access')->toBool()) {
                $jwt = new JwtMiddleware($this->jwtSecret);
                $jwtToken = $jwt->generateToken([
                    'sub' => $user['id'],
                    'username' => $user['username'],
                    'role' => $user['role']
                ], 3600);
            }

            // Handle Remember Me
            if ($rememberMe) {
                $this->setRememberMeCookie($user['id']);
            }

            // Log successful login
            $this->logSuccessfulLogin($user['id'], $clientIp);

            return $this->successResponse([
                'message' => 'Login successful',
                'user' => [
                    'id' => $user['id'],
                    'username' => $user['username'],
                    'role' => $user['role']
                ],
                'jwt_token' => $jwtToken,
                'csrf_token' => AuthFactory::generateCsrfToken()
            ]);

        } catch (Exception $e) {
            return $this->errorResponse('Login failed: ' . $e->getMessage(), 500);
        }
    }

    /**
     * Validate credentials
     */
    private function validateCredentials($username, $password)
    {
        // Find user
        $user = $this->db->select()
            ->from('users')
            ->where(['username', $username])
            ->orWhere(['email', $username])
            ->first();

        if (!$user) {
            return false;
        }

        // Verify password
        if (!AuthFactory::verifyPassword($password, $user->password)) {
            return false;
        }

        return $user->toArray();
    }

    /**
     * Handle Remember Me Cookie
     */
    private function setRememberMeCookie($userId)
    {
        $token = AuthFactory::generateToken(32);
        $expires = time() + (30  24  60  60); // 30 days

        // Save remember token in database
        $this->db->insert('remember_tokens')
            ->values([
                'user_id' => $userId,
                'token' => hash('sha256', $token),
                'expires_at' => date('Y-m-d H:i:s', $expires),
                'created_at' => date('Y-m-d H:i:s')
            ])
            ->execute();

        // Set cookie
        setcookie('remember_me', $token, $expires, '/', '', true, true);
    }

    /**
     * Check Rate Limiting
     */
    private function checkRateLimit($identifier, $action, $limit, $window)
    {
        $key = "rate_limit:{$action}:{$identifier}";
        $attempts = $_SESSION[$key] ?? [];

        // Remove old attempts
        $cutoff = time() - $window;
        $attempts = array_filter($attempts, function($time) use ($cutoff) {
            return $time > $cutoff;
        });

        // Check limit
        if (count($attempts) >= $limit) {
            return false;
        }

        // Record new attempt
        $attempts[] = time();
        $_SESSION[$key] = $attempts;

        return true;
    }

    /**
     * Log successful login
     */
    private function logSuccessfulLogin($userId, $ip)
    {
        $this->db->insert('login_logs')
            ->values([
                'user_id' => $userId,
                'ip_address' => $ip,
                'status' => 'success',
                'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
                'created_at' => date('Y-m-d H:i:s')
            ])
            ->execute();
    }

    /**
     * Log failed login
     */
    private function logFailedLogin($username, $ip)
    {
        $this->db->insert('login_logs')
            ->values([
                'username' => $username,
                'ip_address' => $ip,
                'status' => 'failed',
                'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
                'created_at' => date('Y-m-d H:i:s')
            ])
            ->execute();
    }
}

Multi-layered Security System

class SecuritySystem
{
    /**
     * Comprehensive security middleware
     */
    public function securityMiddleware(Request $request, callable $next)
    {
        // 1. Validate IP access (whitelist/blacklist)
        if (!$this->validateIpAccess($request->server('REMOTE_ADDR'))) {
            return Response::makeForbidden(['error' => 'IP not allowed']);
        }

        // 2. Validate User Agent
        if (!$this->validateUserAgent($request->server('HTTP_USER_AGENT'))) {
            return Response::makeForbidden(['error' => 'Invalid user agent']);
        }

        // 3. Validate Referer for state-changing requests
        if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
            if (!$this->validateReferer($request)) {
                return Response::makeForbidden(['error' => 'Invalid referer']);
            }
        }

        // 4. Validate CSRF token for state-changing requests
        if ($request->isMethod('POST')) {
            $csrfToken = $request->getHeaderLine('X-CSRF-Token')
                      ?: $request->post('csrf_token')->toString();
            if (!AuthFactory::validateCsrfToken($csrfToken)) {
                return Response::makeForbidden(['error' => 'CSRF validation failed']);
            }
        }

        // 5. Validate JWT token for API requests
        if (strpos($request->getHeaderLine('Accept'), 'application/json') !== false) {
            $jwt = new JwtMiddleware(Config::get('jwt_secret'));
            $response = $jwt->handle($request);
            if ($response instanceof Response) {
                return $response;
            }
        }

        // 6. Check permissions
        $user = $request->getAttribute('authenticated_user');
        if (!$this->hasPermission($user, $request)) {
            return Response::makeForbidden(['error' => 'Insufficient permissions']);
        }

        // 7. Rate limiting
        if (!$this->checkGlobalRateLimit($request)) {
            return Response::make(['error' => 'Rate limit exceeded'], 429);
        }

        // All checks passed
        return $next($request);
    }

    /**
     * Check access permissions
     */
    private function hasPermission($userId, Request $request)
    {
        if (!$userId) {
            return false; // Must be logged in
        }

        $route = $request->getAttribute('route');
        $action = $request->getMethod() . ' ' . $route;

        // Check permissions from database
        $hasPermission = $this->db->select('COUNT()')
            ->from('user_permissions')
            ->where(['user_id', $userId])
            ->where(['permission', $action])
            ->where(['status', 'active'])
            ->value();

        return $hasPermission > 0;
    }

    /**
     * Validate IP access
     */
    private function validateIpAccess($clientIp)
    {
        // Check IP blacklist
        $blacklisted = $this->db->select('COUNT()')
            ->from('ip_blacklist')
            ->where(['ip_address', $clientIp])
            ->where(['status', 'active'])
            ->value();

        if ($blacklisted > 0) {
            return false;
        }

        // Check IP whitelist (if any)
        $whitelistCount = $this->db->select('COUNT()')
            ->from('ip_whitelist')
            ->where(['status', 'active'])
            ->value();

        if ($whitelistCount > 0) {
            $whitelisted = $this->db->select('COUNT()')
                ->from('ip_whitelist')
                ->where(['ip_address', $clientIp])
                ->where(['status', 'active'])
                ->value();

            return $whitelisted > 0;
        }

        return true;
    }

    /**
     * Brute Force Attack Prevention
     */
    public function bruteForcePrevention($identifier, $action, $maxAttempts = 5, $blockTime = 300)
    {
        $key = "brute_force:{$action}:{$identifier}";
        $data = $_SESSION[$key] ?? ['attempts' => 0, 'last_attempt' => 0];

        // Check if blocked
        if ($data['attempts'] >= $maxAttempts) {
            $timeSinceBlock = time() - $data['last_attempt'];
            if ($timeSinceBlock < $blockTime) {
                $remainingTime = $blockTime - $timeSinceBlock;
                throw new \Exception("Account blocked. Try again in {$remainingTime} seconds.");
            } else {
                // Block time expired, reset counter
                $data = ['attempts' => 0, 'last_attempt' => 0];
            }
        }

        // Increment attempt counter
        $data['attempts']++;
        $data['last_attempt'] = time();
        $_SESSION[$key] = $data;

        return $data['attempts'];
    }
}

Kotchasan Framework provides a comprehensive authentication and security management system that supports the development of secure and high-performance applications with protection against various security threats.