GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Xcloner_File_System::getMetadataFull()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * XCloner - Backup and Restore backup plugin for Wordpress
4
 *
5
 * class-xcloner-file-system.php
6
 * @author Liuta Ovidiu <[email protected]>
7
 *
8
 *        This program is free software; you can redistribute it and/or modify
9
 *        it under the terms of the GNU General Public License as published by
10
 *        the Free Software Foundation; either version 2 of the License, or
11
 *        (at your option) any later version.
12
 *
13
 *        This program is distributed in the hope that it will be useful,
14
 *        but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *        GNU General Public License for more details.
17
 *
18
 *        You should have received a copy of the GNU General Public License
19
 *        along with this program; if not, write to the Free Software
20
 *        Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
 *        MA 02110-1301, USA.
22
 *
23
 * @link https://github.com/ovidiul/XCloner-Wordpress
24
 *
25
 * @modified 7/31/18 3:46 PM
26
 *
27
 */
28
29
use League\Flysystem\Config;
30
use League\Flysystem\Filesystem;
31
use League\Flysystem\Util;
32
use League\Flysystem\Adapter\Local;
33
34
/**
35
 * Class Xcloner_File_System
36
 */
37
class Xcloner_File_System
38
{
39
40
    private $excluded_files = "";
41
    private $additional_regex_patterns = array();
42
    private $excluded_files_by_default = array("administrator/backups", "wp-content/backups");
43
    private $included_files_handler = "backup_files.csv";
44
    private $temp_dir_handler = ".dir";
45
    public $filesystem;
46
    public $tmp_filesystem;
47
    public $storage_filesystem;
48
    private $xcloner_container;
49
    private $diff_timestamp_start = "";
50
51
    private $logger;
52
    private $start_adapter;
53
    private $tmp_adapter;
54
    private $storage_adapter;
55
    private $xcloner_settings;
56
    private $start_filesystem;
57
    private $tmp_filesystem_append;
58
    private $storage_filesystem_append;
59
60
    private $files_counter;
61
    private $files_size;
62
    private $last_logged_file;
63
    private $folders_to_process_per_session = 25;
64
    private $backup_archive_extensions = array("tar", "tgz", "tar.gz", "gz", "csv", "encrypted", "decrypted");
65
    private $backup_name_tags = array('[time]', '[hostname]', '[domain]');
66
67
    /**
68
     * Xcloner_File_System constructor.
69
     * @param Xcloner $xcloner_container
70
     * @param string $hash
71
     */
72
    public function __construct(Xcloner $xcloner_container, $hash = "")
73
    {
74
        $this->xcloner_container = $xcloner_container;
75
76
        $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_file_system");
77
        $this->xcloner_settings = $xcloner_container->get_xcloner_settings();
78
79
        try {
80
81
            $this->start_adapter = new Local($this->xcloner_settings->get_xcloner_start_path(), LOCK_EX, '0001');
0 ignored issues
show
Bug introduced by
The method get_xcloner_start_path() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

81
            $this->start_adapter = new Local($this->xcloner_settings->/** @scrutinizer ignore-call */ get_xcloner_start_path(), LOCK_EX, '0001');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
82
            $this->start_filesystem = new Filesystem($this->start_adapter, new Config([
83
                'disable_asserts' => true,
84
            ]));
85
86
            $this->tmp_adapter = new Local($this->xcloner_settings->get_xcloner_tmp_path(), LOCK_EX, '0001');
87
            $this->tmp_filesystem = new Filesystem($this->tmp_adapter, new Config([
88
                'disable_asserts' => true,
89
            ]));
90
            $adapter = new Local($this->xcloner_settings->get_xcloner_tmp_path(), LOCK_EX | FILE_APPEND, '0001');
91
            $this->tmp_filesystem_append = new Filesystem($adapter, new Config([
92
                'disable_asserts' => true,
93
            ]));
94
95
            $adapter = new Local($this->xcloner_settings->get_xcloner_store_path(), LOCK_EX, '0001');
96
            $this->storage_filesystem = new Filesystem($adapter, new Config([
97
                'disable_asserts' => true,
98
            ]));
99
100
            $this->storage_adapter = new Local($this->xcloner_settings->get_xcloner_store_path(), FILE_APPEND,
101
                '0001');
102
            $this->storage_filesystem_append = new Filesystem($this->storage_adapter, new Config([
103
                'disable_asserts' => true,
104
            ]));
105
        }catch (Exception $e) {
106
            $this->logger->error("Filesystem Initialization Error: ".$e->getMessage());
107
        }
108
109
110
        if ($value = get_option('xcloner_directories_to_scan_per_request')) {
111
            $this->folders_to_process_per_session = $value;
112
        }
113
114
    }
115
116
    /**
117
     * Set differential timestamp date
118
     * @param string $timestamp
119
     */
120
    public function set_diff_timestamp_start($timestamp = "")
121
    {
122
        if ($timestamp) {
123
            $this->logger->info(sprintf("Setting Differential Timestamp To %s", date("Y-m-d", $timestamp)), array(
0 ignored issues
show
Bug introduced by
$timestamp of type string is incompatible with the type integer expected by parameter $timestamp of date(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

123
            $this->logger->info(sprintf("Setting Differential Timestamp To %s", date("Y-m-d", /** @scrutinizer ignore-type */ $timestamp)), array(
Loading history...
124
                "FILESYSTEM",
125
                "DIFF"
126
            ));
127
            $this->diff_timestamp_start = $timestamp;
128
        }
129
    }
130
131
    /**
132
     * Gets the differential timestamp date
133
     * @return string
134
     */
135
    public function get_diff_timestamp_start()
136
    {
137
        return $this->diff_timestamp_start;
138
    }
139
140
    private function get_xcloner_container()
141
    {
142
        return $this->xcloner_container;
143
    }
144
145
    public function set_hash($hash)
146
    {
147
        $this->xcloner_settings->set_hash($hash);
148
    }
149
150
    public function get_hash($hash)
151
    {
152
        $this->xcloner_settings->get_hash();
153
    }
154
155
    public function get_tmp_filesystem()
156
    {
157
        return $this->tmp_filesystem;
158
    }
159
160
    public function get_storage_filesystem($remote_storage_selection = "")
161
    {
162
        if ($remote_storage_selection != "") {
163
            $remote_storage = $this->get_xcloner_container()->get_xcloner_remote_storage();
164
            $method = "get_".$remote_storage_selection."_filesystem";
165
166
            if (!method_exists($remote_storage, $method)) {
167
                return false;
168
            }
169
170
            list($adapter, $filesystem) = $remote_storage->$method();
171
172
            return $filesystem;
173
        }
174
175
        return $this->storage_filesystem;
176
    }
177
178
    public function get_tmp_filesystem_adapter()
179
    {
180
        return $this->tmp_adapter;
181
    }
182
183
    public function get_tmp_filesystem_append()
184
    {
185
        return $this->tmp_filesystem_append;
186
    }
187
188
    public function get_start_adapter()
189
    {
190
        return $this->start_adapter;
191
    }
192
193
    public function get_start_filesystem()
194
    {
195
        return $this->start_filesystem;
196
    }
197
198
    public function get_logger()
199
    {
200
        return $this->logger;
201
    }
202
203
    public function get_start_path_file_info($file)
204
    {
205
        $info = $this->getMetadataFull('start_adapter', $file);
206
207
        return $this->start_filesystem->normalizeFileInfo($info);
208
    }
209
210
    /**
211
     * @param string $file
212
     */
213
    public function get_storage_path_file_info($file)
214
    {
215
        return $this->getMetadataFull('storage_adapter', $file);
216
    }
217
218
    public function get_included_files_handler($metadata = 0)
219
    {
220
        $path = $this->included_files_handler;
221
        if (!$metadata) {
222
            return $path;
223
        }
224
225
        $spl_info = $this->getMetadataFull('tmp_adapter', $path);
226
227
        return $spl_info;
228
229
    }
230
231
    public function get_temp_dir_handler()
232
    {
233
        return $this->temp_dir_handler;
234
    }
235
236
    public function get_latest_backup()
237
    {
238
        $files = $this->get_backup_archives_list();
239
240
        if (is_array($files)) {
0 ignored issues
show
introduced by
The condition is_array($files) is always true.
Loading history...
241
            $this->sort_by($files, "timestamp", "desc");
242
        }
243
244
        $new_list = array();
245
246
        foreach ($files as $key => $file) {
247
            if (!isset($file['parent'])) {
248
                $new_list[] = ($files[$key]);
249
            }
250
        }
251
252
        if (isset($new_list[0])) {
253
            return $new_list[0];
254
        }
255
    }
256
257
    public function get_latest_backups()
258
    {
259
        $files = $this->get_backup_archives_list();
260
261
        if (is_array($files)) {
0 ignored issues
show
introduced by
The condition is_array($files) is always true.
Loading history...
262
            $this->sort_by($files, "timestamp", "desc");
263
        }
264
265
        $new_list = array();
266
267
        foreach ($files as $key => $file) {
268
            if (!isset($file['parent'])) {
269
                $new_list[] = ($files[$key]);
270
            }
271
        }
272
273
        return $new_list;
274
    }
275
276
    public function get_storage_usage()
277
    {
278
        $files = $this->get_backup_archives_list();
279
        $total = 0;
280
281
        if (is_array($files)) {
0 ignored issues
show
introduced by
The condition is_array($files) is always true.
Loading history...
282
            foreach ($files as $file) {
283
                $total += $file['size'];
284
            }
285
        }
286
287
        return $total;
288
    }
289
290
    public function is_part($backup_name)
291
    {
292
        if (stristr($backup_name, "-part")) {
293
            return true;
294
        }
295
296
        return false;
297
    }
298
299
    public function is_multipart($backup_name)
300
    {
301
        if (stristr($backup_name, "-multipart")) {
302
            return true;
303
        }
304
305
        return false;
306
    }
307
308
    public function get_backup_size($backup_name)
309
    {
310
        $backup_size = $this->get_storage_filesystem()->getSize($backup_name);
311
        if ($this->is_multipart($backup_name)) {
312
            $backup_parts = $this->get_multipart_files($backup_name);
313
            foreach ($backup_parts as $part_file) {
314
                $backup_size += $this->get_storage_filesystem()->getSize($part_file);
315
            }
316
        }
317
318
        return $backup_size;
319
    }
320
321
    public function get_multipart_files($backup_name, $storage_selection = "")
322
    {
323
        $files = array();
324
325
        if ($this->is_multipart($backup_name)) {
326
            $lines = explode(PHP_EOL, $this->get_storage_filesystem($storage_selection)->read($backup_name));
327
            foreach ($lines as $line) {
328
                if ($line) {
329
                    $data = str_getcsv($line);
330
                    $files[] = $data[0];
331
                }
332
            }
333
        }
334
335
        return $files;
336
    }
337
338
    public function delete_backup_by_name($backup_name, $storage_selection = "")
339
    {
340
        if ($this->is_multipart($backup_name)) {
341
            $lines = explode(PHP_EOL, $this->get_storage_filesystem($storage_selection)->read($backup_name));
342
            foreach ($lines as $line) {
343
                if ($line) {
344
                    $data = str_getcsv($line);
345
                    $this->get_storage_filesystem($storage_selection)->delete($data[0]);
346
                }
347
            }
348
        }
349
350
        if ($this->get_storage_filesystem($storage_selection)->delete($backup_name)) {
351
            $return = true;
352
        } else {
353
            $return = false;
354
        }
355
356
        return $return;
357
    }
358
359
    public function getMetadataFull($adapter = "storage_adapter", $path)
360
    {
361
        $location = $this->$adapter->applyPathPrefix($path);
362
        $spl_info = new SplFileInfo($location);
363
364
        return ($spl_info);
365
    }
366
367
368
    public function get_backup_archives_list($storage_selection = "")
369
    {
370
        $list = array();
371
372
373
        if (method_exists($this->get_storage_filesystem($storage_selection), "listContents")) {
374
            $list = $this->get_storage_filesystem($storage_selection)->listContents();
375
        }
376
377
        $backup_files = array();
378
        $parents = array();
379
380
        foreach ($list as $file_info) {
381
            if (isset($file_info['extension']) and $file_info['extension'] == "csv") {
382
                $data = array();
383
384
                $lines = explode(PHP_EOL, $this->get_storage_filesystem($storage_selection)->read($file_info['path']));
385
                foreach ($lines as $line) {
386
                    if ($line) {
387
                        $data = str_getcsv($line);
388
                        if (is_array($data)) {
389
                            $parents[$data[0]] = $file_info['basename'];
390
                            $file_info['childs'][] = $data;
391
                            $file_info['size'] += $data[2];
392
                        }
393
                    }
394
                }
395
396
            }
397
398
            if ($file_info['type'] == 'file' and isset($file_info['extension']) and in_array($file_info['extension'],
399
                    $this->backup_archive_extensions)) {
400
                $backup_files[$file_info['path']] = $file_info;
401
            }
402
        }
403
404
        foreach ($backup_files as $key => $file_info) {
405
            if (!isset($backup_files[$key]['timestamp'])) {
406
                //$backup_files[$key]['timestamp'] = $this->get_storage_filesystem($storage_selection)->getTimestamp($file_info['path']);
407
            }
408
409
            if (isset($parents[$file_info['basename']])) {
410
                $backup_files[$key]['parent'] = $parents[$file_info['basename']];
411
            }
412
        }
413
414
        return $backup_files;
415
    }
416
417
    public function start_file_recursion($init = 0)
418
    {
419
        if ($init) {
420
            $this->logger->info(sprintf(__("Starting the filesystem scanner on root folder %s"),
421
                $this->xcloner_settings->get_xcloner_start_path()));
422
            $this->do_system_init();
423
        }
424
425
        if ($this->tmp_filesystem->has($this->get_temp_dir_handler())) {
426
            //.dir exists, we presume we have files to iterate
427
            $content = $this->tmp_filesystem->read($this->get_temp_dir_handler());
428
            $files = array_filter(explode("\n", $content));
429
            $this->tmp_filesystem->delete($this->get_temp_dir_handler());
430
431
            $counter = 0;
432
            foreach ($files as $file) {
433
                if ($counter < $this->folders_to_process_per_session) {
434
                    $this->build_files_list($file);
435
                    $counter++;
436
                } else {
437
                    $this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file."\n");
438
                }
439
            }
440
        } else {
441
            $this->build_files_list();
442
        }
443
444
        if ($this->scan_finished()) {
445
            $metadata_dumpfile = $this->get_tmp_filesystem()->getMetadata("index.html");
446
            $this->store_file($metadata_dumpfile, 'tmp_filesystem');
447
            $this->files_counter++;
448
449
            //adding included dump file to the included files list
450
            if ($this->get_tmp_filesystem()->has($this->get_included_files_handler())) {
451
                $metadata_dumpfile = $this->get_tmp_filesystem()->getMetadata($this->get_included_files_handler());
452
                $this->store_file($metadata_dumpfile, 'tmp_filesystem');
453
                $this->files_counter++;
454
            }
455
456
            //adding a default index.html to the temp xcloner folder
457
            if (!$this->get_tmp_filesystem()->has("index.html")) {
458
                $this->get_tmp_filesystem()->write("index.html", "");
459
            }
460
461
            //adding the default log file
462
            if ($this->get_tmp_filesystem()->has($this->xcloner_settings->get_logger_filename(1))) {
463
                $metadata_dumpfile = $this->get_tmp_filesystem()->getMetadata($this->xcloner_settings->get_logger_filename(1));
464
                $this->store_file($metadata_dumpfile, 'tmp_filesystem');
465
                $this->files_counter++;
466
            }
467
468
            return false;
469
        }
470
471
        return true;
472
    }
473
474
    public function get_backup_attachments()
475
    {
476
        $return = array();
477
478
        $files_list_file = $this->xcloner_settings->get_xcloner_tmp_path().DS.$this->get_included_files_handler();
479
        if (file_exists($files_list_file)) {
480
            $return[] = $files_list_file;
481
        }
482
483
        if ($this->xcloner_settings->get_xcloner_option('xcloner_enable_log')) {
484
            $log_file = $this->xcloner_settings->get_xcloner_tmp_path().DS.$this->xcloner_settings->get_logger_filename(1);
485
            if (!file_exists($log_file)) {
486
                $log_file = $this->xcloner_settings->get_xcloner_store_path().DS.$this->xcloner_settings->get_logger_filename();
487
            }
488
489
            if (file_exists($log_file)) {
490
                $return[] = $log_file;
491
            }
492
        }
493
494
        return $return;
495
    }
496
497
    public function remove_tmp_filesystem()
498
    {
499
        //delete the temporary folder
500
        $this->logger->debug(sprintf("Deleting the temporary storage folder %s",
501
            $this->xcloner_settings->get_xcloner_tmp_path()));
502
503
        $contents = $this->get_tmp_filesystem()->listContents();
504
505
        if (is_array($contents)) {
506
            foreach ($contents as $file_info) {
507
                $this->get_tmp_filesystem()->delete($file_info['path']);
508
            }
509
        }
510
511
        try {
512
            rmdir($this->xcloner_settings->get_xcloner_tmp_path());
513
        }catch (Exception $e) {
514
            //silent continue
515
        }
516
517
        return;
518
    }
519
520
    public function cleanup_tmp_directories()
521
    {
522
        $this->logger->info(sprintf(("Cleaning up the temporary directories")));
523
524
        $adapter = new Local($this->xcloner_settings->get_xcloner_tmp_path(false), LOCK_EX, '0001');
525
        $tmp_filesystem = new Filesystem($adapter, new Config([
526
            'disable_asserts' => true,
527
        ]));
528
529
        $contents = $tmp_filesystem->listContents();
530
531
        foreach ($contents as $file) {
532
533
            if (preg_match("/.xcloner-(.*)/", $file['path'])) {
534
                if ($file['timestamp'] < strtotime("-1days")) {
535
                    $tmp_filesystem->deleteDir($file['path']);
536
                    $this->logger->debug(sprintf("Delete temporary directory %s", $file['path']));
537
                }
538
            }
539
        }
540
541
        return true;
542
    }
543
544
    private function do_system_init()
545
    {
546
        $this->files_counter = 0;
547
548
        if (!$this->storage_filesystem->has("index.html")) {
549
            $this->storage_filesystem->write("index.html", "");
550
        }
551
552
        if (!$this->tmp_filesystem->has("index.html")) {
553
            $this->tmp_filesystem->write("index.html", "");
554
        }
555
556
        if ($this->tmp_filesystem->has($this->get_included_files_handler())) {
557
            $this->tmp_filesystem->delete($this->get_included_files_handler());
558
        }
559
560
        if ($this->tmp_filesystem->has($this->get_temp_dir_handler())) {
561
            $this->tmp_filesystem->delete($this->get_temp_dir_handler());
562
        }
563
    }
564
565
    public function get_scanned_files_num()
566
    {
567
        return $this->files_counter;
568
    }
569
570
    public function get_scanned_files_total_size()
571
    {
572
        return $this->files_size;
573
    }
574
575
    public function last_logged_file()
576
    {
577
        return $this->last_logged_file;
578
    }
579
580
    public static function is_regex($regex)
581
    {
582
        return preg_match("/^\^(.*)\$$/i", $regex);
583
    }
584
585
    public function set_excluded_files($excluded_files = array())
586
    {
587
        if (!is_array($excluded_files)) {
588
            $excluded_files = array();
589
        }
590
591
        foreach ($excluded_files as $excl) {
592
593
            if ($this->is_regex($excl)) {
594
                $this->additional_regex_patterns[] = $excl;
595
            }
596
        }
597
598
        $this->excluded_files = array_merge($excluded_files, $this->excluded_files_by_default);
599
600
        return $this->excluded_files;
601
    }
602
603
    public function get_excluded_files()
604
    {
605
        return $this->excluded_files_by_default;
606
    }
607
608
    public function list_directory($path)
609
    {
610
        return $this->start_filesystem->listContents($path);
611
    }
612
613
    public function build_files_list($folder = "")
614
    {
615
        $this->logger->debug(sprintf(("Building the files system list")));
616
617
        //if we start with the root folder(empty value), we initializa the file system
618
        if (!$folder) {
619
620
        }
621
622
        try {
623
624
            $files = $this->start_filesystem->listContents($folder);
625
            foreach ($files as $file) {
626
                if (!is_readable($this->xcloner_settings->get_xcloner_start_path().DS.$file['path'])) {
627
                    $this->logger->info(sprintf(__("Excluding %s from the filesystem list, file not readable"),
628
                        $file['path']), array(
629
                        "FILESYSTEM SCAN",
630
                        "NOT READABLE"
631
                    ));
632
                } elseif (!$matching_pattern = $this->is_excluded($file)) {
633
                    $this->logger->info(sprintf(__("Adding %s to the filesystem list"), $file['path']), array(
634
                        "FILESYSTEM SCAN",
635
                        "INCLUDE"
636
                    ));
637
                    $file['visibility'] = $this->start_filesystem->getVisibility($file['path']);
638
                    if ($this->store_file($file)) {
639
                        $this->files_counter++;
640
                    }
641
                    if (isset($file['size'])) {
642
                        $this->files_size += $file['size'];
643
                    }
644
645
                } else {
646
                    $this->logger->info(sprintf(__("Excluding %s from the filesystem list, matching pattern %s"),
647
                        $file['path'], $matching_pattern), array(
648
                        "FILESYSTEM SCAN",
649
                        "EXCLUDE"
650
                    ));
651
                }
652
            }
653
654
        }catch (Exception $e) {
655
656
            $this->logger->error($e->getMessage());
657
658
        }
659
660
    }
661
662
    public function estimate_read_write_time()
663
    {
664
        $tmp_file = ".xcloner".substr(md5(time()), 0, 5);
665
666
        $start_time = microtime(true);
667
668
        $data = str_repeat(rand(0, 9), 1024 * 1024); //write 1MB data
669
670
        try {
671
            $this->tmp_filesystem->write($tmp_file, $data);
672
673
            $end_time = microtime(true) - $start_time;
674
675
            $return['writing_time'] = $end_time;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$return was never initialized. Although not strictly required by PHP, it is generally a good practice to add $return = array(); before regardless.
Loading history...
676
677
            $return['reading_time'] = $this->estimate_reading_time($tmp_file);
678
679
            $this->tmp_filesystem->delete($tmp_file);
680
681
        }catch (Exception $e) {
682
683
            $this->logger->error($e->getMessage());
684
685
        }
686
687
        return $return;
688
    }
689
690
    public function backup_storage_cleanup()
691
    {
692
        $this->logger->info(sprintf(("Cleaning the backup storage on matching rules")));
693
694
        $_storage_size = 0;
695
        $_backup_files_list = array();
696
697
        //rule date limit
698
        $current_timestamp = strtotime("-".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days')." days");
699
700
        $files = $this->storage_filesystem->listContents();
701
702
        if (is_array($files)) {
703
            foreach ($files as $file) {
704
                if (isset($file['extension']) and in_array($file['extension'], $this->backup_archive_extensions)) {
705
                    $_storage_size += $file['size']; //bytes
706
                    $_backup_files_list[] = $file;
707
                }
708
            }
709
        }
710
711
712
        $this->sort_by($_backup_files_list, "timestamp", "asc");
713
714
        $_backups_counter = sizeof($_backup_files_list);
715
716
        foreach ($_backup_files_list as $file) {
717
            //processing rule folder capacity
718
            if ($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit') &&
719
                $_storage_size >= ($set_storage_limit = 1024 * 1024 * $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_capacity_limit')))    //bytes
720
            {
721
                $this->storage_filesystem->delete($file['path']);
722
                $_storage_size -= $file['size'];
723
                $this->logger->info("Deleting backup ".$file['path']." matching rule", array(
724
                    "STORAGE SIZE LIMIT",
725
                    $_storage_size." >= ".$set_storage_limit
726
                ));
727
            }
728
729
            //processing rule days limit
730
            if ($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days') && $current_timestamp >= $file['timestamp']) {
731
                $this->storage_filesystem->delete($file['path']);
732
                $this->logger->info("Deleting backup ".$file['path']." matching rule", array(
733
                    "RETENTION LIMIT TIMESTAMP",
734
                    $file['timestamp']." =< ".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_days')
735
                ));
736
            }
737
738
            //processing backup countert limit
739
            if ($this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives') && $_backups_counter >= $this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives')) {
740
                $this->storage_filesystem->delete($file['path']);
741
                $_backups_counter--;
742
                $this->logger->info("Deleting backup ".$file['path']." matching rule", array(
743
                    "BACKUP QUANTITY LIMIT",
744
                    $_backups_counter." >= ".$this->xcloner_settings->get_xcloner_option('xcloner_cleanup_retention_limit_archives')
745
                ));
746
            }
747
748
749
        }
750
751
    }
752
753
    /**
754
     * @param string $tmp_file
755
     */
756
    public function estimate_reading_time($tmp_file)
757
    {
758
        $this->logger->debug(sprintf(("Estimating file system reading time")));
759
760
        $start_time = microtime(true);
761
762
        if ($this->tmp_filesystem->has($tmp_file)) {
763
            $this->tmp_filesystem->read($tmp_file);
764
        }
765
766
        $end_time = microtime(true) - $start_time;
767
768
        return $end_time;
769
770
    }
771
772
    public function process_backup_name($name = "", $max_length = 100)
773
    {
774
        if (!$name) {
775
            $name = $this->xcloner_settings->get_default_backup_name();
776
        }
777
778
        foreach ($this->backup_name_tags as $tag) {
779
            if ($tag == '[time]') {
780
                $name = str_replace($tag, date("Y-m-d_H-i"), $name);
781
            } elseif ($tag == '[hostname]') {
782
                $name = str_replace($tag, gethostname(), $name);
783
            } elseif ($tag == '[domain]') {
784
                $domain = parse_url(admin_url(), PHP_URL_HOST);
785
                $name = str_replace($tag, $domain, $name);
786
            }
787
        }
788
789
        if ($max_length) {
790
            $name = substr($name, 0, $max_length);
791
        }
792
793
        return $name;
794
    }
795
796
    /**
797
     * @param string $field
798
     */
799
    public function sort_by(&$array, $field, $direction = 'asc')
800
    {
801
        if (strtolower($direction) == "desc" || $direction == SORT_DESC) {
802
            $direction = SORT_DESC;
803
        } else {
804
            $direction = SORT_ASC;
805
        }
806
807
        $array = $this->array_orderby($array, $field, $direction);
808
809
        return true;
810
    }
811
812
    private function array_orderby()
813
    {
814
        $args = func_get_args();
815
        $data = array_shift($args);
816
817
        foreach ($args as $n => $field) {
818
            if (is_string($field)) {
819
                $tmp = array();
820
                foreach ($data as $key => $row) {
821
                    if (is_array($row)) {
822
                        $tmp[$key] = $row[$field];
823
                    } else {
824
                        $tmp[$key] = $row->$field;
825
                    }
826
                }
827
                $args[$n] = $tmp;
828
            }
829
        }
830
        $args[] = &$data;
831
832
        call_user_func_array('array_multisort', $args);
833
834
        return array_pop($args);
835
    }
836
837
    private function check_file_diff_time($file)
838
    {
839
        if ($this->get_diff_timestamp_start() != "") {
840
            $fileMeta = $this->getMetadataFull("start_adapter", $file['path']);
841
            $timestamp = $fileMeta->getMTime();
842
            if ($timestamp < $fileMeta->getCTime()) {
843
                $timestamp = $fileMeta->getCTime();
844
            }
845
846
            if ($timestamp <= $this->get_diff_timestamp_start()) {
847
                return " file DIFF timestamp ".$timestamp." < ".$this->diff_timestamp_start;
848
            }
849
        }
850
851
        return false;
852
    }
853
854
    public function is_excluded($file)
855
    {
856
        $this->logger->debug(sprintf(("Checking if %s is excluded"), $file['path']));
857
858
        if ($xcloner_exclude_files_larger_than_mb = $this->xcloner_settings->get_xcloner_option('xcloner_exclude_files_larger_than_mb')) {
859
            if (isset($file['size']) && $file['size'] > $this->calc_to_bytes($xcloner_exclude_files_larger_than_mb)) {
860
                return "> ".$xcloner_exclude_files_larger_than_mb."MB";
861
            }
862
        }
863
864
        if (!is_array($this->excluded_files) || !sizeof($this->excluded_files)) {
0 ignored issues
show
introduced by
The condition is_array($this->excluded_files) is always false.
Loading history...
865
            $this->set_excluded_files();
866
        }
867
868
        if (is_array($this->excluded_files)) {
0 ignored issues
show
introduced by
The condition is_array($this->excluded_files) is always true.
Loading history...
869
            foreach ($this->excluded_files as $excluded_file_pattern) {
870
                if ($excluded_file_pattern == "/") {
871
                    $needle = "$";
872
                } else {
873
                    $needle = "$".$excluded_file_pattern;
874
                }
875
876
                if (strstr("$".$file['path'], $needle)) {
877
                    return $excluded_file_pattern;
878
                }
879
            }
880
        }
881
882
        if ($regex = $this->is_excluded_regex($file)) {
883
            return $regex;
884
        }
885
886
        if ($file['type'] == "file") {
887
            $check_file_diff_timestamp = $this->check_file_diff_time($file);
888
            if ($check_file_diff_timestamp) {
889
                return $check_file_diff_timestamp;
890
            }
891
        }
892
893
        return false;
894
    }
895
896
    /*REGEX examples
897
     *
898
    * exclude all except .php file
899
    * PATTERN: ^(.*)\.(.+)$(?<!(php))
900
    *
901
    * exclude all except .php and .txt
902
    * PATTERN: ^(.*)\.(.+)$(?<!(php|txt))";
903
    *
904
    * exclude all .svn and .git
905
    * PATTERN: ^(.*)\.(svn|git)(.*)$";
906
    *
907
    * exclude root directory /test
908
    * PATTERN: "^\/test(.*)$";
909
    *
910
    * exclude the wp-admin folder
911
    * PATTERN: ^(\/wp-admin)(.*)$";
912
    *
913
    * exclude the wp-admin, wp-includes and wp-config.php
914
    * PATTERN: ^\/(wp-admin|wp-includes|wp-config.php)(.*)$";
915
    *
916
    * exclude all .avi files
917
    * PATTERN: ^(.*)$(?<=(avi))";
918
    *
919
    * exclude all .jpg and gif files
920
    * PATTERN: ^(.*)$(?<=(gif|jpg))";
921
    *
922
    * exclude all cache folders from wp-content/
923
    * PATTERN: ^\/wp-content(.*)\/cache($|\/)(.*)";
924
    *
925
    * exclude the backup folders
926
    * PATTERN: (^|^\/)(wp-content\/backups|administrator\/backups)(.*)$";
927
    */
928
	private function is_excluded_regex($file)
929
	{
930
		//$this->logger->debug(sprintf(("Checking if %s is excluded"), $file['path']));
931
932
		$regex_patterns = explode(PHP_EOL, $this->xcloner_settings->get_xcloner_option('xcloner_regex_exclude'));
933
934
		if (is_array($this->additional_regex_patterns)) {
0 ignored issues
show
introduced by
The condition is_array($this->additional_regex_patterns) is always true.
Loading history...
935
			$regex_patterns = array_merge($regex_patterns, $this->additional_regex_patterns);
936
		}
937
938
		//print_r($regex_patterns);exit;
939
940
		if (is_array($regex_patterns)) {
0 ignored issues
show
introduced by
The condition is_array($regex_patterns) is always true.
Loading history...
941
			//$this->excluded_files = array();
942
			//$this->excluded_files[] ="(.*)\.(git)(.*)$";
943
			//$this->excluded_files[] ="wp-content\/backups(.*)$";
944
945
			foreach ($regex_patterns as $excluded_file_pattern) {
946
947
				if (substr($excluded_file_pattern, strlen($excluded_file_pattern) - 1,
948
						strlen($excluded_file_pattern)) == "\r") {
949
					$excluded_file_pattern = substr($excluded_file_pattern, 0, strlen($excluded_file_pattern) - 1);
950
				}
951
952
				if ($file['path'] == "/") {
953
					$needle = "/";
954
				} else {
955
					$needle = "/".$file['path'];
956
				}
957
				//echo $needle."---".$excluded_file_pattern."---\n";
958
959
				if (@preg_match("/(^|^\/)".$excluded_file_pattern."/i", $needle)) {
960
					return $excluded_file_pattern;
961
				}
962
			}
963
		}
964
965
		return false;
966
	}
967
968
	public function store_file($file, $storage = 'start_filesystem')
969
	{
970
		$this->logger->debug(sprintf("Storing %s in the backup list", $file['path']));
971
972
		if (!isset($file['size'])) {
973
			$file['size'] = 0;
974
		}
975
		if (!isset($file['visibility'])) {
976
			$file['visibility'] = "private";
977
		}
978
979
		$csv_filename = str_replace('"', '""', $file['path']);
980
981
		$line = '"'.($csv_filename).'","'.$file['timestamp'].'","'.$file['size'].'","'.$file['visibility'].'","'.$storage.'"'.PHP_EOL;
982
983
		$this->last_logged_file = $file['path'];
984
985
		if ($file['type'] == "dir") {
986
			try {
987
				$this->tmp_filesystem_append->write($this->get_temp_dir_handler(), $file['path']."\n");
988
			}catch (Exception $e) {
989
				$this->logger->error($e->getMessage());
990
			}
991
		}
992
993
		if ($this->get_diff_timestamp_start()) {
994
			if ($file['type'] != "file" && $response = $this->check_file_diff_time($file)) {
995
				$this->logger->info(sprintf("Directory %s archiving skipped on differential backup %s", $file['path'],
996
					$response), array(
997
					"FILESYSTEM SCAN",
998
					"DIR DIFF"
999
				));
1000
1001
				return false;
1002
			}
1003
		}
1004
1005
		try {
1006
			if (!$this->tmp_filesystem_append->has($this->get_included_files_handler())) {
1007
				//adding fix for UTF-8 CSV preview
1008
				$start_line = "\xEF\xBB\xBF".'"Filename","Timestamp","Size","Visibility","Storage"'.PHP_EOL;
1009
				$this->tmp_filesystem_append->write($this->get_included_files_handler(), $start_line);
1010
			}
1011
1012
			$this->tmp_filesystem_append->write($this->get_included_files_handler(), $line);
1013
1014
		}catch (Exception $e) {
1015
1016
			$this->logger->error($e->getMessage());
1017
		}
1018
1019
		return true;
1020
	}
1021
1022
	public function get_fileystem_handler()
1023
	{
1024
		return $this;
1025
	}
1026
1027
	public function get_filesystem($system = "")
1028
	{
1029
		if ($system == "storage_filesystem_append") {
1030
			return $this->storage_filesystem_append;
1031
		} elseif ($system == "tmp_filesystem_append") {
1032
			return $this->tmp_filesystem_append;
1033
		} elseif ($system == "tmp_filesystem") {
1034
			return $this->tmp_filesystem;
1035
		} elseif ($system == "storage_filesystem") {
1036
			return $this->storage_filesystem;
1037
		} else {
1038
			return $this->start_filesystem;
1039
		}
1040
	}
1041
1042
	public function get_adapter($system)
1043
	{
1044
		if ($system == "tmp_filesystem") {
1045
			return $this->tmp_adapter;
1046
		} elseif ($system == "storage_filesystem") {
1047
			return $this->storage_adapter;
1048
		} else {
1049
			return $this->start_adapter;
1050
		}
1051
	}
1052
1053
	/**
1054
	 * File scan finished
1055
	 * Method called when file scan is finished
1056
	 *
1057
	 * @return bool
1058
	 */
1059
	private function scan_finished()
1060
	{
1061
		if ($this->tmp_filesystem_append->has($this->get_temp_dir_handler()) &&
1062
			$this->tmp_filesystem_append->getSize($this->get_temp_dir_handler())) {
1063
			return false;
1064
		}
1065
1066
		if ($this->tmp_filesystem->has($this->get_temp_dir_handler())) {
1067
			$this->tmp_filesystem->delete($this->get_temp_dir_handler());
1068
		}
1069
1070
		$this->logger->debug(sprintf(("File scan finished")));
1071
1072
		return true;
1073
	}
1074
1075
	/**
1076
	 * Calculate bytes from MB value
1077
	 *
1078
	 * @param int $mb_size
1079
	 *
1080
	 * @return float|int
1081
	 */
1082
	private function calc_to_bytes($mb_size)
1083
	{
1084
		return $mb_size * (1024 * 1024);
1085
	}
1086
1087
}
1088