stato->get($operationId); abort_if($operazione === null, 404, 'Backup non piu\' disponibile: rigeneralo.'); $percorso = CreateBackupArchive::percorso($operationId); abort_unless(is_file($percorso), 404, 'Archivio di backup non trovato: rigeneralo.'); $nome = $operazione['result']['nome_download'] ?? 'termanager2-backup.zip'; $this->stato->update($operationId, function (array $state) { $state['result']['servito_at'] = now()->toDateTimeString(); return $state; }); return response() ->download($percorso, $nome, [ 'Content-Type' => 'application/zip', 'Content-Length' => (string) filesize($percorso), ]); } /** * Riceve il pacchetto da ripristinare e mette in coda il lavoro. * * Risponde JSON perche' il form viene inviato via XMLHttpRequest: e' l'unico * modo di avere una barra di caricamento reale sull'upload, che per un * archivio di centinaia di MB e' la parte piu' lunga dell'operazione. */ public function upload(Request $request) { // 256 MB e' il tetto reale della pila, non una scelta di questa // validazione: piu' in su intervengono prima `client_max_body_size` di // nginx e `upload_max_filesize`/`post_max_size` di PHP, che rifiutano // la richiesta con un 413 opaco invece di un messaggio leggibile. $request->validate([ 'backupZip' => ['required', 'file', 'mimes:zip', 'max:256000'], ], [ 'backupZip.required' => 'Seleziona il pacchetto di backup da ripristinare.', 'backupZip.mimes' => 'Il pacchetto di backup deve essere un file .zip.', 'backupZip.max' => 'Il pacchetto supera i 256 MB accettati dal server.', ]); $operationId = (string) Str::uuid(); // Il file dell'upload vive in una cartella temporanea che sparisce a // fine richiesta: il job lo troverebbe gia' cancellato. $percorso = $request->file('backupZip')->storeAs( 'backup-restore-in', $operationId . '.zip', 'local' ); $this->stato->initialize( $operationId, BackupOperationState::TIPO_RESTORE, 'In coda' ); $this->stato->log($operationId, 'Archivio ricevuto. In attesa del worker di coda.'); RestoreBackupArchive::dispatch( $operationId, storage_path('app/' . $percorso), (int) auth()->id() ); return response()->json(['operation_id' => $operationId]); } }