PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.1.7
Backup Migration v2.1.7
2.1.7 2.1.6 2.1.5.2 trunk 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.6.1 1.4.7 1.4.8 1.4.9 1.4.9.1 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.5.1
backup-backup / includes / zipper / src / zip.php
backup-backup / includes / zipper / src Last commit date
zip.php 2 weeks ago
zip.php
1221 lines
1 <?php
2
3
4 namespace BMI\Plugin\Zipper;
5
6 use BMI\Plugin\Backup_Migration_Plugin as BMP;
7 use BMI\Plugin\BMI_Logger as Logger;
8 use BMI\Plugin\Dashboard as Dashboard;
9 use BMI\Plugin\Database\BMI_Database as Database;
10 use BMI\Plugin\Database\BMI_Database_Exporter as BetterDatabaseExport;
11 use BMI\Plugin\Progress\BMI_ZipProgress as Progress;
12 use BMI\Plugin\Heart\BMI_Backup_Heart as Bypasser;
13 use BMI\Plugin\Database\Export\DatabaseExportProcessor;
14
15 if ( ! defined( 'ABSPATH' ) ) exit;
16
17 class Zip {
18 protected $lib;
19 protected $org_files;
20 protected $new_file_path;
21 protected $new_file_name;
22 protected $backupname;
23 protected $zip_progress;
24
25 protected $extr_file;
26 protected $extr_dirc;
27 protected $start_zip;
28
29 public function __construct() {
30 $this->lib = 0;
31 $this->extr_file = 0;
32 $this->new_file_path = 0;
33 $this->org_files = [];
34 }
35
36 public function zip_start($file_path, $files = [], $name = '', &$zip_progress = null, $start = null) {
37
38 // save the new file path
39 $this->new_file_path = $file_path;
40 $this->backupname = $name;
41 $this->zip_progress = $zip_progress;
42 $this->start_zip = $start;
43
44 if (sizeof($files) > 0) {
45 $this->org_files = $files;
46 }
47
48 // Some php installations doesn't have the ZipArchive
49 // So in this case we'll use another lib called PclZip
50 if (class_exists("ZipArchive") || class_exists("\ZipArchive")) {
51 $this->lib = 1;
52 } else {
53 $this->lib = 2;
54 }
55
56 return true;
57
58 }
59
60 public function return_bytes($val) {
61 $val = trim($val);
62 $last = strtolower($val[strlen($val) - 1]);
63 $val = substr($val, 0, -1);
64
65 switch ($last) {
66 // The 'G' modifier is available since PHP 5.1.0
67 case 'g':
68 $val *= 1024;
69 // no break
70 case 'm':
71 $val *= 1024;
72 // no break
73 case 'k':
74 $val *= 1024;
75 }
76
77 return $val;
78 }
79
80 public function zip_failed($error) {
81 Logger::error(__("There was an error during backup (packing)...", 'backup-backup'));
82 Logger::error(print_r($error, true));
83
84 if ($this->zip_progress != null) {
85 $this->zip_progress->log(__("Issues during backup (packing)...", 'backup-backup'), 'ERROR');
86 $this->zip_progress->log(print_r($error, true), 'ERROR');
87 $this->zip_progress->log('#004', 'END-CODE');
88 }
89 }
90
91 public function restore_failed($error) {
92 Logger::error(__("There was an error during restore process (extracting)...", 'backup-backup'));
93 Logger::error($error);
94
95 if ($this->zip_progress != null) {
96 $this->zip_progress->log(__("Issues during restore process (extracting)...", 'backup-backup'), 'ERROR');
97 $this->zip_progress->log($error, 'ERROR');
98 $this->zip_progress->log('#004', 'END-CODE');
99 }
100 }
101
102 public function zip_add($in) {
103
104 // Just to make sure.. if the user haven't called the earlier method
105 if ($this->lib === 0 || $this->new_file_path === 0) {
106 throw new \Exception("PHP-ZIP: must call zip_start before zip_add");
107 }
108
109 // Push file
110 array_push($this->org_files, $in);
111
112 // Return
113 return true;
114 }
115
116 public function createDatabaseDump($dbbackupname, $better_database_files_dir, &$database_file, $database_file_dir, $dbBackupEngine = 'v4') {
117
118 $shouldBackupDB = apply_filters('bmip_database_backup', Dashboard\bmi_get_config('BACKUP:DATABASE') == 'true');
119 if ( $shouldBackupDB ) {
120
121 if (Dashboard\bmi_get_config('OTHER:BACKUP:DB:SINGLE:FILE') == 'true') {
122
123 // Require Database Manager
124 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'manager.php';
125
126 // Logs
127 $this->zip_progress->log(__("Making single-file database backup (using deprecated engine, due to used settings)", 'backup-backup'), 'STEP');
128
129 // Get database dump
130 $databaser = new Database(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
131 $databaser->exportDatabase($dbbackupname);
132
133 // Fix for newer version
134 $this->db_exporter_queries = 0;
135 $this->zip_progress->total_queries = 0;
136 $this->db_exporter_files = [];
137
138 $this->dbDumped = true;
139 $this->zip_progress->log(__("Database size: ", 'backup-backup') . BMP::humanSize(filesize($database_file)), 'INFO');
140
141 } else {
142
143 if ($dbBackupEngine == 'v4') {
144
145 // Require Database Manager
146 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'better-backup-v3.php';
147
148 // Get database dump
149
150 $dbEngine = 3;
151 if (Dashboard\bmi_get_config('OTHER::NEW_DATABASE_EXPORT_ENGINE')) {
152 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'export' . DIRECTORY_SEPARATOR . 'class-database-export-processor.php';
153 $dbEngine = 4;
154 $db_exporter = new DatabaseExportProcessor($better_database_files_dir, $this->zip_progress);
155 $this->zip_progress->log(__("Making database backup (using v4 engine, requires at least v1.2.2 to restore)", 'backup-backup'), 'STEP');
156 } else {
157
158 $this->zip_progress->log(__("Making database backup (using v3 engine, requires at least v1.2.2 to restore)", 'backup-backup'), 'STEP');
159 $dbEngine = 3;
160 $db_exporter = new BetterDatabaseExport($better_database_files_dir, $this->zip_progress);
161 }
162 } else {
163
164 // Require Database Manager
165 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'better-backup.php';
166
167 // Get database dump
168 $this->zip_progress->log(__("Making database backup (using v2 engine, requires at least v1.1.0 to restore)", 'backup-backup'), 'STEP');
169
170 }
171
172 $this->zip_progress->log(__("Iterating database...", 'backup-backup'), 'INFO');
173
174 if (!is_dir($better_database_files_dir)) @mkdir($better_database_files_dir, 0755, true);
175
176 $this->zip_progress->log('Exporting database via zip.php', 'VERBOSE');
177 if ($dbEngine === 4) {
178 $result = $db_exporter->exportAll();
179 $this->db_exporter_files = $result['files'];
180 $this->db_exporter_queries = $result['total_queries'];
181 $this->zip_progress->total_queries = $result['total_queries'];
182 } else {
183 $db_exporter->export();
184 $this->db_exporter_files = $db_exporter->files;
185 $this->db_exporter_queries = $db_exporter->total_queries;
186 $this->zip_progress->total_queries = $this->db_exporter_queries;
187 }
188
189 $this->dbDumped = true;
190 $this->zip_progress->log(__("Database backup finished", 'backup-backup'), 'SUCCESS');
191
192 }
193
194 } else {
195
196 $this->dbDumped = false;
197 $this->zip_progress->log(__("Omitting database backup (due to settings)...", 'backup-backup'), 'WARN');
198 $database_file = false;
199 $this->db_exporter_files = [];
200 $this->db_exporter_queries = 0;
201 $this->zip_progress->total_queries = 0;
202
203 }
204
205 }
206
207 public function saveRemoteSettings($settings) {
208 $settings_name = 'currentBackupConfig.' . 'php';
209 $settings_path = BMP::fixSlashes(BMI_TMP . DIRECTORY_SEPARATOR . $settings_name);
210
211 if (file_exists($settings_path)) @unlink($settings_path);
212 file_put_contents($settings_path, '<?php //' . json_encode($settings));
213 }
214
215 // Cut Path for ZIP structure
216 public function cutDir($file) {
217
218 if (substr($file, -4) === '.sql') {
219
220 $path = 'db_tables' . DIRECTORY_SEPARATOR . basename($file);
221
222 } else {
223
224 $path = basename($file);
225
226 }
227
228 $path = str_replace('\\', '/', $path);
229 return $path;
230
231 }
232
233 public function zip_end($force_lib = false, $cron = false) {
234
235 // v4 for new one, v3 for old one
236 $dbBackupEngine = 'v4';
237
238 // Try to set limit
239 $this->zip_progress->log(__("Smart memory calculation...", 'backup-backup'), 'STEP');
240 if ((intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024) < 384) @ini_set('memory_limit', '384M');
241 if (defined('WP_MAX_MEMORY_LIMIT')) $maxwp = WP_MAX_MEMORY_LIMIT;
242 else $maxwp = '1M';
243
244 $memory_limit = (intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024);
245 $maxwp = (intval($this->return_bytes($maxwp)) / 1024 / 1024);
246
247 if ($maxwp < $memory_limit) $memory_limit = $maxwp;
248 $this->zip_progress->log(str_replace('%s', $memory_limit, __("There is %s MBs of memory to use", 'backup-backup')), 'INFO');
249 $this->zip_progress->log(str_replace('%s', $maxwp, __("WordPress memory limit: %s MBs", 'backup-backup')), 'INFO');
250 $safe_limit = intval($memory_limit / 4);
251 if ($safe_limit >= 1024) $safe_limit = 256;
252 else if ($safe_limit >= 512) $safe_limit = 128;
253 else if ($safe_limit === 384) $safe_limit = 96;
254 else if ($safe_limit > 64) $safe_limit = 64;
255
256 // $real_memory = intval(memory_get_usage() * 0.9 / 1024 / 1024);
257 // if ($real_memory < $safe_limit) $safe_limit = $real_memory;
258 $safe_limit = intval($safe_limit * 0.9);
259
260 $this->zip_progress->log(str_replace('%s', $safe_limit, __("Setting the safe limit to %s MB", 'backup-backup')), 'SUCCESS');
261
262 $abs = BMP::fixSlashes(ABSPATH) . DIRECTORY_SEPARATOR;
263
264 $dbbackupname = 'bmi_database_backup.sql';
265 $database_file = BMP::fixSlashes(BMI_TMP . DIRECTORY_SEPARATOR . $dbbackupname);
266 $database_file_dir = BMP::fixSlashes((dirname($database_file))) . DIRECTORY_SEPARATOR;
267 $better_database_files_dir = $database_file_dir . 'db_tables';
268 $encryptionEnabled = defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO === 1 && Dashboard\bmi_get_config('ENCRYPTION:ENABLED');
269 $encryptionPassword = $encryptionEnabled ? Dashboard\bmi_get_config('ENCRYPTION:PASSWORD') : false;
270
271 // force usage of specific lib (for testing purposes)
272 if ($force_lib === 2) {
273
274 $this->lib = 2;
275
276 } elseif ($force_lib === 1) {
277
278 $this->lib = 1;
279
280 }
281
282 $this->dbDumped = false;
283 $this->db_exporter_queries = 0;
284 $this->zip_progress->total_queries = 0;
285 $this->db_exporter_files = [];
286
287 // just to make sure.. if the user haven't called the earlier method
288 if ($this->lib === 0 || $this->new_file_path === 0) {
289 throw new \Exception('PHP-ZIP: zip_start and zip_add haven\'t been called yet');
290 }
291
292 // using zipArchive class
293 // if ($this->lib === 1) {
294 //
295 // // Create DB Dump
296 // $this->createDatabaseDump($dbbackupname, $better_database_files_dir, $database_file, $database_file_dir);
297 //
298 // // All files
299 // $max = sizeof($this->org_files);
300 // $this->zip_progress->log(__("Making archive", 'backup-backup'), 'STEP');
301 // $this->zip_progress->log(__("Compressing...", 'backup-backup'), 'INFO');
302 //
303 // // Verbose
304 // $this->zip_progress->log(__("Using Zlib to create Backup", 'backup-backup'));
305 //
306 // $lib = new \ZipArchive();
307 // if (!$lib->open($this->new_file_path, \ZipArchive::CREATE)) {
308 // throw new \Exception('PHP-ZIP: Permission Denied or zlib can\'t be found');
309 // }
310 //
311 // // Add each file
312 // for ($i = 0; $i < $max; $i++) {
313 // $file = $this->org_files[$i];
314 // $zippath = substr($file, strlen($abs));
315 // $lib->addFile($file, 'wordpress' . DIRECTORY_SEPARATOR . $zippath);
316 //
317 // if ($i % 100 === 0) {
318 // if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) {
319 // break;
320 // }
321 // $this->zip_progress->progress($i + 1 . '/' . $max);
322 // }
323 //
324 // if (($i + 1) % 500 === 0 || $i == 0) {
325 // if (($i + 1) < $max) {
326 // $this->zip_progress->log((__("Milestone: ", 'backup-backup') . ($i + 1) . '/' . $max), 'info');
327 // }
328 // }
329 // }
330 //
331 // if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) {
332 //
333 // // close the archive
334 // $lib->close();
335 // } else {
336 // $this->zip_progress->log((__("Milestone: ", 'backup-backup') . $max . '/' . $max), 'info');
337 // $this->zip_progress->log(__("Compressed ", 'backup-backup') . $max . __(" files", 'backup-backup'), 'SUCCESS');
338 //
339 // // Log time of ZIP Process
340 // $this->zip_progress->log(__("Archiving of ", 'backup-backup') . $max . __(" files took: ", 'backup-backup') . number_format(microtime(true) - $this->start_zip, 2) . 's');
341 //
342 // $this->zip_progress->log(__("Finalizing backup", 'backup-backup'), 'STEP');
343 // $this->zip_progress->log(__("Adding manifest...", 'backup-backup'), 'INFO');
344 // $this->zip_progress->log(__("Closing files and archives", 'backup-backup'), 'STEP');
345 // $this->zip_progress->log('#001', 'END-CODE');
346 //
347 // $this->zip_progress->end();
348 // $logs = file_get_contents(BMI_BACKUPS . DIRECTORY_SEPARATOR . 'latest.log');
349 // $this->zip_progress->start(true);
350 //
351 // if ($database_file !== false) {
352 // if (Dashboard\bmi_get_config('OTHER:BACKUP:DB:SINGLE:FILE') == 'true') {
353 // if (file_exists($database_file)) {
354 // $lib->addFile($database_file, 'bmi_database_backup.sql');
355 // }
356 // } else {
357 // if ($db_exporter_files && sizeof($db_exporter_files) > 0) {
358 // for ($i = 0; $i < sizeof($db_exporter_files); ++$i) {
359 // $lib->addFile($db_exporter_files[$i], 'db_tables' . DIRECTORY_SEPARATOR . basename($db_exporter_files[$i]));
360 // }
361 // }
362 // }
363 // }
364 //
365 // $lib->addFromString('bmi_backup_manifest.json', $this->zip_progress->createManifest($dbBackupEngine));
366 // $lib->addFromString('bmi_logs_this_backup.log', $logs);
367 // $this->zip_progress->progress($max . '/' . $max);
368 //
369 // // close the archive
370 // $lib->close();
371 // }
372 // }
373
374 // using PclZip
375 if ($this->lib === 2) {
376
377 // All files
378 $max = sizeof($this->org_files);
379
380 $legacyVersion = apply_filters('bmi_legacy_version', BMI_LEGACY_VERSION);
381 $legacyHardVersion = apply_filters('bmi_legacy_hard_version', BMI_LEGACY_HARD_VERSION);
382 // Verbose
383 $legacy = $legacyVersion;
384 if ($legacy) $legacy = $legacyHardVersion;
385 if (class_exists('\ZipArchive') || class_exists('ZipArchive')) {
386 $this->zip_progress->log(__("ZipArchive is available this process should use ZipArchive", 'backup-backup'), 'INFO');
387 } else {
388 $this->zip_progress->log(__("Using PclZip module to create the backup", 'backup-backup'), 'INFO');
389 }
390 if (!$legacyVersion) {
391 if ($cron && Dashboard\bmi_get_config('CRON:REMOTE_PING') && defined('BMI_BACKUPS_PRO') && BMI_BACKUPS_PRO){
392 $this->zip_progress->log(__("Setting: Relying on remote cron ping to keep the backup alive", 'backup-backup'), 'INFO');
393 } else {
394 $this->zip_progress->log(__("Legacy setting: Using server-sided script and cURL based loop for better capabilities", 'backup-backup'), 'INFO');
395 }
396 } elseif (!$legacyHardVersion) {
397 if ($cron && Dashboard\bmi_get_config('CRON:REMOTE_PING') && defined('BMI_BACKUPS_PRO') && BMI_BACKUPS_PRO){
398 $this->zip_progress->log(__("Setting: Relying on remote cron ping to keep the backup alive", 'backup-backup'), 'INFO');
399 } else {
400 if ($cron) $this->zip_progress->log(__("Legacy setting: Using server-sided script and cURL based loop for better capabilities", 'backup-backup'), 'INFO');
401 else $this->zip_progress->log(__("Legacy setting: Using user browser as middleware for full capabilities", 'backup-backup'), 'INFO');
402 }
403 } else {
404
405 $this->zip_progress->log(__("Legacy setting: Using default modules depending on user server", 'backup-backup'), 'INFO');
406
407 // Create DB Dump
408 $this->createDatabaseDump($dbbackupname, $better_database_files_dir, $database_file, $database_file_dir, $dbBackupEngine);
409
410 $this->zip_progress->log(__("Making archive", 'backup-backup'), 'STEP');
411 $this->zip_progress->log(__("Compressing...", 'backup-backup'), 'INFO');
412
413 }
414
415 // Run the backup in background
416 $cliEnabled = false;
417 if (defined('BMI_CLI_ENABLED')) $cliEnabled = apply_filters('bmi_cli_enabled', BMI_CLI_ENABLED);
418 if ((!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false) && ($legacy === false || $cliEnabled === true) && sizeof($this->org_files) > 10 && !defined('BMI_CLI_FAILED')) {
419 file_put_contents($database_file_dir . 'bmi_backup_manifest.json', $this->zip_progress->createManifest($dbBackupEngine));
420 // $url = plugins_url('') . '/backup-backup/includes/middleware-backup-proxy.php';
421 $url = admin_url('admin-ajax.php');
422 $identy = 'BMI-' . rand(10000000, 99999999);
423 $remote_settings = [
424 'identy' => $identy,
425 'manifest' => $database_file_dir . 'bmi_backup_manifest.json',
426 'backupname' => $this->backupname,
427 'safelimit' => $safe_limit,
428 'rev' => BMI_REV,
429 'total_files' => sizeof($this->org_files),
430 'filessofar' => 0,
431 'start' => microtime(true),
432 'config_dir' => BMI_CONFIG_DIR,
433 'content_dir' => trailingslashit(WP_CONTENT_DIR),
434 'backup_dir' => BMI_BACKUPS,
435 'abs_dir' => trailingslashit(ABSPATH),
436 'root_dir' => plugin_dir_path(BMI_ROOT_FILE),
437 'browser' => false,
438 'shareallowed' => BMP::canShareLogsOrShouldAsk(),
439 'dbiteratio' => 0,
440 'it' => 0,
441 'dbit' => 0,
442 'dblast' => 0,
443 'bmitmp' => BMI_TMP,
444 'url' => $url,
445 'db_v2_engine' => false,
446 'final_made' => false,
447 'final_batch' => false,
448 'dbitJustFinished' => false,
449 'is_streamed' => apply_filters('bmip_streaming_backup_is_enabled', false),
450 'useragent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'WordPress.org Site Self Request'
451 ];
452 $fix = true;
453 $Xfiles = glob(BMI_TMP . DIRECTORY_SEPARATOR . '.BMI-*');
454 foreach ($Xfiles as $xfile) if (is_file($xfile)) unlink($xfile);
455 touch(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy);
456
457 if ($fix === true) {
458 if ($legacyHardVersion === false && $cron === false) {
459 $remote_settings['browser'] = true;
460 $this->zip_progress->log(__("Saving backup configuration for current session...", 'backup-backup'), 'INFO');
461 $this->saveRemoteSettings($remote_settings);
462 $this->zip_progress->log(__("Sending confirmation to user browser to keep pinging the process.", 'backup-backup'), 'INFO');
463 BMP::res(['status' => 'background_hard', 'filename' => $this->backupname, 'url' => $url]);
464 exit;
465 } else {
466 $this->zip_progress->log(__("Saving backup configuration for current session...", 'backup-backup'), 'INFO');
467 $this->saveRemoteSettings($remote_settings);
468 $this->zip_progress->log(__('Starting background process on server-side...', 'backup-backup'), 'INFO');
469 require_once BMI_INCLUDES . '/backup-process.php';
470 $request = new Bypasser($identy, BMI_CONFIG_DIR, trailingslashit(WP_CONTENT_DIR), BMI_BACKUPS, trailingslashit(ABSPATH), plugin_dir_path(BMI_ROOT_FILE));
471 $request->handle_batch();
472 }
473 }
474
475 sleep(2);
476 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running')) {
477 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy . '-running')) {
478 // $this->zip_progress->log(__('Request received correctly – backup is running.', 'backup-backup'), 'SUCCESS');
479 if ($cron === true) return ['status' => 'background', 'filename' => $this->backupname];
480 else BMP::res(['status' => 'background', 'filename' => $this->backupname]);
481 exit;
482 } else {
483 $this->zip_progress->log(__('Could not find any response from the server, trying again in 3 seconds.', 'backup-backup'), 'WARN');
484 sleep(3);
485 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy . '-running')) {
486 // $this->zip_progress->log(__('Request received correctly – backup is running.', 'backup-backup'), 'SUCCESS');
487 if ($cron === true) return ['status' => 'background', 'filename' => $this->backupname];
488 else BMP::res(['status' => 'background', 'filename' => $this->backupname]);
489 exit;
490 } else {
491 $this->zip_progress->log(__('Still nothing backup probably is not running.', 'backup-backup'), 'WARN');
492 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy . '-running')) @unlink(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy . '-running');
493 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy)) @unlink(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy);
494 throw new \Exception('Backup could not run on your server, please check global logs.');
495 }
496 }
497 } else {
498 if ($cron === true) return ['status' => 'background', 'filename' => $this->backupname];
499 else BMP::res(['status' => 'background', 'filename' => $this->backupname]);
500 exit;
501 }
502
503 // ob_end_clean();
504 exit;
505 } else {
506 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
507 $this->zip_progress->log(__("Backup is running under PHP CLI environment.", 'backup-backup'), 'INFO');
508 } else {
509 $this->zip_progress->log(__("Backup will run as single-request, may be unstable...", 'backup-backup'), 'WARN');
510 }
511 }
512
513 if ($this->dbDumped === false) {
514 $this->createDatabaseDump($dbbackupname, $better_database_files_dir, $database_file, $database_file_dir);
515 }
516
517 $zipArchive = false;
518 if (class_exists('\ZipArchive') || class_exists('ZipArchive')) {
519 if (!isset($zip)) {
520 $zip = new \ZipArchive();
521 }
522
523 if ($zip) {
524 $zipArchive = true;
525 } else {
526 $zipArchive = false;
527 }
528 }
529
530 // Check if PclZip exists
531 if ($zipArchive === false) {
532 if (!class_exists('PclZip')) {
533 if (!defined('PCLZIP_TEMPORARY_DIR')) {
534 $bmi_tmp_dir = BMI_TMP;
535 if (!file_exists($bmi_tmp_dir)) {
536 @mkdir($bmi_tmp_dir, 0775, true);
537 }
538
539 define('PCLZIP_TEMPORARY_DIR', $bmi_tmp_dir . DIRECTORY_SEPARATOR . 'bmi-');
540 }
541
542 if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
543 define('PCLZIP_READ_BLOCK_SIZE', 32768);
544 }
545 }
546
547 // Require the LIB and check if it's compatible
548 if (defined('BMI_PRO_PCLZIP') && file_exists(BMI_PRO_PCLZIP)) {
549 $this->zip_progress->log(__('Using dedicated PclZIP for Premium Users.', 'backup-backup'), 'INFO');
550 require_once BMI_PRO_PCLZIP;
551 } else {
552 require_once trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
553 }
554
555 // Get/Create the Archive
556 if (!$lib = new \PclZip($this->new_file_path)) {
557 throw new \Exception('PHP-ZIP: Permission Denied or zlib can\'t be found');
558 }
559
560 } else {
561
562 if (file_exists($this->new_file_path)) $zip->open($this->new_file_path);
563 else $zip->open($this->new_file_path, \ZipArchive::CREATE);
564
565 $this->zip_progress->log('Using ZipArchive extension for this backup process.', 'INFO');
566 if ($encryptionEnabled && $encryptionPassword) {
567 $this->zip_progress->log('Encryption is enabled, setting password for the archive.', 'INFO');
568 $zip->setPassword($encryptionPassword);
569 }
570
571 }
572
573 // require the lib
574 // if (!class_exists('PclZip')) {
575 // if (!defined('PCLZIP_TEMPORARY_DIR')) {
576 // $bmi_tmp_dir = BMI_TMP;
577 // if (!file_exists($bmi_tmp_dir)) {
578 // @mkdir($bmi_tmp_dir, 0775, true);
579 // }
580 // define('PCLZIP_TEMPORARY_DIR', $bmi_tmp_dir . DIRECTORY_SEPARATOR . 'bmi-');
581 // }
582 // if (defined('BMI_PRO_PCLZIP') && file_exists(BMI_PRO_PCLZIP)) {
583 // $this->zip_progress->log(__('Using dedicated PclZIP for Premium Users.', 'backup-backup'), 'INFO');
584 // require_once BMI_PRO_PCLZIP;
585 // } else {
586 // require_once trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
587 // }
588 // }
589 $common = $this->org_files;
590
591 if ($this->dbDumped === true) {
592 try {
593
594 $this->zip_progress->log(__('Adding database SQL file(s) to the backup file.', 'backup-backup'), 'STEP');
595
596 $files = [];
597
598 if ($database_file !== false && !($this->db_exporter_files && sizeof($this->db_exporter_files) > 0)) {
599 $files[] = $database_file;
600 }
601
602 $this->zip_progress->log('Database files in total found: ' . sizeof($this->db_exporter_files), 'VERBOSE');
603 if ($this->db_exporter_files && sizeof($this->db_exporter_files) > 0) {
604 for ($i = 0; $i < sizeof($this->db_exporter_files); ++$i) {
605 $files[] = $this->db_exporter_files[$i];
606 }
607 } else {
608 $this->zip_progress->log(__('No database files found to be added into backup, ignore this message if database was not meant to be included.', 'backup-backup'), 'WARN');
609 $this->zip_progress->log('No database files found to be added into backup, ignore this message if database was not meant to be included.', 'VERBOSE');
610 }
611
612 $files = array_filter($files, function ($path) {
613 if (is_readable($path) && is_writable($path) && !is_link($path)) return true;
614 else {
615 $this->zip_progress->log(sprintf(__("Excluding file that cannot be read: %s", 'backup-backup'), $path), 'warn');
616 return false;
617 }
618 });
619
620 if (sizeof($files) > 0) {
621 if ($zipArchive) {
622 for ($i = 0; $i < sizeof($files); ++$i) {
623
624 // Add the file
625 if (is_dir($files[$i])) {
626 $zip->addEmptyDir($this->cutDir($files[$i]));
627 } else {
628 $zip->addFile($files[$i], $this->cutDir($files[$i]));
629 if ($encryptionEnabled) {
630 $zip->setEncryptionName($this->cutDir($files[$i]), \ZipArchive::EM_AES_256);
631 }
632 }
633
634 }
635
636 $zAresult = $zip->close();
637 if ($zAresult !== true) {
638 $this->zip_progress->log('not_enough_space', 'verbose');
639 $this->zip_failed('Error, there is most likely not enough space for the backup.');
640 return false;
641
642 }
643 $zip->open($this->new_file_path);
644 if ($encryptionEnabled && $encryptionPassword) {
645 $zip->setPassword($encryptionPassword);
646 }
647 } else {
648 $dbback = $lib->add($files, PCLZIP_OPT_REMOVE_PATH, $database_file_dir, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
649
650 if ($dbback == 0) {
651 $this->zip_failed($lib->errorInfo(true));
652 return false;
653 }
654 }
655 }
656
657 } catch (\Exception $e) {
658 $this->zip_failed($e->getMessage());
659
660 return false;
661 } catch (\Throwable $e) {
662 $this->zip_failed($e->getMessage());
663
664 return false;
665 }
666
667 if (sizeof($files) > 0) {
668 $this->zip_progress->log(__('Database added to the backup successfully.', 'backup-backup'), 'SUCCESS');
669 } else {
670 $this->zip_progress->log(__('Database was not added to the backup.', 'backup-backup'), 'WARN');
671 }
672 }
673
674 $this->zip_progress->log(__('Performing site files backup...', 'backup-backup'), 'STEP');
675
676 try {
677 $splitby = 200; $milestoneby = 500;
678 $filestotal = sizeof($this->org_files);
679 if ($filestotal < 3000) { $splitby = 250; $milestoneby = 500; }
680 if ($filestotal > 5000) { $splitby = 500; $milestoneby = 500; }
681 if ($filestotal > 10000) { $splitby = 1000; $milestoneby = 1000; }
682 if ($filestotal > 15000) { $splitby = 2000; $milestoneby = 2000; }
683 if ($filestotal > 20000) { $splitby = 4000; $milestoneby = 4000; }
684 if ($filestotal > 25000) { $splitby = 6000; $milestoneby = 6000; }
685 if ($filestotal > 30000) { $splitby = 8000; $milestoneby = 8000; }
686 if ($filestotal > 32000) { $splitby = 10000; $milestoneby = 10000; }
687 if ($filestotal > 60500) { $splitby = 20000; $milestoneby = 20000; }
688 if ($filestotal > 90500) { $splitby = 40000; $milestoneby = 40000; }
689
690 $this->zip_progress->log(__("Chunks contain ", 'backup-backup') . $splitby . __(" files.", 'backup-backup'));
691
692 $chunks = array_chunk($this->org_files, $splitby);
693 $chunkslen = sizeof($chunks);
694 if ($chunkslen > 0) {
695 $sizeoflast = sizeof($chunks[$chunkslen - 1]);
696 if ($chunkslen > 1 && $sizeoflast == 1) {
697 $buffer = array_slice($chunks[$chunkslen - 2], -1);
698 $chunks[$chunkslen - 2] = array_slice($chunks[$chunkslen - 2], 0, -1);
699 $chunks[$chunkslen - 1][] = $buffer[0];
700 }
701 }
702
703 $backupSize = 0;
704 for ($i = 0; $i < $chunkslen; ++$i) {
705
706 // Abort if user wants it (check every 100 files)
707 if (file_exists(BMI_BACKUPS . '/.abort')) {
708 break;
709 }
710
711 $back = 0;
712 $chunk = $chunks[$i];
713 $chunk = array_filter($chunk, function ($path) {
714 if (is_readable($path) && file_exists($path) && !is_link($path)) return true;
715 else {
716 $this->zip_progress->log(sprintf(__("Excluding file that cannot be read: %s", 'backup-backup'), $path), 'warn');
717 return false;
718 }
719 });
720 $chunk = array_values($chunk);
721
722 if (sizeof($chunk) > 0) {
723 $needManipulation = false;
724 if (strpos(WP_CONTENT_DIR, ABSPATH) === false) {
725 $needManipulation = true;
726 }
727 if ($zipArchive) {
728 for ($j = 0; $j < sizeof($chunk); ++$j) {
729
730 if ($needManipulation) {
731 if (strpos($chunk[$j], WP_CONTENT_DIR) !== false) {
732 $path = 'wordpress' . DIRECTORY_SEPARATOR . 'wp-content' . DIRECTORY_SEPARATOR . substr($chunk[$j], strlen(WP_CONTENT_DIR));
733 } else {
734 $path = 'wordpress' . DIRECTORY_SEPARATOR . substr($chunk[$j], strlen(ABSPATH));
735 }
736 } else {
737 $path = 'wordpress' . DIRECTORY_SEPARATOR . substr($chunk[$j], strlen(ABSPATH));
738 }
739
740 // Add the file
741 $path = BMP::fixSlashes($path);
742 if (is_dir($chunk[$j])) {
743 $zip->addEmptyDir($path);
744 } else {
745 $zip->addFile($chunk[$j], $path);
746 if ($encryptionEnabled && $encryptionPassword) {
747 $zip->setEncryptionName($path, \ZipArchive::EM_AES_256);
748 }
749 }
750
751 }
752
753 $zAresult = $zip->close();
754 if ($zAresult !== true) {
755 $this->zip_progress->log('not_enough_space', 'verbose');
756 $this->zip_failed('Error, there is most likely not enough space for the backup.');
757 return false;
758
759 }
760 $zip->open($this->new_file_path);
761 if ($encryptionEnabled && $encryptionPassword) {
762 $zip->setPassword($encryptionPassword);
763 }
764 } else {
765
766 if ($needManipulation) {
767 $abs = BMP::fixSlashes(ABSPATH) . DIRECTORY_SEPARATOR;
768 $content = BMP::fixSlashes(WP_CONTENT_DIR) . DIRECTORY_SEPARATOR;
769 $coreFiles = [];
770 $contentFiles = [];
771 foreach ($chunk as $file) {
772 if (strpos($file, $content) !== false) {
773 $contentFiles[] = $file;
774 } else {
775 $coreFiles[] = $file;
776 }
777 }
778
779 $back_1 = $lib->add($coreFiles, PCLZIP_OPT_REMOVE_PATH, $abs, PCLZIP_OPT_ADD_PATH, 'wordpress' . DIRECTORY_SEPARATOR, PCLZIP_OPT_ADD_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
780 $back_2 = $lib->add($contentFiles, PCLZIP_OPT_REMOVE_PATH, $content, PCLZIP_OPT_ADD_PATH, 'wordpress' . DIRECTORY_SEPARATOR . 'wp-content' . DIRECTORY_SEPARATOR, PCLZIP_OPT_ADD_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
781 $back = $back_1 && $back_2;
782
783 } else {
784 $back = $lib->add($chunk, PCLZIP_OPT_REMOVE_PATH, ABSPATH, PCLZIP_OPT_ADD_PATH, 'wordpress' . DIRECTORY_SEPARATOR, PCLZIP_OPT_ADD_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
785 }
786 if ($back == 0) {
787 $this->zip_failed($lib->errorInfo(true));
788 return false;
789 }
790
791 }
792 }
793
794 $curfile = (($i * $splitby) + $splitby);
795 $this->zip_progress->progress($curfile . '/' . $max);
796 if ($curfile % $milestoneby === 0 && $curfile < $max) {
797 if (!file_exists($this->new_file_path))
798 return $this->zip_failed('Expected backup file does not exist, there could be some issue or the backup was removed by third parties.');
799
800 $currentBackupSize = filesize($this->new_file_path);
801 if ($backupSize > $currentBackupSize)
802 return $this->zip_failed('Backup size is smaller than it should be, it has been damaged, it may not be restorable, abort recommended.');
803
804 $backupSize = $currentBackupSize;
805
806 $this->zip_progress->log(__("Milestone: ", 'backup-backup') . ($curfile . '/' . $max), 'info');
807 }
808 }
809
810 } catch (\Exception $e) {
811 $this->zip_failed($e->getMessage());
812
813 return false;
814 } catch (\Throwable $e) {
815 $this->zip_failed($e->getMessage());
816
817 return false;
818 }
819
820 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) {
821
822 $this->zip_progress->log(' Backup process was aborted by user, cleaning up...', 'WARN');
823
824 if (file_exists($database_file_dir . 'bmi_backup_manifest.json')) {
825 @unlink($database_file_dir . 'bmi_backup_manifest.json');
826 }
827 if (file_exists($database_file_dir . 'bmi_logs_this_backup.log')) {
828 @unlink($database_file_dir . 'bmi_logs_this_backup.log');
829 }
830 if (file_exists($database_file_dir . '.backup_name')) {
831 @unlink($database_file_dir . '.backup_name');
832 }
833
834 } else {
835
836 // End
837 $this->zip_progress->log(__("Milestone: ", 'backup-backup') . ($max . '/' . $max), 'info');
838 $this->zip_progress->log(__("Compressed ", 'backup-backup') . $max . __(" files", 'backup-backup'), 'SUCCESS');
839
840 // Log time of ZIP Process
841 $this->zip_progress->log(__("Archiving of ", 'backup-backup') . $max . __(" files took: ", 'backup-backup') . number_format(microtime(true) - $this->start_zip, 2) . 's');
842
843 $this->zip_progress->log(__("Finalizing backup", 'backup-backup'), 'STEP');
844 $this->zip_progress->log(__("Generating manifest file and saving current live-log...", 'backup-backup'), 'INFO');
845
846 file_put_contents($database_file_dir . 'bmi_backup_manifest.json', $this->zip_progress->createManifest($dbBackupEngine));
847 file_put_contents($database_file_dir . 'bmi_logs_this_backup.log', file_get_contents(BMI_BACKUPS . DIRECTORY_SEPARATOR . 'latest.' . BMI_LOGS_SUFFIX . '.log'));
848
849 $backupName = $database_file_dir . '.backup_name';
850 file_put_contents($backupName, $this->backupname);
851
852 sleep(1);
853
854 $files = [];
855
856 if (file_exists($database_file_dir . 'bmi_logs_this_backup.log')) {
857 $files[] = $database_file_dir . 'bmi_logs_this_backup.log';
858 }
859 if (file_exists($database_file_dir . 'bmi_backup_manifest.json')) {
860 $files[] = $database_file_dir . 'bmi_backup_manifest.json';
861 } else {
862 $this->zip_failed('Manifest file could not be added, manifest does not exist.');
863 return false;
864 }
865 if (file_exists($database_file_dir . '.backup_name')) {
866 $files[] = $database_file_dir . '.backup_name';
867 }
868
869 $this->zip_progress->log(__("Adding manifest...", 'backup-backup'), 'INFO');
870 try {
871
872 if ($zipArchive) {
873 for ($i = 0; $i < sizeof($files); ++$i) {
874
875 // Add the file
876 if (is_dir($files[$i])) {
877 $zip->addEmptyDir($this->cutDir($files[$i]));
878 } else {
879 $zip->addFile($files[$i], $this->cutDir($files[$i]));
880 if ($encryptionEnabled && $encryptionPassword !== false && basename($files[$i]) === '.backup_name') {
881 $zip->setEncryptionName($this->cutDir($files[$i]), \ZipArchive::EM_AES_256);
882 }
883 }
884
885 }
886
887 $zAresult = $zip->close();
888 if ($zAresult !== true) {
889 $this->zip_progress->log('not_enough_space', 'verbose');
890 $this->zip_failed('Error, there is most likely not enough space for the backup.');
891 return false;
892
893 }
894 } else {
895
896 $maback = $lib->add($files, PCLZIP_OPT_REMOVE_PATH, $database_file_dir, PCLZIP_OPT_ADD_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
897
898 if ($maback == 0) {
899 $this->zip_failed($lib->errorInfo(true));
900 return false;
901 }
902
903 }
904
905 } catch (\Exception $e) {
906 $this->zip_failed($e->getMessage());
907
908 return false;
909 } catch (\Throwable $e) {
910 $this->zip_failed($e->getMessage());
911
912 return false;
913 }
914
915 if (file_exists($database_file_dir . 'bmi_backup_manifest.json')) {
916 @unlink($database_file_dir . 'bmi_backup_manifest.json');
917 }
918 if (file_exists($database_file_dir . 'bmi_logs_this_backup.log')) {
919 @unlink($database_file_dir . 'bmi_logs_this_backup.log');
920 }
921 if (file_exists($database_file_dir . '.backup_name')) {
922 @unlink($database_file_dir . '.backup_name');
923 }
924
925 $this->zip_progress->progress($max . '/' . $max);
926
927 $this->zip_progress->log(__("Manifest file and logs added to the backup. Temporary files removed.", 'backup-backup'), 'SUCCESS');
928
929 }
930 }
931
932 $this->zip_progress->log(__("Closing files and archives", 'backup-backup'), 'STEP');
933
934 // Remove Better DB SQL Files
935 if ($this->db_exporter_files && sizeof($this->db_exporter_files) > 0) {
936 for ($i = 0; $i < sizeof($this->db_exporter_files); ++$i) {
937 if (file_exists($this->db_exporter_files[$i])) @unlink($this->db_exporter_files[$i]);
938 }
939 if (file_exists($better_database_files_dir) && is_dir($better_database_files_dir)) {
940 @rmdir($better_database_files_dir);
941 }
942 }
943
944 if ($database_file && file_exists($database_file)) @unlink($database_file);
945 if (!file_exists($this->new_file_path)) {
946 $this->zip_failed('PHP-ZIP: After doing the zipping file can not be found');
947 }
948 if (filesize($this->new_file_path) === 0) {
949 $this->zip_failed('PHP-ZIP: After doing the zipping file size is still 0 bytes');
950 }
951
952 // empty the array
953 $this->org_files = [];
954
955 $this->zip_progress->log(__("Cleanup finished, backup complete.", 'backup-backup'), 'SUCCESS');
956 // $this->zip_progress->log('#001', 'END-CODE');
957 return true;
958
959 }
960
961 public function zip_files($files, $to) {
962 $this->zip_start($to);
963 $this->zip_add($files);
964
965 return $this->zip_end();
966 }
967
968 public function unzip_file($file_path, $target_dir = null, &$zip_progress = null, $password = null) {
969
970 // Progress
971 $this->zip_progress = $zip_progress;
972
973 // if it doesn't exist
974 if (!file_exists($file_path)) {
975 throw new \Exception("PHP-ZIP: File doesn't Exist");
976 }
977
978 $this->extr_file = $file_path;
979
980 if (class_exists("ZipArchive")) $this->lib = 1;
981 else $this->lib = 2;
982
983 if ($target_dir !== null) {
984 return $this->unzip_to($target_dir, $password);
985 } else {
986 return true;
987 }
988 }
989
990 public function extract_files($zip_path, $files, $target_dir = null, &$zip_progress = null, $isFirstExtract = true, $password = null) {
991
992 $this->zip_progress = $zip_progress;
993
994 // it exists, but it's not a directory
995 if (file_exists($target_dir) && (!is_dir($target_dir))) {
996 throw new \Exception("PHP-ZIPv2: Target directory exists as a file not a directory");
997 }
998 // it doesn't exist
999 if (!file_exists($target_dir)) {
1000 if (!mkdir($target_dir)) {
1001 throw new \Exception("PHP-ZIPv2: Directory not found, and unable to create it");
1002 }
1003 }
1004 // validations -- end //
1005 // TODO: NOTICE: Force disable PCLZIP
1006 if (class_exists("ZipArchive") || class_exists("\ZipArchive")) {
1007
1008 $zip = new \ZipArchive;
1009 $res = $zip->open($zip_path);
1010
1011 if ($res === true) {
1012
1013 if ($password !== null) {
1014 $zip->setPassword($password);
1015 }
1016
1017 if ($isFirstExtract) {
1018 $this->zip_progress->log(__("Using ZipArchive, omiting memory limit calculations...", 'backup-backup'), 'INFO');
1019 }
1020
1021 $zip->extractTo($target_dir, $files);
1022 $zip->close();
1023 return true;
1024
1025 } else {
1026
1027 $this->restore_failed('PHP-ZIPv2: Could not open Backup with ZipArchive.');
1028 return false;
1029
1030 }
1031
1032 } else {
1033
1034 if ($isFirstExtract) {
1035 $this->zip_progress->log(__("ZipArchive is not available, using PclZIP.", 'backup-backup'), 'INFO');
1036 if ($password !== null) {
1037 $this->zip_progress->log(__("PclZIP does not support passwords, please enable ZipArchive to be able to restore the backup.", 'backup-backup'), 'ERROR');
1038 $this->restore_failed('PHP-ZIPv2: PclZIP does not support passwords, please enable ZipArchive to be able to restore the backup.');
1039 return false;
1040 }
1041 }
1042
1043 $safe_limit = $this->smartMemory($isFirstExtract);
1044 $this->loadPclZip($isFirstExtract);
1045 $lib = new \PclZip($zip_path);
1046 $restor = $lib->extract(PCLZIP_OPT_BY_NAME, $files, PCLZIP_OPT_PATH, $target_dir, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
1047
1048 if ($restor == 0) {
1049
1050 $this->restore_failed($lib->errorInfo(true));
1051 return false;
1052
1053 }
1054
1055 return true;
1056
1057 }
1058
1059 }
1060
1061 public function loadPclZip($isFirstExtract = true) {
1062
1063 if (!class_exists('PclZip')) {
1064 if (!defined('PCLZIP_TEMPORARY_DIR')) {
1065 $bmi_tmp_dir = BMI_TMP;
1066 if (!file_exists($bmi_tmp_dir)) {
1067 @mkdir($bmi_tmp_dir, 0775, true);
1068 }
1069 define('PCLZIP_TEMPORARY_DIR', $bmi_tmp_dir . DIRECTORY_SEPARATOR . 'bmi-');
1070 }
1071
1072 if (defined('BMI_PRO_PCLZIP') && file_exists(BMI_PRO_PCLZIP)) {
1073 require_once BMI_PRO_PCLZIP;
1074 if ($isFirstExtract) {
1075 $this->zip_progress->log(__('Using dedicated PclZIP for Premium Users.', 'backup-backup'), 'INFO');
1076 }
1077 } else {
1078 require_once trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
1079 }
1080 }
1081
1082 }
1083
1084 public function smartMemory($isFirstExtract = true) {
1085
1086 // Smart memory -- start //
1087 if ($this->zip_progress != null && $isFirstExtract) {
1088 $this->zip_progress->log(__("Smart memory calculation...", 'backup-backup'), 'STEP');
1089 }
1090
1091 if ((intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024) < 384) {
1092 @ini_set('memory_limit', '384M');
1093 }
1094
1095 $memory_limit = (intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024);
1096 if ($this->zip_progress != null && $isFirstExtract) {
1097 $this->zip_progress->log(str_replace('%s', $memory_limit, __("There is %s MBs of memory to use", 'backup-backup')), 'INFO');
1098 }
1099
1100 $safe_limit = intval($memory_limit / 4);
1101 if ($safe_limit > 64) $safe_limit = 64;
1102 if ($memory_limit === 384) $safe_limit = 78;
1103 if ($memory_limit >= 512) $safe_limit = 104;
1104 if ($memory_limit >= 1024) $safe_limit = 228;
1105 if ($memory_limit >= 2048) $safe_limit = 428;
1106
1107 // $real_memory = intval(memory_get_usage() * 0.9 / 1024 / 1024);
1108 // if ($real_memory < $safe_limit) $safe_limit = $real_memory;
1109 $safe_limit = intval($safe_limit * 0.8);
1110
1111 if ($this->zip_progress != null && $isFirstExtract) {
1112 $this->zip_progress->log(str_replace('%s', $safe_limit, __("Setting the safe limit to %s MB", 'backup-backup')), 'SUCCESS');
1113 }
1114 // Smart memory -- end //
1115
1116 return $safe_limit;
1117
1118 }
1119
1120 public function unzip_to($target_dir, $password = null) {
1121
1122 // validations -- start //
1123 if ($this->lib === 0 && $this->extr_file === 0) {
1124 throw new \Exception("PHP-ZIP: unzip_file hasn't been called");
1125 }
1126 // it exists, but it's not a directory
1127 if (file_exists($target_dir) && (!is_dir($target_dir))) {
1128 throw new \Exception("PHP-ZIP: Target directory exists as a file not a directory");
1129 }
1130 // it doesn't exist
1131 if (!file_exists($target_dir)) {
1132 if (!mkdir($target_dir)) {
1133 throw new \Exception("PHP-ZIP: Directory not found, and unable to create it");
1134 }
1135 }
1136
1137 if ($password !== null && $this->lib === 2) {
1138 throw new \Exception("PHP-ZIP: Password is not supported for PCLZip, please enable ZipArchive in your PHP installation to extract encrypted backups.");
1139 }
1140 // validations -- end //
1141
1142 // Target Directory
1143 $this->extr_dirc = $target_dir;
1144
1145 // Smart Memory
1146 $safe_limit = $this->smartMemory();
1147
1148 // Extract msg
1149 $this->zip_progress->log(__('Extracting files into temporary directory (this process can take some time)...', 'backup_migration'), 'STEP');
1150
1151 if (class_exists("ZipArchive")) $this->lib = 1;
1152 else $this->lib = 2;
1153
1154 // extract using ZipArchive
1155 if($this->lib === 1) {
1156 $lib = new \ZipArchive;
1157 if(!$lib->open($this->extr_file)) throw new \Exception("PHP-ZIP: Unable to open the zip file");
1158 if ($password !== null) $lib->setPassword($password);
1159 if(!$lib->extractTo($this->extr_dirc)) throw new \Exception("PHP-ZIP: Unable to extract files");
1160 $lib->close();
1161 }
1162
1163 // extarct using PclZip
1164 if ($this->lib === 2) {
1165 $this->loadPclZip();
1166 $lib = new \PclZip($this->extr_file);
1167 $restor = $lib->extract(PCLZIP_OPT_PATH, $this->extr_dirc, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
1168 if ($restor == 0) {
1169 $this->restore_failed($lib->errorInfo(true));
1170
1171 return false;
1172 }
1173 }
1174
1175 return true;
1176 }
1177
1178 private function dir_to_assoc_arr(DirectoryIterator $dir) {
1179 $data = [];
1180 foreach ($dir as $node) {
1181 if ($node->isDir() && !$node->isDot()) {
1182 $data[$node->getFilename()] = $this->dir_to_assoc_arr(new DirectoryIterator($node->getPathname()));
1183 } elseif ($node->isFile()) {
1184 $data[] = $node->getFilename();
1185 }
1186 }
1187
1188 return $data;
1189 }
1190
1191 private function path() {
1192 return join(DIRECTORY_SEPARATOR, func_get_args());
1193 }
1194
1195 private function commonPath($files, $remove = true) {
1196 foreach ($files as $index => $filesStr) {
1197 $files[$index] = explode(DIRECTORY_SEPARATOR, $filesStr);
1198 }
1199 $toDiff = $files;
1200 foreach ($toDiff as $arr_i => $arr) {
1201 foreach ($arr as $name_i => $name) {
1202 $toDiff[$arr_i][$name_i] = $name . "___" . $name_i;
1203 }
1204 }
1205 $diff = call_user_func_array("array_diff", $toDiff);
1206 reset($diff);
1207 $i = key($diff) - 1;
1208 if ($remove) {
1209 foreach ($files as $index => $arr) {
1210 $files[$index] = implode(DIRECTORY_SEPARATOR, array_slice($files[$index], $i));
1211 }
1212 } else {
1213 foreach ($files as $index => $arr) {
1214 $files[$index] = implode(DIRECTORY_SEPARATOR, array_slice($files[$index], 0, $i));
1215 }
1216 }
1217
1218 return $files;
1219 }
1220 }
1221