This commit is contained in:
lizandrogd
2026-01-20 22:13:02 -05:00
parent f0a713e1da
commit 648a6c0291
19 changed files with 762 additions and 33 deletions
+80
View File
@@ -0,0 +1,80 @@
<?php
/**
* API - Obtener payload crudo de un webhook
* Fecha: 20 de enero de 2026
*/
require_once '../config/config_enhanced.php';
// Suprimir errores para obtener JSON limpio
error_reporting(E_ERROR | E_PARSE);
// Modo debug: desactivar autenticación si existe el parámetro debug
$debugMode = isset($_GET['debug']) && $_GET['debug'] === 'true';
if (!$debugMode) {
requireAuthentication();
}
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
echo json_encode(['error' => 'Método no permitido. Use GET.']);
exit;
}
try {
$db = Database::getInstance();
$id = intval($_GET['id'] ?? 0);
if (!$id) {
http_response_code(400);
echo json_encode(['error' => 'ID de webhook requerido']);
exit;
}
$row = $db->fetch(
'SELECT id, request_body, response_body, status_code, ip_address, created_at FROM webhook_logs WHERE id = ? LIMIT 1',
[$id]
);
if (!$row) {
http_response_code(404);
echo json_encode(['error' => 'Registro no encontrado']);
exit;
}
// Intentar parsear JSON bonito
$pretty = null;
$decoded = json_decode($row['request_body'], true);
if ($decoded !== null) {
$pretty = json_encode($decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}
echo json_encode([
'success' => true,
'data' => [
'id' => $row['id'],
'request_body' => $row['request_body'],
'request_body_pretty' => $pretty,
'response_body' => $row['response_body'],
'status_code' => $row['status_code'],
'ip_address' => $row['ip_address'],
'created_at' => $row['created_at']
]
]);
} catch (Exception $e) {
error_log("Error in get_webhook_log.php: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Error interno del servidor']);
}
+101
View File
@@ -0,0 +1,101 @@
<?php
/**
* API - Obtener registros de webhooks
* Fecha: 20 de enero de 2026
*/
require_once '../config/config_enhanced.php';
// Suprimir errores para obtener JSON limpio
error_reporting(E_ERROR | E_PARSE);
// Modo debug: desactivar autenticación si existe el parámetro debug
$debugMode = isset($_GET['debug']) && $_GET['debug'] === 'true';
if (!$debugMode) {
requireAuthentication();
}
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
echo json_encode(['error' => 'Método no permitido. Use GET.']);
exit;
}
try {
$db = Database::getInstance();
$limit = max(1, min(200, intval($_GET['limit'] ?? 50)));
$page = max(1, intval($_GET['page'] ?? 1));
$offset = ($page - 1) * $limit;
$sinceId = isset($_GET['since_id']) ? intval($_GET['since_id']) : null;
$search = trim($_GET['search'] ?? '');
$filter = trim($_GET['filter'] ?? ''); // e.g., HAS_MESSAGES
$where = [];
$params = [];
if ($sinceId) {
$where[] = 'id > ?';
$params[] = $sinceId;
}
if ($search !== '') {
$where[] = '(request_body LIKE ?)';
$params[] = "%{$search}%";
}
if ($filter === 'HAS_MESSAGES') {
$where[] = 'request_body LIKE ?';
$params[] = '%"messages"%';
}
$whereClause = empty($where) ? '' : 'WHERE ' . implode(' AND ', $where);
if ($sinceId) {
// Return newer logs only in ascending order for incremental updates
$rows = $db->fetchAll(
"SELECT id, SUBSTRING(request_body, 1, 1000) as snippet, status_code, ip_address, created_at FROM webhook_logs {$whereClause} ORDER BY id ASC LIMIT ?",
array_merge($params, [$limit])
);
echo json_encode(['success' => true, 'data' => $rows]);
exit;
}
$rows = $db->fetchAll(
"SELECT id, SUBSTRING(request_body, 1, 500) as snippet, status_code, ip_address, created_at FROM webhook_logs {$whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?",
array_merge($params, [$limit, $offset])
);
$total = $db->fetch(
"SELECT COUNT(*) as cnt FROM webhook_logs {$whereClause}",
$params
);
$totalCount = intval($total['cnt'] ?? 0);
echo json_encode([
'success' => true,
'data' => $rows,
'pagination' => [
'page' => $page,
'limit' => $limit,
'total' => $totalCount,
'pages' => $totalCount > 0 ? ceil($totalCount / $limit) : 0
]
]);
} catch (Exception $e) {
error_log("Error in get_webhook_logs.php: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Error interno del servidor']);
}
+50 -11
View File
@@ -4,7 +4,7 @@
* Fecha: 13 de noviembre de 2025
*/
require_once '../config/config.php';
require_once __DIR__ . '/../config/config_enhanced.php';
// Headers para API
header('Content-Type: application/json; charset=utf-8');
@@ -146,8 +146,12 @@ class WhatsAppWebhook {
'status' => 'received'
]);
// Procesar con bot
$this->botService->processMessage($user, $messageText, $messageType);
// Procesar con bot (protección contra excepciones externas)
try {
$this->botService->processMessage($user, $messageText, $messageType);
} catch (Exception $e) {
error_log("Bot processing failed: " . $e->getMessage());
}
}
// Procesar estados de mensajes (entregado, leído, etc.)
@@ -207,15 +211,50 @@ class WhatsAppWebhook {
]);
}
}
/**
* Procesar un payload (array) recibido manualmente (replay)
* Útil para reproducir entradas desde la UI o scripts.
*/
public function processPayload(array $data) {
error_log("processPayload START");
// Registrar como recibido (reproducción)
$this->logWebhook(json_encode($data), json_encode(['status' => 'replayed']), 200);
if (empty($data) || !isset($data['entry'])) {
error_log("processPayload: empty or missing entry");
return false;
}
foreach ($data['entry'] as $entry) {
if (isset($entry['changes'])) {
foreach ($entry['changes'] as $change) {
error_log("processPayload: processing change field=" . ($change['field'] ?? ''));
if (($change['field'] ?? '') === 'messages' && isset($change['value'])) {
try {
$this->processMessages($change['value']);
} catch (Exception $e) {
error_log("processPayload: processMessages failed: " . $e->getMessage());
}
}
}
}
}
error_log("processPayload END");
return true;
}
}
// Procesar la solicitud
try {
$webhook = new WhatsAppWebhook();
$webhook->handleRequest();
} catch (Exception $e) {
error_log("Fatal error in webhook: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Error fatal del servidor']);
// Procesar la solicitud (solo si no estamos en CLI)
if (php_sapi_name() !== 'cli') {
try {
$webhook = new WhatsAppWebhook();
$webhook->handleRequest();
} catch (Exception $e) {
error_log("Fatal error in webhook: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Error fatal del servidor']);
}
}
?>
+61
View File
@@ -0,0 +1,61 @@
<?php
/**
* API - Reproducir payload de webhook (simulación)
* Fecha: 20 de enero de 2026
*/
require_once __DIR__ . '/../config/config_enhanced.php';
require_once __DIR__ . '/webhook.php';
error_log('webhook_replay loaded');
// Suprimir errores para obtener JSON limpio
error_reporting(E_ERROR | E_PARSE);
$debugMode = isset($_GET['debug']) && $_GET['debug'] === 'true';
if (!$debugMode) {
requireAuthentication();
}
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Método no permitido. Use POST.']);
exit;
}
try {
error_log('webhook_replay START');
$raw = file_get_contents('php://input');
error_log('webhook_replay raw length: ' . strlen($raw));
$data = json_decode($raw, true);
if (!$data) {
error_log('webhook_replay: invalid json');
http_response_code(400);
echo json_encode(['error' => 'JSON inválido o vacío']);
exit;
}
$webhook = new WhatsAppWebhook();
$ok = $webhook->processPayload($data);
if ($ok) {
echo json_encode(['success' => true, 'message' => 'Payload reproducido correctamente']);
} else {
http_response_code(400);
echo json_encode(['error' => 'El payload no contenía entradas válidas']);
}
} catch (Exception $e) {
error_log('Error in webhook_replay.php: ' . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Error interno del servidor']);
}