226 lines
9.4 KiB
PHP
226 lines
9.4 KiB
PHP
<?php
|
|
/**
|
|
* API - Subir archivos multimedia
|
|
* Fecha: 13 de enero de 2026
|
|
*/
|
|
|
|
require_once '../config/config.php';
|
|
|
|
// Asegurar que errores no se impriman al cliente y se registren en logs
|
|
error_reporting(E_ALL);
|
|
@ini_set('display_errors', 0);
|
|
@ini_set('log_errors', 1);
|
|
|
|
// Verificar autenticación
|
|
requireAuthentication();
|
|
|
|
// Forzar buffer para poder limpiar salidas accidentales
|
|
if (ob_get_level() === 0) ob_start();
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: POST');
|
|
header('Access-Control-Allow-Headers: Content-Type');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
http_response_code(405);
|
|
echo json_encode(['success' => false, 'error' => 'Método no permitido']);
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
// Verificar que se subió un archivo
|
|
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
|
|
// Log for debugging
|
|
error_log('upload_media.php - FILES content: ' . print_r($_FILES, true));
|
|
// Make sure any buffered content is cleared before sending JSON
|
|
if (ob_get_length()) ob_clean();
|
|
http_response_code(400);
|
|
echo json_encode(['success' => false, 'error' => 'No se recibió ningún archivo o hubo un error en la carga']);
|
|
exit;
|
|
}
|
|
|
|
$file = $_FILES['file'];
|
|
$fileSize = $file['size'];
|
|
$fileName = basename($file['name']);
|
|
$fileTmpPath = $file['tmp_name'];
|
|
$fileType = $file['type'];
|
|
|
|
// Validar tamaño según tipo
|
|
$maxSize = 16 * 1024 * 1024; // 16MB por defecto
|
|
|
|
if (strpos($fileType, 'image/') === 0) {
|
|
$maxSize = 5 * 1024 * 1024; // 5MB para imágenes
|
|
} elseif (strpos($fileType, 'application/') === 0) {
|
|
$maxSize = 100 * 1024 * 1024; // 100MB para documentos
|
|
}
|
|
|
|
if ($fileSize > $maxSize) {
|
|
throw new Exception('El archivo es demasiado grande. Máximo: ' . ($maxSize / 1024 / 1024) . 'MB');
|
|
}
|
|
|
|
// Validar tipos de archivo permitidos
|
|
$allowedTypes = [
|
|
// Imágenes
|
|
'image/jpeg', 'image/jpg', 'image/png', 'image/webp',
|
|
// Videos (webm será convertido a mp4)
|
|
'video/mp4', 'video/3gpp', 'video/quicktime', 'video/webm',
|
|
// Audios (webm será convertido a ogg)
|
|
'audio/aac', 'audio/mp3', 'audio/mpeg', 'audio/ogg', 'audio/amr', 'audio/webm',
|
|
// Documentos
|
|
'application/pdf',
|
|
'application/msword',
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
'application/vnd.ms-excel',
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
'application/vnd.ms-powerpoint',
|
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
|
];
|
|
|
|
if (!in_array($fileType, $allowedTypes)) {
|
|
throw new Exception('Tipo de archivo no permitido: ' . $fileType);
|
|
}
|
|
|
|
// Crear directorio de uploads si no existe
|
|
$uploadDir = __DIR__ . '/../uploads/';
|
|
if (!is_dir($uploadDir)) {
|
|
mkdir($uploadDir, 0755, true);
|
|
}
|
|
|
|
// Generar nombre único
|
|
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
|
|
$uniqueName = uniqid('media_', true) . '.' . $extension;
|
|
$uploadPath = $uploadDir . $uniqueName;
|
|
|
|
// Mover archivo
|
|
if (!move_uploaded_file($fileTmpPath, $uploadPath)) {
|
|
throw new Exception('Error al guardar el archivo en el servidor');
|
|
}
|
|
|
|
// Convertir archivos WebM (audio y video) a formatos compatibles con WhatsApp
|
|
$converted = false;
|
|
$conversion_error = null;
|
|
|
|
if (strpos($fileType, 'audio/webm') === 0 || strpos($fileType, 'video/webm') === 0) {
|
|
// Evitar fatal si shell_exec está deshabilitado en el hosting
|
|
if (function_exists('shell_exec')) {
|
|
$ffmpeg = trim(@shell_exec('which ffmpeg 2>/dev/null'));
|
|
if ($ffmpeg) {
|
|
try {
|
|
if (strpos($fileType, 'audio/webm') === 0) {
|
|
// Audio WebM -> OGG/Opus (Compatible con WhatsApp Voice Messages)
|
|
$convertedName = uniqid('media_', true) . '.ogg';
|
|
$convertedPath = $uploadDir . $convertedName;
|
|
// Parámetros WhatsApp Voice:
|
|
// -c:a libopus = códec OPUS (requerido para transcripción)
|
|
// -b:a 32k = bitrate bajo para mantener archivo < 512KB (ícono play)
|
|
// -ar 48000 = sample rate 48kHz (estándar OPUS)
|
|
// -ac 1 = mono (reduce tamaño)
|
|
// -vbr on = variable bitrate
|
|
$cmd = escapeshellcmd($ffmpeg) . ' -y -i ' . escapeshellarg($uploadPath) . ' -map 0:a:0 -c:a libopus -b:a 32k -vbr on -ar 48000 -ac 1 -f ogg ' . escapeshellarg($convertedPath) . ' 2>&1';
|
|
$newType = 'audio/ogg';
|
|
$logType = 'Audio';
|
|
} else {
|
|
// Video WebM -> MP4
|
|
$convertedName = uniqid('media_', true) . '.mp4';
|
|
$convertedPath = $uploadDir . $convertedName;
|
|
// Convertir a MP4 con H.264 (compatible con WhatsApp)
|
|
$cmd = escapeshellcmd($ffmpeg) . ' -y -i ' . escapeshellarg($uploadPath) . ' -c:v libx264 -preset fast -crf 23 -c:a aac -b:a 128k -movflags +faststart ' . escapeshellarg($convertedPath) . ' 2>&1';
|
|
$newType = 'video/mp4';
|
|
$logType = 'Video';
|
|
}
|
|
|
|
$out = @shell_exec($cmd);
|
|
// Añadir comprobación diagnóstica con "ffmpeg -i" sobre el archivo convertido
|
|
$probe = @shell_exec(escapeshellcmd($ffmpeg) . ' -i ' . escapeshellarg($convertedPath) . ' 2>&1');
|
|
|
|
if (file_exists($convertedPath) && filesize($convertedPath) > 0) {
|
|
// Reemplazar archivo original por el convertido
|
|
@unlink($uploadPath);
|
|
$uploadPath = $convertedPath;
|
|
$uniqueName = $convertedName;
|
|
$fileType = $newType;
|
|
$converted = true;
|
|
error_log("upload_media.php - $logType convertido: $convertedName");
|
|
error_log('upload_media.php - ffmpeg output: ' . substr($out ?: '', 0, 2000));
|
|
error_log('upload_media.php - ffmpeg probe: ' . substr($probe ?: '', 0, 2000));
|
|
} else {
|
|
$conversion_error = 'Conversion failed or no output';
|
|
error_log('upload_media.php - Falló conversión con ffmpeg. Output: ' . substr($out ?: '', 0, 2000));
|
|
error_log('upload_media.php - ffmpeg probe after failure: ' . substr($probe ?: '', 0, 2000));
|
|
}
|
|
} catch (Exception $ex) {
|
|
$conversion_error = 'Conversion exception: ' . $ex->getMessage();
|
|
error_log('upload_media.php - Conversion exception: ' . $ex->getMessage());
|
|
}
|
|
} else {
|
|
$conversion_error = 'ffmpeg not found';
|
|
error_log('upload_media.php - ffmpeg no encontrado, no se puede convertir webm.');
|
|
}
|
|
} else {
|
|
$conversion_error = 'shell_exec disabled';
|
|
error_log('upload_media.php - shell_exec disabled, no se puede convertir webm.');
|
|
}
|
|
}
|
|
|
|
// Construir URL pública
|
|
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
|
|
$host = $_SERVER['HTTP_HOST'];
|
|
$publicUrl = $protocol . '://' . $host . '/uploads/' . $uniqueName;
|
|
|
|
// Determinar tipo de medio
|
|
$mediaType = 'document';
|
|
if (strpos($fileType, 'image/') === 0) {
|
|
$mediaType = 'image';
|
|
} elseif (strpos($fileType, 'video/') === 0) {
|
|
$mediaType = 'video';
|
|
} elseif (strpos($fileType, 'audio/') === 0) {
|
|
$mediaType = 'audio';
|
|
}
|
|
|
|
// Guardar información en base de datos (opcional)
|
|
$db = Database::getInstance();
|
|
$mediaId = $db->insert('media_files', [
|
|
'filename' => $fileName,
|
|
'unique_name' => $uniqueName,
|
|
'file_type' => $fileType,
|
|
'file_size' => $fileSize,
|
|
'media_type' => $mediaType,
|
|
'file_path' => $uploadPath,
|
|
'public_url' => $publicUrl,
|
|
'uploaded_by' => $_SESSION['user']['id'] ?? null,
|
|
'created_at' => date('Y-m-d H:i:s')
|
|
]);
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'message' => 'Archivo subido correctamente',
|
|
'id' => $mediaId,
|
|
'filename' => $fileName,
|
|
'public_url' => $publicUrl,
|
|
'media_type' => $mediaType,
|
|
'mime_type' => $fileType,
|
|
'size' => $fileSize,
|
|
'converted' => isset($converted) ? (bool)$converted : false,
|
|
'conversion_error' => isset($conversion_error) ? $conversion_error : null,
|
|
// Mantener compatibilidad con código existente
|
|
'data' => [
|
|
'id' => $mediaId,
|
|
'filename' => $fileName,
|
|
'url' => $publicUrl,
|
|
'type' => $mediaType,
|
|
'mime_type' => $fileType,
|
|
'size' => $fileSize
|
|
]
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
error_log("Error en upload_media.php: " . $e->getMessage());
|
|
http_response_code(500);
|
|
echo json_encode([
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
}
|
|
?>
|