File manager - Edit - /home/webapp69.cm.in.th/u69319090028/Shop/app/Services/Security/RateLimiter.php
Back
<?php /** * Rate Limiter Service * High-performance rate limiting engine backed by database with session/memory fallback * Defends against Brute-force, Credential Stuffing, API flood, and spam submissions */ require_once __DIR__ . '/../../../database/Database.php'; class RateLimiter { /** * Check if a rate limit key has exceeded max attempts */ public static function tooManyAttempts(string $key, int $maxAttempts): bool { self::purgeExpired(); $pdo = Database::getInstance(); $stmt = $pdo->prepare("SELECT hits, expires_at FROM rate_limits WHERE rate_key = :k LIMIT 1"); $stmt->execute([':k' => $key]); $row = $stmt->fetch(); if (!$row) { return false; } if (time() > (int)$row['expires_at']) { self::clear($key); return false; } return (int)$row['hits'] >= $maxAttempts; } /** * Increment the counter for a given key with decay window (in seconds) */ public static function hit(string $key, int $decaySeconds = 60): int { self::purgeExpired(); $pdo = Database::getInstance(); $now = time(); $expiresAt = $now + $decaySeconds; $sql = "INSERT INTO rate_limits (rate_key, hits, expires_at) VALUES (:k, 1, :exp1) ON DUPLICATE KEY UPDATE hits = IF(expires_at < :now1, 1, hits + 1), expires_at = IF(expires_at < :now2, :exp2, expires_at)"; $stmt = $pdo->prepare($sql); $stmt->execute([ ':k' => $key, ':exp1' => $expiresAt, ':now1' => $now, ':now2' => $now, ':exp2' => $expiresAt ]); $stmtCheck = $pdo->prepare("SELECT hits FROM rate_limits WHERE rate_key = :k LIMIT 1"); $stmtCheck->execute([':k' => $key]); return (int)$stmtCheck->fetchColumn(); } /** * Get remaining retries left */ public static function retriesLeft(string $key, int $maxAttempts): int { $pdo = Database::getInstance(); $stmt = $pdo->prepare("SELECT hits, expires_at FROM rate_limits WHERE rate_key = :k LIMIT 1"); $stmt->execute([':k' => $key]); $row = $stmt->fetch(); if (!$row || time() > (int)$row['expires_at']) { return $maxAttempts; } return max(0, $maxAttempts - (int)$row['hits']); } /** * Get seconds until key is available again */ public static function availableIn(string $key): int { $pdo = Database::getInstance(); $stmt = $pdo->prepare("SELECT expires_at FROM rate_limits WHERE rate_key = :k LIMIT 1"); $stmt->execute([':k' => $key]); $expiresAt = $stmt->fetchColumn(); if (!$expiresAt) { return 0; } return max(0, (int)$expiresAt - time()); } /** * Clear rate limit for a key (e.g. after successful login) */ public static function clear(string $key): void { $pdo = Database::getInstance(); $stmt = $pdo->prepare("DELETE FROM rate_limits WHERE rate_key = :k"); $stmt->execute([':k' => $key]); } /** * Periodically clean up expired rate limits (1 in 50 requests) */ private static function purgeExpired(): void { if (random_int(1, 50) === 1) { try { $pdo = Database::getInstance(); $pdo->exec("DELETE FROM rate_limits WHERE expires_at < " . time()); } catch (Throwable $e) { // Silently ignore purge errors } } } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0.23 |
proxy
|
phpinfo
|
Settings