WP Staging – DB & File Duplicator & Migration - Version 2.2.0

Version Description

  • Fix: Old staging site is not listed and pushing is not working properly if plugin is updated from wp staging version 1.6 and lower
Download this release

Release Info

Developer ReneHermi
Plugin Icon 128x128 WP Staging – DB & File Duplicator & Migration
Version 2.2.0
Comparing to
See all releases

Code changes from version 2.1.8 to 2.2.0

Files changed (39) hide show
  1. apps/Backend/Administrator.php +695 -695
  2. apps/Backend/Modules/Jobs/Cancel.php +74 -74
  3. apps/Backend/Modules/Jobs/CancelUpdate.php +90 -90
  4. apps/Backend/Modules/Jobs/Cloning.php +249 -249
  5. apps/Backend/Modules/Jobs/Data.php +459 -408
  6. apps/Backend/Modules/Jobs/Database.php +264 -262
  7. apps/Backend/Modules/Jobs/Delete.php +497 -497
  8. apps/Backend/Modules/Jobs/Directories.php +428 -451
  9. apps/Backend/Modules/Jobs/Files.php +366 -365
  10. apps/Backend/Modules/Jobs/Finish.php +120 -261
  11. apps/Backend/Modules/Jobs/Job.php +487 -484
  12. apps/Backend/Modules/Jobs/JobExecutable.php +111 -111
  13. apps/Backend/Modules/Jobs/Scan.php +406 -401
  14. apps/Backend/Modules/Jobs/Updating.php +248 -261
  15. apps/Backend/Modules/SystemInfo.php +512 -512
  16. apps/Backend/Modules/Views/Forms/Settings.php +219 -219
  17. apps/Backend/Notices/Notices.php +154 -154
  18. apps/Backend/Upgrade/Upgrade.php +316 -229
  19. apps/Backend/public/css/wpstg-admin.css +783 -783
  20. apps/Backend/public/js/wpstg-admin-rating.js +31 -31
  21. apps/Backend/public/js/wpstg-admin.js +1177 -1260
  22. apps/Backend/views/_includes/messages/beta.php +19 -19
  23. apps/Backend/views/_includes/messages/rating.php +30 -30
  24. apps/Backend/views/_includes/messages/wp-version-compatible-message.php +12 -12
  25. apps/Backend/views/clone/ajax/scan.php +128 -128
  26. apps/Backend/views/clone/ajax/single-overview.php +55 -55
  27. apps/Backend/views/clone/ajax/start.php +112 -112
  28. apps/Backend/views/clone/ajax/update.php +45 -45
  29. apps/Backend/views/settings/index.php +1 -1
  30. apps/Core/Iterators/RecursiveDirectoryIterator.php +52 -52
  31. apps/Core/Iterators/RecursiveFilterExclude.php +23 -23
  32. apps/Core/Iterators/RecursiveFilterNewLine.php +21 -21
  33. apps/Core/Utils/Cache.php +211 -211
  34. apps/Core/Utils/Strings.php +27 -0
  35. apps/Core/WPStaging.php +429 -429
  36. package-lock.json +0 -3333
  37. readme.txt +317 -301
  38. uninstall.php +89 -89
  39. wp-staging.php +91 -91
apps/Backend/Administrator.php CHANGED
@@ -1,695 +1,695 @@
1
- <?php
2
-
3
- namespace WPStaging\Backend;
4
-
5
- // No Direct Access
6
- if( !defined( "WPINC" ) ) {
7
- die;
8
- }
9
-
10
- use WPStaging\Backend\Modules\Jobs\Cancel;
11
- use WPStaging\Backend\Modules\Jobs\CancelUpdate;
12
- use WPStaging\Backend\Modules\Jobs\Cloning;
13
- use WPStaging\Backend\Modules\Jobs\Updating;
14
- use WPStaging\Backend\Modules\Jobs\Data;
15
- use WPStaging\Backend\Modules\Jobs\Database;
16
- use WPStaging\Backend\Modules\Jobs\Delete;
17
- use WPStaging\Backend\Modules\Jobs\Files;
18
- use WPStaging\Backend\Modules\Jobs\Scan;
19
- use WPStaging\Backend\Modules\Jobs\Logs;
20
- use WPStaging\Backend\Modules\Optimizer;
21
- use WPStaging\Backend\Modules\SystemInfo;
22
- use WPStaging\Backend\Modules\Views\Tabs\Tabs;
23
- use WPStaging\Backend\Notices\Notices;
24
- use WPStaging\DI\InjectionAware;
25
- use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
26
- use WPStaging\Backend\Activation;
27
- use WPStaging\WPStaging;
28
- use WPStaging\Backend\Pro\Modules\Jobs\Processing;
29
- use WPStaging\Backend\Pro\Licensing;
30
-
31
- /**
32
- * Class Administrator
33
- * @package WPStaging\Backend
34
- */
35
- class Administrator extends InjectionAware {
36
-
37
- /**
38
- * @var string
39
- */
40
- private $path;
41
-
42
- /**
43
- * @var string
44
- */
45
- private $url;
46
-
47
- /**
48
- * Initialize class
49
- */
50
- public function initialize() {
51
- $this->defineHooks();
52
-
53
- // Path to backend
54
- $this->path = plugin_dir_path( __FILE__ );
55
-
56
- // URL to public backend folder
57
- $this->url = plugin_dir_url( __FILE__ ) . "public/";
58
-
59
- // Load plugins meta data
60
- $this->loadMeta();
61
- }
62
-
63
- /**
64
- * Load plugn meta data
65
- */
66
- public function loadMeta() {
67
- $run = new \WPStaging\Backend\Pluginmeta\Pluginmeta();
68
- }
69
-
70
- /**
71
- * Define Hooks
72
- */
73
- private function defineHooks() {
74
- // Get loader
75
- $loader = $this->di->get( "loader" );
76
-
77
- $Activation = new \WPStaging\Backend\Activation\Activation();
78
-
79
- $Welcome = new Activation\Welcome();
80
-
81
- $loader->addAction( "activated_plugin", $Activation, 'deactivate_other_instances' );
82
- $loader->addAction( "admin_menu", $this, "addMenu", 10 );
83
- $loader->addAction( "admin_init", $this, "setOptionFormElements" );
84
- $loader->addAction( "admin_init", $this, "upgrade" );
85
- $loader->addAction( "admin_post_wpstg_download_sysinfo", $this, "systemInfoDownload" );
86
- $loader->addAction( "admin_post_wpstg_export", $this, "export" );
87
- $loader->addAction( "admin_post_wpstg_import_settings", $this, "import" );
88
- $loader->addAction( "admin_notices", $this, "messages" );
89
-
90
- // Ajax Requests
91
- $loader->addAction( "wp_ajax_wpstg_overview", $this, "ajaxOverview" );
92
- $loader->addAction( "wp_ajax_wpstg_scanning", $this, "ajaxScan" );
93
- $loader->addAction( "wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName" );
94
- //$loader->addAction( "wp_ajax_wpstg_update_struc", $this, "ajaxStartUpdate" );
95
- $loader->addAction( "wp_ajax_wpstg_update", $this, "ajaxUpdateProcess" );
96
- $loader->addAction( "wp_ajax_wpstg_cloning", $this, "ajaxStartClone" );
97
- $loader->addAction( "wp_ajax_wpstg_clone_database", $this, "ajaxCloneDatabase" );
98
- $loader->addAction( "wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories" );
99
- $loader->addAction( "wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles" );
100
- $loader->addAction( "wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData" );
101
- $loader->addAction( "wp_ajax_wpstg_clone_finish", $this, "ajaxFinish" );
102
- $loader->addAction( "wp_ajax_wpstg_confirm_delete_clone", $this, "ajaxDeleteConfirmation" );
103
- $loader->addAction( "wp_ajax_wpstg_delete_clone", $this, "ajaxDeleteClone" );
104
- $loader->addAction( "wp_ajax_wpstg_cancel_clone", $this, "ajaxCancelClone" );
105
- $loader->addAction( "wp_ajax_wpstg_cancel_update", $this, "ajaxCancelUpdate" );
106
- $loader->addAction( "wp_ajax_wpstg_hide_poll", $this, "ajaxHidePoll" );
107
- $loader->addAction( "wp_ajax_wpstg_hide_rating", $this, "ajaxHideRating" );
108
- $loader->addAction( "wp_ajax_wpstg_hide_beta", $this, "ajaxHideBeta" );
109
- $loader->addAction( "wp_ajax_wpstg_logs", $this, "ajaxLogs" );
110
- $loader->addAction( "wp_ajax_wpstg_check_disk_space", $this, "ajaxCheckFreeSpace" );
111
-
112
- // Ajax hooks pro Version
113
- $loader->addAction( "wp_ajax_wpstg_scan", $this, "ajaxPushScan" );
114
- $loader->addAction( "wp_ajax_wpstg_push_processing", $this, "ajaxPushProcessing" );
115
- //$loader->addAction( "wp_ajax_wpstg_copy_database", $this, "ajaxCopyDatabase" );
116
- }
117
-
118
- /**
119
- * Register options form elements
120
- */
121
- public function setOptionFormElements() {
122
- register_setting( "wpstg_settings", "wpstg_settings", array($this, "sanitizeOptions") );
123
- }
124
-
125
- /**
126
- * Upgrade routine
127
- */
128
- public function upgrade() {
129
- $upgrade = new Upgrade\Upgrade();
130
- $upgrade->doUpgrade();
131
- }
132
-
133
- /**
134
- * Sanitize options data and delete the cache
135
- * @param array $data
136
- * @return array
137
- */
138
- public function sanitizeOptions( $data = array() ) {
139
- $sanitized = $this->sanitizeData( $data );
140
-
141
- add_settings_error( "wpstg-notices", '', __( "Settings updated.", "wpstg" ), "updated" );
142
-
143
- // Return sanitized data
144
- //return $sanitized;
145
- return apply_filters( "wpstg-settings", $sanitized, $data );
146
- }
147
-
148
- /**
149
- * @param array $data
150
- * @return array
151
- */
152
- private function sanitizeData( $data = array() ) {
153
- $sanitized = array();
154
-
155
- foreach ( $data as $key => $value ) {
156
- $sanitized[$key] = (is_array( $value )) ? $this->sanitizeData( $value ) : htmlspecialchars( $value );
157
- }
158
-
159
- return $sanitized;
160
- }
161
-
162
- /**
163
- * Add Admin Menu(s)
164
- */
165
- public function addMenu() {
166
-
167
- $logo = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiIGZpbGw9Im5vbmUiPgo8Zz48Zz48cGF0aCBzdHlsZT0iZmlsbDojZmZmIiAgZD0iTTEzNy42LDU2MS4zSDEzLjhIMTB2MzA2LjNsOTAuNy04My40QzE4OS42LDkwOC43LDMzNS4zLDk5MCw1MDAsOTkwYzI0OS45LDAsNDU2LjEtMTg3LjEsNDg2LjItNDI4LjhIODYyLjRDODMzLjMsNzM1LjEsNjgyLjEsODY3LjUsNTAwLDg2Ny41Yy0xMjksMC0yNDIuNS02Ni41LTMwOC4xLTE2Ny4ybDE1MS4zLTEzOS4xSDEzNy42eiIvPjxwYXRoIHN0eWxlPSJmaWxsOiNmZmYiICBkPSJNNTAwLDEwQzI1MC4xLDEwLDQzLjksMTk3LjEsMTMuOCw0MzguOGgxMjMuOEMxNjYuNywyNjQuOSwzMTcuOSwxMzIuNSw1MDAsMTMyLjVjMTMyLjksMCwyNDkuMyw3MC41LDMxMy44LDE3Ni4yTDY4My44LDQzOC44aDEyMi41aDU2LjJoMTIzLjhoMy44VjEzMi41bC04Ny43LDg3LjdDODEzLjgsOTMuMSw2NjYuNiwxMCw1MDAsMTB6Ii8+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvZz4KPC9zdmc+';
168
-
169
- // Main WP Staging Menu
170
- add_menu_page(
171
- "WP-Staging", __( "WP Staging", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage"), $logo
172
- );
173
-
174
- // Page: Clone
175
- add_submenu_page(
176
- "wpstg_clone", __( "WP Staging Jobs", "wpstg" ), __( "Start", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage")
177
- );
178
-
179
- // Page: Settings
180
- add_submenu_page(
181
- "wpstg_clone", __( "WP Staging Settings", "wpstg" ), __( "Settings", "wpstg" ), "manage_options", "wpstg-settings", array($this, "getSettingsPage")
182
- );
183
-
184
- // Page: Tools
185
- add_submenu_page(
186
- "wpstg_clone", __( "WP Staging Tools", "wpstg" ), __( "Tools", "wpstg" ), "manage_options", "wpstg-tools", array($this, "getToolsPage")
187
- );
188
- // Page: Tools
189
- add_submenu_page(
190
- "wpstg_clone", __( "WP Staging Welcome", "wpstg" ), __( "Get WP Staging Pro", "wpstg" ), "manage_options", "wpstg-welcome", array($this, "getWelcomePage")
191
- );
192
-
193
- if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
194
- // Page: License
195
- add_submenu_page(
196
- "wpstg_clone", __( "WP Staging License", "wpstg" ), __( "License", "wpstg" ), "manage_options", "wpstg-license", array($this, "getLicensePage")
197
- );
198
- }
199
- }
200
-
201
- /**
202
- * Settings Page
203
- */
204
- public function getSettingsPage() {
205
- // Tabs
206
- $tabs = new Tabs( array(
207
- "general" => __( "General", "wpstg" )
208
- ) );
209
-
210
-
211
- $this->di
212
- // Set tabs
213
- ->set( "tabs", $tabs )
214
- // Forms
215
- ->set( "forms", new FormSettings( $tabs ) );
216
-
217
- require_once "{$this->path}views/settings/index.php";
218
- }
219
-
220
- /**
221
- * Clone Page
222
- */
223
- public function getClonePage() {
224
- // Existing clones
225
- $availableClones = get_option( "wpstg_existing_clones_beta", array() );
226
-
227
- require_once "{$this->path}views/clone/index.php";
228
- }
229
-
230
- /**
231
- * Welcome Page
232
- */
233
- public function getWelcomePage() {
234
- require_once "{$this->path}views/welcome/welcome.php";
235
- }
236
-
237
- /**
238
- * Tools Page
239
- */
240
- public function getToolsPage() {
241
- // Tabs
242
- $tabs = new Tabs( array(
243
- "import_export" => __( "Import/Export", "wpstg" ),
244
- "system_info" => __( "System Info", "wpstg" )
245
- ) );
246
-
247
- $this->di->set( "tabs", $tabs );
248
-
249
- $this->di->set( "systemInfo", new SystemInfo( $this->di ) );
250
-
251
- require_once "{$this->path}views/tools/index.php";
252
- }
253
-
254
- /**
255
- * System Information Download
256
- */
257
- public function systemInfoDownload() {
258
- if( !current_user_can( "update_plugins" ) ) {
259
- return;
260
- }
261
-
262
- nocache_headers();
263
- header( "Content-Type: text/plain" );
264
- header( "Content-Disposition: attachment; filename='wpstg-system-info.txt'" );
265
- echo wp_strip_all_tags( new SystemInfo( $this->di ) );
266
- }
267
-
268
- /**
269
- * Import JSON settings file
270
- */
271
- public function import() {
272
- if( empty( $_POST["wpstg_import_nonce"] ) ) {
273
- return;
274
- }
275
-
276
- if( !wp_verify_nonce( $_POST["wpstg_import_nonce"], "wpstg_import_nonce" ) ) {
277
- return;
278
- }
279
-
280
- if( !current_user_can( "update_plugins" ) ) {
281
- return;
282
- }
283
-
284
- $fileExtension = explode( '.', $_FILES["import_file"]["name"] );
285
- $fileExtension = end( $fileExtension );
286
- if( "json" !== $fileExtension ) {
287
- wp_die( "Please upload a valid .json file", "wpstg" );
288
- }
289
-
290
-
291
- $importFile = $_FILES["import_file"]["tmp_name"];
292
-
293
- if( empty( $importFile ) ) {
294
- wp_die( __( "Please upload a file to import", "wpstg" ) );
295
- }
296
-
297
- update_option( "wpstg_settings", json_decode( file_get_contents( $importFile, true ) ) );
298
-
299
- wp_safe_redirect( admin_url( "admin.php?page=wpstg-tools&amp;wpstg-message=settings-imported" ) );
300
-
301
- return;
302
- }
303
-
304
- /**
305
- * Export settings to JSON file
306
- */
307
- public function export() {
308
- if( empty( $_POST["wpstg_export_nonce"] ) ) {
309
- return;
310
- }
311
-
312
- if( !wp_verify_nonce( $_POST["wpstg_export_nonce"], "wpstg_export_nonce" ) ) {
313
- return;
314
- }
315
-
316
- if( !current_user_can( "manage_options" ) ) {
317
- return;
318
- }
319
-
320
- $settings = get_option( "wpstg_settings", array() );
321
-
322
- ignore_user_abort( true );
323
-
324
- if( !in_array( "set_time_limit", explode( ',', ini_get( "disable_functions" ) ) ) && !@ini_get( "safe_mode" ) ) {
325
- set_time_limit( 0 );
326
- }
327
-
328
- $fileName = apply_filters( "wpstg_settings_export_filename", "wpstg-settings-export-" . date( "m-d-Y" ) ) . ".json";
329
-
330
- nocache_headers();
331
- header( "Content-Type: application/json; charset=utf-8" );
332
- header( "Content-Disposition: attachment; filename={$fileName}" );
333
- header( "Expires: 0" );
334
-
335
- echo json_encode( $settings );
336
- }
337
-
338
- /**
339
- * Render a view file
340
- * @param string $file
341
- * @param array $vars
342
- * @return string
343
- */
344
- public function render( $file, $vars = array() ) {
345
- $fullPath = $this->path . "views" . DIRECTORY_SEPARATOR;
346
- $fullPath = str_replace( array('/', "\\"), DIRECTORY_SEPARATOR, $fullPath . $file . ".php" );
347
-
348
- if( !file_exists( $fullPath ) || !is_readable( $fullPath ) ) {
349
- return "Can't render : {$fullPath} either file doesn't exist or can't read it";
350
- }
351
-
352
- $contents = @file_get_contents( $fullPath );
353
-
354
- // Variables are set
355
- if( count( $vars ) > 0 ) {
356
- $vars = array_combine(
357
- array_map( function ($key) {
358
- return "{{" . $key . "}}";
359
- }, array_keys( $vars )
360
- ), $vars
361
- );
362
-
363
- $contents = str_replace( array_keys( $vars ), array_values( $vars ), $contents );
364
- }
365
-
366
- return $contents;
367
- }
368
-
369
- /**
370
- * Ajax Overview
371
- */
372
- public function ajaxOverview() {
373
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
374
-
375
- // Existing clones
376
- $availableClones = get_option( "wpstg_existing_clones_beta", array() );
377
-
378
- // Get license data
379
- $license = get_option( 'wpstg_license_status' );
380
-
381
-
382
- if( \WPStaging\WPStaging::getSlug() === 'wp-staging-pro' ) {
383
- require_once "{$this->path}Pro/views/single-overview-pro.php";
384
- } else {
385
- require_once "{$this->path}views/clone/ajax/single-overview.php";
386
- }
387
-
388
- wp_die();
389
- }
390
-
391
- /**
392
- * Ajax Scan
393
- */
394
- public function ajaxScan() {
395
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
396
-
397
- // Scan
398
- $scan = new Scan();
399
- $scan->start();
400
-
401
- // Get Options
402
- $options = $scan->getOptions();
403
-
404
- require_once "{$this->path}views/clone/ajax/scan.php";
405
-
406
- wp_die();
407
- }
408
-
409
- /**
410
- * Ajax Check Clone Name
411
- */
412
- public function ajaxCheckCloneName() {
413
- $cloneName = sanitize_key( $_POST["cloneID"] );
414
- $cloneNameLength = strlen( $cloneName );
415
- $clones = get_option( "wpstg_existing_clones_beta", array() );
416
-
417
- // Check clone name length
418
- if( $cloneNameLength < 1 || $cloneNameLength > 16 ) {
419
- echo wp_send_json( array(
420
- "status" => "failed",
421
- "message" => "Clone name must be between 1 - 16 characters"
422
- ) );
423
- } elseif( array_key_exists( $cloneName, $clones ) ) {
424
- echo wp_send_json( array(
425
- "status" => "failed",
426
- "message" => "Clone name is already in use, please choose an another clone name"
427
- ) );
428
- }
429
-
430
- echo wp_send_json( array("status" => "success") );
431
- }
432
-
433
-
434
-
435
-
436
- /**
437
- * Ajax Start Updating Clone (Basically just layout and saving data)
438
- */
439
- // public function ajaxStartUpdate() {
440
- // check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
441
- //
442
- // $cloning = new Updating();
443
- //
444
- // if( !$cloning->save() ) {
445
- // wp_die('can not save clone data');
446
- // }
447
- //
448
- // require_once "{$this->path}views/clone/ajax/update.php";
449
- //
450
- // wp_die();
451
- // }
452
- /**
453
- * Ajax Start Updating Clone (Basically just layout and saving data)
454
- */
455
- public function ajaxUpdateProcess() {
456
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
457
-
458
- $cloning = new Updating();
459
-
460
- if( !$cloning->save() ) {
461
- wp_die('can not save clone data');
462
- }
463
-
464
- require_once "{$this->path}views/clone/ajax/update.php";
465
-
466
- wp_die();
467
-
468
- //wp_send_json( $cloning->start() );
469
- }
470
- /**
471
- * Ajax Start Clone (Basically just layout and saving data)
472
- */
473
- public function ajaxStartClone() {
474
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
475
-
476
- $cloning = new Cloning();
477
-
478
- if( !$cloning->save() ) {
479
- wp_die('can not save clone data');
480
- }
481
-
482
- require_once "{$this->path}views/clone/ajax/start.php";
483
-
484
- wp_die();
485
- }
486
-
487
- /**
488
- * Ajax Clone Database
489
- */
490
- public function ajaxCloneDatabase() {
491
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
492
-
493
- $cloning = new Cloning();
494
-
495
- wp_send_json( $cloning->start() );
496
- }
497
-
498
- /**
499
- * Ajax Prepare Directories (get listing of files)
500
- */
501
- public function ajaxPrepareDirectories() {
502
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
503
-
504
- $cloning = new Cloning();
505
-
506
- wp_send_json( $cloning->start() );
507
- }
508
-
509
- /**
510
- * Ajax Clone Files
511
- */
512
- public function ajaxCopyFiles() {
513
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
514
-
515
- $cloning = new Cloning();
516
-
517
- wp_send_json( $cloning->start() );
518
- }
519
-
520
- /**
521
- * Ajax Replace Data
522
- */
523
- public function ajaxReplaceData() {
524
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
525
-
526
- $cloning = new Cloning();
527
-
528
- wp_send_json( $cloning->start() );
529
- }
530
-
531
- /**
532
- * Ajax Finish
533
- */
534
- public function ajaxFinish() {
535
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
536
-
537
- $cloning = new Cloning();
538
-
539
- wp_send_json( $cloning->start() );
540
- }
541
-
542
- /**
543
- * Ajax Delete Confirmation
544
- */
545
- public function ajaxDeleteConfirmation() {
546
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
547
-
548
- $delete = new Delete();
549
- $delete->setData();
550
-
551
- $clone = $delete->getClone();
552
-
553
- require_once "{$this->path}views/clone/ajax/delete-confirmation.php";
554
-
555
- wp_die();
556
- }
557
-
558
- /**
559
- * Delete clone
560
- */
561
- public function ajaxDeleteClone() {
562
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
563
-
564
- $delete = new Delete();
565
- wp_send_json( $delete->start() );
566
- }
567
-
568
- /**
569
- * Delete clone
570
- */
571
- public function ajaxCancelClone() {
572
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
573
-
574
- $cancel = new Cancel();
575
- wp_send_json( $cancel->start() );
576
- }
577
-
578
- /**
579
- * Cancel updating process / Do not delete clone!
580
- */
581
- public function ajaxCancelUpdate() {
582
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
583
-
584
- $cancel = new CancelUpdate();
585
- wp_send_json( $cancel->start() );
586
- }
587
-
588
- /**
589
- * Admin Messages
590
- */
591
- public function messages() {
592
- $notice = new Notices( $this->path, $this->url );
593
-
594
- $run = $notice->messages();
595
- }
596
-
597
- /**
598
- * Ajax Hide Poll
599
- * @return mixed boolean | json
600
- */
601
- public function ajaxHidePoll() {
602
- if( false !== update_option( "wpstg_poll", "no" ) ) {
603
- wp_send_json( true );
604
- }
605
- return wp_send_json();
606
- }
607
-
608
- /**
609
- * Ajax Hide Rating
610
- * @return mixed bool | json
611
- */
612
- public function ajaxHideRating() {
613
- if( false !== update_option( "wpstg_rating", "no" ) ) {
614
- wp_send_json( true );
615
- }
616
- return wp_send_json();
617
- }
618
-
619
- /**
620
- * Ajax Hide Beta
621
- */
622
- public function ajaxHideBeta() {
623
- wp_send_json( update_option( "wpstg_beta", "no" ) );
624
- }
625
-
626
- /**
627
- * Clone logs
628
- */
629
- public function ajaxLogs() {
630
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
631
-
632
- $logs = new Logs();
633
- wp_send_json( $logs->start() );
634
- }
635
-
636
- /**
637
- * Ajax Checks Free Disk Space
638
- */
639
- public function ajaxCheckFreeSpace() {
640
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
641
-
642
- $scan = new Scan();
643
- return $scan->hasFreeDiskSpace();
644
- }
645
-
646
- /**
647
- * Ajax Start Push Changes Process
648
- * Start with the module Scan
649
- */
650
- public function ajaxPushScan() {
651
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
652
-
653
- if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Scan' ) ) {
654
- return false;
655
- }
656
-
657
- // Scan
658
- $scan = new Pro\Modules\Jobs\Scan();
659
-
660
- $scan->start();
661
-
662
- // Get Options
663
- $options = $scan->getOptions();
664
-
665
- require_once "{$this->path}Pro/views/scan.php";
666
-
667
- wp_die();
668
- }
669
-
670
- /**
671
- * Ajax Start Pushing. Needs wp quads pro)
672
- */
673
- public function ajaxPushProcessing() {
674
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
675
-
676
- if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Processing' ) ) {
677
- return false;
678
- }
679
- // Start the process
680
- $processing = new Processing();
681
- wp_send_json( $processing->start() );
682
- }
683
-
684
- /**
685
- * License Page
686
- */
687
- public function getLicensePage() {
688
-
689
- // Get license data
690
- $license = get_option( 'wpstg_license_status' );
691
-
692
- require_once "{$this->path}Pro/views/licensing.php";
693
- }
694
-
695
- }
1
+ <?php
2
+
3
+ namespace WPStaging\Backend;
4
+
5
+ // No Direct Access
6
+ if( !defined( "WPINC" ) ) {
7
+ die;
8
+ }
9
+
10
+ use WPStaging\Backend\Modules\Jobs\Cancel;
11
+ use WPStaging\Backend\Modules\Jobs\CancelUpdate;
12
+ use WPStaging\Backend\Modules\Jobs\Cloning;
13
+ use WPStaging\Backend\Modules\Jobs\Updating;
14
+ use WPStaging\Backend\Modules\Jobs\Data;
15
+ use WPStaging\Backend\Modules\Jobs\Database;
16
+ use WPStaging\Backend\Modules\Jobs\Delete;
17
+ use WPStaging\Backend\Modules\Jobs\Files;
18
+ use WPStaging\Backend\Modules\Jobs\Scan;
19
+ use WPStaging\Backend\Modules\Jobs\Logs;
20
+ use WPStaging\Backend\Modules\Optimizer;
21
+ use WPStaging\Backend\Modules\SystemInfo;
22
+ use WPStaging\Backend\Modules\Views\Tabs\Tabs;
23
+ use WPStaging\Backend\Notices\Notices;
24
+ use WPStaging\DI\InjectionAware;
25
+ use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
26
+ use WPStaging\Backend\Activation;
27
+ use WPStaging\WPStaging;
28
+ use WPStaging\Backend\Pro\Modules\Jobs\Processing;
29
+ use WPStaging\Backend\Pro\Licensing;
30
+
31
+ /**
32
+ * Class Administrator
33
+ * @package WPStaging\Backend
34
+ */
35
+ class Administrator extends InjectionAware {
36
+
37
+ /**
38
+ * @var string
39
+ */
40
+ private $path;
41
+
42
+ /**
43
+ * @var string
44
+ */
45
+ private $url;
46
+
47
+ /**
48
+ * Initialize class
49
+ */
50
+ public function initialize() {
51
+ $this->defineHooks();
52
+
53
+ // Path to backend
54
+ $this->path = plugin_dir_path( __FILE__ );
55
+
56
+ // URL to public backend folder
57
+ $this->url = plugin_dir_url( __FILE__ ) . "public/";
58
+
59
+ // Load plugins meta data
60
+ $this->loadMeta();
61
+ }
62
+
63
+ /**
64
+ * Load plugn meta data
65
+ */
66
+ public function loadMeta() {
67
+ $run = new \WPStaging\Backend\Pluginmeta\Pluginmeta();
68
+ }
69
+
70
+ /**
71
+ * Define Hooks
72
+ */
73
+ private function defineHooks() {
74
+ // Get loader
75
+ $loader = $this->di->get( "loader" );
76
+
77
+ $Activation = new \WPStaging\Backend\Activation\Activation();
78
+
79
+ $Welcome = new Activation\Welcome();
80
+
81
+ $loader->addAction( "activated_plugin", $Activation, 'deactivate_other_instances' );
82
+ $loader->addAction( "admin_menu", $this, "addMenu", 10 );
83
+ $loader->addAction( "admin_init", $this, "setOptionFormElements" );
84
+ $loader->addAction( "admin_init", $this, "upgrade" );
85
+ $loader->addAction( "admin_post_wpstg_download_sysinfo", $this, "systemInfoDownload" );
86
+ $loader->addAction( "admin_post_wpstg_export", $this, "export" );
87
+ $loader->addAction( "admin_post_wpstg_import_settings", $this, "import" );
88
+ $loader->addAction( "admin_notices", $this, "messages" );
89
+
90
+ // Ajax Requests
91
+ $loader->addAction( "wp_ajax_wpstg_overview", $this, "ajaxOverview" );
92
+ $loader->addAction( "wp_ajax_wpstg_scanning", $this, "ajaxScan" );
93
+ $loader->addAction( "wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName" );
94
+ //$loader->addAction( "wp_ajax_wpstg_update_struc", $this, "ajaxStartUpdate" );
95
+ $loader->addAction( "wp_ajax_wpstg_update", $this, "ajaxUpdateProcess" );
96
+ $loader->addAction( "wp_ajax_wpstg_cloning", $this, "ajaxStartClone" );
97
+ $loader->addAction( "wp_ajax_wpstg_clone_database", $this, "ajaxCloneDatabase" );
98
+ $loader->addAction( "wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories" );
99
+ $loader->addAction( "wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles" );
100
+ $loader->addAction( "wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData" );
101
+ $loader->addAction( "wp_ajax_wpstg_clone_finish", $this, "ajaxFinish" );
102
+ $loader->addAction( "wp_ajax_wpstg_confirm_delete_clone", $this, "ajaxDeleteConfirmation" );
103
+ $loader->addAction( "wp_ajax_wpstg_delete_clone", $this, "ajaxDeleteClone" );
104
+ $loader->addAction( "wp_ajax_wpstg_cancel_clone", $this, "ajaxCancelClone" );
105
+ $loader->addAction( "wp_ajax_wpstg_cancel_update", $this, "ajaxCancelUpdate" );
106
+ $loader->addAction( "wp_ajax_wpstg_hide_poll", $this, "ajaxHidePoll" );
107
+ $loader->addAction( "wp_ajax_wpstg_hide_rating", $this, "ajaxHideRating" );
108
+ $loader->addAction( "wp_ajax_wpstg_hide_beta", $this, "ajaxHideBeta" );
109
+ $loader->addAction( "wp_ajax_wpstg_logs", $this, "ajaxLogs" );
110
+ $loader->addAction( "wp_ajax_wpstg_check_disk_space", $this, "ajaxCheckFreeSpace" );
111
+
112
+ // Ajax hooks pro Version
113
+ $loader->addAction( "wp_ajax_wpstg_scan", $this, "ajaxPushScan" );
114
+ $loader->addAction( "wp_ajax_wpstg_push_processing", $this, "ajaxPushProcessing" );
115
+ //$loader->addAction( "wp_ajax_wpstg_copy_database", $this, "ajaxCopyDatabase" );
116
+ }
117
+
118
+ /**
119
+ * Register options form elements
120
+ */
121
+ public function setOptionFormElements() {
122
+ register_setting( "wpstg_settings", "wpstg_settings", array($this, "sanitizeOptions") );
123
+ }
124
+
125
+ /**
126
+ * Upgrade routine
127
+ */
128
+ public function upgrade() {
129
+ $upgrade = new Upgrade\Upgrade();
130
+ $upgrade->doUpgrade();
131
+ }
132
+
133
+ /**
134
+ * Sanitize options data and delete the cache
135
+ * @param array $data
136
+ * @return array
137
+ */
138
+ public function sanitizeOptions( $data = array() ) {
139
+ $sanitized = $this->sanitizeData( $data );
140
+
141
+ add_settings_error( "wpstg-notices", '', __( "Settings updated.", "wpstg" ), "updated" );
142
+
143
+ // Return sanitized data
144
+ //return $sanitized;
145
+ return apply_filters( "wpstg-settings", $sanitized, $data );
146
+ }
147
+
148
+ /**
149
+ * @param array $data
150
+ * @return array
151
+ */
152
+ private function sanitizeData( $data = array() ) {
153
+ $sanitized = array();
154
+
155
+ foreach ( $data as $key => $value ) {
156
+ $sanitized[$key] = (is_array( $value )) ? $this->sanitizeData( $value ) : htmlspecialchars( $value );
157
+ }
158
+
159
+ return $sanitized;
160
+ }
161
+
162
+ /**
163
+ * Add Admin Menu(s)
164
+ */
165
+ public function addMenu() {
166
+
167
+ $logo = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiIGZpbGw9Im5vbmUiPgo8Zz48Zz48cGF0aCBzdHlsZT0iZmlsbDojZmZmIiAgZD0iTTEzNy42LDU2MS4zSDEzLjhIMTB2MzA2LjNsOTAuNy04My40QzE4OS42LDkwOC43LDMzNS4zLDk5MCw1MDAsOTkwYzI0OS45LDAsNDU2LjEtMTg3LjEsNDg2LjItNDI4LjhIODYyLjRDODMzLjMsNzM1LjEsNjgyLjEsODY3LjUsNTAwLDg2Ny41Yy0xMjksMC0yNDIuNS02Ni41LTMwOC4xLTE2Ny4ybDE1MS4zLTEzOS4xSDEzNy42eiIvPjxwYXRoIHN0eWxlPSJmaWxsOiNmZmYiICBkPSJNNTAwLDEwQzI1MC4xLDEwLDQzLjksMTk3LjEsMTMuOCw0MzguOGgxMjMuOEMxNjYuNywyNjQuOSwzMTcuOSwxMzIuNSw1MDAsMTMyLjVjMTMyLjksMCwyNDkuMyw3MC41LDMxMy44LDE3Ni4yTDY4My44LDQzOC44aDEyMi41aDU2LjJoMTIzLjhoMy44VjEzMi41bC04Ny43LDg3LjdDODEzLjgsOTMuMSw2NjYuNiwxMCw1MDAsMTB6Ii8+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvZz4KPC9zdmc+';
168
+
169
+ // Main WP Staging Menu
170
+ add_menu_page(
171
+ "WP-Staging", __( "WP Staging", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage"), $logo
172
+ );
173
+
174
+ // Page: Clone
175
+ add_submenu_page(
176
+ "wpstg_clone", __( "WP Staging Jobs", "wpstg" ), __( "Sites / Start", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage")
177
+ );
178
+
179
+ // Page: Settings
180
+ add_submenu_page(
181
+ "wpstg_clone", __( "WP Staging Settings", "wpstg" ), __( "Settings", "wpstg" ), "manage_options", "wpstg-settings", array($this, "getSettingsPage")
182
+ );
183
+
184
+ // Page: Tools
185
+ add_submenu_page(
186
+ "wpstg_clone", __( "WP Staging Tools", "wpstg" ), __( "Tools", "wpstg" ), "manage_options", "wpstg-tools", array($this, "getToolsPage")
187
+ );
188
+ // Page: Tools
189
+ add_submenu_page(
190
+ "wpstg_clone", __( "WP Staging Welcome", "wpstg" ), __( "Get WP Staging Pro", "wpstg" ), "manage_options", "wpstg-welcome", array($this, "getWelcomePage")
191
+ );
192
+
193
+ if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
194
+ // Page: License
195
+ add_submenu_page(
196
+ "wpstg_clone", __( "WP Staging License", "wpstg" ), __( "License", "wpstg" ), "manage_options", "wpstg-license", array($this, "getLicensePage")
197
+ );
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Settings Page
203
+ */
204
+ public function getSettingsPage() {
205
+ // Tabs
206
+ $tabs = new Tabs( array(
207
+ "general" => __( "General", "wpstg" )
208
+ ) );
209
+
210
+
211
+ $this->di
212
+ // Set tabs
213
+ ->set( "tabs", $tabs )
214
+ // Forms
215
+ ->set( "forms", new FormSettings( $tabs ) );
216
+
217
+ require_once "{$this->path}views/settings/index.php";
218
+ }
219
+
220
+ /**
221
+ * Clone Page
222
+ */
223
+ public function getClonePage() {
224
+ // Existing clones
225
+ $availableClones = get_option( "wpstg_existing_clones_beta", array() );
226
+
227
+ require_once "{$this->path}views/clone/index.php";
228
+ }
229
+
230
+ /**
231
+ * Welcome Page
232
+ */
233
+ public function getWelcomePage() {
234
+ require_once "{$this->path}views/welcome/welcome.php";
235
+ }
236
+
237
+ /**
238
+ * Tools Page
239
+ */
240
+ public function getToolsPage() {
241
+ // Tabs
242
+ $tabs = new Tabs( array(
243
+ "import_export" => __( "Import/Export", "wpstg" ),
244
+ "system_info" => __( "System Info", "wpstg" )
245
+ ) );
246
+
247
+ $this->di->set( "tabs", $tabs );
248
+
249
+ $this->di->set( "systemInfo", new SystemInfo( $this->di ) );
250
+
251
+ require_once "{$this->path}views/tools/index.php";
252
+ }
253
+
254
+ /**
255
+ * System Information Download
256
+ */
257
+ public function systemInfoDownload() {
258
+ if( !current_user_can( "update_plugins" ) ) {
259
+ return;
260
+ }
261
+
262
+ nocache_headers();
263
+ header( "Content-Type: text/plain" );
264
+ header( "Content-Disposition: attachment; filename='wpstg-system-info.txt'" );
265
+ echo wp_strip_all_tags( new SystemInfo( $this->di ) );
266
+ }
267
+
268
+ /**
269
+ * Import JSON settings file
270
+ */
271
+ public function import() {
272
+ if( empty( $_POST["wpstg_import_nonce"] ) ) {
273
+ return;
274
+ }
275
+
276
+ if( !wp_verify_nonce( $_POST["wpstg_import_nonce"], "wpstg_import_nonce" ) ) {
277
+ return;
278
+ }
279
+
280
+ if( !current_user_can( "update_plugins" ) ) {
281
+ return;
282
+ }
283
+
284
+ $fileExtension = explode( '.', $_FILES["import_file"]["name"] );
285
+ $fileExtension = end( $fileExtension );
286
+ if( "json" !== $fileExtension ) {
287
+ wp_die( "Please upload a valid .json file", "wpstg" );
288
+ }
289
+
290
+
291
+ $importFile = $_FILES["import_file"]["tmp_name"];
292
+
293
+ if( empty( $importFile ) ) {
294
+ wp_die( __( "Please upload a file to import", "wpstg" ) );
295
+ }
296
+
297
+ update_option( "wpstg_settings", json_decode( file_get_contents( $importFile, true ) ) );
298
+
299
+ wp_safe_redirect( admin_url( "admin.php?page=wpstg-tools&amp;wpstg-message=settings-imported" ) );
300
+
301
+ return;
302
+ }
303
+
304
+ /**
305
+ * Export settings to JSON file
306
+ */
307
+ public function export() {
308
+ if( empty( $_POST["wpstg_export_nonce"] ) ) {
309
+ return;
310
+ }
311
+
312
+ if( !wp_verify_nonce( $_POST["wpstg_export_nonce"], "wpstg_export_nonce" ) ) {
313
+ return;
314
+ }
315
+
316
+ if( !current_user_can( "manage_options" ) ) {
317
+ return;
318
+ }
319
+
320
+ $settings = get_option( "wpstg_settings", array() );
321
+
322
+ ignore_user_abort( true );
323
+
324
+ if( !in_array( "set_time_limit", explode( ',', ini_get( "disable_functions" ) ) ) && !@ini_get( "safe_mode" ) ) {
325
+ set_time_limit( 0 );
326
+ }
327
+
328
+ $fileName = apply_filters( "wpstg_settings_export_filename", "wpstg-settings-export-" . date( "m-d-Y" ) ) . ".json";
329
+
330
+ nocache_headers();
331
+ header( "Content-Type: application/json; charset=utf-8" );
332
+ header( "Content-Disposition: attachment; filename={$fileName}" );
333
+ header( "Expires: 0" );
334
+
335
+ echo json_encode( $settings );
336
+ }
337
+
338
+ /**
339
+ * Render a view file
340
+ * @param string $file
341
+ * @param array $vars
342
+ * @return string
343
+ */
344
+ public function render( $file, $vars = array() ) {
345
+ $fullPath = $this->path . "views" . DIRECTORY_SEPARATOR;
346
+ $fullPath = str_replace( array('/', "\\"), DIRECTORY_SEPARATOR, $fullPath . $file . ".php" );
347
+
348
+ if( !file_exists( $fullPath ) || !is_readable( $fullPath ) ) {
349
+ return "Can't render : {$fullPath} either file doesn't exist or can't read it";
350
+ }
351
+
352
+ $contents = @file_get_contents( $fullPath );
353
+
354
+ // Variables are set
355
+ if( count( $vars ) > 0 ) {
356
+ $vars = array_combine(
357
+ array_map( function ($key) {
358
+ return "{{" . $key . "}}";
359
+ }, array_keys( $vars )
360
+ ), $vars
361
+ );
362
+
363
+ $contents = str_replace( array_keys( $vars ), array_values( $vars ), $contents );
364
+ }
365
+
366
+ return $contents;
367
+ }
368
+
369
+ /**
370
+ * Ajax Overview
371
+ */
372
+ public function ajaxOverview() {
373
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
374
+
375
+ // Existing clones
376
+ $availableClones = get_option( "wpstg_existing_clones_beta", array() );
377
+
378
+ // Get license data
379
+ $license = get_option( 'wpstg_license_status' );
380
+
381
+
382
+ if( \WPStaging\WPStaging::getSlug() === 'wp-staging-pro' ) {
383
+ require_once "{$this->path}Pro/views/single-overview-pro.php";
384
+ } else {
385
+ require_once "{$this->path}views/clone/ajax/single-overview.php";
386
+ }
387
+
388
+ wp_die();
389
+ }
390
+
391
+ /**
392
+ * Ajax Scan
393
+ */
394
+ public function ajaxScan() {
395
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
396
+
397
+ // Scan
398
+ $scan = new Scan();
399
+ $scan->start();
400
+
401
+ // Get Options
402
+ $options = $scan->getOptions();
403
+
404
+ require_once "{$this->path}views/clone/ajax/scan.php";
405
+
406
+ wp_die();
407
+ }
408
+
409
+ /**
410
+ * Ajax Check Clone Name
411
+ */
412
+ public function ajaxCheckCloneName() {
413
+ $cloneName = sanitize_key( $_POST["cloneID"] );
414
+ $cloneNameLength = strlen( $cloneName );
415
+ $clones = get_option( "wpstg_existing_clones_beta", array() );
416
+
417
+ // Check clone name length
418
+ if( $cloneNameLength < 1 || $cloneNameLength > 16 ) {
419
+ echo wp_send_json( array(
420
+ "status" => "failed",
421
+ "message" => "Clone name must be between 1 - 16 characters"
422
+ ) );
423
+ } elseif( array_key_exists( $cloneName, $clones ) ) {
424
+ echo wp_send_json( array(
425
+ "status" => "failed",
426
+ "message" => "Clone name is already in use, please choose an another clone name"
427
+ ) );
428
+ }
429
+
430
+ echo wp_send_json( array("status" => "success") );
431
+ }
432
+
433
+
434
+
435
+
436
+ /**
437
+ * Ajax Start Updating Clone (Basically just layout and saving data)
438
+ */
439
+ // public function ajaxStartUpdate() {
440
+ // check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
441
+ //
442
+ // $cloning = new Updating();
443
+ //
444
+ // if( !$cloning->save() ) {
445
+ // wp_die('can not save clone data');
446
+ // }
447
+ //
448
+ // require_once "{$this->path}views/clone/ajax/update.php";
449
+ //
450
+ // wp_die();
451
+ // }
452
+ /**
453
+ * Ajax Start Updating Clone (Basically just layout and saving data)
454
+ */
455
+ public function ajaxUpdateProcess() {
456
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
457
+
458
+ $cloning = new Updating();
459
+
460
+ if( !$cloning->save() ) {
461
+ wp_die('can not save clone data');
462
+ }
463
+
464
+ require_once "{$this->path}views/clone/ajax/update.php";
465
+
466
+ wp_die();
467
+
468
+ //wp_send_json( $cloning->start() );
469
+ }
470
+ /**
471
+ * Ajax Start Clone (Basically just layout and saving data)
472
+ */
473
+ public function ajaxStartClone() {
474
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
475
+
476
+ $cloning = new Cloning();
477
+
478
+ if( !$cloning->save() ) {
479
+ wp_die('can not save clone data');
480
+ }
481
+
482
+ require_once "{$this->path}views/clone/ajax/start.php";
483
+
484
+ wp_die();
485
+ }
486
+
487
+ /**
488
+ * Ajax Clone Database
489
+ */
490
+ public function ajaxCloneDatabase() {
491
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
492
+
493
+ $cloning = new Cloning();
494
+
495
+ wp_send_json( $cloning->start() );
496
+ }
497
+
498
+ /**
499
+ * Ajax Prepare Directories (get listing of files)
500
+ */
501
+ public function ajaxPrepareDirectories() {
502
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
503
+
504
+ $cloning = new Cloning();
505
+
506
+ wp_send_json( $cloning->start() );
507
+ }
508
+
509
+ /**
510
+ * Ajax Clone Files
511
+ */
512
+ public function ajaxCopyFiles() {
513
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
514
+
515
+ $cloning = new Cloning();
516
+
517
+ wp_send_json( $cloning->start() );
518
+ }
519
+
520
+ /**
521
+ * Ajax Replace Data
522
+ */
523
+ public function ajaxReplaceData() {
524
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
525
+
526
+ $cloning = new Cloning();
527
+
528
+ wp_send_json( $cloning->start() );
529
+ }
530
+
531
+ /**
532
+ * Ajax Finish
533
+ */
534
+ public function ajaxFinish() {
535
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
536
+
537
+ $cloning = new Cloning();
538
+
539
+ wp_send_json( $cloning->start() );
540
+ }
541
+
542
+ /**
543
+ * Ajax Delete Confirmation
544
+ */
545
+ public function ajaxDeleteConfirmation() {
546
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
547
+
548
+ $delete = new Delete();
549
+ $delete->setData();
550
+
551
+ $clone = $delete->getClone();
552
+
553
+ require_once "{$this->path}views/clone/ajax/delete-confirmation.php";
554
+
555
+ wp_die();
556
+ }
557
+
558
+ /**
559
+ * Delete clone
560
+ */
561
+ public function ajaxDeleteClone() {
562
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
563
+
564
+ $delete = new Delete();
565
+ wp_send_json( $delete->start() );
566
+ }
567
+
568
+ /**
569
+ * Delete clone
570
+ */
571
+ public function ajaxCancelClone() {
572
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
573
+
574
+ $cancel = new Cancel();
575
+ wp_send_json( $cancel->start() );
576
+ }
577
+
578
+ /**
579
+ * Cancel updating process / Do not delete clone!
580
+ */
581
+ public function ajaxCancelUpdate() {
582
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
583
+
584
+ $cancel = new CancelUpdate();
585
+ wp_send_json( $cancel->start() );
586
+ }
587
+
588
+ /**
589
+ * Admin Messages
590
+ */
591
+ public function messages() {
592
+ $notice = new Notices( $this->path, $this->url );
593
+
594
+ $run = $notice->messages();
595
+ }
596
+
597
+ /**
598
+ * Ajax Hide Poll
599
+ * @return mixed boolean | json
600
+ */
601
+ public function ajaxHidePoll() {
602
+ if( false !== update_option( "wpstg_poll", "no" ) ) {
603
+ wp_send_json( true );
604
+ }
605
+ return wp_send_json();
606
+ }
607
+
608
+ /**
609
+ * Ajax Hide Rating
610
+ * @return mixed bool | json
611
+ */
612
+ public function ajaxHideRating() {
613
+ if( false !== update_option( "wpstg_rating", "no" ) ) {
614
+ wp_send_json( true );
615
+ }
616
+ return wp_send_json();
617
+ }
618
+
619
+ /**
620
+ * Ajax Hide Beta
621
+ */
622
+ public function ajaxHideBeta() {
623
+ wp_send_json( update_option( "wpstg_beta", "no" ) );
624
+ }
625
+
626
+ /**
627
+ * Clone logs
628
+ */
629
+ public function ajaxLogs() {
630
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
631
+
632
+ $logs = new Logs();
633
+ wp_send_json( $logs->start() );
634
+ }
635
+
636
+ /**
637
+ * Ajax Checks Free Disk Space
638
+ */
639
+ public function ajaxCheckFreeSpace() {
640
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
641
+
642
+ $scan = new Scan();
643
+ return $scan->hasFreeDiskSpace();
644
+ }
645
+
646
+ /**
647
+ * Ajax Start Push Changes Process
648
+ * Start with the module Scan
649
+ */
650
+ public function ajaxPushScan() {
651
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
652
+
653
+ if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Scan' ) ) {
654
+ return false;
655
+ }
656
+
657
+ // Scan
658
+ $scan = new Pro\Modules\Jobs\Scan();
659
+
660
+ $scan->start();
661
+
662
+ // Get Options
663
+ $options = $scan->getOptions();
664
+
665
+ require_once "{$this->path}Pro/views/scan.php";
666
+
667
+ wp_die();
668
+ }
669
+
670
+ /**
671
+ * Ajax Start Pushing. Needs wp quads pro)
672
+ */
673
+ public function ajaxPushProcessing() {
674
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
675
+
676
+ if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Processing' ) ) {
677
+ return false;
678
+ }
679
+ // Start the process
680
+ $processing = new Processing();
681
+ wp_send_json( $processing->start() );
682
+ }
683
+
684
+ /**
685
+ * License Page
686
+ */
687
+ public function getLicensePage() {
688
+
689
+ // Get license data
690
+ $license = get_option( 'wpstg_license_status' );
691
+
692
+ require_once "{$this->path}Pro/views/licensing.php";
693
+ }
694
+
695
+ }
apps/Backend/Modules/Jobs/Cancel.php CHANGED
@@ -1,74 +1,74 @@
1
- <?php
2
-
3
- namespace WPStaging\Backend\Modules\Jobs;
4
-
5
- /**
6
- * Class Cancel Processing
7
- * @package WPStaging\Backend\Modules\Jobs
8
- */
9
- class Cancel extends Job {
10
-
11
- /**
12
- * Start Module
13
- * @return bool
14
- */
15
- public function start() {
16
- $cloneData = $this->createCloneData();
17
-
18
- if (empty($cloneData)) {
19
- return true;
20
- }
21
-
22
-
23
- $delete = new Delete();
24
- return $delete->start($cloneData);
25
- }
26
-
27
- /**
28
- * @return array
29
- */
30
- protected function createCloneData() {
31
- $clone = array();
32
-
33
- if (!$this->check()) {
34
- return $clone;
35
- }
36
-
37
- $clone["name"] = $this->options->clone;
38
- $clone["number"] = $this->options->cloneNumber;
39
- $clone["path"] = ABSPATH . $this->options->cloneDirectoryName;
40
- $clone["prefix"] = ABSPATH . $this->options->prefix;
41
-
42
- return $clone;
43
- }
44
-
45
- /**
46
- * @return bool
47
- */
48
- public function check() {
49
- return (
50
- isset($this->options) &&
51
- isset($this->options->clone) &&
52
- isset($this->options->cloneNumber) &&
53
- isset($this->options->cloneDirectoryName) &&
54
- isset($_POST["clone"]) &&
55
- $_POST["clone"] === $this->options->clone
56
- );
57
- }
58
-
59
- /**
60
- * Get json response
61
- * return json
62
- */
63
- private function returnFinish($message = '') {
64
-
65
- wp_die(json_encode(array(
66
- 'job' => 'delete',
67
- 'status' => true,
68
- 'message' => $message,
69
- 'error' => false,
70
- 'delete' => 'finished'
71
- )));
72
- }
73
-
74
- }
1
+ <?php
2
+
3
+ namespace WPStaging\Backend\Modules\Jobs;
4
+
5
+ /**
6
+ * Class Cancel Processing
7
+ * @package WPStaging\Backend\Modules\Jobs
8
+ */
9
+ class Cancel extends Job {
10
+
11
+ /**
12
+ * Start Module
13
+ * @return bool
14
+ */
15
+ public function start() {
16
+ $cloneData = $this->createCloneData();
17
+
18
+ if (empty($cloneData)) {
19
+ return true;
20
+ }
21
+
22
+
23
+ $delete = new Delete();
24
+ return $delete->start($cloneData);
25
+ }
26
+
27
+ /**
28
+ * @return array
29
+ */
30
+ protected function createCloneData() {
31
+ $clone = array();
32
+
33
+ if (!$this->check()) {
34
+ return $clone;
35
+ }
36
+
37
+ $clone["name"] = $this->options->clone;
38
+ $clone["number"] = $this->options->cloneNumber;
39
+ $clone["path"] = ABSPATH . $this->options->cloneDirectoryName;
40
+ $clone["prefix"] = ABSPATH . $this->options->prefix;
41
+
42
+ return $clone;
43
+ }
44
+
45
+ /**
46
+ * @return bool
47
+ */
48
+ public function check() {
49
+ return (
50
+ isset($this->options) &&
51
+ isset($this->options->clone) &&
52
+ isset($this->options->cloneNumber) &&
53
+ isset($this->options->cloneDirectoryName) &&
54
+ isset($_POST["clone"]) &&
55
+ $_POST["clone"] === $this->options->clone
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Get json response
61
+ * return json
62
+ */
63
+ private function returnFinish($message = '') {
64
+
65
+ wp_die(json_encode(array(
66
+ 'job' => 'delete',
67
+ 'status' => true,
68
+ 'message' => $message,
69
+ 'error' => false,
70
+ 'delete' => 'finished'
71
+ )));
72
+ }
73
+
74
+ }
apps/Backend/Modules/Jobs/CancelUpdate.php CHANGED
@@ -1,90 +1,90 @@
1
- <?php
2
-
3
- namespace WPStaging\Backend\Modules\Jobs;
4
-
5
- /**
6
- * Class Cancel Update Processing
7
- * @package WPStaging\Backend\Modules\Jobs
8
- */
9
- class CancelUpdate extends Job {
10
-
11
- /**
12
- * Start Module
13
- * @return bool
14
- */
15
- public function start() {
16
- $cloneData = $this->createCloneData();
17
-
18
- if (empty($cloneData)) {
19
- return true;
20
- }
21
- // Delete Cache Files
22
- $this->deleteCacheFiles();
23
-
24
- $this->returnFinish();
25
-
26
- }
27
-
28
- /**
29
- * @return array
30
- */
31
- protected function createCloneData() {
32
- $clone = array();
33
-
34
- if (!$this->check()) {
35
- return $clone;
36
- }
37
-
38
- $clone["name"] = $this->options->clone;
39
- $clone["number"] = $this->options->cloneNumber;
40
- $clone["path"] = ABSPATH . $this->options->cloneDirectoryName;
41
- $clone["prefix"] = ABSPATH . $this->options->prefix;
42
-
43
- return $clone;
44
- }
45
-
46
- /**
47
- * @return bool
48
- */
49
- public function check() {
50
- return (
51
- isset($this->options) &&
52
- isset($this->options->clone) &&
53
- isset($this->options->cloneNumber) &&
54
- isset($this->options->cloneDirectoryName) &&
55
- isset($_POST["clone"]) &&
56
- $_POST["clone"] === $this->options->clone
57
- );
58
- }
59
-
60
- /**
61
- * Get json response
62
- * return json
63
- */
64
- private function returnFinish($message = '') {
65
-
66
- wp_die(json_encode(array(
67
- 'job' => 'delete',
68
- 'status' => true,
69
- 'message' => $message,
70
- 'error' => false,
71
- 'delete' => 'finished'
72
- )));
73
- }
74
-
75
-
76
- /**
77
- * Delete Cache Files
78
- */
79
- protected function deleteCacheFiles()
80
- {
81
- $this->log("Cancel Updating: Deleting clone job's cache files...");
82
-
83
- // Clean cache files
84
- $this->cache->delete("clone_options");
85
- $this->cache->delete("files_to_copy");
86
-
87
- $this->log("Updating process canceled");
88
- }
89
-
90
- }
1
+ <?php
2
+
3
+ namespace WPStaging\Backend\Modules\Jobs;
4
+
5
+ /**
6
+ * Class Cancel Update Processing
7
+ * @package WPStaging\Backend\Modules\Jobs
8
+ */
9
+ class CancelUpdate extends Job {
10
+
11
+ /**
12
+ * Start Module
13
+ * @return bool
14
+ */
15
+ public function start() {
16
+ $cloneData = $this->createCloneData();
17
+
18
+ if (empty($cloneData)) {
19
+ return true;
20
+ }
21
+ // Delete Cache Files
22
+ $this->deleteCacheFiles();
23
+
24
+ $this->returnFinish();
25
+
26
+ }
27
+
28
+ /**
29
+ * @return array
30
+ */
31
+ protected function createCloneData() {
32
+ $clone = array();
33
+
34
+ if (!$this->check()) {
35
+ return $clone;
36
+ }
37
+
38
+ $clone["name"] = $this->options->clone;
39
+ $clone["number"] = $this->options->cloneNumber;
40
+ $clone["path"] = ABSPATH . $this->options->cloneDirectoryName;
41
+ $clone["prefix"] = ABSPATH . $this->options->prefix;
42
+
43
+ return $clone;
44
+ }
45
+
46
+ /**
47
+ * @return bool
48
+ */
49
+ public function check() {
50
+ return (
51
+ isset($this->options) &&
52
+ isset($this->options->clone) &&
53
+ isset($this->options->cloneNumber) &&
54
+ isset($this->options->cloneDirectoryName) &&
55
+ isset($_POST["clone"]) &&
56
+ $_POST["clone"] === $this->options->clone
57
+ );
58
+ }
59
+
60
+ /**
61
+ * Get json response
62
+ * return json
63
+ */
64
+ private function returnFinish($message = '') {
65
+
66
+ wp_die(json_encode(array(
67
+ 'job' => 'delete',
68
+ 'status' => true,
69
+ 'message' => $message,
70
+ 'error' => false,
71
+ 'delete' => 'finished'
72
+ )));
73
+ }
74
+
75
+
76
+ /**
77
+ * Delete Cache Files
78
+ */
79
+ protected function deleteCacheFiles()
80
+ {
81
+ $this->log("Cancel Updating: Deleting clone job's cache files...");
82
+
83
+ // Clean cache files
84
+ $this->cache->delete("clone_options");
85
+ $this->cache->delete("files_to_copy");
86
+
87
+ $this->log("Updating process canceled");
88
+ }
89
+
90
+ }
apps/Backend/Modules/Jobs/Cloning.php CHANGED
@@ -1,250 +1,250 @@
1
- <?php
2
- namespace WPStaging\Backend\Modules\Jobs;
3
-
4
- use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
5
- use WPStaging\WPStaging;
6
-
7
- /**
8
- * Class Cloning
9
- * @package WPStaging\Backend\Modules\Jobs
10
- */
11
- class Cloning extends Job
12
- {
13
- /**
14
- * Initialize is called in \Job
15
- */
16
- public function initialize(){
17
- $this->db = WPStaging::getInstance()->get("wpdb");
18
- }
19
-
20
- /**
21
- * Save Chosen Cloning Settings
22
- * @return bool
23
- */
24
- public function save()
25
- {
26
- if (!isset($_POST) || !isset($_POST["cloneID"]))
27
- {
28
- return false;
29
- }
30
-
31
- // Generate Options
32
- // Clone
33
- $this->options->clone = $_POST["cloneID"];
34
- $this->options->cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($this->options->clone));
35
- $this->options->cloneNumber = 1;
36
- $this->options->prefix = $this->getStagingPrefix();
37
-
38
- //$this->options->prefix = $this->getStagingPrefix();
39
- $this->options->includedDirectories = array();
40
- $this->options->excludedDirectories = array();
41
- $this->options->extraDirectories = array();
42
- $this->options->excludedFiles = array('.htaccess', '.DS_Store', '.git', '.svn', '.tmp', 'desktop.ini', '.gitignore', '.log');
43
-
44
- // Job
45
- $this->options->job = new \stdClass();
46
-
47
- // Check if clone data already exists and use that one
48
- if (isset($this->options->existingClones[$this->options->clone]) )
49
- {
50
-
51
- $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
52
-
53
- $this->options->prefix = isset($this->options->existingClones[$this->options->clone]->prefix) ?
54
- $this->options->existingClones[$this->options->clone]->prefix :
55
- $this->getStagingPrefix();
56
-
57
- } // Clone does not exist but there are other clones in db
58
- // Get data and increment it
59
- elseif (!empty($this->options->existingClones))
60
- {
61
- $this->options->cloneNumber = count($this->options->existingClones)+1;
62
- $this->options->prefix = $this->getStagingPrefix();
63
- }
64
-
65
- // Excluded Tables
66
- if (isset($_POST["excludedTables"]) && is_array($_POST["excludedTables"]))
67
- {
68
- $this->options->excludedTables = $_POST["excludedTables"];
69
- }
70
-
71
- // Excluded Directories
72
- if (isset($_POST["excludedDirectories"]) && is_array($_POST["excludedDirectories"]))
73
- {
74
- $this->options->excludedDirectories = $_POST["excludedDirectories"];
75
- }
76
-
77
- // Excluded Directories TOTAL
78
- // Do not copy these folders and plugins
79
- $excludedDirectories = array(
80
- ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
81
- ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
82
- ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-super-cache',
83
- );
84
-
85
- $this->options->excludedDirectories = array_merge($excludedDirectories, $this->options->excludedDirectories);
86
-
87
- // Included Directories
88
- if (isset($_POST["includedDirectories"]) && is_array($_POST["includedDirectories"]))
89
- {
90
- $this->options->includedDirectories = $_POST["includedDirectories"];
91
- }
92
-
93
- // Extra Directories
94
- if (isset($_POST["extraDirectories"]) && !empty($_POST["extraDirectories"]) )
95
- {
96
- $this->options->extraDirectories = $_POST["extraDirectories"];
97
- }
98
-
99
- // Directories to Copy
100
- $this->options->directoriesToCopy = array_merge(
101
- $this->options->includedDirectories,
102
- $this->options->extraDirectories
103
- );
104
-
105
- array_unshift($this->options->directoriesToCopy, ABSPATH);
106
-
107
- // Delete files to copy listing
108
- $this->cache->delete("files_to_copy");
109
-
110
- return $this->saveOptions();
111
- }
112
-
113
- /**
114
- * Create a new staging prefix which does not already exists in database
115
- */
116
- public function getStagingPrefix(){
117
-
118
- // Find a new prefix that does not already exist in database.
119
- // 1000 different possible prefixes should be enough here
120
- for($i=0; $i <= 10000; $i++){
121
- $this->options->prefix = isset($this->options->existingClones) ?
122
- 'wpstg' . (count($this->options->existingClones)+$i) . '_' :
123
- 'wpstg' . $i . '_';
124
-
125
- $sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
126
- $tables = $this->db->get_results($sql);
127
-
128
- // Prefix does not exists. We can use it
129
- if (!$tables){
130
- //$this->returnException('new ' . $this->options->prefix);
131
- return $this->options->prefix;
132
- }
133
- }
134
- $this->returnException("Fatal Error: Can not create staging prefix. '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
135
- wp_die("Fatal Error: Can not create staging prefix. Prefix '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
136
- }
137
-
138
- /**
139
- * Check if potential new prefix of staging site would be identical with live site.
140
- * @return boolean
141
- */
142
- private function isPrefixIdentical(){
143
- $db = WPStaging::getInstance()->get("wpdb");
144
-
145
- $livePrefix = $db->prefix;
146
- $stagingPrefix = $this->options->prefix;
147
-
148
- if ($livePrefix == $stagingPrefix){
149
- return true;
150
- }
151
- return false;
152
- }
153
-
154
- /**
155
- * Start the cloning job
156
- */
157
- public function start()
158
- {
159
- if (null === $this->options->currentJob)
160
- {
161
- $this->log("Cloning job for {$this->options->clone} finished");
162
- return true;
163
- }
164
-
165
- $methodName = "job" . ucwords($this->options->currentJob);
166
-
167
- if (!method_exists($this, $methodName))
168
- {
169
- $this->log("Can't execute job; Job's method {$methodName} is not found");
170
- throw new JobNotFoundException($methodName);
171
- }
172
-
173
- // Call the job
174
- //$this->log("execute job: Job's method {$methodName}");
175
- return $this->{$methodName}();
176
- }
177
-
178
- /**
179
- * @param object $response
180
- * @param string $nextJob
181
- * @return object
182
- */
183
- private function handleJobResponse($response, $nextJob)
184
- {
185
- // Job is not done
186
- if (true !== $response->status)
187
- {
188
- return $response;
189
- }
190
-
191
- $this->options->currentJob = $nextJob;
192
- $this->options->currentStep = 0;
193
- $this->options->totalSteps = 0;
194
-
195
- // Save options
196
- $this->saveOptions();
197
-
198
- return $response;
199
- }
200
-
201
- /**
202
- * Clone Database
203
- * @return object
204
- */
205
- public function jobDatabase()
206
- {
207
- $database = new Database();
208
- return $this->handleJobResponse($database->start(), "directories");
209
- }
210
-
211
- /**
212
- * Get All Files From Selected Directories Recursively Into a File
213
- * @return object
214
- */
215
- public function jobDirectories()
216
- {
217
- $directories = new Directories();
218
- return $this->handleJobResponse($directories->start(), "files");
219
- }
220
-
221
- /**
222
- * Copy Files
223
- * @return object
224
- */
225
- public function jobFiles()
226
- {
227
- $files = new Files();
228
- return $this->handleJobResponse($files->start(), "data");
229
- }
230
-
231
- /**
232
- * Replace Data
233
- * @return object
234
- */
235
- public function jobData()
236
- {
237
- $data = new Data();
238
- return $this->handleJobResponse($data->start(), "finish");
239
- }
240
-
241
- /**
242
- * Save Clone Data
243
- * @return object
244
- */
245
- public function jobFinish()
246
- {
247
- $finish = new Finish();
248
- return $this->handleJobResponse($finish->start(), '');
249
- }
250
}
1
+ <?php
2
+ namespace WPStaging\Backend\Modules\Jobs;
3
+
4
+ use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
5
+ use WPStaging\WPStaging;
6
+
7
+ /**
8
+ * Class Cloning
9
+ * @package WPStaging\Backend\Modules\Jobs
10
+ */
11
+ class Cloning extends Job
12
+ {
13
+ /**
14
+ * Initialize is called in \Job
15
+ */
16
+ public function initialize(){
17
+ $this->db = WPStaging::getInstance()->get("wpdb");
18
+ }
19
+
20
+ /**
21
+ * Save Chosen Cloning Settings
22
+ * @return bool
23
+ */
24
+ public function save()
25
+ {
26
+ if (!isset($_POST) || !isset($_POST["cloneID"]))
27
+ {
28
+ return false;
29
+ }
30
+
31
+ // Generate Options
32
+ // Clone
33
+ $this->options->clone = $_POST["cloneID"];
34
+ $this->options->cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($this->options->clone));
35
+ $this->options->cloneNumber = 1;
36
+ $this->options->prefix = $this->getStagingPrefix();
37
+
38
+ //$this->options->prefix = $this->getStagingPrefix();
39
+ $this->options->includedDirectories = array();
40
+ $this->options->excludedDirectories = array();
41
+ $this->options->extraDirectories = array();
42
+ $this->options->excludedFiles = array('.htaccess', '.DS_Store', '.git', '.svn', '.tmp', 'desktop.ini', '.gitignore', '.log');
43
+
44
+ // Job
45
+ $this->options->job = new \stdClass();
46
+
47
+ // Check if clone data already exists and use that one
48
+ if (isset($this->options->existingClones[$this->options->clone]) )
49
+ {
50
+
51
+ $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
52
+
53
+ $this->options->prefix = isset($this->options->existingClones[$this->options->clone]->prefix) ?
54
+ $this->options->existingClones[$this->options->clone]->prefix :
55
+ $this->getStagingPrefix();
56
+
57
+ } // Clone does not exist but there are other clones in db
58
+ // Get data and increment it
59
+ elseif (!empty($this->options->existingClones))
60
+ {
61
+ $this->options->cloneNumber = count($this->options->existingClones)+1;
62
+ $this->options->prefix = $this->getStagingPrefix();
63
+ }
64
+
65
+ // Excluded Tables
66
+ if (isset($_POST["excludedTables"]) && is_array($_POST["excludedTables"]))
67
+ {
68
+ $this->options->excludedTables = $_POST["excludedTables"];
69
+ }
70
+
71
+ // Excluded Directories
72
+ if (isset($_POST["excludedDirectories"]) && is_array($_POST["excludedDirectories"]))
73
+ {
74
+ $this->options->excludedDirectories = $_POST["excludedDirectories"];
75
+ }
76
+
77
+ // Excluded Directories TOTAL
78
+ // Do not copy these folders and plugins
79
+ $excludedDirectories = array(
80
+ ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
81
+ ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
82
+ ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-super-cache',
83
+ );
84
+
85
+ $this->options->excludedDirectories = array_merge($excludedDirectories, $this->options->excludedDirectories);
86
+
87
+ // Included Directories
88
+ if (isset($_POST["includedDirectories"]) && is_array($_POST["includedDirectories"]))
89
+ {
90
+ $this->options->includedDirectories = $_POST["includedDirectories"];
91
+ }
92
+
93
+ // Extra Directories
94
+ if (isset($_POST["extraDirectories"]) && !empty($_POST["extraDirectories"]) )
95
+ {
96
+ $this->options->extraDirectories = $_POST["extraDirectories"];
97
+ }
98
+
99
+ // Directories to Copy
100
+ $this->options->directoriesToCopy = array_merge(
101
+ $this->options->includedDirectories,
102
+ $this->options->extraDirectories
103
+ );
104
+
105
+ array_unshift($this->options->directoriesToCopy, ABSPATH);
106
+
107
+ // Delete files to copy listing
108
+ $this->cache->delete("files_to_copy");
109
+
110
+ return $this->saveOptions();
111
+ }
112
+
113
+ /**
114
+ * Create a new staging prefix which does not already exists in database
115
+ */
116
+ public function getStagingPrefix(){
117
+
118
+ // Find a new prefix that does not already exist in database.
119
+ // 1000 different possible prefixes should be enough here
120
+ for($i=0; $i <= 10000; $i++){
121
+ $this->options->prefix = isset($this->options->existingClones) ?
122
+ 'wpstg' . (count($this->options->existingClones)+$i) . '_' :
123
+ 'wpstg' . $i . '_';
124
+
125
+ $sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
126
+ $tables = $this->db->get_results($sql);
127
+
128
+ // Prefix does not exists. We can use it
129
+ if (!$tables){
130
+ //$this->returnException('new ' . $this->options->prefix);
131
+ return $this->options->prefix;
132
+ }
133
+ }
134
+ $this->returnException("Fatal Error: Can not create staging prefix. '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
135
+ wp_die("Fatal Error: Can not create staging prefix. Prefix '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
136
+ }
137
+
138
+ /**
139
+ * Check if potential new prefix of staging site would be identical with live site.
140
+ * @return boolean
141
+ */
142
+ private function isPrefixIdentical(){
143
+ $db = WPStaging::getInstance()->get("wpdb");
144
+
145
+ $livePrefix = $db->prefix;
146
+ $stagingPrefix = $this->options->prefix;
147
+
148
+ if ($livePrefix == $stagingPrefix){
149
+ return true;
150
+ }
151
+ return false;
152
+ }
153
+
154
+ /**
155
+ * Start the cloning job
156
+ */
157
+ public function start()
158
+ {
159
+ if (null === $this->options->currentJob)
160
+ {
161
+ $this->log("Cloning job for {$this->options->clone} finished");
162
+ return true;
163
+ }
164
+
165
+ $methodName = "job" . ucwords($this->options->currentJob);
166
+
167
+ if (!method_exists($this, $methodName))
168
+ {
169
+ $this->log("Can't execute job; Job's method {$methodName} is not found");
170
+ throw new JobNotFoundException($methodName);
171
+ }
172
+
173
+ // Call the job
174
+ //$this->log("execute job: Job's method {$methodName}");
175
+ return $this->{$methodName}();
176
+ }
177
+
178
+ /**
179
+ * @param object $response
180
+ * @param string $nextJob
181
+ * @return object
182
+ */
183
+ private function handleJobResponse($response, $nextJob)
184
+ {
185
+ // Job is not done
186
+ if (true !== $response->status)
187
+ {
188
+ return $response;
189
+ }
190
+
191
+ $this->options->currentJob = $nextJob;
192
+ $this->options->currentStep = 0;
193
+ $this->options->totalSteps = 0;
194
+
195
+ // Save options
196
+ $this->saveOptions();
197
+
198
+ return $response;
199
+ }
200
+
201
+ /**
202
+ * Clone Database
203
+ * @return object
204
+ */
205
+ public function jobDatabase()
206
+ {
207
+ $database = new Database();
208
+ return $this->handleJobResponse($database->start(), "directories");
209
+ }
210
+
211
+ /**
212
+ * Get All Files From Selected Directories Recursively Into a File
213
+ * @return object
214
+ */
215
+ public function jobDirectories()
216
+ {
217
+ $directories = new Directories();
218
+ return $this->handleJobResponse($directories->start(), "files");
219
+ }
220
+
221
+ /**
222
+ * Copy Files
223
+ * @return object
224
+ */
225
+ public function jobFiles()
226
+ {
227
+ $files = new Files();
228
+ return $this->handleJobResponse($files->start(), "data");
229
+ }
230
+
231
+ /**
232
+ * Replace Data
233
+ * @return object
234
+ */
235
+ public function jobData()
236
+ {
237
+ $data = new Data();
238
+ return $this->handleJobResponse($data->start(), "finish");
239
+ }
240
+
241
+ /**
242
+ * Save Clone Data
243
+ * @return object
244
+ */
245
+ public function jobFinish()
246
+ {
247
+ $finish = new Finish();
248
+ return $this->handleJobResponse($finish->start(), '');
249
+ }
250
}
apps/Backend/Modules/Jobs/Data.php CHANGED
@@ -1,409 +1,460 @@
1
- <?php
2
- namespace WPStaging\Backend\Modules\Jobs;
3
-
4
- // No Direct Access
5
- if (!defined("WPINC"))
6
- {
7
- die;
8
- }
9
-
10
- use WPStaging\Utils\Logger;
11
- use WPStaging\WPStaging;
12
-
13
- /**
14
- * Class Data
15
- * @package WPStaging\Backend\Modules\Jobs
16
- */
17
- class Data extends JobExecutable
18
- {
19
-
20
- /**
21
- * @var \wpdb
22
- */
23
- private $db;
24
-
25
- /**
26
- * @var string
27
- */
28
- private $prefix;
29
-
30
- /**
31
- * Initialize
32
- */
33
- public function initialize()
34
- {
35
- $this->db = WPStaging::getInstance()->get("wpdb");
36
-
37
- //$this->prefix = "wpstg{$this->options->cloneNumber}_";
38
- $this->prefix = $this->options->prefix;
39
-
40
- // Fix current step
41
- if (0 == $this->options->currentStep)
42
- {
43
- $this->options->currentStep = 1;
44
- }
45
- }
46
-
47
- /**
48
- * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
49
- * @return void
50
- */
51
- protected function calculateTotalSteps()
52
- {
53
- $this->options->totalSteps = 6;
54
- }
55
-
56
- /**
57
- * Start Module
58
- * @return object
59
- */
60
- public function start()
61
- {
62
- // Execute steps
63
- $this->run();
64
-
65
- // Save option, progress
66
- $this->saveOptions();
67
-
68
- // Prepare response
69
- $this->response = array(
70
- "status" => true,
71
- "percentage" => 100,
72
- "total" => $this->options->totalSteps,
73
- "step" => $this->options->totalSteps,
74
- "last_msg" => $this->logger->getLastLogMsg(),
75
- "running_time" => $this->time() - time(),
76
- "job_done" => true
77
- );
78
-
79
- return (object) $this->response;
80
- }
81
-
82
- /**
83
- * Execute the Current Step
84
- * Returns false when over threshold limits are hit or when the job is done, true otherwise
85
- * @return bool
86
- */
87
- protected function execute()
88
- {
89
- // Fatal error. Let this happen never and break here immediately
90
- if ($this->isRoot()){
91
- return false;
92
- }
93
-
94
- // Over limits threshold
95
- if ($this->isOverThreshold())
96
- {
97
- // Prepare response and save current progress
98
- $this->prepareResponse(false, false);
99
- $this->saveOptions();
100
- return false;
101
- }
102
-
103
- // No more steps, finished
104
- if ($this->isFinished())
105
- {
106
- $this->prepareResponse(true, false);
107
- return false;
108
- }
109
-
110
- // Execute step
111
- $stepMethodName = "step" . $this->options->currentStep;
112
- if (!$this->{$stepMethodName}())
113
- {
114
- $this->prepareResponse(false, false);
115
- return false;
116
- }
117
-
118
- // Prepare Response
119
- $this->prepareResponse();
120
-
121
- // Not finished
122
- return true;
123
- }
124
-
125
- /**
126
- * Checks Whether There is Any Job to Execute or Not
127
- * @return bool
128
- */
129
- private function isFinished()
130
- {
131
- return (
132
- $this->options->currentStep > $this->options->totalSteps ||
133
- !method_exists($this, "step" . $this->options->currentStep)
134
- );
135
- }
136
-
137
- /**
138
- * Check if current operation is done on the root folder or on the live DB
139
- * @return boolean
140
- */
141
- private function isRoot(){
142
-
143
- // Prefix is the same as the one of live site
144
- $wpdb = WPStaging::getInstance()->get("wpdb");
145
- if ($wpdb->prefix === $this->prefix){
146
- return true;
147
- }
148
-
149
- // CloneName is empty
150
- $name = (array)$this->options->cloneDirectoryName;
151
- if (empty($name)){
152
- return true;
153
- }
154
-
155
- // Live Path === Staging path
156
- if (get_home_url() . $this->options->cloneDirectoryName === get_home_url()){
157
- return true;
158
- }
159
-
160
- return false;
161
- }
162
-
163
-
164
- /**
165
- * Check if table exists
166
- * @param string $table
167
- * @return boolean
168
- */
169
- protected function isTable($table){
170
- if($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table ){
171
- $this->log( "Table {$table} does not exists", Logger::TYPE_ERROR );
172
- return false;
173
- }
174
- return true;
175
- }
176
-
177
- /**
178
- * Replace "siteurl"
179
- * @return bool
180
- */
181
- protected function step1() {
182
- $this->log( "Search & Replace: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO );
183
-
184
- if( false === $this->isTable( $this->prefix . 'options' ) ) {
185
- return true;
186
- }
187
-
188
- // Installed in sub-directory
189
- if( isset( $this->settings->wpSubDirectory ) && "1" === $this->settings->wpSubDirectory ) {
190
- $subDirectory = str_replace( get_home_path(), '', ABSPATH );
191
- $this->log( "Updating siteurl and homeurl to " . get_home_url() . '/' . $subDirectory . $this->options->cloneDirectoryName );
192
- // Replace URLs
193
- $result = $this->db->query(
194
- $this->db->prepare(
195
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", get_home_url() . '/' . $subDirectory . $this->options->cloneDirectoryName
196
- )
197
- );
198
- } else {
199
- $this->log( "Search & Replace:: Updating siteurl and homeurl to " . get_home_url() . '/' . $this->options->cloneDirectoryName );
200
- // Replace URLs
201
- $result = $this->db->query(
202
- $this->db->prepare(
203
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", get_home_url() . '/' . $this->options->cloneDirectoryName
204
- )
205
- );
206
- }
207
-
208
-
209
- // All good
210
- if( $result ) {
211
- return true;
212
- }
213
-
214
- $this->log( "Search & Replace: Failed to update siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
215
- return false;
216
- }
217
-
218
- /**
219
- * Update "wpstg_is_staging_site"
220
- * @return bool
221
- */
222
- protected function step2()
223
- {
224
-
225
- $this->log( "Search & Replace: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}" );
226
-
227
- if( false === $this->isTable( $this->prefix . 'options' ) ) {
228
- return true;
229
- }
230
-
231
- $result = $this->db->query(
232
- $this->db->prepare(
233
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_is_staging_site'",
234
- "true"
235
- )
236
- );
237
-
238
- // No errors but no option name such as wpstg_is_staging_site
239
- if ('' === $this->db->last_error && 0 == $result)
240
- {
241
- $result = $this->db->query(
242
- $this->db->prepare(
243
- "INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_is_staging_site',%s)",
244
- "true"
245
- )
246
- );
247
- }
248
-
249
- // All good
250
- if ($result)
251
- {
252
- return true;
253
- }
254
-
255
- $this->log("Search & Replace: Failed to update wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
256
- return false;
257
- }
258
-
259
- /**
260
- * Update rewrite_rules
261
- * @return bool
262
- */
263
- protected function step3()
264
- {
265
-
266
- $this->log("Search & Replace: Updating rewrite_rules in {$this->prefix}options {$this->db->last_error}");
267
-
268
- if( false === $this->isTable( $this->prefix . 'options' ) ) {
269
- return true;
270
- }
271
-
272
- $result = $this->db->query(
273
- $this->db->prepare(
274
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'rewrite_rules'",
275
- ' '
276
- )
277
- );
278
-
279
- // All good
280
- if ($result)
281
- {
282
- return true;
283
- }
284
-
285
- $this->log("Failed to update rewrite_rules in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
286
- return true;
287
- }
288
-
289
- /**
290
- * Update Table Prefix in meta_keys
291
- * @return bool
292
- */
293
- protected function step4() {
294
- $this->log( "Search & Replace: Updating {$this->prefix}usermeta db prefix {$this->db->last_error}" );
295
-
296
- if( false === $this->isTable( $this->prefix . 'usermeta' ) ) {
297
- return true;
298
- }
299
-
300
- $resultOptions = $this->db->query(
301
- $this->db->prepare(
302
- "UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
303
- )
304
- );
305
-
306
- if( !$resultOptions ) {
307
- $this->log( "Search & Replace: Failed to update usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
308
- return false;
309
- }
310
-
311
- $this->log( "Updating {$this->prefix}options, option_name database table prefixes; {$this->db->last_error}" );
312
-
313
- $resultUserMeta = $this->db->query(
314
- $this->db->prepare(
315
- "UPDATE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
316
- )
317
- );
318
-
319
- if( !$resultUserMeta ) {
320
- $this->log( "Search & Replace: Failed to update options, option_name database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
321
- return false;
322
- }
323
-
324
- return true;
325
- }
326
-
327
- /**
328
- * Update $table_prefix in wp-config.php
329
- * @return bool
330
- */
331
- protected function step5()
332
- {
333
- $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
334
-
335
- $this->log("Search & Replace: Updating table_prefix in {$path} to " . $this->prefix);
336
- if (false === ($content = file_get_contents($path)))
337
- {
338
- $this->log("Search & Replace: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR);
339
- return false;
340
- }
341
-
342
- // Replace table prefix
343
- $content = str_replace('$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content);
344
-
345
- // Replace URLs
346
- $content = str_replace(get_home_url(), get_home_url() . '/' . $this->options->cloneDirectoryName, $content);
347
-
348
- if (false === @file_put_contents($path, $content))
349
- {
350
- $this->log("Search & Replace: Failed to update $table_prefix in {$path} to " .$this->prefix . ". Can't save contents", Logger::TYPE_ERROR);
351
- return false;
352
- }
353
-
354
- return true;
355
- }
356
-
357
- /**
358
- * Reset index.php to original file
359
- * Check first if main wordpress is used in subfolder and index.php in parent directory
360
- * @see: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
361
- * @return bool
362
- */
363
- protected function step6()
364
- {
365
- // No settings, all good
366
- if (!isset($this->settings->wpSubDirectory) || "1" !== $this->settings->wpSubDirectory)
367
- {
368
- $this->log("Search & Replace: WP installation is not in a subdirectory! All good, skipping this step");
369
- return true;
370
- }
371
-
372
- $path = ABSPATH . $this->options->cloneDirectoryName . "/index.php";
373
-
374
- if (false === ($content = file_get_contents($path)))
375
- {
376
- $this->log("Search & Replace: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR);
377
- return false;
378
- }
379
-
380
-
381
- if (!preg_match("/(require(.*)wp-blog-header.php' \);)/", $content, $matches))
382
- {
383
- $this->log(
384
- "Search & Replace: Failed to reset index.php for sub directory; wp-blog-header.php is missing",
385
- Logger::TYPE_ERROR
386
- );
387
- return false;
388
- }
389
-
390
- $pattern = "/require(.*) dirname(.*) __FILE__ (.*) \. '(.*)wp-blog-header.php'(.*);/";
391
-
392
- $replace = "require( dirname( __FILE__ ) . '/wp-blog-header.php' ); // " . $matches[0];
393
- $replace.= " // Changed by WP-Staging";
394
-
395
- if (null === preg_replace($pattern, $replace, $content))
396
- {
397
- $this->log("Search & Replace: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR);
398
- return false;
399
- }
400
-
401
- if (false === @file_put_contents($path, $content))
402
- {
403
- $this->log("Search & Replace: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR);
404
- return false;
405
- }
406
-
407
- return true;
408
- }
409
}
1
+ <?php
2
+ namespace WPStaging\Backend\Modules\Jobs;
3
+
4
+ // No Direct Access
5
+ if (!defined("WPINC"))
6
+ {
7
+ die;
8
+ }
9
+
10
+ use WPStaging\Utils\Logger;
11
+ use WPStaging\WPStaging;
12
+
13
+ /**
14
+ * Class Data
15
+ * @package WPStaging\Backend\Modules\Jobs
16
+ */
17
+ class Data extends JobExecutable
18
+ {
19
+
20
+ /**
21
+ * @var \wpdb
22
+ */
23
+ private $db;
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ private $prefix;
29
+
30
+ /**
31
+ * Initialize
32
+ */
33
+ public function initialize()
34
+ {
35
+ $this->db = WPStaging::getInstance()->get("wpdb");
36
+
37
+ $this->prefix = $this->options->prefix;
38
+
39
+ // Fix current step
40
+ if (0 == $this->options->currentStep)
41
+ {
42
+ $this->options->currentStep = 1;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
48
+ * @return void
49
+ */
50
+ protected function calculateTotalSteps()
51
+ {
52
+ $this->options->totalSteps = 6;
53
+ }
54
+
55
+ /**
56
+ * Start Module
57
+ * @return object
58
+ */
59
+ public function start()
60
+ {
61
+ // Execute steps
62
+ $this->run();
63
+
64
+ // Save option, progress
65
+ $this->saveOptions();
66
+
67
+ // Prepare response
68
+ // $this->response = array(
69
+ // "status" => true,
70
+ // "percentage" => 100,
71
+ // "total" => $this->options->totalSteps,
72
+ // "step" => $this->options->totalSteps,
73
+ // "last_msg" => $this->logger->getLastLogMsg(),
74
+ // "running_time" => $this->time() - time(),
75
+ // "job_done" => true
76
+ // );
77
+
78
+ return (object) $this->response;
79
+ }
80
+
81
+ /**
82
+ * Execute the Current Step
83
+ * Returns false when over threshold limits are hit or when the job is done, true otherwise
84
+ * @return bool
85
+ */
86
+ protected function execute()
87
+ {
88
+ // Fatal error. Let this happen never and break here immediately
89
+ if ($this->isRoot()){
90
+ return false;
91
+ }
92
+
93
+ // Over limits threshold
94
+ if ($this->isOverThreshold())
95
+ {
96
+ // Prepare response and save current progress
97
+ $this->prepareResponse(false, false);
98
+ $this->saveOptions();
99
+ return false;
100
+ }
101
+
102
+ // No more steps, finished
103
+ if ($this->isFinished())
104
+ {
105
+ $this->prepareResponse(true, false);
106
+ return false;
107
+ }
108
+
109
+ // Execute step
110
+ $stepMethodName = "step" . $this->options->currentStep;
111
+ if (!$this->{$stepMethodName}())
112
+ {
113
+ $this->prepareResponse(false, false);
114
+ return false;
115
+ }
116
+
117
+ // Prepare Response
118
+ $this->prepareResponse();
119
+
120
+ // Not finished
121
+ return true;
122
+ }
123
+
124
+ /**
125
+ * Checks Whether There is Any Job to Execute or Not
126
+ * @return bool
127
+ */
128
+ private function isFinished()
129
+ {
130
+ return (
131
+ $this->options->currentStep > $this->options->totalSteps ||
132
+ !method_exists($this, "step" . $this->options->currentStep)
133
+ );
134
+ }
135
+
136
+ /**
137
+ * Check if current operation is done on the root folder or on the live DB
138
+ * @return boolean
139
+ */
140
+ private function isRoot(){
141
+
142
+ // Prefix is the same as the one of live site
143
+ $wpdb = WPStaging::getInstance()->get("wpdb");
144
+ if ($wpdb->prefix === $this->prefix){
145
+ return true;
146
+ }
147
+
148
+ // CloneName is empty
149
+ $name = (array)$this->options->cloneDirectoryName;
150
+ if (empty($name)){
151
+ return true;
152
+ }
153
+
154
+ // Live Path === Staging path
155
+ if (get_home_url() . $this->options->cloneDirectoryName === get_home_url()){
156
+ return true;
157
+ }
158
+
159
+ return false;
160
+ }
161
+
162
+
163
+ /**
164
+ * Check if table exists
165
+ * @param string $table
166
+ * @return boolean
167
+ */
168
+ protected function isTable($table){
169
+ if($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table ){
170
+ $this->log( "Table {$table} does not exists", Logger::TYPE_ERROR );
171
+ return false;
172
+ }
173
+ return true;
174
+ }
175
+
176
+ /**
177
+ * Replace "siteurl"
178
+ * @return bool
179
+ */
180
+ protected function step1() {
181
+ $this->log( "Search & Replace: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO );
182
+
183
+ if( false === $this->isTable( $this->prefix . 'options' ) ) {
184
+ return true;
185
+ }
186
+
187
+ // Installed in sub-directory
188
+ //if( isset( $this->settings->wpSubDirectory ) && "1" === $this->settings->wpSubDirectory ) {
189
+ if( $this->isSubDir() ) {
190
+ $subDirectory = str_replace( get_home_path(), '', ABSPATH );
191
+ $this->log( "Updating siteurl and homeurl to " . get_home_url() . '/' . $subDirectory . $this->options->cloneDirectoryName );
192
+ // Replace URLs
193
+ $result = $this->db->query(
194
+ $this->db->prepare(
195
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", get_home_url() . '/' . $subDirectory . $this->options->cloneDirectoryName
196
+ )
197
+ );
198
+ } else {
199
+ $this->log( "Search & Replace:: Updating siteurl and homeurl to " . get_home_url() . '/' . $this->options->cloneDirectoryName );
200
+ // Replace URLs
201
+ $result = $this->db->query(
202
+ $this->db->prepare(
203
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", get_home_url() . '/' . $this->options->cloneDirectoryName
204
+ )
205
+ );
206
+ }
207
+
208
+
209
+ // All good
210
+ if( $result ) {
211
+ return true;
212
+ }
213
+
214
+ $this->log( "Search & Replace: Failed to update siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
215
+ return false;
216
+ }
217
+
218
+ /**
219
+ * Update "wpstg_is_staging_site"
220
+ * @return bool
221
+ */
222
+ protected function step2()
223
+ {
224
+
225
+ $this->log( "Search & Replace: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}" );
226
+
227
+ if( false === $this->isTable( $this->prefix . 'options' ) ) {
228
+ return true;
229
+ }
230
+
231
+ $result = $this->db->query(
232
+ $this->db->prepare(
233
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_is_staging_site'",
234
+ "true"
235
+ )
236
+ );
237
+
238
+ // No errors but no option name such as wpstg_is_staging_site
239
+ if ('' === $this->db->last_error && 0 == $result)
240
+ {
241
+ $result = $this->db->query(
242
+ $this->db->prepare(
243
+ "INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_is_staging_site',%s)",
244
+ "true"
245
+ )
246
+ );
247
+ }
248
+
249
+ // All good
250
+ if ($result)
251
+ {
252
+ return true;
253
+ }
254
+
255
+ $this->log("Search & Replace: Failed to update wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
256
+ return false;
257
+ }
258
+
259
+ /**
260
+ * Update rewrite_rules
261
+ * @return bool
262
+ */
263
+ protected function step3()
264
+ {
265
+
266
+ $this->log("Search & Replace: Updating rewrite_rules in {$this->prefix}options {$this->db->last_error}");
267
+
268
+ if( false === $this->isTable( $this->prefix . 'options' ) ) {
269
+ return true;
270
+ }
271
+
272
+ $result = $this->db->query(
273
+ $this->db->prepare(
274
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'rewrite_rules'",
275
+ ' '
276
+ )
277
+ );
278
+
279
+ // All good
280
+ if ($result)
281
+ {
282
+ return true;
283
+ }
284
+
285
+ $this->log("Failed to update rewrite_rules in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
286
+ return true;
287
+ }
288
+
289
+ /**
290
+ * Update Table Prefix in meta_keys
291
+ * @return bool
292
+ */
293
+ protected function step4() {
294
+ $this->log( "Search & Replace: Updating {$this->prefix}usermeta db prefix {$this->db->last_error}" );
295
+
296
+ if( false === $this->isTable( $this->prefix . 'usermeta' ) ) {
297
+ return true;
298
+ }
299
+
300
+ $resultOptions = $this->db->query(
301
+ $this->db->prepare(
302
+ "UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
303
+ )
304
+ );
305
+
306
+ if( !$resultOptions ) {
307
+ $this->log( "Search & Replace: Failed to update usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
308
+ return false;
309
+ }
310
+
311
+ $this->log( "Updating {$this->prefix}options, option_name database table prefixes; {$this->db->last_error}" );
312
+
313
+ $resultUserMeta = $this->db->query(
314
+ $this->db->prepare(
315
+ "UPDATE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
316
+ )
317
+ );
318
+
319
+ if( !$resultUserMeta ) {
320
+ $this->log( "Search & Replace: Failed to update options, option_name database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
321
+ return false;
322
+ }
323
+
324
+ return true;
325
+ }
326
+
327
+ /**
328
+ * Update $table_prefix in wp-config.php
329
+ * @return bool
330
+ */
331
+ protected function step5()
332
+ {
333
+ $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
334
+
335
+ $this->log("Search & Replace: Updating table_prefix in {$path} to " . $this->prefix);
336
+ if (false === ($content = file_get_contents($path)))
337
+ {
338
+ $this->log("Search & Replace: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR);
339
+ return false;
340
+ }
341
+
342
+ // Replace table prefix
343
+ $content = str_replace('$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content);
344
+
345
+ // Replace URLs
346
+ $content = str_replace(get_home_url(), get_home_url() . '/' . $this->options->cloneDirectoryName, $content);
347
+
348
+ if (false === @file_put_contents($path, $content))
349
+ {
350
+ $this->log("Search & Replace: Failed to update $table_prefix in {$path} to " .$this->prefix . ". Can't save contents", Logger::TYPE_ERROR);
351
+ return false;
352
+ }
353
+
354
+ return true;
355
+ }
356
+
357
+ /**
358
+ * Reset index.php to original file
359
+ * This is needed if live site is located in subfolder
360
+ * Check first if main wordpress is used in subfolder and index.php in parent directory
361
+ * @see: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
362
+ * @return bool
363
+ */
364
+ protected function step6()
365
+ {
366
+ // No settings, all good
367
+ // if (!isset($this->settings->wpSubDirectory) || "1" !== $this->settings->wpSubDirectory)
368
+ // {
369
+ // $this->log("Search & Replace: WP installation is not in a subdirectory! All good, skipping this step");
370
+ // return true;
371
+ // }
372
+ if (!$this->isSubDir())
373
+ {
374
+ $this->debugLog("Search & Replace: WP installation is not in a subdirectory! All good, skipping this step");
375
+ return true;
376
+ }
377
+
378
+ $path = ABSPATH . $this->options->cloneDirectoryName . "/index.php";
379
+
380
+ if (false === ($content = file_get_contents($path)))
381
+ {
382
+ $this->log("Search & Replace: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR);
383
+ return false;
384
+ }
385
+
386
+
387
+ if (!preg_match("/(require(.*)wp-blog-header.php' \);)/", $content, $matches))
388
+ {
389
+ $this->log(
390
+ "Search & Replace: Failed to reset index.php for sub directory; wp-blog-header.php is missing",
391
+ Logger::TYPE_ERROR
392
+ );
393
+ return false;
394
+ }
395
+ $this->log("Search & Replace: WP installation is in a subdirectory. Progressing...");
396
+
397
+ $pattern = "/require(.*) dirname(.*) __FILE__ (.*) \. '(.*)wp-blog-header.php'(.*);/";
398
+
399
+ $replace = "require( dirname( __FILE__ ) . '/wp-blog-header.php' ); // " . $matches[0];
400
+ $replace.= " // Changed by WP-Staging";
401
+
402
+
403
+
404
+ if (null === ($content = preg_replace(array($pattern), $replace, $content)))
405
+ {
406
+ $this->log("Search & Replace: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR);
407
+ return false;
408
+ }
409
+
410
+ if (false === @file_put_contents($path, $content))
411
+ {
412
+ $this->log("Search & Replace: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR);
413
+ return false;
414
+ }
415
+ $this->Log("Search & Replace: Finished Step 6 successfully");
416
+
417
+ return true;
418
+ }
419
+
420
+ /**
421
+ * Update wpstg_rmpermalinks_executed
422
+ * @return bool
423
+ */
424
+ protected function step7()
425
+ {
426
+
427
+ $this->log("Search & Replace: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}");
428
+
429
+ if( false === $this->isTable( $this->prefix . 'options' ) ) {
430
+ return true;
431
+ }
432
+
433
+ $result = $this->db->query(
434
+ $this->db->prepare(
435
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_rmpermalinks_executed'",
436
+ ' '
437
+ )
438
+ );
439
+
440
+ // All good
441
+ if ($result)
442
+ {
443
+ return true;
444
+ }
445
+
446
+ $this->log("Failed to update wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_WARNING);
447
+ return true;
448
+ }
449
+
450
+ /**
451
+ * Check if WP is installed in subdir
452
+ * @return boolean
453
+ */
454
+ protected function isSubDir(){
455
+ if ( get_option( 'siteurl' ) !== get_option( 'home' ) ) {
456
+ return true;
457
+ }
458
+ return false;
459
+ }
460
}
apps/Backend/Modules/Jobs/Database.php CHANGED
@@ -1,263 +1,265 @@
1
- <?php </