prepare('INSERT INTO rate_limit_attempts (bucket) VALUES (?)')->execute([$bucket]); // Opportunistic cleanup so the table doesn't grow unbounded; scoped to // this bucket to keep each call cheap. $pdo->prepare('DELETE FROM rate_limit_attempts WHERE bucket = ? AND created_at < DATE_SUB(NOW(), INTERVAL ? SECOND)') ->execute([$bucket, $windowSeconds]); $stmt = $pdo->prepare( 'SELECT COUNT(*) FROM rate_limit_attempts WHERE bucket = ? AND created_at >= DATE_SUB(NOW(), INTERVAL ? SECOND)' ); $stmt->execute([$bucket, $windowSeconds]); return (int)$stmt->fetchColumn() <= $maxAttempts; }