1
|
|
|
<?php |
2
|
|
|
namespace phpbu\App\Backup; |
3
|
|
|
|
4
|
|
|
use phpbu\App\Exception; |
5
|
|
|
use phpbu\App\Util\Str; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* Backup Target class. |
9
|
|
|
* |
10
|
|
|
* @package phpbu |
11
|
|
|
* @subpackage Backup |
12
|
|
|
* @author Sebastian Feldmann <[email protected]> |
13
|
|
|
* @copyright Sebastian Feldmann <[email protected]> |
14
|
|
|
* @license https://opensource.org/licenses/MIT The MIT License (MIT) |
15
|
|
|
* @link http://phpbu.de/ |
16
|
|
|
* @since Class available since Release 1.0.0 |
17
|
|
|
*/ |
18
|
|
|
class Target |
19
|
|
|
{ |
20
|
|
|
/** |
21
|
|
|
* Absolute path to the directory where to store the backup. |
22
|
|
|
* |
23
|
|
|
* @var string |
24
|
|
|
*/ |
25
|
|
|
private $path; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Path to the backup with potential date placeholders like %d. |
29
|
|
|
* |
30
|
|
|
* @var string |
31
|
|
|
*/ |
32
|
|
|
private $pathRaw; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Indicates if the path changes over time. |
36
|
|
|
* |
37
|
|
|
* @var boolean |
38
|
|
|
*/ |
39
|
|
|
private $pathIsChanging = false; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Part of the path without placeholders |
43
|
|
|
* |
44
|
|
|
* @var string |
45
|
|
|
*/ |
46
|
|
|
private $pathNotChanging; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* List of directories containing date placeholders |
50
|
|
|
* |
51
|
|
|
* @var array |
52
|
|
|
*/ |
53
|
|
|
private $pathElementsChanging = []; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Backup filename. |
57
|
|
|
* |
58
|
|
|
* @var string |
59
|
|
|
*/ |
60
|
|
|
private $filename; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Filename with potential date placeholders like %d. |
64
|
|
|
* |
65
|
|
|
* @var string |
66
|
|
|
*/ |
67
|
|
|
private $filenameRaw; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* List of custom file suffixes f.e. 'tar' |
71
|
|
|
* |
72
|
|
|
* @var array |
73
|
|
|
*/ |
74
|
|
|
private $fileSuffixes = []; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Indicates if the filename changes over time. |
78
|
|
|
* |
79
|
|
|
* @var boolean |
80
|
|
|
*/ |
81
|
|
|
private $filenameIsChanging = false; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Target MIME type |
85
|
|
|
* |
86
|
|
|
* @var string |
87
|
|
|
*/ |
88
|
|
|
private $mimeType = 'text/plain'; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Size in bytes |
92
|
|
|
* |
93
|
|
|
* @var integer |
94
|
|
|
*/ |
95
|
|
|
private $size; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Should the file be compressed. |
99
|
|
|
* |
100
|
|
|
* @var boolean |
101
|
|
|
*/ |
102
|
|
|
private $compress = false; |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* File compression. |
106
|
|
|
* |
107
|
|
|
* @var \phpbu\App\Backup\Compressor |
108
|
|
|
*/ |
109
|
|
|
private $compressor; |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Should the file be encrypted. |
113
|
|
|
* |
114
|
|
|
* @var boolean |
115
|
|
|
*/ |
116
|
|
|
private $crypt = false; |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* File crypter. |
120
|
|
|
* |
121
|
|
|
* @var \phpbu\App\Backup\Crypter |
122
|
|
|
*/ |
123
|
|
|
private $crypter; |
124
|
|
|
|
125
|
|
|
/** |
126
|
34 |
|
* Constructor. |
127
|
|
|
* |
128
|
34 |
|
* @param string $path |
129
|
34 |
|
* @param string $filename |
130
|
34 |
|
* @param integer $time |
131
|
|
|
* @throws \phpbu\App\Exception |
132
|
|
|
*/ |
133
|
|
|
public function __construct($path, $filename, $time = null) |
134
|
|
|
{ |
135
|
|
|
$this->setPath($path, $time); |
136
|
|
|
$this->setFile($filename, $time); |
137
|
|
|
} |
138
|
|
|
|
139
|
34 |
|
/** |
140
|
|
|
* Directory setter. |
141
|
34 |
|
* |
142
|
34 |
|
* @param string $path |
143
|
10 |
|
* @param integer $time |
144
|
|
|
* @throws \phpbu\App\Exception |
145
|
10 |
|
*/ |
146
|
|
|
public function setPath($path, $time = null) |
147
|
10 |
|
{ |
148
|
10 |
|
$this->pathRaw = $path; |
149
|
10 |
|
if ($this->isContainingPlaceholder($path)) { |
150
|
10 |
|
$this->pathIsChanging = true; |
151
|
10 |
|
// path should be absolute so we remove the root slash |
152
|
10 |
|
$dirs = explode('/', substr($this->pathRaw, 1)); |
153
|
10 |
|
|
154
|
10 |
|
$this->pathNotChanging = ''; |
155
|
|
|
$foundChangingElement = false; |
156
|
10 |
|
foreach ($dirs as $d) { |
157
|
|
|
if ($foundChangingElement || $this->isContainingPlaceholder($d)) { |
158
|
10 |
|
$this->pathElementsChanging[] = $d; |
159
|
10 |
|
$foundChangingElement = true; |
160
|
24 |
|
} else { |
161
|
|
|
$this->pathNotChanging .= DIRECTORY_SEPARATOR . $d; |
162
|
34 |
|
} |
163
|
34 |
|
} |
164
|
|
|
// replace potential date placeholder |
165
|
|
|
$path = Str::replaceDatePlaceholders($path, $time); |
166
|
|
|
} else { |
167
|
|
|
$this->pathNotChanging = $path; |
168
|
|
|
} |
169
|
|
|
$this->path = rtrim($path, DIRECTORY_SEPARATOR); |
170
|
|
|
} |
171
|
34 |
|
|
172
|
|
|
/** |
173
|
34 |
|
* Does the path contain a date placeholder. |
174
|
34 |
|
* |
175
|
20 |
|
* @param string $path |
176
|
20 |
|
* @return bool |
177
|
20 |
|
*/ |
178
|
34 |
|
public function isContainingPlaceholder($path) |
179
|
34 |
|
{ |
180
|
|
|
return false !== strpos($path, '%'); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* Filename setter. |
185
|
|
|
* |
186
|
|
|
* @param string $file |
187
|
4 |
|
* @param integer $time |
188
|
|
|
*/ |
189
|
|
|
public function setFile($file, $time = null) |
190
|
4 |
|
{ |
191
|
3 |
|
$this->filenameRaw = $file; |
192
|
3 |
|
if ($this->isContainingPlaceholder($file)) { |
193
|
3 |
|
$this->filenameIsChanging = true; |
194
|
3 |
|
$file = Str::replaceDatePlaceholders($file, $time); |
195
|
3 |
|
} |
196
|
1 |
|
$this->filename = $file; |
197
|
|
|
} |
198
|
2 |
|
|
199
|
3 |
|
/** |
200
|
1 |
|
* Append another suffix to the filename. |
201
|
|
|
* |
202
|
2 |
|
* @param string $suffix |
203
|
|
|
*/ |
204
|
|
|
public function appendFileSuffix($suffix) |
205
|
|
|
{ |
206
|
|
|
$this->fileSuffixes[] = $suffix; |
207
|
|
|
} |
208
|
|
|
|
209
|
1 |
|
/** |
210
|
|
|
* Checks if the backup target directory is writable. |
211
|
1 |
|
* Creates the Directory if it doesn't exist. |
212
|
1 |
|
* |
213
|
|
|
* @throws \phpbu\App\Exception |
214
|
|
|
*/ |
215
|
|
|
public function setupPath() |
216
|
|
|
{ |
217
|
|
|
// if directory doesn't exist, create it |
218
|
|
|
if (!is_dir($this->path)) { |
219
|
5 |
|
$reporting = error_reporting(); |
220
|
|
|
error_reporting(0); |
221
|
5 |
|
$created = mkdir($this->path, 0755, true); |
222
|
|
|
error_reporting($reporting); |
223
|
|
|
if (!$created) { |
224
|
|
|
throw new Exception(sprintf('cant\'t create directory: %s', $this->path)); |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
if (!is_writable($this->path)) { |
228
|
|
|
throw new Exception(sprintf('no write permission for directory: %s', $this->path)); |
229
|
1 |
|
} |
230
|
|
|
} |
231
|
1 |
|
|
232
|
|
|
/** |
233
|
|
|
* Target file MIME type setter. |
234
|
|
|
* |
235
|
|
|
* @param string $mime |
236
|
|
|
*/ |
237
|
|
|
public function setMimeType($mime) |
238
|
|
|
{ |
239
|
|
|
$this->mimeType = $mime; |
240
|
18 |
|
} |
241
|
|
|
|
242
|
18 |
|
/** |
243
|
18 |
|
* Return the path to the backup file. |
244
|
16 |
|
* |
245
|
16 |
|
* @return string |
246
|
16 |
|
*/ |
247
|
18 |
|
public function getPath() |
248
|
|
|
{ |
249
|
|
|
return $this->path; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Return the path to the backup file. |
254
|
|
|
* |
255
|
1 |
|
* @return string |
256
|
|
|
*/ |
257
|
1 |
|
public function getPathRaw() |
258
|
|
|
{ |
259
|
|
|
return $this->pathRaw; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Return the name to the backup file. |
264
|
|
|
* |
265
|
7 |
|
* @return string |
266
|
|
|
*/ |
267
|
7 |
|
public function getFilename() |
268
|
|
|
{ |
269
|
|
|
return $this->filename |
270
|
|
|
. $this->getFilenameSuffix() |
271
|
|
|
. $this->getCompressorSuffix() |
272
|
|
|
. $this->getCrypterSuffix();; |
273
|
|
|
} |
274
|
|
|
|
275
|
3 |
|
/** |
276
|
|
|
* Return the name of the backup file without compressor or encryption suffix. |
277
|
3 |
|
* |
278
|
3 |
|
* @return string |
279
|
1 |
|
*/ |
280
|
1 |
|
public function getFilenamePlain() |
281
|
3 |
|
{ |
282
|
|
|
return $this->filename . $this->getFilenameSuffix(); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
/** |
286
|
|
|
* Return the raw name of the backup file incl. date placeholder. |
287
|
|
|
* |
288
|
|
|
* @return string |
289
|
|
|
*/ |
290
|
2 |
|
public function getFilenameRaw() |
291
|
|
|
{ |
292
|
2 |
|
return $this->filenameRaw |
293
|
2 |
|
. $this->getFilenameSuffix() |
294
|
1 |
|
. $this->getCompressorSuffix() |
295
|
|
|
. $this->getCrypterSuffix(); |
296
|
1 |
|
} |
297
|
1 |
|
|
298
|
1 |
|
/** |
299
|
|
|
* Return custom file suffix like '.tar'. |
300
|
|
|
* |
301
|
|
|
* @return string |
302
|
|
|
*/ |
303
|
|
|
public function getFilenameSuffix() |
304
|
|
|
{ |
305
|
|
|
return count($this->fileSuffixes) ? '.' . implode('.', $this->fileSuffixes) : ''; |
306
|
|
|
} |
307
|
4 |
|
|
308
|
|
|
/** |
309
|
4 |
|
* Return the compressor suffix. |
310
|
|
|
* |
311
|
|
|
* @return string |
312
|
|
|
*/ |
313
|
|
|
public function getCompressorSuffix() |
314
|
|
|
{ |
315
|
|
|
return $this->shouldBeCompressed() ? '.' . $this->compressor->getSuffix() : ''; |
316
|
|
|
} |
317
|
|
|
|
318
|
3 |
|
/** |
319
|
|
|
* Return the crypter suffix. |
320
|
3 |
|
* |
321
|
1 |
|
* @return string |
322
|
|
|
*/ |
323
|
2 |
|
public function getCrypterSuffix() |
324
|
1 |
|
{ |
325
|
|
|
return $this->shouldBeEncrypted() ? '.' . $this->crypter->getSuffix() : ''; |
326
|
1 |
|
} |
327
|
1 |
|
|
328
|
|
|
/** |
329
|
|
|
* Return file MIME type. |
330
|
|
|
* |
331
|
|
|
* @return string |
332
|
|
|
*/ |
333
|
|
|
public function getMimeType() |
334
|
|
|
{ |
335
|
14 |
|
$mimeType = $this->mimeType; |
336
|
|
|
if ($this->shouldBeCompressed()) { |
337
|
14 |
|
$mimeType = $this->compressor->getMimeType(); |
338
|
|
|
} |
339
|
14 |
|
return $mimeType; |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
/** |
343
|
|
|
* Size setter. |
344
|
|
|
* |
345
|
|
|
* @param int $size |
346
|
|
|
*/ |
347
|
1 |
|
public function setSize($size) |
348
|
|
|
{ |
349
|
1 |
|
$this->size = $size; |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* Return the actual file size in bytes. |
354
|
|
|
* |
355
|
|
|
* @throws Exception |
356
|
|
|
* @return integer |
357
|
2 |
|
*/ |
358
|
|
|
public function getSize() |
359
|
2 |
|
{ |
360
|
|
|
if (null === $this->size) { |
361
|
|
|
if (!file_exists($this)) { |
362
|
|
|
throw new Exception(sprintf('target file \'%s\' doesn\'t exist', $this->getFilename())); |
363
|
|
|
} |
364
|
|
|
$this->size = filesize($this); |
365
|
|
|
} |
366
|
|
|
return $this->size; |
367
|
7 |
|
} |
368
|
|
|
|
369
|
7 |
|
/** |
370
|
|
|
* Target file exists already. |
371
|
|
|
* |
372
|
|
|
* @param boolean $plain |
373
|
|
|
* @return boolean |
374
|
|
|
*/ |
375
|
|
|
public function fileExists($plain = false) |
376
|
|
|
{ |
377
|
1 |
|
return file_exists($this->getPathname($plain)); |
|
|
|
|
378
|
|
|
} |
379
|
1 |
|
|
380
|
|
|
/** |
381
|
|
|
* Return as backup file object. |
382
|
|
|
* |
383
|
|
|
* @return \phpbu\App\Backup\File |
384
|
|
|
*/ |
385
|
|
|
public function toFile() |
386
|
|
|
{ |
387
|
9 |
|
return new File(new \SplFileInfo($this->getPathname())); |
388
|
|
|
} |
389
|
9 |
|
|
390
|
|
|
/** |
391
|
|
|
* Deletes the target file. |
392
|
|
|
* |
393
|
|
|
* @param boolean $plain |
394
|
|
|
* @throws \phpbu\App\Exception |
395
|
|
|
*/ |
396
|
|
|
public function unlink($plain = false) |
397
|
2 |
|
{ |
398
|
|
|
if (!$this->fileExists($plain)) { |
399
|
2 |
|
throw new Exception(sprintf('target file \'%s\' doesn\'t exist', $this->getFilename($plain))); |
|
|
|
|
400
|
|
|
} |
401
|
|
|
if (!is_writable($this->getPathname($plain))) { |
|
|
|
|
402
|
|
|
throw new Exception(sprintf('can\t delete file \'%s\'', $this->getFilename($plain))); |
|
|
|
|
403
|
|
|
} |
404
|
|
|
unlink($this->getPathname($plain)); |
|
|
|
|
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* Return path and filename of the backup file. |
409
|
|
|
* |
410
|
|
|
* @return string |
411
|
|
|
*/ |
412
|
|
|
public function getPathname() |
413
|
|
|
{ |
414
|
|
|
return $this->path . DIRECTORY_SEPARATOR . $this->getFilename(); |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
/** |
418
|
|
|
* Return path and plain filename of the backup file. |
419
|
|
|
* |
420
|
|
|
* @return string |
421
|
|
|
*/ |
422
|
|
|
public function getPathnamePlain() |
423
|
|
|
{ |
424
|
|
|
return $this->path . DIRECTORY_SEPARATOR . $this->getFilenamePlain(); |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
/** |
428
|
7 |
|
* Is dirname configured with any date placeholders. |
429
|
|
|
* |
430
|
7 |
|
* @return boolean |
431
|
7 |
|
*/ |
432
|
7 |
|
public function hasChangingPath() |
433
|
|
|
{ |
434
|
|
|
return $this->pathIsChanging; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* Return the part of the path that is not changing. |
439
|
2 |
|
* |
440
|
|
|
* @return string |
441
|
2 |
|
*/ |
442
|
|
|
public function getPathThatIsNotChanging() |
443
|
|
|
{ |
444
|
|
|
return $this->pathNotChanging; |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
/** |
448
|
|
|
* Changing path elements getter. |
449
|
20 |
|
* |
450
|
|
|
* @return array |
451
|
20 |
|
*/ |
452
|
|
|
public function getChangingPathElements() |
453
|
|
|
{ |
454
|
|
|
return $this->pathElementsChanging; |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
/** |
458
|
|
|
* Return amount of changing path elements. |
459
|
1 |
|
* |
460
|
|
|
* @return integer |
461
|
1 |
|
*/ |
462
|
|
|
public function countChangingPathElements() |
463
|
|
|
{ |
464
|
|
|
return count($this->pathElementsChanging); |
465
|
|
|
} |
466
|
|
|
|
467
|
|
|
/** |
468
|
|
|
* Filename configured with any date placeholders. |
469
|
2 |
|
* |
470
|
|
|
* @return boolean |
471
|
2 |
|
*/ |
472
|
2 |
|
public function hasChangingFilename() |
473
|
2 |
|
{ |
474
|
|
|
return $this->filenameIsChanging; |
475
|
|
|
} |
476
|
|
|
|
477
|
|
|
/** |
478
|
|
|
* Disable file compression. |
479
|
|
|
*/ |
480
|
1 |
|
public function disableCompression() |
481
|
|
|
{ |
482
|
1 |
|
$this->compress = false; |
483
|
|
|
} |
484
|
|
|
|
485
|
|
|
/** |
486
|
|
|
* Enable file compression. |
487
|
|
|
* |
488
|
|
|
* @throws \phpbu\App\Exception |
489
|
|
|
*/ |
490
|
|
|
public function enableCompression() |
491
|
|
|
{ |
492
|
|
|
if (null == $this->compressor) { |
493
|
|
|
throw new Exception('can\'t enable compression without a compressor'); |
494
|
|
|
} |
495
|
|
|
$this->compress = true; |
496
|
|
|
} |
497
|
|
|
|
498
|
16 |
|
/** |
499
|
|
|
* Compressor setter. |
500
|
16 |
|
* |
501
|
|
|
* @param \phpbu\App\Backup\Compressor $compressor |
502
|
|
|
*/ |
503
|
|
|
public function setCompressor(Compressor $compressor) |
504
|
|
|
{ |
505
|
|
|
$this->compressor = $compressor; |
506
|
|
|
$this->compress = true; |
507
|
|
|
} |
508
|
2 |
|
|
509
|
|
|
/** |
510
|
2 |
|
* Compressor getter. |
511
|
|
|
* |
512
|
|
|
* @return \phpbu\App\Backup\Compressor |
513
|
|
|
*/ |
514
|
|
|
public function getCompressor() |
515
|
|
|
{ |
516
|
|
|
return $this->compressor; |
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
/** |
520
|
|
|
* Is a compressor set? |
521
|
|
|
* |
522
|
|
|
* @return boolean |
523
|
|
|
*/ |
524
|
|
|
public function shouldBeCompressed() |
525
|
|
|
{ |
526
|
|
|
return $this->compress !== false; |
527
|
|
|
} |
528
|
|
|
|
529
|
|
|
/** |
530
|
|
|
* Crypter setter. |
531
|
|
|
* |
532
|
|
|
* @param \phpbu\App\Backup\Crypter $crypter |
533
|
|
|
*/ |
534
|
|
|
public function setCrypter(Crypter $crypter) |
535
|
|
|
{ |
536
|
|
|
$this->crypter = $crypter; |
537
|
|
|
$this->crypt = true; |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
/** |
541
|
|
|
* Crypter getter. |
542
|
|
|
* |
543
|
|
|
* @return \phpbu\App\Backup\Crypter |
544
|
|
|
*/ |
545
|
|
|
public function getCrypter() |
546
|
|
|
{ |
547
|
|
|
return $this->crypter; |
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
/** |
551
|
|
|
* Disable file encryption. |
552
|
|
|
*/ |
553
|
|
|
public function disableEncryption() |
554
|
|
|
{ |
555
|
|
|
$this->crypt = false; |
556
|
|
|
} |
557
|
|
|
|
558
|
|
|
/** |
559
|
|
|
* Is a crypter set? |
560
|
|
|
* |
561
|
|
|
* @return boolean |
562
|
|
|
*/ |
563
|
|
|
public function shouldBeEncrypted() |
564
|
|
|
{ |
565
|
|
|
return $this->crypt !== false; |
566
|
|
|
} |
567
|
|
|
|
568
|
|
|
/** |
569
|
|
|
* Magic to string method. |
570
|
|
|
* |
571
|
|
|
* @return string |
572
|
|
|
*/ |
573
|
|
|
public function __toString() |
574
|
|
|
{ |
575
|
|
|
return $this->getPathname(); |
576
|
|
|
} |
577
|
|
|
} |
578
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.