PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.1.2
Backup Migration v2.1.2
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 3 months ago
zip.php
1164 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
269 // force usage of specific lib (for testing purposes)
270 if ($force_lib === 2) {
271
272 $this->lib = 2;
273
274 } elseif ($force_lib === 1) {
275
276 $this->lib = 1;
277
278 }
279
280 $this->dbDumped = false;
281 $this->db_exporter_queries = 0;
282 $this->zip_progress->total_queries = 0;
283 $this->db_exporter_files = [];
284
285 // just to make sure.. if the user haven't called the earlier method
286 if ($this->lib === 0 || $this->new_file_path === 0) {
287 throw new \Exception('PHP-ZIP: zip_start and zip_add haven\'t been called yet');
288 }
289
290 // using zipArchive class
291 // if ($this->lib === 1) {
292 //
293 // // Create DB Dump
294 // $this->createDatabaseDump($dbbackupname, $better_database_files_dir, $database_file, $database_file_dir);
295 //
296 // // All files
297 // $max = sizeof($this->org_files);
298 // $this->zip_progress->log(__("Making archive", 'backup-backup'), 'STEP');
299 // $this->zip_progress->log(__("Compressing...", 'backup-backup'), 'INFO');
300 //
301 // // Verbose
302 // $this->zip_progress->log(__("Using Zlib to create Backup", 'backup-backup'));
303 //
304 // $lib = new \ZipArchive();
305 // if (!$lib->open($this->new_file_path, \ZipArchive::CREATE)) {
306 // throw new \Exception('PHP-ZIP: Permission Denied or zlib can\'t be found');
307 // }
308 //
309 // // Add each file
310 // for ($i = 0; $i < $max; $i++) {
311 // $file = $this->org_files[$i];
312 // $zippath = substr($file, strlen($abs));
313 // $lib->addFile($file, 'wordpress' . DIRECTORY_SEPARATOR . $zippath);
314 //
315 // if ($i % 100 === 0) {
316 // if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) {
317 // break;
318 // }
319 // $this->zip_progress->progress($i + 1 . '/' . $max);
320 // }
321 //
322 // if (($i + 1) % 500 === 0 || $i == 0) {
323 // if (($i + 1) < $max) {
324 // $this->zip_progress->log((__("Milestone: ", 'backup-backup') . ($i + 1) . '/' . $max), 'info');
325 // }
326 // }
327 // }
328 //
329 // if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) {
330 //
331 // // close the archive
332 // $lib->close();
333 // } else {
334 // $this->zip_progress->log((__("Milestone: ", 'backup-backup') . $max . '/' . $max), 'info');
335 // $this->zip_progress->log(__("Compressed ", 'backup-backup') . $max . __(" files", 'backup-backup'), 'SUCCESS');
336 //
337 // // Log time of ZIP Process
338 // $this->zip_progress->log(__("Archiving of ", 'backup-backup') . $max . __(" files took: ", 'backup-backup') . number_format(microtime(true) - $this->start_zip, 2) . 's');
339 //
340 // $this->zip_progress->log(__("Finalizing backup", 'backup-backup'), 'STEP');
341 // $this->zip_progress->log(__("Adding manifest...", 'backup-backup'), 'INFO');
342 // $this->zip_progress->log(__("Closing files and archives", 'backup-backup'), 'STEP');
343 // $this->zip_progress->log('#001', 'END-CODE');
344 //
345 // $this->zip_progress->end();
346 // $logs = file_get_contents(BMI_BACKUPS . DIRECTORY_SEPARATOR . 'latest.log');
347 // $this->zip_progress->start(true);
348 //
349 // if ($database_file !== false) {
350 // if (Dashboard\bmi_get_config('OTHER:BACKUP:DB:SINGLE:FILE') == 'true') {
351 // if (file_exists($database_file)) {
352 // $lib->addFile($database_file, 'bmi_database_backup.sql');
353 // }
354 // } else {
355 // if ($db_exporter_files && sizeof($db_exporter_files) > 0) {
356 // for ($i = 0; $i < sizeof($db_exporter_files); ++$i) {
357 // $lib->addFile($db_exporter_files[$i], 'db_tables' . DIRECTORY_SEPARATOR . basename($db_exporter_files[$i]));
358 // }
359 // }
360 // }
361 // }
362 //
363 // $lib->addFromString('bmi_backup_manifest.json', $this->zip_progress->createManifest($dbBackupEngine));
364 // $lib->addFromString('bmi_logs_this_backup.log', $logs);
365 // $this->zip_progress->progress($max . '/' . $max);
366 //
367 // // close the archive
368 // $lib->close();
369 // }
370 // }
371
372 // using PclZip
373 if ($this->lib === 2) {
374
375 // All files
376 $max = sizeof($this->org_files);
377
378 $legacyVersion = apply_filters('bmi_legacy_version', BMI_LEGACY_VERSION);
379 $legacyHardVersion = apply_filters('bmi_legacy_hard_version', BMI_LEGACY_HARD_VERSION);
380 // Verbose
381 $legacy = $legacyVersion;
382 if ($legacy) $legacy = $legacyHardVersion;
383 if (class_exists('\ZipArchive') || class_exists('ZipArchive')) {
384 $this->zip_progress->log(__("ZipArchive is available this process should use ZipArchive", 'backup-backup'), 'INFO');
385 } else {
386 $this->zip_progress->log(__("Using PclZip module to create the backup", 'backup-backup'), 'INFO');
387 }
388 if (!$legacyVersion) {
389 $this->zip_progress->log(__("Legacy setting: Using server-sided script and cURL based loop for better capabilities", 'backup-backup'), 'INFO');
390 } elseif (!$legacyHardVersion) {
391 $this->zip_progress->log(__("Legacy setting: Using user browser as middleware for full capabilities", 'backup-backup'), 'INFO');
392 } else {
393
394 $this->zip_progress->log(__("Legacy setting: Using default modules depending on user server", 'backup-backup'), 'INFO');
395
396 // Create DB Dump
397 $this->createDatabaseDump($dbbackupname, $better_database_files_dir, $database_file, $database_file_dir, $dbBackupEngine);
398
399 $this->zip_progress->log(__("Making archive", 'backup-backup'), 'STEP');
400 $this->zip_progress->log(__("Compressing...", 'backup-backup'), 'INFO');
401
402 }
403
404 // Run the backup in background
405 $cliEnabled = false;
406 if (defined('BMI_CLI_ENABLED')) $cliEnabled = apply_filters('bmi_cli_enabled', BMI_CLI_ENABLED);
407 if ((!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false) && ($legacy === false || $cliEnabled === true) && sizeof($this->org_files) > 10 && !defined('BMI_CLI_FAILED')) {
408 file_put_contents($database_file_dir . 'bmi_backup_manifest.json', $this->zip_progress->createManifest($dbBackupEngine));
409 // $url = plugins_url('') . '/backup-backup/includes/middleware-backup-proxy.php';
410 $url = admin_url('admin-ajax.php');
411 $identy = 'BMI-' . rand(10000000, 99999999);
412 $remote_settings = [
413 'identy' => $identy,
414 'manifest' => $database_file_dir . 'bmi_backup_manifest.json',
415 'backupname' => $this->backupname,
416 'safelimit' => $safe_limit,
417 'rev' => BMI_REV,
418 'total_files' => sizeof($this->org_files),
419 'filessofar' => 0,
420 'start' => microtime(true),
421 'config_dir' => BMI_CONFIG_DIR,
422 'content_dir' => trailingslashit(WP_CONTENT_DIR),
423 'backup_dir' => BMI_BACKUPS,
424 'abs_dir' => trailingslashit(ABSPATH),
425 'root_dir' => plugin_dir_path(BMI_ROOT_FILE),
426 'browser' => false,
427 'shareallowed' => BMP::canShareLogsOrShouldAsk(),
428 'dbiteratio' => 0,
429 'it' => 0,
430 'dbit' => 0,
431 'dblast' => 0,
432 'bmitmp' => BMI_TMP,
433 'url' => $url,
434 'db_v2_engine' => false,
435 'final_made' => false,
436 'final_batch' => false,
437 'dbitJustFinished' => false,
438 'useragent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'WordPress.org Site Self Request'
439 ];
440 $fix = true;
441 $Xfiles = glob(BMI_TMP . DIRECTORY_SEPARATOR . '.BMI-*');
442 foreach ($Xfiles as $xfile) if (is_file($xfile)) unlink($xfile);
443 touch(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy);
444
445 if ($fix === true) {
446 if ($legacyHardVersion === false && $cron === false) {
447 $remote_settings['browser'] = true;
448 $this->zip_progress->log(__("Saving backup configuration for current session...", 'backup-backup'), 'INFO');
449 $this->saveRemoteSettings($remote_settings);
450 $this->zip_progress->log(__("Sending confirmation to user browser to keep pinging the process.", 'backup-backup'), 'INFO');
451 BMP::res(['status' => 'background_hard', 'filename' => $this->backupname, 'url' => $url]);
452 exit;
453 } else {
454 $this->zip_progress->log(__("Saving backup configuration for current session...", 'backup-backup'), 'INFO');
455 $this->saveRemoteSettings($remote_settings);
456 $this->zip_progress->log(__('Starting background process on server-side...', 'backup-backup'), 'INFO');
457 require_once BMI_INCLUDES . '/backup-process.php';
458 $request = new Bypasser($identy, BMI_CONFIG_DIR, trailingslashit(WP_CONTENT_DIR), BMI_BACKUPS, trailingslashit(ABSPATH), plugin_dir_path(BMI_ROOT_FILE));
459 $request->handle_batch();
460 }
461 }
462
463 sleep(2);
464 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running')) {
465 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy . '-running')) {
466 // $this->zip_progress->log(__('Request received correctly – backup is running.', 'backup-backup'), 'SUCCESS');
467 if ($cron === true) return ['status' => 'background', 'filename' => $this->backupname];
468 else BMP::res(['status' => 'background', 'filename' => $this->backupname]);
469 exit;
470 } else {
471 $this->zip_progress->log(__('Could not find any response from the server, trying again in 3 seconds.', 'backup-backup'), 'WARN');
472 sleep(3);
473 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy . '-running')) {
474 // $this->zip_progress->log(__('Request received correctly – backup is running.', 'backup-backup'), 'SUCCESS');
475 if ($cron === true) return ['status' => 'background', 'filename' => $this->backupname];
476 else BMP::res(['status' => 'background', 'filename' => $this->backupname]);
477 exit;
478 } else {
479 $this->zip_progress->log(__('Still nothing backup probably is not running.', 'backup-backup'), 'WARN');
480 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy . '-running')) @unlink(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy . '-running');
481 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy)) @unlink(BMI_TMP . DIRECTORY_SEPARATOR . '.' . $identy);
482 throw new \Exception('Backup could not run on your server, please check global logs.');
483 }
484 }
485 } else {
486 if ($cron === true) return ['status' => 'background', 'filename' => $this->backupname];
487 else BMP::res(['status' => 'background', 'filename' => $this->backupname]);
488 exit;
489 }
490
491 // ob_end_clean();
492 exit;
493 } else {
494 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
495 $this->zip_progress->log(__("Backup is running under PHP CLI environment.", 'backup-backup'), 'INFO');
496 } else {
497 $this->zip_progress->log(__("Backup will run as single-request, may be unstable...", 'backup-backup'), 'WARN');
498 }
499 }
500
501 if ($this->dbDumped === false) {
502 $this->createDatabaseDump($dbbackupname, $better_database_files_dir, $database_file, $database_file_dir);
503 }
504
505 $zipArchive = false;
506 if (class_exists('\ZipArchive') || class_exists('ZipArchive')) {
507 if (!isset($zip)) {
508 $zip = new \ZipArchive();
509 }
510
511 if ($zip) {
512 $zipArchive = true;
513 } else {
514 $zipArchive = false;
515 }
516 }
517
518 // Check if PclZip exists
519 if ($zipArchive === false) {
520 if (!class_exists('PclZip')) {
521 if (!defined('PCLZIP_TEMPORARY_DIR')) {
522 $bmi_tmp_dir = BMI_TMP;
523 if (!file_exists($bmi_tmp_dir)) {
524 @mkdir($bmi_tmp_dir, 0775, true);
525 }
526
527 define('PCLZIP_TEMPORARY_DIR', $bmi_tmp_dir . DIRECTORY_SEPARATOR . 'bmi-');
528 }
529
530 if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
531 define('PCLZIP_READ_BLOCK_SIZE', 32768);
532 }
533 }
534
535 // Require the LIB and check if it's compatible
536 if (defined('BMI_PRO_PCLZIP') && file_exists(BMI_PRO_PCLZIP)) {
537 $this->zip_progress->log(__('Using dedicated PclZIP for Premium Users.', 'backup-backup'), 'INFO');
538 require_once BMI_PRO_PCLZIP;
539 } else {
540 require_once trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
541 }
542
543 // Get/Create the Archive
544 if (!$lib = new \PclZip($this->new_file_path)) {
545 throw new \Exception('PHP-ZIP: Permission Denied or zlib can\'t be found');
546 }
547
548 } else {
549
550 if (file_exists($this->new_file_path)) $zip->open($this->new_file_path);
551 else $zip->open($this->new_file_path, \ZipArchive::CREATE);
552
553 $this->zip_progress->log('Using ZipArchive extension for this backup process.', 'INFO');
554
555 }
556
557 // require the lib
558 // if (!class_exists('PclZip')) {
559 // if (!defined('PCLZIP_TEMPORARY_DIR')) {
560 // $bmi_tmp_dir = BMI_TMP;
561 // if (!file_exists($bmi_tmp_dir)) {
562 // @mkdir($bmi_tmp_dir, 0775, true);
563 // }
564 // define('PCLZIP_TEMPORARY_DIR', $bmi_tmp_dir . DIRECTORY_SEPARATOR . 'bmi-');
565 // }
566 // if (defined('BMI_PRO_PCLZIP') && file_exists(BMI_PRO_PCLZIP)) {
567 // $this->zip_progress->log(__('Using dedicated PclZIP for Premium Users.', 'backup-backup'), 'INFO');
568 // require_once BMI_PRO_PCLZIP;
569 // } else {
570 // require_once trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
571 // }
572 // }
573 $common = $this->org_files;
574
575 if ($this->dbDumped === true) {
576 try {
577
578 $this->zip_progress->log(__('Adding database SQL file(s) to the backup file.', 'backup-backup'), 'STEP');
579
580 $files = [];
581
582 if ($database_file !== false && !($this->db_exporter_files && sizeof($this->db_exporter_files) > 0)) {
583 $files[] = $database_file;
584 }
585
586 $this->zip_progress->log('Database files in total found: ' . sizeof($this->db_exporter_files), 'VERBOSE');
587 if ($this->db_exporter_files && sizeof($this->db_exporter_files) > 0) {
588 for ($i = 0; $i < sizeof($this->db_exporter_files); ++$i) {
589 $files[] = $this->db_exporter_files[$i];
590 }
591 } else {
592 $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');
593 $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');
594 }
595
596 $files = array_filter($files, function ($path) {
597 if (is_readable($path) && is_writable($path) && !is_link($path)) return true;
598 else {
599 $this->zip_progress->log(sprintf(__("Excluding file that cannot be read: %s", 'backup-backup'), $path), 'warn');
600 return false;
601 }
602 });
603
604 if (sizeof($files) > 0) {
605 if ($zipArchive) {
606 for ($i = 0; $i < sizeof($files); ++$i) {
607
608 // Add the file
609 if (is_dir($files[$i])) {
610 $zip->addEmptyDir($this->cutDir($files[$i]));
611 } else {
612 $zip->addFile($files[$i], $this->cutDir($files[$i]));
613 }
614
615 }
616
617 $zAresult = $zip->close();
618 if ($zAresult !== true) {
619 $this->zip_progress->log('not_enough_space', 'verbose');
620 $this->zip_failed('Error, there is most likely not enough space for the backup.');
621 return false;
622
623 }
624 $zip->open($this->new_file_path);
625 } else {
626 $dbback = $lib->add($files, PCLZIP_OPT_REMOVE_PATH, $database_file_dir, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
627
628 if ($dbback == 0) {
629 $this->zip_failed($lib->errorInfo(true));
630 return false;
631 }
632 }
633 }
634
635 } catch (\Exception $e) {
636 $this->zip_failed($e->getMessage());
637
638 return false;
639 } catch (\Throwable $e) {
640 $this->zip_failed($e->getMessage());
641
642 return false;
643 }
644
645 if (sizeof($files) > 0) {
646 $this->zip_progress->log(__('Database added to the backup successfully.', 'backup-backup'), 'SUCCESS');
647 } else {
648 $this->zip_progress->log(__('Database was not added to the backup.', 'backup-backup'), 'WARN');
649 }
650 }
651
652 $this->zip_progress->log(__('Performing site files backup...', 'backup-backup'), 'STEP');
653
654 try {
655 $splitby = 200; $milestoneby = 500;
656 $filestotal = sizeof($this->org_files);
657 if ($filestotal < 3000) { $splitby = 250; $milestoneby = 500; }
658 if ($filestotal > 5000) { $splitby = 500; $milestoneby = 500; }
659 if ($filestotal > 10000) { $splitby = 1000; $milestoneby = 1000; }
660 if ($filestotal > 15000) { $splitby = 2000; $milestoneby = 2000; }
661 if ($filestotal > 20000) { $splitby = 4000; $milestoneby = 4000; }
662 if ($filestotal > 25000) { $splitby = 6000; $milestoneby = 6000; }
663 if ($filestotal > 30000) { $splitby = 8000; $milestoneby = 8000; }
664 if ($filestotal > 32000) { $splitby = 10000; $milestoneby = 10000; }
665 if ($filestotal > 60500) { $splitby = 20000; $milestoneby = 20000; }
666 if ($filestotal > 90500) { $splitby = 40000; $milestoneby = 40000; }
667
668 $this->zip_progress->log(__("Chunks contain ", 'backup-backup') . $splitby . __(" files.", 'backup-backup'));
669
670 $chunks = array_chunk($this->org_files, $splitby);
671 $chunkslen = sizeof($chunks);
672 if ($chunkslen > 0) {
673 $sizeoflast = sizeof($chunks[$chunkslen - 1]);
674 if ($chunkslen > 1 && $sizeoflast == 1) {
675 $buffer = array_slice($chunks[$chunkslen - 2], -1);
676 $chunks[$chunkslen - 2] = array_slice($chunks[$chunkslen - 2], 0, -1);
677 $chunks[$chunkslen - 1][] = $buffer[0];
678 }
679 }
680
681 $backupSize = 0;
682 for ($i = 0; $i < $chunkslen; ++$i) {
683
684 // Abort if user wants it (check every 100 files)
685 if (file_exists(BMI_BACKUPS . '/.abort')) {
686 break;
687 }
688
689 $back = 0;
690 $chunk = $chunks[$i];
691 $chunk = array_filter($chunk, function ($path) {
692 if (is_readable($path) && file_exists($path) && !is_link($path)) return true;
693 else {
694 $this->zip_progress->log(sprintf(__("Excluding file that cannot be read: %s", 'backup-backup'), $path), 'warn');
695 return false;
696 }
697 });
698 $chunk = array_values($chunk);
699
700 if (sizeof($chunk) > 0) {
701 $needManipulation = false;
702 if (strpos(WP_CONTENT_DIR, ABSPATH) === false) {
703 $needManipulation = true;
704 }
705 if ($zipArchive) {
706 for ($j = 0; $j < sizeof($chunk); ++$j) {
707
708 if ($needManipulation) {
709 if (strpos($chunk[$j], WP_CONTENT_DIR) !== false) {
710 $path = 'wordpress' . DIRECTORY_SEPARATOR . 'wp-content' . DIRECTORY_SEPARATOR . substr($chunk[$j], strlen(WP_CONTENT_DIR));
711 } else {
712 $path = 'wordpress' . DIRECTORY_SEPARATOR . substr($chunk[$j], strlen(ABSPATH));
713 }
714 } else {
715 $path = 'wordpress' . DIRECTORY_SEPARATOR . substr($chunk[$j], strlen(ABSPATH));
716 }
717
718 // Add the file
719 $path = BMP::fixSlashes($path);
720 if (is_dir($chunk[$j])) {
721 $zip->addEmptyDir($path);
722 } else {
723 $zip->addFile($chunk[$j], $path);
724 }
725
726 }
727
728 $zAresult = $zip->close();
729 if ($zAresult !== true) {
730 $this->zip_progress->log('not_enough_space', 'verbose');
731 $this->zip_failed('Error, there is most likely not enough space for the backup.');
732 return false;
733
734 }
735 $zip->open($this->new_file_path);
736 } else {
737
738 if ($needManipulation) {
739 $abs = BMP::fixSlashes(ABSPATH) . DIRECTORY_SEPARATOR;
740 $content = BMP::fixSlashes(WP_CONTENT_DIR) . DIRECTORY_SEPARATOR;
741 $coreFiles = [];
742 $contentFiles = [];
743 foreach ($chunk as $file) {
744 if (strpos($file, $content) !== false) {
745 $contentFiles[] = $file;
746 } else {
747 $coreFiles[] = $file;
748 }
749 }
750
751 $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);
752 $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);
753 $back = $back_1 && $back_2;
754
755 } else {
756 $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);
757 }
758 if ($back == 0) {
759 $this->zip_failed($lib->errorInfo(true));
760 return false;
761 }
762
763 }
764 }
765
766 $curfile = (($i * $splitby) + $splitby);
767 $this->zip_progress->progress($curfile . '/' . $max);
768 if ($curfile % $milestoneby === 0 && $curfile < $max) {
769 if (!file_exists($this->new_file_path))
770 return $this->zip_failed('Expected backup file does not exist, there could be some issue or the backup was removed by third parties.');
771
772 $currentBackupSize = filesize($this->new_file_path);
773 if ($backupSize > $currentBackupSize)
774 return $this->zip_failed('Backup size is smaller than it should be, it has been damaged, it may not be restorable, abort recommended.');
775
776 $backupSize = $currentBackupSize;
777
778 $this->zip_progress->log(__("Milestone: ", 'backup-backup') . ($curfile . '/' . $max), 'info');
779 }
780 }
781
782 } catch (\Exception $e) {
783 $this->zip_failed($e->getMessage());
784
785 return false;
786 } catch (\Throwable $e) {
787 $this->zip_failed($e->getMessage());
788
789 return false;
790 }
791
792 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) {
793
794 $this->zip_progress->log('#002', 'END-CODE');
795
796 if (file_exists($database_file_dir . 'bmi_backup_manifest.json')) {
797 @unlink($database_file_dir . 'bmi_backup_manifest.json');
798 }
799 if (file_exists($database_file_dir . 'bmi_logs_this_backup.log')) {
800 @unlink($database_file_dir . 'bmi_logs_this_backup.log');
801 }
802
803 } else {
804
805 // End
806 $this->zip_progress->log(__("Milestone: ", 'backup-backup') . ($max . '/' . $max), 'info');
807 $this->zip_progress->log(__("Compressed ", 'backup-backup') . $max . __(" files", 'backup-backup'), 'SUCCESS');
808
809 // Log time of ZIP Process
810 $this->zip_progress->log(__("Archiving of ", 'backup-backup') . $max . __(" files took: ", 'backup-backup') . number_format(microtime(true) - $this->start_zip, 2) . 's');
811
812 $this->zip_progress->log(__("Finalizing backup", 'backup-backup'), 'STEP');
813 $this->zip_progress->log(__("Generating manifest file and saving current live-log...", 'backup-backup'), 'INFO');
814
815 file_put_contents($database_file_dir . 'bmi_backup_manifest.json', $this->zip_progress->createManifest($dbBackupEngine));
816 file_put_contents($database_file_dir . 'bmi_logs_this_backup.log', file_get_contents(BMI_BACKUPS . DIRECTORY_SEPARATOR . 'latest.' . BMI_LOGS_SUFFIX . '.log'));
817
818 sleep(1);
819
820 $files = [];
821
822 if (file_exists($database_file_dir . 'bmi_logs_this_backup.log')) $files[] = $database_file_dir . 'bmi_logs_this_backup.log';
823 if (file_exists($database_file_dir . 'bmi_backup_manifest.json')) $files[] = $database_file_dir . 'bmi_backup_manifest.json';
824 else {
825
826 $this->zip_failed('Manifest file could not be added, manifest does not exist.');
827 return false;
828
829 }
830
831 $this->zip_progress->log(__("Adding manifest...", 'backup-backup'), 'INFO');
832 try {
833
834 if ($zipArchive) {
835 for ($i = 0; $i < sizeof($files); ++$i) {
836
837 // Add the file
838 if (is_dir($files[$i])) {
839 $zip->addEmptyDir($this->cutDir($files[$i]));
840 } else {
841 $zip->addFile($files[$i], $this->cutDir($files[$i]));
842 }
843
844 }
845
846 $zAresult = $zip->close();
847 if ($zAresult !== true) {
848 $this->zip_progress->log('not_enough_space', 'verbose');
849 $this->zip_failed('Error, there is most likely not enough space for the backup.');
850 return false;
851
852 }
853 } else {
854
855 $maback = $lib->add($files, PCLZIP_OPT_REMOVE_PATH, $database_file_dir, PCLZIP_OPT_ADD_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
856
857 if ($maback == 0) {
858 $this->zip_failed($lib->errorInfo(true));
859 return false;
860 }
861
862 }
863
864 } catch (\Exception $e) {
865 $this->zip_failed($e->getMessage());
866
867 return false;
868 } catch (\Throwable $e) {
869 $this->zip_failed($e->getMessage());
870
871 return false;
872 }
873
874 if (file_exists($database_file_dir . 'bmi_backup_manifest.json')) {
875 @unlink($database_file_dir . 'bmi_backup_manifest.json');
876 }
877 if (file_exists($database_file_dir . 'bmi_logs_this_backup.log')) {
878 @unlink($database_file_dir . 'bmi_logs_this_backup.log');
879 }
880
881 $this->zip_progress->progress($max . '/' . $max);
882
883 $this->zip_progress->log(__("Manifest file and logs added to the backup. Temporary files removed.", 'backup-backup'), 'SUCCESS');
884
885 }
886 }
887
888 $this->zip_progress->log(__("Closing files and archives", 'backup-backup'), 'STEP');
889
890 // Remove Better DB SQL Files
891 if ($this->db_exporter_files && sizeof($this->db_exporter_files) > 0) {
892 for ($i = 0; $i < sizeof($this->db_exporter_files); ++$i) {
893 if (file_exists($this->db_exporter_files[$i])) @unlink($this->db_exporter_files[$i]);
894 }
895 if (file_exists($better_database_files_dir) && is_dir($better_database_files_dir)) {
896 @rmdir($better_database_files_dir);
897 }
898 }
899
900 if ($database_file && file_exists($database_file)) @unlink($database_file);
901 if (!file_exists($this->new_file_path)) {
902 $this->zip_failed('PHP-ZIP: After doing the zipping file can not be found');
903 }
904 if (filesize($this->new_file_path) === 0) {
905 $this->zip_failed('PHP-ZIP: After doing the zipping file size is still 0 bytes');
906 }
907
908 // empty the array
909 $this->org_files = [];
910
911 $this->zip_progress->log(__("Cleanup finished, backup complete.", 'backup-backup'), 'SUCCESS');
912 // $this->zip_progress->log('#001', 'END-CODE');
913 return true;
914
915 }
916
917 public function zip_files($files, $to) {
918 $this->zip_start($to);
919 $this->zip_add($files);
920
921 return $this->zip_end();
922 }
923
924 public function unzip_file($file_path, $target_dir = null, &$zip_progress = null) {
925
926 // Progress
927 $this->zip_progress = $zip_progress;
928
929 // if it doesn't exist
930 if (!file_exists($file_path)) {
931 throw new \Exception("PHP-ZIP: File doesn't Exist");
932 }
933
934 $this->extr_file = $file_path;
935
936 // if (class_exists("ZipArchive")) $this->lib = 1;
937 // else $this->lib = 2;
938 $this->lib = 2;
939
940 if ($target_dir !== null) {
941 return $this->unzip_to($target_dir);
942 } else {
943 return true;
944 }
945 }
946
947 public function extract_files($zip_path, $files, $target_dir = null, &$zip_progress = null, $isFirstExtract = true) {
948
949 $this->zip_progress = $zip_progress;
950
951 // it exists, but it's not a directory
952 if (file_exists($target_dir) && (!is_dir($target_dir))) {
953 throw new \Exception("PHP-ZIPv2: Target directory exists as a file not a directory");
954 }
955 // it doesn't exist
956 if (!file_exists($target_dir)) {
957 if (!mkdir($target_dir)) {
958 throw new \Exception("PHP-ZIPv2: Directory not found, and unable to create it");
959 }
960 }
961 // validations -- end //
962 // TODO: NOTICE: Force disable PCLZIP
963 if (class_exists("ZipArchive") || class_exists("\ZipArchive")) {
964
965 $zip = new \ZipArchive;
966 $res = $zip->open($zip_path);
967
968 if ($res === true) {
969
970 if ($isFirstExtract) {
971 $this->zip_progress->log(__("Using ZipArchive, omiting memory limit calculations...", 'backup-backup'), 'INFO');
972 }
973
974 $zip->extractTo($target_dir, $files);
975 $zip->close();
976 return true;
977
978 } else {
979
980 $this->restore_failed('PHP-ZIPv2: Could not open Backup with ZipArchive.');
981 return false;
982
983 }
984
985 } else {
986
987 if ($isFirstExtract) {
988 $this->zip_progress->log(__("ZipArchive is not available, using PclZIP.", 'backup-backup'), 'INFO');
989 }
990
991 $safe_limit = $this->smartMemory($isFirstExtract);
992 $this->loadPclZip($isFirstExtract);
993 $lib = new \PclZip($zip_path);
994 $restor = $lib->extract(PCLZIP_OPT_BY_NAME, $files, PCLZIP_OPT_PATH, $target_dir, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
995
996 if ($restor == 0) {
997
998 $this->restore_failed($lib->errorInfo(true));
999 return false;
1000
1001 }
1002
1003 return true;
1004
1005 }
1006
1007 }
1008
1009 public function loadPclZip($isFirstExtract = true) {
1010
1011 if (!class_exists('PclZip')) {
1012 if (!defined('PCLZIP_TEMPORARY_DIR')) {
1013 $bmi_tmp_dir = BMI_TMP;
1014 if (!file_exists($bmi_tmp_dir)) {
1015 @mkdir($bmi_tmp_dir, 0775, true);
1016 }
1017 define('PCLZIP_TEMPORARY_DIR', $bmi_tmp_dir . DIRECTORY_SEPARATOR . 'bmi-');
1018 }
1019
1020 if (defined('BMI_PRO_PCLZIP') && file_exists(BMI_PRO_PCLZIP)) {
1021 require_once BMI_PRO_PCLZIP;
1022 if ($isFirstExtract) {
1023 $this->zip_progress->log(__('Using dedicated PclZIP for Premium Users.', 'backup-backup'), 'INFO');
1024 }
1025 } else {
1026 require_once trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
1027 }
1028 }
1029
1030 }
1031
1032 public function smartMemory($isFirstExtract = true) {
1033
1034 // Smart memory -- start //
1035 if ($this->zip_progress != null && $isFirstExtract) {
1036 $this->zip_progress->log(__("Smart memory calculation...", 'backup-backup'), 'STEP');
1037 }
1038
1039 if ((intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024) < 384) {
1040 @ini_set('memory_limit', '384M');
1041 }
1042
1043 $memory_limit = (intval($this->return_bytes(ini_get('memory_limit'))) / 1024 / 1024);
1044 if ($this->zip_progress != null && $isFirstExtract) {
1045 $this->zip_progress->log(str_replace('%s', $memory_limit, __("There is %s MBs of memory to use", 'backup-backup')), 'INFO');
1046 }
1047
1048 $safe_limit = intval($memory_limit / 4);
1049 if ($safe_limit > 64) $safe_limit = 64;
1050 if ($memory_limit === 384) $safe_limit = 78;
1051 if ($memory_limit >= 512) $safe_limit = 104;
1052 if ($memory_limit >= 1024) $safe_limit = 228;
1053 if ($memory_limit >= 2048) $safe_limit = 428;
1054
1055 // $real_memory = intval(memory_get_usage() * 0.9 / 1024 / 1024);
1056 // if ($real_memory < $safe_limit) $safe_limit = $real_memory;
1057 $safe_limit = intval($safe_limit * 0.8);
1058
1059 if ($this->zip_progress != null && $isFirstExtract) {
1060 $this->zip_progress->log(str_replace('%s', $safe_limit, __("Setting the safe limit to %s MB", 'backup-backup')), 'SUCCESS');
1061 }
1062 // Smart memory -- end //
1063
1064 return $safe_limit;
1065
1066 }
1067
1068 public function unzip_to($target_dir) {
1069
1070 // validations -- start //
1071 if ($this->lib === 0 && $this->extr_file === 0) {
1072 throw new \Exception("PHP-ZIP: unzip_file hasn't been called");
1073 }
1074 // it exists, but it's not a directory
1075 if (file_exists($target_dir) && (!is_dir($target_dir))) {
1076 throw new \Exception("PHP-ZIP: Target directory exists as a file not a directory");
1077 }
1078 // it doesn't exist
1079 if (!file_exists($target_dir)) {
1080 if (!mkdir($target_dir)) {
1081 throw new \Exception("PHP-ZIP: Directory not found, and unable to create it");
1082 }
1083 }
1084 // validations -- end //
1085
1086 // Target Directory
1087 $this->extr_dirc = $target_dir;
1088
1089 // Smart Memory
1090 $safe_limit = $this->smartMemory();
1091
1092 // Extract msg
1093 $this->zip_progress->log(__('Extracting files into temporary directory (this process can take some time)...', 'backup_migration'), 'STEP');
1094
1095 // Force PCL Zip
1096 $this->lib = 2;
1097
1098 // extract using ZipArchive
1099 // if($this->lib === 1) {
1100 // $lib = new \ZipArchive;
1101 // if(!$lib->open($this->extr_file)) throw new \Exception("PHP-ZIP: Unable to open the zip file");
1102 // if(!$lib->extractTo($this->extr_dirc)) throw new \Exception("PHP-ZIP: Unable to extract files");
1103 // $lib->close();
1104 // }
1105
1106 // extarct using PclZip
1107 if ($this->lib === 2) {
1108 $this->loadPclZip();
1109 $lib = new \PclZip($this->extr_file);
1110 $restor = $lib->extract(PCLZIP_OPT_PATH, $this->extr_dirc, PCLZIP_OPT_TEMP_FILE_THRESHOLD, $safe_limit);
1111 if ($restor == 0) {
1112 $this->restore_failed($lib->errorInfo(true));
1113
1114 return false;
1115 }
1116 }
1117
1118 return true;
1119 }
1120
1121 private function dir_to_assoc_arr(DirectoryIterator $dir) {
1122 $data = [];
1123 foreach ($dir as $node) {
1124 if ($node->isDir() && !$node->isDot()) {
1125 $data[$node->getFilename()] = $this->dir_to_assoc_arr(new DirectoryIterator($node->getPathname()));
1126 } elseif ($node->isFile()) {
1127 $data[] = $node->getFilename();
1128 }
1129 }
1130
1131 return $data;
1132 }
1133
1134 private function path() {
1135 return join(DIRECTORY_SEPARATOR, func_get_args());
1136 }
1137
1138 private function commonPath($files, $remove = true) {
1139 foreach ($files as $index => $filesStr) {
1140 $files[$index] = explode(DIRECTORY_SEPARATOR, $filesStr);
1141 }
1142 $toDiff = $files;
1143 foreach ($toDiff as $arr_i => $arr) {
1144 foreach ($arr as $name_i => $name) {
1145 $toDiff[$arr_i][$name_i] = $name . "___" . $name_i;
1146 }
1147 }
1148 $diff = call_user_func_array("array_diff", $toDiff);
1149 reset($diff);
1150 $i = key($diff) - 1;
1151 if ($remove) {
1152 foreach ($files as $index => $arr) {
1153 $files[$index] = implode(DIRECTORY_SEPARATOR, array_slice($files[$index], $i));
1154 }
1155 } else {
1156 foreach ($files as $index => $arr) {
1157 $files[$index] = implode(DIRECTORY_SEPARATOR, array_slice($files[$index], 0, $i));
1158 }
1159 }
1160
1161 return $files;
1162 }
1163 }
1164