77 lines
2.6 KiB
PHP
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();
|
|
}
|
|
}
|