false, 'message' => '', 'uploaded' => [], 'errors' => [] ]; try { if ($_SERVER['REQUEST_METHOD'] !== 'POST') { throw new Exception('Metodo non consentito'); } if (!isset($_POST['idmatrice']) || !is_numeric($_POST['idmatrice'])) { throw new Exception('ID matrice non valido'); } if (!isset($_FILES['files'])) { throw new Exception('Nessun file ricevuto'); } $idmatrice = (int)$_POST['idmatrice']; $descriptions = isset($_POST['descriptions']) && is_array($_POST['descriptions']) ? $_POST['descriptions'] : []; $db = DBHandlerSelect::getInstance(); $pdo = $db->getConnection(); // Verifica esistenza matrice $checkStmt = $pdo->prepare("SELECT id FROM matrice WHERE id = :id LIMIT 1"); $checkStmt->execute([':id' => $idmatrice]); if (!$checkStmt->fetchColumn()) { throw new Exception('Matrice non trovata'); } $uploadDirRelative = 'photos/matrici/allegati/'; $uploadDirAbsolute = __DIR__ . '/' . $uploadDirRelative; if (!is_dir($uploadDirAbsolute)) { if (!mkdir($uploadDirAbsolute, 0775, true) && !is_dir($uploadDirAbsolute)) { throw new Exception('Impossibile creare la cartella di upload'); } } $allowedExtensions = [ 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic', 'heif', 'doc', 'docx' ]; $imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic', 'heif']; $fileNames = $_FILES['files']['name'] ?? []; $tmpNames = $_FILES['files']['tmp_name'] ?? []; $errors = $_FILES['files']['error'] ?? []; $sizes = $_FILES['files']['size'] ?? []; if (!is_array($fileNames) || count($fileNames) === 0) { throw new Exception('Nessun file valido ricevuto'); } $maxFileSize = 20 * 1024 * 1024; // 20 MB per file $pdo->beginTransaction(); $sortStmt = $pdo->prepare("SELECT COALESCE(MAX(sort_order), 0) FROM matrice_attachments WHERE matrice_id = :matrice_id"); $sortStmt->execute([':matrice_id' => $idmatrice]); $nextSort = (int)$sortStmt->fetchColumn(); $insertSql = "INSERT INTO matrice_attachments (matrice_id, file_name, file_path, file_type, description, sort_order, created_at, updated_at) VALUES (:matrice_id, :file_name, :file_path, :file_type, :description, :sort_order, NOW(), NOW())"; $insertStmt = $pdo->prepare($insertSql); foreach ($fileNames as $index => $originalName) { $originalName = trim((string)$originalName); $tmpName = $tmpNames[$index] ?? ''; $errorCode = $errors[$index] ?? UPLOAD_ERR_NO_FILE; $size = (int)($sizes[$index] ?? 0); $description = isset($descriptions[$index]) ? trim((string)$descriptions[$index]) : ''; if ($errorCode === UPLOAD_ERR_NO_FILE) { continue; } if ($errorCode !== UPLOAD_ERR_OK) { $response['errors'][] = "Errore upload file: {$originalName}"; continue; } if (!is_uploaded_file($tmpName)) { $response['errors'][] = "File non valido: {$originalName}"; continue; } if ($size <= 0) { $response['errors'][] = "File vuoto: {$originalName}"; continue; } if ($size > $maxFileSize) { $response['errors'][] = "File troppo grande (max 20 MB): {$originalName}"; continue; } $safeOriginalName = preg_replace('/[^\w.\- ]+/u', '_', $originalName); $extension = strtolower(pathinfo($safeOriginalName, PATHINFO_EXTENSION)); if (!in_array($extension, $allowedExtensions, true)) { $response['errors'][] = "Formato non ammesso: {$originalName}"; continue; } if (in_array($extension, $imageExtensions, true)) { $fileType = 'image'; } elseif ($extension === 'pdf') { $fileType = 'pdf'; } elseif (in_array($extension, ['doc', 'docx'], true)) { $fileType = 'doc'; } else { $fileType = 'other'; } $uniqueName = 'matrice_' . $idmatrice . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $extension; $destinationAbsolute = $uploadDirAbsolute . $uniqueName; $destinationRelative = $uploadDirRelative . $uniqueName; if (!move_uploaded_file($tmpName, $destinationAbsolute)) { $response['errors'][] = "Impossibile salvare il file: {$originalName}"; continue; } $nextSort++; $insertStmt->execute([ ':matrice_id' => $idmatrice, ':file_name' => $safeOriginalName, ':file_path' => $destinationRelative, ':file_type' => $fileType, ':description' => $description, ':sort_order' => $nextSort ]); $response['uploaded'][] = [ 'id' => (int)$pdo->lastInsertId(), 'file_name' => $safeOriginalName, 'file_path' => $destinationRelative, 'file_type' => $fileType, 'description' => $description ]; } if (empty($response['uploaded']) && !empty($response['errors'])) { $pdo->rollBack(); $response['message'] = 'Nessun file caricato'; echo json_encode($response, JSON_UNESCAPED_UNICODE); exit; } $pdo->commit(); $response['success'] = true; if (!empty($response['errors'])) { $response['message'] = 'Upload completato con alcuni avvisi'; } else { $response['message'] = 'File caricati correttamente'; } } catch (Throwable $e) { if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) { $pdo->rollBack(); } $response['message'] = $e->getMessage(); } echo json_encode($response, JSON_UNESCAPED_UNICODE); exit;