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

Version Description

  • New: Performance improvement increase db query limit to 5000
  • New: Detect automatically if WordPress is installed in sub folder
  • Tweak: Tested up to WP 4.9.4
  • Fix: Updating from an old version 1.1.6 < to latest version deletes the staging sites listing table
  • Fix: Reduce memory size of the logging window to prevent browser timeouts
  • Fix: Can not copy db table if table name contains the db prefix multiple times
  • Fix: Some excluded folders are not ignored during copy process
  • Fix: mod_security is causing script termination
  • Fix: Skip directory listings for symlinks
Download this release

Release Info

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

Code changes from version 2.1.8 to 2.1.9

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 +221 -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 +314 -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" ), __( "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