N, 'data' => [0=>.., 1=>.., ...]] ] * - Include _engine.php e applica applyRoutine(). * - Risponde JSON con la riga elaborata + intestazioni + lettere colonna. */ ob_start(); session_start(); require_once '../../vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; Dotenv\Dotenv::createImmutable(dirname(__DIR__, 2))->safeLoad(); date_default_timezone_set($_ENV['APP_TIMEZONE'] ?? 'Europe/Rome'); header('Content-Type: application/json'); $response = [ 'error' => '', 'headers' => [], // intestazioni prese dalla header row 'letters' => [], // lettere colonna (A, B, C, ...) allineate ai valori 'row' => [], // valori della riga DOPO l'applicazione del motore 'excelrow' => 0, // numero riga excel elaborata ]; /** * Indice zero-based -> lettera colonna Excel (0 -> A, 25 -> Z, 26 -> AA...). */ function previewIndexToCol($index) { $index = (int)$index; if ($index < 0) { return ''; } $letters = ''; $index += 1; while ($index > 0) { $rem = ($index - 1) % 26; $letters = chr(ord('A') + $rem) . $letters; $index = intdiv($index - 1, 26); } return $letters; } try { if ($_SERVER['REQUEST_METHOD'] !== 'POST') { throw new Exception('Richiesta non valida.'); } $idroutine = (int)($_POST['idroutine'] ?? 0); if ($idroutine <= 0) { throw new Exception('ID routine mancante.'); } if ( empty($_FILES['file']) || !isset($_FILES['file']['tmp_name']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK ) { throw new Exception('Nessun file caricato o upload non riuscito.'); } // --- Recupera la routine e verifica che sia a motore --- require_once __DIR__ . '/class/db-functions.php'; $pdo = DBHandlerSelect::getInstance()->getConnection(); $stmt = $pdo->prepare("SELECT idroutine, name, engine, headerrow FROM routine WHERE idroutine = :id LIMIT 1"); $stmt->execute([':id' => $idroutine]); $routine = $stmt->fetch(PDO::FETCH_ASSOC); if (!$routine) { throw new Exception('Routine non trovata.'); } if ((int)$routine['engine'] !== 1) { throw new Exception('Questa routine non è di tipo Motore: anteprima non disponibile.'); } $headerRow = max(1, (int)$routine['headerrow']); // riga 1-based dell'intestazione // --- Legge l'XLS dal file temporaneo (nessun salvataggio) --- $tmpPath = $_FILES['file']['tmp_name']; $reader = IOFactory::createReaderForFile($tmpPath); $reader->setReadDataOnly(true); $spreadsheet = $reader->load($tmpPath); $sheet = $spreadsheet->getActiveSheet(); $highestColIndex = Coordinate::columnIndexFromString($sheet->getHighestDataColumn()); // 1-based $highestRow = $sheet->getHighestDataRow(); // --- Intestazioni dalla header row --- $headers = []; $letters = []; for ($c = 1; $c <= $highestColIndex; $c++) { $val = $sheet->getCell([$c, $headerRow])->getValue(); $headers[] = ($val === null ? '' : (string)$val); $letters[] = previewIndexToCol($c - 1); // zero-based -> lettera } // --- Trova la prima riga dati valorizzata dopo l'header --- $dataRowNumber = null; $rowValues = null; for ($r = $headerRow + 1; $r <= $highestRow; $r++) { $vals = []; $hasValue = false; for ($c = 1; $c <= $highestColIndex; $c++) { $v = $sheet->getCell([$c, $r])->getValue(); $v = ($v === null ? '' : (string)$v); if ($v !== '') { $hasValue = true; } $vals[$c - 1] = $v; // indice zero-based, allineato alle colonne } if ($hasValue) { $dataRowNumber = $r; $rowValues = $vals; break; } } if ($dataRowNumber === null) { throw new Exception('Nessuna riga dati valorizzata trovata dopo la riga di intestazione (' . $headerRow . ').'); } // --- Impacchetta nel formato excelData e applica il motore --- $excelData = [ [ 'excelrow' => $dataRowNumber, 'data' => $rowValues, ], ]; // Il motore legge gli step dal DB in base a idroutine. $routineData = [ 'idroutine' => $idroutine, 'name' => $routine['name'], 'headerrow' => $headerRow, 'xls_headers' => $headers, ]; require_once __DIR__ . '/routines/_engine.php'; applyRoutine($excelData, $routineData); // modifica in place $processed = $excelData[0]['data'] ?? []; // Riallinea l'output all'ampiezza delle intestazioni (il merge può creare indici nuovi). $maxIndex = max( count($headers) - 1, empty($processed) ? 0 : max(array_keys($processed)) ); $outRow = []; $outLetters = []; $outHeaders = []; for ($i = 0; $i <= $maxIndex; $i++) { $outRow[] = array_key_exists($i, $processed) ? (string)$processed[$i] : ''; $outLetters[] = previewIndexToCol($i); $outHeaders[] = array_key_exists($i, $headers) ? $headers[$i] : ''; } $response['headers'] = $outHeaders; $response['letters'] = $outLetters; $response['row'] = $outRow; $response['excelrow'] = $dataRowNumber; } catch (Throwable $e) { $response['error'] = 'Errore anteprima: ' . $e->getMessage(); error_log('routine_preview.php: ' . $e->getMessage()); } ob_end_clean(); echo json_encode($response, JSON_UNESCAPED_UNICODE); exit;