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