This commit is contained in:
lizandrogd
2026-01-21 12:20:46 -05:00
parent 6cec747ae3
commit 901d51c82f
11 changed files with 363 additions and 7 deletions
+4 -1
View File
@@ -69,7 +69,10 @@ try {
'direction' => $msg['direction'],
'message_type' => $msg['message_type'],
'content' => $msg['content'] ?? '',
'media_url' => (isset($msg['media_url']) && $msg['media_url']) ? (preg_match('#^https?://#i', $msg['media_url']) ? $msg['media_url'] : ("api/get_media.php?id=" . urlencode($msg['media_url']))) : null,
'media_url' => null,
'local_file' => $msg['local_file'] ?? null,
'local_thumb' => $msg['local_thumb'] ?? null,
'media_url_external' => (isset($msg['media_url']) && $msg['media_url']) ? (preg_match('#^https?://#i', $msg['media_url']) ? $msg['media_url'] : ("api/get_media.php?id=" . urlencode($msg['media_url']))) : null,
'filename' => $msg['filename'] ?? null,
'mime_type' => $msg['mime_type'] ?? null,
'status' => $msg['status'] ?? 'sent',
+4 -1
View File
@@ -86,7 +86,10 @@ try {
'user_id' => intval($msg['user_id']),
'content' => $msg['content'] ?? '',
'message_id' => $msg['message_id'] ?? null,
'media_url' => (isset($msg['media_url']) && $msg['media_url']) ? (preg_match('#^https?://#i', $msg['media_url']) ? $msg['media_url'] : ("api/get_media.php?id=" . urlencode($msg['media_url']))) : null,
'media_url' => null,
'local_file' => $msg['local_file'] ?? null,
'local_thumb' => $msg['local_thumb'] ?? null,
'media_url_external' => (isset($msg['media_url']) && $msg['media_url']) ? (preg_match('#^https?://#i', $msg['media_url']) ? $msg['media_url'] : ("api/get_media.php?id=" . urlencode($msg['media_url']))) : null,
'filename' => $msg['filename'] ?? null,
'mime_type' => $msg['mime_type'] ?? null,
'user_phone' => $msg['user_phone'] ?? null,
+49
View File
@@ -70,6 +70,49 @@ if ($providedUrl) {
}
}
// Soporte para archivos locales (local=uploads/media/...)
$local = $_GET['local'] ?? null;
if ($local) {
$localPath = realpath(__DIR__ . '/../../' . ltrim($local, '/'));
$base = realpath(__DIR__ . '/../../uploads/media');
// Prevención simple de path traversal
if (!$localPath || strpos($localPath, $base) !== 0) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Ruta local inválida']);
exit;
}
if (!file_exists($localPath)) {
http_response_code(404);
echo json_encode(['success' => false, 'error' => 'Archivo no encontrado']);
exit;
}
if ($wantsJson) {
// devolver URL pública directa (relative)
echo json_encode(['success' => true, 'url' => '/' . ltrim($local, '/')]);
exit;
}
if ($download) {
// Forzar descarga del archivo local
header('Cache-Control: public, max-age=3600');
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$ctype = finfo_file($finfo, $localPath);
finfo_close($finfo);
header('Content-Type: ' . $ctype);
header('Content-Length: ' . filesize($localPath));
header('Content-Disposition: attachment; filename="' . basename($localPath) . '"');
readfile($localPath);
exit;
}
// Redirigir al archivo local (servidor web lo servirá)
header('Cache-Control: public, max-age=3600');
header('Location: /' . ltrim($local, '/'), true, 302);
exit;
}
// Si se solicitó JSON, devolver la URL
if ($wantsJson) {
echo json_encode(['success' => true, 'url' => $mediaUrl]);
@@ -79,11 +122,17 @@ if ($wantsJson) {
// Si se pidió proxy (download=1), traer el contenido y retornarlo como descarga
if ($download) {
$ch = curl_init();
// Añadir Authorization si existe token en configuración
$token = getConfigFromDB('whatsapp_token', '');
$headers = ['User-Agent: WhatsAppMediaProxy/1.0', 'Accept: */*'];
if ($token) $headers[] = 'Authorization: Bearer ' . $token;
curl_setopt_array($ch, [
CURLOPT_URL => $mediaUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_HTTPHEADER => $headers,
]);
$content = curl_exec($ch);
$info = curl_getinfo($ch);
+87
View File
@@ -164,23 +164,103 @@ class WhatsAppWebhook {
$mediaUrl = $message['image']['url'] ?? ($message['image']['id'] ?? null);
$mimeType = $message['image']['mime_type'] ?? null;
$filename = $message['image']['filename'] ?? null;
// Intentar descargar y almacenar imagen localmente
try {
$ms = new MediaService();
$res = null;
if ($mediaUrl && preg_match('#^https?://#i', $mediaUrl)) {
// Si venía URL directa, descargar desde URL
$content = $ms->downloadUrl($mediaUrl);
if ($content !== false) {
$subdir = date('Y/m');
$dir = 'uploads/media/' . $subdir;
if (!is_dir(__DIR__ . '/../' . $dir)) mkdir(__DIR__ . '/../' . $dir, 0755, true);
$ext = $ms->extensionFromMime($mimeType) ?: pathinfo(parse_url($mediaUrl, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'jpg';
$fname = uniqid('m_') . '.' . $ext;
$path = __DIR__ . '/../' . $dir . '/' . $fname;
file_put_contents($path, $content);
$res = ['local_file' => $dir . '/' . $fname];
// crear thumb
if ($ms->isImageMime($mimeType)) {
$thumbPath = __DIR__ . '/../' . $dir . '/thumb_' . $fname . '.jpg';
if ($ms->createThumbnail($path, $thumbPath)) {
$res['local_thumb'] = $dir . '/thumb_' . $fname . '.jpg';
}
}
}
} elseif ($mediaUrl) {
// mediaUrl probablemente es media id -> usar fetchAndStoreFromGraph
$res = $ms->fetchAndStoreFromGraph($mediaUrl, date('Y/m'));
}
if ($res) {
$localFile = $res['local_file'] ?? null;
$localThumb = $res['local_thumb'] ?? null;
}
} catch (Exception $e) {
error_log('Media download failed: ' . $e->getMessage());
// Encolar para reintento si tenemos un media id (no descargar documentos aquí)
try {
if ($mediaUrl && !preg_match('#^https?://#i', $mediaUrl)) {
$this->db->insert('media_queue', [
'media_id' => $mediaUrl,
'subdir' => date('Y/m'),
'status' => 'pending',
'created_at' => date('Y-m-d H:i:s')
]);
}
} catch (Exception $e2) {
error_log('Failed to enqueue media download: ' . $e2->getMessage());
}
}
} elseif (isset($message['audio'])) {
$messageType = 'audio';
$mediaUrl = $message['audio']['url'] ?? ($message['audio']['id'] ?? null);
$mimeType = $message['audio']['mime_type'] ?? null;
$filename = $message['audio']['filename'] ?? null;
// Descargar audio y guardar local (opcional)
try {
$ms = new MediaService();
if ($mediaUrl && !preg_match('#^https?://#i', $mediaUrl)) {
$res = $ms->fetchAndStoreFromGraph($mediaUrl, date('Y/m'));
if ($res) {
$localFile = $res['local_file'] ?? null;
}
}
} catch (Exception $e) {
error_log('Audio download failed: ' . $e->getMessage());
}
} elseif (isset($message['video'])) {
$messageText = $message['video']['caption'] ?? '';
$messageType = 'video';
$mediaUrl = $message['video']['url'] ?? ($message['video']['id'] ?? null);
$mimeType = $message['video']['mime_type'] ?? null;
$filename = $message['video']['filename'] ?? null;
// Descargar video y guardar local (opcional)
try {
$ms = new MediaService();
if ($mediaUrl && !preg_match('#^https?://#i', $mediaUrl)) {
$res = $ms->fetchAndStoreFromGraph($mediaUrl, date('Y/m'));
if ($res) {
$localFile = $res['local_file'] ?? null;
}
}
} catch (Exception $e) {
error_log('Video download failed: ' . $e->getMessage());
}
} elseif (isset($message['document'])) {
$messageText = $message['document']['filename'] ?? '';
$messageType = 'document';
$mediaUrl = $message['document']['url'] ?? ($message['document']['id'] ?? null);
$mimeType = $message['document']['mime_type'] ?? null;
$filename = $message['document']['filename'] ?? null;
// Do NOT download documents automatically; keep media id so browser will redirect and download
}
// Log debug (temporal) para verificar cómo llegan media_url/filename
@@ -205,6 +285,13 @@ class WhatsAppWebhook {
if (isset($mimeType) && $mimeType !== null) {
$saveData['mime_type'] = $mimeType;
}
// Si se descargó y almacenó localmente, añadir las rutas locales
if (isset($localFile) && $localFile) {
$saveData['local_file'] = $localFile;
}
if (isset($localThumb) && $localThumb) {
$saveData['local_thumb'] = $localThumb;
}
// Si el mensaje incluye contexto (es respuesta a otro mensaje)
if (isset($message['context']) && isset($message['context']['id'])) {