Completed
Push — master ( 54f974...313cde )
by Freek
06:27
created

BackupCommand::getBackupDestinationFileName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 2
Metric Value
c 4
b 1
f 2
dl 0
loc 7
rs 9.4286
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
3
namespace Spatie\Backup\Commands;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Support\Facades\Storage;
7
use Symfony\Component\Console\Input\InputOption;
8
use ZipArchive;
9
10
class BackupCommand extends Command
11
{
12
    /**
13
     * The console command name.
14
     *
15
     * @var string
16
     */
17
    protected $name = 'backup:run';
18
19
    /**
20
     * The console command description.
21
     *
22
     * @var string
23
     */
24
    protected $description = 'Run the backup';
25
26
    /**
27
     * Files that will be remove at the end of the command.
28
     *
29
     * @var array
30
     */
31
    protected $temporaryFiles = [];
32
33
    /**
34
     * Execute the console command.
35
     *
36
     * @return bool
37
     */
38
    public function fire()
39
    {
40
        $this->guardAgainstInvalidOptions();
41
42
        $this->info('Start backing up');
43
44
        $files = $this->getAllFilesToBeBackedUp();
45
46
        if (count($files) == 0) {
47
            $this->info('Nothing to backup');
48
49
            return true;
50
        }
51
52
        $backupZipFile = $this->createZip($files);
53
54
        $this->temporaryFiles[] = $backupZipFile;
55
56
        if (filesize($backupZipFile) == 0) {
57
            $this->warn('The zipfile that will be backupped has a filesize of zero.');
58
        }
59
60
        foreach ($this->getTargetFileSystems() as $fileSystem) {
61
            $this->copyFileToFileSystem($backupZipFile, $fileSystem);
62
        }
63
64
        $this->removeTemporaryFiles();
65
66
        $this->info('Backup successfully completed');
67
68
        return true;
69
    }
70
71
    /**
72
     * Return an array with path to files that should be backed up.
73
     *
74
     * @return array
75
     */
76
    protected function getAllFilesToBeBackedUp()
77
    {
78
        $files = [];
79
80
        if ((!$this->option('only-files')) && config('laravel-backup.source.backup-db')) {
81
            $files[] = ['realFile' => $this->getDatabaseDump($files), 'fileInZip' => 'dump.sql'];
82
        }
83
84
        if (!$this->option('only-db')) {
85
            $this->comment('Determining which files should be backed up...');
86
            $fileBackupHandler = app()->make('Spatie\Backup\BackupHandlers\Files\FilesBackupHandler')
87
                ->setIncludedFiles(config('laravel-backup.source.files.include'))
88
                ->setExcludedFiles(config('laravel-backup.source.files.exclude'));
89
            foreach ($fileBackupHandler->getFilesToBeBackedUp() as $file) {
90
                $files[] = ['realFile' => $file, 'fileInZip' => 'files/'.$file];
91
            }
92
        }
93
94
        return $files;
95
    }
96
97
    /**
98
     * Create a zip for the given files.
99
     *
100
     * @param $files
101
     *
102
     * @return string
103
     */
104
    protected function createZip($files)
105
    {
106
        $this->comment('Start zipping '.count($files).' files...');
107
108
        $tempZipFile = tempnam(sys_get_temp_dir(), 'laravel-backup-zip');
109
110
        $zip = new ZipArchive();
111
        $zip->open($tempZipFile, ZipArchive::CREATE);
112
113
        foreach ($files as $file) {
114
            if (file_exists($file['realFile'])) {
115
                $zip->addFile($file['realFile'], $file['fileInZip']);
116
            }
117
        }
118
119
        $zip->close();
120
121
        $this->comment('Zip created!');
122
123
        return $tempZipFile;
124
    }
125
126
    /**
127
     * Copy the given file on the given disk to the given destination.
128
     *
129
     * @param string                                      $file
130
     * @param \Illuminate\Contracts\Filesystem\Filesystem $disk
131
     * @param string                                      $destination
132
     * @param bool                                        $addIgnoreFile
133
     */
134
    protected function copyFile($file, $disk, $destination, $addIgnoreFile = false)
135
    {
136
        $destinationDirectory = dirname($destination);
137
138
        $disk->makeDirectory($destinationDirectory);
139
140
        if ($addIgnoreFile) {
141
            $this->writeIgnoreFile($disk, $destinationDirectory);
142
        }
143
144
        /*
145
         * The file could be quite large. Use a stream to copy it
146
         * to the target disk to avoid memory problems
147
         */
148
        $disk->getDriver()->writeStream($destination, fopen($file, 'r+'));
149
    }
150
151
    /**
152
     * Get the filesystems to where the database should be dumped.
153
     *
154
     * @return array
155
     */
156
    protected function getTargetFileSystems()
157
    {
158
        $fileSystems = config('laravel-backup.destination.filesystem');
159
160
        if (is_array($fileSystems)) {
161
            return $fileSystems;
162
        }
163
164
        return [$fileSystems];
165
    }
166
167
    /**
168
     * Write an ignore-file on the given disk in the given directory.
169
     *
170
     * @param \Illuminate\Contracts\Filesystem\Filesystem $disk
171
     * @param string                                      $dumpDirectory
172
     */
173
    protected function writeIgnoreFile($disk, $dumpDirectory)
174
    {
175
        $gitIgnoreContents = '*'.PHP_EOL.'!.gitignore';
176
        $disk->put($dumpDirectory.'/.gitignore', $gitIgnoreContents);
177
    }
178
179
    /**
180
     * Determine the name of the zip that contains the backup.
181
     *
182
     * @return string
183
     */
184
    protected function getBackupDestinationFileName()
185
    {
186
        $backupDirectory = config('laravel-backup.destination.path');
187
        $backupFilename = $this->getPrefix().date('YmdHis').$this->getSuffix().'.zip';
188
189
        $destination = $backupDirectory;
190
        
191
        if ($destination !='') {
192
            $destination .= '/'
193
        }
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected '}'
Loading history...
194
        
195
        $destination .= $backupFilename;
196
197
        return $destination;
198
    }
199
200
    /**
201
     * Get the prefix to be used in the filename of the backup file.
202
     *
203
     * @return string
204
     */
205
    public function getPrefix()
206
    {
207
        if ($this->option('prefix') != '') {
208
            return $this->option('prefix');
209
        }
210
211
        return config('laravel-backup.destination.prefix');
212
    }
213
214
    /**
215
     * Get the suffix to be used in the filename of the backup file.
216
     *
217
     * @return string
218
     */
219
    public function getSuffix()
220
    {
221
        if ($this->option('suffix') != '') {
222
            return $this->option('suffix');
223
        }
224
225
        return config('laravel-backup.destination.suffix');
226
    }
227
228
    /**
229
     * Copy the given file to given filesystem.
230
     *
231
     * @param string $file
232
     * @param $fileSystem
233
     */
234
    public function copyFileToFileSystem($file, $fileSystem)
235
    {
236
        $this->comment('Start uploading backup to '.$fileSystem.'-filesystem...');
237
238
        $disk = Storage::disk($fileSystem);
239
240
        $backupFilename = $this->getBackupDestinationFileName();
241
242
        $this->copyFile($file, $disk, $backupFilename, $fileSystem == 'local');
243
244
        $this->comment('Backup stored on '.$fileSystem.'-filesystem in file "'.$backupFilename.'"');
245
    }
246
247
    /**
248
     * Get the console command options.
249
     *
250
     * @return array
251
     */
252
    protected function getOptions()
253
    {
254
        return [
255
            ['only-db', null, InputOption::VALUE_NONE, 'Only backup the database.'],
256
            ['only-files', null, InputOption::VALUE_NONE, 'Only backup the files.'],
257
            ['prefix', null, InputOption::VALUE_REQUIRED, 'The name of the zip file will get prefixed with this string.'],
258
            ['suffix', null, InputOption::VALUE_REQUIRED, 'The name of the zip file will get suffixed with this string.'],
259
        ];
260
    }
261
262
    /**
263
     * Get a dump of the db.
264
     *
265
     * @return string
266
     *
267
     * @throws \Exception
268
     */
269
    protected function getDatabaseDump()
270
    {
271
        $databaseBackupHandler = app()->make('Spatie\Backup\BackupHandlers\Database\DatabaseBackupHandler');
272
273
        $filesToBeBackedUp = $databaseBackupHandler->getFilesToBeBackedUp();
274
275
        if (count($filesToBeBackedUp) != 1) {
276
            throw new \Exception('could not backup db');
277
        }
278
279
        $this->comment('Database dumped');
280
281
        $dbDumpFile = $filesToBeBackedUp[0];
282
283
        $this->temporaryFiles[] = $dbDumpFile;
284
285
        return $dbDumpFile;
286
    }
287
288
    /**
289
     * @throws \Exception
290
     */
291
    protected function guardAgainstInvalidOptions()
292
    {
293
        if ($this->option('only-db') && $this->option('only-files')) {
294
            throw new \Exception('cannot use only-db and only-files together');
295
        }
296
    }
297
298
    /**
299
     * Remove temporary files
300
     */
301
    protected function removeTemporaryFiles()
302
    {
303
        foreach ($this->temporaryFiles as $temporaryFile) {
304
            if (file_exists($temporaryFile)) {
305
                unlink($temporaryFile);
306
            }
307
        }
308
    }
309
}
310