PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.1.7
Backup Migration v2.1.7
2.1.7 2.1.6 2.1.5.2 trunk 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.6.1 1.4.7 1.4.8 1.4.9 1.4.9.1 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.5.1
backup-backup / includes / database / even-better-restore-v3.php
backup-backup / includes / database Last commit date
export 3 weeks ago better-backup-v3.php 3 weeks ago better-backup.php 3 weeks ago better-restore.php 3 weeks ago even-better-restore-v3.php 3 weeks ago even-better-restore-v4.php 3 weeks ago interface-search-replace-repository.php 3 weeks ago manager.php 3 weeks ago search-replace-processor.php 3 weeks ago search-replace-repository.php 3 weeks ago search-replace-stack-based.php 3 weeks ago search-replace-v2.php 3 weeks ago search-replace.php 3 weeks ago smart-sort.php 3 weeks ago
even-better-restore-v3.php
940 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 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
169 $wpdb->query("DROP TABLE IF EXISTS " . BMP::escapeSQLIDentifier($tableName) . ";");
170
171 $str = __("Started restoration of %table_name% %total_tables% table", 'backup-backup');
172 $str = str_replace('%table_name%', $realTableName, $str);
173 $str = str_replace('%total_tables%', $this->getTableProgress(), $str);
174 $this->logger->log($str, 'STEP');
175
176 // Check if file can be cleaned
177 $this->filterFile($filePath, basename($filePath));
178 }
179
180 $qs = "/* QUERY START */\n";
181 $qe = "/* QUERY END */\n";
182
183 $vs = "/* VALUES START */\n";
184 $ve = "/* VALUES END */\n";
185
186 $wpdb->suppress_errors();
187
188 $wpdb->query('SET autocommit = 0;');
189 $wpdb->query('SET foreign_key_checks = 0;');
190 $wpdb->query("SET SQL_MODE = '';");
191 $wpdb->query('START TRANSACTION;');
192
193 $sqlStarted = false;
194
195 $sql = '';
196 while (!$objFile->eof()) {
197 $objFile->seek($seek); $seek++;
198
199 if ($objFile->current() == $qs) { $sqlStarted = true; continue; }
200 else if ($objFile->current() == $vs || $objFile->current() == $ve) {
201 continue;
202 } else if ($objFile->current() == $qe) {
203 $sqlStarted = false;
204 break;
205 }
206
207 if ($sqlStarted == true) $sql .= rtrim($objFile->current(), "\n");
208 }
209
210 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared –– $sql is assumed to be safe here
211 $wpdb->query($sql); unset($sql);
212 $wpdb->query('COMMIT;');
213 $wpdb->query('SET autocommit = 1;');
214 $wpdb->query('SET foreign_key_checks = 1;');
215
216 $str = __("Progress of %table_name%: %progress%", 'backup-backup');
217 $str = str_replace('%table_name%', $realTableName, $str);
218
219 $objFile->seek($objFile->getSize());
220 $total_size = $objFile->key();
221 $objFile->seek($seek);
222
223 $progress = ($seek - 1) . '/' . $total_size . " (" . number_format(($seek - 1) / $total_size * 100, 2) . "%)";
224 $str = str_replace('%progress%', $progress, $str);
225 $this->logger->log($str, 'INFO');
226
227 $wpdb->show_errors();
228
229 if ($objFile->eof()) {
230 return true;
231 } else {
232 return false;
233 }
234
235 }
236
237 private function addNewTableToMap($from, $to, $file) {
238
239 if (!array_key_exists($from, $this->map['tables'])) {
240 $this->map['tables'][$from] = $to;
241 }
242
243 file_put_contents($this->tablemap, json_encode($this->map));
244
245 }
246
247 private function processFile($file) {
248
249 if ($this->seek['last_seek'] == 0) {
250 $this->seek['last_start'] = microtime(true);
251 }
252
253 $objFile = new \SplFileObject($file);
254
255 $objFile->seek(17);
256 $realTableName = explode('`', $objFile->current())[1];
257
258 $objFile->seek(18);
259 $tmpTableName = explode('`', $objFile->current())[1];
260
261 $finished = $this->queryFile($objFile, $file, $tmpTableName, $realTableName);
262
263 if ($finished && file_exists($file)) {
264 $this->seek['last_seek'] = 0;
265 $this->seek['last_file'] = '...';
266 @unlink($file);
267
268 $totalTime = microtime(true) - intval($this->seek['last_start']);
269 $totalTime = number_format($totalTime, 5);
270
271 $str = __("Table %table_name% restoration took %time% seconds", 'backup-backup');
272 $str = str_replace('%table_name%', $realTableName, $str);
273 $str = str_replace('%time%', $totalTime, $str);
274
275 $this->logger->log($str, 'SUCCESS');
276 $this->seek['last_start'] = 0;
277 }
278
279 $this->addNewTableToMap($tmpTableName, $realTableName, $file);
280
281 return true;
282
283 }
284
285 private function parseDomain($domain, $removeWWW = true) {
286
287 if (substr($domain, 0, 8) == 'https://') $domain = substr($domain, 8);
288 if (substr($domain, 0, 7) == 'http://') $domain = substr($domain, 7);
289 if ($removeWWW === true) {
290 if (substr($domain, 0, 4) == 'www.') $domain = substr($domain, 4);
291 }
292 $domain = untrailingslashit($domain);
293
294 return $domain;
295
296 }
297
298 private function replaceTableNames($tables) {
299
300 global $wpdb;
301
302 $this->logger->log(__('Performing table replacement', 'backup-backup'), 'STEP');
303
304 $wpdb->suppress_errors();
305 foreach ($tables as $oldTable => $newTable) {
306
307 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
308 $wpdb->query("DROP TABLE IF EXISTS " . BMP::escapeSQLIDentifier($newTable) . ";");
309
310 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
311 $wpdb->query("ALTER TABLE " . BMP::escapeSQLIDentifier($oldTable) . " RENAME TO " . BMP::escapeSQLIDentifier($newTable) . ";");
312
313 $str = __('Table %old% renamed to %new%', 'backup-backup');
314 $str = str_replace('%old%', $oldTable, $str);
315 $str = str_replace('%new%', $newTable, $str);
316 $this->logger->log($str, 'INFO');
317
318 }
319
320 $wpdb->show_errors();
321 $this->logger->log(__('All tables replaced', 'backup-backup'), 'SUCCESS');
322
323 }
324
325 private function performReplace($step = 0, $tableIndex = 0, $currentPage = 0, $totalPages = 0, $fieldAdjustments = 0, $newPrefix = "wp_") {
326
327 $status = [
328 'step' => $step,
329 'tableIndex' => $tableIndex,
330 'finished' => false,
331 'currentPage' => $currentPage,
332 'totalPages' => $totalPages,
333 'fieldAdjustments' => $fieldAdjustments
334 ];
335
336 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'search-replace.php';
337
338 $backupRootDir = $this->manifest->config->ABSPATH;
339 $currentRootDir = ABSPATH;
340
341 $backupDomain = $this->parseDomain($this->manifest->dbdomain);
342 $currentDomain = $this->parseDomain(get_option('siteurl'), false);
343
344 $currentTable = false;
345 $allTables = array_keys($this->map['tables']);
346
347 if ($tableIndex < sizeof($allTables) && array_key_exists($tableIndex, $allTables)) {
348 $currentTable = $allTables[$tableIndex];
349 }
350
351 if ($currentTable == false && !$currentTable) {
352 if ($backupRootDir != $currentRootDir || $currentDomain != $this->parseDomain($backupDomain, false)) {
353 $this->logger->log(__('Search & Replace finished successfully.', 'backup-backup'), 'SUCCESS');
354 }
355
356 $status['finished'] = true;
357 return $status;
358 }
359
360 if (strpos($currentTable, $newPrefix) === false) {
361 $this->logger->log(__('Adjustments are not required for this table.', 'backup-backup') . "(" . sanitize_text_field(strval($currentTable)) . ")", 'INFO');
362
363 $status['step'] = 1;
364 $status['fieldAdjustments'] = 0;
365 $status['tableIndex'] = $tableIndex + 1;
366 return $status;
367 }
368
369 $replaceEngine = new BMISearchReplace([$currentTable], $currentPage, $totalPages);
370
371 if ($step == 0) {
372 if ($backupRootDir != $currentRootDir || $currentDomain != $this->parseDomain($backupDomain, false)) {
373 $this->logger->log(__('Performing Search & Replace', 'backup-backup'), 'STEP');
374 $pagesize = '?';
375 if (defined('BMI_MAX_SEARCH_REPLACE_PAGE')) $pagesize = BMI_MAX_SEARCH_REPLACE_PAGE;
376 $this->logger->log(__('Page size for that restoration: ', 'backup-backup') . $pagesize, 'INFO');
377 $status['step'] = $step + 1; $step++;
378 } else {
379 $this->logger->log(__('This backup was made on the same site, ommiting search & replace.', 'backup-backup'), 'INFO');
380 $status['finished'] = true;
381 return $status;
382 }
383 }
384
385 if ($step == 1) {
386 $replaceProgress = ($tableIndex + 1) . "/" . sizeof($allTables);
387 $replaceProgressPercentage = number_format((($tableIndex + 1) / sizeof($allTables) * 100), 2);
388 $progressLogT = __('Performing database adjustments for table %progress%: %table_name% (%progress_percentage%)', 'backup-backup');
389 $progressLogT = str_replace('%progress%', $replaceProgress, $progressLogT);
390 $progressLogT = str_replace('%table_name%', $currentTable, $progressLogT);
391 $progressLogT = str_replace('%progress_percentage%', $replaceProgressPercentage . '%', $progressLogT);
392 $this->logger->log($progressLogT, 'STEP');
393
394 $percentageProgress = number_format($replaceProgressPercentage, 0);
395 $this->logger->progress(number_format(90 + ($percentageProgress / 100) * 8, 0));
396
397 if ($backupRootDir != $currentRootDir) {
398
399 $dtables = 0; $drows = 0; $dchange = 0; $dupdates = 0;
400
401 $r = $replaceEngine->perform($backupRootDir, $currentRootDir);
402 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
403
404 $status['currentPage'] = $r['currentPage'];
405 $status['totalPages'] = $r['totalPages'];
406
407 if ($status['totalPages'] > 0) {
408
409 $info = __("Batch for path adjustment (%page%/%allPages%) updated: %updates% fields.", 'backup-backup');
410 $updates = $dupdates;
411 if ($updates == 0) $updates = 1;
412 $info = str_replace('%page%', $status['currentPage'], $info);
413 $info = str_replace('%allPages%', $status['totalPages'], $info);
414 $info = str_replace('%updates%', $updates, $info);
415 $this->logger->log($info, 'INFO');
416 $status['fieldAdjustments']++;
417
418 } else {
419
420 // $this->logger->log(__('Path adjustments are not required for this table.', 'backup-backup'), 'INFO');
421
422 }
423
424 if ($status['currentPage'] >= $status['totalPages']) {
425 $status['currentPage'] = 0;
426 $status['totalPages'] = 0;
427 $status['step'] = $step + 1;
428 }
429 return $status;
430
431 } else {
432
433 $status['step'] = $step + 1; $step++;
434
435 }
436 }
437
438 if ($step == 2 || $step == 3 || $step == 4 || $step == 5 || $step == 6 || $step == 7) {
439 if ($currentDomain != $this->parseDomain($backupDomain, false)) {
440 $ssl = is_ssl() == true ? 'https://' : 'http://';
441
442 $dtables = 0; $drows = 0; $dchange = 0; $dupdates = 0;
443
444 $possibleDomainsBackup = [
445 "https://www." . $backupDomain,
446 "http://www." . $backupDomain,
447 "https://" . $backupDomain,
448 "http://" . $backupDomain,
449 'www.' . $backupDomain,
450 $backupDomain
451 ];
452
453 $possibleDomainsCurrent = [
454 $ssl . $currentDomain,
455 $ssl . $currentDomain,
456 $ssl . $currentDomain,
457 $ssl . $currentDomain,
458 $currentDomain,
459 $currentDomain
460 ];
461
462 if ($step == 2) {
463 $r = $replaceEngine->perform($possibleDomainsBackup[0], $possibleDomainsCurrent[0]);
464 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
465 }
466
467 if ($step == 3) {
468 $r = $replaceEngine->perform($possibleDomainsBackup[1], $possibleDomainsCurrent[1]);
469 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
470 }
471
472 if ($step == 4) {
473 $r = $replaceEngine->perform($possibleDomainsBackup[2], $possibleDomainsCurrent[2]);
474 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
475 }
476
477 if ($step == 5) {
478 $r = $replaceEngine->perform($possibleDomainsBackup[3], $possibleDomainsCurrent[3]);
479 $dtables += $r['tables']; $drows += $r['rows']; $dchange += $r['change']; $dupdates += $r['updates'];
480 }
481
482 if ($step == 6) {
483 $r = $replaceEngine->perform($possibleDomainsBackup[4], $possibleDomainsCurrent[4]);
484 $dchange += $r['change']; $dupdates += $r['updates'];
485 }
486
487 if ($step == 7) {
488 if (!(substr($currentDomain, -strlen($backupDomain)) === $backupDomain)) {
489 $r = $replaceEngine->perform($possibleDomainsBackup[5], $possibleDomainsCurrent[5]);
490 $dchange += $r['change']; $dupdates += $r['updates'];
491 }
492 }
493
494 $status['currentPage'] = $r['currentPage'];
495 $status['totalPages'] = $r['totalPages'];
496
497 $variants = [
498 __('variant A', 'backup-backup'),
499 __('variant B', 'backup-backup'),
500 __('variant C', 'backup-backup'),
501 __('variant D', 'backup-backup'),
502 __('variant E', 'backup-backup'),
503 __('variant F', 'backup-backup')
504 ];
505
506 if ($status['totalPages'] > 0) {
507
508 $info = __("Batch for domain (%variant%) adjustments (%page%/%allPages%) updated: %updates% fields.", 'backup-backup');
509 $updates = $dupdates;
510 if ($updates == 0) $updates = 1;
511 $info = str_replace('%variant%', $variants[$step - 2], $info);
512 $info = str_replace('%page%', $status['currentPage'], $info);
513 $info = str_replace('%allPages%', $status['totalPages'], $info);
514 $info = str_replace('%updates%', $updates, $info);
515 $this->logger->log($info, 'INFO');
516 $status['fieldAdjustments']++;
517
518 } else {
519
520 // $info = __('Domain (%variant%) adjustments are not required for this table.', 'backup-backup');
521 // $info = str_replace('%variant%', $variants[$step - 2], $info);
522 // $this->logger->log($info, 'INFO');
523
524 }
525
526 if ($status['currentPage'] >= $status['totalPages']) {
527 $status['currentPage'] = 0;
528 $status['totalPages'] = 0;
529 $status['step'] = $step + 1;
530 }
531 return $status;
532 }
533 }
534
535 if ($step == 8) {
536 if ($fieldAdjustments === 0) {
537 $this->logger->log(__('Adjustments are not required for this table.', 'backup-backup'), 'INFO');
538 }
539
540 $status['step'] = 1;
541 $status['fieldAdjustments'] = 0;
542 $status['tableIndex'] = $tableIndex + 1;
543 return $status;
544 }
545
546 return $status;
547
548 }
549
550 public function is_valid_plugin($plugin) {
551
552 global $wp_version;
553
554 $default_headers = array( 'wp' => 'Requires at least', 'php' => 'Requires PHP' );
555
556 $wp = false;
557 $php = false;
558
559 $detectedwp = '0.0.0';
560 $detectedphp = '0.0.0';
561
562 try {
563
564 $plugin_file = BMP::fixSlashes(WP_PLUGIN_DIR . '/' . $plugin);
565 $plugin_readme = BMP::fixSlashes(WP_PLUGIN_DIR . '/' . dirname($plugin) . '/readme.txt');
566 if (!file_exists($plugin_readme)) $plugin_readme = BMP::fixSlashes(WP_PLUGIN_DIR . '/' . dirname($plugin) . '/README.txt');
567
568 if (file_exists($plugin_file)) {
569 $plugin_data = get_file_data($plugin_file, $default_headers, 'plugin');
570 if (!empty($plugin_data['wp']) && version_compare($plugin_data['wp'], $wp_version, '<=')) {
571 $detectedwp = $plugin_data['wp'];
572 $wp = true;
573 }
574 if (!empty($plugin_data['php']) && version_compare($plugin_data['php'], PHP_VERSION, '<=')) {
575 $detectedphp = $plugin_data['php'];
576 $php = true;
577 }
578 }
579
580 if (file_exists($plugin_readme)) {
581 $readme_data = get_file_data($plugin_readme, $default_headers, 'plugin');
582 if (!empty($readme_data['wp']) && version_compare($readme_data['wp'], $wp_version, '<=')) {
583 $detectedwp = $readme_data['wp'];
584 $wp = true;
585 }
586
587 if (!empty($readme_data['php']) && version_compare($readme_data['php'], PHP_VERSION, '<=')) {
588 $detectedphp = $readme_data['php'];
589 $php = true;
590 }
591 }
592
593 $this->logger->log(sprintf('Detected version WP/PHP for plugin: %s, is (%s/%s)', $plugin, $detectedwp, $detectedphp), 'VERBOSE');
594
595 if ($plugin == 'hello.php') return true;
596 if ($php && $wp) return true;
597 else return false;
598
599 } catch (Error $e) {
600 return false;
601 }
602
603 return false;
604
605 }
606
607 private function try_activate_plugins($plugins, $sucstr_source, $failstr_source, $failed_plugins = []) {
608
609 $plugins_copy = array_values($plugins);
610 $should_continue = false;
611 $activated_plugins = [];
612 $failed_plugins = $failed_plugins;
613 $disallowed_plugins = [
614 'bluehost-wordpress-plugin/bluehost-wordpress-plugin.php',
615 'sg-cachepress/sg-cachepress.php',
616 'wordpress-starter/siteground-wizard.php',
617 'revslider/revslider.php',
618 'easy-soundcloud-shortcode/easy-soundcloud-shortcode.php',
619 'easy-soundcloud-shortcode/EasySoundcloudShortcode.php'
620 ];
621
622 for ($i = 0; $i < sizeof($plugins_copy); ++$i) {
623
624 $plugin_name = $plugins_copy[$i];
625 $plugin_display = $plugin_name;
626
627 $shouldActivate = true;
628
629 if (empty($plugin_name)) {
630 $shouldActivate = false;
631 $plugin_display = '(---)';
632 } else if ($plugin_name == 'hello.php') {
633 $shouldActivate = true;
634 } else if (strpos($plugin_name, '/') === false) {
635 $shouldActivate = false;
636 }
637
638 $sucstr = str_replace('%plugin_name%', $plugin_display, $sucstr_source);
639 $failstr = str_replace('%plugin_name%', $plugin_display, $failstr_source);
640
641 if ($shouldActivate) {
642 try {
643
644 if ($this->is_valid_plugin($plugin_name) && !in_array($plugin_name, $disallowed_plugins)) {
645
646 $resultWP = activate_plugin($plugin_name, '', true, true);
647
648 $this->logger->log($sucstr, 'INFO');
649 $activated_plugins[] = $plugin_name;
650
651 $should_continue = true;
652 break;
653
654 } else {
655
656 if (!in_array($plugin_name, $failed_plugins)) {
657 $failed_plugins[] = $plugin_name;
658 }
659
660 }
661
662 } catch (\Exception $e) {
663
664 if (!in_array($plugin_name, $failed_plugins)) {
665
666 $failed_plugins[] = $plugin_name;
667 error_log(strval($e));
668
669 }
670
671 } catch (\Throwable $e) {
672
673 if (!in_array($plugin_name, $failed_plugins)) {
674
675 $msg = $e->getMessage();
676 if (strpos($msg, 'add_rule()') != false || strpos($msg, 'rewrite.php:143') != false) {
677
678 $activated_plugins[] = $plugin_name;
679 error_log(strval($e));
680
681 } else {
682
683 $failed_plugins[] = $plugin_name;
684 error_log(strval($e));
685
686 }
687
688 }
689
690 }
691
692 } else {
693
694 $this->logger->log($failstr, 'WARN');
695
696 }
697
698 }
699
700 return [ 'failed' => $failed_plugins, 'active' => $activated_plugins, 'should_continue' => $should_continue ];
701
702 }
703
704 public function enablePlugins() {
705
706 global $wpdb;
707
708 $this->logger->log(__('Enabling plugins included in the backup', 'backup-backup'), 'STEP');
709
710 if (is_serialized($this->seek['active_plugins'])) {
711
712 $plugins = unserialize($this->seek['active_plugins']);
713 usort($plugins, function ($a, $b) { return strlen($a) - strlen($b); });
714 $plugins = array_values($plugins);
715
716 $sucstr_source = __('Plugin %plugin_name% enabled successfully.', 'backup-backup');
717 $failstr_source = __('Failed to enable plugin %plugin_name%, trying to not end at fatal error...', 'backup-backup');
718
719 $fullyActive = [];
720 $failed_plugins = [];
721
722 if (!function_exists('activate_plugin')) {
723 require_once(ABSPATH .'/wp-admin/includes/plugin.php');
724 }
725
726 $one_more_time = true;
727 $try_again = true;
728 while ($try_again) {
729
730 $res = $this->try_activate_plugins($plugins, $sucstr_source, $failstr_source, $failed_plugins);
731
732 $fullyActive = array_unique(array_merge($fullyActive, $res['active']));
733 $plugins = array_diff($plugins, $res['active']);
734 $failed_plugins = array_unique(array_diff(array_merge($failed_plugins, $res['failed']), $fullyActive));
735
736 $try_again = $res['should_continue'];
737 if ($try_again == false && $one_more_time == true) {
738 $one_more_time = false;
739 $try_again = true;
740 }
741
742 }
743
744 for ($i = 0; $i < sizeof($failed_plugins); ++$i) {
745
746 $failstr = str_replace('%plugin_name%', $failed_plugins[$i], $failstr_source);
747 $this->logger->log($failstr, 'WARN');
748
749 }
750
751 if (!in_array('backup-backup/backup-backup.php', $fullyActive)) {
752 $fullyActive[] = 'backup-backup/backup-backup.php';
753 }
754
755 update_option('active_plugins', $fullyActive);
756
757 }
758
759 $this->logger->progress(100);
760 $this->logger->log(__('All plugins enabled, you are ready to go :)', 'backup-backup'), 'SUCCESS');
761
762 }
763
764 public function searchReplace($step = 0, $tableIndex = 0, $currentPage = 0, $totalPages = 0, $fieldAdjustments = 0, $newPrefix = 'wp_') {
765
766 $this->logger->progress(90);
767 return $this->performReplace($step, $tableIndex, $currentPage, $totalPages, $fieldAdjustments, $newPrefix);
768
769 }
770
771 public function alter_tables() {
772
773 $this->logger->progress(98);
774 $this->prepareFinalDatabase();
775 $this->replaceTableNames($this->map['tables']);
776
777 }
778
779 private function prepareFinalDatabase() {
780
781 global $wpdb;
782
783 $tables = array_keys($this->map['tables']);
784 $unique_prefix = explode('_', $tables[0])[0];
785 $backupPrefix = $this->manifest->config->table_prefix;
786
787 $options_table = $unique_prefix . '_' . $backupPrefix . 'options';
788 if (!in_array($options_table, $tables)) {
789 $tablename = false;
790 for ($i = 0; $i < sizeof($tables); ++$i) {
791 $table = $tables[$i];
792 if (substr($table, -7) == 'options') {
793 $tablename = $table;
794 break;
795 }
796 }
797
798 $options_table = $tablename;
799 }
800
801 if ($options_table != false && in_array($options_table, $tables)) {
802
803 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
804 $wpdb->query($wpdb->prepare("
805 DELETE FROM " . BMP::escapeSQLIDentifier($options_table) . " WHERE option_name LIKE (%s)
806 ", '%\_transient\_%'
807 ));
808
809 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
810 $active_plugins = $wpdb->get_results($wpdb->prepare('SELECT option_value FROM ' . BMP::escapeSQLIDentifier($options_table) . ' WHERE option_name = %s', 'active_plugins'));
811 if ($active_plugins && sizeof($active_plugins) > 0) {
812 $active_plugins = $active_plugins[0]->option_value;
813 } else {
814 $active_plugins = '';
815 }
816
817 $this->seek['active_plugins'] = $active_plugins;
818
819 update_option('active_plugins', ['backup-backup/backup-backup.php']);
820
821 $ssl = is_ssl() == true ? 'https://' : 'http://';
822 $currentDomain = $ssl . $this->parseDomain(get_option('siteurl'), false);
823
824 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
825 $wpdb->query($wpdb->prepare('UPDATE ' . BMP::escapeSQLIDentifier($options_table) . ' SET option_value = %s WHERE option_name = "siteurl"', $currentDomain));
826
827 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
828 $wpdb->query($wpdb->prepare('UPDATE ' . BMP::escapeSQLIDentifier($options_table) . ' SET option_value = %s WHERE option_name = "home"', $currentDomain));
829
830 }
831
832 }
833
834 private function filterFile($path, $name) {
835
836 $blacklist = $this->unwantedTables;
837 $tablename = strtolower(substr($name, 0, -4));
838
839 $shouldBeExcluded = false;
840 for ($i = 0; $i < sizeof($blacklist); ++$i) {
841
842 $rule = strtolower($blacklist[$i]);
843 if (substr($tablename, -(strlen($rule))) == $rule) {
844 $shouldBeExcluded = true;
845 break;
846 }
847
848 }
849
850 if ($shouldBeExcluded == true) {
851
852 $str = '';
853 $str .= "/" . "* QUERY START */\n";
854 $str .= "SET foreign_key_checks = 0;\n";
855 $str .= "/" . "* QUERY END */\n";
856 $str .= "\n";
857 $str .= "/" . "* QUERY START */\n";
858 $str .= "SET SQL_MODE = '';\n";
859 $str .= "/" . "* QUERY END */\n";
860 $str .= "\n";
861 $str .= "/" . "* QUERY START */\n";
862 $str .= "SET time_zone = '+00:00';\n";
863 $str .= "/" . "* QUERY END */\n";
864 $str .= "\n";
865 $str .= "/" . "* QUERY START */\n";
866 $str .= "SET NAMES 'utf8';\n";
867 $str .= "/" . "* QUERY END */\n";
868 $str .= "\n";
869
870 $file = new \SplFileObject($path);
871 $file->seek($file->getSize());
872 $total_lines = $file->key() + 1;
873
874 $query_has_not_ended = true;
875 for ($i = 16; $query_has_not_ended && $i < $total_lines; ++$i) {
876 $file->seek($i);
877 $line = trim($file->current());
878
879 if ($line == "/" . "* QUERY END */") {
880
881 $str .= $line;
882 $query_has_not_ended = false;
883 break;
884
885 } else {
886
887 $str .= $line . "\n";
888
889 }
890 }
891
892 if ($query_has_not_ended === false) {
893
894 $this->logger->log(str_replace('%s', substr($name, 0, -4), __('Cleaning up contents of %s table.', 'backup-backup')), 'INFO');
895 file_put_contents($path, $str);
896
897 }
898
899 }
900
901 }
902
903 private function getNextFile() {
904
905 if ($this->seek['last_file'] == '...') {
906
907 $nextFile = false;
908
909 $sqlFiles = array_diff(scandir($this->storage), ['..', '.']);
910 $sqlFiles = array_values($sqlFiles);
911
912 if (sizeof($sqlFiles) > 0) {
913 $nextFilePath = $this->storage . DIRECTORY_SEPARATOR . $sqlFiles[0];
914 return $nextFilePath;
915 }
916
917 $this->seek['last_file'] = $nextFile;
918 return $nextFile;
919
920 } else {
921
922 return $this->seek['last_file'];
923
924 }
925
926 }
927
928 private function initMessage() {
929
930 $this->logger->log(__('Successfully detected backup created with v2 engine, importing...', 'backup-backup'), 'INFO');
931 $this->logger->log(__('Restoring database (using v3 engine)...', 'backup-backup'), 'STEP');
932
933 if (file_exists($this->tablemap)) {
934 @unlink($this->tablemap);
935 }
936
937 }
938
939 }
940