PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 1.3.0
Backup Migration v1.3.0
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 years ago
zip.php
892 lines
1 <?php
2
3 namespace BMI\Plugin\Zipper;
4
5 use BMI\Plugin\Backup_Migration_Plugin as BMP;
6 use BMI\Plugin\BMI_Logger as Logger;
7 use BMI\Plugin\Dashboard as Dashboard;
8 use BMI\Plugin\Database\BMI_Database as Database;
9 use BMI\Plugin\Database\BMI_Database_Exporter as BetterDatabaseExport;
10 use BMI\Plugin\Progress\BMI_ZipProgress as Progress;
11 use BMI\Plugin\Heart\BMI_Backup_Heart as Bypasser;
12
13 class Zip {
14 protected $lib;
15 protected $org_files;
16 protected $new_file_path;
17 protected $new_file_name;
18 protected $backupname;
19 protected $zip_progress;
20
21 protected $extr_file;
22 protected $extr_dirc;
23 protected $start_zip;
24
25 public function __construct() {
26 $this->lib = 0;
27 $this->extr_file = 0;
28 $this->new_file_path = 0;
29 $this->org_files = [];
30 }
31
32 public function zip_start($file_path, $files = [], $name = '', &$zip_progress = null, $start = null) {
33
34 // save the new file path
35 $this->new_file_path = $file_path;
36 $this->backupname = $name;
37 $this->zip_progress = $zip_progress;
38 $this->start_zip = $start;
39
40 if (sizeof($files) > 0) {
41 $this->org_files = $files;
42 }
43
44 // Some php installations doesn't have the ZipArchive
45 // So in this case we'll use another lib called PclZip
46 if (class_exists("ZipArchive") || class_exists("\ZipArchive")) {
47 $this->lib = 1;
48 } else {
49 $this->lib = 2;
50 }
51
52 return true;
53
54 }
55
56 public function return_bytes($val) {
57 $val = trim($val);
58 $last = strtolower($val[strlen($val) - 1]);
59 $val = substr($val, 0, -1);
60
61 switch ($last) {
62 // The 'G' modifier is available since PHP 5.1.0
63 case 'g':
64 $val *= 1024;
65 // no break
66 case 'm':
67 $val *= 1024;
68 // no break
69 case 'k':
70 $val *= 1024;
71 }
72
73 return $val;
74 }
75
76 public function zip_failed($error) {
77 Logger::error(__("There was an error during backup (packing)...", 'backup-backup'));
78 Logger::error($error);
79
80 if ($this->zip_progress != null) {
81 $this->zip_progress->log(__("Issues during backup (packing)...", 'backup-backup'), 'ERROR');
82 $this->zip_progress->log($error, 'ERROR');
83 }
84 }
85
86 public function restore_failed($error) {
87 Logger::error(__("There was an error during restore process (extracting)...", 'backup-backup'));
88 Logger::error($error);
89
90 if ($this->zip_progress != null) {
91 $this->zip_progress->log(__("Issues during restore process (extracting)...", 'backup-backup'), 'ERROR');
92 $this->zip_progress->log($error, 'ERROR');
93 }
94 }
95
96 public function zip_add($in) {
97
98 // Just to make sure.. if the user haven't called the earlier method
99 if ($this->lib === 0 || $this->new_file_path === 0) {
100 throw new \Exception("PHP-ZIP: must call zip_start before zip_add");
101 }
102
103 // Push file
104 array_push($this->org_files, $in);
105
106 // Return
107 return true;
108 }
109
110 public function createDatabaseDump($dbbackupname, $better_database_files_dir, &$database_file, $database_file_dir, $dbBackupEngine = 'v4') {
111
112 if (Dashboard\bmi_get_config('BACKUP:DATABASE') == 'true') {
113
114 if (Dashboard\bmi_get_config('OTHER:BACKUP:DB:SINGLE:FILE') == 'true') {
115
116 // Require Database Manager
117 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'manager.php';
118
119 // Logs
120 $this->zip_progress->log(__("Making single-file database backup (using deprecated engine, due to used settings)", 'backup-backup'), 'STEP');
121
122 // Get database dump
123 $databaser = new Database(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
124 $databaser->exportDatabase($dbbackupname);
125
126 // Fix for newer version
127 $this->db_exporter_queries = 0;
128 $this->zip_progress->total_queries = 0;
129 $this->db_exporter_files = [];
130
131 $this->dbDumped = true;
132 $this->zip_progress->log(__("Database size: ", 'backup-backup') . BMP::humanSize(filesize($database_file)), 'INFO');
133
134 } else {
135
136 if ($dbBackupEngine == 'v4') {
137
138 // Require Database Manager
139 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'better-backup-v3.php';
140
141 // Get database dump
142 $this->zip_progress->log(__("Making database backup (using v3 engine, requires at least v1.2.2 to restore)", 'backup-backup'), 'STEP');
143
144 } else {
145
146 // Require Database Manager
147 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'better-backup.php';
148
149 // Get database dump
150 $this->zip_progress->log(__("Making database backup (using v2 engine, requires at least v1.1.0 to restore)", 'backup-backup'), 'STEP');
151
152 }
153
154 $this->zip_progress->log(__("Iterating database...", 'backup-backup'), 'INFO');
155
156 if (!is_dir($better_database_files_dir)) @mkdir($better_database_files_dir, 0755, true);
157 $db_exporter = new BetterDatabaseExport($better_database_files_dir, $this->zip_progress);
158
159 $this->zip_progress->log('Exporting database via zip.php', 'VERBOSE');
160 $db_exporter->export();
161 $this->db_exporter_files = $db_exporter->files;
162 $this->db_exporter_queries = $db_exporter->total_queries;
163
164 $this->zip_progress->total_queries = $this->db_exporter_queries;
165
166 $this->dbDumped = true;
167 $this->zip_progress->log(__("Database backup finished", 'backup-backup'), 'SUCCESS');
168
169 }
170
171 } else {
172
173 $this->dbDumped = false;
174 $this->zip_progress->log(__("Omitting database backup (due to settings)...", 'backup-backup'), 'WARN');
175 $database_file = false;
176 $this->db_exporter_files = [];
177 $this->db_exporter_queries = 0;
178 $this->zip_progress->total_queries = 0;
179
180 }
181
182 }
183
184 public function zip_end($force_lib = false, $cron = false) {
185
186 // v4 for new one, v3 for old one
187 $dbBackupEngine = 'v4';
188
189 // Try to set limit
190 $this->zip_progress->log(__("Smart memory calculation...", 'backup-backup'), 'STEP');
191 if ((intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024) < 384) @ini_set('memory_limit', '384M');
192 if (defined('WP_MAX_MEMORY_LIMIT')) $maxwp = WP_MAX_MEMORY_LIMIT;
193 else $maxwp = '1M';
194
195 $memory_limit = (intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024);
196 $maxwp = (intval($this->return_bytes($maxwp)) / 1024 / 1024);
197
198 if ($maxwp > $memory_limit) $memory_limit = $maxwp;
199 $this->zip_progress->log(str_replace('%s', $memory_limit, __("There is %s MBs of memory to use", 'backup-backup')), 'INFO');
200 $this->zip_progress->log(str_replace('%s', $maxwp, __("WordPress memory limit: %s MBs", 'backup-backup')), 'INFO');
201 $safe_limit = intval($memory_limit / 4);
202 if ($safe_limit > 64) $safe_limit = 64;
203 if ($memory_limit === 384) $safe_limit = 96;
204 if ($memory_limit >= 512) $safe_limit = 128;
205 if ($memory_limit >= 1024) $safe_limit = 256;
206
207 // $real_memory = intval(memory_get_usage() * 0.9 / 1024 / 1024);
208 // if ($real_memory < $safe_limit) $safe_limit = $real_memory;
209 $safe_limit = intval($safe_limit * 0.9);
210
211 $this->zip_progress->log(str_replace('%s', $safe_limit, __("Setting the safe limit to %s MB", 'backup-backup')), 'SUCCESS');
212
213 $abs = BMP::fixSlashes(ABSPATH) . DIRECTORY_SEPARATOR;
214
215 $dbbackupname = 'bmi_database_backup.sql';
216 $database_file = BMP::fixSlashes(BMI_INCLUDES . DIRECTORY_SEPARATOR . 'htaccess' . DIRECTORY_SEPARATOR . $dbbackupname);
217 $database_file_dir = BMP::fixSlashes((dirname($database_file))) . DIRECTORY_SEPARATOR;
218 $better_database_files_dir = $database_file_dir . 'db_tables';
219
220 // force usage of specific lib (for testing purposes)
221 if ($force_lib === 2) {
222
223 $this->lib = 2;
224
225 } elseif ($force_lib === 1) {
226
227 $this->lib = 1;
228
229 }
230
231 $this->dbDumped = false;
232 $this->db_exporter_queries = 0;
233 $this->zip_progress->total_queries = 0;
234 $this->db_exporter_files = [];
235
236 // just to make sure.. if the user haven't called the earlier method
237 if ($this->lib === 0 || $this->new_file_path === 0) {
238 throw new \Exception('PHP-ZIP: zip_start and zip_add haven\'t been called yet');
239 }
240
241 // using zipArchive class
242 // if ($this->lib === 1) {
243 //
244 // // Create DB Dump
245 // $this->createDatabaseDump($dbbackupname, $better_database_files_dir, $database_file, $database_file_dir);
246 //
247 // // All files
248 // $max = sizeof($this->org_files);
249 // $this->zip_progress->log(__("Making archive", 'backup-backup'), 'STEP');
250 // $this->zip_progress->log(__("Compressing...", 'backup-backup'), 'INFO');
251 //
252 // // Verbose
253 // $this->zip_progress->log(__("Using Zlib to create Backup", 'backup-backup'));
254 //
255 // $lib = new \ZipArchive();
256 // if (!$lib->open($this->new_file_path, \ZipArchive::CREATE)) {
257 // throw new \Exception('PHP-ZIP: Permission Denied or zlib can\'t be found');
258 // }
259 //
260 // // Add each file
261 // for ($i = 0; $i < $max; $i++) {
262 // $file = $this->org_files[$i];
263 // $zippath = substr($file, strlen($abs));
264 // $lib->addFile($file, 'wordpress' . DIRECTORY_SEPARATOR . $zippath);
265 //
266 // if ($i % 100 === 0) {
267 // if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) {
268 // break;
269 // }
270 // $this->zip_progress->progress($i + 1 . '/' . $max);
271 // }
272 //
273 // if (($i + 1) % 500 === 0 || $i == 0) {
274 // if (($i + 1) < $max) {
275 // $this->zip_progress->log((__("Milestone: ", 'backup-backup') . ($i + 1) . '/' . $max), 'info');
276 // }
277 // }
278 // }
279 //
280 // if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) {
281 //
282 // // close the archive
283 // $lib->close();
284 // } else {
285 // $this->zip_progress->log((__("Milestone: ", 'backup-backup') . $max . '/' . $max), 'info');
286 // $this->zip_progress->log(__("Compressed ", 'backup-backup') . $max . __(" files", 'backup-backup'), 'SUCCESS');
287 //
288 // // Log time of ZIP Process
289 // $this->zip_progress->log(__("Archiving of ", 'backup-backup') . $max . __(" files took: ", 'backup-backup') . number_format(microtime(true) - $this->start_zip, 2) . 's');
290 //
291 // $this->zip_progress->log(__("Finalizing backup", 'backup-backup'), 'STEP');
292 // $this->zip_progress->log(__("Adding manifest...", 'backup-backup'), 'INFO');
293 // $this->zip_progress->log(__("Closing files and archives", 'backup-backup'), 'STEP');
294 // $this->zip_progress->log('#001', 'END-CODE');
295 //
296 // $this->zip_progress->end();
297 // $logs = file_get_contents(BMI_BACKUPS . DIRECTORY_SEPARATOR . 'latest.log');
298 // $this->zip_progress->start(true);
299 //
300 // if ($database_file !== false) {
301 // if (Dashboard\bmi_get_config('OTHER:BACKUP:DB:SINGLE:FILE') == 'true') {
302 // if (file_exists($database_file)) {
303 // $lib->addFile($database_file, 'bmi_database_backup.sql');
304 // }
305 // } else {
306 // if ($db_exporter_files && sizeof($db_exporter_files) > 0) {
307 // for ($i = 0; $i < sizeof($db_exporter_files); ++$i) {
308 // $lib->addFile($db_exporter_files[$i], 'db_tables' . DIRECTORY_SEPARATOR . basename($db_exporter_files[$i]));
309 // }
310 // }
311 // }
312 // }
313 //
314 // $lib->addFromString('bmi_backup_manifest.json', $this->zip_progress->createManifest($dbBackupEngine));
315 // $lib->addFromString('bmi_logs_this_backup.log', $logs);
316 // $this->zip_progress->progress($max . '/' . $max);
317 //
318 // // close the archive
319 // $lib->close();
320 // }
321 // }
322
323 // using PclZip
324 if ($this->lib === 2) {
325
326 // All files
327 $max = sizeof($this->org_files);
328
329 // Verbose
330 $legacy = BMI_LEGACY_VERSION;
331 if ($legacy) $legacy = BMI_LEGACY_HARD_VERSION;
332 $this->zip_progress->log(__("Using PclZip module to create the backup", 'backup-backup'), 'INFO');
333 if (!BMI_LEGACY_VERSION) {
334 $this->zip_progress->log(__("Legacy setting: Using server-sided script and cURL based loop for better capabilities", 'backup-backup'), 'INFO');
335 } elseif (!BMI_LEGACY_HARD_VERSION) {
336 $this->zip_progress->log(__("Legacy setting: Using user browser as middleware for full capabilities", 'backup-backup'), 'INFO');
337 } else {
338
339 $this->zip_progress->log(__("Legacy setting: Using default modules depending on user server", 'backup-backup'), 'INFO');
340
341 // Create DB Dump
342 $this->createDatabaseDump($dbbackupname, $better_database_files_dir, $database_file, $database_file_dir, $dbBackupEngine);
343
344 $this->zip_progress->log(__("Making archive", 'backup-backup'), 'STEP');
345 $this->zip_progress->log(__("Compressing...", 'backup-backup'), 'INFO');
346
347 }
348
349 // Run the backup in background
350 if ((!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false) && ($legacy === false || BMI_CLI_ENABLED === true) && sizeof($this->org_files) > 10 && !defined('BMI_CLI_FAILED')) {
351 file_put_contents($database_file_dir . 'bmi_backup_manifest.json', $this->zip_progress->createManifest($dbBackupEngine));
352 $url = plugins_url(null) . '/backup-backup/includes/backup-heart.php';
353 $identy = 'BMI-' . rand(10000000, 999999999);
354 $remote_settings = [
355 'identy' => $identy,
356 'manifest' => $database_file_dir . 'bmi_backup_manifest.json',
357 'backupname' => $this->backupname,
358 'safelimit' => $safe_limit,
359 'rev' => BMI_REV,
360 'total_files' => sizeof($this->org_files),
361 'filessofar' => 0,
362 'start' => microtime(true),
363 'config_dir' => BMI_CONFIG_DIR,
364 'content_dir' => trailingslashit(WP_CONTENT_DIR),
365 'backup_dir' => BMI_BACKUPS,
366 'abs_dir' => trailingslashit(ABSPATH),
367 'root_dir' => plugin_dir_path(BMI_ROOT_FILE),
368 'browser' => false,
369 'shareallowed' => BMP::canShareLogsOrShouldAsk(),
370 'dbiteratio' => 0,
371 'dblast' => 0,
372 'url' => $url
373 ];
374
375 $fix = true;
376 $Xfiles = glob(BMI_INCLUDES . '/htaccess' . '/.BMI-*');
377 foreach ($Xfiles as $xfile) if (is_file($xfile)) unlink($xfile);
378 touch(BMI_INCLUDES . '/htaccess' . '/.' . $identy);
379
380 if ($fix === true) {
381 if (BMI_LEGACY_HARD_VERSION === false && $cron === false) {
382 $remote_settings['browser'] = true;
383 $this->zip_progress->log(__("Sending backup settings and identy to the browser", 'backup-backup'), 'INFO');
384 BMP::res(['status' => 'background_hard', 'filename' => $this->backupname, 'settings' => $remote_settings, 'url' => $url]);
385 exit;
386 } else {
387 $this->zip_progress->log(__('Starting background process on server-side...', 'backup-backup'), 'INFO');
388 require_once BMI_INCLUDES . '/bypasser.php';
389 $request = new Bypasser(false, BMI_CONFIG_DIR, trailingslashit(WP_CONTENT_DIR), BMI_BACKUPS, trailingslashit(ABSPATH), plugin_dir_path(BMI_ROOT_FILE), $url, $remote_settings);
390 $request->send_beat(true, $this->zip_progress);
391 }
392 }
393
394 sleep(2);
395 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running')) {
396 if (file_exists(BMI_INCLUDES . '/htaccess' . '/.' . $identy . '-running')) {
397 // $this->zip_progress->log(__('Request received correctly – backup is running.', 'backup-backup'), 'SUCCESS');
398 BMP::res(['status' => 'background', 'filename' => $this->backupname]);
399 exit;
400 } else {
401 $this->zip_progress->log(__('Could not find any response from the server, trying again in 3 seconds.', 'backup-backup'), 'WARN');
402 sleep(3);
403 if (file_exists(BMI_INCLUDES . '/htaccess' . '/.' . $identy . '-running')) {
404 // $this->zip_progress->log(__('Request received correctly – backup is running.', 'backup-backup'), 'SUCCESS');
405 BMP::res(['status' => 'background', 'filename' => $this->backupname]);
406 exit;
407 } else {
408 $this->zip_progress->log(__('Still nothing backup probably is not running.', 'backup-backup'), 'WARN');
409 if (file_exists(BMI_INCLUDES . '/htaccess' . '/.' . $identy . '-running')) @unlink(BMI_INCLUDES . '/htaccess' . '/.' . $identy . '-running');
410 if (file_exists(BMI_INCLUDES . '/htaccess' . '/.' . $identy)) @unlink(BMI_INCLUDES . '/htaccess' . '/.' . $identy);
411 throw new \Exception('Backup could not run on your server, please check global logs.');
412 }
413 }
414 } else {
415 BMP::res(['status' => 'background', 'filename' => $this->backupname]);
416 exit;
417 }
418
419 // ob_end_clean();
420 exit;
421 } else {
422 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
423 $this->zip_progress->log(__("Backup is running under PHP CLI environment.", 'backup-backup'), 'INFO');
424 if ($this->dbDumped === false) {
425 $this->createDatabaseDump($dbbackupname, $better_database_files_dir, $database_file, $database_file_dir);
426 }
427 } else {
428 $this->zip_progress->log(__("Backup will run as single-request, may be unstable...", 'backup-backup'), 'WARN');
429 }
430 }
431
432 // require the lib
433 if (!class_exists('PclZip')) {
434 if (!defined('PCLZIP_TEMPORARY_DIR')) {
435 $bmi_tmp_dir = BMI_ROOT_DIR . '/tmp';
436 if (!file_exists($bmi_tmp_dir)) {
437 @mkdir($bmi_tmp_dir, 0775, true);
438 }
439 define('PCLZIP_TEMPORARY_DIR', $bmi_tmp_dir . '/bmi-');
440 }
441 if (defined('BMI_PRO_PCLZIP') && file_exists(BMI_PRO_PCLZIP)) {
442 $this->zip_progress->log(__('Using dedicated PclZIP for Premium Users.', 'backup-backup'), 'INFO');
443 require_once BMI_PRO_PCLZIP;
444 } else {
445 require_once trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
446 }
447 }
448 $common = $this->org_files;
449
450 if (!$lib = new \PclZip($this->new_file_path)) {
451 throw new \Exception('PHP-ZIP: Permission Denied or zlib can\'t be found');
452 }
453
454 if ($this->dbDumped === true) {
455 try {
456
457 $this->zip_progress->log(__('Adding database SQL file(s) to the backup file.', 'backup-backup'), 'STEP');
458
459 $files = [];
460
461 if ($database_file !== false && !($this->db_exporter_files && sizeof($this->db_exporter_files) > 0)) {
462 $files[] = $database_file;
463 }
464
465 if ($this->db_exporter_files && sizeof($this->db_exporter_files) > 0) {
466 for ($i = 0; $i < sizeof($this->db_exporter_files); ++$i) {
467 $files[] = $this->db_exporter_files[$i];
468 }
469 }
470
471 $dbback = $lib->add($files, PCLZIP_OPT_REMOVE_PATH, $database_file_dir);
472
473 if ($dbback == 0) {
474 $this->zip_failed($lib->errorInfo(true));
475 return false;
476 }
477
478 } catch (\Exception $e) {
479 $this->zip_failed($e->getMessage());
480
481 return false;
482 } catch (\Throwable $e) {
483 $this->zip_failed($e->getMessage());
484
485 return false;
486 }
487
488 $this->zip_progress->log(__('Database added to the backup successfully.', 'backup-backup'), 'SUCCESS');
489 }
490
491 $this->zip_progress->log(__('Performing site files backup...', 'backup-backup'), 'STEP');
492
493 try {
494 $splitby = 200; $milestoneby = 500;
495 $filestotal = sizeof($this->org_files);
496 if ($filestotal < 3000) { $splitby = 250; $milestoneby = 500; }
497 if ($filestotal > 5000) { $splitby = 500; $milestoneby = 500; }
498 if ($filestotal > 10000) { $splitby = 1000; $milestoneby = 1000; }
499 if ($filestotal > 15000) { $splitby = 2000; $milestoneby = 2000; }
500 if ($filestotal > 20000) { $splitby = 4000; $milestoneby = 4000; }
501 if ($filestotal > 25000) { $splitby = 6000; $milestoneby = 6000; }
502 if ($filestotal > 30000) { $splitby = 8000; $milestoneby = 8000; }
503 if ($filestotal > 32000) { $splitby = 10000; $milestoneby = 10000; }
504 if ($filestotal > 60500) { $splitby = 20000; $milestoneby = 20000; }
505 if ($filestotal > 90500) { $splitby = 40000; $milestoneby = 40000; }
506
507 $this->zip_progress->log(__("Chunks contain ", 'backup-backup') . $splitby . __(" files.", 'backup-backup'));
508
509 $chunks = array_chunk($this->org_files, $splitby);
510 $chunkslen = sizeof($chunks);
511 if ($chunkslen > 0) {
512 $sizeoflast = sizeof($chunks[$chunkslen - 1]);
513 if ($chunkslen > 1 && $sizeoflast == 1) {
514 $buffer = array_slice($chunks[$chunkslen - 2], -1);
515 $chunks[$chunkslen - 2] = array_slice($chunks[$chunkslen - 2], 0, -1);
516 $chunks[$chunkslen - 1][] = $buffer[0];
517 }
518 }
519
520 for ($i = 0; $i < $chunkslen; ++$i) {
521
522 // Abort if user wants it (check every 100 files)
523 if (file_exists(BMI_BACKUPS . '/.abort')) {
524 break;
525 }
526
527 $chunk = $chunks[$i];
528 $back = $lib->add($chunk, 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);
529 if ($back == 0) {
530 $this->zip_failed($lib->errorInfo(true));
531 return false;
532 }
533
534 $curfile = (($i * $splitby) + $splitby);
535 $this->zip_progress->progress($curfile . '/' . $max);
536 if ($curfile % $milestoneby === 0 && $curfile < $max) {
537 $this->zip_progress->log(__("Milestone: ", 'backup-backup') . ($curfile . '/' . $max), 'info');
538 }
539 }
540
541 } catch (\Exception $e) {
542 $this->zip_failed($e->getMessage());
543
544 return false;
545 } catch (\Throwable $e) {
546 $this->zip_failed($e->getMessage());
547
548 return false;
549 }
550
551 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) {
552
553 if (file_exists($database_file_dir . 'bmi_backup_manifest.json')) {
554 @unlink($database_file_dir . 'bmi_backup_manifest.json');
555 }
556 if (file_exists($database_file_dir . 'bmi_logs_this_backup.log')) {
557 @unlink($database_file_dir . 'bmi_logs_this_backup.log');
558 }
559
560 } else {
561
562 // End
563 $this->zip_progress->log(__("Milestone: ", 'backup-backup') . ($max . '/' . $max), 'info');
564 $this->zip_progress->log(__("Compressed ", 'backup-backup') . $max . __(" files", 'backup-backup'), 'SUCCESS');
565
566 // Log time of ZIP Process
567 $this->zip_progress->log(__("Archiving of ", 'backup-backup') . $max . __(" files took: ", 'backup-backup') . number_format(microtime(true) - $this->start_zip, 2) . 's');
568
569 $this->zip_progress->log(__("Finalizing backup", 'backup-backup'), 'STEP');
570 $this->zip_progress->log(__("Adding manifest...", 'backup-backup'), 'INFO');
571 $this->zip_progress->log(__("Closing files and archives", 'backup-backup'), 'STEP');
572 $this->zip_progress->log('#001', 'END-CODE');
573
574 $this->zip_progress->end();
575
576 file_put_contents($database_file_dir . 'bmi_backup_manifest.json', $this->zip_progress->createManifest($dbBackupEngine));
577 file_put_contents($database_file_dir . 'bmi_logs_this_backup.log', file_get_contents(BMI_BACKUPS . DIRECTORY_SEPARATOR . 'latest.log'));
578
579 $this->zip_progress->start(true);
580
581 $files = [];
582
583 if (file_exists($database_file_dir . 'bmi_logs_this_backup.log')) $files[] = $database_file_dir . 'bmi_logs_this_backup.log';
584 if (file_exists($database_file_dir . 'bmi_backup_manifest.json')) $files[] = $database_file_dir . 'bmi_backup_manifest.json';
585 else {
586
587 $this->zip_failed('Manifest file could not be added, manifest does not exist.');
588 return false;
589
590 }
591
592 try {
593
594 $maback = $lib->add($files, PCLZIP_OPT_REMOVE_PATH, $database_file_dir);
595
596 if ($maback == 0) {
597 $this->zip_failed($lib->errorInfo(true));
598 return false;
599 }
600
601 } catch (\Exception $e) {
602 $this->zip_failed($e->getMessage());
603
604 return false;
605 } catch (\Throwable $e) {
606 $this->zip_failed($e->getMessage());
607
608 return false;
609 }
610
611 if (file_exists($database_file_dir . 'bmi_backup_manifest.json')) {
612 @unlink($database_file_dir . 'bmi_backup_manifest.json');
613 }
614 if (file_exists($database_file_dir . 'bmi_logs_this_backup.log')) {
615 @unlink($database_file_dir . 'bmi_logs_this_backup.log');
616 }
617
618 $this->zip_progress->progress($max . '/' . $max);
619
620 }
621 }
622
623 // Remove Better DB SQL Files
624 if ($this->db_exporter_files && sizeof($this->db_exporter_files) > 0) {
625 for ($i = 0; $i < sizeof($this->db_exporter_files); ++$i) {
626 if (file_exists($this->db_exporter_files[$i])) @unlink($this->db_exporter_files[$i]);
627 }
628 @rmdir($better_database_files_dir);
629 }
630
631 if ($database_file && file_exists($database_file)) @unlink($database_file);
632 if (!file_exists($this->new_file_path)) {
633 throw new \Exception('PHP-ZIP: After doing the zipping file can not be found');
634 }
635 if (filesize($this->new_file_path) === 0) {
636 throw new \Exception('PHP-ZIP: After doing the zipping file size is still 0 bytes');
637 }
638
639 // empty the array
640 $this->org_files = [];
641
642 return true;
643 }
644
645 public function zip_files($files, $to) {
646 $this->zip_start($to);
647 $this->zip_add($files);
648
649 return $this->zip_end();
650 }
651
652 public function unzip_file($file_path, $target_dir = null, &$zip_progress = null) {
653
654 // Progress
655 $this->zip_progress = $zip_progress;
656
657 // if it doesn't exist
658 if (!file_exists($file_path)) {
659 throw new \Exception("PHP-ZIP: File doesn't Exist");
660 }
661
662 $this->extr_file = $file_path;
663
664 // if (class_exists("ZipArchive")) $this->lib = 1;
665 // else $this->lib = 2;
666 $this->lib = 2;
667
668 if ($target_dir !== null) {
669 return $this->unzip_to($target_dir);
670 } else {
671 return true;
672 }
673 }
674
675 public function extract_files($zip_path, $files, $target_dir = null, &$zip_progress = null, $isFirstExtract = true) {
676
677 $this->zip_progress = $zip_progress;
678
679 // it exists, but it's not a directory
680 if (file_exists($target_dir) && (!is_dir($target_dir))) {
681 throw new \Exception("PHP-ZIPv2: Target directory exists as a file not a directory");
682 }
683 // it doesn't exist
684 if (!file_exists($target_dir)) {
685 if (!mkdir($target_dir)) {
686 throw new \Exception("PHP-ZIPv2: Directory not found, and unable to create it");
687 }
688 }
689 // validations -- end //
690 // TODO: NOTICE: Force disable PCLZIP
691 if (false && (class_exists("ZipArchive") || class_exists("\ZipArchive"))) {
692
693 $zip = new \ZipArchive;
694 $res = $zip->open($zip_path);
695
696 if ($res === true) {
697
698 if ($isFirstExtract) {
699 $this->zip_progress->log(__("Using ZipArchive, omiting memory limit calculations...", 'backup-backup'), 'INFO');
700 }
701
702 $zip->extractTo($target_dir, $files);
703 $zip->close();
704 return true;
705
706 } else {
707
708 $this->restore_failed('PHP-ZIPv2: Could not open Backup with ZipArchive.');
709 return false;
710
711 }
712
713 } else {
714
715 if ($isFirstExtract) {
716 $this->zip_progress->log(__("ZipArchive is not available, using PclZIP.", 'backup-backup'), 'INFO');
717 }
718
719 $safe_limit = $this->smartMemory($isFirstExtract);
720 $this->loadPclZip($isFirstExtract);
721 $lib = new \PclZip($zip_path);
722 $restor = $lib->extract(PCLZIP_OPT_BY_NAME, $files, PCLZIP_OPT_PATH, $target_dir, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
723
724 if ($restor == 0) {
725
726 $this->restore_failed($lib->errorInfo(true));
727 return false;
728
729 }
730
731 return true;
732
733 }
734
735 }
736
737 public function loadPclZip($isFirstExtract = true) {
738
739 if (!class_exists('PclZip')) {
740 if (!defined('PCLZIP_TEMPORARY_DIR')) {
741 $bmi_tmp_dir = BMI_ROOT_DIR . '/tmp';
742 if (!file_exists($bmi_tmp_dir)) {
743 @mkdir($bmi_tmp_dir, 0775, true);
744 }
745 define('PCLZIP_TEMPORARY_DIR', $bmi_tmp_dir . '/bmi-');
746 }
747
748 if (defined('BMI_PRO_PCLZIP') && file_exists(BMI_PRO_PCLZIP)) {
749 require_once BMI_PRO_PCLZIP;
750 if ($isFirstExtract) {
751 $this->zip_progress->log(__('Using dedicated PclZIP for Premium Users.', 'backup-backup'), 'INFO');
752 }
753 } else {
754 require_once trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
755 }
756 }
757
758 }
759
760 public function smartMemory($isFirstExtract = true) {
761
762 // Smart memory -- start //
763 if ($this->zip_progress != null && $isFirstExtract) {
764 $this->zip_progress->log(__("Smart memory calculation...", 'backup-backup'), 'STEP');
765 }
766
767 if ((intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024) < 384) {
768 @ini_set('memory_limit', '384M');
769 }
770
771 $memory_limit = (intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024);
772 if ($this->zip_progress != null && $isFirstExtract) {
773 $this->zip_progress->log(str_replace('%s', $memory_limit, __("There is %s MBs of memory to use", 'backup-backup')), 'INFO');
774 }
775
776 $safe_limit = intval($memory_limit / 4);
777 if ($safe_limit > 64) $safe_limit = 64;
778 if ($memory_limit === 384) $safe_limit = 78;
779 if ($memory_limit >= 512) $safe_limit = 104;
780 if ($memory_limit >= 1024) $safe_limit = 228;
781 if ($memory_limit >= 2048) $safe_limit = 428;
782
783 // $real_memory = intval(memory_get_usage() * 0.9 / 1024 / 1024);
784 // if ($real_memory < $safe_limit) $safe_limit = $real_memory;
785 $safe_limit = intval($safe_limit * 0.8);
786
787 if ($this->zip_progress != null && $isFirstExtract) {
788 $this->zip_progress->log(str_replace('%s', $safe_limit, __("Setting the safe limit to %s MB", 'backup-backup')), 'SUCCESS');
789 }
790 // Smart memory -- end //
791
792 return $safe_limit;
793
794 }
795
796 public function unzip_to($target_dir) {
797
798 // validations -- start //
799 if ($this->lib === 0 && $this->extr_file === 0) {
800 throw new \Exception("PHP-ZIP: unzip_file hasn't been called");
801 }
802 // it exists, but it's not a directory
803 if (file_exists($target_dir) && (!is_dir($target_dir))) {
804 throw new \Exception("PHP-ZIP: Target directory exists as a file not a directory");
805 }
806 // it doesn't exist
807 if (!file_exists($target_dir)) {
808 if (!mkdir($target_dir)) {
809 throw new \Exception("PHP-ZIP: Directory not found, and unable to create it");
810 }
811 }
812 // validations -- end //
813
814 // Target Directory
815 $this->extr_dirc = $target_dir;
816
817 // Smart Memory
818 $safe_limit = $this->smartMemory();
819
820 // Extract msg
821 $this->zip_progress->log(__('Extracting files into temporary directory (this process can take some time)...', 'backup_migration'), 'STEP');
822
823 // Force PCL Zip
824 $this->lib = 2;
825
826 // extract using ZipArchive
827 // if($this->lib === 1) {
828 // $lib = new \ZipArchive;
829 // if(!$lib->open($this->extr_file)) throw new \Exception("PHP-ZIP: Unable to open the zip file");
830 // if(!$lib->extractTo($this->extr_dirc)) throw new \Exception("PHP-ZIP: Unable to extract files");
831 // $lib->close();
832 // }
833
834 // extarct using PclZip
835 if ($this->lib === 2) {
836 $this->loadPclZip();
837 $lib = new \PclZip($this->extr_file);
838 $restor = $lib->extract(PCLZIP_OPT_PATH, $this->extr_dirc, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
839 if ($restor == 0) {
840 $this->restore_failed($lib->errorInfo(true));
841
842 return false;
843 }
844 }
845
846 return true;
847 }
848
849 private function dir_to_assoc_arr(DirectoryIterator $dir) {
850 $data = [];
851 foreach ($dir as $node) {
852 if ($node->isDir() && !$node->isDot()) {
853 $data[$node->getFilename()] = $this->dir_to_assoc_arr(new DirectoryIterator($node->getPathname()));
854 } elseif ($node->isFile()) {
855 $data[] = $node->getFilename();
856 }
857 }
858
859 return $data;
860 }
861
862 private function path() {
863 return join(DIRECTORY_SEPARATOR, func_get_args());
864 }
865
866 private function commonPath($files, $remove = true) {
867 foreach ($files as $index => $filesStr) {
868 $files[$index] = explode(DIRECTORY_SEPARATOR, $filesStr);
869 }
870 $toDiff = $files;
871 foreach ($toDiff as $arr_i => $arr) {
872 foreach ($arr as $name_i => $name) {
873 $toDiff[$arr_i][$name_i] = $name . "___" . $name_i;
874 }
875 }
876 $diff = call_user_func_array("array_diff", $toDiff);
877 reset($diff);
878 $i = key($diff) - 1;
879 if ($remove) {
880 foreach ($files as $index => $arr) {
881 $files[$index] = implode(DIRECTORY_SEPARATOR, array_slice($files[$index], $i));
882 }
883 } else {
884 foreach ($files as $index => $arr) {
885 $files[$index] = implode(DIRECTORY_SEPARATOR, array_slice($files[$index], 0, $i));
886 }
887 }
888
889 return $files;
890 }
891 }
892