false, 'message' => 'ID mescola non valido']); exit; } if (!array_key_exists($categoria, $categorie)) { echo json_encode(['success' => false, 'message' => 'Categoria non valida']); exit; } if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) { echo json_encode(['success' => false, 'message' => 'File mancante o upload non riuscito']); exit; } // --- Validazioni di sicurezza sul file --- $allowedExt = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'jpg', 'jpeg', 'png']; $maxSize = 15 * 1024 * 1024; // 15 MB $originalName = $_FILES['file']['name']; $tmpPath = $_FILES['file']['tmp_name']; $size = (int)$_FILES['file']['size']; $ext = strtolower(pathinfo($originalName, PATHINFO_EXTENSION)); // Titolo automatico dal nome file se non fornito if ($titolo === '') { $titolo = pathinfo($originalName, PATHINFO_FILENAME); $titolo = trim(preg_replace('/[_\-]+/', ' ', $titolo)); if ($titolo === '') { $titolo = 'Documento del ' . date('d/m/Y'); } } $titolo = mb_substr($titolo, 0, 255); if (!in_array($ext, $allowedExt, true)) { echo json_encode(['success' => false, 'message' => 'Estensione file non consentita (' . $ext . ')']); exit; } if ($size <= 0 || $size > $maxSize) { echo json_encode(['success' => false, 'message' => 'Il file supera la dimensione massima di 15MB']); exit; } $finfo = finfo_open(FILEINFO_MIME_TYPE); $mimeType = finfo_file($finfo, $tmpPath); finfo_close($finfo); // Cartella dedicata per mescola: uploads/mescole/{idmescola}/ $destDir = __DIR__ . '/uploads/mescole/' . $idmescola . '/'; if (!is_dir($destDir)) { mkdir($destDir, 0775, true); } // Nome fisico casuale: evita collisioni e path traversal $storedName = bin2hex(random_bytes(16)) . '.' . $ext; $destPath = $destDir . $storedName; if (!move_uploaded_file($tmpPath, $destPath)) { echo json_encode(['success' => false, 'message' => 'Impossibile salvare il file sul server']); exit; } try { $db = DBHandlerSelect::getInstance(); $pdo = $db->getConnection(); $stmt = $pdo->prepare(" INSERT INTO mescole_files (idmescola, categoria, titolo, filename, original_filename, mime_type, filesize, uploaded_at) VALUES (?, ?, ?, ?, ?, ?, ?, NOW()) "); $stmt->execute([$idmescola, $categoria, $titolo, $storedName, $originalName, $mimeType, $size]); $newId = (int)$pdo->lastInsertId(); echo json_encode([ 'success' => true, 'id' => $newId, 'row' => [ 'id' => $newId, 'idmescola' => $idmescola, 'categoria' => $categoria, 'categoria_label' => $categorie[$categoria], 'titolo' => $titolo, 'filename' => $storedName, 'original_filename' => $originalName, 'mime_type' => $mimeType, 'filesize' => $size, 'uploaded_at' => date('Y-m-d H:i:s'), 'url' => 'uploads/mescole/' . $idmescola . '/' . $storedName, ], ]); } catch (Throwable $e) { // rollback file se il DB fallisce @unlink($destPath); echo json_encode(['success' => false, 'message' => 'Errore database: ' . $e->getMessage()]); }