1 | <?php |
||||||
2 | /** |
||||||
3 | * XCloner - Backup and Restore backup plugin for Wordpress |
||||||
4 | * |
||||||
5 | * class-xcloner-archive.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:10 PM |
||||||
26 | * |
||||||
27 | */ |
||||||
28 | |||||||
29 | use splitbrain\PHPArchive\Tar; |
||||||
30 | use splitbrain\PHPArchive\Archive; |
||||||
31 | use splitbrain\PHPArchive\FileInfo; |
||||||
32 | |||||||
33 | /** |
||||||
34 | * Class responsible for adding files to Tar |
||||||
35 | * Class Xcloner_Archive |
||||||
36 | */ |
||||||
37 | class Xcloner_Archive extends Tar |
||||||
38 | { |
||||||
39 | /** |
||||||
40 | * Process file size per API request |
||||||
41 | * @var float|int |
||||||
42 | */ |
||||||
43 | private $file_size_per_request_limit = 52428800; //50MB = 52428800; 1MB = 1048576 |
||||||
44 | /** |
||||||
45 | * Files count to process per API request |
||||||
46 | * @var int |
||||||
47 | */ |
||||||
48 | private $files_to_process_per_request = 250; //block of 512 bytes |
||||||
49 | /** |
||||||
50 | * Compression level, 0-uncompressed, 9-maximum compression |
||||||
51 | * @var int |
||||||
52 | */ |
||||||
53 | private $compression_level = 0; //0-9 , 0 uncompressed |
||||||
54 | /** |
||||||
55 | * Split backup size limit |
||||||
56 | * Create a new backup archive file once the set size is reached |
||||||
57 | * @var float|int |
||||||
58 | */ |
||||||
59 | private $xcloner_split_backup_limit = 2048; //2048MB |
||||||
60 | /** |
||||||
61 | * Number of processed bytes |
||||||
62 | * @var int |
||||||
63 | */ |
||||||
64 | private $processed_size_bytes = 0; |
||||||
65 | |||||||
66 | /** |
||||||
67 | * The backup name encryption suffix |
||||||
68 | * @var string |
||||||
69 | */ |
||||||
70 | private $encrypt_suffix = "-enc"; |
||||||
71 | |||||||
72 | /** |
||||||
73 | * Archive name |
||||||
74 | * @var string |
||||||
75 | */ |
||||||
76 | private $archive_name; |
||||||
77 | /** |
||||||
78 | * @var Tar |
||||||
79 | */ |
||||||
80 | private $backup_archive; |
||||||
81 | /** |
||||||
82 | * @var Xcloner_File_System |
||||||
83 | */ |
||||||
84 | private $filesystem; |
||||||
85 | /** |
||||||
86 | * @var Xcloner_Logger |
||||||
87 | */ |
||||||
88 | private $logger; |
||||||
89 | /** |
||||||
90 | * @var Xcloner_Settings |
||||||
91 | */ |
||||||
92 | private $xcloner_settings; |
||||||
93 | |||||||
94 | /** |
||||||
95 | * [__construct description] |
||||||
96 | * @param Xcloner $xcloner_container XCloner Container |
||||||
97 | * @param string $archive_name Achive Name |
||||||
98 | */ |
||||||
99 | public function __construct(Xcloner $xcloner_container, $archive_name = "") |
||||||
100 | { |
||||||
101 | $this->filesystem = $xcloner_container->get_xcloner_filesystem(); |
||||||
102 | $this->logger = $xcloner_container->get_xcloner_logger()->withName("xcloner_archive"); |
||||||
103 | $this->xcloner_settings = $xcloner_container->get_xcloner_settings(); |
||||||
104 | |||||||
105 | if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_size_limit_per_request')) { |
||||||
0 ignored issues
–
show
|
|||||||
106 | $this->file_size_per_request_limit = $value * 1024 * 1024; |
||||||
107 | } //MB |
||||||
108 | |||||||
109 | if ($value = $this->xcloner_settings->get_xcloner_option('xcloner_files_to_process_per_request')) { |
||||||
110 | $this->files_to_process_per_request = $value; |
||||||
111 | } |
||||||
112 | |||||||
113 | if ($value = get_option('xcloner_backup_compression_level')) { |
||||||
114 | $this->compression_level = $value; |
||||||
115 | } |
||||||
116 | |||||||
117 | if ($value = get_option('xcloner_split_backup_limit')) { |
||||||
118 | $this->xcloner_split_backup_limit = $value; |
||||||
119 | } |
||||||
120 | |||||||
121 | $this->xcloner_split_backup_limit = $this->xcloner_split_backup_limit * 1024 * 1024; //transform to bytes |
||||||
122 | |||||||
123 | if (isset($archive_name) && $archive_name) { |
||||||
124 | $this->set_archive_name($archive_name); |
||||||
125 | } |
||||||
126 | } |
||||||
127 | |||||||
128 | /* |
||||||
129 | * Rename backup archive |
||||||
130 | * |
||||||
131 | * @param string $old_name |
||||||
132 | * @param string $new_name |
||||||
133 | * |
||||||
134 | */ |
||||||
135 | public function rename_archive($old_name, $new_name) |
||||||
136 | { |
||||||
137 | $this->logger->info(sprintf("Renaming backup archive %s to %s", $old_name, $new_name)); |
||||||
138 | $storage_filesystem = $this->filesystem->get_storage_filesystem(); |
||||||
139 | $storage_filesystem->rename($old_name, $new_name); |
||||||
140 | } |
||||||
141 | |||||||
142 | /* |
||||||
143 | * |
||||||
144 | * Set the backup archive name |
||||||
145 | * |
||||||
146 | */ |
||||||
147 | public function set_archive_name($name = "", $part = 0, $encrypt_prefix = false) |
||||||
148 | { |
||||||
149 | |||||||
150 | $this->archive_name = $this->filesystem->process_backup_name($name); |
||||||
151 | |||||||
152 | if($encrypt_prefix) { |
||||||
153 | $this->archive_name .= $this->encrypt_suffix; |
||||||
154 | } |
||||||
155 | |||||||
156 | if ($diff_timestamp_start = $this->filesystem->get_diff_timestamp_start()) { |
||||||
157 | //$this->archive_name = $this->archive_name."-diff-".date("Y-m-d_H-i",$diff_timestamp_start); |
||||||
158 | $new_name = $this->archive_name; |
||||||
159 | |||||||
160 | if (!stristr($new_name, "-diff")) { |
||||||
161 | $new_name = $this->archive_name."-diff".date("Y-m-d_H-i", $diff_timestamp_start); |
||||||
0 ignored issues
–
show
$diff_timestamp_start 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
![]() |
|||||||
162 | } |
||||||
163 | |||||||
164 | $this->archive_name = $new_name; |
||||||
165 | |||||||
166 | } |
||||||
167 | |||||||
168 | if (isset($part) and $part) { |
||||||
169 | $new_name = preg_replace('/-part(\d*)/', "-part".$part, $this->archive_name); |
||||||
170 | if (!stristr($new_name, "-part")) { |
||||||
171 | $new_name = $this->archive_name."-part".$part; |
||||||
172 | } |
||||||
173 | |||||||
174 | $this->archive_name = $new_name; |
||||||
175 | } |
||||||
176 | |||||||
177 | return $this; |
||||||
178 | } |
||||||
179 | |||||||
180 | /* |
||||||
181 | * |
||||||
182 | * Returns the backup archive name |
||||||
183 | * |
||||||
184 | * @return string archive name |
||||||
185 | */ |
||||||
186 | public function get_archive_name() |
||||||
187 | { |
||||||
188 | return $this->archive_name; |
||||||
189 | } |
||||||
190 | |||||||
191 | /* |
||||||
192 | * |
||||||
193 | * Returns the multipart naming for the backup archive |
||||||
194 | * |
||||||
195 | * @return string multi-part backup name |
||||||
196 | */ |
||||||
197 | public function get_archive_name_multipart() |
||||||
198 | { |
||||||
199 | $new_name = preg_replace('/-part(\d*)/', "", $this->archive_name); |
||||||
200 | return $new_name."-multipart".$this->xcloner_settings->get_backup_extension_name(".csv"); |
||||||
201 | } |
||||||
202 | |||||||
203 | /* |
||||||
204 | * |
||||||
205 | * Returns the full backup name including extension |
||||||
206 | * |
||||||
207 | */ |
||||||
208 | public function get_archive_name_with_extension() |
||||||
209 | { |
||||||
210 | return $this->archive_name.$this->xcloner_settings->get_backup_extension_name(); |
||||||
211 | } |
||||||
212 | |||||||
213 | /* |
||||||
214 | * |
||||||
215 | * Send notification error by E-Mail |
||||||
216 | * |
||||||
217 | * @param $to |
||||||
218 | * @param $from |
||||||
219 | * @param $subject |
||||||
220 | * @param $backup_name |
||||||
221 | * @param $params |
||||||
222 | * @param $error_message |
||||||
223 | * |
||||||
224 | * @return bool |
||||||
225 | */ |
||||||
226 | |||||||
227 | /** |
||||||
228 | * @param string $error_message |
||||||
229 | */ |
||||||
230 | public function send_notification_error($to, $from, $subject, $backup_name, $params, $error_message) |
||||||
0 ignored issues
–
show
The parameter
$backup_name is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() The parameter
$params is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||||
231 | { |
||||||
232 | |||||||
233 | $body = ""; |
||||||
234 | $body .= sprintf(__("Backup Site Url: %s"), get_site_url()); |
||||||
235 | $body .= "<br /><>"; |
||||||
236 | |||||||
237 | $body .= sprintf(__("Error Message: %s"), $error_message); |
||||||
238 | |||||||
239 | $this->logger->info(sprintf("Sending backup error notification to %s", $to)); |
||||||
240 | |||||||
241 | $admin_email = get_option("admin_email"); |
||||||
242 | |||||||
243 | $headers = array('Content-Type: text/html; charset=UTF-8'); |
||||||
244 | |||||||
245 | if ($admin_email and $from) { |
||||||
246 | $headers[] = 'From: '.$from.' <'.$admin_email.'>'; |
||||||
247 | } |
||||||
248 | |||||||
249 | $return = wp_mail($to, $subject, $body, $headers); |
||||||
250 | |||||||
251 | return $return; |
||||||
252 | } |
||||||
253 | |||||||
254 | /* |
||||||
255 | * |
||||||
256 | * Send backup archive notfication by E-Mail |
||||||
257 | * |
||||||
258 | * @param $to |
||||||
259 | * @param $from |
||||||
260 | * @param $subject |
||||||
261 | * @param $backup_name |
||||||
262 | * @param $params |
||||||
263 | * @param string $error_message |
||||||
264 | * @param array $additional |
||||||
265 | * |
||||||
266 | * @return bool |
||||||
267 | */ |
||||||
268 | public function send_notification( |
||||||
269 | $to, |
||||||
270 | $from, |
||||||
271 | $subject, |
||||||
272 | $backup_name, |
||||||
273 | $params, |
||||||
274 | $error_message = "", |
||||||
275 | $additional = array() |
||||||
276 | ) { |
||||||
277 | if (!$from) { |
||||||
278 | $from = "XCloner Backup"; |
||||||
279 | } |
||||||
280 | |||||||
281 | if (($error_message)) { |
||||||
282 | return $this->send_notification_error($to, $from, $subject, $backup_name, $params, $error_message); |
||||||
283 | } |
||||||
284 | |||||||
285 | $params = (array)$params; |
||||||
286 | |||||||
287 | if (!$subject) { |
||||||
288 | $subject = sprintf(__("New backup generated %s"), $backup_name); |
||||||
289 | } |
||||||
290 | |||||||
291 | $body = sprintf(__("Generated Backup Size: %s"), size_format($this->filesystem->get_backup_size($backup_name))); |
||||||
0 ignored issues
–
show
It seems like
size_format($this->files...kup_size($backup_name)) can also be of type false ; however, parameter $args of sprintf() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
292 | $body .= "<br /><br />"; |
||||||
293 | |||||||
294 | if (isset($additional['lines_total'])) { |
||||||
295 | $body .= sprintf(__("Total files added: %s"), $additional['lines_total']); |
||||||
296 | $body .= "<br /><br />"; |
||||||
297 | } |
||||||
298 | |||||||
299 | $backup_parts = $this->filesystem->get_multipart_files($backup_name); |
||||||
300 | |||||||
301 | if (!$backups_counter = sizeof($backup_parts)) { |
||||||
302 | $backups_counter = 1; |
||||||
303 | } |
||||||
304 | |||||||
305 | $body .= sprintf(__("Backup Parts: %s"), $backups_counter); |
||||||
306 | $body .= "<br />"; |
||||||
307 | |||||||
308 | if (sizeof($backup_parts)) { |
||||||
309 | $body .= implode("<br />", $backup_parts); |
||||||
310 | $body .= "<br />"; |
||||||
311 | } |
||||||
312 | |||||||
313 | $body .= "<br />"; |
||||||
314 | |||||||
315 | $body .= sprintf(__("Backup Site Url: %s"), get_site_url()); |
||||||
316 | $body .= "<br />"; |
||||||
317 | |||||||
318 | if (isset($params['backup_params']->backup_comments)) { |
||||||
319 | $body .= __("Backup Comments: ").$params['backup_params']->backup_comments; |
||||||
320 | $body .= "<br /><br />"; |
||||||
321 | } |
||||||
322 | |||||||
323 | if ($this->xcloner_settings->get_xcloner_option('xcloner_enable_log')) { |
||||||
324 | $body .= __("Latest 50 Log Lines: ")."<br />".implode("<br />\n", |
||||||
325 | $this->logger->getLastDebugLines(50)); |
||||||
0 ignored issues
–
show
It seems like
$this->logger->getLastDebugLines(50) can also be of type false ; however, parameter $pieces of implode() does only seem to accept array , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
326 | } |
||||||
327 | |||||||
328 | $attachments = $this->filesystem->get_backup_attachments(); |
||||||
329 | |||||||
330 | $attachments_archive = $this->xcloner_settings->get_xcloner_tmp_path().DS."info.tgz"; |
||||||
331 | |||||||
332 | $tar = new Tar(); |
||||||
333 | $tar->create($attachments_archive); |
||||||
334 | |||||||
335 | foreach ($attachments as $key => $file) { |
||||||
336 | $tar->addFile($file, basename($file)); |
||||||
337 | } |
||||||
338 | $tar->close(); |
||||||
339 | |||||||
340 | $this->logger->info(sprintf("Sending backup notification to %s", $to)); |
||||||
341 | |||||||
342 | $admin_email = get_option("admin_email"); |
||||||
343 | |||||||
344 | $headers = array('Content-Type: text/html; charset=UTF-8', 'From: '.$from.' <'.$admin_email.'>'); |
||||||
0 ignored issues
–
show
Are you sure
$admin_email of type false|mixed can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
345 | |||||||
346 | $return = wp_mail($to, $subject, $body, $headers, array($attachments_archive)); |
||||||
347 | |||||||
348 | return $return; |
||||||
349 | } |
||||||
350 | |||||||
351 | /* |
||||||
352 | * |
||||||
353 | * Incremental Backup method |
||||||
354 | * |
||||||
355 | */ |
||||||
356 | public function start_incremental_backup($backup_params, $extra_params, $init) |
||||||
357 | { |
||||||
358 | $return = array(); |
||||||
359 | |||||||
360 | if (!isset($extra_params['backup_part'])) { |
||||||
361 | $extra_params['backup_part'] = 0; |
||||||
362 | } |
||||||
363 | |||||||
364 | $return['extra']['backup_part'] = $extra_params['backup_part']; |
||||||
365 | |||||||
366 | if (isset($extra_params['backup_archive_name'])) { |
||||||
367 | $this->set_archive_name($extra_params['backup_archive_name'], $return['extra']['backup_part']); |
||||||
368 | } else { |
||||||
369 | $encrypt = false; |
||||||
370 | if(isset($backup_params['backup_encrypt']) && $backup_params['backup_encrypt']) { |
||||||
371 | $encrypt = true; |
||||||
372 | } |
||||||
373 | $this->set_archive_name($backup_params['backup_name'], 0, $encrypt); |
||||||
374 | } |
||||||
375 | |||||||
376 | if (!$this->get_archive_name()) { |
||||||
377 | $this->set_archive_name(); |
||||||
378 | } |
||||||
379 | |||||||
380 | $this->backup_archive = new Tar(); |
||||||
381 | $this->backup_archive->setCompression($this->compression_level); |
||||||
382 | |||||||
383 | $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension()); |
||||||
384 | |||||||
385 | if ($init) { |
||||||
386 | $this->logger->info(sprintf(__("Initializing the backup archive %s"), $this->get_archive_name())); |
||||||
387 | |||||||
388 | $this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename()); |
||||||
389 | |||||||
390 | $return['extra']['backup_init'] = 1; |
||||||
391 | |||||||
392 | } else { |
||||||
393 | $this->logger->info(sprintf(__("Opening for append the backup archive %s"), $this->get_archive_name())); |
||||||
394 | |||||||
395 | $this->backup_archive->openForAppend($archive_info->getPath().DS.$archive_info->getFilename()); |
||||||
396 | |||||||
397 | $return['extra']['backup_init'] = 0; |
||||||
398 | |||||||
399 | } |
||||||
400 | |||||||
401 | $return['extra']['backup_archive_name'] = $this->get_archive_name(); |
||||||
402 | $return['extra']['backup_archive_name_full'] = $this->get_archive_name_with_extension(); |
||||||
403 | |||||||
404 | if (!isset($extra_params['start_at_line'])) { |
||||||
405 | $extra_params['start_at_line'] = 0; |
||||||
406 | } |
||||||
407 | |||||||
408 | if (!isset($extra_params['start_at_byte'])) { |
||||||
409 | $extra_params['start_at_byte'] = 0; |
||||||
410 | } |
||||||
411 | |||||||
412 | if (!$this->filesystem->get_tmp_filesystem()->has($this->filesystem->get_included_files_handler())) { |
||||||
413 | $this->logger->error(sprintf("Missing the includes file handler %s, aborting...", |
||||||
414 | $this->filesystem->get_included_files_handler())); |
||||||
415 | |||||||
416 | $return['finished'] = 1; |
||||||
417 | return $return; |
||||||
418 | } |
||||||
419 | |||||||
420 | $included_files_handler = $this->filesystem->get_included_files_handler(1); |
||||||
421 | |||||||
422 | $file = new SplFileObject($included_files_handler); |
||||||
423 | |||||||
424 | $file->seek(PHP_INT_MAX); |
||||||
425 | |||||||
426 | $return['extra']['lines_total'] = ($file->key() - 1); |
||||||
427 | |||||||
428 | //we skip the first CSV line with headers |
||||||
429 | if (!$extra_params['start_at_line']) { |
||||||
430 | $file->seek(1); |
||||||
431 | } else { |
||||||
432 | $file->seek($extra_params['start_at_line'] + 1); |
||||||
433 | } |
||||||
434 | |||||||
435 | $this->processed_size_bytes = 0; |
||||||
436 | |||||||
437 | $counter = 0; |
||||||
438 | |||||||
439 | $start_byte = $extra_params['start_at_byte']; |
||||||
440 | |||||||
441 | $byte_limit = 0; |
||||||
0 ignored issues
–
show
|
|||||||
442 | |||||||
443 | while (!$file->eof() and $counter <= $this->files_to_process_per_request) { |
||||||
444 | $current_line_str = $file->current(); |
||||||
445 | |||||||
446 | $line = str_getcsv($current_line_str); |
||||||
0 ignored issues
–
show
It seems like
$current_line_str can also be of type array ; however, parameter $input of str_getcsv() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
447 | |||||||
448 | $relative_path = stripslashes($line[0]); |
||||||
449 | |||||||
450 | $start_filesystem = "start_filesystem"; |
||||||
451 | |||||||
452 | if (isset($line[4])) { |
||||||
453 | $start_filesystem = $line[4]; |
||||||
454 | } |
||||||
455 | |||||||
456 | //$adapter = $this->filesystem->get_adapter($start_filesystem); |
||||||
457 | |||||||
458 | if (!$relative_path || !$this->filesystem->get_filesystem($start_filesystem)->has($relative_path)) { |
||||||
459 | if ($relative_path != "") { |
||||||
460 | $this->logger->error(sprintf("Could not add file %b to backup archive, file not found", |
||||||
461 | $relative_path)); |
||||||
462 | } |
||||||
463 | |||||||
464 | $extra_params['start_at_line']++; |
||||||
465 | $file->next(); |
||||||
466 | continue; |
||||||
467 | } |
||||||
468 | |||||||
469 | $file_info = $this->filesystem->get_filesystem($start_filesystem)->getMetadata($relative_path); |
||||||
470 | |||||||
471 | if (!isset($file_info['size'])) { |
||||||
472 | $file_info['size'] = 0; |
||||||
473 | } |
||||||
474 | |||||||
475 | if ($start_filesystem == "tmp_filesystem") { |
||||||
476 | $file_info['archive_prefix_path'] = $this->xcloner_settings->get_xcloner_tmp_path_suffix(); |
||||||
477 | } |
||||||
478 | |||||||
479 | $byte_limit = (int)$this->file_size_per_request_limit / 512; |
||||||
480 | |||||||
481 | $append = 0; |
||||||
482 | |||||||
483 | if ($file_info['size'] > $byte_limit * 512 or $start_byte) { |
||||||
484 | $append = 1; |
||||||
485 | } |
||||||
486 | |||||||
487 | if (!isset($return['extra']['backup_size'])) { |
||||||
488 | $return['extra']['backup_size'] = 0; |
||||||
489 | } |
||||||
490 | |||||||
491 | $return['extra']['backup_size'] = $archive_info->getSize(); |
||||||
492 | |||||||
493 | $estimated_new_size = $return['extra']['backup_size'] + $file_info['size']; |
||||||
494 | |||||||
495 | //we create a new backup part if we reach the Split Achive Limit |
||||||
496 | if ($this->xcloner_split_backup_limit and ($estimated_new_size > $this->xcloner_split_backup_limit) and (!$start_byte)) { |
||||||
497 | $this->logger->info(sprintf("Backup size limit %s bytes reached, file add estimate %s, attempt to create a new archive ", |
||||||
498 | $this->xcloner_split_backup_limit, $estimated_new_size)); |
||||||
499 | list($archive_info, $return['extra']['backup_part']) = $this->create_new_backup_part($return['extra']['backup_part']); |
||||||
500 | |||||||
501 | if ($file_info['size'] > $this->xcloner_split_backup_limit) { |
||||||
502 | $this->logger->info(sprintf("Excluding %s file as it's size(%s) is bigger than the backup split limit of %s and it won't fit a single backup file", |
||||||
503 | $file_info['path'], $file_info['size'], $this->xcloner_split_backup_limit)); |
||||||
504 | $extra_params['start_at_line']++; |
||||||
505 | } |
||||||
506 | |||||||
507 | $return['extra']['start_at_line'] = $extra_params['start_at_line']; |
||||||
508 | $return['extra']['start_at_byte'] = 0; |
||||||
509 | |||||||
510 | $return['finished'] = 0; |
||||||
511 | |||||||
512 | return $return; |
||||||
513 | } |
||||||
514 | |||||||
515 | list($bytes_wrote, $last_position) = $this->add_file_to_archive($file_info, $start_byte, $byte_limit, |
||||||
516 | $append, $start_filesystem); |
||||||
517 | $this->processed_size_bytes += $bytes_wrote; |
||||||
518 | |||||||
519 | //echo" - processed ".$this->processed_size_bytes." bytes ".$this->file_size_per_request_limit." last_position:".$last_position." \n"; |
||||||
520 | $return['extra']['processed_file'] = $file_info['path']; |
||||||
521 | $return['extra']['processed_file_size'] = $file_info['size']; |
||||||
522 | $return['extra']['backup_size'] = $archive_info->getSize(); |
||||||
523 | |||||||
524 | if ($last_position > 0) { |
||||||
525 | $start_byte = $last_position; |
||||||
526 | } else { |
||||||
527 | $extra_params['start_at_line']++; |
||||||
528 | $file->next(); |
||||||
529 | $start_byte = 0; |
||||||
530 | $counter++; |
||||||
531 | } |
||||||
532 | |||||||
533 | if ($this->processed_size_bytes >= $this->file_size_per_request_limit) { |
||||||
534 | clearstatcache(); |
||||||
535 | $return['extra']['backup_size'] = $archive_info->getSize(); |
||||||
536 | |||||||
537 | $return['finished'] = 0; |
||||||
538 | $return['extra']['start_at_line'] = $extra_params['start_at_line']; |
||||||
539 | $return['extra']['start_at_byte'] = $last_position; |
||||||
540 | $this->logger->info(sprintf("Reached the maximum %s request data limit, returning response", |
||||||
541 | $this->file_size_per_request_limit)); |
||||||
542 | return $return; |
||||||
543 | } |
||||||
544 | } |
||||||
545 | |||||||
546 | if (!$file->eof()) { |
||||||
547 | clearstatcache(); |
||||||
548 | $return['extra']['backup_size'] = $archive_info->getSize(); |
||||||
549 | |||||||
550 | $return['finished'] = 0; |
||||||
551 | $return['extra']['start_at_line'] = $extra_params['start_at_line']; |
||||||
552 | $return['extra']['start_at_byte'] = $last_position; |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
553 | $this->logger->info(sprintf("We have reached the maximum files to process per request limit of %s, returning response", |
||||||
554 | $this->files_to_process_per_request)); |
||||||
555 | |||||||
556 | return $return; |
||||||
557 | } |
||||||
558 | |||||||
559 | //close the backup archive by adding 2*512 blocks of zero bytes |
||||||
560 | $this->logger->info(sprintf("Closing the backup archive %s with 2*512 zero bytes blocks.", |
||||||
561 | $this->get_archive_name_with_extension())); |
||||||
562 | $this->backup_archive->close(); |
||||||
563 | |||||||
564 | /** |
||||||
565 | * XCloner HOOK backup_archive_finished. |
||||||
566 | * |
||||||
567 | * This will get triggered when a backup archive is finished writing. |
||||||
568 | */ |
||||||
569 | //do_action('backup_archive_finished', $this->backup_archive, $this); |
||||||
570 | |||||||
571 | //updating archive_info |
||||||
572 | $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension()); |
||||||
573 | |||||||
574 | if ($return['extra']['backup_part']) { |
||||||
575 | $this->write_multipart_file($this->get_archive_name_with_extension()); |
||||||
576 | } |
||||||
577 | |||||||
578 | $return['extra']['start_at_line'] = $extra_params['start_at_line'] - 1; |
||||||
579 | |||||||
580 | if (isset($file_info)) { |
||||||
581 | $return['extra']['processed_file'] = $file_info['path']; |
||||||
582 | $return['extra']['processed_file_size'] = $file_info['size']; |
||||||
583 | } |
||||||
584 | |||||||
585 | clearstatcache(); |
||||||
586 | $return['extra']['backup_size'] = $archive_info->getSize(); |
||||||
587 | |||||||
588 | $return['finished'] = 1; |
||||||
589 | return $return; |
||||||
590 | } |
||||||
591 | |||||||
592 | /* |
||||||
593 | * |
||||||
594 | * Write multipart file components |
||||||
595 | * |
||||||
596 | */ |
||||||
597 | private function write_multipart_file($path = "") |
||||||
598 | { |
||||||
599 | if (!$path) { |
||||||
600 | $path = $this->get_archive_name_with_extension(); |
||||||
601 | } |
||||||
602 | |||||||
603 | $file = $this->filesystem->get_filesystem("storage_filesystem_append")->getMetadata($path); |
||||||
604 | //print_r($file_info); |
||||||
605 | $line = '"'.$file['path'].'","'.$file['timestamp'].'","'.$file['size'].'"'.PHP_EOL; |
||||||
606 | |||||||
607 | |||||||
608 | $this->filesystem->get_filesystem("storage_filesystem_append") |
||||||
609 | ->write($this->get_archive_name_multipart(), $line); |
||||||
610 | } |
||||||
611 | |||||||
612 | /* |
||||||
613 | * |
||||||
614 | * Create a new backup part |
||||||
615 | * |
||||||
616 | */ |
||||||
617 | private function create_new_backup_part($part = 0) |
||||||
618 | { |
||||||
619 | //close the backup archive by adding 2*512 blocks of zero bytes |
||||||
620 | $this->logger->info(sprintf("Closing the backup archive %s with 2*512 zero bytes blocks.", |
||||||
621 | $this->get_archive_name_with_extension())); |
||||||
622 | $this->backup_archive->close(); |
||||||
623 | |||||||
624 | if (!$part) { |
||||||
625 | $old_name = $this->get_archive_name_with_extension(); |
||||||
626 | $this->set_archive_name($this->get_archive_name(), ++$part); |
||||||
627 | $this->rename_archive($old_name, $this->get_archive_name_with_extension()); |
||||||
628 | |||||||
629 | if ($this->filesystem->get_storage_filesystem()->has($this->get_archive_name_multipart())) { |
||||||
630 | $this->filesystem->get_storage_filesystem()->delete($this->get_archive_name_multipart()); |
||||||
631 | } |
||||||
632 | |||||||
633 | $this->write_multipart_file($this->get_archive_name_with_extension()); |
||||||
634 | |||||||
635 | } else { |
||||||
636 | $this->logger->info(sprintf("Creating new multipart info file %s", |
||||||
637 | $this->get_archive_name_with_extension())); |
||||||
638 | $this->write_multipart_file($this->get_archive_name_with_extension()); |
||||||
639 | } |
||||||
640 | |||||||
641 | $this->set_archive_name($this->get_archive_name(), ++$part); |
||||||
642 | |||||||
643 | $this->logger->info(sprintf("Creating new backup archive part %s", $this->get_archive_name_with_extension())); |
||||||
644 | |||||||
645 | $this->backup_archive = new Tar(); |
||||||
646 | $this->backup_archive->setCompression($this->compression_level); |
||||||
647 | $archive_info = $this->filesystem->get_storage_path_file_info($this->get_archive_name_with_extension()); |
||||||
648 | $this->backup_archive->create($archive_info->getPath().DS.$archive_info->getFilename()); |
||||||
649 | |||||||
650 | return array($archive_info, $part); |
||||||
651 | |||||||
652 | } |
||||||
653 | |||||||
654 | /* |
||||||
655 | * |
||||||
656 | * Add file to archive |
||||||
657 | * |
||||||
658 | */ |
||||||
659 | |||||||
660 | /** |
||||||
661 | * @param integer $append |
||||||
662 | */ |
||||||
663 | public function add_file_to_archive($file_info, $start_at_byte, $byte_limit = 0, $append, $filesystem) |
||||||
664 | { |
||||||
665 | |||||||
666 | $start_adapter = $this->filesystem->get_adapter($filesystem); |
||||||
667 | $start_filesystem = $this->filesystem->get_adapter($filesystem); |
||||||
668 | |||||||
669 | if (!$file_info['path']) { |
||||||
670 | return; |
||||||
671 | } |
||||||
672 | |||||||
673 | if (isset($file_info['archive_prefix_path'])) { |
||||||
674 | $file_info['target_path'] = $file_info['archive_prefix_path']."/".$file_info['path']; |
||||||
675 | } else { |
||||||
676 | $file_info['target_path'] = $file_info['path']; |
||||||
677 | } |
||||||
678 | |||||||
679 | $last_position = $start_at_byte; |
||||||
680 | |||||||
681 | //$start_adapter = $this->filesystem->get_start_adapter(); |
||||||
682 | |||||||
683 | if (!$append) { |
||||||
684 | $bytes_wrote = $file_info['size']; |
||||||
685 | $this->logger->info(sprintf("Adding %s bytes of file %s to archive %s ", $bytes_wrote, |
||||||
686 | $file_info['target_path'], $this->get_archive_name_with_extension())); |
||||||
687 | $this->backup_archive->addFile($start_adapter->applyPathPrefix($file_info['path']), |
||||||
688 | $file_info['target_path']); |
||||||
689 | } else { |
||||||
690 | $tmp_file = md5($file_info['path']); |
||||||
691 | |||||||
692 | //we isolate file to tmp if we are at byte 0, the starting point of file reading |
||||||
693 | if (!$start_at_byte) { |
||||||
694 | $this->logger->info(sprintf("Copying %s file to tmp filesystem file %s to prevent reading changes", |
||||||
695 | $file_info['path'], $tmp_file)); |
||||||
696 | $file_stream = $start_filesystem->readStream($file_info['path']); |
||||||
697 | |||||||
698 | if (is_resource($file_stream['stream'])) { |
||||||
699 | $this->filesystem->get_tmp_filesystem()->writeStream($tmp_file, $file_stream['stream']); |
||||||
700 | } |
||||||
701 | } |
||||||
702 | |||||||
703 | if ($this->filesystem->get_tmp_filesystem()->has($tmp_file)) { |
||||||
704 | $is_tmp = 1; |
||||||
705 | $last_position = $this->backup_archive->appendFileData($this->filesystem->get_tmp_filesystem_adapter() |
||||||
0 ignored issues
–
show
Are you sure the assignment to
$last_position is correct as $this->backup_archive->a...t_at_byte, $byte_limit) targeting splitbrain\PHPArchive\Tar::appendFileData() seems to always return null.
This check looks for function or method calls that always return null and whose return value is assigned to a variable. class A
{
function getObject()
{
return null;
}
}
$a = new A();
$object = $a->getObject();
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||
706 | ->applyPathPrefix($tmp_file), |
||||||
707 | $file_info['target_path'], $start_at_byte, $byte_limit); |
||||||
708 | } else { |
||||||
709 | $is_tmp = 0; |
||||||
710 | $last_position = $this->backup_archive->appendFileData($start_adapter->applyPathPrefix($file_info['path']), |
||||||
0 ignored issues
–
show
Are you sure the assignment to
$last_position is correct as $this->backup_archive->a...t_at_byte, $byte_limit) targeting splitbrain\PHPArchive\Tar::appendFileData() seems to always return null.
This check looks for function or method calls that always return null and whose return value is assigned to a variable. class A
{
function getObject()
{
return null;
}
}
$a = new A();
$object = $a->getObject();
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||
711 | $file_info['target_path'], $start_at_byte, $byte_limit); |
||||||
712 | } |
||||||
713 | |||||||
714 | |||||||
715 | if ($last_position == -1) { |
||||||
716 | $bytes_wrote = $file_info['size'] - $start_at_byte; |
||||||
717 | } else { |
||||||
718 | $bytes_wrote = $last_position - $start_at_byte; |
||||||
719 | } |
||||||
720 | |||||||
721 | |||||||
722 | if ($is_tmp) { |
||||||
723 | $this->logger->info(sprintf("Appended %s bytes, starting position %s, of tmp file %s (%s) to archive %s ", |
||||||
724 | $bytes_wrote, $start_at_byte, $tmp_file, $file_info['target_path'], $this->get_archive_name())); |
||||||
725 | } else { |
||||||
726 | $this->logger->info(sprintf("Appended %s bytes, starting position %s, of original file %s to archive %s ", |
||||||
727 | $bytes_wrote, $start_at_byte, $file_info['target_path'], $tmp_file, $this->get_archive_name())); |
||||||
728 | } |
||||||
729 | |||||||
730 | //we delete here the isolated tmp file |
||||||
731 | if ($last_position == -1) { |
||||||
732 | if ($this->filesystem->get_tmp_filesystem_adapter()->has($tmp_file)) { |
||||||
733 | $this->logger->info(sprintf("Deleting %s from the tmp filesystem", $tmp_file)); |
||||||
734 | $this->filesystem->get_tmp_filesystem_adapter()->delete($tmp_file); |
||||||
735 | } |
||||||
736 | } |
||||||
737 | |||||||
738 | } |
||||||
739 | |||||||
740 | return array($bytes_wrote, $last_position); |
||||||
741 | } |
||||||
742 | |||||||
743 | /** |
||||||
744 | * Open a TAR archive and put the file cursor at the end for data appending |
||||||
745 | * |
||||||
746 | * If $file is empty, the tar file will be created in memory |
||||||
747 | * |
||||||
748 | * @param string $file |
||||||
749 | * @throws ArchiveIOException |
||||||
750 | */ |
||||||
751 | /* |
||||||
752 | public function openForAppend($file = '') |
||||||
753 | { |
||||||
754 | $this->file = $file; |
||||||
755 | $this->memory = ''; |
||||||
756 | $this->fh = 0; |
||||||
757 | |||||||
758 | if ($this->file) { |
||||||
759 | // determine compression |
||||||
760 | if ($this->comptype == Archive::COMPRESS_AUTO) { |
||||||
761 | $this->setCompression($this->complevel, $this->filetype($file)); |
||||||
762 | } |
||||||
763 | |||||||
764 | if ($this->comptype === Archive::COMPRESS_GZIP) { |
||||||
765 | $this->fh = @gzopen($this->file, 'ab'.$this->complevel); |
||||||
766 | } elseif ($this->comptype === Archive::COMPRESS_BZIP) { |
||||||
767 | $this->fh = @bzopen($this->file, 'a'); |
||||||
768 | } else { |
||||||
769 | $this->fh = @fopen($this->file, 'ab'); |
||||||
770 | } |
||||||
771 | |||||||
772 | if (!$this->fh) { |
||||||
773 | throw new ArchiveIOException('Could not open file for writing: '.$this->file); |
||||||
774 | } |
||||||
775 | } |
||||||
776 | $this->backup_archive->writeaccess = true; |
||||||
777 | $this->backup_archive->closed = false; |
||||||
778 | } |
||||||
779 | */ |
||||||
780 | |||||||
781 | /** |
||||||
782 | * Append data to a file to the current TAR archive using an existing file in the filesystem |
||||||
783 | * |
||||||
784 | * @param string $file path to the original file |
||||||
785 | * @param int $start starting reading position in file |
||||||
786 | * @param int $end end position in reading multiple with 512 |
||||||
787 | * @param string|FileInfo $fileinfo either the name to us in archive (string) or a FileInfo oject with |
||||||
788 | * all meta data, empty to take from original |
||||||
789 | * @throws ArchiveIOException |
||||||
790 | */ |
||||||
791 | /* |
||||||
792 | * public function appendFileData($file, $fileinfo = '', $start = 0, $limit = 0) |
||||||
793 | { |
||||||
794 | $end = $start+($limit*512); |
||||||
795 | |||||||
796 | //check to see if we are at the begining of writing the file |
||||||
797 | if(!$start) |
||||||
798 | { |
||||||
799 | if (is_string($fileinfo)) { |
||||||
800 | $fileinfo = FileInfo::fromPath($file, $fileinfo); |
||||||
801 | } |
||||||
802 | } |
||||||
803 | |||||||
804 | if ($this->closed) { |
||||||
805 | throw new ArchiveIOException('Archive has been closed, files can no longer be added'); |
||||||
806 | } |
||||||
807 | |||||||
808 | $fp = fopen($file, 'rb'); |
||||||
809 | |||||||
810 | fseek($fp, $start); |
||||||
811 | |||||||
812 | if (!$fp) { |
||||||
813 | throw new ArchiveIOException('Could not open file for reading: '.$file); |
||||||
814 | } |
||||||
815 | |||||||
816 | // create file header |
||||||
817 | if(!$start) |
||||||
818 | $this->backup_archive->writeFileHeader($fileinfo); |
||||||
819 | |||||||
820 | $bytes = 0; |
||||||
821 | // write data |
||||||
822 | while ($end >=ftell($fp) and !feof($fp) ) { |
||||||
823 | $data = fread($fp, 512); |
||||||
824 | if ($data === false) { |
||||||
825 | break; |
||||||
826 | } |
||||||
827 | if ($data === '') { |
||||||
828 | break; |
||||||
829 | } |
||||||
830 | $packed = pack("a512", $data); |
||||||
831 | $bytes += $this->backup_archive->writebytes($packed); |
||||||
832 | } |
||||||
833 | |||||||
834 | |||||||
835 | |||||||
836 | //if we are not at the end of file, we return the current position for incremental writing |
||||||
837 | if(!feof($fp)) |
||||||
838 | $last_position = ftell($fp); |
||||||
839 | else |
||||||
840 | $last_position = -1; |
||||||
841 | |||||||
842 | fclose($fp); |
||||||
843 | |||||||
844 | return $last_position; |
||||||
845 | }*/ |
||||||
846 | |||||||
847 | /** |
||||||
848 | * Adds a file to a TAR archive by appending it's data |
||||||
849 | * |
||||||
850 | * @param string $archive name of the archive file |
||||||
851 | * @param string $file name of the file to read data from |
||||||
852 | * @param string $start start position from where to start reading data |
||||||
853 | * @throws ArchiveIOException |
||||||
854 | */ |
||||||
855 | /*public function addFileToArchive($archive, $file, $start = 0) |
||||||
856 | { |
||||||
857 | $this->openForAppend($archive); |
||||||
858 | return $start = $this->appendFileData($file, $start, $this->file_size_per_request_limit); |
||||||
859 | } |
||||||
860 | */ |
||||||
861 | |||||||
862 | } |
||||||
863 |
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.