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
|
|||||
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
$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
![]() |
|||||
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
|
|||||
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
|
|||||
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
|
|||||
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
|
|||||
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
|
|||||
865 | $this->set_excluded_files(); |
||||
866 | } |
||||
867 | |||||
868 | if (is_array($this->excluded_files)) { |
||||
0 ignored issues
–
show
|
|||||
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
|
|||||
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
|
|||||
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 |
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.