PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 1.3.0
Backup Migration v1.3.0
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 2 years ago local.php 2 years ago tastewp.php 2 years ago
controller.php
835 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 $sql = "DROP TABLE %i;";
369 $sql = $wpdb->prepare($sql, [$name]);
370 $wpdb->query($sql);
371 }
372 }
373 }
374
375 }
376
377 public function deleteFromTasteWP() {
378
379 if (isset($this->siteConfig['communication_secret']) && $this->siteConfig['communication_secret'] == 'local') return;
380 $url = $this->tastewpURL . '/stg/delete/' . $this->siteConfig['communication_secret'];
381 if (isset($this->siteConfig['entry'])) $data = [ 'entry' => $this->siteConfig['entry'] ];
382 else $data = [];
383
384 $this->httpRequest($url, $data);
385
386 }
387
388 public function deleteRelatedConfigs() {
389
390 unset($this->config[$this->name]);
391 if (file_exists($this->siteConfigPath)) {
392 @unlink($this->siteConfigPath);
393 }
394
395 $this->saveConfig();
396 $this->isRemoved = true;
397
398 }
399
400 public function delete($name, $ignoreTWP = false) {
401
402 $this->name = strval($name);
403 $this->loadConfig();
404
405 $this->deleteAllStagingFiles();
406 $this->deleteRelatedDatabase();
407 $this->deleteRelatedConfigs();
408
409 // In case of some false positive, keep the site on TasteWP.
410 if ($ignoreTWP != true) $this->deleteFromTasteWP();
411
412 return ['status' => 'success' ];
413
414 }
415
416 private function rrmdir($dir) {
417 if (is_dir($dir)) {
418 $objects = scandir($dir);
419 foreach ($objects as $object) {
420 if ($object != "." && $object != "..") {
421 if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && !is_link($dir . DIRECTORY_SEPARATOR . $object)) {
422 $this->rrmdir($dir . DIRECTORY_SEPARATOR . $object);
423 } else {
424 @unlink($dir . DIRECTORY_SEPARATOR . $object);
425 }
426 }
427 }
428 @rmdir($dir);
429 } else {
430 if (file_exists($dir) && is_file($dir)) {
431 @unlink($dir);
432 }
433 }
434 }
435
436 protected function copyOverPasswordLessScript($quiet = false) {
437
438 if (!$quiet) $this->log(__('Inserting auto-login script for staging site', 'backup-backup'), 'STEP');
439
440 $this->siteConfig['login_user_id'] = get_current_user_id();
441 $this->siteConfig['password'] = $this->getRandomPassword();
442 $this->saveConfigSite();
443
444 $pathToScript = BMI_INCLUDES . DIRECTORY_SEPARATOR . 'htaccess' . DIRECTORY_SEPARATOR . '.autologin.php';
445
446 $mudirPath = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'mu-plugins';
447 if (defined('WPMU_PLUGIN_DIR')) $mudirPath = WPMU_PLUGIN_DIR;
448
449 $sourceABSPATH = untrailingslashit($this->siteConfig['root_source']);
450 $destinationABSPATH = untrailingslashit($this->siteConfig['root_staging']);
451 $pathToDestination = str_replace($sourceABSPATH, $destinationABSPATH, $mudirPath);
452 $pathToDestination = untrailingslashit($pathToDestination) . DIRECTORY_SEPARATOR . 'bmi-autologin.php';
453
454 if (!(file_exists(dirname($pathToDestination)) && is_dir(dirname($pathToDestination)))) {
455 @mkdir(dirname($pathToDestination), 0755, true);
456 }
457
458 $script = file_get_contents($pathToScript);
459 $script = str_replace('%%user_ip%%', $this->getIpAddress(), $script);
460 $script = str_replace('%%user_id%%', $this->siteConfig['login_user_id'], $script);
461 $script = str_replace('%%secret_password%%', $this->siteConfig['password'], $script);
462 file_put_contents($pathToDestination, $script);
463
464 if (!$quiet) $this->log(__('Inserting auto-login script for staging site', 'backup-backup'), 'SUCCESS');
465
466 }
467
468 protected function getRandomPassword() {
469
470 $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
471 $pass = [];
472 $alphaLength = strlen($alphabet) - 1;
473
474 for ($i = 0; $i < 24; $i++) {
475 $n = rand(0, $alphaLength);
476 $pass[] = $alphabet[$n];
477 }
478
479 return implode($pass);
480
481 }
482
483 private function createDefaultConfig() {
484
485 $defaultConfig = [];
486 file_put_contents($this->configPath, '<?php //' . serialize($defaultConfig));
487
488 return $defaultConfig;
489
490 }
491
492 private function createDefaultConfigForSite($rand) {
493
494 $defaultConfig = [];
495 $configPath = BMI_STAGING . DIRECTORY_SEPARATOR . $rand . '.php';
496 file_put_contents($configPath, '<?php //' . serialize($defaultConfig));
497
498 return $defaultConfig;
499
500 }
501
502 protected function loadConfig() {
503
504 $name = $this->name;
505 if (!$name || !is_string($name)) return;
506 if (!file_exists($this->configPath)) $this->createDefaultConfig();
507
508 $config = file_get_contents($this->configPath);
509 $config = trim(substr($config, 8));
510
511 if (is_serialized($config)) $config = maybe_unserialize($config);
512 else $config = $this->createDefaultConfig();
513
514 if (isset($config[$name]) && isset($config[$name]['config'])) {
515
516 $this->siteConfigPath = BMI_STAGING . DIRECTORY_SEPARATOR . sanitize_text_field($config[$name]['config']) . '.php';
517
518 } else {
519
520 $config[$name] = [];
521 $config[$name]['config'] = uniqid();
522 $this->siteConfigPath = BMI_STAGING . DIRECTORY_SEPARATOR . $config[$name]['config'] . '.php';
523 $this->createDefaultConfigForSite($config[$name]['config']);
524
525 }
526
527 if (file_exists($this->siteConfigPath)) {
528
529 $siteConfig = file_get_contents($this->siteConfigPath);
530 $siteConfig = trim(substr($siteConfig, 8));
531
532 if (is_serialized($siteConfig)) $siteConfig = maybe_unserialize($siteConfig);
533 else $siteConfig = $this->createDefaultConfigForSite($config[$name]['config']);
534
535 $this->siteConfig = $siteConfig;
536
537 } else {
538
539 unset($this->config[$this->name]);
540 $this->siteConfig = [];
541
542 }
543
544 $this->config = $config;
545
546 }
547
548 protected function saveConfig() {
549
550 if (!$this->configPath || !isset($this->config)) return;
551 file_put_contents($this->configPath, '<?php //' . serialize($this->config));
552
553 }
554
555 protected function saveConfigSite() {
556
557 if (!$this->siteConfigPath || !$this->siteConfig) return;
558 file_put_contents($this->siteConfigPath, '<?php //' . serialize($this->siteConfig));
559
560 }
561
562 protected function log($msg, $level = 'INFO') {
563
564 // Append logs to live-log file
565 if ($this->logger) $this->logger->log($msg, $level);
566
567 }
568
569 protected function printInitialLogs() {
570
571 global $wp_version;
572
573 $this->log(__("Backup & Migration version: ", 'backup-backup') . BMI_VERSION);
574 $this->log(__("PHP Version: ", 'backup-backup') . PHP_VERSION);
575 $this->log(__("WP Version: ", 'backup-backup') . $wp_version);
576 $this->log(__("MySQL Version: ", 'backup-backup') . $GLOBALS['wpdb']->db_version());
577 $this->log(__("MySQL Max Length: ", 'backup-backup') . $GLOBALS['wpdb']->get_results("SHOW VARIABLES LIKE 'max_allowed_packet';")[0]->Value);
578
579 if (isset($_SERVER['SERVER_SOFTWARE']) && !empty($_SERVER['SERVER_SOFTWARE'])) {
580 $this->log(__("Web server: ", 'backup-backup') . $_SERVER['SERVER_SOFTWARE']);
581 } else {
582 $this->log(__("Web server: Not available", 'backup-backup'));
583 }
584
585 $this->log(__("Max execution time (in seconds): ", 'backup-backup') . @ini_get('max_execution_time'));
586
587 $this->log(__("Memory limit (server): ", 'backup-backup') . @ini_get('memory_limit'));
588
589 if (defined('WP_MEMORY_LIMIT')) {
590 $this->log(__("Memory limit (wp-config): ", 'backup-backup') . WP_MEMORY_LIMIT);
591 }
592
593 if (defined('WP_MAX_MEMORY_LIMIT')) {
594 $this->log(__("Memory limit (wp-config admin): ", 'backup-backup') . WP_MAX_MEMORY_LIMIT);
595 }
596
597 if (defined('BMI_DB_MAX_ROWS_PER_QUERY')) {
598 $this->log(__('Max rows per query (this site): ', 'backup-backup') . BMI_DB_MAX_ROWS_PER_QUERY);
599 }
600
601 if (defined('BMI_BACKUP_PRO')) {
602 if (BMI_BACKUP_PRO == 1) {
603 $this->log(__("Premium plugin is enabled and activated", 'backup-backup'));
604 } else {
605 $this->log(__("Premium version is enabled but not active, using free plugin.", 'backup-backup'), 'warn');
606 }
607 }
608
609 }
610
611 protected function progress($progress) {
612
613 // Sets new percentage of progress
614 if ($this->logger) $this->logger->progress($progress);
615
616 }
617
618 protected function returnError($reason, $english) {
619
620 $this->log(__('Aborting staging site creation process...', 'backup-backup'), 'STEP');
621 $this->log(__('There was an error during creation of staging site:', 'backup-backup'), 'ERROR');
622 $this->log($reason, 'ERROR');
623 $this->log($english, 'VERBOSE');
624 $this->log('#300', 'END-CODE');
625
626 $this->wasError = true;
627 $this->wasErrorMsg = $english;
628 $this->continue = true;
629 $this->continuationData = [ 'status' => 'fail', 'message' => $reason ];
630
631 $this->abort();
632
633 BMP::res($this->continuationData);
634 exit;
635
636 }
637
638 protected function sendSuccess($isTasteWP = false) {
639
640 $this->log(__('Performing final cleanup', 'backup-backup'), 'STEP');
641 $this->cleanup();
642 $this->log(__('Cleanup performed, entire process finished successfully', 'backup-backup'), 'SUCCESS');
643
644 if ($isTasteWP) {
645
646 $siteURL = $this->siteConfig['url'];
647
648 $this->continue = true;
649 $this->continuationData = [ 'status' => 'success', 'url' => $siteURL ];
650
651 } else {
652
653 $siteURL = $this->siteConfig['url'];
654 $userid = $this->siteConfig['login_user_id'];
655 $password = $this->siteConfig['password'];
656
657 $this->continue = true;
658 $this->continuationData = [ 'status' => 'success', 'url' => $siteURL, 'password' => $password, 'userid' => $userid ];
659
660 }
661
662 $this->saveConfig();
663 $this->saveConfigSite();
664
665 BMP::res($this->continuationData);
666 exit;
667
668 }
669
670 protected function errorHandler() {
671 set_error_handler(function ($errno, $errstr, $errfile, $errline) {
672
673 if (BMI_DEBUG) {
674 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (ERROR HANDLER #5):');
675 error_log(print_r($errno, true));
676 error_log(print_r($errstr, true));
677 error_log(print_r($errfile, true));
678 error_log(print_r($errline, true));
679 }
680
681 if (strpos($errstr, 'deprecated') !== false) return;
682 if (strpos($errstr, 'php_uname') !== false) return;
683
684 if ($errno != E_ERROR && $errno != E_CORE_ERROR && $errno != E_COMPILE_ERROR && $errno != E_USER_ERROR && $errno != E_RECOVERABLE_ERROR) {
685 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration') === false) return;
686 Logger::error(__('There was an error before request shutdown (but it was not logged to staging log)', 'backup-backup'));
687 Logger::error(__('Error message: ', 'backup-backup') . $errstr);
688 Logger::error(__('Error file/line: ', 'backup-backup') . $errfile . '|' . $errline);
689 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#04' . '|' . $errno);
690 return;
691 }
692
693 if (strpos($errfile, 'backup-backup') === false) {
694 Logger::error(__("Restore process was not aborted because this error is not related to Backup Migration.", 'backup-backup'));
695 $this->log(__("There was an error not related to Backup Migration Plugin.", 'backup-backup'), 'warn');
696 $this->log(__("Message: ", 'backup-backup') . $errstr, 'warn');
697 $this->log(__("Staging process will not be aborted because of this.", 'backup-backup'), 'warn');
698 return;
699 }
700
701 $this->log(__("There was an error during staging process:", 'backup-backup'), 'error');
702 $this->log(__("Message: ", 'backup-backup') . $errstr, 'error');
703 $this->log(__("File/line: ", 'backup-backup') . $errfile . '|' . $errline, 'error');
704 $this->log(__('Unfortunately we had to remove the site (if partly created).', 'backup-backup'), 'error');
705
706 $this->abort();
707
708 $this->log(__("Aborting staging site creation process...", 'backup-backup'), 'step');
709 $this->log('#003', 'end-code');
710 $this->end();
711
712 exit;
713
714 }, E_ALL);
715 }
716
717 protected function exceptionHandler() {
718 set_exception_handler(function ($exception) {
719 if (BMI_DEBUG) {
720 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (EXCEPTION HANDLER #3):');
721 error_log(print_r($exception, true));
722 }
723
724 $this->log(__("Exception: ", 'backup-backup') . $exception->getMessage(), 'warn');
725 Logger::log(__("Exception: ", 'backup-backup') . $exception->getMessage());
726 });
727 }
728
729 protected function getIpAddress() {
730
731 $ip = '127.0.0.1';
732 if (isset($_SERVER['HTTP_CLIENT_IP'])) {
733 $ip = $_SERVER['HTTP_CLIENT_IP'];
734 } else {
735 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
736 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
737 }
738 if ($ip === false) {
739 if (isset($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR'];
740 }
741 }
742
743 return $ip;
744
745 }
746
747 protected function getAllStagingSiteDirectories() {
748
749 $sites = array_keys($this->config);
750 return $sites;
751
752 }
753
754 protected function getAllStagingSitePrefixes() {
755
756 $prefixes = [];
757 $sites = $this->getAllStagingSiteDirectories();
758
759 foreach ($sites as $siteName) {
760 $site = $this->config[$siteName];
761 if (isset($site['prefix'])) {
762 $prefix = $site['prefix'];
763 $prefixes[] = $prefix;
764 }
765 }
766
767 return $prefixes;
768
769 }
770
771 protected function setContinuation($step, $batch = 1, $siteData = []) {
772
773 $this->siteConfig['step'] = $step;
774 $this->siteConfig['batch'] = $batch;
775
776 $siteData['name'] = $this->name;
777
778 $this->continue = true;
779 $this->continuationData = [ 'status' => 'continue', 'data' => $siteData ];
780
781 $this->log('Setting continuation for: ' . $step . ' ' . $batch, 'VERBOSE');
782
783 $this->saveConfig();
784 $this->saveConfigSite();
785
786 BMP::res($this->continuationData);
787 exit;
788
789 }
790
791 protected function cleanup() {
792
793 $this->log('Cleaning up not needed files and parsing configs.', 'VERBOSE');
794 $pathDirsListFile = BMI_INCLUDES . DIRECTORY_SEPARATOR . 'htaccess' . DIRECTORY_SEPARATOR . '.staging_directories';
795 $pathFilesListFile = BMI_INCLUDES . DIRECTORY_SEPARATOR . 'htaccess' . DIRECTORY_SEPARATOR . '.staging_files';
796 $staging_lock = BMI_STAGING . '/.staging_lock';
797
798 if (file_exists($pathDirsListFile)) @unlink($pathDirsListFile);
799 if (file_exists($pathFilesListFile)) @unlink($pathFilesListFile);
800 if (file_exists($staging_lock)) @unlink($staging_lock);
801
802 }
803
804 protected function abort($delete = false) {
805
806 if ($delete) $this->log(__('Aborting the process due to user will.', 'backup-backup'), 'STEP');
807
808 $this->log('Aborting the staging process and removing all related configs, files.', 'VERBOSE');
809 $this->cleanup();
810 $this->delete($this->name);
811
812 if ($delete) $this->log(__('Process successfully aborted and cleaned up.', 'backup-backup'), 'SUCCESS');
813
814 if ($delete) {
815 $this->continuationData = BMP::res([ 'status' => 'deleted', 'name' => $this->name ]);
816 return $this->continuationData;
817 }
818
819 }
820
821 public function __destruct() {
822
823 // End logger
824 $this->log('Saving staging sites configuration (end of request/batch)...', 'VERBOSE');
825 if ($this->isRemoved == false) {
826 $this->saveConfig();
827 $this->saveConfigSite();
828 }
829 $this->log('Configuration saved, destructing the logger (controller)...', 'VERBOSE');
830 if ($this->logger) $this->logger->end();
831
832 }
833
834 }
835