'Method not allowed']); exit; } if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) { echo json_encode(['error' => 'No se recibió ningún archivo.']); exit; } $file = $_FILES['file']; // Validate size if ($file['size'] > MAX_UPLOAD_SIZE) { echo json_encode(['error' => 'El archivo excede el tamaño máximo de 5MB.']); exit; } // Validate type $allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml']; $finfo = new finfo(FILEINFO_MIME_TYPE); $mimeType = $finfo->file($file['tmp_name']); if (!in_array($mimeType, $allowedTypes, true)) { echo json_encode(['error' => 'Tipo de archivo no permitido. Solo se aceptan imágenes (JPG, PNG, GIF, WebP, SVG).']); exit; } // Validate extension $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg']; $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($extension, $allowedExtensions, true)) { echo json_encode(['error' => 'Extensión de archivo no permitida.']); exit; } // Generate unique filename $filename = date('Y-m') . '-' . bin2hex(random_bytes(8)) . '.' . $extension; // Create monthly subdirectory $monthDir = UPLOAD_DIR . date('Y') . '/' . date('m') . '/'; if (!is_dir($monthDir)) { mkdir($monthDir, 0755, true); } $destination = $monthDir . $filename; if (move_uploaded_file($file['tmp_name'], $destination)) { $url = UPLOAD_URL . date('Y') . '/' . date('m') . '/' . $filename; echo json_encode(['location' => $url]); } else { echo json_encode(['error' => 'No se pudo guardar el archivo.']); }