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

Version Description

  • New: Compatible to WP 5.0.0 Gutenberg
  • New: Increase file scanning process performance
  • New: Preview for external database cloning
  • New: Add delay between requests setting to prevent timeouts on rate limited servers
  • New: Try again automatically cloning process if ajax request has been killed due to server ressource limit error

  • Fix: Error when removing heartbeat api

  • Fix: remove ? parameter from staging site

  • Fix: Do not load theme while WP Staging is running. Prevents processing interruption if there are fatal errors in the theme

  • Fix: When cloning has been canceled page needs to be reloaded before beeing able to clone again

  • Fix: Under rare circumstances plugins are disabled when wp staging runs.

  • Fix: Prevent error 503 (firewall/performance timeout) by adding post parameter to the ajax url

  • Fix: Adding automatic resume function to the ajax processing to prevent cloning and pushing interruptions due to hitting server ressource or network glitches.

  • Fix: Selected folders are not excluded under Windows IIS server

  • Fix: Windows IIS server compatibilility issues resolved

Download this release

Release Info

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

Code changes from version 2.3.9 to 2.4.0

Files changed (39) hide show
  1. apps/Backend/Administrator.php +8 -13
  2. apps/Backend/Modules/Jobs/Cloning.php +377 -271
  3. apps/Backend/Modules/Jobs/Data.php +141 -63
  4. apps/Backend/Modules/Jobs/Delete.php +11 -1
  5. apps/Backend/Modules/Jobs/Directories.php +18 -58
  6. apps/Backend/Modules/Jobs/Files.php +381 -343
  7. apps/Backend/Modules/Jobs/Finish.php +98 -58
  8. apps/Backend/Modules/Jobs/Job.php +1 -81
  9. apps/Backend/Modules/Jobs/Multisite/Data.php +937 -894
  10. apps/Backend/Modules/Jobs/Multisite/DataExternal.php +1041 -988
  11. apps/Backend/Modules/Jobs/Multisite/Database.php +112 -65
  12. apps/Backend/Modules/Jobs/Multisite/DatabaseExternal.php +118 -57
  13. apps/Backend/Modules/Jobs/Multisite/Directories.php +8 -4
  14. apps/Backend/Modules/Jobs/Multisite/Files.php +407 -359
  15. apps/Backend/Modules/Jobs/Multisite/Finish.php +101 -59
  16. apps/Backend/Modules/Jobs/Multisite/SearchReplace.php +761 -717
  17. apps/Backend/Modules/Jobs/Multisite/SearchReplaceExternal.php +793 -672
  18. apps/Backend/Modules/Jobs/SearchReplace.php +710 -636
  19. apps/Backend/Modules/Jobs/Updating.php +299 -250
  20. apps/Backend/Modules/SystemInfo.php +1 -2
  21. apps/Backend/Modules/Views/Forms/Settings.php +0 -10
  22. apps/Backend/Optimizer/blank-theme/functions.php +7 -0
  23. apps/Backend/Optimizer/wp-staging-optimizer.php +88 -14
  24. apps/Backend/public/css/wpstg-admin.css +261 -262
  25. apps/Backend/public/js/wpstg-admin.js +64 -34
  26. apps/Backend/views/_includes/header.php +2 -2
  27. apps/Backend/views/clone/ajax/custom-directory.php +36 -0
  28. apps/Backend/views/clone/ajax/delete-confirmation.php +2 -2
  29. apps/Backend/views/clone/ajax/external-database.php +6 -8
  30. apps/Backend/views/clone/ajax/scan.php +54 -59
  31. apps/Backend/views/settings/main-settings.php +219 -235
  32. apps/Core/DTO/Settings.php +83 -74
  33. apps/Core/Utils/Strings.php +41 -32
  34. apps/Core/Utils/functions.php +75 -0
  35. apps/Core/WPStaging.php +434 -403
  36. apps/Frontend/Frontend.php +1 -21
  37. apps/Frontend/loginForm.php +252 -250
  38. readme.txt +23 -3
  39. wp-staging.php +2 -2
apps/Backend/Administrator.php CHANGED
@@ -7,27 +7,21 @@ 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
use WPStaging\Utils\Report;
31
32
/**
33
* Class Administrator
@@ -95,7 +89,8 @@ class Administrator extends InjectionAware {
95
$loader->addAction( "wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName" );
96
$loader->addAction( "wp_ajax_wpstg_update", $this, "ajaxUpdateProcess" );
97
$loader->addAction( "wp_ajax_wpstg_cloning", $this, "ajaxStartClone" );
98
- $loader->addAction( "wp_ajax_wpstg_clone_database", $this, "ajaxCloneDatabase" );
99
$loader->addAction( "wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories" );
100
$loader->addAction( "wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles" );
101
$loader->addAction( "wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData" );
@@ -141,8 +136,6 @@ class Administrator extends InjectionAware {
141
142
add_settings_error( "wpstg-notices", '', __( "Settings updated.", "wp-staging" ), "updated" );
143
144
- // Return sanitized data
145
- //return $sanitized;
146
return apply_filters( "wpstg-settings", $sanitized, $data );
147
}
148
@@ -380,6 +373,8 @@ class Administrator extends InjectionAware {
380
// Get license data
381
$license = get_option( 'wpstg_license_status' );
382
383
384
if( \WPStaging\WPStaging::getSlug() === 'wp-staging-pro' ) {
385
require_once "{$this->path}Pro/views/single-overview-pro.php";
@@ -450,7 +445,7 @@ class Administrator extends InjectionAware {
450
$cloning = new Updating();
451
452
if( !$cloning->save() ) {
453
- wp_die('can not save clone data');
454
}
455
456
require_once "{$this->path}views/clone/ajax/update.php";
@@ -467,7 +462,7 @@ class Administrator extends InjectionAware {
467
$cloning = new Cloning();
468
469
if( !$cloning->save() ) {
470
- wp_die('can not save clone data');
471
}
472
473
require_once "{$this->path}views/clone/ajax/start.php";
7
die;
8
}
9
10
+ use WPStaging\WPStaging;
11
use WPStaging\Backend\Modules\Jobs\Cancel;
12
use WPStaging\Backend\Modules\Jobs\CancelUpdate;
13
use WPStaging\Backend\Modules\Jobs\Cloning;
14
use WPStaging\Backend\Modules\Jobs\Updating;
15
use WPStaging\Backend\Modules\Jobs\Delete;
16
use WPStaging\Backend\Modules\Jobs\Scan;
17
use WPStaging\Backend\Modules\Jobs\Logs;
18
use WPStaging\Backend\Modules\SystemInfo;
19
use WPStaging\Backend\Modules\Views\Tabs\Tabs;
20
use WPStaging\Backend\Notices\Notices;
21
use WPStaging\DI\InjectionAware;
22
use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
23
use WPStaging\Utils\Report;
24
+ use WPStaging\Backend\Activation;
25
26
/**
27
* Class Administrator
89
$loader->addAction( "wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName" );
90
$loader->addAction( "wp_ajax_wpstg_update", $this, "ajaxUpdateProcess" );
91
$loader->addAction( "wp_ajax_wpstg_cloning", $this, "ajaxStartClone" );
92
+ $loader->addAction( "wp_ajax_wpstg_processing", $this, "ajaxCloneDatabase" );
93
+ $loader->addAction( "wp_ajax_wpstg_database_connect", $this, "ajaxDatabaseConnect" );
94
$loader->addAction( "wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories" );
95
$loader->addAction( "wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles" );
96
$loader->addAction( "wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData" );
136
137
add_settings_error( "wpstg-notices", '', __( "Settings updated.", "wp-staging" ), "updated" );
138
139
return apply_filters( "wpstg-settings", $sanitized, $data );
140
}
141
373
// Get license data
374
$license = get_option( 'wpstg_license_status' );
375
376
+ // Get db
377
+ $db = WPStaging::getInstance()->get( 'wpdb' );
378
379
if( \WPStaging\WPStaging::getSlug() === 'wp-staging-pro' ) {
380
require_once "{$this->path}Pro/views/single-overview-pro.php";
445
$cloning = new Updating();
446
447
if( !$cloning->save() ) {
448
+ wp_die( 'can not save clone data' );
449
}
450
451
require_once "{$this->path}views/clone/ajax/update.php";
462
$cloning = new Cloning();
463
464
if( !$cloning->save() ) {
465
+ wp_die( 'can not save clone data' );
466
}
467
468
require_once "{$this->path}views/clone/ajax/start.php";
apps/Backend/Modules/Jobs/Cloning.php CHANGED
@@ -4,6 +4,7 @@ namespace WPStaging\Backend\Modules\Jobs;
4
5
use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
6
use WPStaging\WPStaging;
7
8
/**
9
* Class Cloning
@@ -11,276 +12,381 @@ use WPStaging\WPStaging;
11
*/
12
class Cloning extends Job {
13
14
- /**
15
- * Initialize is called in \Job
16
- */
17
- public function initialize() {
18
- $this->db = WPStaging::getInstance()->get( "wpdb" );
19
- }
20
-
21
- /**
22
- * Save Chosen Cloning Settings
23
- * @return bool
24
- */
25
- public function save() {
26
- if( !isset( $_POST ) || !isset( $_POST["cloneID"] ) ) {
27
- return false;
28
- }
29
-
30
- // Generate Options
31
- // Clone
32
- $this->options->clone = $_POST["cloneID"];
33
- $this->options->cloneDirectoryName = preg_replace( "#\W+#", '-', strtolower( $this->options->clone ) );
34
- $this->options->cloneNumber = 1;
35
- $this->options->prefix = $this->setStagingPrefix();
36
- $this->options->includedDirectories = array();
37
- $this->options->excludedDirectories = array();
38
- $this->options->extraDirectories = array();
39
- $this->options->excludedFiles = array(
40
- '.htaccess',
41
- '.DS_Store',
42
- '.git',
43
- '.svn',
44
- '.tmp',
45
- 'desktop.ini',
46
- '.gitignore',
47
- '.log',
48
- 'web.config'
49
- );
50
- $this->options->excludedFilesFullPath = array(
51
- 'wp-content' . DIRECTORY_SEPARATOR . 'db.php',
52
- 'wp-content' . DIRECTORY_SEPARATOR . 'object-cache.php',
53
- 'wp-content' . DIRECTORY_SEPARATOR . 'advanced-cache.php'
54
- );
55
- $this->options->currentStep = 0;
56
-
57
-
58
- // Job
59
- $this->options->job = new \stdClass();
60
-
61
- // Check if clone data already exists and use that one
62
- if( isset( $this->options->existingClones[$this->options->clone] ) ) {
63
-
64
- $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
65
-
66
- $this->options->prefix = isset( $this->options->existingClones[$this->options->clone]->prefix ) ?
67
- $this->options->existingClones[$this->options->clone]->prefix :
68
- $this->setStagingPrefix();
69
- } // Clone does not exist but there are other clones in db
70
- // Get data and increment it
71
- elseif( !empty( $this->options->existingClones ) ) {
72
- $this->options->cloneNumber = count( $this->options->existingClones ) + 1;
73
- $this->options->prefix = $this->setStagingPrefix();
74
- }
75
-
76
- // Included Tables
77
- if( isset( $_POST["includedTables"] ) && is_array( $_POST["includedTables"] ) ) {
78
- $this->options->tables = $_POST["includedTables"];
79
- } else {
80
- $this->options->tables = array();
81
- }
82
- // Excluded Tables
83
- // if (isset($_POST["excludedTables"]) && is_array($_POST["excludedTables"]))
84
- // {
85
- // $this->options->excludedTables = $_POST["excludedTables"];
86
- // }
87
- // Excluded Directories
88
- if( isset( $_POST["excludedDirectories"] ) && is_array( $_POST["excludedDirectories"] ) ) {
89
- $this->options->excludedDirectories = $_POST["excludedDirectories"];
90
- }
91
-
92
-
93
- // Excluded Directories TOTAL
94
- // Do not copy these folders and plugins
95
- $excludedDirectories = array(
96
- \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
97
- \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
98
- \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-super-cache',
99
- \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'peters-login-redirect',
100
- );
101
-
102
- $this->options->excludedDirectories = array_merge( $excludedDirectories, $this->options->excludedDirectories );
103
-
104
- // Included Directories
105
- if( isset( $_POST["includedDirectories"] ) && is_array( $_POST["includedDirectories"] ) ) {
106
- $this->options->includedDirectories = $_POST["includedDirectories"];
107
- }
108
-
109
- // Extra Directories
110
- if( isset( $_POST["extraDirectories"] ) && !empty( $_POST["extraDirectories"] ) ) {
111
- $this->options->extraDirectories = $_POST["extraDirectories"];
112
- }
113
-
114
- // Directories to Copy
115
- $this->options->directoriesToCopy = array_merge(
116
- $this->options->includedDirectories, $this->options->extraDirectories
117
- );
118
-
119
- array_unshift( $this->options->directoriesToCopy, \WPStaging\WPStaging::getWPpath() );
120
-
121
- $this->options->databaseServer = 'localhost';
122
- if( isset( $_POST["databaseServer"] ) && !empty( $_POST["databaseServer"] ) ) {
123
- $this->options->databaseServer = $_POST["databaseServer"];
124
- }
125
- $this->options->databaseUser = '';
126
- if( isset( $_POST["databaseUser"] ) && !empty( $_POST["databaseUser"] ) ) {
127
- $this->options->databaseUser = $_POST["databaseUser"];
128
- }
129
- $this->options->databasePassword = '';
130
- if( isset( $_POST["databasePassword"] ) && !empty( $_POST["databasePassword"] ) ) {
131
- $this->options->databasePassword = $_POST["databasePassword"];
132
- }
133
- $this->options->databaseDatabase = '';
134
- if( isset( $_POST["databaseDatabase"] ) && !empty( $_POST["databaseDatabase"] ) ) {
135
- $this->options->databaseDatabase = $_POST["databaseDatabase"];
136
- }
137
- $this->options->databasePrefix = 'wp_';
138
- if( isset( $_POST["databasePrefix"] ) && !empty( $_POST["databasePrefix"] ) ) {
139
- $this->options->databasePrefix = $_POST["databasePrefix"];
140
- }
141
-
142
-
143
-
144
- // Delete files to copy listing
145
- $this->cache->delete( "files_to_copy" );
146
-
147
- return $this->saveOptions();
148
- }
149
-
150
- /**
151
- * Create a new staging prefix which does not already exists in database
152
- */
153
- private function setStagingPrefix() {
154
-
155
- // Get & find a new prefix that does not already exist in database.
156
- // Loop through up to 1000 different possible prefixes should be enough here;)
157
- for ( $i = 0; $i <= 10000; $i++ ) {
158
- $this->options->prefix = isset( $this->options->existingClones ) ?
159
- 'wpstg' . (count( $this->options->existingClones ) + $i) . '_' :
160
- 'wpstg' . $i . '_';
161
-
162
- $sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
163
- $tables = $this->db->get_results( $sql );
164
-
165
- // Prefix does not exists. We can use it
166
- if( !$tables ) {
167
- return $this->options->prefix;
168
- }
169
- }
170
- $this->returnException( "Fatal Error: Can not create staging prefix. '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com" );
171
- wp_die( "Fatal Error: Can not create staging prefix. Prefix '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com" );
172
- }
173
-
174
- /**
175
- * Check if potential new prefix of staging site would be identical with live site.
176
- * @return boolean
177
- */
178
- private function isPrefixIdentical() {
179
- $db = WPStaging::getInstance()->get( "wpdb" );
180
-
181
- $livePrefix = $db->prefix;
182
- $stagingPrefix = $this->options->prefix;
183
-
184
- if( $livePrefix == $stagingPrefix ) {
185
- return true;
186
- }
187
- return false;
188
- }
189
-
190
- /**
191
- * Start the cloning job
192
- */
193
- public function start() {
194
- if( null === $this->options->currentJob ) {
195
- $this->log( "Cloning job for {$this->options->clone} finished" );
196
- return true;
197
- }
198
-
199
- $methodName = "job" . ucwords( $this->options->currentJob );
200
-
201
- if( !method_exists( $this, $methodName ) ) {
202
- $this->log( "Can't execute job; Job's method {$methodName} is not found" );
203
- throw new JobNotFoundException( $methodName );
204
- }
205
-
206
- // Call the job
207
- //$this->log("execute job: Job's method {$methodName}");
208
- return $this->{$methodName}();
209
- }
210
-
211
- /**
212
- * @param object $response
213
- * @param string $nextJob
214
- * @return object
215
- */
216
- private function handleJobResponse( $response, $nextJob ) {
217
- // Job is not done
218
- if( true !== $response->status ) {
219
- return $response;
220
- }
221
-
222
- $this->options->currentJob = $nextJob;
223
- $this->options->currentStep = 0;
224
- $this->options->totalSteps = 0;
225
-
226
- // Save options
227
- $this->saveOptions();
228
-
229
- return $response;
230
- }
231
-
232
- /**
233
- * Clone Database
234
- * @return object
235
- */
236
- public function jobDatabase() {
237
- $database = new Database();
238
- return $this->handleJobResponse( $database->start(), "SearchReplace" );
239
- }
240
-
241
- /**
242
- * Search & Replace
243
- * @return object
244
- */
245
- public function jobSearchReplace() {
246
- $searchReplace = new SearchReplace();
247
- return $this->handleJobResponse( $searchReplace->start(), "directories" );
248
- }
249
-
250
- /**
251
- * Get All Files From Selected Directories Recursively Into a File
252
- * @return object
253
- */
254
- public function jobDirectories() {
255
- $directories = new Directories();
256
- return $this->handleJobResponse( $directories->start(), "files" );
257
- }
258
-
259
- /**
260
- * Copy Files
261
- * @return object
262
- */
263
- public function jobFiles() {
264
- $files = new Files();
265
- return $this->handleJobResponse( $files->start(), "data" );
266
- }
267
-
268
- /**
269
- * Replace Data
270
- * @return object
271
- */
272
- public function jobData() {
273
- $data = new Data();
274
- return $this->handleJobResponse( $data->start(), "finish" );
275
- }
276
-
277
- /**
278
- * Save Clone Data
279
- * @return object
280
- */
281
- public function jobFinish() {
282
- $finish = new Finish();
283
- return $this->handleJobResponse( $finish->start(), '' );
284
- }
285
286
}
4
5
use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
6
use WPStaging\WPStaging;
7
+ use WPStaging\Utils\Helper;
8
9
/**
10
* Class Cloning
12
*/
13
class Cloning extends Job {
14
15
+ /**
16
+ * Initialize is called in \Job
17
+ */
18
+ public function initialize() {
19
+ $this->db = WPStaging::getInstance()->get( "wpdb" );
20
+ }
21
+
22
+ /**
23
+ * Save Chosen Cloning Settings
24
+ * @return bool
25
+ */
26
+ public function save() {
27
+ if( !isset( $_POST ) || !isset( $_POST["cloneID"] ) ) {
28
+ return false;
29
+ }
30
+
31
+ // Delete files to copy listing
32
+ $this->cache->delete( "files_to_copy" );
33
+
34
+ // Generate Options
35
+ // Clone
36
+ $this->options->clone = $_POST["cloneID"];
37
+ $this->options->cloneDirectoryName = preg_replace( "#\W+#", '-', strtolower( $this->options->clone ) );
38
+ $this->options->cloneNumber = 1;
39
+ $this->options->prefix = $this->setStagingPrefix();
40
+ $this->options->includedDirectories = array();
41
+ $this->options->excludedDirectories = array();
42
+ $this->options->extraDirectories = array();
43
+ $this->options->excludedFiles = array(
44
+ '.htaccess',
45
+ '.DS_Store',
46
+ '.git',
47
+ '.svn',
48
+ '.tmp',
49
+ 'desktop.ini',
50
+ '.gitignore',
51
+ '.log',
52
+ 'web.config'
53
+ );
54
+ $this->options->excludedFilesFullPath = array(
55
+ 'wp-content' . DIRECTORY_SEPARATOR . 'db.php',
56
+ 'wp-content' . DIRECTORY_SEPARATOR . 'object-cache.php',
57
+ 'wp-content' . DIRECTORY_SEPARATOR . 'advanced-cache.php'
58
+ );
59
+ $this->options->currentStep = 0;
60
+
61
+ // Job
62
+ $this->options->job = new \stdClass();
63
+
64
+ // Check if clone data already exists and use that one
65
+ if( isset( $this->options->existingClones[$this->options->clone] ) ) {
66
+
67
+ $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
68
+
69
+ $this->options->prefix = isset( $this->options->existingClones[$this->options->clone]->prefix ) ?
70
+ $this->options->existingClones[$this->options->clone]->prefix :
71
+ $this->setStagingPrefix();
72
+ }
73
+ // Clone does not exist but there are other clones in db
74
+ // Get data and increment it
75
+ elseif( !empty( $this->options->existingClones ) ) {
76
+ $this->options->cloneNumber = count( $this->options->existingClones ) + 1;
77
+ $this->options->prefix = $this->setStagingPrefix();
78
+ }
79
+
80
+ // Included Tables
81
+ if( isset( $_POST["includedTables"] ) && is_array( $_POST["includedTables"] ) ) {
82
+ $this->options->tables = $_POST["includedTables"];
83
+ } else {
84
+ $this->options->tables = array();
85
+ }
86
+
87
+ // Excluded Directories
88
+ if( isset( $_POST["excludedDirectories"] ) && is_array( $_POST["excludedDirectories"] ) ) {
89
+ $this->options->excludedDirectories = $_POST["excludedDirectories"];
90
+ }
91
+
92
+ // Excluded Directories TOTAL
93
+ // Do not copy these folders and plugins
94
+ $excludedDirectories = array(
95
+ \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
96
+ \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
97
+ \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-super-cache',
98
+ \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'peters-login-redirect',
99
+ );
100
+
101
+ $this->options->excludedDirectories = array_merge( $excludedDirectories, $this->options->excludedDirectories );
102
+
103
+ array_unshift( $this->options->directoriesToCopy, \WPStaging\WPStaging::getWPpath() );
104
+
105
+ // Included Directories
106
+ if( isset( $_POST["includedDirectories"] ) && is_array( $_POST["includedDirectories"] ) ) {
107
+ $this->options->includedDirectories = $_POST["includedDirectories"];
108
+ }
109
+
110
+ // Extra Directories
111
+ if( isset( $_POST["extraDirectories"] ) && !empty( $_POST["extraDirectories"] ) ) {
112
+ $this->options->extraDirectories = $_POST["extraDirectories"];
113
+ }
114
+
115
+ // Directories to Copy
116
+ $this->options->directoriesToCopy = array_merge(
117
+ $this->options->includedDirectories, $this->options->extraDirectories
118
+ );
119
+
120
+
121
+ $this->options->databaseServer = 'localhost';
122
+ if( isset( $_POST["databaseServer"] ) && !empty( $_POST["databaseServer"] ) ) {
123
+ $this->options->databaseServer = $_POST["databaseServer"];
124
+ }
125
+ $this->options->databaseUser = '';
126
+ if( isset( $_POST["databaseUser"] ) && !empty( $_POST["databaseUser"] ) ) {
127
+ $this->options->databaseUser = $_POST["databaseUser"];
128
+ }
129
+ $this->options->databasePassword = '';
130
+ if( isset( $_POST["databasePassword"] ) && !empty( $_POST["databasePassword"] ) ) {
131
+ $this->options->databasePassword = $_POST["databasePassword"];
132
+ }
133
+ $this->options->databaseDatabase = '';
134
+ if( isset( $_POST["databaseDatabase"] ) && !empty( $_POST["databaseDatabase"] ) ) {
135
+ $this->options->databaseDatabase = $_POST["databaseDatabase"];
136
+ }
137
+ $this->options->databasePrefix = '';
138
+ if( isset( $_POST["databasePrefix"] ) && !empty( $_POST["databasePrefix"] ) ) {
139
+ $this->options->databasePrefix = $this->sanitizePrefix( $_POST["databasePrefix"] );
140
+ }
141
+ $this->options->cloneDir = '';
142
+ if( isset( $_POST["cloneDir"] ) && !empty( $_POST["cloneDir"] ) ) {
143
+ $this->options->cloneDir = trailingslashit( $_POST["cloneDir"] );
144
+ }
145
+ $this->options->cloneHostname = '';
146
+ if( isset( $_POST["cloneHostname"] ) && !empty( $_POST["cloneHostname"] ) ) {
147
+ $this->options->cloneHostname = $_POST["cloneHostname"];
148
+ }
149
+
150
+ $this->options->destinationHostname = $this->getDestinationHostname();
151
+ $this->options->destinationDir = $this->getDestinationDir();
152
+
153
+ $helper = new Helper();
154
+ $this->options->homeHostname = $helper->get_home_url_without_scheme();
155
+
156
+ return $this->saveOptions();
157
+ }
158
+
159
+ /**
160
+ * Return target hostname
161
+ * @return string
162
+ */
163
+ private function getDestinationHostname() {
164
+ if( empty( $this->options->cloneHostname ) ) {
165
+ $helper = new Helper();
166
+ return $helper->get_home_url_without_scheme();
167
+ }
168
+ return $this->getHostnameWithoutScheme( $this->options->cloneHostname );
169
+ }
170
+
171
+ /**
172
+ * Return Hostname without scheme
173
+ * @param string $str
174
+ * @return string
175
+ */
176
+ private function getHostnameWithoutScheme( $string ) {
177
+ return preg_replace( '#^https?://#', '', rtrim( $string, '/' ) );
178
+ }
179
+
180
+ /**
181
+ * Get Destination Directory including staging subdirectory
182
+ * @return type
183
+ */
184
+ private function getDestinationDir() {
185
+ // No custom clone dir or clone dir equals abspath of main wordpress site
186
+ if( empty( $this->options->cloneDir ) || $this->options->cloneDir == (string)\WPStaging\WPStaging::getWPpath()) {
187
+ return trailingslashit( \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName );
188
+ }
189
+ //return trailingslashit($this->options->cloneDir . $this->options->cloneDirectoryName);
190
+ return trailingslashit( $this->options->cloneDir );
191
+ }
192
+
193
+ /**
194
+ * Check if WP is installed in subdir
195
+ * @return boolean
196
+ */
197
+ // private function isSubDir() {
198
+ // // Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
199
+ // // This is happening much more often than you would expect
200
+ // $siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
201
+ // $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
202
+ //
203
+ // if( $home !== $siteurl ) {
204
+ // return true;
205
+ // }
206
+ // return false;
207
+ // }
208
+
209
+ /**
210
+ * Get the install sub directory if WP is installed in sub directory or return empty string
211
+ * Result contains a trailingslash
212
+ * @return string
213
+ */
214
+ // private function getSubDir() {
215
+ //
216
+ // if(!$this->isSubDir()){
217
+ // return '';
218
+ // }
219
+ //
220
+ // $home = get_option( 'home' );
221
+ // $siteurl = get_option( 'siteurl' );
222
+ //
223
+ // if( empty( $home ) || empty( $siteurl ) ) {
224
+ // return '';
225
+ // }
226
+ //
227
+ // $dir = str_replace( $home, '', $siteurl );
228
+ // return trailingslashit($dir);
229
+ // }
230
+
231
+ /**
232
+ * Get Destination Directory
233
+ * @return type
234
+ */
235
+ // private function getDestinationRoot() {
236
+ // if( empty( $this->options->cloneDir ) ) {
237
+ // return \WPStaging\WPStaging::getWPpath();
238
+ // }
239
+ // return $this->options->cloneDir;
240
+ // }
241
+
242
+ /**
243
+ * Make sure prefix contains appending underscore
244
+ *
245
+ * @param string $string
246
+ * @return string
247
+ */
248
+ private function sanitizePrefix( $string ) {
249
+ $lastCharacter = substr( $string, -1 );
250
+ if( $lastCharacter === '_' ) {
251
+ return $string;
252
+ }
253
+ return $string . '_';
254
+ }
255
+
256
+ /**
257
+ * Create a new staging prefix which does not already exists in database
258
+ */
259
+ private function setStagingPrefix() {
260
+
261
+ // Get & find a new prefix that does not already exist in database.
262
+ // Loop through up to 1000 different possible prefixes should be enough here;)
263
+ for ( $i = 0; $i <= 10000; $i++ ) {
264
+ $this->options->prefix = isset( $this->options->existingClones ) ?
265
+ 'wpstg' . (count( $this->options->existingClones ) + $i) . '_' :
266
+ 'wpstg' . $i . '_';
267
+
268
+ $sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
269
+ $tables = $this->db->get_results( $sql );
270
+
271
+ // Prefix does not exists. We can use it
272
+ if( !$tables ) {
273
+ return $this->options->prefix;
274
+ }
275
+ }
276
+ $this->returnException( "Fatal Error: Can not create staging prefix. '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com" );
277
+ wp_die( "Fatal Error: Can not create staging prefix. Prefix '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com" );
278
+ }
279
+
280
+ /**
281
+ * Check if potential new prefix of staging site would be identical with live site.
282
+ * @return boolean
283
+ */
284
+ private function isPrefixIdentical() {
285
+ $db = WPStaging::getInstance()->get( "wpdb" );
286
+
287
+ $livePrefix = $db->prefix;
288
+ $stagingPrefix = $this->options->prefix;
289
+
290
+ if( $livePrefix == $stagingPrefix ) {
291
+ return true;
292
+ }
293
+ return false;
294
+ }
295
+
296
+ /**
297
+ * Start the cloning job
298
+ */
299
+ public function start() {
300
+ if( null === $this->options->currentJob ) {
301
+ $this->log( "Cloning job for {$this->options->clone} finished" );
302
+ return true;
303
+ }
304
+
305
+ $methodName = "job" . ucwords( $this->options->currentJob );
306
+
307
+ if( !method_exists( $this, $methodName ) ) {
308
+ $this->log( "Can't execute job; Job's method {$methodName} is not found" );
309
+ throw new JobNotFoundException( $methodName );
310
+ }
311
+
312
+ // Call the job
313
+ //$this->log("execute job: Job's method {$methodName}");
314
+ return $this->{$methodName}();
315
+ }
316
+
317
+ /**
318
+ * @param object $response
319
+ * @param string $nextJob
320
+ * @return object
321
+ */
322
+ private function handleJobResponse( $response, $nextJob ) {
323
+ // Job is not done
324
+ if( true !== $response->status ) {
325
+ return $response;
326
+ }
327
+
328
+ $this->options->currentJob = $nextJob;
329
+ $this->options->currentStep = 0;
330
+ $this->options->totalSteps = 0;
331
+
332
+ // Save options
333
+ $this->saveOptions();
334
+
335
+ return $response;
336
+ }
337
+
338
+ /**
339
+ * Clone Database
340
+ * @return object
341
+ */
342
+ public function jobDatabase() {
343
+ $database = new Database();
344
+ return $this->handleJobResponse( $database->start(), "SearchReplace" );
345
+ }
346
+
347
+ /**
348
+ * Search & Replace
349
+ * @return object
350
+ */
351
+ public function jobSearchReplace() {
352
+ $searchReplace = new SearchReplace();
353
+ return $this->handleJobResponse( $searchReplace->start(), "directories" );
354
+ }
355
+
356
+ /**
357
+ * Get All Files From Selected Directories Recursively Into a File
358
+ * @return object
359
+ */
360
+ public function jobDirectories() {
361
+ $directories = new Directories();
362
+ return $this->handleJobResponse( $directories->start(), "files" );
363
+ }
364
+
365
+ /**
366
+ * Copy Files
367
+ * @return object
368
+ */
369
+ public function jobFiles() {
370
+ $files = new Files();
371
+ return $this->handleJobResponse( $files->start(), "data" );
372
+ }
373
+
374
+ /**
375
+ * Replace Data
376
+ * @return object
377
+ */
378
+ public function jobData() {
379
+ $data = new Data();
380
+ return $this->handleJobResponse( $data->start(), "finish" );
381
+ }
382
+
383
+ /**
384
+ * Save Clone Data
385
+ * @return object
386
+ */
387
+ public function jobFinish() {
388
+ $finish = new Finish();
389
+ return $this->handleJobResponse( $finish->start(), '' );
390
+ }
391
392
}
apps/Backend/Modules/Jobs/Data.php CHANGED
@@ -50,11 +50,9 @@ class Data extends JobExecutable {
50
51
$this->getTables();
52
53
- $helper = new Helper();
54
-
55
$this->homeUrl = $helper->get_home_url();
56
57
-
58
// Fix current step
59
if( 0 == $this->options->currentStep ) {
60
$this->options->currentStep = 0;
@@ -65,7 +63,7 @@ class Data extends JobExecutable {
65
* Get a list of tables to copy
66
*/
67
private function getTables() {
68
- $strings = new Strings();
69
$this->tables = array();
70
foreach ( $this->options->tables as $table ) {
71
$this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, $table );
@@ -77,7 +75,7 @@ class Data extends JobExecutable {
77
* @return void
78
*/
79
protected function calculateTotalSteps() {
80
- $this->options->totalSteps = 14;
81
}
82
83
/**
@@ -183,22 +181,6 @@ class Data extends JobExecutable {
183
return true;
184
}
185
186
- /**
187
- * Get the install sub directory if WP is installed in sub directory
188
- * @return string
189
- */
190
- protected function getSubDir() {
191
- $home = get_option( 'home' );
192
- $siteurl = get_option( 'siteurl' );
193
-
194
- if( empty( $home ) || empty( $siteurl ) ) {
195
- return '/';
196
- }
197
-
198
- $dir = str_replace( $home, '', $siteurl );
199
- return '/' . str_replace( '/', '', $dir ) . '/';
200
- }
201
-
202
/**
203
* Copy wp-config.php if it is located outside of root one level up
204
* @todo Needs some more testing before it will be released
@@ -211,7 +193,7 @@ class Data extends JobExecutable {
211
212
$source = $dir . 'wp-config.php';
213
214
- $destination = trailingslashit( ABSPATH ) . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR . 'wp-config.php';
215
216
217
// Do not do anything
@@ -258,28 +240,36 @@ class Data extends JobExecutable {
258
}
259
260
// Installed in sub-directory
261
- if( $this->isSubDir() ) {
262
- $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->homeUrl, "/" ) . $this->getSubDir() . $this->options->cloneDirectoryName );
263
// Replace URLs
264
$result = $this->db->query(
265
$this->db->prepare(
266
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", rtrim( $this->homeUrl, "/" ) . $this->getSubDir() . $this->options->cloneDirectoryName
267
)
268
);
269
- } else {
270
- $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->homeUrl, "/" ) . '/' . $this->options->cloneDirectoryName );
271
- // Replace URLs
272
- $result = $this->db->query(
273
- $this->db->prepare(
274
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->homeUrl . '/' . $this->options->cloneDirectoryName
275
- )
276
- );
277
- }
278
279
280
// All good
281
- if( false !== $result) {
282
- $this->log( "Preparing Data Step1: Successfull", Logger::TYPE_INFO );
283
return true;
284
}
285
@@ -306,6 +296,11 @@ class Data extends JobExecutable {
306
return true;
307
}
308
309
$delete = $this->db->query(
310
$this->db->prepare(
311
"DELETE FROM `{$this->prefix}options` WHERE `option_name` = %s;", 'wpstg_is_staging_site'
@@ -321,7 +316,6 @@ class Data extends JobExecutable {
321
)
322
);
323
//}
324
-
325
// All good
326
if( $insert ) {
327
$this->log( "Preparing Data Step2: Successfull", Logger::TYPE_INFO );
@@ -394,7 +388,7 @@ class Data extends JobExecutable {
394
395
if( !$update ) {
396
$this->log( "Preparing Data Step4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
397
- $this->returnException( "Data Crunching Step 4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}" );
398
return false;
399
}
400
@@ -408,7 +402,7 @@ class Data extends JobExecutable {
408
* @return bool
409
*/
410
protected function step5() {
411
- $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
412
413
$this->log( "Preparing Data Step5: Updating table_prefix in {$path} to " . $this->prefix );
414
if( false === ($content = file_get_contents( $path )) ) {
@@ -420,7 +414,7 @@ class Data extends JobExecutable {
420
$content = str_replace( '$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content );
421
422
// Replace URLs
423
- $content = str_replace( $this->homeUrl, $this->homeUrl . '/' . $this->options->cloneDirectoryName, $content );
424
425
if( false === @file_put_contents( $path, $content ) ) {
426
$this->log( "Preparing Data Step5: Failed to update $table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR );
@@ -444,7 +438,7 @@ class Data extends JobExecutable {
444
return true;
445
}
446
447
- $path = ABSPATH . $this->options->cloneDirectoryName . "/index.php";
448
449
if( false === ($content = file_get_contents( $path )) ) {
450
$this->log( "Preparing Data Step6: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR );
@@ -476,7 +470,7 @@ class Data extends JobExecutable {
476
$this->log( "Preparing Data: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR );
477
return false;
478
}
479
- $this->Log( "Preparing Data: Finished Step 6 successfully" );
480
return true;
481
}
482
@@ -507,7 +501,7 @@ class Data extends JobExecutable {
507
508
// All good
509
if( $result ) {
510
- $this->Log( "Preparing Data Step7: Finished Step 7 successfully" );
511
return true;
512
}
513
@@ -542,7 +536,7 @@ class Data extends JobExecutable {
542
543
// All good
544
if( $result ) {
545
- $this->Log( "Preparing Data Step8: Finished Step 8 successfully" );
546
return true;
547
}
548
@@ -576,7 +570,7 @@ class Data extends JobExecutable {
576
577
// All good
578
if( $result ) {
579
- $this->Log( "Preparing Data Step9: Finished Step 9 successfully" );
580
return true;
581
}
582
@@ -589,7 +583,7 @@ class Data extends JobExecutable {
589
* @return bool
590
*/
591
protected function step10() {
592
- $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
593
594
$this->log( "Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl() );
595
@@ -622,7 +616,7 @@ class Data extends JobExecutable {
622
$this->log( "Preparing Data Step10: Failed to update WP_HOME. Can't save contents", Logger::TYPE_ERROR );
623
return false;
624
}
625
- $this->Log( "Preparing Data: Finished Step 10 successfully" );
626
return true;
627
}
628
@@ -631,7 +625,7 @@ class Data extends JobExecutable {
631
* @return bool
632
*/
633
protected function step11() {
634
- $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
635
636
$this->log( "Preparing Data Step11: Updating WP_SITEURL in wp-config.php to " . $this->getStagingSiteUrl() );
637
@@ -665,11 +659,77 @@ class Data extends JobExecutable {
665
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR );
666
return false;
667
}
668
- $this->Log( "Preparing Data: Finished Step 11 successfully" );
669
return true;
670
}
671
672
/**
673
* Update Table Prefix in wp_options
674
* @return bool
675
*/
@@ -687,10 +747,9 @@ class Data extends JobExecutable {
687
return true;
688
}
689
690
- $notice = isset( $this->db->last_error ) ? 'Last error: ' . $this->db->last_error : '';
691
-
692
- $this->log( "Updating option_name in {$this->prefix}options. {$notice}" );
693
694
// Filter the rows below. Do not update them!
695
$filters = array(
696
'wp_mail_smtp',
@@ -712,11 +771,11 @@ class Data extends JobExecutable {
712
);
713
714
if( !$updateOptions ) {
715
- $this->log( "Preparing Data Step12: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}", Logger::TYPE_ERROR );
716
$this->returnException( " Preparing Data Step12: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}" );
717
return false;
718
}
719
- $this->Log( "Preparing Data: Finished Step 12 successfully" );
720
return true;
721
}
722
@@ -735,13 +794,13 @@ class Data extends JobExecutable {
735
$newUploadPath = $this->getNewUploadPath();
736
737
if( false === $newUploadPath ) {
738
- $this->log( "Preparing Data Step13: Skipping" );
739
return true;
740
}
741
742
// Skip - Table is not selected or updated
743
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
744
- $this->log( "Preparing Data Step13: Skipping" );
745
return true;
746
}
747
@@ -759,7 +818,7 @@ class Data extends JobExecutable {
759
$this->log( "Preparing Data Step13: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR );
760
return true;
761
}
762
- $this->Log( "Preparing Data: Finished Step 13 successfully" );
763
return true;
764
}
765
@@ -768,7 +827,7 @@ class Data extends JobExecutable {
768
* @return bool
769
*/
770
protected function step14() {
771
- $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
772
773
$this->log( "Preparing Data Step14: Set WP_CACHE in wp-config.php to false" );
774
@@ -801,7 +860,7 @@ class Data extends JobExecutable {
801
$this->log( "Preparing Data Step14: Failed to update WP_CACHE. Can't save contents", Logger::TYPE_ERROR );
802
return false;
803
}
804
- $this->Log( "Preparing Data: Finished Step 14 successfully" );
805
return true;
806
}
807
@@ -814,7 +873,7 @@ class Data extends JobExecutable {
814
815
$customSlug = str_replace( \WPStaging\WPStaging::getWPpath(), '', $uploadPath );
816
817
- $newUploadPath = \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR . $customSlug;
818
819
return $newUploadPath;
820
}
@@ -824,11 +883,14 @@ class Data extends JobExecutable {
824
* @return string
825
*/
826
protected function getStagingSiteUrl() {
827
if( $this->isSubDir() ) {
828
- return rtrim( $this->homeUrl, "/" ) . $this->getSubDir() . $this->options->cloneDirectoryName;
829
}
830
831
- return rtrim( $this->homeUrl, "/" ) . '/' . $this->options->cloneDirectoryName;
832
}
833
834
/**
@@ -839,7 +901,7 @@ class Data extends JobExecutable {
839
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
840
// This is happening much more often than you would expect
841
$siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
842
- $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
843
844
if( $home !== $siteurl ) {
845
return true;
@@ -847,4 +909,20 @@ class Data extends JobExecutable {
847
return false;
848
}
849
850
}
50
51
$this->getTables();
52
53
+ $helper = new Helper();
54
$this->homeUrl = $helper->get_home_url();
55
56
// Fix current step
57
if( 0 == $this->options->currentStep ) {
58
$this->options->currentStep = 0;
63
* Get a list of tables to copy
64
*/
65
private function getTables() {
66
+ $strings = new Strings();
67
$this->tables = array();
68
foreach ( $this->options->tables as $table ) {
69
$this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, $table );
75
* @return void
76
*/
77
protected function calculateTotalSteps() {
78
+ $this->options->totalSteps = 15;
79
}
80
81
/**
181
return true;
182
}
183
184
/**
185
* Copy wp-config.php if it is located outside of root one level up
186
* @todo Needs some more testing before it will be released
193
194
$source = $dir . 'wp-config.php';
195
196
+ $destination = $this->options->destinationDir . 'wp-config.php';
197
198
199
// Do not do anything
240
}
241
242
// Installed in sub-directory
243
+ // if( $this->isSubDir() ) {
244
+ // $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl() );
245
+ // // Replace URLs
246
+ // $result = $this->db->query(
247
+ // $this->db->prepare(
248
+ // "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->getStagingSiteUrl()
249
+ // )
250
+ // );
251
+ // } else {
252
+ // $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl() );
253
+ // // Replace URLs
254
+ // $result = $this->db->query(
255
+ // $this->db->prepare(
256
+ // "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->getStagingSiteUrl()
257
+ // )
258
+ // );
259
+ // }
260
+
261
+ $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl() );
262
// Replace URLs
263
$result = $this->db->query(
264
$this->db->prepare(
265
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->getStagingSiteUrl()
266
)
267
);
268
+
269
270
271
// All good
272
+ if( $result ) {
273
return true;
274
}
275
296
return true;
297
}
298
299
+ // $result = $this->db->query(
300
+ // $this->db->prepare(
301
+ // "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_is_staging_site'", "true"
302
+ // )
303
+ // );
304
$delete = $this->db->query(
305
$this->db->prepare(
306
"DELETE FROM `{$this->prefix}options` WHERE `option_name` = %s;", 'wpstg_is_staging_site'
316
)
317
);
318
//}
319
// All good
320
if( $insert ) {
321
$this->log( "Preparing Data Step2: Successfull", Logger::TYPE_INFO );
388
389
if( !$update ) {
390
$this->log( "Preparing Data Step4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
391
+ $this->returnException( "Preparing Data Step4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}" );
392
return false;
393
}
394
402
* @return bool
403
*/
404
protected function step5() {
405
+ $path = $this->options->destinationDir . "wp-config.php";
406
407
$this->log( "Preparing Data Step5: Updating table_prefix in {$path} to " . $this->prefix );
408
if( false === ($content = file_get_contents( $path )) ) {
414
$content = str_replace( '$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content );
415
416
// Replace URLs
417
+ $content = str_replace( $this->homeUrl, $this->getStagingSiteUrl(), $content );
418
419
if( false === @file_put_contents( $path, $content ) ) {
420
$this->log( "Preparing Data Step5: Failed to update $table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR );
438
return true;
439
}
440
441
+ $path = $this->options->destinationDir . "index.php";
442
443
if( false === ($content = file_get_contents( $path )) ) {
444
$this->log( "Preparing Data Step6: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR );
470
$this->log( "Preparing Data: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR );
471
return false;
472
}
473
+ $this->Log( "Preparing Data Step 6: Finished successfully" );
474
return true;
475
}
476
501
502
// All good
503
if( $result ) {
504
+ $this->Log( "Preparing Data Step7: Finished successfully" );
505
return true;
506
}
507
536
537
// All good
538
if( $result ) {
539
+ $this->Log( "Preparing Data Step8: Finished successfully" );
540
return true;
541
}
542
570
571
// All good
572
if( $result ) {
573
+ $this->Log( "Preparing Data Step9: Finished successfully" );
574
return true;
575
}
576
583
* @return bool
584
*/
585
protected function step10() {
586
+ $path = $this->options->destinationDir . "wp-config.php";
587
588
$this->log( "Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl() );
589
616
$this->log( "Preparing Data Step10: Failed to update WP_HOME. Can't save contents", Logger::TYPE_ERROR );
617
return false;
618
}
619
+ $this->Log( "Preparing Data Step 10: Finished successfully" );
620
return true;
621
}
622
625
* @return bool
626
*/
627
protected function step11() {
628
+ $path = $this->options->destinationDir . "wp-config.php";
629
630
$this->log( "Preparing Data Step11: Updating WP_SITEURL in wp-config.php to " . $this->getStagingSiteUrl() );
631
659
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR );
660
return false;
661
}
662
+ $this->Log( "Preparing Data Step 11: Finished successfully" );
663
return true;
664
}
665
666
/**
667
+ * Set true WP_DEBUG & WP_DEBUG_DISPLAY in wp-config.php
668
+ * @return bool
669
+ */
670
+ // protected function step12() {
671
+ // $path = $this->getAbsDestination() . $this->options->cloneDirectoryName . "/wp-config.php";
672
+ //
673
+ // $this->log( "Preparing Data Step12: Set WP_DEBUG to true in wp-config.php." );
674
+ //
675
+ // if( false === ($content = file_get_contents( $path )) ) {
676
+ // $this->log( "Preparing Data Step12: Failed to update WP_DEBUG in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
677
+ // return false;
678
+ // }
679
+ //
680
+ //
681
+ // // Get WP_DEBUG from wp-config.php
682
+ // preg_match( "/define\s*\(\s*'WP_DEBUG'\s*,\s*(.*)\s*\);/", $content, $matches );
683
+ //
684
+ // // Found it!
685
+ // if( !empty( $matches[1] ) ) {
686
+ // $matches[1];
687
+ //
688
+ // $pattern = "/define\s*\(\s*'WP_DEBUG'\s*,\s*(.*)\s*\);/";
689
+ //
690
+ // $replace = "define('WP_DEBUG',true); // " . $matches[1];
691
+ // $replace.= " // Changed by WP-Staging";
692
+ //
693
+ // if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
694
+ // $this->log( "Preparing Data Step12: Failed to update WP_DEBUG", Logger::TYPE_ERROR );
695
+ // return false;
696
+ // }
697
+ // } else {
698
+ // $this->log( "Preparing Data Step12: WP_DEBUG not defined in wp-config.php. Skip it." );
699
+ // }
700
+ //
701
+ //
702
+ //
703
+ // // Get WP_DEBUG_DISPLAY
704
+ // preg_match( "/define\s*\(\s*'WP_DEBUG_DISPLAY'\s*,\s*(.*)\s*\);/", $content, $matches );
705
+ //
706
+ // // Found it!
707
+ // if( !empty( $matches[1] ) ) {
708
+ // $matches[1];
709
+ //
710
+ // $pattern = "/define\s*\(\s*'WP_DEBUG_DISPLAY'\s*,\s*(.*)\s*\);/";
711
+ //
712
+ // $replace = "define('WP_DEBUG_DISPLAY',true); // " . $matches[1];
713
+ // $replace.= " // Changed by WP-Staging";
714
+ //
715
+ // if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
716
+ // $this->log( "Preparing Data Step12: Failed to update WP_DEBUG", Logger::TYPE_ERROR );
717
+ // return false;
718
+ // }
719
+ // } else {
720
+ // $this->log( "Preparing Data Step12: WP_DEBUG not defined in wp-config.php. Skip it." );
721
+ // }
722
+ //
723
+ //
724
+ // if( false === @file_put_contents( $path, $content ) ) {
725
+ // $this->log( "Preparing Data Step12: Failed to update WP_DEBUG. Can't save content in wp-config.php", Logger::TYPE_ERROR );
726
+ // return false;
727
+ // }
728
+ // $this->Log( "Preparing Data: Finished Step 12 successfully" );
729
+ // return true;
730
+ // }
731
+
732
+ /**
733
* Update Table Prefix in wp_options
734
* @return bool
735
*/
747
return true;
748
}
749
750
+ $notice = !empty( $this->db->last_error ) ? 'Last error: ' . $this->db->last_error : '';
751
752
+ //$this->log( "Updating option_name in {$this->prefix}options. {$notice}" );
753
// Filter the rows below. Do not update them!
754
$filters = array(
755
'wp_mail_smtp',
771
);
772
773
if( !$updateOptions ) {
774
+ $this->log( "Preparing Data Step12: Failed to update option_name in {$this->prefix}options. Error: {$this->db->last_error}", Logger::TYPE_ERROR );
775
$this->returnException( " Preparing Data Step12: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}" );
776
return false;
777
}
778
+ $this->Log( "Preparing Data Step 12: Finished successfully" );
779
return true;
780
}
781
794
$newUploadPath = $this->getNewUploadPath();
795
796
if( false === $newUploadPath ) {
797
+ $this->log( "Preparing Data Step13: Skipped" );
798
return true;
799
}
800
801
// Skip - Table is not selected or updated
802
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
803
+ $this->log( "Preparing Data Step13: Skipped" );
804
return true;
805
}
806
818
$this->log( "Preparing Data Step13: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR );
819
return true;
820
}
821
+ $this->Log( "Preparing Data Step 13: Finished successfully" );
822
return true;
823
}
824
827
* @return bool
828
*/
829
protected function step14() {
830
+ $path = $this->options->destinationDir . "wp-config.php";
831
832
$this->log( "Preparing Data Step14: Set WP_CACHE in wp-config.php to false" );
833
860
$this->log( "Preparing Data Step14: Failed to update WP_CACHE. Can't save contents", Logger::TYPE_ERROR );
861
return false;
862
}
863
+ $this->Log( "Preparing Data Step 14: Finished successfully" );
864
return true;
865
}
866
873
874
$customSlug = str_replace( \WPStaging\WPStaging::getWPpath(), '', $uploadPath );
875
876
+ $newUploadPath = $this->options->destinationDir . $customSlug;
877
878
return $newUploadPath;
879
}
883
* @return string
884
*/
885
protected function getStagingSiteUrl() {
886
+ if( !empty( $this->options->cloneHostname ) ) {
887
+ return $this->options->cloneHostname;
888
+ }
889
if( $this->isSubDir() ) {
890
+ return trailingslashit( $this->homeUrl ) . trailingslashit( $this->getSubDir() ) . $this->options->cloneDirectoryName;
891
}
892
893
+ return trailingslashit( $this->homeUrl ) . $this->options->cloneDirectoryName;
894
}
895
896
/**
901
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
902
// This is happening much more often than you would expect
903
$siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
904
+ $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
905
906
if( $home !== $siteurl ) {
907
return true;
909
return false;
910
}
911
912
+ /**
913
+ * Get the install sub directory if WP is installed in sub directory
914
+ * @return string
915
+ */
916
+ protected function getSubDir() {
917
+ $home = get_option( 'home' );
918
+ $siteurl = get_option( 'siteurl' );
919
+
920
+ if( empty( $home ) || empty( $siteurl ) ) {
921
+ return '';
922
+ }
923
+
924
+ $dir = str_replace( $home, '', $siteurl );
925
+ return str_replace( '/', '', $dir );
926
+ }
927
+
928
}
apps/Backend/Modules/Jobs/Delete.php CHANGED
@@ -38,12 +38,18 @@ class Delete extends Job {
38
* @var object
39
*/
40
public $wpdb;
41
private $isExternal;
42
43
public function __construct( $isExternal = false ) {
44
parent::__construct();
45
$this->isExternal = $isExternal;
46
- //$this->wpdb = WPStaging::getInstance()->get("wpdb");
47
}
48
49
/**
@@ -74,6 +80,10 @@ class Delete extends Job {
74
return new \wpdb( $this->clone->databaseUser, $this->clone->databasePassword, $this->clone->databaseDatabase, $this->clone->databaseServer );
75
}
76
77
public function getDbName() {
78
return $this->wpdb->dbname;
79
}
38
* @var object
39
*/
40
public $wpdb;
41
+
42
+ /**
43
+ *
44
+ * @var bool
45
+ */
46
private $isExternal;
47
48
+
49
+
50
public function __construct( $isExternal = false ) {
51
parent::__construct();
52
$this->isExternal = $isExternal;
53
}
54
55
/**
80
return new \wpdb( $this->clone->databaseUser, $this->clone->databasePassword, $this->clone->databaseDatabase, $this->clone->databaseServer );
81
}
82
83
+ /**
84
+ * Date database name
85
+ * @return type
86
+ */
87
public function getDbName() {
88
return $this->wpdb->dbname;
89
}
apps/Backend/Modules/Jobs/Directories.php CHANGED
@@ -68,8 +68,6 @@ class Directories extends JobExecutable {
68
return ( object ) $this->response;
69
}
70
71
-
72
-
73
/**
74
* Step 0
75
* Get WP Root files
@@ -94,14 +92,13 @@ class Directories extends JobExecutable {
94
if( $this->write( $files, $iterator->getFilename() . PHP_EOL ) ) {
95
$this->options->totalFiles++;
96
97
- // Add current file size
98
- $this->options->totalFileSize += $iterator->getSize();
99
}
100
}
101
}
102
} catch ( \Exception $e ) {
103
$this->returnException( 'Error: ' . $e->getMessage() );
104
- //throw new \Exception('Out of disk space.');
105
} catch ( \Exception $e ) {
106
// Skip bad file permissions
107
}
@@ -118,7 +115,7 @@ class Directories extends JobExecutable {
118
119
// Skip it
120
if( $this->isDirectoryExcluded( WP_CONTENT_DIR ) ) {
121
- $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR);
122
return true;
123
}
124
// open file handle
@@ -127,9 +124,7 @@ class Directories extends JobExecutable {
127
$excludeWpContent = array(
128
'cache',
129
'wps-hide-login',
130
- 'node_modules',
131
- 'nbproject',
132
- '.idea'
133
);
134
135
try {
@@ -153,8 +148,8 @@ class Directories extends JobExecutable {
153
if( $this->write( $files, 'wp-content' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
154
$this->options->totalFiles++;
155
156
- // Add current file size
157
- $this->options->totalFileSize += $iterator->getSize();
158
}
159
}
160
}
@@ -179,7 +174,7 @@ class Directories extends JobExecutable {
179
180
// Skip it
181
if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR ) ) {
182
- $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR);
183
return true;
184
}
185
@@ -205,8 +200,8 @@ class Directories extends JobExecutable {
205
if( $this->write( $files, 'wp-includes' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
206
$this->options->totalFiles++;
207
208
- // Add current file size
209
- $this->options->totalFileSize += $iterator->getSize();
210
}
211
}
212
}
@@ -231,7 +226,7 @@ class Directories extends JobExecutable {
231
232
// Skip it
233
if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR ) ) {
234
- $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR);
235
return true;
236
}
237
@@ -256,8 +251,8 @@ class Directories extends JobExecutable {
256
if( $item->isFile() ) {
257
if( $this->write( $files, 'wp-admin' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
258
$this->options->totalFiles++;
259
- // Add current file size
260
- $this->options->totalFileSize += $iterator->getSize();
261
}
262
}
263
}
@@ -280,6 +275,9 @@ class Directories extends JobExecutable {
280
*/
281
private function getExtraFiles( $folder ) {
282
283
284
// open file handle and attach data to end of file
285
$files = $this->open( $this->filename, 'a' );
@@ -318,8 +316,8 @@ class Directories extends JobExecutable {
318
//if( $this->write( $files, $strings->getLastElemAfterString( '/', $folder ) . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
319
if( $this->write( $files, str_replace( \WPStaging\WPStaging::getWPpath(), '', $folder ) . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
320
$this->options->totalFiles++;
321
- // Add current file size
322
- $this->options->totalFileSize += $iterator->getSize();
323
}
324
}
325
}
@@ -332,43 +330,6 @@ class Directories extends JobExecutable {
332
// close the file handler
333
$this->close( $files );
334
return true;
335
-
336
-
337
- // Skip it
338
- // if ($this->isDirectoryExcluded(ABSPATH)){
339
- // return true;
340
- // }
341
- // // open file handle
342
- // $files = $this->open($this->filename, 'a');
343
- //
344
- //
345
- // try {
346
- //
347
- // // Iterate over wp root directory
348
- // $iterator = new \DirectoryIterator(ABSPATH);
349
- //
350
- // $this->log( "Scanning ".ABSPATH." for its sub-directories and files" );
351
- //
352
- // // Write path line
353
- // foreach ($iterator as $item) {
354
- // if (!$item->isDot() && $item->isFile()) {
355
- // if ($this->write($files, $iterator->getFilename() . PHP_EOL)) {
356
- // $this->options->totalFiles++;
357
- //
358
- // // Add current file size
359
- // $this->options->totalFileSize += $iterator->getSize();
360
- // }
361
- // }
362
- // }
363
- // } catch (\Exception $e) {
364
- // $this->returnException('Error: ' . $e->getMessage());
365
- // //throw new \Exception('Out of disk space.');
366
- // } catch (\Exception $e) {
367
- // // Skip bad file permissions
368
- // }
369
- //
370
- // $this->close($files);
371
- // return true;
372
}
373
374
/**
@@ -513,7 +474,6 @@ class Directories extends JobExecutable {
513
$this->files = explode( PHP_EOL, $this->files );
514
}
515
516
-
517
/**
518
* Replace forward slash with current directory separator
519
*
@@ -535,7 +495,7 @@ class Directories extends JobExecutable {
535
$directory = $this->sanitizeDirectorySeparator( $directory );
536
foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
537
$excludedDirectory = $this->sanitizeDirectorySeparator( $excludedDirectory );
538
- if( strpos( $directory, $excludedDirectory ) === 0 ) {
539
return true;
540
}
541
}
68
return ( object ) $this->response;
69
}
70
71
/**
72
* Step 0
73
* Get WP Root files
92
if( $this->write( $files, $iterator->getFilename() . PHP_EOL ) ) {
93
$this->options->totalFiles++;
94
95
+ // Too much cpu time
96
+ //$this->options->totalFileSize += $iterator->getSize();
97
}
98
}
99
}
100
} catch ( \Exception $e ) {
101
$this->returnException( 'Error: ' . $e->getMessage() );
102
} catch ( \Exception $e ) {
103
// Skip bad file permissions
104
}
115
116
// Skip it
117
if( $this->isDirectoryExcluded( WP_CONTENT_DIR ) ) {
118
+ $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR );
119
return true;
120
}
121
// open file handle
124
$excludeWpContent = array(
125
'cache',
126
'wps-hide-login',
127
+ 'node_modules'
128
);
129
130
try {
148
if( $this->write( $files, 'wp-content' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
149
$this->options->totalFiles++;
150
151
+ // Too much cpu time
152
+ //$this->options->totalFileSize += $iterator->getSize();
153
}
154
}
155
}
174
175
// Skip it
176
if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR ) ) {
177
+ $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR );
178
return true;
179
}
180
200
if( $this->write( $files, 'wp-includes' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
201
$this->options->totalFiles++;
202
203
+ // Too much cpu time
204
+ //$this->options->totalFileSize += $iterator->getSize();
205
}
206
}
207
}
226
227
// Skip it
228
if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR ) ) {
229
+ $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR );
230
return true;
231
}
232
251
if( $item->isFile() ) {
252
if( $this->write( $files, 'wp-admin' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
253
$this->options->totalFiles++;
254
+ // Too much cpu time
255
+ //$this->options->totalFileSize += $iterator->getSize();
256
}
257
}
258
}
275
*/
276
private function getExtraFiles( $folder ) {
277
278
+ if( !is_dir( $folder ) ) {
279
+ return true;
280
+ }
281
282
// open file handle and attach data to end of file
283
$files = $this->open( $this->filename, 'a' );
316
//if( $this->write( $files, $strings->getLastElemAfterString( '/', $folder ) . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
317
if( $this->write( $files, str_replace( \WPStaging\WPStaging::getWPpath(), '', $folder ) . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
318
$this->options->totalFiles++;
319
+ // Too much cpu time
320
+ //$this->options->totalFileSize += $iterator->getSize();
321
}
322
}
323
}
330
// close the file handler
331
$this->close( $files );
332
return true;
333
}
334
335
/**
474
$this->files = explode( PHP_EOL, $this->files );
475
}
476
477
/**
478
* Replace forward slash with current directory separator
479
*
495
$directory = $this->sanitizeDirectorySeparator( $directory );
496
foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
497
$excludedDirectory = $this->sanitizeDirectorySeparator( $excludedDirectory );
498
+ if( strpos( trailingslashit( $directory ), trailingslashit( $excludedDirectory ) ) === 0 ) {
499
return true;
500
}
501
}
apps/Backend/Modules/Jobs/Files.php CHANGED
@@ -7,7 +7,7 @@ use WPStaging\WPStaging;
7
use WPStaging\Utils\Logger;
8
9
if( !defined( "WPINC" ) ) {
10
- die;
11
}
12
13
/**
@@ -16,352 +16,390 @@ if( !defined( "WPINC" ) ) {
16
*/
17
class Files extends JobExecutable {
18
19
- /**
20
- * @var \SplFileObject
21
- */
22
- private $file;
23
-
24
- /**
25
- * @var int
26
- */
27
- private $maxFilesPerRun;
28
-
29
- /**
30
- * @var string
31
- */
32
- private $destination;
33
-
34
- /**
35
- * Initialization
36
- */
37
- public function initialize() {
38
-
39
- $this->destination = \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR;
40
-
41
- $filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
42
-
43
- if( is_file( $filePath ) ) {
44
- $this->file = new \SplFileObject( $filePath, 'r' );
45
- }
46
-
47
- // Informational logs
48
- if( 0 == $this->options->currentStep ) {
49
- $this->log( "Copying files..." );
50
- }
51
-
52
- $this->settings->batchSize = $this->settings->batchSize * 1000000;
53
- $this->maxFilesPerRun = $this->settings->fileLimit;
54
- }
55
-
56
- /**
57
- * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
58
- * @return void
59
- */
60
- protected function calculateTotalSteps() {
61
- $this->options->totalSteps = ceil( $this->options->totalFiles / $this->maxFilesPerRun );
62
- }
63
-
64
- /**
65
- * Execute the Current Step
66
- * Returns false when over threshold limits are hit or when the job is done, true otherwise
67
- * @return bool
68
- */
69
- protected function execute() {
70
- // Finished
71
- if( $this->isFinished() ) {
72
- $this->log( "Copying files finished" );
73
- $this->prepareResponse( true, false );
74
- return false;
75
- }
76
-
77
- // Get files and copy'em
78
- if( !$this->getFilesAndCopy() ) {
79
- $this->prepareResponse( false, false );
80
- return false;
81
- }
82
-
83
- // Prepare and return response
84
- $this->prepareResponse();
85
-
86
- // Not finished
87
- return true;
88
- }
89
-
90
- /**
91
- * Get files and copy
92
- * @return bool
93
- */
94
- private function getFilesAndCopy() {
95
- // Over limits threshold
96
- if( $this->isOverThreshold() ) {
97
- // Prepare response and save current progress
98
- $this->prepareResponse( false, false );
99
- $this->saveOptions();
100
- return false;
101
- }
102
-
103
- // Go to last copied line and than to next one
104
- //if ($this->options->copiedFiles != 0) {
105
- if( isset( $this->options->copiedFiles ) && $this->options->copiedFiles != 0 ) {
106
- $this->file->seek( $this->options->copiedFiles - 1 );
107
- }
108
-
109
- $this->file->setFlags( \SplFileObject::SKIP_EMPTY | \SplFileObject::READ_AHEAD );
110
-
111
-
112
- // Loop x files at a time
113
- for ( $i = 0; $i < $this->maxFilesPerRun; $i++ ) {
114
-
115
- // Increment copied files
116
- // Do this anytime to make sure to not stuck in the same step / files
117
- $this->options->copiedFiles++;
118
-
119
- // End of file
120
- if( $this->file->eof() ) {
121
- break;
122
- }
123
-
124
-
125
- $file = $this->file->fgets();
126
- //$this->debugLog('copy file ' . $file, Logger::TYPE_DEBUG);
127
- $this->copyFile( $file );
128
- }
129
-
130
- $totalFiles = $this->options->copiedFiles;
131
- // Log this only every 50 entries to keep the log small and to not block the rendering browser
132
- if( $this->options->copiedFiles % 50 == 0 ) {
133
- $this->log( "Total {$totalFiles} files processed" );
134
- }
135
-
136
- return true;
137
- }
138
-
139
- /**
140
- * Checks Whether There is Any Job to Execute or Not
141
- * @return bool
142
- */
143
- private function isFinished() {
144
- return (
145
- $this->options->currentStep > $this->options->totalSteps ||
146
- $this->options->copiedFiles >= $this->options->totalFiles
147
- );
148
- }
149
-
150
- /**
151
- * @param string $file
152
- * @return bool
153
- */
154
- private function copyFile( $file ) {
155
- $file = trim( \WPStaging\WPStaging::getWPpath() . $file );
156
-
157
- $directory = dirname( $file );
158
-
159
- // Directory is excluded
160
- if( $this->isDirectoryExcluded( $directory ) ) {
161
- $this->debugLog( "Directory Excluded: {$file}", Logger::TYPE_INFO );
162
- return false;
163
- }
164
-
165
- // File is excluded
166
- if( $this->isFileExcluded( $file ) ) {
167
- $this->debugLog( "File excluded: {$file}", Logger::TYPE_INFO );
168
- return false;
169
- }
170
-
171
- // Path + File is excluded
172
- if( $this->isFileExcludedFullPath( $file ) ) {
173
- $this->debugLog( "File Excluded Full Path: {$file}", Logger::TYPE_INFO );
174
- return false;
175
- }
176
-
177
-
178
- // Invalid file, skipping it as if succeeded
179
- if( !is_file( $file ) ) {
180
- $this->debugLog( "Not a file {$file}" );
181
- return true;
182
- }
183
-
184
- // Get file size
185
- $fileSize = filesize( $file );
186
- // File is over maximum allowed file size (8MB)
187
- if( $fileSize >= $this->settings->maxFileSize * 1000000 ) {
188
- $this->log( "Skipping big file: {$file}", Logger::TYPE_INFO );
189
- return false;
190
- }
191
- // Invalid file, skipping it as if succeeded
192
- if( !is_readable( $file ) ) {
193
- $this->log( "Can't read file {$file}" );
194
- return true;
195
- }
196
-
197
- // Failed to get destination
198
- if( false === ($destination = $this->getDestination( $file )) ) {
199
- $this->log( "Can't get the destination of {$file}" );
200
- return false;
201
- }
202
-
203
- // File is over batch size
204
- if( $fileSize >= $this->settings->batchSize ) {
205
- $this->log( "Trying to copy big file: {$file} -> {$destination}", Logger::TYPE_INFO );
206
- return $this->copyBig( $file, $destination, $this->settings->batchSize );
207
- }
208
-
209
- // Attempt to copy
210
- if( !@copy( $file, $destination ) ) {
211
- $errors = error_get_last();
212
- $this->log( "Files: Failed to copy file to destination. Error: {$errors['message']} {$file} -> {$destination}", Logger::TYPE_ERROR );
213
- return false;
214
- }
215
-
216
- return true;
217
-
218
- // Good old PHP
219
- //return $this->copy($file, $destination);
220
- }
221
-
222
- /**
223
- * Gets destination file and checks if the directory exists, if it does not attempts to create it.
224
- * If creating destination directory fails, it returns false, gives destination full path otherwise
225
- * @param string $file
226
- * @return bool|string
227
- */
228
- private function getDestination( $file ) {
229
- $relativePath = str_replace( \WPStaging\WPStaging::getWPpath(), null, $file );
230
- $destinationPath = $this->destination . $relativePath;
231
- $destinationDirectory = dirname( $destinationPath );
232
-
233
- if( !is_dir( $destinationDirectory ) && !@mkdir( $destinationDirectory, 0755, true ) ) {
234
- $this->log( "Files: Can not create directory {$destinationDirectory}", Logger::TYPE_ERROR );
235
- return false;
236
- }
237
-
238
- return $destinationPath;
239
- }
240
-
241
- /**
242
- * Copy bigger files than $this->settings->batchSize
243
- * @param string $src
244
- * @param string $dst
245
- * @param int $buffersize
246
- * @return boolean
247
- */
248
- private function copyBig( $src, $dst, $buffersize ) {
249
- $src = fopen( $src, 'r' );
250
- $dest = fopen( $dst, 'w' );
251
-
252
- // Try first method:
253
- while ( !feof( $src ) ) {
254
- if( false === fwrite( $dest, fread( $src, $buffersize ) ) ) {
255
- $error = true;
256
- }
257
- }
258
- // Try second method if first one failed
259
- if( isset( $error ) && ($error === true) ) {
260
- while ( !feof( $src ) ) {
261
- if( false === stream_copy_to_stream( $src, $dest, 1024 ) ) {
262
- $this->log( "Can not copy big file; {$src} -> {$dest}" );
263
- fclose( $src );
264
- fclose( $dest );
265
- return false;
266
}
267
- }
268
- }
269
- // Close any open handler
270
- fclose( $src );
271
- fclose( $dest );
272
- return true;
273
- }
274
-
275
- /**
276
- * Check if file is excluded from copying process
277
- *
278
- * @param string $file filename including ending
279
- * @return boolean
280
- */
281
- private function isFileExcluded( $file ) {
282
-
283
- if( in_array( basename( $file ), $this->options->excludedFiles ) ) {
284
- return true;
285
- }
286
- // Do not copy wp-config.php if the clone gets updated. This is for security purposes,
287
- // because if the updating process fails, the staging site would not be accessable any longer
288
- if( isset( $this->options->mainJob ) && $this->options->mainJob == "updating" && stripos( strrev( $file ), strrev( "wp-config.php" ) ) === 0 ) {
289
- return true;
290
- }
291
-
292
-
293
- return false;
294
- }
295
-
296
- /**
297
- * Check if certain file is excluded from copying process
298
- *
299
- * @param string $file filename including ending + (part) path e.g wp-content/db.php
300
- * @return boolean
301
- */
302
- private function isFileExcludedFullPath( $file ) {
303
- // If path + file exists
304
- foreach ( $this->options->excludedFilesFullPath as $excludedFile ) {
305
- if( false !== strpos( $file, $excludedFile ) ) {
306
return true;
307
- }
308
- }
309
-
310
- return false;
311
- }
312
-
313
- /**
314
- * Replace forward slash with current directory separator
315
- * Windows Compatibility Fix
316
- * @param string $path Path
317
- *
318
- * @return string
319
- */
320
- private function sanitizeDirectorySeparator( $path ) {
321
- $string = str_replace( "/", "\\", $path );
322
- return str_replace( '\\\\', '\\', $string );
323
- }
324
-
325
- /**
326
- * Check if directory is excluded from copying
327
- * @param string $directory
328
- * @return bool
329
- */
330
- private function isDirectoryExcluded( $directory ) {
331
-
332
- // Make sure that wp-staging-pro directory / plugin is never excluded
333
- if( false !== strpos( $directory, 'wp-staging' ) || false !== strpos( $directory, 'wp-staging-pro' ) ) {
334
- return false;
335
- }
336
-
337
- $directory = $this->sanitizeDirectorySeparator( $directory );
338
-
339
- foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
340
- //echo 'excl:' . $excludedDirectory . '<br>';
341
- //echo 'dir' . $directory . '<br>';
342
- if( strpos( $directory, $this->sanitizeDirectorySeparator( $excludedDirectory ) ) === 0 && !$this->isExtraDirectory( $directory ) ) {
343
return true;
344
- }
345
- }
346
-
347
- return false;
348
- }
349
-
350
- /**
351
- * Check if directory is an extra directory and should be copied
352
- * @param string $directory
353
- * @return boolean
354
- */
355
- private function isExtraDirectory( $directory ) {
356
- $directory = $this->sanitizeDirectorySeparator( $directory );
357
-
358
- foreach ( $this->options->extraDirectories as $extraDirectory ) {
359
- if( strpos( $directory, $this->sanitizeDirectorySeparator( $extraDirectory ) ) === 0 ) {
360
return true;
361
- }
362
- }
363
364
- return false;
365
- }
366
367
}
7
use WPStaging\Utils\Logger;
8
9
if( !defined( "WPINC" ) ) {
10
+ die;
11
}
12
13
/**
16
*/
17
class Files extends JobExecutable {
18
19
+ /**
20
+ * @var \SplFileObject
21
+ */
22
+ private $file;
23
+
24
+ /**
25
+ * @var int
26
+ */
27
+ private $maxFilesPerRun;
28
+
29
+ /**
30
+ * @var string
31
+ */
32
+ private $destination;
33
+
34
+ /**
35
+ * Initialization
36
+ */
37
+ public function initialize() {
38
+
39
+ $this->destination = $this->options->destinationDir;
40
+
41
+ $filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
42
+
43
+ if( is_file( $filePath ) ) {
44
+ $this->file = new \SplFileObject( $filePath, 'r' );
45
+ }
46
+
47
+ // Informational logs
48
+ if( 0 == $this->options->currentStep ) {
49
+ $this->log( "Copying files..." );
50
+ }
51
+
52
+ $this->settings->batchSize = $this->settings->batchSize * 1000000;
53
+ $this->maxFilesPerRun = $this->settings->fileLimit;
54
+ //$this->maxFilesPerRun = ($this->settings->cpuLoad === 'low') ? 50 : 1;
55
+ }
56
+
57
+ /**
58
+ * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
59
+ * @return void
60
+ */
61
+ protected function calculateTotalSteps() {
62
+ $this->options->totalSteps = ceil( $this->options->totalFiles / $this->maxFilesPerRun );
63
+ }
64
+
65
+ /**
66
+ * Execute the Current Step
67
+ * Returns false when over threshold limits are hit or when the job is done, true otherwise
68
+ * @return bool
69
+ */
70
+ protected function execute() {
71
+ // Finished
72
+ if( $this->isFinished() ) {
73
+ $this->log( "Copying files finished" );
74
+ $this->prepareResponse( true, false );
75
+ return false;
76
+ }
77
+
78
+ // Get files and copy'em
79
+ if( !$this->getFilesAndCopy() ) {
80
+ $this->prepareResponse( false, false );
81
+ return false;
82
+ }
83
+
84
+ // Prepare and return response
85
+ $this->prepareResponse();
86
+
87
+ // Not finished
88
+ return true;
89
+ }
90
+
91
+ /**
92
+ * Get files and copy
93
+ * @return bool
94
+ */
95
+ private function getFilesAndCopy() {
96
+ // Over limits threshold
97
+ if( $this->isOverThreshold() ) {
98
+ // Prepare response and save current progress
99
+ $this->prepareResponse( false, false );
100
+ $this->saveOptions();
101
+ return false;
102
+ }
103
+
104
+ // Go to last copied line and than to next one
105
+ //if ($this->options->copiedFiles != 0) {
106
+ if( isset( $this->options->copiedFiles ) && $this->options->copiedFiles != 0 ) {
107
+ $this->file->seek( $this->options->copiedFiles - 1 );
108
+ }
109
+
110
+ $this->file->setFlags( \SplFileObject::SKIP_EMPTY | \SplFileObject::READ_AHEAD );
111
+
112
+ // Start time
113
+ //$start = microtime( true );
114
+ // Loop x files at a time
115
+ //$this->maxFilesPerRun = 300;
116
+ for ( $i = 0; $i < $this->maxFilesPerRun; $i++ ) {
117
+
118
+ // Reached timeout
119
+ // if( ( $timeout = apply_filters( 'wpstg_job_timeout', 10 ) ) ) {
120
+ // if( ( \microtime( true ) - $start ) > $timeout ) {
121
+ // // Prepare response and save current progress
122
+ // $this->prepareResponse( false, true );
123
+ // $this->saveOptions();
124
+ // return false;
125
+ // }
126
+ // }
127
+ // Increment copied files
128
+ // Do this anytime to make sure to not stuck in the same step / files
129
+ $this->options->copiedFiles++;
130
+
131
+ // End of file
132
+ if( $this->file->eof() ) {
133
+ break;
134
}
135
+
136
+ $file = $this->file->fgets();
137
+
138
+ // if( false !== strpos( $file, 'index.php' ) ) {
139
+ // $test = $file;
140
+ // }
141
+ $this->copyFile( $file );
142
+ }
143
+
144
+
145
+
146
+ $totalFiles = $this->options->copiedFiles;
147
+ // Log this only every 50 entries to keep the log small and to not block the rendering browser
148
+ if( $this->options->copiedFiles % 50 == 0 ) {
149
+ $this->log( "Total {$totalFiles} files processed" );
150
+ }
151
+
152
+ return true;
153
+ }
154
+
155
+ /**
156
+ * Checks Whether There is Any Job to Execute or Not
157
+ * @return bool
158
+ */
159
+ private function isFinished() {
160
+ return (
161
+ $this->options->currentStep > $this->options->totalSteps ||
162
+ $this->options->copiedFiles >= $this->options->totalFiles
163
+ );
164
+ }
165
+
166
+ /**
167
+ * @param string $file
168
+ * @return bool
169
+ */
170
+ private function copyFile( $file ) {
171
+
172
+ $file = trim( \WPStaging\WPStaging::getWPpath() . $file );
173
+
174
+ $directory = dirname( $file );
175
+
176
+ // Directory is excluded
177
+ if( $this->isDirectoryExcluded( $directory ) ) {
178
+ $this->debugLog( "Skipping directory by rule: {$file}", Logger::TYPE_INFO );
179
+ return false;
180
+ }
181
+
182
+ // File is excluded
183
+ if( $this->isFileExcluded( $file ) ) {
184
+ $this->debugLog( "Skipping file by rule: {$file}", Logger::TYPE_INFO );
185
+ return false;
186
+ }
187
+ // Path + File is excluded
188
+ if( $this->isFileExcludedFullPath( $file ) ) {
189
+ $this->debugLog( "Skipping file by rule: {$file}", Logger::TYPE_INFO );
190
+ return false;
191
+ }
192
+
193
+ // Invalid file, skipping it as if succeeded
194
+ if( !is_file( $file ) ) {
195
+ $this->log( "File doesn't exist {$file}", Logger::TYPE_WARNING );
196
+ return true;
197
+ }
198
+ // Invalid file, skipping it as if succeeded
199
+ if( !is_readable( $file ) ) {
200
+ $this->log( "Can't read file {$file}", Logger::TYPE_WARNING );
201
return true;
202
+ }
203
+
204
+
205
+ // Get file size
206
+ $fileSize = filesize( $file );
207
+
208
+ // File is over maximum allowed file size (8MB)
209
+ if( $fileSize >= $this->settings->maxFileSize * 1000000 ) {
210
+ $this->log( "Skipping big file: {$file}", Logger::TYPE_INFO );
211
+ return false;
212
+ }
213
+
214
+ // Failed to get destination
215
+ if( false === ($destination = $this->getDestination( $file )) ) {
216
+ $this->log( "Can't get the destination of {$file}", Logger::TYPE_WARNING );
217
+ return false;
218
+ }
219
+
220
+ // File is over batch size
221
+ if( $fileSize >= $this->settings->batchSize ) {
222
+ $this->log( "Trying to copy big file: {$file} -> {$destination}", Logger::TYPE_INFO );
223
+ return $this->copyBig( $file, $destination, $this->settings->batchSize );
224
+ }
225
+
226
+ // Attempt to copy
227
+ if( !@copy( $file, $destination ) ) {
228
+ $errors = error_get_last();
229
+ $this->log( "Files: Failed to copy file to destination. Error: {$errors['message']} {$file} -> {$destination}", Logger::TYPE_ERROR );
230
+ return false;
231
+ }
232
+
233
+ // Set file permissions
234
+ @chmod( $destination, wpstg_get_permissions_for_file() );
235
+
236
+ $this->setDirPermissions( $destination );
237
+
238
+ return true;
239
+ }
240
+
241
+ /**
242
+ * Set directory permissions
243
+ * @param type $file
244
+ * @return boolean
245
+ */
246
+ private function setDirPermissions( $file ) {
247
+ $dir = dirname( $file );
248
+ if( is_dir( $dir ) ) {
249
+ @chmod( $dir, wpstg_get_permissions_for_directory() );
250
+ }
251
+ return false;
252
+ }
253
+
254
+ /**
255
+ * Gets destination file and checks if the directory exists, if it does not attempts to create it.
256
+ * If creating destination directory fails, it returns false, gives destination full path otherwise
257
+ * @param string $file
258
+ * @return bool|string
259
+ */
260
+ private function getDestination( $file ) {
261
+
262
+ $relativePath = str_replace( \WPStaging\WPStaging::getWPpath(), null, $file );
263
+ $destinationPath = $this->destination . $relativePath;
264
+ $destinationDirectory = dirname( $destinationPath );
265
+
266
+ if( !is_dir( $destinationDirectory ) && !@mkdir( $destinationDirectory, wpstg_get_permissions_for_directory(), true ) ) {
267
+ $this->log( "Files: Can not create directory {$destinationDirectory}", Logger::TYPE_ERROR );
268
+ return false;
269
+ }
270
+
271
+ return $this->sanitizeDirectorySeparator( $destinationPath );
272
+ }
273
+
274
+ /**
275
+ * Copy bigger files than $this->settings->batchSize
276
+ * @param string $src
277
+ * @param string $dst
278
+ * @param int $buffersize
279
+ * @return boolean
280
+ */
281
+ private function copyBig( $src, $dst, $buffersize ) {
282
+ $src = fopen( $src, 'r' );
283
+ $dest = fopen( $dst, 'w' );
284
+
285
+ // Try first method:
286
+ while ( !feof( $src ) ) {
287
+ if( false === fwrite( $dest, fread( $src, $buffersize ) ) ) {
288
+ $error = true;
289
+ }
290
+ }
291
+ // Try second method if first one failed
292
+ if( isset( $error ) && ($error === true) ) {
293
+ while ( !feof( $src ) ) {
294
+ if( false === stream_copy_to_stream( $src, $dest, 1024 ) ) {
295
+ $this->log( "Can not copy file; {$src} -> {$dest}" );
296
+ fclose( $src );
297
+ fclose( $dest );
298
+ return false;
299
+ }
300
+ }
301
+ }
302
+ // Close any open handler
303
+ fclose( $src );
304
+ fclose( $dest );
305
+ return true;
306
+ }
307
+
308
+ /**
309
+ * Check if certain file is excluded from copying process
310
+ *
311
+ * @param string $file filename including ending without full path
312
+ * @return boolean
313
+ */
314
+ private function isFileExcluded( $file ) {
315
+ // If file name exists
316
+ if( in_array( basename( $file ), $this->options->excludedFiles ) ) {
317
return true;
318
+ }
319
+
320
+ // Do not copy wp-config.php if the clone gets updated. This is for security purposes,
321
+ // because if the updating process fails, the staging site would not be accessable any longer
322
+ if( isset( $this->options->mainJob ) && $this->options->mainJob == "updating" && stripos( strrev( $file ), strrev( "wp-config.php" ) ) === 0 ) {
323
return true;
324
+ }
325
+
326
+
327
+ return false;
328
+ }
329
+
330
+ /**
331
+ * Check if certain file is excluded from copying process
332
+ *
333
+ * @param string $file filename including ending + (part) path e.g wp-content/db.php
334
+ * @return boolean
335
+ */
336
+ private function isFileExcludedFullPath( $file ) {
337
+ // If path + file exists
338
+ foreach ( $this->options->excludedFilesFullPath as $excludedFile ) {
339
+ if( false !== strpos( $file, $excludedFile ) ) {
340
+ return true;
341
+ }
342
+ }
343
+
344
+ return false;
345
+ }
346
+
347
+ /**
348
+ * Replace backward slash with forward slash directory separator
349
+ * Windows Compatibility Fix
350
+ *
351
+ * @param string $path Path
352
+ * @return string
353
+ */
354
+ private function sanitizeDirectorySeparator( $path ) {
355
+ //$string = str_replace( '\\', '/', $path );
356
+ //$string = str_replace( "/", "\\", $path );
357
+ //return str_replace( '\\\\', '\\', $string );
358
+ //return preg_replace( '/[\\\\]+/', '\\\\\\\\', $string );
359
+ return preg_replace( '/[\\\\]+/', '/', $path );
360
+ }
361
+
362
+ /**
363
+ * Check if directory is excluded from copying
364
+ * @param string $directory
365
+ * @return bool
366
+ */
367
+ private function isDirectoryExcluded( $directory ) {
368
+ // Make sure that wp-staging-pro directory / plugin is never excluded
369
+ if( false !== strpos( $directory, 'wp-staging' ) || false !== strpos( $directory, 'wp-staging-pro' ) ) {
370
+ return false;
371
+ }
372
+ // $directory = wpstg_replace_windows_directory_separator( $directory );
373
+ // $directory = trailingslashit( $directory );
374
+ $directory = trailingslashit( $this->sanitizeDirectorySeparator( $directory ) );
375
+
376
+ foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
377
+ // $excludedDirectory = wpstg_replace_windows_directory_separator( $excludedDirectory );
378
+ // $excludedDirectory = trailingslashit( $excludedDirectory );
379
+ $excludedDirectory = trailingslashit( $this->sanitizeDirectorySeparator( $excludedDirectory ) );
380
+ if( strpos( $directory, $excludedDirectory ) === 0 && !$this->isExtraDirectory( $directory ) ) {
381
+ return true;
382
+ }
383
+ }
384
+
385
+ return false;
386
+ }
387
+
388
+ /**
389
+ * Check if directory is an extra directory and should be copied
390
+ * @param string $directory
391
+ * @return boolean
392
+ */
393
+ private function isExtraDirectory( $directory ) {
394
+ $directory = $this->sanitizeDirectorySeparator( $directory );
395
+
396
+ foreach ( $this->options->extraDirectories as $extraDirectory ) {
397
+ if( strpos( $directory, $this->sanitizeDirectorySeparator( $extraDirectory ) ) === 0 ) {
398
+ return true;
399
+ }
400
+ }
401
402
+ return false;
403
+ }
404
405
}
apps/Backend/Modules/Jobs/Finish.php CHANGED
@@ -1,16 +1,15 @@
1
<?php
2
namespace WPStaging\Backend\Modules\Jobs;
3
4
use WPStaging\WPStaging;
5
6
- //error_reporting( E_ALL );
7
-
8
/**
9
* Class Finish
10
* @package WPStaging\Backend\Modules\Jobs
11
*/
12
- class Finish extends Job
13
- {
14
/**
15
* Clone Key
16
* @var string
@@ -21,97 +20,138 @@ class Finish extends Job
21
* Start Module
22
* @return object
23
*/
24
- public function start()
25
- {
26
// sanitize the clone name before saving
27
- $this->clone = preg_replace("#\W+#", '-', strtolower($this->options->clone));
28
-
29
// Delete Cache Files
30
$this->deleteCacheFiles();
31
32
// Prepare clone records & save scanned directories for delete job later
33
$this->prepareCloneDataRecords();
34
35
-
36
$return = array(
37
- "directoryName" => $this->options->cloneDirectoryName,
38
- "path" => \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName,
39
- "url" => get_site_url() . '/' . $this->options->cloneDirectoryName,
40
- "number" => $this->options->cloneNumber,
41
- "version" => \WPStaging\WPStaging::VERSION,
42
- "status" => 'finished',
43
- "prefix" => $this->options->prefix,
44
- "last_msg" => $this->logger->getLastLogMsg(),
45
- "job" => $this->options->currentJob,
46
- "percentage" => 100
47
-
48
);
49
-
50
//$this->flush();
51
52
- return (object) $return;
53
}
54
55
/**
56
* Delete Cache Files
57
*/
58
- protected function deleteCacheFiles()
59
- {
60
- $this->log("Finish: Deleting clone job's cache files...");
61
62
// Clean cache files
63
- $this->cache->delete("clone_options");
64
- $this->cache->delete("files_to_copy");
65
66
- $this->log("Finish: Clone job's cache files have been deleted!");
67
}
68
-
69
- /**
70
* Prepare clone records
71
* @return bool
72
*/
73
- protected function prepareCloneDataRecords()
74
- {
75
// Check if clones still exist
76
- $this->log("Finish: Verifying existing clones...");
77
78
// Clone data already exists
79
- if (isset($this->options->existingClones[$this->options->clone]))
80
- {
81
- $this->options->existingClones[$this->options->clone]['datetime'] = time();
82
- update_option("wpstg_existing_clones_beta", $this->options->existingClones);
83
- $this->log("Finish: The job finished!");
84
return true;
85
}
86
87
// Save new clone data
88
- $this->log("Finish: {$this->options->clone}'s clone job's data is not in database, generating data");
89
-
90
// sanitize the clone name before saving
91
//$clone = preg_replace("#\W+#", '-', strtolower($this->options->clone));
92
-
93
$this->options->existingClones[$this->clone] = array(
94
- "directoryName" => $this->options->cloneDirectoryName,
95
- "path" => \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName,
96
- "url" => get_site_url() . '/' . $this->options->cloneDirectoryName,
97
- "number" => $this->options->cloneNumber,
98
- "version" => \WPStaging\WPStaging::VERSION,
99
- "status" => false,
100
- "prefix" => $this->options->prefix,
101
- "datetime" => time(),
102
- "databaseUser" => $this->options->databaseUser,
103
- "databasePassword" => $this->options->databasePassword,
104
- "databaseDatabase" => $this->options->databaseDatabase,
105
- "databaseServer" => $this->options->databaseServer,
106
- "databasePrefix" => $this->options->databasePrefix,
107
);
108
109
- if (false === update_option("wpstg_existing_clones_beta", $this->options->existingClones))
110
- {
111
- $this->log("Finish: Failed to save {$this->options->clone}'s clone job data to database'");
112
return false;
113
}
114
115
return true;
116
}
117
- }