Files
2026-07-24 14:59:44 +01:00

77 lines
2.6 KiB
PHP

<?php
namespace Modules\Enterprise\Services;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Modules\Enterprise\Models\Backup;
use RuntimeException;
use ZipArchive;
final class BackupService
{
public function create(?int $userId = null): Backup
{
if (! class_exists(ZipArchive::class)) {
throw new RuntimeException('The PHP zip extension is required.');
}
$disk = (string) config('enterprise.backup_disk', 'local');
$directory = trim((string) config('enterprise.backup_path', 'backups'), '/');
$name = 'cms-'.now()->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();
}
}