ip(); $ua = strtolower($request->userAgent() ?? ''); $path = $request->path(); // Skip paths foreach (self::SKIP_PATHS as $skip) { if (str_starts_with('/' . $path, $skip)) { return $next($request); } } // Güvenilir IP (Google vb.) — tüm kontrolleri atla foreach (self::TRUSTED_IP_PREFIXES as $prefix) { if (str_starts_with($ip, $prefix)) { return $next($request); } } // Manuel engelli IP kontrolü if ($this->isBlockedIp($ip)) { $this->logBot($ip, $request->userAgent(), '/' . $path, $request->method(), 'ip_blocked', 'blocked_ip'); return response('Erişim engellendi.', 403); } // UA boşsa bot olarak işaretle if (empty($ua)) { $request->attributes->set('is_bot', true); $request->attributes->set('bot_type', 'noua'); $this->logBot($ip, '', '/' . $path, $request->method(), 'allowed', 'no_ua'); return $next($request); } // Kötü bot mu? foreach (self::BAD_BOTS as $pattern) { if (str_contains($ua, $pattern)) { $this->logBot($ip, $request->userAgent(), '/' . $path, $request->method(), 'blocked', $pattern); return response('', 403); } } // İyi bot mu? foreach (self::GOOD_BOTS as $pattern) { if (str_contains($ua, $pattern)) { $request->attributes->set('is_bot', true); $request->attributes->set('bot_type', 'good'); // İyi botlar için çok agresif rate limit (dakikada 60) if ($this->isRateLimited($ip, 60, 'good_bot')) { return response('', 429); } return $next($request); } } // Generic araç mı? foreach (self::GENERIC_BOTS as $pattern) { if (str_contains($ua, $pattern)) { $request->attributes->set('is_bot', true); $request->attributes->set('bot_type', 'generic'); if ($this->isRateLimited($ip, 10, 'generic')) { $this->logBot($ip, $request->userAgent(), '/' . $path, $request->method(), 'rate_limited', $pattern); // 30+ istek → otomatik engelle $count = Cache::get("bot_count_{$ip}", 0); if ($count > 30) { $this->autoBlock($ip, 'Otomatik: dakikada 30+ generic bot isteği'); } return response('', 429); } $this->logBot($ip, $request->userAgent(), '/' . $path, $request->method(), 'allowed', $pattern); return $next($request); } } // Normal kullanıcı — genel rate limit (dakikada 120 istek) if ($this->isRateLimited($ip, 120, 'human')) { $this->logBot($ip, $request->userAgent(), '/' . $path, $request->method(), 'rate_limited', 'human_flood'); $count = Cache::get("bot_count_{$ip}", 0); if ($count > 200) { $this->autoBlock($ip, 'Otomatik: dakikada 200+ istek flood'); } return response('', 429); } $request->attributes->set('is_bot', false); return $next($request); } private function isBlockedIp(string $ip): bool { return Cache::remember("blocked_ip_{$ip}", 300, function () use ($ip) { try { return DB::table('blocked_ips') ->where('ip', $ip) ->where(function ($q) { $q->whereNull('expires_at')->orWhere('expires_at', '>', now()); }) ->exists(); } catch (\Exception) { return false; } }); } private function isRateLimited(string $ip, int $maxPerMinute, string $type): bool { $key = "rl_{$type}_{$ip}"; $count = Cache::get($key, 0); if ($count === 0) { Cache::put($key, 1, 60); } else { Cache::increment($key); } // Bot count ayrı izle Cache::put("bot_count_{$ip}", Cache::get("bot_count_{$ip}", 0) + 1, 60); return $count >= $maxPerMinute; } private function autoBlock(string $ip, string $reason): void { try { DB::table('blocked_ips')->insertOrIgnore([ 'ip' => $ip, 'reason' => $reason, 'auto_blocked' => 1, 'blocked_at' => now(), 'expires_at' => now()->addHours(24), ]); Cache::forget("blocked_ip_{$ip}"); } catch (\Exception) {} } private function logBot(string $ip, ?string $ua, string $path, string $method, string $action, string $botName): void { try { DB::table('analytics_bot_logs')->insert([ 'ip' => $ip, 'user_agent' => mb_substr($ua ?? '', 0, 500), 'path' => mb_substr($path, 0, 500), 'method' => $method, 'action' => $action, 'bot_name' => mb_substr($botName, 0, 100), 'created_at' => now(), ]); } catch (\Exception) {} } }