w
This commit is contained in:
+221
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
/**
|
||||
* Webhook para recibir mensajes de WhatsApp
|
||||
* Fecha: 13 de noviembre de 2025
|
||||
*/
|
||||
|
||||
require_once '../config/config.php';
|
||||
|
||||
// Headers para API
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: GET, POST');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
|
||||
class WhatsAppWebhook {
|
||||
private $db;
|
||||
private $whatsappService;
|
||||
private $botService;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance();
|
||||
$this->whatsappService = new WhatsAppService();
|
||||
$this->botService = new BotService();
|
||||
}
|
||||
|
||||
public function handleRequest() {
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
if ($method === 'GET') {
|
||||
$this->verifyWebhook();
|
||||
} elseif ($method === 'POST') {
|
||||
$this->processIncomingMessage();
|
||||
} else {
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Método no permitido']);
|
||||
}
|
||||
}
|
||||
|
||||
private function verifyWebhook() {
|
||||
$verifyToken = $_GET['hub_verify_token'] ?? '';
|
||||
$challenge = $_GET['hub_challenge'] ?? '';
|
||||
$mode = $_GET['hub_mode'] ?? '';
|
||||
|
||||
if ($mode === 'subscribe' && $verifyToken === WEBHOOK_VERIFY_TOKEN) {
|
||||
echo $challenge;
|
||||
exit;
|
||||
} else {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Token de verificación inválido']);
|
||||
}
|
||||
}
|
||||
|
||||
private function processIncomingMessage() {
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
|
||||
// Registrar webhook en logs
|
||||
$this->logWebhook($input, json_encode(['status' => 'received']), 200);
|
||||
|
||||
if (!$data || !isset($data['entry'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Datos inválidos']);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($data['entry'] as $entry) {
|
||||
if (isset($entry['changes'])) {
|
||||
foreach ($entry['changes'] as $change) {
|
||||
if ($change['field'] === 'messages') {
|
||||
$this->processMessages($change['value']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode(['status' => 'success']);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Error processing webhook: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Error interno del servidor']);
|
||||
}
|
||||
}
|
||||
|
||||
private function processMessages($value) {
|
||||
if (!isset($value['messages'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($value['messages'] as $message) {
|
||||
$phoneNumber = $message['from'];
|
||||
$messageId = $message['id'];
|
||||
$timestamp = $message['timestamp'];
|
||||
|
||||
// Verificar si ya procesamos este mensaje
|
||||
$existing = $this->db->fetch(
|
||||
"SELECT id FROM conversations WHERE message_id = :message_id",
|
||||
['message_id' => $messageId]
|
||||
);
|
||||
|
||||
if ($existing) {
|
||||
continue; // Ya procesamos este mensaje
|
||||
}
|
||||
|
||||
// Obtener o crear usuario
|
||||
$user = $this->getUserByPhone($phoneNumber);
|
||||
if (!$user) {
|
||||
$userId = $this->createUser($phoneNumber);
|
||||
$user = $this->getUserById($userId);
|
||||
}
|
||||
|
||||
// Procesar diferentes tipos de mensaje
|
||||
$messageText = '';
|
||||
$messageType = 'text';
|
||||
$mediaUrl = null;
|
||||
|
||||
if (isset($message['text'])) {
|
||||
$messageText = $message['text']['body'];
|
||||
$messageType = 'text';
|
||||
} elseif (isset($message['image'])) {
|
||||
$messageText = $message['image']['caption'] ?? '';
|
||||
$messageType = 'image';
|
||||
$mediaUrl = $message['image']['id'];
|
||||
} elseif (isset($message['audio'])) {
|
||||
$messageType = 'audio';
|
||||
$mediaUrl = $message['audio']['id'];
|
||||
} elseif (isset($message['video'])) {
|
||||
$messageText = $message['video']['caption'] ?? '';
|
||||
$messageType = 'video';
|
||||
$mediaUrl = $message['video']['id'];
|
||||
} elseif (isset($message['document'])) {
|
||||
$messageText = $message['document']['filename'] ?? '';
|
||||
$messageType = 'document';
|
||||
$mediaUrl = $message['document']['id'];
|
||||
}
|
||||
|
||||
// Guardar mensaje en base de datos
|
||||
$this->saveMessage([
|
||||
'user_id' => $user['id'],
|
||||
'message_id' => $messageId,
|
||||
'direction' => 'incoming',
|
||||
'message_type' => $messageType,
|
||||
'content' => $messageText,
|
||||
'media_url' => $mediaUrl,
|
||||
'status' => 'received'
|
||||
]);
|
||||
|
||||
// Procesar con bot
|
||||
$this->botService->processMessage($user, $messageText, $messageType);
|
||||
}
|
||||
|
||||
// Procesar estados de mensajes (entregado, leído, etc.)
|
||||
if (isset($value['statuses'])) {
|
||||
$this->processMessageStatuses($value['statuses']);
|
||||
}
|
||||
}
|
||||
|
||||
private function processMessageStatuses($statuses) {
|
||||
foreach ($statuses as $status) {
|
||||
$messageId = $status['id'];
|
||||
$newStatus = $status['status']; // sent, delivered, read, failed
|
||||
|
||||
$this->db->update(
|
||||
'conversations',
|
||||
['status' => $newStatus],
|
||||
'message_id = :message_id',
|
||||
['message_id' => $messageId]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function getUserByPhone($phoneNumber) {
|
||||
return $this->db->fetch(
|
||||
"SELECT * FROM users WHERE phone_number = :phone",
|
||||
['phone' => $phoneNumber]
|
||||
);
|
||||
}
|
||||
|
||||
private function getUserById($userId) {
|
||||
return $this->db->fetch(
|
||||
"SELECT * FROM users WHERE id = :id",
|
||||
['id' => $userId]
|
||||
);
|
||||
}
|
||||
|
||||
private function createUser($phoneNumber) {
|
||||
return $this->db->insert('users', [
|
||||
'phone_number' => $phoneNumber,
|
||||
'status' => 'active',
|
||||
'created_at' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
}
|
||||
|
||||
private function saveMessage($messageData) {
|
||||
return $this->db->insert('conversations', $messageData);
|
||||
}
|
||||
|
||||
private function logWebhook($requestBody, $responseBody, $statusCode) {
|
||||
if (ENABLE_LOGGING) {
|
||||
$this->db->insert('webhook_logs', [
|
||||
'request_body' => $requestBody,
|
||||
'response_body' => $responseBody,
|
||||
'status_code' => $statusCode,
|
||||
'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
|
||||
'created_at' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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']);
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user