STRIKE_TIMEOUT) { $strikes = 0; } } $strikes++; @file_put_contents($strike_file, $strikes . '|' . time()); $log_entry = sprintf( "[%s] IP: %s | Strike: %d | Path: %s | UA: %s\n", $timestamp, substr($ip, 0, 100), $strikes, substr($path, 0, 100), substr($user_agent, 0, 100) ); @file_put_contents(LOG_FILE, $log_entry, FILE_APPEND); // Response based on strikes if ($strikes === 1) { showSilent($ip, $path, $strikes); } elseif ($strikes === 2) { showWarning($ip, $path, $strikes); } else { showBan($ip, $path, $strikes); } // --- Template rendering --- function renderTemplate($file, array $vars = []) { if (!is_readable($file)) { http_response_code(500); exit('Template error'); } $html = file_get_contents($file); foreach ($vars as $key => $value) { $html = str_replace('{{' . strtoupper($key) . '}}', htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'), $html); } header('Content-Type: text/html; charset=utf-8'); echo $html; exit; } function showSilent($ip, $path, $strikes) { http_response_code(404); renderTemplate(TEMPLATE_DIR . '/silent404.html'); } function showWarning($ip, $path, $strikes) { http_response_code(403); renderTemplate(TEMPLATE_DIR . '/warning.html', ['strikes' => $strikes]); } function showBan($ip, $path, $strikes) { http_response_code(403); renderTemplate(TEMPLATE_DIR . '/ban.html', ['incident' => md5($ip . time())]); } ?>