PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.1.3
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.1.3
4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Backend / Administrator.php
wp-staging / Backend Last commit date
Activation 5 years ago Feedback 2 years ago Modules 2 years ago Optimizer 2 years ago Pluginmeta 2 years ago Upgrade 2 years ago helpers 5 years ago views 2 years ago Administrator.php 2 years ago
Administrator.php
1384 lines
1 <?php
2
3 namespace WPStaging\Backend;
4
5 use WPStaging\Backend\Modules\Jobs\Job;
6 use WPStaging\Core\WPStaging;
7 use WPStaging\Core\DTO\Settings;
8 use WPStaging\Framework\Analytics\Actions\AnalyticsStagingReset;
9 use WPStaging\Framework\Analytics\Actions\AnalyticsStagingUpdate;
10 use WPStaging\Framework\Assets\Assets;
11 use WPStaging\Framework\Database\DbInfo;
12 use WPStaging\Framework\SiteInfo;
13 use WPStaging\Framework\Security\Auth;
14 use WPStaging\Framework\Mails\Report\Report;
15 use WPStaging\Framework\Filesystem\Filters\ExcludeFilter;
16 use WPStaging\Framework\Filesystem\DebugLogReader;
17 use WPStaging\Framework\Filesystem\PathIdentifier;
18 use WPStaging\Framework\TemplateEngine\TemplateEngine;
19 use WPStaging\Framework\CloningProcess\Database\CompareExternalDatabase;
20 use WPStaging\Framework\Utils\Math;
21 use WPStaging\Framework\Utils\WpDefaultDirectories;
22 use WPStaging\Framework\Notices\DismissNotice;
23 use WPStaging\Framework\Staging\Sites;
24 use WPStaging\Backend\Modules\Jobs\Cancel;
25 use WPStaging\Backend\Modules\Jobs\CancelUpdate;
26 use WPStaging\Backend\Modules\Jobs\Cloning;
27 use WPStaging\Backend\Modules\Jobs\Updating;
28 use WPStaging\Backend\Modules\Jobs\Delete;
29 use WPStaging\Backend\Modules\Jobs\Scan;
30 use WPStaging\Backend\Modules\Jobs\Logs;
31 use WPStaging\Backend\Modules\Jobs\ProcessLock;
32 use WPStaging\Backend\Modules\SystemInfo;
33 use WPStaging\Backend\Modules\Views\Tabs\Tabs;
34 use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
35 use WPStaging\Backend\Activation;
36 use WPStaging\Backend\Pro\Modules\Jobs\Processing;
37 use WPStaging\Backend\Pro\Modules\Jobs\Backups\BackupUploadsDir;
38 use WPStaging\Backend\Pluginmeta\Pluginmeta;
39 use WPStaging\Framework\Database\SelectedTables;
40 use WPStaging\Framework\Utils\Sanitize;
41 use WPStaging\Backend\Pro\Modules\Jobs\Scan as ScanProModule;
42 use WPStaging\Backend\Feedback\Feedback;
43 use WPStaging\Backup\Ajax\Restore\PrepareRestore;
44 use WPStaging\Framework\Database\WpDbInfo;
45 use WPStaging\Framework\Utils\PluginInfo;
46 use WPStaging\Framework\Security\Nonce;
47
48 /**
49 * Class Administrator
50 * @package WPStaging\Backend
51 */
52 class Administrator
53 {
54 /**
55 * @var int Place WP Staging Menu below Plugins
56 */
57 const MENU_POSITION_ORDER = 65;
58
59 /**
60 * @var int Place WP Staging Menu below Plugins for multisite
61 */
62 const MENU_POSITION_ORDER_MULTISITE = 20;
63
64 /**
65 * Path to plugin's Backend Dir
66 * @var string
67 */
68 private $path;
69
70 /**
71 * @var Assets
72 */
73 private $assets;
74
75 /**
76 * @var Auth
77 */
78 private $auth;
79
80 /**
81 * @var SiteInfo
82 */
83 private $siteInfo;
84
85 /** @var Sanitize */
86 private $sanitize;
87
88 /** @var Report */
89 private $report;
90
91 /** @var PluginInfo */
92 private $pluginInfo;
93
94 public function __construct()
95 {
96 $this->auth = WPStaging::make(Auth::class);
97 $this->assets = WPStaging::make(Assets::class);
98 $this->siteInfo = WPStaging::make(SiteInfo::class);
99 $this->report = WPStaging::make(Report::class);
100 $this->pluginInfo = WPStaging::make(PluginInfo::class);
101
102 $this->defineHooks();
103
104 // Path to backend
105 $this->path = plugin_dir_path(__FILE__);
106
107 $this->sanitize = WPStaging::make(Sanitize::class);
108
109 // Load plugins meta data
110 $this->loadMeta();
111 }
112
113 /**
114 * Load plugin meta data
115 */
116 public function loadMeta()
117 {
118 new Pluginmeta();
119 }
120
121 /**
122 * Define Hooks
123 */
124 private function defineHooks()
125 {
126 if (!defined('WPSTGPRO_VERSION')) {
127 new Activation\Welcome();
128 }
129
130 if ($this->pluginInfo->canShowAdminMenu()) {
131 add_action("admin_menu", [$this, "addMenu"], 10);
132 }
133
134 add_action("admin_init", [$this, "upgrade"]);
135 add_action("admin_post_wpstg_download_sysinfo", [$this, "downloadSystemInfoAndLogFiles"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
136
137 if (!defined('WPSTGPRO_VERSION') && $this->isPluginsPage()) {
138 add_filter('admin_footer', [$this, 'loadFeedbackForm']);
139 }
140
141 // Ajax Requests
142 add_action("wp_ajax_wpstg_overview", [$this, "ajaxOverview"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
143 add_action("wp_ajax_wpstg_scanning", [$this, "ajaxCloneScan"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
144 add_action("wp_ajax_wpstg_check_clone", [$this, "ajaxCheckCloneDirectoryName"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
145 add_action("wp_ajax_wpstg_restart", [$this, "ajaxRestart"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
146 add_action("wp_ajax_wpstg_update", [$this, "ajaxUpdateProcess"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
147 add_action("wp_ajax_wpstg_reset", [$this, "ajaxResetProcess"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
148 add_action("wp_ajax_wpstg_cloning", [$this, "ajaxStartClone"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
149 add_action("wp_ajax_wpstg_processing", [$this, "ajaxCloneDatabase"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
150 add_action("wp_ajax_wpstg_database_connect", [$this, "ajaxDatabaseConnect"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
151 add_action("wp_ajax_wpstg_database_verification", [$this, "ajaxDatabaseVerification"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
152 add_action("wp_ajax_wpstg_clone_prepare_directories", [$this, "ajaxPrepareDirectories"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
153 add_action("wp_ajax_wpstg_clone_files", [$this, "ajaxCopyFiles"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
154 add_action("wp_ajax_wpstg_clone_replace_data", [$this, "ajaxReplaceData"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
155 add_action("wp_ajax_wpstg_clone_finish", [$this, "ajaxFinish"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
156 add_action("wp_ajax_wpstg_confirm_delete_clone", [$this, "ajaxDeleteConfirmation"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
157 add_action("wp_ajax_wpstg_delete_clone", [$this, "ajaxDeleteClone"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
158 add_action("wp_ajax_wpstg_cancel_clone", [$this, "ajaxCancelClone"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
159 add_action("wp_ajax_wpstg_cancel_update", [$this, "ajaxCancelUpdate"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
160 add_action("wp_ajax_wpstg_hide_rating", [$this, "ajaxHideRating"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
161 add_action("wp_ajax_wpstg_hide_later", [$this, "ajaxHideLaterRating"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
162 add_action("wp_ajax_wpstg_hide_beta", [$this, "ajaxHideBeta"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
163 add_action("wp_ajax_wpstg_logs", [$this, "ajaxLogs"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
164 add_action("wp_ajax_wpstg_check_disk_space", [$this, "ajaxCheckFreeSpace"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
165 add_action("wp_ajax_wpstg_send_report", [$this, "ajaxSendReport"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
166 add_action("wp_ajax_wpstg_send_feedback", [$this, "sendFeedback"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
167 add_action("wp_ajax_wpstg_enable_staging_cloning", [$this, "ajaxEnableStagingCloning"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
168 add_action("wp_ajax_wpstg_clone_excludes_settings", [$this, "ajaxCloneExcludesSettings"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
169 add_action("wp_ajax_wpstg_fetch_dir_children", [$this, "ajaxFetchDirChildren"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
170 add_action("wp_ajax_wpstg_modal_error", [$this, "ajaxModalError"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
171 add_action("wp_ajax_wpstg_dismiss_notice", [$this, "ajaxDismissNotice"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
172 add_action("wp_ajax_wpstg_restore_settings", [$this, "ajaxRestoreSettings"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
173 add_action("wp_ajax_wpstg_send_debug_log_report", [$this->report, "ajaxSendDebugLog"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
174
175 // Ajax hooks pro Version
176 // TODO: move all below actions to pro service provider?
177 add_action("wp_ajax_wpstg_edit_clone_data", [$this, "ajaxEditCloneData"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
178 add_action("wp_ajax_wpstg_save_clone_data", [$this, "ajaxSaveCloneData"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
179 add_action("wp_ajax_wpstg_scan", [$this, "ajaxPushScan"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
180 add_action("wp_ajax_wpstg_push_tables", [$this, "ajaxPushTables"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
181 add_action("wp_ajax_wpstg_push_processing", [$this, "ajaxPushProcessing"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
182 add_action("wp_ajax_nopriv_wpstg_push_processing", [$this, "ajaxPushProcessing"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
183
184 // TODO: replace uploads backup during push once we have backups PR ready,
185 // Then there will be no need to have any cron to delete those backups
186 if (class_exists('WPStaging\Backend\Pro\Modules\Jobs\Backups\BackupUploadsDir')) {
187 add_action(BackupUploadsDir::BACKUP_DELETE_CRON_HOOK_NAME, [$this, "removeOldUploadsBackup"]); // phpcs:ignore WPStaging.Security.FirstArgNotAString -- Cron callback
188 }
189 }
190
191 /**
192 * Load Feedback Form on plugins.php
193 */
194 public function loadFeedbackForm()
195 {
196 $form = WPStaging::make(Feedback::class);
197 $form->loadForm();
198 }
199
200 /**
201 * Send Feedback data via mail
202 */
203 public function sendFeedback()
204 {
205 if (!$this->isAuthenticated()) {
206 return;
207 }
208
209 $form = WPStaging::make(Feedback::class);
210 $form->sendMail();
211 }
212
213 /**
214 * Upgrade routine
215 * @action admin_init 10 0
216 * @see \WPStaging\Backend\Administrator::defineHooks
217 */
218 public function upgrade()
219 {
220 if (defined('WPSTGPRO_VERSION') && class_exists('WPStaging\Backend\Pro\Upgrade\Upgrade')) {
221 $upgrade = WPStaging::make('WPStaging\Backend\Pro\Upgrade\Upgrade');
222 } else {
223 $upgrade = WPStaging::make('WPStaging\Backend\Upgrade\Upgrade');
224 }
225 $upgrade->doUpgrade();
226 }
227
228 /**
229 * Add Admin Menu(s)
230 */
231 public function addMenu()
232 {
233 global $wp_version;
234 $logo = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiIGZpbGw9Im5vbmUiPgo8Zz48Zz48cGF0aCBzdHlsZT0iZmlsbDojZmZmIiAgZD0iTTEzNy42LDU2MS4zSDEzLjhIMTB2MzA2LjNsOTAuNy04My40QzE4OS42LDkwOC43LDMzNS4zLDk5MCw1MDAsOTkwYzI0OS45LDAsNDU2LjEtMTg3LjEsNDg2LjItNDI4LjhIODYyLjRDODMzLjMsNzM1LjEsNjgyLjEsODY3LjUsNTAwLDg2Ny41Yy0xMjksMC0yNDIuNS02Ni41LTMwOC4xLTE2Ny4ybDE1MS4zLTEzOS4xSDEzNy42eiIvPjxwYXRoIHN0eWxlPSJmaWxsOiNmZmYiICBkPSJNNTAwLDEwQzI1MC4xLDEwLDQzLjksMTk3LjEsMTMuOCw0MzguOGgxMjMuOEMxNjYuNywyNjQuOSwzMTcuOSwxMzIuNSw1MDAsMTMyLjVjMTMyLjksMCwyNDkuMyw3MC41LDMxMy44LDE3Ni4yTDY4My44LDQzOC44aDEyMi41aDU2LjJoMTIzLjhoMy44VjEzMi41bC04Ny43LDg3LjdDODEzLjgsOTMuMSw2NjYuNiwxMCw1MDAsMTB6Ii8+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvZz4KPC9zdmc+';
235
236 $pos = self::MENU_POSITION_ORDER;
237 if (is_multisite()) {
238 $pos = self::MENU_POSITION_ORDER_MULTISITE;
239 }
240
241 // Menu Position order needs to be unique for WordPress < 4.4
242 // We are not using a unique position by default to keep WP Staging directly below plugin menu
243 if (version_compare($wp_version, '4.4', '<')) {
244 $pos++;
245 }
246
247 $proSlug = defined('WPSTGPRO_VERSION') ? 'Pro' : '';
248
249 // Main WP Staging Menu
250 add_menu_page(
251 "WP STAGING",
252 __("WP Staging " . $proSlug, "wp-staging"),
253 "manage_options",
254 "wpstg_clone",
255 [$this, "getClonePage"],
256 $logo,
257 $pos
258 );
259
260 // Page: Clone
261 add_submenu_page(
262 "wpstg_clone",
263 __("WP Staging Jobs", "wp-staging"),
264 __("Staging Sites", "wp-staging"),
265 "manage_options",
266 "wpstg_clone",
267 [$this, "getClonePage"]
268 );
269
270 add_submenu_page(
271 "wpstg_clone",
272 __("WP Staging Jobs", "wp-staging"),
273 __("Backup & Migration", "wp-staging"),
274 "manage_options",
275 "wpstg_backup",
276 [$this, "getBackupPage"]
277 );
278
279 // Page: Settings
280 add_submenu_page(
281 "wpstg_clone",
282 __("WP Staging Settings", "wp-staging"),
283 __("Settings", "wp-staging"),
284 "manage_options",
285 "wpstg-settings",
286 [$this, "getSettingsPage"]
287 );
288
289 // Page: Tools
290 add_submenu_page(
291 "wpstg_clone",
292 __("WP Staging Tools", "wp-staging"),
293 __("System Info", "wp-staging"),
294 "manage_options",
295 "wpstg-tools",
296 [$this, "getToolsPage"]
297 );
298
299 if (!defined('WPSTGPRO_VERSION')) {
300 // Page: Tools
301 add_submenu_page(
302 "wpstg_clone",
303 __("WP Staging Welcome", "wp-staging"),
304 __("Get WP Staging Pro", "wp-staging"),
305 "manage_options",
306 "wpstg-welcome",
307 [$this, "getWelcomePage"]
308 );
309 }
310
311 if (defined('WPSTGPRO_VERSION')) {
312 // Page: License
313 add_submenu_page(
314 "wpstg_clone",
315 __("WP Staging License", "wp-staging"),
316 __("License", "wp-staging"),
317 "manage_options",
318 "wpstg-license",
319 [$this, "getLicensePage"]
320 );
321 }
322 }
323
324 /**
325 * Settings Page
326 */
327 public function getSettingsPage()
328 {
329
330 $license = get_option('wpstg_license_status');
331
332 // Tabs
333 $tabs = new Tabs(apply_filters('wpstg_main_settings_tabs', [
334 "general" => __("General", "wp-staging")
335 ]));
336
337 WPStaging::getInstance()
338 // Set tabs
339 ->set("tabs", $tabs)
340 // Forms
341 ->set("forms", new FormSettings($tabs));
342
343 require_once "{$this->path}views/settings/main-settings.php";
344 }
345
346 /**
347 * Clone Page
348 */
349 public function getClonePage()
350 {
351
352 $license = get_option('wpstg_license_status');
353
354 $availableClones = get_option(Sites::STAGING_SITES_OPTION, []);
355
356 require_once "{$this->path}views/clone/index.php";
357 }
358
359 /**
360 * Backup & Migration Page
361 */
362 public function getBackupPage()
363 {
364 $license = get_option('wpstg_license_status');
365
366 // Existing clones
367 $availableClones = get_option(Sites::STAGING_SITES_OPTION, []);
368
369 $isBackupPage = true;
370
371 require_once "{$this->path}views/clone/index.php";
372 }
373
374 /**
375 * Welcome Page
376 */
377 public function getWelcomePage()
378 {
379 if (defined('WPSTGPRO_VERSION')) {
380 return;
381 }
382
383 require_once "{$this->path}views/welcome/welcome.php";
384 }
385
386 /**
387 * Tools Page
388 */
389 public function getToolsPage()
390 {
391 // Tabs
392 $tabs = new Tabs([
393 "system-info" => __("System Info", "wp-staging")
394 ]);
395
396 WPStaging::getInstance()->set("tabs", $tabs);
397
398 WPStaging::getInstance()->set("systemInfo", new SystemInfo());
399
400 // Get license data
401 $license = get_option('wpstg_license_status');
402
403 require_once "{$this->path}views/tools/index.php";
404 }
405
406 /**
407 * Download System Information and latest log files.
408 * @return void
409 */
410 public function downloadSystemInfoAndLogFiles()
411 {
412 if (!current_user_can("update_plugins")) {
413 return;
414 }
415
416 nocache_headers();
417 header("Content-Type: text/plain");
418 header('Content-Disposition: attachment; filename="wpstg-bundled-logs.txt"');
419 echo esc_html(wp_strip_all_tags(WPStaging::make(SystemInfo::class)->get("systemInfo")));
420 echo esc_html("\n\n" . str_repeat("-", 25) . "\n\n");
421 $wpstgLogs = WPStaging::make(DebugLogReader::class)->getLastLogEntries(100 * KB_IN_BYTES, true, false);
422 echo esc_html(wp_strip_all_tags($wpstgLogs));
423 echo esc_html(PHP_EOL . PHP_EOL . str_repeat("-", 25) . PHP_EOL . PHP_EOL);
424 $wpCoreDebugLog = WPStaging::make(DebugLogReader::class)->getLastLogEntries((256 * KB_IN_BYTES ), false, true);
425 echo esc_html(wp_strip_all_tags($wpCoreDebugLog));
426
427 $latestLogFiles = WPStaging::make(DebugLogReader::class)->getLatestLogFiles();
428 if (count($latestLogFiles) === 0) {
429 return;
430 }
431
432 foreach ($latestLogFiles as $logFile) {
433 echo esc_html(PHP_EOL . PHP_EOL . str_repeat("-", 25) . PHP_EOL . PHP_EOL);
434 $logs = file_get_contents($logFile);
435 echo esc_html($logs);
436 }
437 }
438
439 /**
440 * Render a view file
441 * @param string $file
442 * @param array $vars
443 * @return string
444 */
445 public function render($file, $vars = [])
446 {
447 $fullPath = $this->path . "views/" . $file . ".php";
448 $fullPath = wp_normalize_path($fullPath);
449
450 if (!file_exists($fullPath) || !is_readable($fullPath)) {
451 return "Can't render : {$fullPath} either file doesn't exist or can't read it";
452 }
453
454 $contents = @file_get_contents($fullPath);
455
456 // Variables are set
457 if (count($vars) > 0) {
458 $vars = array_combine(
459 array_map(function ($key) {
460 return "{{" . $key . "}}";
461 }, array_keys($vars)),
462 $vars
463 );
464
465 $contents = str_replace(array_keys($vars), array_values($vars), $contents);
466 }
467
468 return $contents;
469 }
470
471 /**
472 * @return bool Whether the current request is considered to be authenticated.
473 */
474 private function isAuthenticated($nonce = Nonce::WPSTG_NONCE)
475 {
476 return $this->auth->isAuthenticatedRequest($nonce);
477 }
478
479 /**
480 * Restart cloning process
481 */
482 public function ajaxRestart()
483 {
484 if (!$this->isAuthenticated()) {
485 return;
486 }
487
488 $process = WPStaging::make(ProcessLock::class);
489 $process->restart();
490 }
491
492 /**
493 * Ajax Overview
494 */
495 public function ajaxOverview()
496 {
497 if (!$this->isAuthenticated()) {
498 return;
499 }
500
501 // Existing clones
502 $sites = WPStaging::make(Sites::class);
503 $availableClones = $sites->getSortedStagingSites();
504
505 // Get license data
506 $license = get_option('wpstg_license_status');
507
508 // Get db
509 $db = WPStaging::make('wpdb');
510
511 $iconPath = $this->assets->getAssetsUrl('svg/vendor/dashicons/cloud.svg');
512
513 require_once "{$this->path}views/clone/ajax/single-overview.php";
514
515 wp_die();
516 }
517
518 /**
519 * Ajax Scan
520 * @action wp_ajax_wpstg_scanning 10 0
521 * @see Administrator::defineHooks()
522 */
523 public function ajaxCloneScan()
524 {
525 if (!$this->isAuthenticated()) {
526 return;
527 }
528
529 // Check first if there is already a process running
530 $processLock = WPStaging::make(ProcessLock::class);
531 $response = $processLock->ajaxIsRunning();
532 if ($response !== false) {
533 echo json_encode($response);
534
535 exit();
536 }
537
538 $db = WPStaging::make('wpdb');
539
540 // Scan
541 $scan = WPStaging::make(Scan::class);
542 $scan->setGifLoaderPath($this->assets->getAssetsUrl('img/spinner.gif'));
543 $scan->setInfoIcon($this->assets->getAssetsUrl('svg/vendor/dashicons/info-outline.svg'));
544 $scan->start();
545
546 // Get Options
547 $options = $scan->getOptions();
548 $excludeUtils = WPStaging::make(ExcludeFilter::class);
549 $wpDefaultDirectories = WPStaging::make(WpDefaultDirectories::class);
550 require_once "{$this->path}views/clone/ajax/scan.php";
551
552 wp_die();
553 }
554
555 /**
556 * Fetch children of the given directory
557 */
558 public function ajaxFetchDirChildren()
559 {
560 if (!$this->isAuthenticated()) {
561 wp_send_json(['success' => false]);
562 return;
563 }
564
565 $isChecked = isset($_POST['isChecked']) ? $this->sanitize->sanitizeBool($_POST['isChecked']) : false;
566 $forceDefault = isset($_POST['forceDefault']) ? $this->sanitize->sanitizeBool($_POST['forceDefault']) : false;
567 $path = isset($_POST['dirPath']) ? $this->sanitize->sanitizePath($_POST['dirPath']) : "";
568 $prefix = isset($_POST['prefix']) ? $this->sanitize->sanitizePath($_POST['prefix']) : "";
569 $basePath = ABSPATH;
570 if ($prefix === PathIdentifier::IDENTIFIER_WP_CONTENT) {
571 $basePath = WP_CONTENT_DIR;
572 }
573
574 $path = trailingslashit($basePath) . $path;
575 $scan = new Scan($path);
576 $scan->setBasePath($basePath);
577 $scan->setPathIdentifier($prefix);
578 $scan->setGifLoaderPath($this->assets->getAssetsUrl('img/spinner.gif'));
579 $scan->getDirectories($path);
580 wp_send_json([
581 "success" => true,
582 "directoryListing" => json_encode($scan->directoryListing($isChecked, $forceDefault)),
583 ]);
584 }
585
586 /**
587 * Ajax Check Clone Name
588 */
589 public function ajaxCheckCloneDirectoryName()
590 {
591 if (!$this->isAuthenticated()) {
592 return;
593 }
594
595 /** @var Sites $sitesHelper */
596 $sitesHelper = WPStaging::make(Sites::class);
597 $cloneDirectoryName = isset($_POST["directoryName"]) ? $sitesHelper->sanitizeDirectoryName($_POST["directoryName"]) : '';
598
599 if (strlen($cloneDirectoryName) < 1) {
600 return;
601 }
602
603 $result = $sitesHelper->isCloneExists($cloneDirectoryName);
604 if ($result === false) {
605 wp_send_json(["status" => "success"]);
606 return;
607 }
608
609 wp_send_json([
610 "status" => "failed",
611 "message" => $result
612 ]);
613 }
614
615 /**
616 * Ajax Start Updating Clone (Basically just layout and saving data)
617 */
618 public function ajaxUpdateProcess()
619 {
620 if (!$this->isAuthenticated()) {
621 return;
622 }
623
624 $cloning = WPStaging::make(Updating::class);
625
626 if (!$cloning->save()) {
627 wp_die('Can not save clone data');
628 }
629
630 $options = $cloning->getOptions();
631 WPStaging::make(AnalyticsStagingUpdate::class)->enqueueStartEvent($options->jobIdentifier, $options);
632
633 require_once "{$this->path}views/clone/ajax/update.php";
634
635 wp_die();
636 }
637
638 /**
639 * Ajax Start Resetting Clone
640 */
641 public function ajaxResetProcess()
642 {
643 if (!$this->isAuthenticated()) {
644 return;
645 }
646
647 $cloning = WPStaging::make(Updating::class);
648 $cloning->setMainJob(Job::RESET);
649 if (!$cloning->save()) {
650 wp_die('can not save clone data');
651 }
652
653 $options = $cloning->getOptions();
654 WPStaging::make(AnalyticsStagingReset::class)->enqueueStartEvent($options->jobIdentifier, $options);
655
656 require_once "{$this->path}views/clone/ajax/update.php";
657 wp_die();
658 }
659
660 /**
661 * Ajax Start Clone (Basically just layout and saving data)
662 */
663 public function ajaxStartClone()
664 {
665 if (!$this->isAuthenticated()) {
666 return;
667 }
668
669 // Check first if there is already a process running
670 $processLock = WPStaging::make(ProcessLock::class);
671 $processLock->isRunning();
672
673 $cloning = WPStaging::make(Cloning::class);
674
675 if (!$cloning->save()) {
676 $message = $cloning->getErrorMessage();
677 wp_send_json([
678 'success' => false,
679 'message' => $message !== '' ? $message : 'Can not save clone data'
680 ]);
681
682 wp_die();
683 }
684
685 require_once "{$this->path}views/clone/ajax/start.php";
686
687 wp_die();
688 }
689
690 /**
691 * Ajax Clone Database
692 */
693 public function ajaxCloneDatabase()
694 {
695 if (!$this->isAuthenticated()) {
696 return;
697 }
698
699 wp_send_json(WPStaging::make(Cloning::class)->start());
700 }
701
702 /**
703 * Ajax Prepare Directories (get listing of files)
704 */
705 public function ajaxPrepareDirectories()
706 {
707 if (!$this->isAuthenticated()) {
708 return;
709 }
710
711 wp_send_json(WPStaging::make(Cloning::class)->start());
712 }
713
714 /**
715 * Ajax Clone Files
716 */
717 public function ajaxCopyFiles()
718 {
719 if (!$this->isAuthenticated()) {
720 return;
721 }
722
723 wp_send_json(WPStaging::make(Cloning::class)->start());
724 }
725
726 /**
727 * Ajax Replace Data
728 */
729 public function ajaxReplaceData()
730 {
731 if (!$this->isAuthenticated()) {
732 return;
733 }
734
735 wp_send_json(WPStaging::make(Cloning::class)->start());
736 }
737
738 /**
739 * Ajax Finish
740 */
741 public function ajaxFinish()
742 {
743 if (!$this->isAuthenticated()) {
744 return;
745 }
746
747 wp_send_json(WPStaging::make(Cloning::class)->start());
748 }
749
750 /**
751 * Ajax Delete Confirmation
752 */
753 public function ajaxDeleteConfirmation()
754 {
755 if (!$this->isAuthenticated()) {
756 return;
757 }
758
759 $delete = WPStaging::make(Delete::class);
760
761 $isDatabaseConnected = $delete->setData();
762
763 $clone = $delete->getClone();
764
765 $dbname = $delete->getDbName();
766
767 require_once "{$this->path}views/clone/ajax/delete-confirmation.php";
768
769 wp_die();
770 }
771
772 /**
773 * Delete clone
774 */
775 public function ajaxDeleteClone()
776 {
777 if (!$this->isAuthenticated()) {
778 return;
779 }
780
781 $delete = WPStaging::make(Delete::class);
782
783 wp_send_json($delete->start());
784 }
785
786 /**
787 * Cancel clone
788 */
789 public function ajaxCancelClone()
790 {
791 if (!$this->isAuthenticated()) {
792 return;
793 }
794
795 $cancel = WPStaging::make(Cancel::class);
796 wp_send_json($cancel->start());
797 }
798
799 /**
800 * Cancel updating process / Do not delete clone!
801 */
802 public function ajaxCancelUpdate()
803 {
804 if (!$this->isAuthenticated()) {
805 return;
806 }
807
808 $cancelUpdate = WPStaging::make(CancelUpdate::class);
809 wp_send_json($cancelUpdate->start());
810 }
811
812 /**
813 * Ajax Hide Rating
814 *
815 * Runs when the user dismisses the notice to rate the plugin.
816 */
817 public function ajaxHideRating()
818 {
819 if (!$this->isAuthenticated()) {
820 return;
821 }
822
823 if (update_option("wpstg_rating", "no") !== false) {
824 wp_send_json(true);
825 }
826
827 wp_send_json(null);
828 }
829
830 /**
831 * Ajax Hide Rating and show it again after one week
832 *
833 * Runs when the user chooses to rate the plugin later.
834 */
835 public function ajaxHideLaterRating()
836 {
837 if (!$this->isAuthenticated()) {
838 return;
839 }
840
841 $date = date('Y-m-d', strtotime(date('Y-m-d') . ' + 7 days'));
842 if (update_option('wpstg_rating', $date) !== false) {
843 wp_send_json(true);
844 }
845
846 wp_send_json(false);
847 }
848
849 /**
850 * Ajax Hide Beta
851 */
852 public function ajaxHideBeta()
853 {
854 if (!$this->isAuthenticated()) {
855 return;
856 }
857
858 wp_send_json(update_option("wpstg_beta", "no"));
859 }
860
861 /**
862 * @return void
863 */
864 public function ajaxDismissNotice()
865 {
866 if (!$this->isAuthenticated()) {
867 return;
868 }
869
870 // Early bail if no notice option available
871 if (!isset($_POST['wpstg_notice'])) {
872 wp_send_json(null);
873 return;
874 }
875
876 /** @var DismissNotice */
877 $dismissNotice = WPStaging::make(DismissNotice::class);
878 $dismissNotice->dismiss($this->sanitize->sanitizeString($_POST['wpstg_notice']));
879 }
880
881 /**
882 * Clone logs
883 */
884 public function ajaxLogs()
885 {
886 if (!$this->isAuthenticated()) {
887 return;
888 }
889
890 $logs = WPStaging::make(Logs::class);
891 wp_send_json($logs->start());
892 }
893
894 /**
895 * Ajax Checks Free Disk Space
896 */
897 public function ajaxCheckFreeSpace()
898 {
899 if (!$this->isAuthenticated()) {
900 return false;
901 }
902
903 $excludedDirectories = isset($_POST["excludedDirectories"]) ? $this->sanitize->sanitizeString($_POST["excludedDirectories"]) : '';
904 $extraDirectories = isset($_POST["extraDirectories"]) ? $this->sanitize->sanitizeString($_POST["extraDirectories"]) : '';
905
906 $scan = WPStaging::make(Scan::class);
907 return $scan->hasFreeDiskSpace($excludedDirectories, $extraDirectories);
908 }
909
910 /**
911 * Allows the user to edit the clone's data
912 */
913 public function ajaxEditCloneData()
914 {
915 if (!$this->isAuthenticated()) {
916 return;
917 }
918
919 $existingClones = get_option(Sites::STAGING_SITES_OPTION, []);
920 if (isset($_POST["clone"]) && array_key_exists($_POST["clone"], $existingClones)) {
921 $clone = $existingClones[$this->sanitize->sanitizeString($_POST["clone"])];
922 require_once "{$this->path}Pro/views/edit-clone-data.php";
923 } else {
924 echo esc_html__("Unknown error. Please reload the page and try again", "wp-staging");
925 }
926
927 wp_die();
928 }
929
930 /**
931 * Allow the user to Save Clone Data
932 */
933 public function ajaxSaveCloneData()
934 {
935 if (!$this->isAuthenticated()) {
936 return;
937 }
938
939 $existingClones = get_option(Sites::STAGING_SITES_OPTION, []);
940 if (isset($_POST["clone"]) && array_key_exists($_POST["clone"], $existingClones)) {
941 if (empty($_POST['directoryName'])) {
942 echo esc_html__("Site name is required!", "wp-staging");
943 wp_die();
944 }
945
946 $cloneId = $this->sanitize->sanitizeString($_POST["clone"]);
947 $cloneName = isset($_POST["cloneName"]) ? $this->sanitize->sanitizeString($_POST["cloneName"]) : '';
948 $cloneDirectoryName = $this->sanitize->sanitizeString($_POST["directoryName"]);
949 $cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($cloneDirectoryName));
950
951 $updateClones = [
952 "cloneName" => $this->sanitize->sanitizeString($cloneName),
953 "directoryName" => $this->sanitize->sanitizeString($cloneDirectoryName),
954 "path" => isset($_POST["path"]) ? $this->sanitize->sanitizeString($_POST["path"]) : '',
955 "url" => isset($_POST["url"]) ? $this->sanitize->sanitizeString($_POST["url"]) : '',
956 "prefix" => isset($_POST["prefix"]) ? $this->sanitize->sanitizeString($_POST["prefix"]) : '',
957 "databaseUser" => isset($_POST["externalDBUser"]) ? $this->sanitize->sanitizeString($_POST["externalDBUser"]) : '',
958 "databasePassword" => isset($_POST["externalDBPassword"]) ? $this->sanitize->sanitizePassword($_POST["externalDBPassword"]) : '',
959 "databaseDatabase" => isset($_POST["externalDBDatabase"]) ? $this->sanitize->sanitizeString($_POST["externalDBDatabase"]) : '',
960 "databaseServer" => isset($_POST["externalDBHost"]) ? $this->sanitize->sanitizeString($_POST["externalDBHost"]) : 'localhost',
961 "databasePrefix" => isset($_POST["externalDBPrefix"]) ? $this->sanitize->sanitizeString($_POST["externalDBPrefix"]) : 'wp_',
962 "databaseSsl" => isset($_POST["externalDBSsl"]) && 'true' === $this->sanitize->sanitizeString($_POST["externalDBSsl"]) ? true : false,
963 "datetime" => ! empty($existingClones["datetime"]) ? $existingClones["datetime"] : time(),
964 "ownerId" => ! empty($existingClones['ownerId']) ? $existingClones['ownerId'] : get_current_user_id()
965 ];
966
967 $existingClones[$cloneId] = array_merge($existingClones[$cloneId], $updateClones);
968
969 if (update_option(Sites::STAGING_SITES_OPTION, $existingClones)) {
970 // Update datetime if data was updated
971 $existingClones[$cloneId]["datetime"] = time();
972 update_option(Sites::STAGING_SITES_OPTION, $existingClones);
973 }
974
975 echo esc_html__("Success", "wp-staging");
976 } else {
977 echo esc_html__("Unknown error. Please reload the page and try again", "wp-staging");
978 }
979
980 wp_die();
981 }
982
983 /**
984 * Ajax Start Push Changes Process
985 * Start with the module Scan
986 * @action wp_ajax_wpstg_scans 10 0
987 * @see Administrator::defineHooks()
988 */
989 public function ajaxPushScan()
990 {
991 if (!$this->isAuthenticated()) {
992 return false;
993 }
994
995 if (!class_exists('WPStaging\Backend\Pro\Modules\Jobs\Scan')) {
996 return false;
997 }
998
999 // Scan
1000 $scan = WPStaging::make(ScanProModule::class);
1001
1002 $scan->start();
1003
1004 // Get Options
1005 $options = $scan->getOptions();
1006
1007 // Get Framework\Utils\Math
1008 $utilsMath = WPStaging::make(Math::class);
1009
1010 require_once "{$this->path}Pro/views/scan.php";
1011
1012 wp_die();
1013 }
1014
1015 /**
1016 * Fetch all tables for push process
1017 */
1018 public function ajaxPushTables()
1019 {
1020 if (!$this->isAuthenticated()) {
1021 return false;
1022 }
1023
1024 if (!class_exists('WPStaging\Backend\Pro\Modules\Jobs\Scan')) {
1025 return false;
1026 }
1027
1028 // Scan
1029 $scan = WPStaging::make(ScanProModule::class);
1030 $scan->loadStagingDBTables($onlyLoadStagingPrefixTables = false);
1031 $scan->start();
1032 $options = $scan->getOptions();
1033
1034 $includedTables = isset($_POST['includedTables']) ? $this->sanitize->sanitizeString($_POST['includedTables']) : '';
1035 $excludedTables = isset($_POST['excludedTables']) ? $this->sanitize->sanitizeString($_POST['excludedTables']) : '';
1036 $selectedTablesWithoutPrefix = isset($_POST['selectedTablesWithoutPrefix']) ? $this->sanitize->sanitizeString($_POST['selectedTablesWithoutPrefix']) : '';
1037 $selectedTables = new SelectedTables($includedTables, $excludedTables, $selectedTablesWithoutPrefix);
1038 $selectedTables->setDatabaseInfo($options->databaseServer, $options->databaseUser, $options->databasePassword, $options->databaseDatabase, empty($options->databasePrefix) ? $options->prefix : $options->databasePrefix, $options->databaseSsl);
1039 $tables = $selectedTables->getSelectedTables($options->networkClone);
1040
1041 $templateEngine = WPStaging::make(TemplateEngine::class);
1042
1043 echo json_encode([
1044 'success' => true,
1045 "content" => $templateEngine->render("/Backend/Pro/views/selections/tables.php", [
1046 'isNetworkClone' => $scan->isNetworkClone(),
1047 'options' => $options,
1048 'showAll' => true,
1049 'selected' => $tables
1050 ])
1051 ]);
1052
1053 exit();
1054 }
1055
1056 /**
1057 * Ajax Start Pushing. Needs WP Staging Pro
1058 */
1059 public function ajaxPushProcessing()
1060 {
1061 if (!$this->isAuthenticated()) {
1062 return false;
1063 }
1064
1065 if (!class_exists('WPStaging\Backend\Pro\Modules\Jobs\Processing')) {
1066 return false;
1067 }
1068
1069 // Start the process
1070 wp_send_json(WPStaging::make(Processing::class)->start());
1071
1072 return false;
1073 }
1074
1075 /**
1076 * License Page
1077 */
1078 public function getLicensePage()
1079 {
1080 // Get license data
1081 $license = get_option('wpstg_license_status');
1082
1083 require_once "{$this->path}Pro/views/licensing.php";
1084 }
1085
1086 /**
1087 * Send mail via ajax
1088 * @param array $args
1089 */
1090 public function ajaxSendReport($args = [])
1091 {
1092 if (!$this->isAuthenticated()) {
1093 return;
1094 }
1095
1096 // Set params
1097 if (empty($args)) {
1098 $args = stripslashes_deep($_POST);
1099 }
1100
1101 // Set e-mail
1102 $emailRecipient = null;
1103 if (isset($args['wpstg_email'])) {
1104 $emailRecipient = trim($this->sanitize->sanitizeString($args['wpstg_email']));
1105 }
1106
1107 // Set hosting provider
1108 $providerName = null;
1109 if (isset($args['wpstg_provider'])) {
1110 $providerName = trim($this->sanitize->sanitizeString($args['wpstg_provider']));
1111 }
1112
1113 // Set message
1114 $messageBody = null;
1115 if (isset($args['wpstg_message'])) {
1116 $messageBody = trim($this->sanitize->sanitizeString($args['wpstg_message']));
1117 }
1118
1119 // Set syslog
1120 $sendLogFiles = false;
1121 if (isset($args['wpstg_syslog'])) {
1122 $sendLogFiles = $this->sanitize->sanitizeBool($args['wpstg_syslog']);
1123 }
1124
1125 // Set terms
1126 $termsAccepted = false;
1127 if (isset($args['wpstg_terms'])) {
1128 $termsAccepted = $this->sanitize->sanitizeBool($args['wpstg_terms']);
1129 }
1130
1131 // Set forceSend
1132 $forceSend = isset($_POST['wpstg_force_send']) && $this->sanitize->sanitizeBool($_POST['wpstg_force_send']);
1133
1134 $report = WPStaging::make(Report::class);
1135 $errors = $report->send($emailRecipient, $messageBody, $termsAccepted, $sendLogFiles, $providerName, $forceSend);
1136
1137 echo json_encode(['errors' => $errors]);
1138 exit;
1139 }
1140
1141 /**
1142 * Connect to external database for testing correct credentials
1143 */
1144 public function ajaxDatabaseConnect()
1145 {
1146 if (!$this->isAuthenticated()) {
1147 return;
1148 }
1149
1150 global $wpdb;
1151
1152 $args = $_POST;
1153 $user = !empty($args['databaseUser']) ? $this->sanitize->sanitizeString($args['databaseUser']) : '';
1154 $password = !empty($args['databasePassword']) ? $this->sanitize->sanitizePassword($args['databasePassword']) : '';
1155 $database = !empty($args['databaseDatabase']) ? $this->sanitize->sanitizeString($args['databaseDatabase']) : '';
1156 $server = !empty($args['databaseServer']) ? $this->sanitize->sanitizeString($args['databaseServer']) : 'localhost';
1157 $prefix = !empty($args['databasePrefix']) ? $this->sanitize->sanitizeString($args['databasePrefix']) : $wpdb->prefix;
1158 $useSsl = !empty($args['databaseSsl']) && 'true' === $this->sanitize->sanitizeString($args['databaseSsl']) ? true : false;
1159
1160 // make sure prefix doesn't contains any invalid character
1161 // same condition as in WordPress wpdb::set_prefix() method
1162 if (preg_match('|[^a-z0-9_]|i', $prefix)) {
1163 echo json_encode(['success' => 'false', 'errors' => __('Table prefix contains an invalid character.', 'wp-staging')]);
1164 exit;
1165 }
1166
1167 $tmpPrefixes = [
1168 PrepareRestore::TMP_DATABASE_PREFIX,
1169 PrepareRestore::TMP_DATABASE_PREFIX_TO_DROP,
1170 ];
1171
1172 if (in_array($prefix, $tmpPrefixes)) {
1173 echo json_encode(['success' => 'false', 'errors' => 'Prefix wpstgtmp_ and wpstgbak_ are preserved by WP Staging and cannot be used for CLONING purpose! Please use another prefix.']);
1174 exit;
1175 }
1176
1177 // ensure tables with the given prefix exist, default false
1178 $ensurePrefixTableExist = !empty($args['databaseEnsurePrefixTableExist']) ? $this->sanitize->sanitizeBool($args['databaseEnsurePrefixTableExist']) : false;
1179
1180 $dbInfo = new DbInfo($server, $user, stripslashes($password), $database, $useSsl);
1181 $wpdb = $dbInfo->connect();
1182
1183 // Can not connect to mysql database
1184 $error = $dbInfo->getError();
1185 if ($error !== null) {
1186 echo json_encode(['success' => 'false', 'errors' => $error]);
1187 exit;
1188 }
1189
1190 // Check if any table with provided prefix already exist
1191 $existingTables = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $wpdb->esc_like($prefix) . '%'));
1192 // used in new clone
1193 if ($existingTables !== null && !$ensurePrefixTableExist) {
1194 echo json_encode(['success' => 'false', 'errors' => __('Tables with prefix ' . $prefix . ' already exist in database. Select another prefix.', 'wp-staging')]);
1195 exit;
1196 }
1197
1198 // no need to check further for new clone
1199 if ($existingTables === null && !$ensurePrefixTableExist) {
1200 echo json_encode(['success' => 'true']);
1201 exit;
1202 }
1203
1204 // used in edit and update of clone
1205 if ($existingTables === null && $ensurePrefixTableExist) {
1206 echo json_encode(['success' => 'true', 'errors' => __('Tables with prefix "' . $prefix . '" not exist in database. Make sure it exists.', 'wp-staging')]);
1207 exit;
1208 }
1209
1210 // get production db
1211 $productionDb = WPStaging::make('wpdb');
1212 $productionDbInfo = new WpDbInfo($productionDb);
1213 $stagingDbInfo = new WpDbInfo($wpdb);
1214
1215 $stagingSiteAddress = $stagingDbInfo->getServerIp();
1216 $productionSiteAddress = $productionDbInfo->getServerIp();
1217 if ($stagingSiteAddress === null || $productionSiteAddress === null) {
1218 echo json_encode(['success' => 'false', 'errors' => __('Unable to find database server hostname of the staging or the production site.', 'wp-staging')]);
1219 exit;
1220 }
1221
1222 $isSameAddress = $productionSiteAddress === $stagingSiteAddress;
1223 $isSamePort = $productionDbInfo->getServerPort() === $stagingDbInfo->getServerPort();
1224
1225 $isSameServer = ($isSameAddress && $isSamePort) || $server === DB_HOST;
1226
1227 if ($database === DB_NAME && $prefix === $productionDb->prefix && $isSameServer) {
1228 echo json_encode(['success' => 'false', 'errors' => __('Cannot use production site database. Use another database.', 'wp-staging')]);
1229 exit;
1230 }
1231
1232 echo json_encode(['success' => 'true']);
1233 exit;
1234 }
1235
1236 /**
1237 * Action to perform when error modal confirm button is clicked
1238 *
1239 * @todo use constants instead of hardcoded strings for error types
1240 */
1241 public function ajaxModalError()
1242 {
1243 if (!$this->isAuthenticated()) {
1244 return;
1245 }
1246
1247 $type = isset($_POST['type']) ? $this->sanitize->sanitizeString($_POST['type']) : null;
1248 if ($type === 'processLock') {
1249 $process = WPStaging::make(ProcessLock::class);
1250 $process->restart();
1251
1252 exit();
1253 }
1254 }
1255
1256 /**
1257 * Render tables and files selection for RESET function
1258 */
1259 public function ajaxCloneExcludesSettings()
1260 {
1261 if (!$this->isAuthenticated()) {
1262 return;
1263 }
1264
1265 $processLock = WPStaging::make(ProcessLock::class);
1266 $response = $processLock->ajaxIsRunning();
1267 if ($response !== false) {
1268 echo json_encode($response);
1269
1270 exit();
1271 }
1272
1273 $templateEngine = WPStaging::make(TemplateEngine::class);
1274
1275 // Scan
1276 $scan = WPStaging::make(Scan::class);
1277 $scan->setGifLoaderPath($this->assets->getAssetsUrl('img/spinner.gif'));
1278 $scan->start();
1279
1280 echo json_encode([
1281 'success' => true,
1282 "html" => $templateEngine->render("/Backend/views/clone/ajax/exclude-settings.php", [
1283 'scan' => $scan,
1284 'options' => $scan->getOptions(),
1285 'excludeUtils' => WPStaging::make(ExcludeFilter::class),
1286 ])
1287 ]);
1288
1289 exit();
1290 }
1291
1292 /**
1293 * Compare database and table properties of separate db with local db
1294 */
1295 public function ajaxDatabaseVerification()
1296 {
1297 if (!$this->isAuthenticated()) {
1298 return;
1299 }
1300
1301 if (!$this->isPro()) {
1302 return;
1303 }
1304
1305 $user = !empty($_POST['databaseUser']) ? $this->sanitize->sanitizeString($_POST['databaseUser']) : '';
1306 $password = !empty($_POST['databasePassword']) ? $this->sanitize->sanitizePassword($_POST['databasePassword']) : '';
1307 $database = !empty($_POST['databaseDatabase']) ? $this->sanitize->sanitizeString($_POST['databaseDatabase']) : '';
1308 $server = !empty($_POST['databaseServer']) ? $this->sanitize->sanitizeString($_POST['databaseServer']) : 'localhost';
1309 $useSsl = !empty($_POST['databaseSsl']) && 'true' === $this->sanitize->sanitizeString($_POST['databaseSsl']) ? true : false;
1310
1311 $comparison = new CompareExternalDatabase($server, $user, stripslashes($password), $database, $useSsl);
1312 $results = $comparison->maybeGetComparison();
1313
1314 echo json_encode($results);
1315 exit();
1316 }
1317
1318 /**
1319 * Enable cloning on staging site if it is not enabled already
1320 */
1321 public function ajaxEnableStagingCloning()
1322 {
1323 if (!$this->isAuthenticated()) {
1324 return;
1325 }
1326
1327 if ($this->siteInfo->enableStagingSiteCloning()) {
1328 echo json_encode(['success' => 'true']);
1329 exit();
1330 }
1331
1332 echo json_encode(['success' => 'false', 'message' => __('Unable to enable cloning in the staging site', 'wp-staging')]);
1333 exit();
1334 }
1335
1336 /**
1337 * Restore Settings, can be used when settings are corrupted
1338 */
1339 public function ajaxRestoreSettings()
1340 {
1341 if (!$this->isAuthenticated()) {
1342 return;
1343 }
1344
1345 // Delete old settings
1346 delete_option('wpstg_settings');
1347 $settings = WPStaging::make(Settings::class);
1348 $settings->setDefault();
1349 }
1350
1351 /**
1352 * Remove uploads backup
1353 */
1354 public function removeOldUploadsBackup()
1355 {
1356 $backup = new BackupUploadsDir(null);
1357 $backup->removeUploadsBackup();
1358 }
1359
1360 /**
1361 * Check if Plugin is Pro version
1362 * @return bool
1363 */
1364 protected function isPro()
1365 {
1366 if (!defined("WPSTGPRO_VERSION")) {
1367 return false;
1368 }
1369
1370 return true;
1371 }
1372
1373 /**
1374 * Check if current page is plugins.php
1375 * @global array $pagenow
1376 * @return bool
1377 */
1378 private function isPluginsPage()
1379 {
1380 global $pagenow;
1381 return ($pagenow === 'plugins.php');
1382 }
1383 }
1384