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