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 / extracter / extract.php
backup-backup / includes / extracter Last commit date
extract.php 3 months ago
extract.php
2134 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin\Extracter;
5
6 // Use
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_Importer as BetterDatabaseImport;
11 use BMI\Plugin\Database\BMI_Even_Better_Database_Restore as EvenBetterDatabaseImport;
12 use BMI\Plugin\Progress\BMI_ZipProgress as Progress;
13 use BMI\Plugin\Backup_Migration_Plugin as BMP;
14 use BMI\Plugin\Zipper\Zip as Zip;
15 use BMI\Plugin\Zipper\BMI_Zipper as ZipManager;
16 use BMI\Plugin\Database\BMI_Database_Sorting as SmartDatabaseSort;
17
18 // Exit on direct access
19 if (!defined('ABSPATH')) {
20 exit;
21 }
22
23 /**
24 * BMI_Extracter
25 */
26 class BMI_Extracter {
27
28 public function __construct($backup, &$migration, $tmptime = false, $isCLI = false, $options = []) {
29
30 // Globals
31 global $table_prefix;
32
33 // Requirements
34 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'manager.php';
35 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'better-restore.php';
36 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'smart-sort.php';
37
38 // IsCLI?
39 $this->isCLI = $isCLI;
40
41 // Backup name
42 $this->backup_name = $backup;
43
44 // Logger
45 $this->migration = $migration;
46
47 // Temp name
48 $this->tmptime = time();
49
50 // Use specified name if it is in batching mode
51 if (is_numeric($tmptime)) $this->tmptime = $tmptime;
52
53 // Splitting enabled?
54 $this->splitting = Dashboard\bmi_get_config('OTHER:RESTORE:SPLITTING') ? true : false;
55 $this->v3engine = Dashboard\bmi_get_config('OTHER:RESTORE:DB:V3') ? true : false;
56 $this->cleanupbefore = Dashboard\bmi_get_config('OTHER:RESTORE:BEFORE:CLEANUP') ? true : false;
57
58 // Restore start time
59 $this->start = intval(microtime(true));
60
61 // File amount by default 0 later we replace it with scan
62 $this->fileAmount = 0;
63 $this->recent_export_seek = 0;
64 $this->processData = [];
65 $this->conversionStats = [];
66
67 // Options
68 $this->batchStep = 0;
69 if (isset($options['amount'])) {
70 $this->fileAmount = intval($options['amount']);
71 }
72 if (isset($options['start'])) {
73 $this->start = intval($options['start']);
74 }
75 $this->continueFile = false;
76 if (isset($options['continueFile'])) {
77 $this->continueFile = $options['continueFile'];
78 }
79 $this->continueSeek = false;
80 if (isset($options['continueSeek'])) {
81 $this->continueSeek = $options['continueSeek'];
82 }
83 if (isset($options['step'])) {
84 $this->batchStep = intval($options['step']);
85 }
86 $this->databaseExist = false;
87 if (isset($options['databaseExist'])) {
88 $this->databaseExist = (($options['databaseExist'] == 'true' || $options['databaseExist'] === '1' || $options['databaseExist'] === 1 || $options['databaseExist'] === true) ? true : false);
89 }
90 $this->firstDB = true;
91 if (isset($options['firstDB'])) {
92 $this->firstDB = (($options['firstDB'] == 'true' || $options['firstDB'] === '1' || $options['firstDB'] === 1 || $options['firstDB'] === true) ? true : false);
93 }
94 $this->v3RestoreUsed = false;
95 if (isset($options['v3RestoreUsed'])) {
96 $this->v3RestoreUsed = (($options['v3RestoreUsed'] == 'true' || $options['v3RestoreUsed'] === '1' || $options['v3RestoreUsed'] === 1 || $options['v3RestoreUsed'] === true) ? true : false);
97 }
98 $this->firstExtract = true;
99 if (isset($options['firstExtract'])) {
100 $this->firstExtract = (($options['firstExtract'] == 'false' || $options['firstExtract'] === '1' || $options['firstExtract'] === 1 || $options['firstExtract'] === false) ? false : true);
101 }
102
103 $this->db_xi = 0;
104 $this->ini_start = 0;
105 $this->table_names_alter = [];
106
107 if (isset($options['db_xi'])) {
108 $this->db_xi = ((is_numeric($options['db_xi'])) ? intval($options['db_xi']) : 0);
109 }
110 if (isset($options['ini_start'])) {
111 $this->ini_start = ((is_numeric($options['ini_start'])) ? intval($options['ini_start']) : microtime(true));
112 }
113 if (isset($options['table_names_alter'])) {
114 $this->table_names_alter = $options['table_names_alter'];
115 }
116 if (isset($options['recent_export_seek'])) {
117 $this->recent_export_seek = intval($options['recent_export_seek']);
118 }
119 if (isset($options['processData'])) {
120 $this->processData = $options['processData'];
121 }
122 if (isset($options['conversionStats'])) {
123 $this->conversionStats = $options['conversionStats'];
124 }
125
126 $this->tableIndex = 0;
127 $this->replaceStep = 0;
128 $this->totalReplacePage = 0;
129 $this->currentReplacePage = 0;
130 $this->fieldAdjustments = 0;
131 $this->dbFoundPrefix = 'wp_';
132
133 if (isset($options['replaceStep'])) {
134 $this->replaceStep = intval($options['replaceStep']);
135 }
136 if (isset($options['tableIndex'])) {
137 $this->tableIndex = intval($options['tableIndex']);
138 }
139 if (isset($options['currentReplacePage'])) {
140 $this->currentReplacePage = intval($options['currentReplacePage']);
141 }
142 if (isset($options['totalReplacePage'])) {
143 $this->totalReplacePage = intval($options['totalReplacePage']);
144 }
145 if (isset($options['fieldAdjustments'])) {
146 $this->fieldAdjustments = intval($options['fieldAdjustments']);
147 }
148 if (isset($options['dbFoundPrefix'])) {
149 $this->dbFoundPrefix = sanitize_text_field($options['dbFoundPrefix']);
150 }
151
152 // Name
153 // $this->tmp = untrailingslashit(ABSPATH) . DIRECTORY_SEPARATOR . 'backup-migration_' . $this->tmptime;
154 $this->tmp = BMI_TMP . DIRECTORY_SEPARATOR . 'backup-migration_' . $this->tmptime;
155 $GLOBALS['bmi_current_tmp_restore'] = $this->tmp;
156 $GLOBALS['bmi_current_tmp_restore_unique'] = $this->tmptime;
157
158 // Scan file
159 $this->scanFile = BMI_TMP . DIRECTORY_SEPARATOR . '.restore_scan_' . $this->tmptime;
160
161 // Prepare database connection
162 $this->db = new Database(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
163
164 // Save current wp-config to replace (only those required)
165 $this->DB_NAME = DB_NAME;
166 $this->DB_USER = DB_USER;
167 $this->DB_PASSWORD = DB_PASSWORD;
168 $this->DB_HOST = DB_HOST;
169 $this->DB_CHARSET = (defined('DB_CHARSET') ? DB_CHARSET : '');
170 $this->DB_COLLATE = (defined('DB_COLLATE') ? DB_COLLATE : '');
171
172 $this->AUTH_KEY = (defined('AUTH_KEY') ? AUTH_KEY : '');
173 $this->SECURE_AUTH_KEY = (defined('SECURE_AUTH_KEY') ? SECURE_AUTH_KEY : '');
174 $this->LOGGED_IN_KEY = (defined('LOGGED_IN_KEY') ? LOGGED_IN_KEY : '');
175 $this->NONCE_KEY = (defined('NONCE_KEY') ? NONCE_KEY : '');
176 $this->AUTH_SALT = (defined('AUTH_SALT') ? AUTH_SALT : '');
177 $this->SECURE_AUTH_SALT = (defined('SECURE_AUTH_SALT') ? SECURE_AUTH_SALT : '');
178 $this->LOGGED_IN_SALT = (defined('LOGGED_IN_SALT') ? LOGGED_IN_SALT : '');
179 $this->NONCE_SALT = (defined('NONCE_SALT') ? NONCE_SALT : '');
180
181 $this->ABSPATH = ABSPATH;
182 $this->WP_CONTENT_DIR = trailingslashit(WP_CONTENT_DIR);
183
184 $this->WP_DEBUG_LOG = WP_DEBUG_LOG;
185 $this->table_prefix = $table_prefix;
186 $this->code = get_option('z__bmi_xhria', false);
187 if (isset($options['code']) && $this->code == false) {
188 $this->code = $options['code'];
189 }
190
191 $this->backupStorage = get_option('BMI::STORAGE::LOCAL::PATH', false);
192 if (isset($options['storage'])) $this->backupStorage = $options['storage'];
193
194 $this->siteurl = get_option('siteurl');
195 $this->home = get_option('home');
196
197 $this->src = BMI_BACKUPS . DIRECTORY_SEPARATOR . $this->backup_name;
198
199 $this->v3Importer = null;
200 $this->usingDbEngineV4 = null;
201
202 $this->backupStorage = str_replace('/', DIRECTORY_SEPARATOR, $this->backupStorage);
203
204 }
205
206 public function removeUnwantedFiles() {
207 $preventMoveFiles = [
208 'wp-config.php',
209 'debug.log',
210 '.user.ini',
211 'php.ini',
212 '.htaccess'
213 ];
214
215 $base = $this->tmp . DIRECTORY_SEPARATOR . 'wordpress' . DIRECTORY_SEPARATOR;
216
217 foreach ($preventMoveFiles as $idx => $value) {
218 if (file_exists($base . $value)) @unlink($base . $value);
219 }
220 }
221
222 public function replacePath($path, $sub, $content) {
223 $path .= DIRECTORY_SEPARATOR . 'wordpress' . $sub;
224
225 // Handle only database backup
226 if (!file_exists($path)) return;
227
228 $rii = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
229
230 $clent = strlen($content);
231 $sublen = strlen($path);
232 $files = [];
233 $dirs = [];
234
235 $preventMoveFiles = [
236 'wp-config.php',
237 'debug.log',
238 '.user.ini',
239 'php.ini',
240 '.htaccess'
241 ];
242
243 foreach ($rii as $file) {
244 if (!$file->isDir()) {
245 $files[] = substr($file->getPathname(), $sublen);
246 } else {
247 $dirs[] = substr($file->getPathname(), $sublen);
248 }
249 }
250
251 for ($i = 0; $i < sizeof($dirs); ++$i) {
252 $src = $path . $dirs[$i];
253 if (strpos($dirs[$i], $content) !== false) {
254 $dest = untrailingslashit($this->WP_CONTENT_DIR) . $sub . ltrim(substr($dirs[$i], $clent), DIRECTORY_SEPARATOR);
255 } else {
256 $dest = untrailingslashit($this->ABSPATH) . $sub . ltrim($dirs[$i], DIRECTORY_SEPARATOR);
257 }
258
259 $dest = untrailingslashit($dest);
260 if (!(file_exists($dest) && is_dir($dest))) {
261 try { @mkdir($dest, 0755, true); }
262 catch (Exception $e) { /* Slience */ }
263 catch (Throwable $t) { /* Slience */ }
264 }
265 }
266
267 $max = sizeof($files);
268 for ($i = 0; $i < $max; ++$i) {
269 $src = $path . $files[$i];
270 if (strpos($files[$i], $content) !== false) {
271 $dest = untrailingslashit($this->WP_CONTENT_DIR) . $sub . substr($files[$i], $clent);
272 } else {
273 $dest = untrailingslashit($this->ABSPATH) . $sub . $files[$i];
274 }
275
276 if (file_exists($src)) {
277 $fileDest = BMP::fixSlashes($dest);
278 $srcFileName = basename($src);
279
280 if (!in_array($srcFileName, $preventMoveFiles)) {
281 rename($src, $fileDest);
282 }
283 }
284
285 if ($i % 100 === 0 || ($i == ($max - 1))) {
286 $this->migration->progress(25 + intval((($i / $max) * 100) / 4));
287 if ($i != 0 && ($i % 500 === 0 || ($i == ($max - 1)))) {
288 if ($i == ($max - 1)) $i++;
289 $this->migration->log(sprintf(__('File replacement progress: %s/%s (%s%%)', 'backup-backup'), $i, $max, intval(($i / $max) * 100)));
290 }
291 }
292 }
293 }
294
295 public function removePreviousSelectionsIfDatabaseIncluded() {
296 if (!isset($manifest)) {
297 $manifest = $this->getCurrentManifest();
298 }
299 $restorePartsFile= BMI_TMP . DIRECTORY_SEPARATOR . 'restore_parts.json';
300 $prefix = $manifest->config->table_prefix;
301 if (file_exists($restorePartsFile)) {
302 $restoreParts = json_decode(file_get_contents($restorePartsFile));
303 if (isset($restoreParts->backupName) && $restoreParts->backupName == basename($this->src)) {
304 if (!isset($restoreParts->dirs['db_tables']) && !isset($restoreParts->files[$prefix . 'options.sql'])) {
305 return;
306 }
307 }
308 } else {
309 $manager = new ZipManager();
310 $optionsTable = $manager->getZipFileContent($this->src, 'db_tables' . DIRECTORY_SEPARATOR . $prefix . 'options.sql');
311 if ($optionsTable === false) {
312 return;
313 }
314 }
315
316 $themedir = get_theme_root();
317 $tempTheme = $themedir . DIRECTORY_SEPARATOR . 'backup_migration_restoration_in_progress';
318
319 if (file_exists($tempTheme . DIRECTORY_SEPARATOR . '.previous_theme')) {
320 @unlink($tempTheme . DIRECTORY_SEPARATOR . '.previous_theme');
321 }
322
323 if (file_exists($tempTheme . DIRECTORY_SEPARATOR . '.previous_stylesheet')) {
324 @unlink($tempTheme . DIRECTORY_SEPARATOR . '.previous_stylesheet');
325 }
326
327 if (file_exists($tempTheme . DIRECTORY_SEPARATOR . '.earlier_active_plugins')) {
328 @unlink($tempTheme . DIRECTORY_SEPARATOR . '.earlier_active_plugins');
329 }
330
331 }
332
333 public function replaceAll($content) {
334
335 $themedir = get_theme_root();
336 $tempTheme = $themedir . DIRECTORY_SEPARATOR . 'backup_migration_restoration_in_progress';
337 if (!(file_exists($tempTheme) && is_dir($tempTheme))) {
338 @mkdir($tempTheme, 0755, true);
339 }
340
341 $visitLaterText = __('Site restoration in progress, please visit that website a bit later, thank you! :)', 'backup-backup');
342 file_put_contents($tempTheme . DIRECTORY_SEPARATOR . 'header.php', '<?php wp_head(); show_admin_bar(true);');
343 file_put_contents($tempTheme . DIRECTORY_SEPARATOR . 'footer.php', '<?php wp_footer(); get_footer();');
344 file_put_contents($tempTheme . DIRECTORY_SEPARATOR . 'index.php', '<?php get_header(); wp_body_open(); ?>' . $visitLaterText);
345 file_put_contents($tempTheme . DIRECTORY_SEPARATOR . '.previous_theme', get_option('template', ''));
346 file_put_contents($tempTheme . DIRECTORY_SEPARATOR . '.previous_stylesheet', get_option('stylesheet', ''));
347 file_put_contents($tempTheme . DIRECTORY_SEPARATOR . '.earlier_active_plugins', serialize(get_option('active_plugins')));
348
349 update_option('active_plugins', ['backup-backup/backup-backup.php']);
350 update_option('template', 'backup_migration_restoration_in_progress');
351 update_option('stylesheet', 'backup_migration_restoration_in_progress');
352
353 $this->replacePath($this->tmp, DIRECTORY_SEPARATOR, $content);
354
355 }
356
357 public function cleanup() {
358
359 // Fix for automatic redirection module at TasteWP
360 if (strpos(site_url(), 'tastewp') !== false) {
361 if (function_exists('wp_load_alloptions')) wp_load_alloptions(true);
362 delete_option('__tastewp_redirection_performed', true);
363 delete_option('auto_smart_tastewp_redirect_performed', 1);
364 delete_option('tastewp_auto_activated', true);
365 delete_option('__tastewp_sub_requested', true);
366
367 if (function_exists('wp_load_alloptions')) wp_load_alloptions(true);
368 update_option('__tastewp_redirection_performed', true);
369 update_option('auto_smart_tastewp_redirect_performed', 1);
370 update_option('tastewp_auto_activated', true);
371 update_option('__tastewp_sub_requested', true);
372 }
373
374 delete_option('bmi_pro_cron_new_domain_done');
375
376 $filesToBeRemoved = [];
377 $dir = $this->tmp;
378
379 $themedir = get_theme_root();
380 $tempTheme = $themedir . DIRECTORY_SEPARATOR . 'backup_migration_restoration_in_progress';
381
382 if (get_option('template') == 'backup_migration_restoration_in_progress' || get_option('stylesheet') == 'backup_migration_restoration_in_progress') {
383 if (file_exists($tempTheme . DIRECTORY_SEPARATOR . '.previous_theme')) {
384 update_option('template', file_get_contents($tempTheme . DIRECTORY_SEPARATOR . '.previous_theme'));
385 }
386 if (file_exists($tempTheme . DIRECTORY_SEPARATOR . '.previous_stylesheet')) {
387 update_option('stylesheet', file_get_contents($tempTheme . DIRECTORY_SEPARATOR . '.previous_stylesheet'));
388 }
389 if (file_exists($tempTheme . DIRECTORY_SEPARATOR . '.earlier_active_plugins')) {
390 update_option('active_plugins', unserialize(file_get_contents($tempTheme . DIRECTORY_SEPARATOR . '.earlier_active_plugins')));
391 }
392 }
393
394 $filesToBeRemoved[] = $tempTheme;
395
396 if (is_dir($dir) && file_exists($dir)) {
397
398 $it = new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS);
399 $files = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
400
401 $this->migration->log(__('Removing ', 'backup-backup') . iterator_count($files) . __(' files', 'backup-backup'), 'INFO');
402 foreach ($files as $file) {
403 $pathReal = $file->getRealPath();
404 if (!file_exists($pathReal)) continue;
405 if ($file->isDir()) {
406 @rmdir($pathReal);
407 } else {
408 gc_collect_cycles();
409 @unlink($pathReal);
410 }
411 }
412
413 @rmdir($dir);
414
415 }
416
417 if (file_exists($this->scanFile)) {
418 @unlink($this->scanFile);
419 }
420
421 $sc = BMI_TMP . DIRECTORY_SEPARATOR . '.restore_secret';
422 if (file_exists($sc)) {
423 @unlink($sc);
424 }
425
426 $tblmap = BMI_TMP . DIRECTORY_SEPARATOR . '.table_map';
427 if (file_exists($tblmap)) {
428 @unlink($tblmap);
429 }
430 $allowedFiles = ['wp-config.php', '.htaccess', '.litespeed', '.default.json', 'driveKeys.php', 'dropboxKeys.php', '.autologin.php', '.migrationFinished', 'onedriveKeys.php', 'awsKeys.php', 'wasabiKeys.php', 'backupblissKeys.php', 'sftpKeys.php', 'pcloudKeys.php'];
431 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'backup-migration_??????????') as $filename) {
432
433 $basename = basename($filename);
434
435 if (is_dir($filename) && !in_array($basename, ['.', '..'])) {
436 $filesToBeRemoved[] = $filename;
437 }
438
439 }
440
441 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . '.*') as $filename) {
442
443 $basename = basename($filename);
444
445 if (in_array($basename, ['.', '..'])) continue;
446 if (is_file($filename) && !in_array($basename, $allowedFiles)) {
447 $filesToBeRemoved[] = $filename;
448 }
449
450 }
451
452 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_scan_*') as $filename) {
453
454 $basename = basename($filename);
455
456 if (in_array($basename, ['.', '..'])) continue;
457 if (is_file($filename) && !in_array($basename, $allowedFiles)) {
458 $filesToBeRemoved[] = $filename;
459 }
460
461 }
462
463 foreach (glob(untrailingslashit(ABSPATH) . DIRECTORY_SEPARATOR . 'wp-config.??????????.php') as $filename) {
464
465 $basename = basename($filename);
466
467 if (in_array($basename, ['.', '..'])) continue;
468 if (is_file($filename) && !in_array($filename, $allowedFiles)) {
469 $filesToBeRemoved[] = $filename;
470 }
471
472 }
473
474 if (is_array($filesToBeRemoved) || is_object($filesToBeRemoved)) {
475 foreach ((array) $filesToBeRemoved as $file) {
476 $this->rrmdir($file);
477 }
478 }
479
480 }
481
482 private function rrmdir($dir) {
483
484 if (is_dir($dir)) {
485
486 $objects = scandir($dir);
487 foreach ($objects as $object) {
488
489 if ($object != "." && $object != "..") {
490
491 if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && !is_link($dir . DIRECTORY_SEPARATOR . $object)) {
492
493 $this->rrmdir($dir . DIRECTORY_SEPARATOR . $object);
494
495 } else {
496
497 @unlink($dir . DIRECTORY_SEPARATOR . $object);
498
499 }
500
501 }
502
503 }
504
505 @rmdir($dir);
506
507 } else {
508
509 if (file_exists($dir) && is_file($dir)) {
510
511 @unlink($dir);
512
513 }
514
515 }
516
517 }
518
519 public function fixDumbWindowsSlashes() {
520
521 // Extraction directory (no trailing slash)
522 $tmp = $this->tmp;
523
524 $files = scandir($tmp);
525 if (sizeof($files) > 10) {
526
527 $this->migration->log(__("Performing solution to Windows backslashes...", 'backup-backup'), 'STEP');
528
529 foreach ($files as $index => $file) {
530
531 if (strpos($file, '\\') !== false) {
532
533 $path = explode('\\', $file);
534 $filename = array_pop($path);
535 $dirname = $tmp . DIRECTORY_SEPARATOR . join(DIRECTORY_SEPARATOR, $path);
536
537 if (!(file_exists($dirname) && is_dir($dirname))) {
538 mkdir($dirname, 0755, true);
539 }
540
541 rename($tmp . DIRECTORY_SEPARATOR . $file, $dirname . DIRECTORY_SEPARATOR . $filename);
542
543 }
544
545 }
546
547 $this->migration->log(__("Windows file structure fixed...", 'backup-backup'), 'SUCCESS');
548
549 }
550
551 }
552
553 public function findTablePrefixByFiles($manifestPrefix) {
554
555 $tmp = $this->tmp . DIRECTORY_SEPARATOR . 'db_tables';
556 $manifestPrefixExist = false;
557
558 if (!(file_exists($tmp) && is_dir($tmp))) {
559 return $manifestPrefix;
560 }
561
562 $originalPrefix = [
563 file_exists($tmp . DIRECTORY_SEPARATOR . $manifestPrefix . 'options.sql'),
564 file_exists($tmp . DIRECTORY_SEPARATOR . $manifestPrefix . 'users.sql'),
565 file_exists($tmp . DIRECTORY_SEPARATOR . $manifestPrefix . 'usermeta.sql'),
566 file_exists($tmp . DIRECTORY_SEPARATOR . $manifestPrefix . 'posts.sql'),
567 file_exists($tmp . DIRECTORY_SEPARATOR . $manifestPrefix . 'postmeta.sql')
568 ];
569
570 $lowerPrefix = [
571 file_exists($tmp . DIRECTORY_SEPARATOR . strtolower($manifestPrefix) . 'options.sql'),
572 file_exists($tmp . DIRECTORY_SEPARATOR . strtolower($manifestPrefix) . 'users.sql'),
573 file_exists($tmp . DIRECTORY_SEPARATOR . strtolower($manifestPrefix) . 'usermeta.sql'),
574 file_exists($tmp . DIRECTORY_SEPARATOR . strtolower($manifestPrefix) . 'posts.sql'),
575 file_exists($tmp . DIRECTORY_SEPARATOR . strtolower($manifestPrefix) . 'postmeta.sql')
576 ];
577
578 if (count(array_filter($lowerPrefix)) == 5 || count(array_filter($originalPrefix)) == 5) {
579 return $manifestPrefix;
580 }
581
582 $files = scandir($tmp);
583 $prefixes = [];
584
585 foreach ($files as $index => $file) {
586
587 if ($file == '.' || $file == '..') continue;
588
589 if (substr($file, 0, strlen($manifestPrefix)) == $manifestPrefix) {
590 $manifestPrefixExist = true;
591 return $manifestPrefix;
592 }
593
594 foreach ($files as $index2 => $comparefile) {
595
596 if ($comparefile == $file) continue;
597 $currentTopPrefix = '';
598
599 for ($i = 0; $i < min(strlen($comparefile), strlen($file)); ++$i) {
600
601 if ($file[$i] == $comparefile[$i]) {
602 $currentTopPrefix .= $file[$i];
603 } else break;
604
605 }
606
607 if ($currentTopPrefix != '') {
608 if (isset($prefixes[$currentTopPrefix])) {
609 $prefixes[$currentTopPrefix]++;
610 } else {
611 $prefixes[$currentTopPrefix] = 1;
612 }
613 }
614
615 }
616
617 }
618
619 if (sizeof($prefixes) <= 0) return $manifestPrefix;
620 else return array_search(max($prefixes), $prefixes);
621
622 }
623
624 public function makeUnZIP() {
625
626 // Source
627 $src = $this->src;
628
629 // Extract
630 $this->zip = new Zip();
631
632 if ($this->isCLI) {
633
634 $isOk = $this->zip->unzip_file($src, $this->tmp, $this->migration);
635
636 } else {
637
638 $last_seek = $this->recent_export_seek;
639
640 $file = new \SplFileObject($this->scanFile);
641 $file->seek($file->getSize());
642 $total_lines = $file->key() + 1;
643 $files = [];
644 $seek_begin = 0;
645 $recent_seek = $last_seek;
646 $shouldRepeat = false;
647
648 $batch = 50;
649 if ($total_lines > 1000) $batch = 100;
650 if ($total_lines > 2000) $batch = 200;
651 if ($total_lines > 6000) $batch = 300;
652 if ($total_lines > 12000) $batch = 500;
653 if ($total_lines > 36000) $batch = 1000;
654 if ($total_lines > 50000) $batch = 2500;
655 if ($total_lines > 100000) $batch = 5000;
656 if ($total_lines > 150000) $batch = 10000;
657 if ($total_lines > 200000) $batch = 20000;
658
659 if (defined('BMI_MAX_FILE_EXTRACTION_LIMIT')) {
660 $definedSize = BMI_MAX_FILE_EXTRACTION_LIMIT;
661 if (is_numeric($definedSize) && $definedSize > 50 && $definedSize < 20000) {
662 $batch = intval($definedSize);
663 }
664 }
665
666 if ($this->firstExtract == true) {
667 $this->migration->log(__("Preparing batching technique for extraction...", 'backup-backup'), 'STEP');
668 $this->migration->log(__('Files exported per batch: ', 'backup-backup') . $batch, 'INFO');
669 }
670
671 for ($i = $last_seek; $i < $total_lines; ++$i) {
672
673 $file->seek($i);
674 $line = trim($file->current());
675
676 if ($line && strlen($line) > 0) {
677
678 $files[] = $line;
679
680 }
681
682 $seek_begin++;
683 $recent_seek = $i;
684 if ($seek_begin > $batch) {
685
686 $shouldRepeat = true;
687 break;
688
689 }
690
691 }
692
693 $isOk = $this->zip->extract_files($src, $files, $this->tmp, $this->migration, $this->firstExtract);
694
695 }
696
697
698 if (!$isOk) {
699
700 // Verbose
701 $this->migration->log(__('Failed to extract the files...', 'backup-backup'), 'WARN');
702 $this->cleanup();
703
704 return false;
705
706 } else {
707
708 if (!$this->isCLI) {
709
710 $i = $recent_seek + 1;
711 $milestone = intval((($i / $total_lines) * 100) / 4);
712 $this->migration->progress($milestone);
713
714 $plus = -1;
715 if ($shouldRepeat != true) $plus = 0;
716
717 $this->migration->log(__('Extraction milestone: ', 'backup-backup') . ($i + $plus) . '/' . $total_lines . ' (' . number_format(($i / $total_lines) * 100, 2) . '%)', 'INFO');
718
719 }
720
721 }
722
723 // Verbose
724 if (!$this->isCLI && $shouldRepeat === true) {
725
726 $this->recent_export_seek = $recent_seek;
727 return 'repeat';
728
729 } else {
730
731 $this->migration->log(__('Files extracted...', 'backup-backup'), 'SUCCESS');
732 return true;
733
734 }
735
736 }
737
738 public function fixWPLogin(&$manifest) {
739
740 try {
741
742 global $wpdb;
743
744 $loginslug = false;
745 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
746 $results = $wpdb->get_results("SELECT option_value FROM " . BMP::escapeSQLIDentifier($this->dbFoundPrefix . "options") . " WHERE option_name = 'bwpl_slug';");
747
748 if (sizeof($results) > 0) $loginslug = $results[0]->option_value;
749
750 if ($loginslug != false && is_string($loginslug) && strlen($loginslug) >= 1) {
751
752 $wploginfile = trailingslashit(ABSPATH) . 'wp-login.php';
753 $blockedloginfile = trailingslashit(ABSPATH) . $loginslug . '-wp-login.php';
754
755 if (file_exists($wploginfile) && !file_exists($blockedloginfile)) {
756 @copy($wploginfile, $blockedloginfile);
757 }
758
759 }
760
761 }
762 catch (\Exception $e) {}
763 catch (\Throwable $e) {}
764
765 }
766
767 public function randomString($length = 64) {
768
769 $chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
770 $str = "";
771
772 for ($i = 0; $i < $length; ++$i) {
773
774 $str .= $chars[mt_rand(0, strlen($chars) - 1)];
775
776 }
777
778 return $str;
779
780 }
781
782 public function makeWPConfigCopy() {
783
784 $this->migration->log(__('Saving wp-config file...', 'backup-backup'), 'STEP');
785 $configData = file_get_contents(ABSPATH . 'wp-config.php');
786 if ($configData && strlen($configData) > 0) {
787 file_put_contents(ABSPATH . 'wp-config.' . $this->tmptime . '.php', $configData);
788 $this->migration->log(__('File wp-config saved', 'backup-backup'), 'SUCCESS');
789 } else {
790 $this->migration->log(__('Could not backup/read wp-config file.', 'backup-backup'), 'WARN');
791 }
792
793 }
794
795 public function getCurrentManifest($first = false) {
796
797 if ($first == true) {
798 $this->migration->log(__('Getting backup manifest...', 'backup-backup'), 'STEP');
799 }
800
801 $manifest = json_decode(file_get_contents($this->tmp . DIRECTORY_SEPARATOR . 'bmi_backup_manifest.json'));
802
803 if ($first == true) {
804 $this->migration->log(__('Manifest loaded', 'backup-backup'), 'SUCCESS');
805 }
806
807 return $manifest;
808
809 }
810
811 public function restoreBackupFromFiles($manifest) {
812
813 $this->same_domain = untrailingslashit($manifest->dbdomain) == untrailingslashit($this->siteurl) ? true : false;
814 $this->migration->log(__('Restoring files (this process may take a while)...', 'backup-backup'), 'STEP');
815 $contentDirectory = $this->WP_CONTENT_DIR;
816 $pathtowp = DIRECTORY_SEPARATOR . 'wp-content';
817 if (isset($manifest->config->WP_CONTENT_DIR) && isset($manifest->config->ABSPATH)) {
818 $absi = $manifest->config->ABSPATH;
819 $cotsi = $manifest->config->WP_CONTENT_DIR;
820 if (strlen($absi) <= strlen($cotsi) && substr($cotsi, 0, strlen($absi)) == $absi) {
821 $inside = true;
822 $pathtowp = substr($cotsi, strlen($absi));
823 } else {
824 $inside = false;
825 $pathtowp = $cotsi;
826 }
827 }
828
829 $this->replaceAll($pathtowp);
830 $this->migration->log(__('All files restored successfully.', 'backup-backup'), 'SUCCESS');
831
832 }
833
834 public function restoreDatabaseV1(&$manifest) {
835
836 $this->migration->log(__('Older backup detected, using V1 engine to restore database...', 'backup-backup'), 'WARN');
837 $this->migration->log(__('Database size: ' . BMP::humanSize(filesize($this->tmp . DIRECTORY_SEPARATOR . 'bmi_database_backup.sql')), 'backup-backup'), 'INFO');
838 $old_domain = $manifest->dbdomain;
839 $new_domain = $this->siteurl; // parse_url(home_url())['host'];
840
841 $abs = BMP::fixSlashes($manifest->config->ABSPATH);
842 $newabs = BMP::fixSlashes(ABSPATH);
843 $file = $this->tmp . DIRECTORY_SEPARATOR . 'bmi_database_backup.sql';
844 $this->db->importDatabase($file, $old_domain, $new_domain, $abs, $newabs, $this->dbFoundPrefix, $this->siteurl, $this->home);
845 $this->migration->log(__('Database restored', 'backup-backup'), 'SUCCESS');
846
847 }
848
849 public function setDBProgress($xi, $init_start, $table_names_alter) {
850
851 $this->db_xi = $xi;
852 $this->ini_start = $init_start;
853 $this->table_names_alter = $table_names_alter;
854
855 }
856
857 public function alter_tables(&$manifest) {
858
859 $storage = $this->tmp . DIRECTORY_SEPARATOR . 'db_tables';
860
861 $queriesAll = $manifest->total_queries;
862 if (isset($this->conversionStats['total_queries'])) {
863 $queriesAll = $this->conversionStats['total_queries'];
864 }
865
866 // $manifest->total_queries # the other solution
867 $importer = new BetterDatabaseImport($storage, $queriesAll, $manifest->config->ABSPATH, $manifest->dbdomain, $this->siteurl, $this->migration, $this->isCLI, $this->conversionStats);
868
869 $importer->xi = $this->db_xi;
870 $importer->init_start = $this->ini_start;
871 $importer->table_names_alter = $this->table_names_alter;
872
873 $importer->alter_names();
874 $this->migration->log(__('Database restored', 'backup-backup'), 'SUCCESS');
875
876 }
877
878 public function search_replace_v3(&$manifest) {
879
880 $res = false;
881 if (!$this->isCLI || $this->v3Importer == null) {
882 $storage = $this->tmp . DIRECTORY_SEPARATOR . 'db_tables';
883 $importer = new EvenBetterDatabaseImport($storage, false, $manifest, $this->migration, $this->splitting, $this->isCLI);
884 $res = $importer->searchReplace($this->replaceStep, $this->tableIndex, $this->currentReplacePage, $this->totalReplacePage, $this->fieldAdjustments, $manifest->config->table_prefix);
885 } else {
886 $res = $this->v3Importer->searchReplace($this->replaceStep, $this->tableIndex, $this->currentReplacePage, $this->totalReplacePage, $this->fieldAdjustments, $manifest->config->table_prefix);
887 }
888
889 if ($res && is_array($res) && $res['finished'] == true) {
890 $this->migration->log(__('Database restored', 'backup-backup'), 'SUCCESS');
891 }
892
893 return $res;
894
895 }
896
897 public function alter_tables_v3(&$manifest) {
898
899 if (!$this->isCLI || $this->v3Importer == null) {
900 $storage = $this->tmp . DIRECTORY_SEPARATOR . 'db_tables';
901 $importer = new EvenBetterDatabaseImport($storage, false, $manifest, $this->migration, $this->splitting, $this->isCLI);
902 $importer->alter_tables();
903
904 // Modify the WP Config and replace
905 $this->replaceDbPrefixInWPConfig($manifest);
906
907 $importer->enablePlugins();
908 } else {
909 $this->v3Importer->alter_tables();
910
911 // Modify the WP Config and replace
912 $this->replaceDbPrefixInWPConfig($manifest);
913
914 $this->v3Importer->enablePlugins();
915 }
916
917 $this->migration->log(__('Database restored', 'backup-backup'), 'SUCCESS');
918
919 }
920
921 public function restoreDatabaseV3(&$manifest) {
922
923 $storage = $this->tmp . DIRECTORY_SEPARATOR . 'db_tables';
924 $this->v3Importer = new EvenBetterDatabaseImport($storage, $this->firstDB, $manifest, $this->migration, $this->splitting, $this->isCLI);
925 $finished = $this->v3Importer->start();
926
927 if ($finished === true) {
928
929 return true;
930
931 } else {
932
933 return ['status' => 'new_file'];
934
935 }
936
937 }
938
939 public function restoreDatabaseV2(&$manifest) {
940
941 $storage = $this->tmp . DIRECTORY_SEPARATOR . 'db_tables';
942
943 if ($this->firstDB == true) {
944 $this->migration->log(__('Successfully detected backup created with V2 engine, importing...', 'backup-backup'), 'INFO');
945 $this->migration->log(__('Restoring database...', 'backup-backup'), 'STEP');
946 }
947
948 $queriesAll = $manifest->total_queries;
949 if (isset($this->conversionStats['total_queries'])) {
950 $queriesAll = $this->conversionStats['total_queries'];
951 }
952 $importer = new BetterDatabaseImport($storage, $queriesAll, $manifest->config->ABSPATH, $manifest->dbdomain, $this->siteurl, $this->migration, $this->isCLI, $this->conversionStats);
953
954 if ($this->isCLI) {
955
956 $importer->showFirstLogs();
957 $importer->import();
958
959 } else {
960
961 if ($this->firstDB == true) {
962 $importer->showFirstLogs();
963 }
964
965 $sqlFiles = $importer->get_sql_files($this->firstDB);
966
967 if ($this->firstDB != true) {
968 $importer->xi = $this->db_xi;
969 $importer->init_start = $this->ini_start;
970 $importer->table_names_alter = $this->table_names_alter;
971 }
972
973 if ($this->continueFile != false && $this->continueFile != '' && $this->continueSeek != false && $this->continueSeek != '') {
974
975 $import = $importer->restore_by_file($this->continueFile, $this->continueSeek);
976 $importer->queries_ended();
977 $this->continueFile = $this->continueFile;
978 $this->setDBProgress($importer->xi, $importer->init_start, $importer->table_names_alter);
979
980 } else {
981
982 if (sizeof($sqlFiles) > 0) {
983
984 $import = $importer->restore_by_file($sqlFiles[0]);
985 $importer->queries_ended();
986 $this->continueFile = $sqlFiles[0];
987 $this->setDBProgress($importer->xi, $importer->init_start, $importer->table_names_alter);
988
989 } else {
990
991 return true;
992
993 }
994
995 }
996
997 if ($import !== true) {
998
999 return ['status' => 'repeat', 'file' => $this->continueFile, 'seek' => $import];
1000
1001 } else {
1002
1003 return ['status' => 'new_file'];
1004
1005 }
1006
1007 }
1008
1009 $this->migration->log(__('Database restored', 'backup-backup'), 'SUCCESS');
1010
1011 }
1012
1013 public function restoreDatabaseDynamic(&$manifest) {
1014
1015 if ($this->firstDB == true) {
1016 $this->migration->log(__('Checking the database structure...', 'backup-backup'), 'STEP');
1017 }
1018
1019 if (is_dir($this->tmp . DIRECTORY_SEPARATOR . 'db_tables')) {
1020
1021 $forcev3Engine = false;
1022 if (isset($manifest->db_backup_engine) && $manifest->db_backup_engine === 'v4') {
1023 if ($this->v3engine == false) {
1024 $forcev3Engine = true;
1025
1026 if ($this->firstDB == true) {
1027 $this->migration->log(__('New search replace is disabled, nevertheless your backup does not support it, forcing to use new S&R engine.', 'backup-backup'), 'WARN');
1028 }
1029 }
1030 }
1031
1032 if ($this->v3engine || $forcev3Engine) {
1033
1034 if (!$this->isCLI) {
1035
1036 $this->v3RestoreUsed = true;
1037 $import = $this->restoreDatabaseV3($manifest);
1038 return $import;
1039
1040 } else {
1041
1042 $this->v3RestoreUsed = true;
1043 $this->restoreDatabaseV3($manifest);
1044
1045 }
1046
1047 } else {
1048
1049 if (!$this->isCLI) {
1050
1051 $import = $this->restoreDatabaseV2($manifest);
1052 return $import;
1053
1054 } else {
1055
1056 $this->restoreDatabaseV2($manifest);
1057
1058 }
1059
1060 }
1061
1062 } elseif (file_exists($this->tmp . DIRECTORY_SEPARATOR . 'bmi_database_backup.sql')) {
1063
1064 $this->restoreDatabaseV1($manifest);
1065
1066 } else {
1067
1068 $this->migration->log(__('This backup does not contain database copy, omitting...', 'backup-backup'), 'INFO');
1069 return false;
1070
1071 }
1072
1073 return true;
1074
1075 }
1076
1077 public function cleanupCurrentThemesAndPlugins() {
1078
1079 if ($this->cleanupbefore == true) {
1080
1081 $this->migration->log(__('Moving current themes and plugins.', 'backup-backup'), 'STEP');
1082
1083 $plugins_path = BMP::fixSlashes(WP_PLUGIN_DIR);
1084 $themes_path = BMP::fixSlashes(dirname(get_template_directory()));
1085
1086 $plugins = [];
1087 if (file_exists($plugins_path)) {
1088 $plugins = array_values(array_diff(scandir($plugins_path), ['..', '.', 'backup-backup', 'backup-backup-pro']));
1089 }
1090
1091 $themes = [];
1092 if (file_exists($themes_path)) {
1093 $themes = array_values(array_diff(scandir($themes_path), ['..', '.', 'backup-backup', 'backup-backup-pro']));
1094 }
1095
1096 $destination = BMI_BACKUPS_DEFAULT . DIRECTORY_SEPARATOR . 'clean-ups';
1097 $destination_unique = $destination . DIRECTORY_SEPARATOR . 'restoration_' . intval($this->start);
1098
1099 $destination_plugins = $destination_unique . DIRECTORY_SEPARATOR . 'plugins';
1100 $destination_themes = $destination_unique . DIRECTORY_SEPARATOR . 'themes';
1101
1102 if (!file_exists($destination)) @mkdir($destination, 0775, true);
1103 if (!file_exists($destination_unique)) @mkdir($destination_unique, 0775, true);
1104 if (!file_exists($destination_plugins)) @mkdir($destination_plugins, 0775, true);
1105 if (!file_exists($destination_themes)) @mkdir($destination_themes, 0775, true);
1106
1107 for ($i = 0; $i < sizeof($plugins); ++$i) {
1108 $pluginPath = trailingslashit($plugins_path) . $plugins[$i];
1109 $destPath = trailingslashit($destination_plugins) . $plugins[$i];
1110 rename($pluginPath, $destPath);
1111 }
1112
1113 for ($i = 0; $i < sizeof($themes); ++$i) {
1114 $themePath = trailingslashit($themes_path) . $themes[$i];
1115 $destPath = trailingslashit($destination_themes) . $themes[$i];
1116 rename($themePath, $destPath);
1117 }
1118
1119 $this->migration->log(__('Themes and plugins moved to safe directory.', 'backup-backup'), 'SUCCESS');
1120
1121 }
1122
1123 return true;
1124
1125 }
1126
1127 public function rescueCleanedThemesAndPlugins() {
1128
1129 if ($this->cleanupbefore == true) {
1130
1131 $this->migration->log(__('Restoring moved themes and plugins.', 'backup-backup'), 'INFO');
1132
1133 $plugins_path = BMP::fixSlashes(WP_PLUGIN_DIR);
1134 $themes_path = BMP::fixSlashes(dirname(get_template_directory()));
1135
1136 $destination = BMI_BACKUPS_DEFAULT . DIRECTORY_SEPARATOR . 'clean-ups';
1137 $destination_unique = $destination . DIRECTORY_SEPARATOR . 'restoration_' . intval($this->start);
1138
1139 $destination_plugins = $destination_unique . DIRECTORY_SEPARATOR . 'plugins';
1140 $destination_themes = $destination_unique . DIRECTORY_SEPARATOR . 'themes';
1141
1142 $plugins = [];
1143 if (file_exists($destination_plugins)) {
1144 $plugins = array_values(array_diff(scandir($destination_plugins), ['..', '.']));
1145 }
1146
1147 $themes = [];
1148 if (file_exists($destination_themes)) {
1149 $themes = array_values(array_diff(scandir($destination_themes), ['..', '.']));
1150 }
1151
1152 if (!file_exists($plugins_path)) @mkdir($plugins_path, 0775, true);
1153 if (!file_exists($themes_path)) @mkdir($themes_path, 0775, true);
1154
1155 for ($i = 0; $i < sizeof($plugins); ++$i) {
1156 $pluginPath = trailingslashit($destination_plugins) . $plugins[$i];
1157 $destPath = trailingslashit($plugins_path) . $plugins[$i];
1158 rename($pluginPath, $destPath);
1159 }
1160
1161 for ($i = 0; $i < sizeof($themes); ++$i) {
1162 $themePath = trailingslashit($destination_themes) . $themes[$i];
1163 $destPath = trailingslashit($themes_path) . $themes[$i];
1164 rename($themePath, $destPath);
1165 }
1166
1167 }
1168
1169 return true;
1170
1171 }
1172
1173 public function removeCleanedThemesAndPlugins() {
1174
1175 if (defined('BMI_KEEP_CLEANUPS') && BMI_KEEP_CLEANUPS == true) {
1176
1177 return true;
1178
1179 } else {
1180
1181 if ($this->cleanupbefore == true) {
1182
1183 $this->migration->log(__('Removing old plugins and themes moved before restoration.', 'backup-backup'), 'INFO');
1184
1185 $destination = BMI_BACKUPS_DEFAULT . DIRECTORY_SEPARATOR . 'clean-ups';
1186 $destination_unique = $destination . DIRECTORY_SEPARATOR . 'restoration_' . intval($this->start);
1187 $this->rrmdir($destination_unique);
1188
1189 }
1190
1191 }
1192
1193 }
1194
1195 public function replaceDbPrefixInWPConfig(&$manifest) {
1196
1197 $abs = untrailingslashit(ABSPATH);
1198 $curr_prefix = $this->table_prefix;
1199 $new_prefix = $this->dbFoundPrefix;
1200
1201 $this->migration->log('Detected table prefix: ' . $new_prefix, 'VERBOSE');
1202 $this->migration->log('Forwarded table prefix: ' . $curr_prefix, 'VERBOSE');
1203 $this->migration->log('Manifest table prefix: ' . $manifest->config->table_prefix, 'VERBOSE');
1204
1205 // if (strtolower($manifest->config->table_prefix) == strtolower($new_prefix)) {
1206 // $new_prefix = $manifest->config->table_prefix;
1207 // }
1208
1209 // if (strlen(trim($manifest->config->table_prefix)) == 0) {
1210 // return;
1211 // }
1212
1213 // if (strlen(trim($new_prefix)) == 0) {
1214 // return;
1215 // }
1216
1217 $new_prefix = $manifest->config->table_prefix;
1218
1219 $this->migration->log(__('Restoring wp-config file...', 'backup-backup'), 'STEP');
1220 $wpconfigDir = $abs . DIRECTORY_SEPARATOR . 'wp-config.' . $this->tmptime . '.php';
1221 if (file_exists($wpconfigDir) && is_readable($wpconfigDir) && is_writable($wpconfigDir)) {
1222
1223 // rename($abs . DIRECTORY_SEPARATOR . 'wp-config.' . $this->tmptime . '.php', $abs . DIRECTORY_SEPARATOR . 'wp-config.php');
1224 $wpconfig = file_get_contents($abs . DIRECTORY_SEPARATOR . 'wp-config.php');
1225 if (strpos($wpconfig, '"' . $curr_prefix . '";') !== false) {
1226 $wpconfig = str_replace('"' . $curr_prefix . '";', '"' . $new_prefix . '";', $wpconfig);
1227 } elseif (strpos($wpconfig, "'" . $curr_prefix . "';") !== false) {
1228 $wpconfig = str_replace("'" . $curr_prefix . "';", "'" . $new_prefix . "';", $wpconfig);
1229 }
1230
1231 file_put_contents($abs . DIRECTORY_SEPARATOR . 'wp-config.php', $wpconfig);
1232
1233 $this->migration->log(__('WP-Config restored', 'backup-backup'), 'SUCCESS');
1234
1235 } else {
1236
1237 $this->migration->log(__('Cannot write to WP-Config, if you need to change database prefix, please do it manually.', 'backup-backup'), 'WARN');
1238
1239 }
1240
1241 }
1242
1243 public function restoreOriginalWPConfig($remove = true) {
1244
1245 // $abs = untrailingslashit(ABSPATH);
1246 // $tmp_file_f = $abs . DIRECTORY_SEPARATOR . 'wp-config.' . $this->tmptime . '.php';
1247 // if (file_exists($tmp_file_f)) {
1248 // copy($tmp_file_f, $abs . DIRECTORY_SEPARATOR . 'wp-config.php');
1249 // if ($remove === true) @unlink($tmp_file_f);
1250 // }
1251 //
1252 // wp_load_alloptions(true);
1253
1254 }
1255
1256 public function makeNewLoginSession(&$manifest) {
1257 global $wpdb;
1258
1259 $prefix = sanitize_key($manifest->config->table_prefix);
1260 // Ensure correct prefix is used before anything
1261 $wpdb->set_prefix($manifest->config->table_prefix);
1262 wp_load_alloptions(true);
1263 $this->migration->log(__('Making new login session', 'backup-backup'), 'STEP');
1264
1265 $prefix = $wpdb->prefix;
1266 $cap_key = $prefix . 'capabilities';
1267 $uid = isset($manifest->uid) ? intval($manifest->uid) : 0;
1268
1269 // Check if provided UID is valid
1270 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
1271 $is_valid_uid = $uid > 0 && $wpdb->get_var(
1272 $wpdb->prepare("SELECT ID FROM " . BMP::escapeSQLIDentifier($prefix . "users") . " WHERE ID = %d", $uid)
1273 );
1274
1275 // If no UID, cron mode, or invalid UID, find an administrator manually
1276 if (
1277 !$is_valid_uid ||
1278 $manifest->cron === true ||
1279 $manifest->cron === 'true'
1280 ) {
1281 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
1282 $uid = $wpdb->get_var($wpdb->prepare("
1283 SELECT u.ID
1284 FROM " . BMP::escapeSQLIDentifier($prefix . "users") . " u
1285 INNER JOIN " . BMP::escapeSQLIDentifier($prefix . "usermeta") . " um ON u.ID = um.user_id
1286 WHERE um.meta_key = %s
1287 AND um.meta_value LIKE %s
1288 LIMIT 1
1289 ", $cap_key, '%administrator%'));
1290
1291 // Fallback to first user if no admin found
1292 if (!$uid) {
1293 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
1294 $uid = $wpdb->get_var("SELECT ID FROM " . BMP::escapeSQLIDentifier($prefix . "users") . " LIMIT 1");
1295 }
1296
1297 $uid = intval($uid);
1298 }
1299
1300 // Get user login info from correct (possibly changed) users table
1301 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
1302 $user = $wpdb->get_row(
1303 $wpdb->prepare("SELECT ID, user_login FROM " . BMP::escapeSQLIDentifier($prefix . "users") . " WHERE ID = %d", $uid)
1304 );
1305
1306 if ($user && isset($user->ID)) {
1307 remove_all_actions('wp_login', -1000);
1308
1309 clean_user_cache(get_current_user_id());
1310 clean_user_cache($user->ID);
1311
1312 wp_clear_auth_cookie();
1313 wp_set_current_user($user->ID, $user->user_login);
1314 wp_set_auth_cookie($user->ID, true, is_ssl());
1315
1316 // Manually trigger wp_login with minimal object
1317 $fake_user = (object) [
1318 'ID' => $user->ID,
1319 'user_login' => $user->user_login,
1320 ];
1321 do_action('wp_login', $user->user_login, $fake_user);
1322
1323 $manifest->uid = $user->ID;
1324 $this->migration->log(__('User should be logged in', 'backup-backup'), 'SUCCESS');
1325 } else {
1326 $this->migration->log(__('User login failed. Could not find user.', 'backup-backup'), 'ERROR');
1327 }
1328 }
1329
1330
1331 public function setOrUpdateXhria() {
1332
1333 // Update Original Local Storage Path
1334 if ($this->backupStorage && is_string($this->backupStorage)) {
1335 if (function_exists('wp_load_alloptions')) wp_load_alloptions(true);
1336 delete_option('BMI::STORAGE::LOCAL::PATH');
1337 if (function_exists('wp_load_alloptions')) wp_load_alloptions(true);
1338 update_option('BMI::STORAGE::LOCAL::PATH', $this->backupStorage);
1339 }
1340
1341 if ($this->code && is_string($this->code) && strlen($this->code) > 0) update_option('z__bmi_xhria', $this->code);
1342 else delete_option('z__bmi_xhria');
1343
1344 }
1345
1346 public function clearElementorCache() {
1347
1348 $file = trailingslashit(wp_upload_dir()['basedir']) . 'elementor';
1349 if (file_exists($file) && is_dir($file)) {
1350 $this->migration->log(__('Clearing elementor template cache...', 'backup-backup'), 'STEP');
1351 $path = $file . DIRECTORY_SEPARATOR . '*';
1352 foreach (glob($path) as $file_path) if (!is_dir($file_path)) @unlink($file_path);
1353 $this->migration->log(__('Elementor cache cleared!', 'backup-backup'), 'SUCCESS');
1354 }
1355
1356 }
1357
1358 public function finalCleanUP() {
1359
1360 $this->migration->log(__('Cleaning temporary files...', 'backup-backup'), 'STEP');
1361 $this->cleanup();
1362 $this->removeCleanedThemesAndPlugins();
1363 $this->migration->log(__('Temporary files cleaned', 'backup-backup'), 'SUCCESS');
1364
1365 }
1366
1367 public function handleError($e) {
1368
1369 // Restore moved themes and plugins
1370 $this->rescueCleanedThemesAndPlugins();
1371
1372 // On this tragedy at least remove tmp files
1373 $this->migration->log(__('Something bad happened...', 'backup-backup'), 'ERROR');
1374 if (method_exists($e, 'getMessage')) {
1375 $this->migration->log($e->getMessage(), 'ERROR');
1376 $this->migration->log($e->getLine() . ' @ ' . $e->getFile(), 'ERROR');
1377 }
1378 $this->cleanup();
1379
1380 }
1381
1382 public function makeTMPDirectory() {
1383
1384 // Make temp dir
1385 $this->migration->log(__('Making temporary directory', 'backup-backup'), 'INFO');
1386 if (!(is_dir($this->tmp) || file_exists($this->tmp))) {
1387 mkdir($this->tmp, 0755, true);
1388 }
1389
1390 // Deny read of this folder
1391 copy(BMI_INCLUDES . DIRECTORY_SEPARATOR . 'htaccess' . DIRECTORY_SEPARATOR . '.htaccess', $this->tmp . DIRECTORY_SEPARATOR . '.htaccess');
1392 touch($this->tmp . DIRECTORY_SEPARATOR . 'index.html');
1393 touch($this->tmp . DIRECTORY_SEPARATOR . 'index.php');
1394
1395 }
1396
1397 public function backupLocalOptions() {
1398 global $wpdb;
1399 $bmi_config_options = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE option_name LIKE '%bmi_%' OR option_name LIKE '%bmip_%' OR option_name LIKE '%bmi_pro_%'" );
1400 $tempConfigFile = BMI_TMP . DIRECTORY_SEPARATOR . 'bmi_local_options.json';
1401 $options = [];
1402 foreach ( $bmi_config_options as $option ) {
1403 $options[ $option->option_name ] = maybe_unserialize( $option->option_value );
1404 }
1405 $content = json_encode( $options );
1406 file_put_contents($tempConfigFile, $content);
1407
1408 }
1409
1410 public function restoreLocalPluginConfiguration() {
1411 $tempConfigFile = BMI_TMP . DIRECTORY_SEPARATOR . 'bmi_local_options.json';
1412
1413 if (!file_exists($tempConfigFile) || !is_readable($tempConfigFile)) {
1414 return;
1415 }
1416
1417 $json_data = file_get_contents($tempConfigFile);
1418 $options = json_decode($json_data, true);
1419 wp_cache_flush();
1420 wp_load_alloptions(true);
1421
1422 global $wpdb;
1423 $bmi_config_options = $wpdb->get_results( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%bmi_%' OR option_name LIKE '%bmip_%' OR option_name LIKE '%bmi_pro_%'" );
1424 foreach ( $bmi_config_options as $option ) {
1425 delete_option( $option->option_name );
1426 }
1427
1428 if (is_array($options)) {
1429 foreach ($options as $name => $value) {
1430 update_option($name, $value);
1431
1432 }
1433 }
1434
1435 wp_cache_flush();
1436 wp_load_alloptions(true);
1437
1438 unlink($tempConfigFile);
1439 }
1440
1441 private function makeRestoreSecret() {
1442
1443 $this->migration->log(__('Making new secret key for current restore process.', 'backup-backup'), 'STEP');
1444 $secret = $this->randomString();
1445 file_put_contents(BMI_TMP . DIRECTORY_SEPARATOR . '.restore_secret', $secret);
1446 $this->migration->log(__('Secret key generated, it will be returned to you (ping).', 'backup-backup'), 'SUCCESS');
1447
1448 return $secret;
1449
1450 }
1451
1452 public function listBackupContents() {
1453
1454 $manager = new ZipManager();
1455
1456 $save = $this->scanFile;
1457 $amount = $manager->getPartsToRestore($this->src, $save);
1458 if ($amount === false) {
1459 $amount = $manager->getZipContentList($this->src, $save);
1460 }
1461
1462 $this->migration->log(__('Scan found ', 'backup-backup') . $amount . __(' files inside the backup.', 'backup-backup'), 'INFO');
1463
1464 return $amount;
1465
1466 }
1467
1468 public function extractTo($secret = null) {
1469
1470 try {
1471
1472 // Require Universal Zip Library
1473 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'zipper' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'zip.php';
1474
1475 // Make restore secret
1476 if (!$this->isCLI && $this->batchStep == 0) {
1477
1478 // Verbose
1479 Logger::log('Restoring site...');
1480
1481 if ((gettype($secret) != 'string' || strlen($secret) != 64)) {
1482
1483 $secret = $this->makeRestoreSecret();
1484 BMP::res(['status' => 'secret', 'tmp' => $this->tmptime, 'secret' => $secret, 'options' => [
1485 'code' => $this->code,
1486 'start' => $this->start,
1487 'step' => 0
1488 ]]);
1489 return;
1490
1491 } else {
1492
1493 // $this->migration->log(__('Secret key detected successfully (pong)!', 'backup-backup'), 'INFO');
1494
1495 }
1496
1497 }
1498
1499 // STEP: 1
1500 if ($this->isCLI || $this->batchStep == 1) {
1501
1502 if (!$this->isCLI) {
1503
1504 $this->migration->log(__('Secret key detected successfully (pong)!', 'backup-backup'), 'INFO');
1505
1506 }
1507
1508 // Make temporary directory
1509 $this->makeTMPDirectory();
1510
1511 // Migrate local options
1512 $this->backupLocalOptions();
1513
1514 // Time start
1515 $this->migration->log(__('Scanning archive...', 'backup-backup'), 'STEP');
1516
1517 if (!$this->isCLI) {
1518
1519 BMP::res(['status' => 'restore_ongoing', 'tmp' => $this->tmptime, 'secret' => $secret, 'options' => [
1520 'code' => $this->code,
1521 'start' => $this->start,
1522 'step' => 1
1523 ]]);
1524
1525 return;
1526
1527 }
1528
1529 }
1530
1531 // STEP: 2
1532 if ($this->isCLI || $this->batchStep == 2) {
1533
1534 // Get ZIP contents for batch unzipping
1535 $this->fileAmount = $this->listBackupContents();
1536 $this->cleanupCurrentThemesAndPlugins();
1537
1538 if (!$this->isCLI) {
1539
1540 BMP::res(['status' => 'restore_ongoing', 'tmp' => $this->tmptime, 'secret' => $secret, 'options' => [
1541 'code' => $this->code,
1542 'start' => $this->start,
1543 'amount' => $this->fileAmount,
1544 'step' => 2
1545 ]]);
1546
1547 return;
1548
1549 }
1550
1551 }
1552
1553 // STEP: 3
1554 if ($this->isCLI || $this->batchStep == 3) {
1555
1556 // UnZIP the backup
1557 try {
1558 $unzipped = $this->makeUnZIP();
1559 } catch (\Exception $e) {
1560 $this->handleError($e);
1561 return;
1562 } catch (\Throwable $t) {
1563 $this->handleError($t);
1564 return;
1565 }
1566
1567 if ($unzipped === false) {
1568
1569 $this->handleError(__('File extraction process failed.', 'backup-backup'));
1570 return;
1571
1572 }
1573
1574 if (!$this->isCLI) {
1575
1576 $shouldRepeat = false;
1577 if ($unzipped === 'repeat') {
1578
1579 $shouldRepeat = true;
1580
1581 } else {
1582
1583 $shouldRepeat = false;
1584
1585 }
1586
1587 BMP::res(['status' => 'restore_ongoing', 'tmp' => $this->tmptime, 'secret' => $secret, 'options' => [
1588 'code' => $this->code,
1589 'start' => $this->start,
1590 'amount' => $this->fileAmount,
1591 'recent_export_seek' => $this->recent_export_seek,
1592 'repeat_export' => $shouldRepeat,
1593 'firstExtract' => $this->firstExtract,
1594 'step' => 3
1595 ]]);
1596
1597 return;
1598
1599 }
1600
1601 }
1602
1603 // STEP: 4
1604 if ($this->isCLI || $this->batchStep == 4) {
1605
1606 // Check if extracted files are not in backslashed Windows version, otherwise fix it
1607 $this->fixDumbWindowsSlashes();
1608 $this->removeUnwantedFiles();
1609
1610 // WP Config backup
1611 $this->makeWPConfigCopy();
1612
1613 if (!$this->isCLI) {
1614
1615 BMP::res(['status' => 'restore_ongoing', 'tmp' => $this->tmptime, 'secret' => $secret, 'options' => [
1616 'code' => $this->code,
1617 'start' => $this->start,
1618 'amount' => $this->fileAmount,
1619 'storage' => get_option('BMI::STORAGE::LOCAL::PATH', false),
1620 'step' => 4
1621 ]]);
1622
1623 return;
1624
1625 }
1626
1627 }
1628
1629 // STEP: 5
1630 if ($this->isCLI || $this->batchStep == 5) {
1631
1632 // Get manifest
1633 $manifest = $this->getCurrentManifest(true);
1634
1635 try {
1636
1637 if (isset($manifest->version)) {
1638 $this->migration->log(__('Backup Migration version used for that backup: ', 'backup-backup') . $manifest->version, 'INFO');
1639 } else {
1640 $this->migration->log(__('Backup was made with unknown version of Backup Migration plugin.', 'backup-backup'), 'INFO');
1641 }
1642
1643 } catch (\Exception $e) {
1644
1645 $this->migration->log(__('Backup was made with unknown version of Backup Migration plugin.', 'backup-backup'), 'INFO');
1646
1647 } catch (\Throwable $e) {
1648
1649 $this->migration->log(__('Backup was made with unknown version of Backup Migration plugin.', 'backup-backup'), 'INFO');
1650
1651 }
1652
1653 // Even remove extracted WP-config if it's different site.
1654 if (untrailingslashit($manifest->dbdomain) != untrailingslashit($this->siteurl)) {
1655
1656 // Unlink wp-config inside extracted directory
1657 $extractedWpConfigPath = $this->tmp . DIRECTORY_SEPARATOR . 'wordpress' . DIRECTORY_SEPARATOR . 'wp-config.php';
1658 if (file_exists($extractedWpConfigPath)) @unlink($extractedWpConfigPath);
1659
1660 }
1661
1662 // Restore files
1663 $this->restoreBackupFromFiles($manifest);
1664
1665
1666 if (untrailingslashit($manifest->dbdomain) != untrailingslashit($this->siteurl)) {
1667
1668 // Restore WP Config if it's different domain
1669 $this->restoreOriginalWPConfig(false);
1670
1671 }
1672
1673 if (!$this->isCLI) {
1674
1675 BMP::res(['status' => 'restore_ongoing', 'tmp' => $this->tmptime, 'secret' => $secret, 'options' => [
1676 'code' => $this->code,
1677 'start' => $this->start,
1678 'amount' => $this->fileAmount,
1679 'storage' => $this->backupStorage,
1680 'step' => 5
1681 ]]);
1682
1683 return;
1684
1685 }
1686
1687 }
1688
1689 // STEP: 6
1690 if ($this->isCLI || $this->batchStep == 6) {
1691
1692 // This literally does nothing.
1693
1694 if (!$this->isCLI) {
1695
1696 BMP::res(['status' => 'restore_ongoing', 'tmp' => $this->tmptime, 'secret' => $secret, 'options' => [
1697 'code' => $this->code,
1698 'start' => $this->start,
1699 'amount' => $this->fileAmount,
1700 'storage' => $this->backupStorage,
1701 'step' => 6
1702 ]]);
1703
1704 return;
1705
1706 }
1707
1708 }
1709
1710 // STEP 7
1711 if ($this->isCLI || $this->batchStep == 7) {
1712
1713 // Get manifest
1714 if (!isset($manifest)) {
1715 $manifest = $this->getCurrentManifest();
1716 }
1717
1718 $this->migration->log(__('Validating table prefix...', 'backup-backup'), 'STEP');
1719 $dbPrefix = $this->findTablePrefixByFiles($manifest->config->table_prefix);
1720 $this->migration->log(__('Table prefix in manifest: ', 'backup-backup') . $manifest->config->table_prefix, 'INFO');
1721 $this->migration->log(__('Detected table prefix: ', 'backup-backup') . $dbPrefix, 'INFO');
1722
1723 $wasDisabled = 0;
1724 $dbFinishedConv = 'false';
1725 $newDataProcess = $this->processData;
1726
1727 $forcev3Engine = false;
1728 if (isset($manifest->db_backup_engine) && $manifest->db_backup_engine === 'v4') {
1729 if ($this->v3engine == false) {
1730 $forcev3Engine = true;
1731 }
1732 }
1733
1734 if ($this->v3engine || $forcev3Engine) {
1735
1736 if ($this->usingDbEngineV4) {
1737 $this->migration->log(__('Splitting process is disabled because v4 restore engine is enabled.', 'backup-backup'), 'INFO');
1738 } else {
1739 $this->migration->log(__('Splitting process is disabled because v3 restore engine is enabled.', 'backup-backup'), 'INFO');
1740 }
1741
1742 $wasDisabled = 1;
1743
1744 } else if (!$this->splitting) {
1745
1746 $this->migration->log(__('Splitting process is disabled in the settings, omitting.', 'backup-backup'), 'INFO');
1747 $wasDisabled = 1;
1748
1749 } else {
1750
1751 $db_tables = $this->tmp . DIRECTORY_SEPARATOR . 'db_tables';
1752
1753 if (is_dir($db_tables)) {
1754
1755 if (empty($this->processData)) {
1756 $this->migration->log(__('Converting database files into partial files.', 'backup-backup'), 'STEP');
1757 if (defined('BMI_DB_MAX_ROWS_PER_QUERY')) {
1758 $this->migration->log(__('Max rows per query (this site): ', 'backup-backup') . BMI_DB_MAX_ROWS_PER_QUERY, 'INFO');
1759 }
1760
1761 try {
1762
1763 if (isset($manifest->source_query_output)) {
1764 $this->migration->log(__('Max rows per query (source site): ', 'backup-backup') . $manifest->source_query_output, 'INFO');
1765 } else {
1766 $this->migration->log(__('Unknown query output value of backup file, maybe it was made before v1.1.7', 'backup-backup'), 'INFO');
1767 }
1768
1769 } catch (\Exception $e) {
1770
1771 $this->migration->log(__('Unknown query output value of backup file, maybe it was made before v1.1.7', 'backup-backup'), 'INFO');
1772
1773 } catch (\Throwable $e) {
1774
1775 $this->migration->log(__('Unknown query output value of backup file, maybe it was made before v1.1.7', 'backup-backup'), 'INFO');
1776
1777 }
1778
1779 }
1780
1781
1782 $dbsort = new SmartDatabaseSort($db_tables, $this->migration, $this->isCLI);
1783 $process = $dbsort->sortUnsorted($this->processData);
1784
1785 if (!is_null($process) && isset($process)) {
1786 $newDataProcess = $process;
1787 }
1788
1789 if ($this->isCLI || (isset($process['convertionFinished']) && $process['convertionFinished'] == 'yes')) {
1790 $this->migration->log(__('Database convertion finished successfully.', 'backup-backup'), 'SUCCESS');
1791
1792 $this->migration->log(__('Calculating new query size and counts.', 'backup-backup'), 'STEP');
1793 $stats = $dbsort->countAllFilesAndQueries();
1794 $this->migration->log(__('Calculaion completed, printing details.', 'backup-backup'), 'SUCCESS');
1795
1796 $this->migration->log(__('Total queries to insert after conversion: ', 'backup-backup') . $stats['total_queries'], 'INFO');
1797 $this->migration->log(__('Partial files count after conversion: ', 'backup-backup') . sizeof($stats['all_files']), 'INFO');
1798 $this->migration->log(__('Total size of the database: ', 'backup-backup') . BMP::humanSize($stats['total_size']), 'INFO');
1799 $this->migration->log(__('Table count to be imported: ', 'backup-backup') . sizeof($stats['all_tables']), 'INFO');
1800
1801 $total_qrs = $stats['total_queries'];
1802 $this->conversionStats = [];
1803 $this->conversionStats['total_queries'] = $total_qrs;
1804
1805 $dbFinishedConv = 'true';
1806 }
1807
1808 } else {
1809
1810 if (file_exists($this->tmp . DIRECTORY_SEPARATOR . 'bmi_database_backup.sql')) {
1811
1812 $this->migration->log(__('Ommiting database convert step as the database backup included was not made with V2 engine.', 'backup-backup'), 'WARN');
1813 $this->migration->log(__('The process may be less stable if the database is larger than usual.', 'backup-backup'), 'WARN');
1814 $dbFinishedConv = 'true';
1815
1816 } else {
1817
1818 $this->migration->log(__('Ommiting database convert step as there is no database backup included.', 'backup-backup'), 'INFO');
1819 $dbFinishedConv = 'true';
1820
1821 }
1822
1823 }
1824
1825 }
1826
1827 if (!$this->isCLI) {
1828
1829 BMP::res(['status' => 'restore_ongoing', 'tmp' => $this->tmptime, 'secret' => $secret, 'options' => [
1830 'code' => $this->code,
1831 'start' => $this->start,
1832 'amount' => $this->fileAmount,
1833 'dbConvertionFinished' => $dbFinishedConv,
1834 'processData' => $newDataProcess,
1835 'conversionStats' => $this->conversionStats,
1836 'storage' => $this->backupStorage,
1837 'dbFoundPrefix' => $dbPrefix,
1838 'step' => 7 + $wasDisabled
1839 ]]);
1840
1841 return;
1842
1843 }
1844
1845 }
1846
1847 // STEP: 8
1848 if ($this->isCLI || $this->batchStep == 8) {
1849
1850 // Get manifest
1851 if (!isset($manifest)) {
1852 $manifest = $this->getCurrentManifest();
1853 }
1854
1855 if (isset($manifest->db_backup_engine) && $manifest->db_backup_engine === 'v4') {
1856 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'even-better-restore-v4.php';
1857 $this->usingDbEngineV4 = true;
1858 } else {
1859 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'even-better-restore-v3.php';
1860 $this->usingDbEngineV4 = false;
1861 }
1862
1863 // Try to restore database
1864 if (!$this->isCLI) {
1865
1866 $dbFinished = false;
1867 $database_exist = $this->restoreDatabaseDynamic($manifest);
1868
1869 if ($database_exist === false || $database_exist === true) {
1870
1871 $dbFinished = true;
1872
1873 } else {
1874
1875 if ($database_exist['status'] == 'new_file') {
1876
1877 $this->continueFile = false;
1878 $this->continueSeek = false;
1879
1880 } else {
1881
1882 $this->continueFile = $database_exist['file'];
1883 $this->continueSeek = $database_exist['seek'];
1884
1885 }
1886
1887 }
1888
1889 } else {
1890
1891 $database_exist = $this->restoreDatabaseDynamic($manifest);
1892
1893 }
1894
1895 $this->databaseExist = $database_exist;
1896
1897 if (!$this->isCLI) {
1898
1899 BMP::res(['status' => 'restore_ongoing', 'tmp' => $this->tmptime, 'secret' => $secret, 'options' => [
1900 'code' => $this->code,
1901 'start' => $this->start,
1902 'amount' => $this->fileAmount,
1903 'databaseExist' => $database_exist === true ? 'true' : 'false',
1904 'continueFile' => $this->continueFile,
1905 'continueSeek' => $this->continueSeek,
1906 'dbFinished' => $dbFinished,
1907 'firstDB' => $this->firstDB,
1908 'db_xi' => $this->db_xi,
1909 'ini_start' => $this->ini_start,
1910 'table_names_alter' => $this->table_names_alter,
1911 'conversionStats' => $this->conversionStats,
1912 'v3RestoreUsed' => $this->v3RestoreUsed,
1913 'dbFoundPrefix' => $this->dbFoundPrefix,
1914 'storage' => $this->backupStorage,
1915 'step' => 8
1916 ]]);
1917
1918 return;
1919
1920 }
1921
1922 }
1923
1924 // STEP: 9
1925 if ($this->isCLI || $this->batchStep == 9) {
1926
1927 // Get manifest
1928 if (!isset($manifest)) {
1929 $manifest = $this->getCurrentManifest();
1930 }
1931
1932 if (isset($manifest->db_backup_engine) && $manifest->db_backup_engine === 'v4') {
1933 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'even-better-restore-v4.php';
1934 $this->usingDbEngineV4 = true;
1935 } else {
1936 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'even-better-restore-v3.php';
1937 $this->usingDbEngineV4 = false;
1938 }
1939
1940 $database_exist = $this->databaseExist;
1941 if ($database_exist === true || $database_exist === 'true') {
1942 $this->removePreviousSelectionsIfDatabaseIncluded();
1943 }
1944
1945 // Alter all tables
1946 $status = false;
1947 $tableIndex = $this->tableIndex;
1948 $replaceStep = $this->replaceStep;
1949 $replaceFinished = false;
1950 $currentReplacePage = 0;
1951 $totalReplacePage = 0;
1952 $fieldAdjustments = 0;
1953
1954 if ($this->isCLI) {
1955
1956 $srFinished = false;
1957 if ($database_exist && $this->v3RestoreUsed == true) {
1958 while (!$srFinished) {
1959
1960 $status = $this->search_replace_v3($manifest);
1961
1962 if ($status != false && is_array($status)) {
1963 $this->replaceStep = $status['step'];
1964 $this->tableIndex = $status['tableIndex'];
1965 $this->replaceFinished = $status['finished'];
1966 $this->currentReplacePage = $status['currentPage'];
1967 $this->totalReplacePage = $status['totalPages'];
1968 $this->fieldAdjustments = $status['fieldAdjustments'];
1969
1970 if ($this->replaceFinished == true) $srFinished = true;
1971 }
1972
1973 }
1974 } else {
1975 $this->replaceFinished = true;
1976 $this->migration->progress(98);
1977 }
1978
1979 } else {
1980
1981 if ($database_exist && $this->v3RestoreUsed == true) {
1982 $status = $this->search_replace_v3($manifest);
1983 } else {
1984 $this->replaceFinished = true;
1985 $this->migration->progress(98);
1986 }
1987
1988 if ($status != false && is_array($status)) {
1989 $this->replaceStep = $status['step'];
1990 $this->tableIndex = $status['tableIndex'];
1991 $this->replaceFinished = $status['finished'];
1992 $this->currentReplacePage = $status['currentPage'];
1993 $this->totalReplacePage = $status['totalPages'];
1994 $this->fieldAdjustments = $status['fieldAdjustments'];
1995 }
1996
1997 }
1998
1999 if (!$this->isCLI) {
2000
2001 BMP::res([
2002 'status' => 'restore_ongoing',
2003 'tmp' => $this->tmptime,
2004 'secret' => $secret,
2005 'options' => [
2006 'code' => $this->code,
2007 'start' => $this->start,
2008 'amount' => $this->fileAmount,
2009 'databaseExist' => $database_exist === true ? 'true' : 'false',
2010 'firstDB' => $this->firstDB,
2011 'db_xi' => $this->db_xi,
2012 'ini_start' => $this->ini_start,
2013 'table_names_alter' => $this->table_names_alter,
2014 'conversionStats' => $this->conversionStats,
2015 'v3RestoreUsed' => $this->v3RestoreUsed,
2016 'replaceStep' => $this->replaceStep,
2017 'tableIndex' => $this->tableIndex,
2018 'replaceFinished' => $this->replaceFinished,
2019 'currentReplacePage' => $this->currentReplacePage,
2020 'totalReplacePage' => $this->totalReplacePage,
2021 'fieldAdjustments' => $this->fieldAdjustments,
2022 'dbFoundPrefix' => $this->dbFoundPrefix,
2023 'storage' => $this->backupStorage,
2024 'step' => 9
2025 ]
2026 ]);
2027
2028 return;
2029
2030 }
2031
2032 }
2033
2034 // STEP: 10
2035 if ($this->isCLI || $this->batchStep == 10) {
2036
2037 // Rename database from temporary to destination
2038 // And do the rest
2039 // Step 10 runs only at the end of database import
2040 // Get manifest
2041 if (!isset($manifest)) {
2042 $manifest = $this->getCurrentManifest();
2043 }
2044
2045 if (isset($manifest->db_backup_engine) && $manifest->db_backup_engine === 'v4') {
2046 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'even-better-restore-v4.php';
2047 $this->usingDbEngineV4 = true;
2048 } else {
2049 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'even-better-restore-v3.php';
2050 $this->usingDbEngineV4 = false;
2051 }
2052
2053 $database_exist = $this->databaseExist;
2054
2055 // Restore WP Config ** It allows to recover session after restore no matter what
2056 if ($database_exist == true || $database_exist == 'true') {
2057
2058 // Alter all tables
2059 if ($this->v3RestoreUsed == true) {
2060
2061 $this->alter_tables_v3($manifest);
2062
2063 } else {
2064
2065 $this->alter_tables($manifest);
2066
2067 // Modify the WP Config and replace
2068 $this->replaceDbPrefixInWPConfig($manifest);
2069
2070 }
2071
2072 // User is logged off at this point, try to log in
2073 $this->makeNewLoginSession($manifest);
2074
2075 } else {
2076
2077 // Restore WP Config without modifications
2078 $this->restoreOriginalWPConfig();
2079
2080 }
2081
2082 // Make sure the Xhria was not modified
2083 $this->setOrUpdateXhria();
2084
2085 // Fix elementor templates
2086 $this->clearElementorCache();
2087
2088 // Make final cleanup
2089 $this->finalCleanUP();
2090
2091 // Final flush of rewrite rules
2092 flush_rewrite_rules();
2093
2094 // Remove backup migration temporary options
2095 $this->restoreLocalPluginConfiguration();
2096
2097 // Dedicated fix for block-wp-login plugin
2098 $this->fixWPLogin($manifest);
2099
2100 // Touch autologin file
2101 $autologin_file = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.autologin';
2102 touch($autologin_file);
2103
2104 // Final verbose
2105 if ((intval(microtime(true)) - intval($this->start)) > 0) {
2106 $this->migration->log(__('Restore process took: ', 'backup-backup') . (intval(microtime(true)) - intval($this->start)) . ' seconds.', 'INFO');
2107 } else {
2108 $this->migration->log(__('Restore process fully finished.', 'INFO'));
2109 }
2110 Logger::log('Site restored...');
2111
2112 // Return success
2113 return true;
2114
2115 }
2116
2117 } catch (\Exception $e) {
2118
2119 // On this tragedy at least remove tmp files
2120 $this->handleError($e);
2121 return false;
2122
2123 } catch (\Throwable $e) {
2124
2125 // On this tragedy at least remove tmp files
2126 $this->handleError($e);
2127 return false;
2128
2129 }
2130
2131 }
2132
2133 }
2134