['requests' => 5, 'window' => 60], // 5 محاولات / دقيقة 'otp' => ['requests' => 3, 'window' => 300], // 3 محاولات / 5 دقائق 'register' => ['requests' => 3, 'window' => 3600], // 3 محاولات / ساعة 'api' => ['requests' => 120, 'window' => 60], // 120 طلب / دقيقة 'ride' => ['requests' => 30, 'window' => 60], // 30 طلب / دقيقة 'upload' => ['requests' => 10, 'window' => 300], // 10 رفع / 5 دقائق ]; public function __construct(?Redis $redis) { $this->redis = $redis; } // ── فحص الحد ───────────────────────────────────────────── // $identifier: IP:userId أو IP فقط // $type: login | otp | api | ride | upload public function check(string $identifier, string $type = 'api'): bool { if (!$this->redis) { return true; // بدون Redis نمرر (fallback) } $limit = self::LIMITS[$type] ?? self::LIMITS['api']; $window = $limit['window']; $max = $limit['requests']; $key = "rate:{$type}:{$identifier}"; $current = $this->redis->incr($key); if ($current === 1) { $this->redis->expire($key, $window); } return $current <= $max; } // ── تطبيق الحد وإيقاف الطلب إن تجاوز ───────────────────── public function enforce(string $identifier, string $type = 'api'): void { if (!$this->check($identifier, $type)) { $limit = self::LIMITS[$type] ?? self::LIMITS['api']; $window = $limit['window']; error_log("[RATE_LIMIT] Blocked: $identifier | type: $type"); http_response_code(429); header("Retry-After: $window"); echo json_encode([ 'error' => 'Too many requests. Please slow down.', 'retry_after' => $window, ]); exit; } } // ── بناء معرّف المستخدم ──────────────────────────────────── public static function identifier(?string $userId = null): string { $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown'; return $userId ? "{$ip}:{$userId}" : $ip; } // ── إعادة تعيين عداد (مثلاً بعد تسجيل دخول ناجح) ─────────── public function reset(string $identifier, string $type = 'login'): void { if ($this->redis) { $this->redis->del("rate:{$type}:{$identifier}"); } } }