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 / staging / controller.php
backup-backup / includes / staging Last commit date
controller.php 3 months ago local.php 3 months ago tastewp.php 3 months ago
controller.php
834 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin\Staging;
5
6 // Use
7 use BMI\Plugin\BMI_Logger as Logger;
8 use BMI\Plugin\Backup_Migration_Plugin as BMP;
9 use BMI\Plugin\Progress\BMI_StagingProgress as StagingProgress;
10
11 // Exit on direct access
12 if (!defined('ABSPATH')) exit;
13
14 // Require logger
15 require_once BMI_INCLUDES . '/progress/staging.php';
16
17 /**
18 * Main File of Staging Controller
19 */
20 class BMI_Staging {
21
22 public $continue = false;
23 public $continuationData = [];
24 public $tastewpURL = 'https://tastewp.com';
25 protected $name = false;
26 protected $logger = false;
27 protected $config = [];
28 protected $siteConfig = [];
29 protected $siteConfigPath = false;
30 protected $wasError = false;
31 protected $wasErrorMsg = 'No error message...';
32 protected $isRemoved = false;
33 protected $configPath = BMI_STAGING . DIRECTORY_SEPARATOR . 'configuration.php';
34
35 public function __construct($name, $initialize = false) {
36
37 if ($name == '..ajax..') return;
38
39 // Set name of staging site
40 $this->name = strval($name);
41
42 // Initialize staging site logger
43 $this->logger = new StagingProgress(!$initialize);
44 $this->logger->start();
45
46 // Load configuration
47 $this->loadConfig();
48
49 // If it's initial request add intro logs and set progress to 0
50 if ($initialize) {
51 $this->log(__('Preparing creation of staging site...', 'backup-backup'), 'STEP');
52 $this->log(__('Starting custom error handler...', 'backup-backup'));
53 $this->progress('0');
54 }
55
56 $this->errorHandler();
57 $this->exceptionHandler();
58
59 }
60
61 protected function httpRequest($url, &$data, $method = 'POST', $headers = []) {
62
63 // URL & Body data
64 $baseurl = home_url();
65 if (substr($baseurl, 0, 4) != 'http') {
66 if (is_ssl()) $baseurl = 'https://' . home_url();
67 else $baseurl = 'http://' . home_url();
68 }
69
70 // Add base URL to data
71 if ($method != 'PUT') {
72 $data['baseurl'] = $baseurl;
73 } else {
74 $headers['x-baseurl'] = $baseurl;
75 }
76
77 // Get disabled functions to check if CURL can be used
78 $disabled_functions = explode(',', ini_get('disable_functions'));
79 $vA = !in_array('curl_exec', $disabled_functions);
80 $vB = !in_array('curl_init', $disabled_functions);
81
82 if (function_exists('curl_version') && function_exists('curl_exec') && function_exists('curl_init') && $vA && $vB) {
83
84 // Make request
85 $response = wp_remote_post($url, [
86 'method' => $method,
87 'httpversion' => '1.0',
88 'blocking' => true,
89 'timeout' => 25,
90 'sslverify' => false,
91 'headers' => $headers,
92 'body' => $data
93 ]);
94
95 } else {
96
97 return ['status' => 'error', 'message' => 'Library missing. CURL is required for this feature to work, please add cURL extension to your PHP.'];
98
99 }
100
101 // Validate response
102 if (!(is_array($response) && isset($response['body']) && is_string($response['body']))) {
103
104 // Faile if wrong response
105 return ['status' => 'error', 'message' => 'Server response empty, or timed out, please try again.'];
106
107 } else {
108
109 // Return data
110 $response['body'] = substr($response['body'], strpos($response['body'], '{'));
111 $json = json_decode($response['body'], true);
112
113 return $json;
114
115 }
116
117 }
118
119 public function getStagingSites($localOnly = false) {
120
121 if (!file_exists($this->configPath)) return [];
122 $config = file_get_contents($this->configPath);
123 $config = trim(substr($config, 8));
124
125 if (is_serialized($config)) $config = maybe_unserialize($config);
126 else return [];
127
128 $tasteWPSites = [];
129 $parsedSites = [];
130 foreach ($config as $name => $data) {
131 $this->name = strval($name);
132 $this->loadConfig();
133
134 if (!isset($this->siteConfig['name'])) continue;
135 if (isset($this->siteConfig['expiration_time']) && $this->siteConfig['expiration_time'] != 'never' && !is_nan(intval($this->siteConfig['expiration_time']))) {
136 if ($this->siteConfig['expiration_time'] != 'Never' && intval($this->siteConfig['expiration_time']) < time()) {
137 $this->deleteRelatedConfigs();
138 continue;
139 }
140 }
141
142 // Exclude TasteWP Sites if only local should be returned
143 if ($localOnly === true) {
144 if ($this->siteConfig['communication_secret'] != 'local' && isset($this->siteConfig['entry'])) {
145 continue;
146 }
147 }
148
149 $parsedSites[$this->name] = [];
150 $parsedSites[$this->name]['name'] = $this->siteConfig['name'];
151 $parsedSites[$this->name]['url'] = $this->siteConfig['url'];
152 $parsedSites[$this->name]['db_prefix'] = $this->siteConfig['db_prefix'];
153 $parsedSites[$this->name]['total_files'] = $this->siteConfig['total_files'];
154 $parsedSites[$this->name]['communication_secret'] = $this->siteConfig['communication_secret'];
155 $parsedSites[$this->name]['expiration_time'] = __('Never', 'backup-backup');
156 if (isset($this->siteConfig['expiration_time'])) {
157 $parsedSites[$this->name]['expiration_time'] = $this->siteConfig['expiration_time'];
158 }
159 $parsedSites[$this->name]['creation_date'] = date('Y-m-d H:i:s', $this->siteConfig['creation_date']);
160 $parsedSites[$this->name]['creation_date_plain'] = intval($this->siteConfig['creation_date']);
161
162 $parsedSites[$this->name]['display_name'] = $this->siteConfig['name'];
163 if (isset($this->siteConfig['display_name'])) {
164 $parsedSites[$this->name]['display_name'] = $this->siteConfig['display_name'];
165 }
166
167 if (isset($this->siteConfig['sumOfTotalSize'])) {
168 $parsedSites[$this->name]['total_size'] = BMP::humanSize($this->siteConfig['sumOfTotalSize']);
169 } else {
170 $parsedSites[$this->name]['total_size'] = '---';
171 }
172
173 if (isset($this->siteConfig['is_premium'])) {
174 $parsedSites[$this->name]['is_premium'] = $this->siteConfig['is_premium'];
175 }
176
177 if (isset($this->siteConfig['is_affiliated'])) {
178 $parsedSites[$this->name]['is_affiliated'] = $this->siteConfig['is_affiliated'];
179 }
180
181 if ($this->siteConfig['communication_secret'] != 'local' && isset($this->siteConfig['entry'])) {
182 $tasteWPSites[] = [$this->siteConfig['entry'], $this->siteConfig['communication_secret'], $this->name];
183 }
184 }
185
186 if (sizeof($tasteWPSites) > 0) {
187
188 $url = $this->tastewpURL . '/stg/details';
189 $data = [ 'entries' => $tasteWPSites ];
190 $details = $this->httpRequest($url, $data);
191
192 foreach ($details as $entry => $data) {
193
194 if (isset($data['index']) && isset($parsedSites[$data['index']])) {
195 $indexName = $data['index'];
196 $this->name = strval($data['index']);
197 $this->loadConfig();
198 $changes = false;
199
200 if (isset($data['is_deleted']) && $data['is_deleted'] == true) {
201 $this->delete($this->name, true);
202 unset($parsedSites[$this->name]);
203 continue;
204 }
205
206 if (isset($data['expiration']) && isset($this->siteConfig['expiration_time'])) {
207 if ($this->siteConfig['expiration_time'] != $data['expiration']) {
208 $this->siteConfig['expiration_time'] = $data['expiration'];
209 $parsedSites[$this->name]['expiration_time'] = $data['expiration'];
210 $changes = true;
211 }
212 }
213
214 if ((isset($data['is_premium']) && $data['is_premium'] == '1') || (isset($data['is_affiliated']) && $data['is_affiliated'] == '1')) {
215 $never = __('Never', 'backup-backup');
216 if ($this->siteConfig['expiration_time'] != $never) {
217 $this->siteConfig['expiration_time'] = $never;
218 $parsedSites[$this->name]['expiration_time'] = $never;
219 $changes = true;
220
221 if (isset($data['is_premium']) && $data['is_premium'] == '1') {
222 if (!isset($this->siteConfig['is_premium'])) {
223 $this->siteConfig['is_premium'] = '1';
224 $parsedSites[$this->name]['is_premium'] = '1';
225 $changes = true;
226 }
227 }
228
229 if (isset($data['is_affiliated']) && $data['is_affiliated'] == '1') {
230 if (!isset($this->siteConfig['is_affiliated'])) {
231 $this->siteConfig['is_affiliated'] = '1';
232 $parsedSites[$this->name]['is_affiliated'] = '1';
233 $changes = true;
234 }
235 }
236 }
237 } else if (isset($data['expiration']) && isset($this->siteConfig['expiration_time'])) {
238 if ($this->siteConfig['expiration_time'] != $data['expiration']) {
239 $this->siteConfig['expiration_time'] = $data['expiration'];
240 $parsedSites[$this->name]['expiration_time'] = $data['expiration'];
241 $changes = true;
242 }
243 }
244
245 if (isset($this->siteConfig['url']) && isset($data['domain'])) {
246 if ($this->siteConfig['url'] != $data['domain']) {
247 $this->siteConfig['url'] = $data['domain'];
248 $parsedSites[$this->name]['url'] = $data['domain'];
249 $changes = true;
250 }
251 }
252
253 if ($changes) $this->saveConfigSite();
254 }
255
256 }
257
258 }
259
260 usort($parsedSites, function ($a, $b) {
261 $timeA = intval($a['creation_date_plain']);
262 $timeB = intval($b['creation_date_plain']);
263
264 return ($timeA > $timeB) ? 1 : -1;
265 });
266
267 return $parsedSites;
268
269 }
270
271 public function rename($name, $displayName) {
272
273 $empty = __('You have to provide some staging site name before process.', 'backup-backup');
274 $toolong = __('Staging site name cannot be longer than 24 characters.', 'backup-backup');
275 $invalid = __('Provided name contains prohibited characters.', 'backup-backup');
276
277 if (strlen($displayName) <= 0) {
278 return ['status' => 'fail', 'message' => $empty];
279 }
280
281 if (!preg_match('/^[a-zA-Z0-9-_]+$/', $displayName)) {
282 return ['status' => 'fail', 'message' => $invalid];
283 }
284
285 if (strlen($displayName) >= 24) {
286 return ['status' => 'fail', 'message' => $toolong];
287 }
288
289 $this->name = strval($name);
290 $this->loadConfig();
291 $this->siteConfig['display_name'] = $displayName;
292 $this->saveConfigSite();
293
294 return ['status' => 'success' ];
295
296 }
297
298 public function prepareLogin($name) {
299
300 $this->name = strval($name);
301 $this->loadConfig();
302 $this->copyOverPasswordLessScript();
303
304 $user_id = $this->siteConfig['login_user_id'];
305 $pass = $this->siteConfig['password'];
306 $base = $this->siteConfig['url'];
307
308 $url = $base . '/wp-login.php?autologin=true&user=' . $user_id . '&secret=' . $pass;
309 return ['status' => 'success', 'url' => $url ];
310
311 }
312
313 public function deleteAllStagingFiles() {
314
315 // Won't exist for TasteWP
316 if (!isset($this->siteConfig['root_staging'])) return;
317 if (!isset($this->siteConfig['communication_secret'])) return;
318 if ($this->siteConfig['communication_secret'] != 'local') return;
319
320 $rootDirectory = untrailingslashit($this->siteConfig['root_staging']);
321 if (!(file_exists($rootDirectory) && is_dir($rootDirectory))) return;
322
323 // Do not even try to touch files under ABSPATH by any chance.... It would be disaster.
324 if ($rootDirectory == untrailingslashit(ABSPATH)) return;
325 if ($rootDirectory == ABSPATH) return;
326 if ($this->siteConfig['root_staging'] == ABSPATH) return;
327 if (trailingslashit($this->siteConfig['root_staging']) == trailingslashit(ABSPATH)) return;
328 if (BMP::fixSlashes($this->siteConfig['root_staging']) == BMP::fixSlashes(ABSPATH)) return;
329
330 $this->rrmdir($rootDirectory);
331
332 }
333
334 public function deleteRelatedDatabase() {
335
336 global $wpdb, $table_prefix;
337
338 if (!isset($this->siteConfig['db_prefix'])) return;
339 if (!isset($this->siteConfig['communication_secret'])) return;
340 if (isset($this->siteConfig['entry'])) return;
341
342 // For TasteWP websites it won't exist
343 if ($this->siteConfig['communication_secret'] != 'local') return;
344
345 $prefix = $this->siteConfig['db_prefix'];
346
347 // Hell don't even try to remove these.
348 if ($table_prefix == $prefix) return;
349 if ($table_prefix == '') return;
350 if ($prefix == '') return;
351 if (trim($table_prefix) == '') return;
352 if (trim($prefix) == '') return;
353 if ($prefix == null) return;
354 if (strlen($prefix) == 0) return;
355 if (strlen(trim($prefix)) == 0) return;
356 if (strtolower($table_prefix) == strtolower($prefix)) return;
357
358 $allTables = $wpdb->get_results('SHOW TABLES');
359 foreach ($allTables as $table) {
360 foreach ($table as $name) {
361
362 // Twice because why not.
363 if (substr($name, 0, strlen($table_prefix)) == $table_prefix) continue;
364 if (substr($name, 0, strlen($table_prefix)) == $table_prefix) continue;
365 if (strtolower(substr($name, 0, strlen($table_prefix))) == strtolower($table_prefix)) continue;
366
367 if (substr($name, 0, strlen($prefix)) == $prefix) {
368 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Identifier is safely escaped via escapeSQLIDentifier()
369 $wpdb->query("DROP TABLE " . BMP::escapeSQLIDentifier($name) . ";");
370 }
371 }
372 }
373
374 }
375
376 public function deleteFromTasteWP() {
377
378 if (isset($this->siteConfig['communication_secret']) && $this->siteConfig['communication_secret'] == 'local') return;
379 $url = $this->tastewpURL . '/stg/delete/' . $this->siteConfig['communication_secret'];
380 if (isset($this->siteConfig['entry'])) $data = [ 'entry' => $this->siteConfig['entry'] ];
381 else $data = [];
382
383 $this->httpRequest($url, $data);
384
385 }
386
387 public function deleteRelatedConfigs() {
388
389 unset($this->config[$this->name]);
390 if (file_exists($this->siteConfigPath)) {
391 @unlink($this->siteConfigPath);
392 }
393
394 $this->saveConfig();
395 $this->isRemoved = true;
396
397 }
398
399 public function delete($name, $ignoreTWP = false) {
400
401 $this->name = strval($name);
402 $this->loadConfig();
403
404 $this->deleteAllStagingFiles();
405 $this->deleteRelatedDatabase();
406 $this->deleteRelatedConfigs();
407
408 // In case of some false positive, keep the site on TasteWP.
409 if ($ignoreTWP != true) $this->deleteFromTasteWP();
410
411 return ['status' => 'success' ];
412
413 }
414
415 private function rrmdir($dir) {
416 if (is_dir($dir)) {
417 $objects = scandir($dir);
418 foreach ($objects as $object) {
419 if ($object != "." && $object != "..") {
420 if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && !is_link($dir . DIRECTORY_SEPARATOR . $object)) {
421 $this->rrmdir($dir . DIRECTORY_SEPARATOR . $object);
422 } else {
423 @unlink($dir . DIRECTORY_SEPARATOR . $object);
424 }
425 }
426 }
427 @rmdir($dir);
428 } else {
429 if (file_exists($dir) && is_file($dir)) {
430 @unlink($dir);
431 }
432 }
433 }
434
435 protected function copyOverPasswordLessScript($quiet = false) {
436
437 if (!$quiet) $this->log(__('Inserting auto-login script for staging site', 'backup-backup'), 'STEP');
438
439 $this->siteConfig['login_user_id'] = get_current_user_id();
440 $this->siteConfig['password'] = $this->getRandomPassword();
441 $this->saveConfigSite();
442
443 $pathToScript = BMI_INCLUDES . DIRECTORY_SEPARATOR . 'htaccess' . DIRECTORY_SEPARATOR . '.autologin.php';
444
445 $mudirPath = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'mu-plugins';
446 if (defined('WPMU_PLUGIN_DIR')) $mudirPath = WPMU_PLUGIN_DIR;
447
448 $sourceABSPATH = untrailingslashit($this->siteConfig['root_source']);
449 $destinationABSPATH = untrailingslashit($this->siteConfig['root_staging']);
450 $pathToDestination = str_replace($sourceABSPATH, $destinationABSPATH, $mudirPath);
451 $pathToDestination = untrailingslashit($pathToDestination) . DIRECTORY_SEPARATOR . 'bmi-autologin.php';
452
453 if (!(file_exists(dirname($pathToDestination)) && is_dir(dirname($pathToDestination)))) {
454 @mkdir(dirname($pathToDestination), 0755, true);
455 }
456
457 $script = file_get_contents($pathToScript);
458 $script = str_replace('%%user_ip%%', $this->getIpAddress(), $script);
459 $script = str_replace('%%user_id%%', $this->siteConfig['login_user_id'], $script);
460 $script = str_replace('%%secret_password%%', $this->siteConfig['password'], $script);
461 file_put_contents($pathToDestination, $script);
462
463 if (!$quiet) $this->log(__('Inserting auto-login script for staging site', 'backup-backup'), 'SUCCESS');
464
465 }
466
467 protected function getRandomPassword() {
468
469 $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
470 $pass = [];
471 $alphaLength = strlen($alphabet) - 1;
472
473 for ($i = 0; $i < 24; $i++) {
474 $n = rand(0, $alphaLength);
475 $pass[] = $alphabet[$n];
476 }
477
478 return implode($pass);
479
480 }
481
482 private function createDefaultConfig() {
483
484 $defaultConfig = [];
485 file_put_contents($this->configPath, '<?php //' . serialize($defaultConfig));
486
487 return $defaultConfig;
488
489 }
490
491 private function createDefaultConfigForSite($rand) {
492
493 $defaultConfig = [];
494 $configPath = BMI_STAGING . DIRECTORY_SEPARATOR . $rand . '.php';
495 file_put_contents($configPath, '<?php //' . serialize($defaultConfig));
496
497 return $defaultConfig;
498
499 }
500
501 protected function loadConfig() {
502
503 $name = $this->name;
504 if (!$name || !is_string($name)) return;
505 if (!file_exists($this->configPath)) $this->createDefaultConfig();
506
507 $config = file_get_contents($this->configPath);
508 $config = trim(substr($config, 8));
509
510 if (is_serialized($config)) $config = maybe_unserialize($config);
511 else $config = $this->createDefaultConfig();
512
513 if (isset($config[$name]) && isset($config[$name]['config'])) {
514
515 $this->siteConfigPath = BMI_STAGING . DIRECTORY_SEPARATOR . sanitize_text_field($config[$name]['config']) . '.php';
516
517 } else {
518
519 $config[$name] = [];
520 $config[$name]['config'] = uniqid();
521 $this->siteConfigPath = BMI_STAGING . DIRECTORY_SEPARATOR . $config[$name]['config'] . '.php';
522 $this->createDefaultConfigForSite($config[$name]['config']);
523
524 }
525
526 if (file_exists($this->siteConfigPath)) {
527
528 $siteConfig = file_get_contents($this->siteConfigPath);
529 $siteConfig = trim(substr($siteConfig, 8));
530
531 if (is_serialized($siteConfig)) $siteConfig = maybe_unserialize($siteConfig);
532 else $siteConfig = $this->createDefaultConfigForSite($config[$name]['config']);
533
534 $this->siteConfig = $siteConfig;
535
536 } else {
537
538 unset($this->config[$this->name]);
539 $this->siteConfig = [];
540
541 }
542
543 $this->config = $config;
544
545 }
546
547 protected function saveConfig() {
548
549 if (!$this->configPath || !isset($this->config)) return;
550 file_put_contents($this->configPath, '<?php //' . serialize($this->config));
551
552 }
553
554 protected function saveConfigSite() {
555
556 if (!$this->siteConfigPath || !$this->siteConfig) return;
557 file_put_contents($this->siteConfigPath, '<?php //' . serialize($this->siteConfig));
558
559 }
560
561 protected function log($msg, $level = 'INFO') {
562
563 // Append logs to live-log file
564 if ($this->logger) $this->logger->log($msg, $level);
565
566 }
567
568 protected function printInitialLogs() {
569
570 global $wp_version;
571
572 $this->log(__("Backup & Migration version: ", 'backup-backup') . BMI_VERSION);
573 $this->log(__("PHP Version: ", 'backup-backup') . PHP_VERSION);
574 $this->log(__("WP Version: ", 'backup-backup') . $wp_version);
575 $this->log(__("MySQL Version: ", 'backup-backup') . $GLOBALS['wpdb']->db_version());
576 $this->log(__("MySQL Max Length: ", 'backup-backup') . $GLOBALS['wpdb']->get_results("SHOW VARIABLES LIKE 'max_allowed_packet';")[0]->Value);
577
578 if (isset($_SERVER['SERVER_SOFTWARE']) && !empty($_SERVER['SERVER_SOFTWARE'])) {
579 $this->log(__("Web server: ", 'backup-backup') . $_SERVER['SERVER_SOFTWARE']);
580 } else {
581 $this->log(__("Web server: Not available", 'backup-backup'));
582 }
583
584 $this->log(__("Max execution time (in seconds): ", 'backup-backup') . @ini_get('max_execution_time'));
585
586 $this->log(__("Memory limit (server): ", 'backup-backup') . @ini_get('memory_limit'));
587
588 if (defined('WP_MEMORY_LIMIT')) {
589 $this->log(__("Memory limit (wp-config): ", 'backup-backup') . WP_MEMORY_LIMIT);
590 }
591
592 if (defined('WP_MAX_MEMORY_LIMIT')) {
593 $this->log(__("Memory limit (wp-config admin): ", 'backup-backup') . WP_MAX_MEMORY_LIMIT);
594 }
595
596 if (defined('BMI_DB_MAX_ROWS_PER_QUERY')) {
597 $this->log(__('Max rows per query (this site): ', 'backup-backup') . BMI_DB_MAX_ROWS_PER_QUERY);
598 }
599
600 if (defined('BMI_BACKUP_PRO')) {
601 if (BMI_BACKUP_PRO == 1) {
602 $this->log(__("Premium plugin is enabled and activated", 'backup-backup'));
603 } else {
604 $this->log(__("Premium version is enabled but not active, using free plugin.", 'backup-backup'), 'warn');
605 }
606 }
607
608 }
609
610 protected function progress($progress) {
611
612 // Sets new percentage of progress
613 if ($this->logger) $this->logger->progress($progress);
614
615 }
616
617 protected function returnError($reason, $english) {
618
619 $this->log(__('Aborting staging site creation process...', 'backup-backup'), 'STEP');
620 $this->log(__('There was an error during creation of staging site:', 'backup-backup'), 'ERROR');
621 $this->log($reason, 'ERROR');
622 $this->log($english, 'VERBOSE');
623 $this->log('#300', 'END-CODE');
624
625 $this->wasError = true;
626 $this->wasErrorMsg = $english;
627 $this->continue = true;
628 $this->continuationData = [ 'status' => 'fail', 'message' => $reason ];
629
630 $this->abort();
631
632 BMP::res($this->continuationData);
633 exit;
634
635 }
636
637 protected function sendSuccess($isTasteWP = false) {
638
639 $this->log(__('Performing final cleanup', 'backup-backup'), 'STEP');
640 $this->cleanup();
641 $this->log(__('Cleanup performed, entire process finished successfully', 'backup-backup'), 'SUCCESS');
642
643 if ($isTasteWP) {
644
645 $siteURL = $this->siteConfig['url'];
646
647 $this->continue = true;
648 $this->continuationData = [ 'status' => 'success', 'url' => $siteURL ];
649
650 } else {
651
652 $siteURL = $this->siteConfig['url'];
653 $userid = $this->siteConfig['login_user_id'];
654 $password = $this->siteConfig['password'];
655
656 $this->continue = true;
657 $this->continuationData = [ 'status' => 'success', 'url' => $siteURL, 'password' => $password, 'userid' => $userid ];
658
659 }
660
661 $this->saveConfig();
662 $this->saveConfigSite();
663
664 BMP::res($this->continuationData);
665 exit;
666
667 }
668
669 protected function errorHandler() {
670 set_error_handler(function ($errno, $errstr, $errfile, $errline) {
671
672 if (BMI_DEBUG) {
673 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (ERROR HANDLER #5):');
674 error_log(print_r($errno, true));
675 error_log(print_r($errstr, true));
676 error_log(print_r($errfile, true));
677 error_log(print_r($errline, true));
678 }
679
680 if (strpos($errstr, 'deprecated') !== false) return;
681 if (strpos($errstr, 'php_uname') !== false) return;
682
683 if ($errno != E_ERROR && $errno != E_CORE_ERROR && $errno != E_COMPILE_ERROR && $errno != E_USER_ERROR && $errno != E_RECOVERABLE_ERROR) {
684 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration') === false) return;
685 Logger::error(__('There was an error before request shutdown (but it was not logged to staging log)', 'backup-backup'));
686 Logger::error(__('Error message: ', 'backup-backup') . $errstr);
687 Logger::error(__('Error file/line: ', 'backup-backup') . $errfile . '|' . $errline);
688 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#04' . '|' . $errno);
689 return;
690 }
691
692 if (strpos($errfile, 'backup-backup') === false) {
693 Logger::error(__("Restore process was not aborted because this error is not related to Backup Migration.", 'backup-backup'));
694 $this->log(__("There was an error not related to Backup Migration Plugin.", 'backup-backup'), 'warn');
695 $this->log(__("Message: ", 'backup-backup') . $errstr, 'warn');
696 $this->log(__("Staging process will not be aborted because of this.", 'backup-backup'), 'warn');
697 return;
698 }
699
700 $this->log(__("There was an error during staging process:", 'backup-backup'), 'error');
701 $this->log(__("Message: ", 'backup-backup') . $errstr, 'error');
702 $this->log(__("File/line: ", 'backup-backup') . $errfile . '|' . $errline, 'error');
703 $this->log(__('Unfortunately we had to remove the site (if partly created).', 'backup-backup'), 'error');
704
705 $this->abort();
706
707 $this->log(__("Aborting staging site creation process...", 'backup-backup'), 'step');
708 $this->log('#003', 'end-code');
709 $this->end();
710
711 exit;
712
713 }, E_ALL);
714 }
715
716 protected function exceptionHandler() {
717 set_exception_handler(function ($exception) {
718 if (BMI_DEBUG) {
719 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (EXCEPTION HANDLER #3):');
720 error_log(print_r($exception, true));
721 }
722
723 $this->log(__("Exception: ", 'backup-backup') . $exception->getMessage(), 'warn');
724 Logger::log(__("Exception: ", 'backup-backup') . $exception->getMessage());
725 });
726 }
727
728 protected function getIpAddress() {
729
730 $ip = '127.0.0.1';
731 if (isset($_SERVER['HTTP_CLIENT_IP'])) {
732 $ip = $_SERVER['HTTP_CLIENT_IP'];
733 } else {
734 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
735 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
736 }
737 if ($ip === false) {
738 if (isset($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR'];
739 }
740 }
741
742 return $ip;
743
744 }
745
746 protected function getAllStagingSiteDirectories() {
747
748 $sites = array_keys($this->config);
749 return $sites;
750
751 }
752
753 protected function getAllStagingSitePrefixes() {
754
755 $prefixes = [];
756 $sites = $this->getAllStagingSiteDirectories();
757
758 foreach ($sites as $siteName) {
759 $site = $this->config[$siteName];
760 if (isset($site['prefix'])) {
761 $prefix = $site['prefix'];
762 $prefixes[] = $prefix;
763 }
764 }
765
766 return $prefixes;
767
768 }
769
770 protected function setContinuation($step, $batch = 1, $siteData = []) {
771
772 $this->siteConfig['step'] = $step;
773 $this->siteConfig['batch'] = $batch;
774
775 $siteData['name'] = $this->name;
776
777 $this->continue = true;
778 $this->continuationData = [ 'status' => 'continue', 'data' => $siteData ];
779
780 $this->log('Setting continuation for: ' . $step . ' ' . $batch, 'VERBOSE');
781
782 $this->saveConfig();
783 $this->saveConfigSite();
784
785 BMP::res($this->continuationData);
786 exit;
787
788 }
789
790 protected function cleanup() {
791
792 $this->log('Cleaning up not needed files and parsing configs.', 'VERBOSE');
793 $pathDirsListFile = BMI_TMP . DIRECTORY_SEPARATOR . '.staging_directories';
794 $pathFilesListFile = BMI_TMP . DIRECTORY_SEPARATOR . '.staging_files';
795 $staging_lock = BMI_STAGING . '/.staging_lock';
796
797 if (file_exists($pathDirsListFile)) @unlink($pathDirsListFile);
798 if (file_exists($pathFilesListFile)) @unlink($pathFilesListFile);
799 if (file_exists($staging_lock)) @unlink($staging_lock);
800
801 }
802
803 protected function abort($delete = false) {
804
805 if ($delete) $this->log(__('Aborting the process due to user will.', 'backup-backup'), 'STEP');
806
807 $this->log('Aborting the staging process and removing all related configs, files.', 'VERBOSE');
808 $this->cleanup();
809 $this->delete($this->name);
810
811 if ($delete) $this->log(__('Process successfully aborted and cleaned up.', 'backup-backup'), 'SUCCESS');
812
813 if ($delete) {
814 $this->continuationData = BMP::res([ 'status' => 'deleted', 'name' => $this->name ]);
815 return $this->continuationData;
816 }
817
818 }
819
820 public function __destruct() {
821
822 // End logger
823 $this->log('Saving staging sites configuration (end of request/batch)...', 'VERBOSE');
824 if ($this->isRemoved == false) {
825 $this->saveConfig();
826 $this->saveConfigSite();
827 }
828 $this->log('Configuration saved, destructing the logger (controller)...', 'VERBOSE');
829 if ($this->logger) $this->logger->end();
830
831 }
832
833 }
834