Skip to content

Commit 80aeec7

Browse files
committed
New feature: Backup CMS storage
1 parent 6a578c0 commit 80aeec7

20 files changed

+319
-100
lines changed

Plugin.php

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public function register()
3333
{
3434
$this->registerConsoleCommand('smallbackup.db', Console\BackupDb::class);
3535
$this->registerConsoleCommand('smallbackup.theme', Console\BackupTheme::class);
36+
$this->registerConsoleCommand('smallbackup.storage', Console\BackupStorage::class);
3637
}
3738

3839
/**
@@ -48,6 +49,9 @@ public function registerSchedule($schedule)
4849
if (Models\Settings::get('theme_auto')) {
4950
$schedule->command('smallbackup:theme')->daily();
5051
}
52+
if (Models\Settings::get('storage_auto')) {
53+
$schedule->command('smallbackup:storage')->daily();
54+
}
5155
}
5256

5357
/**

README.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Small Backup
2-
> Simple backup for database (MySQL, SQLite) and active theme
2+
> Simple backup for database (MySQL, SQLite), active theme and CMS storages
33
44

55
## Installation
@@ -41,10 +41,12 @@ composer require webula/smallbackup-plugin
4141

4242
## Settings
4343

44-
* Default backups folder `storage/app/uploads/protected/backup`
44+
* Default backups folder `storage/app/backup`
4545
* Default cleanup interval `7 days`
4646

47-
You can download created backups from plugin Settings tabs Database and Theme or you can get it directly from backup folder (eg. with FTP).
47+
You can download created backups from plugin Settings tabs Database, Theme and Storage or you can get it directly from backup folder (eg. with FTP).
48+
49+
It's recommended to put your backup folder into .htaccess' *Black listed folders*, e.g. `RewriteRule ^storage/app/backup/.* index.php [L,NC]`.
4850

4951

5052
## How to make backups
@@ -71,6 +73,7 @@ is_hidden = 0
7173
{
7274
wsb_backup_db($once = false, $connectionName = null,$noCleanup = false);
7375
wsb_backup_theme($once = false, $themeName = null, $noCleanup = false);
76+
wsb_backup_storage($once = false, $cmsStorage = null, $noCleanup = false);
7477
}
7578
?>
7679
==
@@ -89,6 +92,8 @@ There are console commands ready:
8992

9093
* `php artisan smallbackup:theme [themeName] [--no-cleanup] [--once]` (themeName is optional and can be any folder name in themes/)
9194

95+
* `php artisan smallbackup:storage [cmsStorage] [--no-cleanup] [--once]` (cmsStorage is optional and can be any storage registered in *cms.storage* config)
96+
9297

9398
----
9499
> Our thanks goes to:

classes/BackupManager.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ public function __construct(string $folder = null, string $prefix = null)
3838
/**
3939
* Backup source and return his filename
4040
*
41-
* @param string|null $source
41+
* @param string|null $resource
4242
* @param bool $once do not overwrite existing backup file
43-
* @return string file with current backup
43+
* @return string|null file with current backup
4444
*/
45-
abstract public function backup(string $source = null, bool $once = false): string;
45+
abstract public function backup(string $resource = null, bool $once = false): string;
4646

4747
/**
4848
* Clear expired backups
@@ -91,7 +91,7 @@ public function list(): array
9191
*/
9292
protected function getBackupFolder(): string
9393
{
94-
return strval(Settings::get('backup_folder', 'storage/app/uploads/protected/backup'));
94+
return strval(Settings::get('backup_folder', 'storage/app/backup'));
9595
}
9696

9797
/**

classes/DbBackupManager.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ class DbBackupManager extends BackupManager
1818
/**
1919
* Backup DB by connection name (null = default)
2020
*
21-
* @param string|null $source connection name
21+
* @param string|null $resource connection name
2222
* @param bool $once do not overwrite existing backup file
2323
* @return string file with current backup
2424
*/
25-
public function backup(string $source = null, bool $once = false): string
25+
public function backup(string $resource = null, bool $once = false): string
2626
{
27-
$connectionName = $source ?: config('database.default');
27+
$connectionName = $resource ?: config('database.default');
2828
$connectionDriver = config('database.connections.' . $connectionName . '.driver');
2929

3030
if ($connectionDriver == 'mysql') {

classes/StorageBackupManager.php

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php namespace Webula\SmallBackup\Classes;
2+
3+
use File;
4+
use Exception;
5+
use October\Rain\Filesystem\Zip;
6+
use Webula\SmallBackup\Models\Settings;
7+
8+
class StorageBackupManager extends BackupManager
9+
{
10+
/**
11+
* Backup file prefix
12+
*
13+
* @var string
14+
*/
15+
protected $prefix = 'wsb-storage-';
16+
17+
/**
18+
* Backup Storage(s) by resource name (null = all)
19+
*
20+
* @param string|null $resource resource
21+
* @param bool $once do not overwrite existing backup file
22+
* @return string backup file
23+
*/
24+
public function backup(string $resource = null, bool $once = false): string
25+
{
26+
if ($resource) {
27+
$path = config('cms.storage.' . $resource . '.path');
28+
if (!$path) {
29+
throw new Exception(trans('webula.smallbackup::lang.backup.flash.unknown_resource', ['resource' => $resource]));
30+
}
31+
$folders[] = $path;
32+
} else {
33+
$folders = array_diff(array_pluck(config('cms.storage'), 'path'), $this->getExcludedResources());
34+
}
35+
36+
$folders = collect($folders)->map(function ($folder) {
37+
return base_path($folder);
38+
})->filter(function ($folder) {
39+
return File::isDirectory($folder);
40+
})->all();
41+
42+
if (empty($folders)) {
43+
throw new Exception(trans('webula.smallbackup::lang.backup.flash.empty_resource'));
44+
}
45+
46+
$filename = $this->prefix . str_slug($resource ?: 'all') . '-' . now()->format('Y-m-d') . '.zip';
47+
$pathname = $this->folder . '/' . $filename;
48+
49+
if (!$once || !File::exists($pathname)) {
50+
Zip::make(
51+
$pathname,
52+
$folders
53+
);
54+
}
55+
56+
return $pathname;
57+
}
58+
59+
/**
60+
* Get list of excluded folders from storage backup
61+
*
62+
* @return array
63+
*/
64+
protected function getExcludedResources(): array
65+
{
66+
return (array)Settings::get('storage_excluded_resources');
67+
}
68+
}

classes/ThemeBackupManager.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ class ThemeBackupManager extends BackupManager
1717
/**
1818
* Backup Theme(s) by connection name (null = default)
1919
*
20-
* @param string|null $themeName
20+
* @param string|null $resource
2121
* @param bool $once do not overwrite existing backup file
2222
* @return string backup file
2323
*/
24-
public function backup(string $themeName = null, bool $once = false): string
24+
public function backup(string $resource = null, bool $once = false): string
2525
{
26-
$themeName = $themeName ?: Theme::getActiveThemeCode();
26+
$themeName = $resource ?: Theme::getActiveThemeCode();
2727

2828
if ($themeName && File::isDirectory(themes_path($themeName))) {
2929
$filename = $this->prefix . str_slug($themeName) . '-' . now()->format('Y-m-d') . '.zip';

classes/console/BackupCommand.php

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php namespace Webula\SmallBackup\Classes\Console;
2+
3+
use Exception;
4+
use Illuminate\Console\Command;
5+
use Symfony\Component\Console\Input\InputOption;
6+
use Symfony\Component\Console\Input\InputArgument;
7+
use Webula\SmallBackup\Classes\BackupManager;
8+
9+
abstract class BackupCommand extends Command
10+
{
11+
/**
12+
* Cleanup.
13+
* @return void
14+
*/
15+
protected function cleanup(BackupManager $manager)
16+
{
17+
if (!$this->option('no-cleanup')) {
18+
try {
19+
$this->output->write('Cleanup...');
20+
$deleted = $manager->clear();
21+
$this->output->success(
22+
trans('webula.smallbackup::lang.backup.flash.expired_deleted', ['deleted' => $deleted])
23+
);
24+
} catch (Exception $ex) {
25+
$this->output->error("Cleanup failed! " . $ex->getMessage());
26+
}
27+
}
28+
}
29+
30+
/**
31+
* Get the console command options.
32+
* @return array
33+
*/
34+
protected function getOptions()
35+
{
36+
return [
37+
['once', null, InputOption::VALUE_NONE, 'Do not overwrite existing backup file.', null],
38+
['no-cleanup', 'nocleanup', InputOption::VALUE_NONE, 'Do not clean up old backups.', null],
39+
];
40+
}
41+
}

console/BackupDb.php

+4-25
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<?php namespace Webula\SmallBackup\Console;
22

33
use Exception;
4-
use Illuminate\Console\Command;
4+
use Webula\SmallBackup\Classes\Console\BackupCommand;
55
use Symfony\Component\Console\Input\InputOption;
66
use Symfony\Component\Console\Input\InputArgument;
77
use Webula\SmallBackup\Classes\DbBackupManager;
88

9-
class BackupDb extends Command
9+
class BackupDb extends BackupCommand
1010
{
1111
/**
1212
* @var string The console command name.
@@ -25,17 +25,8 @@ class BackupDb extends Command
2525
public function handle()
2626
{
2727
$manager = new DbBackupManager;
28-
if (!$this->option('no-cleanup')) {
29-
try {
30-
$this->output->write('Cleanup...');
31-
$deleted = $manager->clear();
32-
$this->output->success(
33-
trans('webula.smallbackup::lang.backup.flash.expired_deleted', ['deleted' => $deleted])
34-
);
35-
} catch (Exception $ex) {
36-
$this->output->error("Cleanup failed! " . $ex->getMessage());
37-
}
38-
}
28+
29+
$this->cleanup($manager);
3930

4031
try {
4132
$this->output->write('Backup...');
@@ -61,16 +52,4 @@ protected function getArguments()
6152
['name', InputArgument::OPTIONAL, 'Another database connection name.'],
6253
];
6354
}
64-
65-
/**
66-
* Get the console command options.
67-
* @return array
68-
*/
69-
protected function getOptions()
70-
{
71-
return [
72-
['once', null, InputOption::VALUE_NONE, 'Do not overwrite existing backup file.', null],
73-
['no-cleanup', 'nocleanup', InputOption::VALUE_NONE, 'Do not clean up old backups.', null],
74-
];
75-
}
7655
}

console/BackupStorage.php

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php namespace Webula\SmallBackup\Console;
2+
3+
use Exception;
4+
use Webula\SmallBackup\Classes\Console\BackupCommand;
5+
use Symfony\Component\Console\Input\InputOption;
6+
use Symfony\Component\Console\Input\InputArgument;
7+
use Webula\SmallBackup\Classes\StorageBackupManager;
8+
9+
class BackupStorage extends BackupCommand
10+
{
11+
/**
12+
* @var string The console command name.
13+
*/
14+
protected $name = 'smallbackup:storage';
15+
16+
/**
17+
* @var string The console command description.
18+
*/
19+
protected $description = 'Backup current or default CMS storage resource.';
20+
21+
/**
22+
* Execute the console command.
23+
* @return void
24+
*/
25+
public function handle()
26+
{
27+
$manager = new StorageBackupManager();
28+
29+
$this->cleanup($manager);
30+
31+
try {
32+
$this->output->write('Backup...');
33+
$file = $manager->backup($this->argument('name'), boolval($this->option('once')));
34+
35+
$this->output->success(
36+
trans('webula.smallbackup::lang.backup.flash.successfull_backup', ['file' => $file])
37+
);
38+
} catch (Exception $ex) {
39+
$this->output->error("Backup failed! " . $ex->getMessage());
40+
}
41+
42+
$this->output->write('Done.');
43+
44+
}
45+
46+
/**
47+
* Get the console command arguments.
48+
* @return array
49+
*/
50+
protected function getArguments()
51+
{
52+
return [
53+
['name', InputArgument::OPTIONAL, 'Another CMS storage resource name.'],
54+
];
55+
}
56+
}

console/BackupTheme.php

+4-25
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<?php namespace Webula\SmallBackup\Console;
22

33
use Exception;
4-
use Illuminate\Console\Command;
4+
use Webula\SmallBackup\Classes\Console\BackupCommand;
55
use Symfony\Component\Console\Input\InputOption;
66
use Symfony\Component\Console\Input\InputArgument;
77
use Webula\SmallBackup\Classes\ThemeBackupManager;
88

9-
class BackupTheme extends Command
9+
class BackupTheme extends BackupCommand
1010
{
1111
/**
1212
* @var string The console command name.
@@ -25,17 +25,8 @@ class BackupTheme extends Command
2525
public function handle()
2626
{
2727
$manager = new ThemeBackupManager();
28-
if (!$this->option('no-cleanup')) {
29-
try {
30-
$this->output->write('Cleanup...');
31-
$deleted = $manager->clear();
32-
$this->output->success(
33-
trans('webula.smallbackup::lang.backup.flash.expired_deleted', ['deleted' => $deleted])
34-
);
35-
} catch (Exception $ex) {
36-
$this->output->error("Cleanup failed! " . $ex->getMessage());
37-
}
38-
}
28+
29+
$this->cleanup($manager);
3930

4031
try {
4132
$this->output->write('Backup...');
@@ -61,16 +52,4 @@ protected function getArguments()
6152
['name', InputArgument::OPTIONAL, 'Another theme name.'],
6253
];
6354
}
64-
65-
/**
66-
* Get the console command options.
67-
* @return array
68-
*/
69-
protected function getOptions()
70-
{
71-
return [
72-
['once', null, InputOption::VALUE_NONE, 'Do not overwrite existing backup file.', null],
73-
['no-cleanup', 'nocleanup', InputOption::VALUE_NONE, 'Do not clean up old backups.', null],
74-
];
75-
}
7655
}

0 commit comments

Comments
 (0)