Files

279 lines
12 KiB
PHP
Executable File

<?php
/**
* Webhook Principal de Telegram
* Recibe actualizaciones (mensajes, callbacks, etc.)
*/
// Habilitar logging de errores en archivo, no en salida
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/../../logs/webhook_errors.log');
require_once __DIR__ . '/../../shared/utils/helpers.php';
require_once __DIR__ . '/../../shared/database/connection.php';
// Cargar variables de entorno
if (file_exists(__DIR__ . '/../../.env')) {
$lines = file(__DIR__ . '/../../.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (strpos(trim($line), '#') === 0) continue;
if (strpos($line, '=') === false) continue;
list($key, $value) = explode('=', $line, 2);
$_ENV[trim($key)] = trim($value);
}
}
// Constantes de Telegram
define('TELEGRAM_BOT_TOKEN', $_ENV['TELEGRAM_BOT_TOKEN'] ?? getenv('TELEGRAM_BOT_TOKEN'));
define('TELEGRAM_WEBHOOK_TOKEN', $_ENV['TELEGRAM_WEBHOOK_TOKEN'] ?? getenv('TELEGRAM_WEBHOOK_TOKEN')); // Token secreto para verificar el webhook
// Función auxiliar para registrar/actualizar destinatarios en la base de datos local
function registerTelegramRecipient($db, $chatId, $chatType, $firstName = null, $lastName = null, $username = null) {
$db = getDB(); // Asegurarse de tener una conexión a DB
// Asignar un nombre si no está disponible (ej. para canales o si no hay first_name)
$name = $firstName ?: ($username ?: 'Chat/Usuario Telegram');
// Buscar si el destinatario ya existe
$stmt = $db->prepare("SELECT id FROM destinatarios_telegram WHERE telegram_id = ?");
$stmt->execute([$chatId]);
$existingRecipient = $stmt->fetch();
if (!$existingRecipient) {
// Si no existe, insertarlo
$stmt = $db->prepare(<<<'SQL'
INSERT INTO destinatarios_telegram (telegram_id, tipo, nombre, username, fecha_registro, ultima_interaccion)
VALUES (?, ?, ?, ?, NOW(), NOW())
SQL);
$stmt->execute([$chatId, $chatType, $name, $username]);
logToFile('telegram/recipients.log', "Nuevo destinatario registrado vía webhook: {$name} ({$chatId}) de tipo {$chatType}");
} else {
// Si existe, actualizar nombre y última interacción
$stmt = $db->prepare("UPDATE destinatarios_telegram SET nombre = ?, username = ?, ultima_interaccion = NOW() WHERE telegram_id = ?");
$stmt->execute([$name, $username, $chatId]);
}
}
// Función auxiliar para traducir texto
function translateTextTelegram($text, $targetLang) {
if (empty($text) || empty($targetLang) || empty(LIBRETRANSLATE_URL)) {
return $text; // No traducir si faltan datos
}
$libreTranslateUrl = $_ENV['LIBRETRANSLATE_URL'] ?? getenv('LIBRETRANSLATE_URL');
try {
$ch = curl_init($libreTranslateUrl . '/translate');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'q' => $text,
'source' => 'auto', // Detectar idioma automáticamente
'target' => $targetLang
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200 && $response) {
$translatedData = json_decode($response, true);
return $translatedData['translatedText'] ?? $text;
}
} catch (Exception $e) {
error_log("Error al traducir con LibreTranslate: " . $e->getMessage());
}
return $text; // Retornar original en caso de fallo
}
// Función para enviar mensajes a Telegram
function sendTelegramMessage($chat_id, $text, $botToken, $parseMode = null, $replyMarkup = null, $photoUrl = null) {
$telegramApiUrl = "https://api.telegram.org/bot{$botToken}/";
$method = 'sendMessage';
$postFields = [
'chat_id' => $chat_id,
];
if ($photoUrl) {
$method = 'sendPhoto';
$postFields['photo'] = $photoUrl;
$postFields['caption'] = $text;
} else {
$postFields['text'] = $text;
}
if ($parseMode) {
$postFields['parse_mode'] = $parseMode;
}
if ($replyMarkup) {
$postFields['reply_markup'] = $replyMarkup;
}
$ch = curl_init($telegramApiUrl . $method);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return ['ok' => $httpCode === 200, 'response' => json_decode($response, true), 'http_code' => $httpCode];
}
// Verificar secret token del webhook
$headers = array_change_key_case(getallheaders(), CASE_LOWER);
$secretToken = $headers['x-telegram-bot-api-secret-token'] ?? '';
if (TELEGRAM_WEBHOOK_TOKEN && $secretToken !== TELEGRAM_WEBHOOK_TOKEN) {
http_response_code(403);
error_log("Acceso no autorizado al webhook de Telegram. Token secreto inválido: {$secretToken}");
exit('Acceso no autorizado');
}
// Leer el body del request
$update = json_decode(file_get_contents('php://input'), true);
// Si no hay update, salir
if (empty($update)) {
exit;
}
$db = getDB(); // Conexión a DB para todas las operaciones
// Extraer información del usuario/chat
$chatId = $update['message']['chat']['id'] ?? $update['callback_query']['message']['chat']['id'] ?? null;
$chatType = $update['message']['chat']['type'] ?? ($update['callback_query']['message']['chat']['type'] ?? null);
$fromId = $update['message']['from']['id'] ?? $update['callback_query']['from']['id'] ?? null;
$firstName = $update['message']['from']['first_name'] ?? $update['callback_query']['from']['first_name'] ?? null;
$lastName = $update['message']['from']['last_name'] ?? $update['callback_query']['from']['last_name'] ?? null;
$username = $update['message']['from']['username'] ?? $update['callback_query']['from']['username'] ?? null;
// Registrar o actualizar destinatario que interactúa
if ($fromId && $fromId == $chatId) { // Es un mensaje directo o de un usuario
registerTelegramRecipient($db, $fromId, 'usuario', $firstName, $lastName, $username);
} elseif ($chatId && $chatType && ($chatType === 'group' || $chatType === 'supergroup' || $chatType === 'channel')) {
registerTelegramRecipient($db, $chatId, $chatType, $firstName, $lastName, $username); // Registra el chat/canal
}
// Obtener la preferencia de idioma del usuario/chat si está registrado
$userLang = 'es'; // Idioma por defecto
if ($fromId) {
$stmtLang = $db->prepare("SELECT idioma_detectado FROM destinatarios_telegram WHERE telegram_id = ? AND tipo = 'usuario'");
$stmtLang->execute([$fromId]);
$userLang = $stmtLang->fetchColumn() ?: 'es';
}
// --- Manejar Mensajes ---
if (isset($update['message'])) {
$message = $update['message'];
$text = $message['text'] ?? '';
// Detección de comandos de texto
if (strpos($text, '/') === 0) { // Podría ser un comando
$command = explode(' ', $text)[0]; // Obtener el comando principal
switch ($command) {
case '/start':
$response = "¡Hola! Soy tu bot de Telegram. ¿En qué puedo ayudarte?";
if ($userLang !== 'es') {
$response = translateTextTelegram($response, $userLang);
}
sendTelegramMessage($chatId, $response, TELEGRAM_BOT_TOKEN);
logToFile('telegram/interactions.log', "Usuario {$username} ({$fromId}) ejecutó /start.");
break;
case '/help':
$response = "Aquí tienes una lista de comandos disponibles:\n/start - Iniciar\n/help - Ver ayuda";
if ($userLang !== 'es') {
$response = translateTextTelegram($response, $userLang);
}
sendTelegramMessage($chatId, $response, TELEGRAM_BOT_TOKEN);
logToFile('telegram/interactions.log', "Usuario {$username} ({$fromId}) ejecutó /help.");
break;
// Otros comandos de texto o comandos de plantilla
default:
// Intentar buscar el comando en las plantillas
$cmdName = ltrim($command, '/');
$stmt = $db->prepare("SELECT contenido FROM plantillas_telegram WHERE comando = ?");
$stmt->execute([$cmdName]);
$plantilla = $stmt->fetch();
if ($plantilla) {
$responseContent = $plantilla['contenido'];
if ($userLang !== 'es') {
$responseContent = translateTextTelegram($responseContent, $userLang);
}
sendTelegramMessage($chatId, $responseContent, TELEGRAM_BOT_TOKEN, 'HTML'); // Asumimos HTML para plantillas
logToFile('telegram/interactions.log', "Usuario {$username} ({$fromId}) ejecutó comando de plantilla: {$command}.");
} else {
$response = "Comando `{$command}` no reconocido.";
if ($userLang !== 'es') {
$response = translateTextTelegram($response, $userLang);
}
sendTelegramMessage($chatId, $response, TELEGRAM_BOT_TOKEN);
logToFile('telegram/interactions.log', "Usuario {$username} ({$fromId}) ejecutó comando no reconocido: {$command}.");
}
break;
}
exit;
} elseif (strpos($text, '#grupo') !== false) { // Ejemplo de comando de texto no-slash
$response = "Comando de texto `#grupo` detectado. Realizando acción de grupo (placeholder).";
if ($userLang !== 'es') {
$response = translateTextTelegram($response, $userLang);
}
sendTelegramMessage($chatId, $response, TELEGRAM_BOT_TOKEN);
logToFile('telegram/interactions.log', "Usuario {$username} ({$fromId}) ejecutó comando de texto: #grupo.");
exit;
}
// Si no es un comando, y no es un chat de grupo/canal, podrías responder algo por defecto
// o simplemente no hacer nada. Aquí no haremos nada por mensajes no-comando.
logToFile('telegram/interactions.log', "Mensaje no-comando de {$username} ({$fromId}): {$text}");
}
// --- Manejar Callback Queries (Botones Inline) ---
if (isset($update['callback_query'])) {
$callbackQuery = $update['callback_query'];
$data = $callbackQuery['data'];
$messageId = $callbackQuery['message']['message_id'];
$chatId = $callbackQuery['message']['chat']['id'];
if (strpos($data, 'lang_select_') === 0) {
$langCode = substr($data, strlen('lang_select_'));
// Actualizar preferencia en BD para el usuario que presionó el botón
$stmt = $db->prepare("UPDATE destinatarios_telegram SET idioma_detectado = ? WHERE telegram_id = ? AND tipo = 'usuario'");
$stmt->execute([$langCode, $fromId]);
// Responder a la callback query (quitar el "cargando..." del botón)
$telegramApiUrl = "https://api.telegram.org/bot{$botToken}/answerCallbackQuery";
$ch = curl_init($telegramApiUrl);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'callback_query_id' => $callbackQuery['id'],
'text' => "Idioma cambiado a {$langCode}."
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
// Opcional: Editar el mensaje original para mostrar la nueva preferencia
// sendTelegramMessage($chatId, "Tu idioma ha sido configurado a **{$langCode}**", TELEGRAM_BOT_TOKEN, 'Markdown', null, null, $messageId);
logToFile('telegram/interactions.log', "Usuario {$username} ({$fromId}) seleccionó y guardó idioma $langCode vía callback.");
exit;
}
}
// Si no se manejó ninguna actualización específica, responder con OK para Telegram
http_response_code(200);
exit('OK');