format('Ymd-His').'.zip'; $relativePath = $directory.'/'.$name; $temporary = storage_path('app/'.$name); $zip = new ZipArchive; if ($zip->open($temporary, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) { throw new RuntimeException('Unable to create backup archive.'); } $manifest = json_encode([ 'application' => config('app.name'), 'environment' => app()->environment(), 'created_at' => now()->toIso8601String(), 'php' => PHP_VERSION, 'laravel' => app()->version(), ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); $zip->addFromString('manifest.json', $manifest ?: '{}'); $zip->addFile(base_path('composer.json'), 'composer.json'); if (File::exists(base_path('modules_statuses.json'))) { $zip->addFile(base_path('modules_statuses.json'), 'modules_statuses.json'); } if (config('database.default') === 'sqlite') { $database = database_path('database.sqlite'); if (File::exists($database)) { $zip->addFile($database, 'database/database.sqlite'); } } $zip->close(); Storage::disk($disk)->put($relativePath, File::get($temporary)); File::delete($temporary); return Backup::create([ 'user_id' => $userId, 'disk' => $disk, 'path' => $relativePath, 'size' => Storage::disk($disk)->size($relativePath), 'status' => 'completed', 'completed_at' => now(), ]); } public function delete(Backup $backup): void { Storage::disk($backup->disk)->delete($backup->path); $backup->delete(); } public function prune(): int { $cutoff = now()->subDays((int) config('enterprise.retention_days', 30)); $backups = Backup::query()->where('created_at', '<', $cutoff)->get(); $backups->each(fn (Backup $backup) => $this->delete($backup)); return $backups->count(); } }