PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 1.4.9
Backup Migration v1.4.9
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 / database / even-better-restore-v3.php
backup-backup / includes / database Last commit date
better-backup-v3.php 11 months ago better-backup.php 11 months ago better-restore.php 11 months ago even-better-restore-v3.php 11 months ago even-better-restore-v4.php 11 months ago manager.php 11 months ago search-replace.php 11 months ago smart-sort.php 11 months ago
even-better-restore-v3.php
934 lines
1 <?php
2
3 /**
4 * Author: Mikołaj `iClyde` Chodorowski
5 * Contact: kontakt@iclyde.pl
6 * Package: Backup Migration – WP Plugin
7 */
8
9 // Namespace
10 namespace BMI\Plugin\Database;
11
12 // Use
13 use BMI\Plugin\BMI_Logger AS Logger;
14 use BMI\Plugin\Backup_Migration_Plugin as BMP;
15 use BMI\Plugin\Progress\BMI_ZipProgress AS Progress;
16 use BMI\Plugin\Database\BMI_Search_Replace_Engine as BMISearchReplace;
17
18 // Exit on direct access
19 if (!defined('ABSPATH')) exit;
20
21 /**
22 * Database Restore Enginge v3
23 */
24 class BMI_Even_Better_Database_Restore {
25
26 // Unwanted tables
27 private $unwantedTables = [
28 'wfblockediplog',
29 'wfblocks7',
30 'wfcrawlers',
31 'wffilechanges',
32 'wffilemods',
33 'wfhits',
34 'wfhoover',
35 'wfissues',
36 'wfknownfilelist',
37 'wflivetraffichuman',
38 'wflocs',
39 'wflogins',
40 'wfnotifications',
41 'wfpendingissues',
42 'wfreversecache',
43 'wfsnipcache',
44 'wfstatus',
45 'wftrafficrate',
46 'actionscheduler_logs',
47 'slim_stats',
48 'woocommerce_sessions',
49 'yoast_indexable',
50 'slim_events',
51 'cerber_files',
52 'cerber_traffic',
53 'cerber_log',
54 'cerber_countries',
55 'cerber_blocks',
56 'cerber_acl',
57 'statistics_views',
58 'pcachewpr',
59 'statistics_visitor_relationships',
60 'statistics_visitor',
61 'statistics_visit',
62 'statistics_search',
63 'statistics_pages',
64 'icl_languages_translations',
65 'icl_string_pages',
66 'icl_string_translations',
67 'itsec_log',
68 'actionscheduler_actions',
69 'aepc_logs'
70 ];
71
72 /**
73 * __construct - Make connection
74 *
75 * @return @self
76 */
77 function __construct($storage, $firstDB, &$manifest, &$logger, $splitting, $isCLI) {
78
79 $this->isCLI = $isCLI;
80 $this->splitting = $splitting;
81 $this->storage = $storage;
82 $this->logger = &$logger;
83 $this->manifest = &$manifest;
84 $this->tablemap = BMI_TMP . DIRECTORY_SEPARATOR . '.table_map';
85
86 if ($firstDB) $this->initMessage();
87
88 $this->map = $this->getTableMap();
89 $this->seek = &$this->map['seek'];
90
91 }
92
93 public function start() {
94
95 if ($this->isCLI) {
96
97 while ($nextFile = $this->getNextFile()) {
98 $this->processFile($nextFile);
99 }
100
101 return true;
102
103 } else {
104
105 $nextFile = $this->getNextFile();
106 if ($nextFile === false) return true;
107 else {
108
109 $this->processFile($nextFile);
110
111 return false;
112
113 }
114
115 }
116
117 }
118
119 private function getTableMap() {
120
121 if (file_exists($this->tablemap)) {
122
123 $data = json_decode(file_get_contents($this->tablemap), true);
124 $this->map = $data;
125
126 } else {
127
128 $data = [
129 'tables' => [],
130 'seek' => [
131 'last_seek' => 0,
132 'last_file' => '...',
133 'last_start' => 0,
134 'total_tables' => sizeof(array_diff(scandir($this->storage), ['..', '.'])),
135 'active_plugins' => 'a:1:{i:0;s:31:"backup-backup/backup-backup.php";}'
136 ]
137 ];
138
139 file_put_contents($this->tablemap, json_encode($data));
140
141 }
142
143 return $data;
144
145 }
146
147 private function getTableProgress() {
148
149 $total_tables = $this->seek['total_tables'];
150 $tables_left = sizeof(array_diff(scandir($this->storage), ['..', '.']));
151
152 $finished_tables = ($total_tables - $tables_left) + 1;
153 $percentage = number_format(($finished_tables / $total_tables) * 100, 2);
154
155 $this->logger->progress(50 + ((number_format($percentage, 0) / 2) - 10));
156
157 return $finished_tables . '/' . $total_tables . ' (' . $percentage . '%)';
158
159 }
160
161 private function queryFile(&$objFile, $filePath, $tableName, $realTableName) {
162
163 global $wpdb;
164
165 $seek = &$this->seek['last_seek'];
166 if ($seek == 0) {
167 $seek = 19;
168 $wpdb->query("DROP TABLE IF EXISTS `" . $tableName . "`;");
169
170 $str = __("Started restoration of %table_name% %total_tables% table", 'backup-backup');
171 $str = str_replace('%table_name%', $realTableName, $str);
172 $str = str_replace('%total_tables%', $this->getTableProgress(), $str);
173 $this->logger->log($str, 'STEP');
174
175 // Check if file can be cleaned
176 $this->filterFile($filePath, basename($filePath));
177 }
178
179 $qs = "/* QUERY START */\n";
180 $qe = "/* QUERY END */\n";
181
182 $vs = "/* VALUES START */\n";
183 $ve = "/* VALUES END */\n";
184
185 $wpdb->suppress_errors();
186
187 $wpdb->query('SET autocommit = 0;');
188 $wpdb->query('SET foreign_key_checks = 0;');
189 $wpdb->query("SET SQL_MODE = '';");
190 $wpdb->query('START TRANSACTION;');
191
192 $sqlStarted = false;
193
194 $sql = '';
195 while (!$objFile->eof()) {
196 $objFile->seek($seek); $seek++;
197
198 if ($objFile->current() == $qs) { $sqlStarted = true; continue; }
199 else if ($objFile->current() == $vs || $objFile->current() == $ve) {
200 continue;
201 } else if ($objFile->current() == $qe) {
202 $sqlStarted = false;
203 break;
204 }
205
206 if ($sqlStarted == true) $sql .= rtrim($objFile->current(), "\n");
207 }
208
209 $wpdb->query($sql); unset($sql);
210 $wpdb->query('COMMIT;');
211 $wpdb->query('SET autocommit = 1;');
212 $wpdb->query('SET foreign_key_checks = 1;');
213
214 $str = __("Progress of %table_name%: %progress%", 'backup-backup');
215 $str = str_replace('%table_name%', $realTableName, $str);
216
217 $objFile->seek($objFile->getSize());
218 $total_size = $objFile->key();
219 $objFile->seek($seek);
220
221 $progress = ($seek - 1) . '/' . $total_size . " (" . number_format(($seek - 1) / $total_size * 100, 2) . "%)";
222 $str = str_replace('%progress%', $progress, $str);
223 $this->logger->log($str, 'INFO');
224
225 $wpdb->show_errors();
226
227 if ($objFile->eof()) {
228 return true;
229 } else {
230 return false;
231 }
232
233 }
234
235 private function addNewTableToMap($from, $to, $file) {
236
237 if (!array_key_exists($from, $this->map['tables'])) {
238 $this->map['tables'][$from] = $to;
239 }
240
241 file_put_contents($this->tablemap, json_encode($this->map));
242
243 }
244
245 private function processFile($file) {
246
247 if ($this->seek['last_seek'] == 0) {
248 $this->seek['last_start'] = microtime(true);
249 }
250
251 $objFile = new \SplFileObject($file);
252
253 $objFile->seek(17);
254 $realTableName = explode('`', $objFile->current())[1];
255
256 $objFile->seek(18);
257 $tmpTableName = explode('`', $objFile->current())[1];
258
259 $finished = $this->queryFile($objFile, $file, $tmpTableName, $realTableName);
260
261 if ($finished && file_exists($file)) {
262 $this->seek['last_seek'] = 0;
263 $this->seek['last_file'] = '...';
264 @unlink($file);
265
266 $totalTime = microtime(true) - intval($this->seek['last_start']);
267 $totalTime = number_format($totalTime, 5);
268
269 $str = __("Table %table_name% restoration took %time% seconds", 'backup-backup');
270 $str = str_replace('%table_name%', $realTableName, $str);
271 $str = str_replace('%time%', $totalTime, $str);
272
273 $this->logger->log($str, 'SUCCESS');
274 $this->seek['last_start'] = 0;
275 }
276
277 $this->addNewTableToMap($tmpTableName, $realTableName, $file);
278
279 return true;
280
281 }
282
283 private function parseDomain($domain, $removeWWW = true) {
284
285 if (substr($domain, 0, 8) == 'https://') $domain = substr($domain, 8);
286 if (substr($domain, 0, 7) == 'http://') $domain = substr($domain, 7);
287 if ($removeWWW === true) {
288 if (substr($domain, 0, 4) == 'www.') $domain = substr($domain, 4);
289 }
290 $domain = untrailingslashit($domain);
291
292 return $domain;
293
294 }
295
296 private function replaceTableNames($tables) {
297
298 global $wpdb;
299
300 $this->logger->log(__('Performing table replacement', 'backup-backup'), 'STEP');
301
302 $wpdb->suppress_errors();
303 foreach ($tables as $oldTable => $newTable) {
304
305 $sql = "DROP TABLE IF EXISTS `" . $newTable . "`;";
306 $wpdb->query($sql);
307
308 $sql = "ALTER TABLE `" . $oldTable . "` RENAME TO `" . $newTable . "`;";
309 $wpdb->query($sql);
310
311 $str = __('Table %old% renamed to %new%', 'backup-backup');
312 $str = str_replace('%old%', $oldTable, $str);
313 $str = str_replace('%new%', $newTable, $str);
314 $this->logger->log($str, 'INFO');
315
316 }
317
318 $wpdb->show_errors();
319 $this->logger->log(__('All tables replaced', 'backup-backup'), 'SUCCESS');
320
321 }
322
323 private function performReplace($step = 0, $tableIndex = 0, $currentPage = 0, $totalPages = 0, $fieldAdjustments = 0, $newPrefix = "wp_") {
324
325 $status = [
326 'step' => $step,
327 'tableIndex' => $tableIndex,
328 'finished' => false,
329 'currentPage' => $currentPage,
330 'totalPages' => $totalPages,
331 'fieldAdjustments' => $fieldAdjustments
332 ];
333
334 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'search-replace.php';
335
336 $backupRootDir = $this->manifest->config->ABSPATH;
337 $currentRootDir = ABSPATH;
338
339 $backupDomain = $this->parseDomain($this->manifest->dbdomain);
340 $currentDomain = $this->parseDomain(get_option('siteurl'), false);
341
342 $currentTable = false;
343 $allTables = array_keys($this->map['tables']);
344
345 if ($tableIndex < sizeof($allTables) && array_key_exists($tableIndex, $allTables)) {
346 $currentTable = $allTables[$tableIndex];
347 }
348
349 if ($currentTable == false && !$currentTable) {
350 if ($backupRootDir != $currentRootDir || $currentDomain != $this->parseDomain($backupDomain, false)) {
351 $this->logger->log(__('Search & Replace finished successfully.', 'backup-backup'), 'SUCCESS');
352 }
353
354 $status['finished'] = true;
355 return $status;
356 }
357
358 if (strpos($currentTable, $newPrefix) === false) {
359 $this->logger->log(__('Adjustments are not required for this table.', 'backup-backup') . "(" . sanitize_text_field(strval($currentTable)) . ")", 'INFO');
360
361 $status['step'] = 1;
362 $status['fieldAdjustments'] = 0;
363 $status['tableIndex'] = $tableIndex + 1;
364 return $status;
365 }
366
367 $replaceEngine = new BMISearchReplace([$currentTable], $currentPage, $totalPages);
368
369 if ($step == 0) {
370 if ($backupRootDir != $currentRootDir || $currentDomain != $this->parseDomain($backupDomain, false)) {
371 $this->logger->log(__('Performing Search & Replace', 'backup-backup'), 'STEP');
372 $pagesize = '?';
373 if (defined('BMI_MAX_SEARCH_REPLACE_PAGE')) $pagesize = BMI_MAX_SEARCH_REPLACE_PAGE;
374 $this->logger->log(__('Page size for that restoration: ', 'backup-backup') . $pagesize, 'INFO');
375 $status['step'] = $step + 1; $step++;
376 } else {
377 $this->logger->log(__('This backup was made on the same site, ommiting search & replace.', 'backup-backup'), 'INFO');
378 $status['finished'] = true;
379 return $status;
380 }
381 }
382
383 if ($step == 1) {
384 $replaceProgress = ($tableIndex + 1) . "/" . sizeof($allTables);
385 $replaceProgressPercentage = number_format((($tableIndex + 1) / sizeof($allTables) * 100), 2);
386 $progressLogT = __('Performing database adjustments for table %progress%: %table_name% (%progress_percentage%)', 'backup-backup');
387 $progressLogT = str_replace('%progress%', $replaceProgress, $progressLogT);
388 $progressLogT = str_replace('%table_name%', $currentTable, $progressLogT);
389 $progressLogT = str_replace('%progress_percentage%', $replaceProgressPercentage . '%', $progressLogT);
390 $this->logger->log($progressLogT, 'STEP');
391
392 $percentageProgress = number_format($replaceProgressPercentage, 0);
393 $this->logger->progress(number_format(90 + ($percentageProgress / 100) * 8, 0));
394
395 if ($backupRootDir != $currentRootDir) {
396
397 $dtables = 0; $drows = 0; $dchange = 0; $dupdates = 0;
398
399 $r = $replaceEngine->perform($backupRootDir, $currentRootDir);
400 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
401
402 $status['currentPage'] = $r['currentPage'];
403 $status['totalPages'] = $r['totalPages'];
404
405 if ($status['totalPages'] > 0) {
406
407 $info = __("Batch for path adjustment (%page%/%allPages%) updated: %updates% fields.", 'backup-backup');
408 $updates = $dupdates;
409 if ($updates == 0) $updates = 1;
410 $info = str_replace('%page%', $status['currentPage'], $info);
411 $info = str_replace('%allPages%', $status['totalPages'], $info);
412 $info = str_replace('%updates%', $updates, $info);
413 $this->logger->log($info, 'INFO');
414 $status['fieldAdjustments']++;
415
416 } else {
417
418 // $this->logger->log(__('Path adjustments are not required for this table.', 'backup-backup'), 'INFO');
419
420 }
421
422 if ($status['currentPage'] >= $status['totalPages']) {
423 $status['currentPage'] = 0;
424 $status['totalPages'] = 0;
425 $status['step'] = $step + 1;
426 }
427 return $status;
428
429 } else {
430
431 $status['step'] = $step + 1; $step++;
432
433 }
434 }
435
436 if ($step == 2 || $step == 3 || $step == 4 || $step == 5 || $step == 6 || $step == 7) {
437 if ($currentDomain != $this->parseDomain($backupDomain, false)) {
438 $ssl = is_ssl() == true ? 'https://' : 'http://';
439
440 $dtables = 0; $drows = 0; $dchange = 0; $dupdates = 0;
441
442 $possibleDomainsBackup = [
443 "https://www." . $backupDomain,
444 "http://www." . $backupDomain,
445 "https://" . $backupDomain,
446 "http://" . $backupDomain,
447 'www.' . $backupDomain,
448 $backupDomain
449 ];
450
451 $possibleDomainsCurrent = [
452 $ssl . $currentDomain,
453 $ssl . $currentDomain,
454 $ssl . $currentDomain,
455 $ssl . $currentDomain,
456 $currentDomain,
457 $currentDomain
458 ];
459
460 if ($step == 2) {
461 $r = $replaceEngine->perform($possibleDomainsBackup[0], $possibleDomainsCurrent[0]);
462 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
463 }
464
465 if ($step == 3) {
466 $r = $replaceEngine->perform($possibleDomainsBackup[1], $possibleDomainsCurrent[1]);
467 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
468 }
469
470 if ($step == 4) {
471 $r = $replaceEngine->perform($possibleDomainsBackup[2], $possibleDomainsCurrent[2]);
472 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
473 }
474
475 if ($step == 5) {
476 $r = $replaceEngine->perform($possibleDomainsBackup[3], $possibleDomainsCurrent[3]);
477 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
478 }
479
480 if ($step == 6) {
481 $r = $replaceEngine->perform($possibleDomainsBackup[4], $possibleDomainsCurrent[4]);
482 $dchange += $r['change']; $dupdates += $r['updates'];
483 }
484
485 if ($step == 7) {
486 if (!(substr($currentDomain, -strlen($backupDomain)) === $backupDomain)) {
487 $r = $replaceEngine->perform($possibleDomainsBackup[5], $possibleDomainsCurrent[5]);
488 $dchange += $r['change']; $dupdates += $r['updates'];
489 }
490 }
491
492 $status['currentPage'] = $r['currentPage'];
493 $status['totalPages'] = $r['totalPages'];
494
495 $variants = [
496 __('variant A', 'backup-backup'),
497 __('variant B', 'backup-backup'),
498 __('variant C', 'backup-backup'),
499 __('variant D', 'backup-backup'),
500 __('variant E', 'backup-backup'),
501 __('variant F', 'backup-backup')
502 ];
503
504 if ($status['totalPages'] > 0) {
505
506 $info = __("Batch for domain (%variant%) adjustments (%page%/%allPages%) updated: %updates% fields.", 'backup-backup');
507 $updates = $dupdates;
508 if ($updates == 0) $updates = 1;
509 $info = str_replace('%variant%', $variants[$step - 2], $info);
510 $info = str_replace('%page%', $status['currentPage'], $info);
511 $info = str_replace('%allPages%', $status['totalPages'], $info);
512 $info = str_replace('%updates%', $updates, $info);
513 $this->logger->log($info, 'INFO');
514 $status['fieldAdjustments']++;
515
516 } else {
517
518 // $info = __('Domain (%variant%) adjustments are not required for this table.', 'backup-backup');
519 // $info = str_replace('%variant%', $variants[$step - 2], $info);
520 // $this->logger->log($info, 'INFO');
521
522 }
523
524 if ($status['currentPage'] >= $status['totalPages']) {
525 $status['currentPage'] = 0;
526 $status['totalPages'] = 0;
527 $status['step'] = $step + 1;
528 }
529 return $status;
530 }
531 }
532
533 if ($step == 8) {
534 if ($fieldAdjustments === 0) {
535 $this->logger->log(__('Adjustments are not required for this table.', 'backup-backup'), 'INFO');
536 }
537
538 $status['step'] = 1;
539 $status['fieldAdjustments'] = 0;
540 $status['tableIndex'] = $tableIndex + 1;
541 return $status;
542 }
543
544 return $status;
545
546 }
547
548 public function is_valid_plugin($plugin) {
549
550 global $wp_version;
551
552 $default_headers = array( 'wp' => 'Requires at least', 'php' => 'Requires PHP' );
553
554 $wp = false;
555 $php = false;
556
557 $detectedwp = '0.0.0';
558 $detectedphp = '0.0.0';
559
560 try {
561
562 $plugin_file = BMP::fixSlashes(WP_PLUGIN_DIR . '/' . $plugin);
563 $plugin_readme = BMP::fixSlashes(WP_PLUGIN_DIR . '/' . dirname($plugin) . '/readme.txt');
564 if (!file_exists($plugin_readme)) $plugin_readme = BMP::fixSlashes(WP_PLUGIN_DIR . '/' . dirname($plugin) . '/README.txt');
565
566 if (file_exists($plugin_file)) {
567 $plugin_data = get_file_data($plugin_file, $default_headers, 'plugin');
568 if (!empty($plugin_data['wp']) && version_compare($plugin_data['wp'], $wp_version, '<=')) {
569 $detectedwp = $plugin_data['wp'];
570 $wp = true;
571 }
572 if (!empty($plugin_data['php']) && version_compare($plugin_data['php'], PHP_VERSION, '<=')) {
573 $detectedphp = $plugin_data['php'];
574 $php = true;
575 }
576 }
577
578 if (file_exists($plugin_readme)) {
579 $readme_data = get_file_data($plugin_readme, $default_headers, 'plugin');
580 if (!empty($readme_data['wp']) && version_compare($readme_data['wp'], $wp_version, '<=')) {
581 $detectedwp = $readme_data['wp'];
582 $wp = true;
583 }
584
585 if (!empty($readme_data['php']) && version_compare($readme_data['php'], PHP_VERSION, '<=')) {
586 $detectedphp = $readme_data['php'];
587 $php = true;
588 }
589 }
590
591 $this->logger->log(sprintf('Detected version WP/PHP for plugin: %s, is (%s/%s)', $plugin, $detectedwp, $detectedphp), 'VERBOSE');
592
593 if ($plugin == 'hello.php') return true;
594 if ($php && $wp) return true;
595 else return false;
596
597 } catch (Error $e) {
598 return false;
599 }
600
601 return false;
602
603 }
604
605 private function try_activate_plugins($plugins, $sucstr_source, $failstr_source, $failed_plugins = []) {
606
607 $plugins_copy = array_values($plugins);
608 $should_continue = false;
609 $activated_plugins = [];
610 $failed_plugins = $failed_plugins;
611 $disallowed_plugins = [
612 'bluehost-wordpress-plugin/bluehost-wordpress-plugin.php',
613 'sg-cachepress/sg-cachepress.php',
614 'wordpress-starter/siteground-wizard.php',
615 'revslider/revslider.php',
616 'easy-soundcloud-shortcode/easy-soundcloud-shortcode.php',
617 'easy-soundcloud-shortcode/EasySoundcloudShortcode.php'
618 ];
619
620 for ($i = 0; $i < sizeof($plugins_copy); ++$i) {
621
622 $plugin_name = $plugins_copy[$i];
623 $plugin_display = $plugin_name;
624
625 $shouldActivate = true;
626
627 if (empty($plugin_name)) {
628 $shouldActivate = false;
629 $plugin_display = '(---)';
630 } else if ($plugin_name == 'hello.php') {
631 $shouldActivate = true;
632 } else if (strpos($plugin_name, '/') === false) {
633 $shouldActivate = false;
634 }
635
636 $sucstr = str_replace('%plugin_name%', $plugin_display, $sucstr_source);
637 $failstr = str_replace('%plugin_name%', $plugin_display, $failstr_source);
638
639 if ($shouldActivate) {
640 try {
641
642 if ($this->is_valid_plugin($plugin_name) && !in_array($plugin_name, $disallowed_plugins)) {
643
644 $resultWP = activate_plugin($plugin_name, '', true, true);
645
646 $this->logger->log($sucstr, 'INFO');
647 $activated_plugins[] = $plugin_name;
648
649 $should_continue = true;
650 break;
651
652 } else {
653
654 if (!in_array($plugin_name, $failed_plugins)) {
655 $failed_plugins[] = $plugin_name;
656 }
657
658 }
659
660 } catch (\Exception $e) {
661
662 if (!in_array($plugin_name, $failed_plugins)) {
663
664 $failed_plugins[] = $plugin_name;
665 error_log(strval($e));
666
667 }
668
669 } catch (\Throwable $e) {
670
671 if (!in_array($plugin_name, $failed_plugins)) {
672
673 $msg = $e->getMessage();
674 if (strpos($msg, 'add_rule()') != false || strpos($msg, 'rewrite.php:143') != false) {
675
676 $activated_plugins[] = $plugin_name;
677 error_log(strval($e));
678
679 } else {
680
681 $failed_plugins[] = $plugin_name;
682 error_log(strval($e));
683
684 }
685
686 }
687
688 }
689
690 } else {
691
692 $this->logger->log($failstr, 'WARN');
693
694 }
695
696 }
697
698 return [ 'failed' => $failed_plugins, 'active' => $activated_plugins, 'should_continue' => $should_continue ];
699
700 }
701
702 public function enablePlugins() {
703
704 global $wpdb;
705
706 $this->logger->log(__('Enabling plugins included in the backup', 'backup-backup'), 'STEP');
707
708 if (is_serialized($this->seek['active_plugins'])) {
709
710 $plugins = unserialize($this->seek['active_plugins']);
711 usort($plugins, function ($a, $b) { return strlen($a) - strlen($b); });
712 $plugins = array_values($plugins);
713
714 $sucstr_source = __('Plugin %plugin_name% enabled successfully.', 'backup-backup');
715 $failstr_source = __('Failed to enable plugin %plugin_name%, trying to not end at fatal error...', 'backup-backup');
716
717 $fullyActive = [];
718 $failed_plugins = [];
719
720 if (!function_exists('activate_plugin')) {
721 require_once(ABSPATH .'/wp-admin/includes/plugin.php');
722 }
723
724 $one_more_time = true;
725 $try_again = true;
726 while ($try_again) {
727
728 $res = $this->try_activate_plugins($plugins, $sucstr_source, $failstr_source, $failed_plugins);
729
730 $fullyActive = array_unique(array_merge($fullyActive, $res['active']));
731 $plugins = array_diff($plugins, $res['active']);
732 $failed_plugins = array_unique(array_diff(array_merge($failed_plugins, $res['failed']), $fullyActive));
733
734 $try_again = $res['should_continue'];
735 if ($try_again == false && $one_more_time == true) {
736 $one_more_time = false;
737 $try_again = true;
738 }
739
740 }
741
742 for ($i = 0; $i < sizeof($failed_plugins); ++$i) {
743
744 $failstr = str_replace('%plugin_name%', $failed_plugins[$i], $failstr_source);
745 $this->logger->log($failstr, 'WARN');
746
747 }
748
749 if (!in_array('backup-backup/backup-backup.php', $fullyActive)) {
750 $fullyActive[] = 'backup-backup/backup-backup.php';
751 }
752
753 update_option('active_plugins', $fullyActive);
754
755 }
756
757 $this->logger->progress(100);
758 $this->logger->log(__('All plugins enabled, you are ready to go :)', 'backup-backup'), 'SUCCESS');
759
760 }
761
762 public function searchReplace($step = 0, $tableIndex = 0, $currentPage = 0, $totalPages = 0, $fieldAdjustments = 0, $newPrefix = 'wp_') {
763
764 $this->logger->progress(90);
765 return $this->performReplace($step, $tableIndex, $currentPage, $totalPages, $fieldAdjustments, $newPrefix);
766
767 }
768
769 public function alter_tables() {
770
771 $this->logger->progress(98);
772 $this->prepareFinalDatabase();
773 $this->replaceTableNames($this->map['tables']);
774
775 }
776
777 private function prepareFinalDatabase() {
778
779 global $wpdb;
780
781 $tables = array_keys($this->map['tables']);
782 $unique_prefix = explode('_', $tables[0])[0];
783 $backupPrefix = $this->manifest->config->table_prefix;
784
785 $options_table = $unique_prefix . '_' . $backupPrefix . 'options';
786 if (!in_array($options_table, $tables)) {
787 $tablename = false;
788 for ($i = 0; $i < sizeof($tables); ++$i) {
789 $table = $tables[$i];
790 if (substr($table, -7) == 'options') {
791 $tablename = $table;
792 break;
793 }
794 }
795
796 $options_table = $tablename;
797 }
798
799 if ($options_table != false && in_array($options_table, $tables)) {
800
801 $sql = "DELETE FROM " . $options_table . " WHERE option_name LIKE ('%\_transient\_%')";
802 $wpdb->query($sql);
803
804 $active_plugins = $wpdb->get_results('SELECT option_value FROM `' . $options_table . '` WHERE option_name = "active_plugins"');
805 if ($active_plugins && sizeof($active_plugins) > 0) {
806 $active_plugins = $active_plugins[0]->option_value;
807 } else {
808 $active_plugins = '';
809 }
810
811 $this->seek['active_plugins'] = $active_plugins;
812
813 update_option('active_plugins', ['backup-backup/backup-backup.php']);
814
815 $ssl = is_ssl() == true ? 'https://' : 'http://';
816 $currentDomain = $ssl . $this->parseDomain(get_option('siteurl'), false);
817
818 $sql = 'UPDATE ' . $options_table . ' SET option_value = %s WHERE option_name = "siteurl"';
819 $wpdb->query($wpdb->prepare($sql, $currentDomain));
820
821 $sql = 'UPDATE ' . $options_table . ' SET option_value = %s WHERE option_name = "home"';
822 $wpdb->query($wpdb->prepare($sql, $currentDomain));
823
824 }
825
826 }
827
828 private function filterFile($path, $name) {
829
830 $blacklist = $this->unwantedTables;
831 $tablename = strtolower(substr($name, 0, -4));
832
833 $shouldBeExcluded = false;
834 for ($i = 0; $i < sizeof($blacklist); ++$i) {
835
836 $rule = strtolower($blacklist[$i]);
837 if (substr($tablename, -(strlen($rule))) == $rule) {
838 $shouldBeExcluded = true;
839 break;
840 }
841
842 }
843
844 if ($shouldBeExcluded == true) {
845
846 $str = '';
847 $str .= "/" . "* QUERY START */\n";
848 $str .= "SET foreign_key_checks = 0;\n";
849 $str .= "/" . "* QUERY END */\n";
850 $str .= "\n";
851 $str .= "/" . "* QUERY START */\n";
852 $str .= "SET SQL_MODE = '';\n";
853 $str .= "/" . "* QUERY END */\n";
854 $str .= "\n";
855 $str .= "/" . "* QUERY START */\n";
856 $str .= "SET time_zone = '+00:00';\n";
857 $str .= "/" . "* QUERY END */\n";
858 $str .= "\n";
859 $str .= "/" . "* QUERY START */\n";
860 $str .= "SET NAMES 'utf8';\n";
861 $str .= "/" . "* QUERY END */\n";
862 $str .= "\n";
863
864 $file = new \SplFileObject($path);
865 $file->seek($file->getSize());
866 $total_lines = $file->key() + 1;
867
868 $query_has_not_ended = true;
869 for ($i = 16; $query_has_not_ended && $i < $total_lines; ++$i) {
870 $file->seek($i);
871 $line = trim($file->current());
872
873 if ($line == "/" . "* QUERY END */") {
874
875 $str .= $line;
876 $query_has_not_ended = false;
877 break;
878
879 } else {
880
881 $str .= $line . "\n";
882
883 }
884 }
885
886 if ($query_has_not_ended === false) {
887
888 $this->logger->log(str_replace('%s', substr($name, 0, -4), __('Cleaning up contents of %s table.', 'backup-backup')), 'INFO');
889 file_put_contents($path, $str);
890
891 }
892
893 }
894
895 }
896
897 private function getNextFile() {
898
899 if ($this->seek['last_file'] == '...') {
900
901 $nextFile = false;
902
903 $sqlFiles = array_diff(scandir($this->storage), ['..', '.']);
904 $sqlFiles = array_values($sqlFiles);
905
906 if (sizeof($sqlFiles) > 0) {
907 $nextFilePath = $this->storage . DIRECTORY_SEPARATOR . $sqlFiles[0];
908 return $nextFilePath;
909 }
910
911 $this->seek['last_file'] = $nextFile;
912 return $nextFile;
913
914 } else {
915
916 return $this->seek['last_file'];
917
918 }
919
920 }
921
922 private function initMessage() {
923
924 $this->logger->log(__('Successfully detected backup created with v2 engine, importing...', 'backup-backup'), 'INFO');
925 $this->logger->log(__('Restoring database (using v3 engine)...', 'backup-backup'), 'STEP');
926
927 if (file_exists($this->tablemap)) {
928 @unlink($this->tablemap);
929 }
930
931 }
932
933 }
934