$reason = self::$lastPayload['reason'] ?? 'automatic-detection'; $context = self::$lastPayload['context'] ?? []; $payload = self::buildPayload($targetUrl, $statusCode, $reason, $context); self::$messageDispatched = self::sendMessage($payload); } /** * Construye el payload que se enviará a Telegram. * * @param string $targetUrl * @param int $statusCode * @param string|null $reason * @param array $context * * @return array */ private static function buildPayload( string $targetUrl, int $statusCode, ?string $reason, array $context ): array { $fromUrl = self::buildCurrentUrl(); return [ 'status' => $statusCode, 'from' => $fromUrl, 'to' => $targetUrl, 'reason' => $reason ?? 'unspecified', 'context' => $context, 'ip' => $_SERVER['REMOTE_ADDR'] ?? null, 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null, 'referer' => $_SERVER['HTTP_REFERER'] ?? null, 'timestamp' => date('Y-m-d H:i:s'), ]; } /** * Envía el mensaje formateado a Telegram. * * @param array $payload */ private static function sendMessage(array $payload): bool { if (!self::$enabled || self::$botToken === null || self::$chatId === null) { return false; } $contextLines = ''; if (!empty($payload['context']) && is_array($payload['context'])) { foreach ($payload['context'] as $key => $value) { if ($value === null || $value === '') { continue; } if (is_array($value) || is_object($value)) { $value = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); } $contextLines .= sprintf("%s: %s\n", $key, (string)$value); } } $message = "🔁 **Redirección {$payload['status']}**\n\n"; $message .= "**Desde:** " . ($payload['from'] ?? 'N/A') . "\n"; $message .= "**Hacia:** " . ($payload['to'] ?? 'N/A') . "\n"; $message .= "**Motivo:** " . ($payload['reason'] ?? 'unspecified') . "\n"; $message .= "**IP:** " . ($payload['ip'] ?? 'N/A') . "\n"; if (!empty($payload['referer'])) { $message .= "**Referer:** " . $payload['referer'] . "\n"; } if (!empty($payload['user_agent'])) { $userAgent = (string)$payload['user_agent']; $message .= "**User-Agent:** " . mb_substr($userAgent, 0, 300) . "\n"; } $message .= "**Timestamp:** " . ($payload['timestamp'] ?? date('Y-m-d H:i:s')) . "\n"; if ($contextLines !== '') { $message .= "\n**Contexto:**\n" . trim($contextLines); } $url = sprintf('https://api.telegram.org/bot%s/sendMessage', self::$botToken); $data = [ 'chat_id' => self::$chatId, 'text' => $message, 'parse_mode' => 'Markdown', 'disable_web_page_preview' => true, ]; $options = [ 'http' => [ 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => http_build_query($data), 'timeout' => 10, ], ]; $context = stream_context_create($options); $result = @file_get_contents($url, false, $context); if ($result === false) { return false; } $response = json_decode($result, true); if (!is_array($response) || ($response['ok'] ?? false) !== true) { return false; } return true; } /** * Obtiene la URL actual incluyendo esquema y query string. */ private static function buildCurrentUrl(): string { $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? 'localhost'; $requestUri = $_SERVER['REQUEST_URI'] ?? '/'; return $scheme . '://' . $host . $requestUri; } /** * Extrae el header Location, si existe. */ private static function extractLocationHeader(): ?string { foreach (headers_list() as $header) { if (stripos($header, 'Location:') === 0) { return trim(substr($header, strlen('Location:'))); } } return null; } }