Version Description
- Fix: Can not login to staging site under certain circumstances
- Fix: Use user selected language setting instead global site based one
- Fix: Fatal Error: curl_version() not defined in SystemInfo.php
- New: Refactored structure for easier maintenance
- New: Core support for WP Staging snapshots
- New: Implementing of UnitTests
Download this release
Release Info
Developer | ReneHermi |
Plugin | WP Staging – DB & File Duplicator & Migration |
Version | 2.6.9 |
Comparing to | |
See all releases |
Code changes from version 2.6.8 to 2.6.9
- Backend/Modules/Jobs/Cloning.php +150 -131
- Backend/Modules/Jobs/Delete.php +0 -12
- Backend/Modules/Jobs/Files.php +134 -161
- Backend/Modules/Jobs/Multisite/Directories.php +176 -164
- Backend/Modules/Jobs/Multisite/Files.php +12 -26
- Backend/Modules/Jobs/Multisite/SearchReplace.php +13 -7
- Backend/Modules/Jobs/Multisite/SearchReplaceExternal.php +13 -8
- Backend/Modules/Jobs/SearchReplace.php +14 -8
- Backend/Modules/Jobs/SearchReplaceExternal.php +13 -9
- Backend/Modules/Jobs/Updating.php +66 -60
- Backend/Modules/SystemInfo.php +225 -195
- Backend/Notices/Notices.php +2 -2
- Backend/Optimizer/wp-staging-optimizer.php +0 -5
- Backend/public/css/wpstg-admin.css +142 -22
- Backend/public/js/wpstg-admin.js +962 -722
- Backend/views/clone/ajax/start.php +16 -20
- Backend/views/clone/ajax/update.php +1 -1
- Backend/views/clone/single-site/index.php +0 -3
- Backend/views/notices/beta.php +1 -0
- Backend/views/notices/wp-version-compatible-message.php +1 -1
- Core/Utils/Logger.php +111 -37
- Core/Utils/functions.php +1 -47
- Core/WPStaging.php +33 -34
- Frontend/Frontend.php +65 -71
- Manager/Database/TableDto.php +156 -0
- Manager/Database/TableManager.php +48 -0
- Manager/FileSystem/FileManager.php +84 -0
- Manager/SnapshotManager.php +29 -0
- Plugin.php +33 -0
- Service/AbstractPlugin.php +175 -0
- Service/Adapter/Database.php +100 -0
- Service/Adapter/Database/AbstractDatabase.php +8 -0
- Service/Adapter/Database/DatabaseException.php +14 -0
- Service/Adapter/Database/DatabaseQueryDto.php +90 -0
- Service/Adapter/Database/InterfaceDatabase.php +59 -0
- Service/Adapter/Database/WpDbAdapter.php +102 -0
- Service/Adapter/DateTimeAdapter.php +34 -0
- Service/Adapter/Directory.php +74 -0
- Service/Adapter/Dto/HookDto.php +103 -0
- Service/Adapter/Dto/JedDto.php +120 -0
- Service/Adapter/Hooks.php +47 -0
- Service/Adapter/Translation.php +85 -0
- Service/Collection/Collection.php +59 -0
- Service/Collection/OptionCollection.php +85 -0
- Service/Command/CommandInterface.php +11 -0
- Service/Command/HandlerInterface.php +10 -0
- Service/Component/AbstractComponent.php +66 -0
- Service/Component/AbstractTemplateComponent.php +42 -0
- Service/Component/AjaxTrait.php +34 -0
- Service/Component/ComponentInterface.php +10 -0
- Service/Component/RenderableComponentInterface.php +10 -0
- Service/Container/AbstractContainerAware.php +34 -0
- Service/Container/Container.php +350 -0
- Service/Container/ContainerInterface.php +28 -0
- Service/Container/InvalidConstructorParamException.php +16 -0
- Service/Dto/AbstractDto.php +23 -0
- Service/Entity/AbstractEntity.php +42 -0
- Service/Entity/EntityException.php +12 -0
- Service/Entity/IdentifyableEntityInterface.php +13 -0
- Service/Interfaces/ArrayableInterface.php +14 -0
- Service/Interfaces/HydrateableInterface.php +16 -0
- Service/InvalidPluginException.php +16 -0
- Service/PluginFactory.php +43 -0
- Service/PluginFactoryInterface.php +13 -0
- Service/PluginInterface.php +30 -0
- Service/TemplateEngine/TemplateEngine.php +146 -0
- Service/TemplateEngine/TemplateEngineException.php +11 -0
- Service/TemplateEngine/TemplateEngineInterface.php +11 -0
- Service/Traits/ArrayableTrait.php +41 -0
- Service/Traits/HydrateTrait.php +65 -0
- Service/Utils/FileSize.php +15 -0
- Service/Utils/FileSystem.php +64 -0
- Service/Utils/WpDefaultDirectories.php +16 -0
- config.php +59 -0
- install.php +4 -3
- readme.txt +15 -13
- uninstall.php +3 -0
- vendor/autoload.php +7 -0
- vendor/composer/ClassLoader.php +445 -0
- vendor/composer/LICENSE +56 -0
- vendor/composer/autoload_classmap.php +9 -0
- vendor/composer/autoload_namespaces.php +9 -0
- vendor/composer/autoload_psr4.php +12 -0
- vendor/composer/autoload_real.php +52 -0
- vendor/composer/autoload_static.php +43 -0
- vendor/composer/installed.json +51 -0
- vendor/psr/log/LICENSE +19 -0
- vendor/psr/log/Psr/Log/AbstractLogger.php +128 -0
- vendor/psr/log/Psr/Log/InvalidArgumentException.php +7 -0
- vendor/psr/log/Psr/Log/LogLevel.php +18 -0
- vendor/psr/log/Psr/Log/LoggerAwareInterface.php +18 -0
- vendor/psr/log/Psr/Log/LoggerAwareTrait.php +26 -0
- vendor/psr/log/Psr/Log/LoggerInterface.php +125 -0
- vendor/psr/log/Psr/Log/LoggerTrait.php +142 -0
- vendor/psr/log/Psr/Log/NullLogger.php +30 -0
- vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php +146 -0
- vendor/psr/log/Psr/Log/Test/TestLogger.php +147 -0
- vendor/psr/log/README.md +58 -0
- vendor/psr/log/composer.json +26 -0
- wp-staging.php +6 -3
Backend/Modules/Jobs/Cloning.php
CHANGED
@@ -19,46 +19,49 @@ use WPStaging\Utils\Helper;
|
|
19 |
* Class Cloning
|
20 |
* @package WPStaging\Backend\Modules\Jobs
|
21 |
*/
|
22 |
-
class Cloning extends Job
|
|
|
23 |
|
24 |
/**
|
25 |
* Initialize is called in \Job
|
26 |
*/
|
27 |
-
public function initialize()
|
28 |
-
|
|
|
29 |
}
|
30 |
|
31 |
/**
|
32 |
* Save Chosen Cloning Settings
|
33 |
* @return bool
|
34 |
*/
|
35 |
-
public function save()
|
36 |
-
|
|
|
37 |
return false;
|
38 |
}
|
39 |
|
40 |
// Delete files to copy listing
|
41 |
-
$this->cache->delete(
|
42 |
|
43 |
// Generate Options
|
44 |
// Clone
|
45 |
//$this->options->clone = $_POST["cloneID"];
|
46 |
-
$this->options->clone
|
47 |
-
$this->options->cloneDirectoryName
|
48 |
-
$this->options->cloneNumber
|
49 |
-
$this->options->prefix
|
50 |
-
$this->options->includedDirectories
|
51 |
-
$this->options->excludedDirectories
|
52 |
-
$this->options->extraDirectories
|
53 |
-
$this->options->excludedFiles
|
54 |
'.htaccess',
|
55 |
'.DS_Store',
|
56 |
-
'
|
57 |
-
'
|
58 |
-
'
|
59 |
'desktop.ini',
|
60 |
'.gitignore',
|
61 |
-
'
|
62 |
'web.config', // Important: Windows IIS configuration file. Must not be in the staging site!
|
63 |
'.wp-staging' // Determines if a site is a staging site
|
64 |
);
|
@@ -67,36 +70,36 @@ class Cloning extends Job {
|
|
67 |
'wp-content' . DIRECTORY_SEPARATOR . 'object-cache.php',
|
68 |
'wp-content' . DIRECTORY_SEPARATOR . 'advanced-cache.php'
|
69 |
);
|
70 |
-
$this->options->currentStep
|
71 |
|
72 |
// Job
|
73 |
$this->options->job = new \stdClass();
|
74 |
|
75 |
// Check if clone data already exists and use that one
|
76 |
-
if(
|
77 |
|
78 |
$this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
|
79 |
|
80 |
-
$this->options->prefix = isset(
|
81 |
-
|
82 |
-
|
83 |
}
|
84 |
// Clone does not exist but there are other clones in db
|
85 |
// Get data and increment it
|
86 |
-
elseif(
|
87 |
-
$this->options->cloneNumber = count(
|
88 |
}
|
89 |
|
90 |
// Included Tables
|
91 |
-
if(
|
92 |
$this->options->tables = $_POST["includedTables"];
|
93 |
} else {
|
94 |
$this->options->tables = array();
|
95 |
}
|
96 |
|
97 |
// Excluded Directories
|
98 |
-
if(
|
99 |
-
$this->options->excludedDirectories = wpstg_urldecode(
|
100 |
}
|
101 |
|
102 |
// Excluded Directories TOTAL
|
@@ -109,59 +112,59 @@ class Cloning extends Job {
|
|
109 |
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-spamshield',
|
110 |
);
|
111 |
|
112 |
-
$this->options->excludedDirectories = array_merge(
|
113 |
|
114 |
-
array_unshift(
|
115 |
|
116 |
// Included Directories
|
117 |
-
if(
|
118 |
-
$this->options->includedDirectories = wpstg_urldecode(
|
119 |
}
|
120 |
|
121 |
// Extra Directories
|
122 |
-
if(
|
123 |
-
$this->options->extraDirectories = wpstg_urldecode(
|
124 |
}
|
125 |
|
126 |
// Directories to Copy
|
127 |
$this->options->directoriesToCopy = array_merge(
|
128 |
-
|
129 |
);
|
130 |
|
131 |
|
132 |
$this->options->databaseServer = 'localhost';
|
133 |
-
if(
|
134 |
$this->options->databaseServer = $_POST["databaseServer"];
|
135 |
}
|
136 |
$this->options->databaseUser = '';
|
137 |
-
if(
|
138 |
$this->options->databaseUser = $_POST["databaseUser"];
|
139 |
}
|
140 |
$this->options->databasePassword = '';
|
141 |
-
if(
|
142 |
$this->options->databasePassword = $_POST["databasePassword"];
|
143 |
}
|
144 |
$this->options->databaseDatabase = '';
|
145 |
-
if(
|
146 |
$this->options->databaseDatabase = $_POST["databaseDatabase"];
|
147 |
}
|
148 |
$this->options->databasePrefix = '';
|
149 |
-
if(
|
150 |
-
$this->options->databasePrefix = strtolower(
|
151 |
}
|
152 |
$this->options->cloneDir = '';
|
153 |
-
if(
|
154 |
-
$this->options->cloneDir = trailingslashit(
|
155 |
}
|
156 |
$this->options->cloneHostname = '';
|
157 |
-
if(
|
158 |
-
$this->options->cloneHostname = trim(
|
159 |
}
|
160 |
|
161 |
$this->options->destinationHostname = $this->getDestinationHostname();
|
162 |
-
$this->options->destinationDir
|
163 |
|
164 |
-
$helper
|
165 |
$this->options->homeHostname = $helper->get_home_url_without_scheme();
|
166 |
|
167 |
// Process lock state
|
@@ -178,28 +181,29 @@ class Cloning extends Job {
|
|
178 |
* Save clone data initially
|
179 |
* @return boolean
|
180 |
*/
|
181 |
-
private function saveClone()
|
|
|
182 |
// Save new clone data
|
183 |
-
$this->log(
|
184 |
|
185 |
$this->options->existingClones[$this->options->clone] = array(
|
186 |
-
"directoryName"
|
187 |
-
"path"
|
188 |
-
"url"
|
189 |
-
"number"
|
190 |
-
"version"
|
191 |
-
"status"
|
192 |
-
"prefix"
|
193 |
-
"datetime"
|
194 |
-
"databaseUser"
|
195 |
"databasePassword" => $this->options->databasePassword,
|
196 |
"databaseDatabase" => $this->options->databaseDatabase,
|
197 |
-
"databaseServer"
|
198 |
-
"databasePrefix"
|
199 |
);
|
200 |
|
201 |
-
if(
|
202 |
-
$this->log(
|
203 |
return false;
|
204 |
}
|
205 |
|
@@ -210,25 +214,27 @@ class Cloning extends Job {
|
|
210 |
* Get destination Hostname depending on wheather WP has been installed in sub dir or not
|
211 |
* @return type
|
212 |
*/
|
213 |
-
private function getDestinationUrl()
|
|
|
214 |
|
215 |
-
if(
|
216 |
return $this->options->cloneHostname;
|
217 |
}
|
218 |
|
219 |
-
return trailingslashit(
|
220 |
}
|
221 |
|
222 |
/**
|
223 |
* Return target hostname
|
224 |
* @return string
|
225 |
*/
|
226 |
-
private function getDestinationHostname()
|
227 |
-
|
|
|
228 |
$helper = new Helper();
|
229 |
return $helper->get_home_url_without_scheme();
|
230 |
}
|
231 |
-
return $this->getHostnameWithoutScheme(
|
232 |
}
|
233 |
|
234 |
/**
|
@@ -236,39 +242,42 @@ class Cloning extends Job {
|
|
236 |
* @param string $str
|
237 |
* @return string
|
238 |
*/
|
239 |
-
private function getHostnameWithoutScheme(
|
240 |
-
|
|
|
241 |
}
|
242 |
|
243 |
/**
|
244 |
* Get Destination Directory including staging subdirectory
|
245 |
* @return type
|
246 |
*/
|
247 |
-
private function getDestinationDir()
|
|
|
248 |
// Throw fatal error
|
249 |
-
if(
|
250 |
-
$this->returnException('Error: Target Directory must be different from the root of the production website.'
|
251 |
die();
|
252 |
}
|
253 |
|
254 |
// No custom clone dir so clone path will be in subfolder of root
|
255 |
-
if(
|
256 |
-
$this->options->cloneDir = trailingslashit(
|
257 |
return $this->options->cloneDir;
|
258 |
//return trailingslashit( \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName );
|
259 |
}
|
260 |
-
return trailingslashit(
|
261 |
}
|
262 |
|
263 |
/**
|
264 |
* Make sure prefix contains appending underscore
|
265 |
-
*
|
266 |
* @param string $string
|
267 |
* @return string
|
268 |
*/
|
269 |
-
private function sanitizePrefix(
|
270 |
-
|
271 |
-
|
|
|
272 |
return $string;
|
273 |
}
|
274 |
return $string . '_';
|
@@ -277,38 +286,40 @@ class Cloning extends Job {
|
|
277 |
/**
|
278 |
* Create a new staging prefix which does not already exists in database
|
279 |
*/
|
280 |
-
private function setStagingPrefix()
|
|
|
281 |
|
282 |
// Get & find a new prefix that does not already exist in database.
|
283 |
// Loop through up to 1000 different possible prefixes should be enough here;)
|
284 |
-
for (
|
285 |
-
$this->options->prefix = isset(
|
286 |
-
|
287 |
-
|
288 |
|
289 |
-
$sql
|
290 |
-
$tables = $this->db->get_results(
|
291 |
|
292 |
// Prefix does not exist. We can use it
|
293 |
-
if(
|
294 |
-
return strtolower(
|
295 |
}
|
296 |
}
|
297 |
-
$this->returnException(
|
298 |
-
wp_die(
|
299 |
}
|
300 |
|
301 |
/**
|
302 |
-
* Check if potential new prefix of staging site would be identical with live site.
|
303 |
* @return boolean
|
304 |
*/
|
305 |
-
private function isPrefixIdentical()
|
306 |
-
|
|
|
307 |
|
308 |
-
$livePrefix
|
309 |
$stagingPrefix = $this->options->prefix;
|
310 |
|
311 |
-
if(
|
312 |
return true;
|
313 |
}
|
314 |
return false;
|
@@ -317,17 +328,18 @@ class Cloning extends Job {
|
|
317 |
/**
|
318 |
* Start the cloning job
|
319 |
*/
|
320 |
-
public function start()
|
321 |
-
|
322 |
-
|
|
|
323 |
return true;
|
324 |
}
|
325 |
|
326 |
-
$methodName = "job" . ucwords(
|
327 |
|
328 |
-
if(
|
329 |
-
$this->log(
|
330 |
-
throw new JobNotFoundException(
|
331 |
}
|
332 |
|
333 |
// Call the job
|
@@ -340,15 +352,16 @@ class Cloning extends Job {
|
|
340 |
* @param string $nextJob
|
341 |
* @return object
|
342 |
*/
|
343 |
-
private function handleJobResponse(
|
|
|
344 |
// Job is not done
|
345 |
-
if(
|
346 |
return $response;
|
347 |
}
|
348 |
|
349 |
-
$this->options->currentJob
|
350 |
$this->options->currentStep = 0;
|
351 |
-
$this->options->totalSteps
|
352 |
|
353 |
// Save options
|
354 |
$this->saveOptions();
|
@@ -360,13 +373,14 @@ class Cloning extends Job {
|
|
360 |
* Clone Database
|
361 |
* @return object
|
362 |
*/
|
363 |
-
public function jobDatabase()
|
|
|
364 |
|
365 |
// Could be written more elegant
|
366 |
// but for xdebug purposes and breakpoints its cleaner to have separate if blocks
|
367 |
-
if(
|
368 |
// Is Multisite
|
369 |
-
if(
|
370 |
$database = new muDatabase();
|
371 |
} else {
|
372 |
$database = new muDatabaseExternal();
|
@@ -374,60 +388,63 @@ class Cloning extends Job {
|
|
374 |
} else {
|
375 |
|
376 |
// No Multisite
|
377 |
-
if(
|
378 |
$database = new Database();
|
379 |
} else {
|
380 |
$database = new DatabaseExternal();
|
381 |
}
|
382 |
}
|
383 |
-
return $this->handleJobResponse(
|
384 |
}
|
385 |
|
386 |
/**
|
387 |
* Search & Replace
|
388 |
* @return object
|
389 |
*/
|
390 |
-
public function jobSearchReplace()
|
391 |
-
|
392 |
-
|
|
|
393 |
$searchReplace = new muSearchReplace();
|
394 |
} else {
|
395 |
$searchReplace = new muSearchReplaceExternal();
|
396 |
}
|
397 |
} else {
|
398 |
-
if(
|
399 |
$searchReplace = new SearchReplace();
|
400 |
} else {
|
401 |
$searchReplace = new SearchReplaceExternal();
|
402 |
}
|
403 |
}
|
404 |
-
return $this->handleJobResponse(
|
405 |
}
|
406 |
|
407 |
/**
|
408 |
* Get All Files From Selected Directories Recursively Into a File
|
409 |
* @return object
|
410 |
*/
|
411 |
-
public function jobDirectories()
|
412 |
-
|
|
|
413 |
$directories = new muDirectories();
|
414 |
} else {
|
415 |
$directories = new Directories();
|
416 |
}
|
417 |
-
return $this->handleJobResponse(
|
418 |
}
|
419 |
|
420 |
/**
|
421 |
* Copy Files
|
422 |
* @return object
|
423 |
*/
|
424 |
-
public function jobFiles()
|
425 |
-
|
|
|
426 |
$files = new muFiles();
|
427 |
} else {
|
428 |
$files = new Files();
|
429 |
}
|
430 |
-
return $this->handleJobResponse(
|
431 |
}
|
432 |
|
433 |
|
@@ -435,35 +452,37 @@ class Cloning extends Job {
|
|
435 |
* Replace Data
|
436 |
* @return object
|
437 |
*/
|
438 |
-
public function jobData()
|
439 |
-
|
440 |
-
|
|
|
441 |
$data = new muData();
|
442 |
} else {
|
443 |
$data = new muDataExternal();
|
444 |
}
|
445 |
} else {
|
446 |
|
447 |
-
if(
|
448 |
$data = new Data();
|
449 |
} else {
|
450 |
$data = new DataExternal();
|
451 |
}
|
452 |
}
|
453 |
-
return $this->handleJobResponse(
|
454 |
}
|
455 |
|
456 |
/**
|
457 |
* Save Clone Data
|
458 |
* @return object
|
459 |
*/
|
460 |
-
public function jobFinish()
|
461 |
-
|
|
|
462 |
$finish = new muFinish();
|
463 |
} else {
|
464 |
$finish = new Finish();
|
465 |
}
|
466 |
-
return $this->handleJobResponse(
|
467 |
}
|
468 |
|
469 |
}
|
19 |
* Class Cloning
|
20 |
* @package WPStaging\Backend\Modules\Jobs
|
21 |
*/
|
22 |
+
class Cloning extends Job
|
23 |
+
{
|
24 |
|
25 |
/**
|
26 |
* Initialize is called in \Job
|
27 |
*/
|
28 |
+
public function initialize()
|
29 |
+
{
|
30 |
+
$this->db = WPStaging::getInstance()->get("wpdb");
|
31 |
}
|
32 |
|
33 |
/**
|
34 |
* Save Chosen Cloning Settings
|
35 |
* @return bool
|
36 |
*/
|
37 |
+
public function save()
|
38 |
+
{
|
39 |
+
if (!isset($_POST) || !isset($_POST["cloneID"])) {
|
40 |
return false;
|
41 |
}
|
42 |
|
43 |
// Delete files to copy listing
|
44 |
+
$this->cache->delete("files_to_copy");
|
45 |
|
46 |
// Generate Options
|
47 |
// Clone
|
48 |
//$this->options->clone = $_POST["cloneID"];
|
49 |
+
$this->options->clone = preg_replace("#\W+#", '-', strtolower($_POST["cloneID"]));
|
50 |
+
$this->options->cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($this->options->clone));
|
51 |
+
$this->options->cloneNumber = 1;
|
52 |
+
$this->options->prefix = $this->setStagingPrefix();
|
53 |
+
$this->options->includedDirectories = array();
|
54 |
+
$this->options->excludedDirectories = array();
|
55 |
+
$this->options->extraDirectories = array();
|
56 |
+
$this->options->excludedFiles = array(
|
57 |
'.htaccess',
|
58 |
'.DS_Store',
|
59 |
+
'*.git',
|
60 |
+
'*.svn',
|
61 |
+
'*.tmp',
|
62 |
'desktop.ini',
|
63 |
'.gitignore',
|
64 |
+
'*.log',
|
65 |
'web.config', // Important: Windows IIS configuration file. Must not be in the staging site!
|
66 |
'.wp-staging' // Determines if a site is a staging site
|
67 |
);
|
70 |
'wp-content' . DIRECTORY_SEPARATOR . 'object-cache.php',
|
71 |
'wp-content' . DIRECTORY_SEPARATOR . 'advanced-cache.php'
|
72 |
);
|
73 |
+
$this->options->currentStep = 0;
|
74 |
|
75 |
// Job
|
76 |
$this->options->job = new \stdClass();
|
77 |
|
78 |
// Check if clone data already exists and use that one
|
79 |
+
if (isset($this->options->existingClones[$this->options->clone])) {
|
80 |
|
81 |
$this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
|
82 |
|
83 |
+
$this->options->prefix = isset($this->options->existingClones[$this->options->clone]->prefix) ?
|
84 |
+
$this->options->existingClones[$this->options->clone]->prefix :
|
85 |
+
$this->setStagingPrefix();
|
86 |
}
|
87 |
// Clone does not exist but there are other clones in db
|
88 |
// Get data and increment it
|
89 |
+
elseif (!empty($this->options->existingClones)) {
|
90 |
+
$this->options->cloneNumber = count($this->options->existingClones) + 1;
|
91 |
}
|
92 |
|
93 |
// Included Tables
|
94 |
+
if (isset($_POST["includedTables"]) && is_array($_POST["includedTables"])) {
|
95 |
$this->options->tables = $_POST["includedTables"];
|
96 |
} else {
|
97 |
$this->options->tables = array();
|
98 |
}
|
99 |
|
100 |
// Excluded Directories
|
101 |
+
if (isset($_POST["excludedDirectories"]) && is_array($_POST["excludedDirectories"])) {
|
102 |
+
$this->options->excludedDirectories = wpstg_urldecode($_POST["excludedDirectories"]);
|
103 |
}
|
104 |
|
105 |
// Excluded Directories TOTAL
|
112 |
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-spamshield',
|
113 |
);
|
114 |
|
115 |
+
$this->options->excludedDirectories = array_merge($excludedDirectories, wpstg_urldecode($this->options->excludedDirectories));
|
116 |
|
117 |
+
array_unshift($this->options->directoriesToCopy, \WPStaging\WPStaging::getWPpath());
|
118 |
|
119 |
// Included Directories
|
120 |
+
if (isset($_POST["includedDirectories"]) && is_array($_POST["includedDirectories"])) {
|
121 |
+
$this->options->includedDirectories = wpstg_urldecode($_POST["includedDirectories"]);
|
122 |
}
|
123 |
|
124 |
// Extra Directories
|
125 |
+
if (isset($_POST["extraDirectories"]) && !empty($_POST["extraDirectories"])) {
|
126 |
+
$this->options->extraDirectories = wpstg_urldecode($_POST["extraDirectories"]);
|
127 |
}
|
128 |
|
129 |
// Directories to Copy
|
130 |
$this->options->directoriesToCopy = array_merge(
|
131 |
+
$this->options->includedDirectories, $this->options->extraDirectories
|
132 |
);
|
133 |
|
134 |
|
135 |
$this->options->databaseServer = 'localhost';
|
136 |
+
if (isset($_POST["databaseServer"]) && !empty($_POST["databaseServer"])) {
|
137 |
$this->options->databaseServer = $_POST["databaseServer"];
|
138 |
}
|
139 |
$this->options->databaseUser = '';
|
140 |
+
if (isset($_POST["databaseUser"]) && !empty($_POST["databaseUser"])) {
|
141 |
$this->options->databaseUser = $_POST["databaseUser"];
|
142 |
}
|
143 |
$this->options->databasePassword = '';
|
144 |
+
if (isset($_POST["databasePassword"]) && !empty($_POST["databasePassword"])) {
|
145 |
$this->options->databasePassword = $_POST["databasePassword"];
|
146 |
}
|
147 |
$this->options->databaseDatabase = '';
|
148 |
+
if (isset($_POST["databaseDatabase"]) && !empty($_POST["databaseDatabase"])) {
|
149 |
$this->options->databaseDatabase = $_POST["databaseDatabase"];
|
150 |
}
|
151 |
$this->options->databasePrefix = '';
|
152 |
+
if (isset($_POST["databasePrefix"]) && !empty($_POST["databasePrefix"])) {
|
153 |
+
$this->options->databasePrefix = strtolower($this->sanitizePrefix($_POST["databasePrefix"]));
|
154 |
}
|
155 |
$this->options->cloneDir = '';
|
156 |
+
if (isset($_POST["cloneDir"]) && !empty($_POST["cloneDir"])) {
|
157 |
+
$this->options->cloneDir = trailingslashit(wpstg_urldecode($_POST["cloneDir"]));
|
158 |
}
|
159 |
$this->options->cloneHostname = '';
|
160 |
+
if (isset($_POST["cloneHostname"]) && !empty($_POST["cloneHostname"])) {
|
161 |
+
$this->options->cloneHostname = trim($_POST["cloneHostname"]);
|
162 |
}
|
163 |
|
164 |
$this->options->destinationHostname = $this->getDestinationHostname();
|
165 |
+
$this->options->destinationDir = $this->getDestinationDir();
|
166 |
|
167 |
+
$helper = new Helper();
|
168 |
$this->options->homeHostname = $helper->get_home_url_without_scheme();
|
169 |
|
170 |
// Process lock state
|
181 |
* Save clone data initially
|
182 |
* @return boolean
|
183 |
*/
|
184 |
+
private function saveClone()
|
185 |
+
{
|
186 |
// Save new clone data
|
187 |
+
$this->log("Cloning: {$this->options->clone}'s clone job's data is not in database, generating data");
|
188 |
|
189 |
$this->options->existingClones[$this->options->clone] = array(
|
190 |
+
"directoryName" => $this->options->cloneDirectoryName,
|
191 |
+
"path" => trailingslashit($this->options->destinationDir),
|
192 |
+
"url" => $this->getDestinationUrl(),
|
193 |
+
"number" => $this->options->cloneNumber,
|
194 |
+
"version" => WPStaging::getVersion(),
|
195 |
+
"status" => "unfinished or broken",
|
196 |
+
"prefix" => $this->options->prefix,
|
197 |
+
"datetime" => time(),
|
198 |
+
"databaseUser" => $this->options->databaseUser,
|
199 |
"databasePassword" => $this->options->databasePassword,
|
200 |
"databaseDatabase" => $this->options->databaseDatabase,
|
201 |
+
"databaseServer" => $this->options->databaseServer,
|
202 |
+
"databasePrefix" => $this->options->databasePrefix
|
203 |
);
|
204 |
|
205 |
+
if (false === update_option("wpstg_existing_clones_beta", $this->options->existingClones)) {
|
206 |
+
$this->log("Cloning: Failed to save {$this->options->clone}'s clone job data to database'");
|
207 |
return false;
|
208 |
}
|
209 |
|
214 |
* Get destination Hostname depending on wheather WP has been installed in sub dir or not
|
215 |
* @return type
|
216 |
*/
|
217 |
+
private function getDestinationUrl()
|
218 |
+
{
|
219 |
|
220 |
+
if (!empty($this->options->cloneHostname)) {
|
221 |
return $this->options->cloneHostname;
|
222 |
}
|
223 |
|
224 |
+
return trailingslashit(get_site_url()) . $this->options->cloneDirectoryName;
|
225 |
}
|
226 |
|
227 |
/**
|
228 |
* Return target hostname
|
229 |
* @return string
|
230 |
*/
|
231 |
+
private function getDestinationHostname()
|
232 |
+
{
|
233 |
+
if (empty($this->options->cloneHostname)) {
|
234 |
$helper = new Helper();
|
235 |
return $helper->get_home_url_without_scheme();
|
236 |
}
|
237 |
+
return $this->getHostnameWithoutScheme($this->options->cloneHostname);
|
238 |
}
|
239 |
|
240 |
/**
|
242 |
* @param string $str
|
243 |
* @return string
|
244 |
*/
|
245 |
+
private function getHostnameWithoutScheme($string)
|
246 |
+
{
|
247 |
+
return preg_replace('#^https?://#', '', rtrim($string, '/'));
|
248 |
}
|
249 |
|
250 |
/**
|
251 |
* Get Destination Directory including staging subdirectory
|
252 |
* @return type
|
253 |
*/
|
254 |
+
private function getDestinationDir()
|
255 |
+
{
|
256 |
// Throw fatal error
|
257 |
+
if (!empty($this->options->cloneDir) & (trailingslashit($this->options->cloneDir) === ( string )trailingslashit(\WPStaging\WPStaging::getWPpath()))) {
|
258 |
+
$this->returnException('Error: Target Directory must be different from the root of the production website.');
|
259 |
die();
|
260 |
}
|
261 |
|
262 |
// No custom clone dir so clone path will be in subfolder of root
|
263 |
+
if (empty($this->options->cloneDir)) {
|
264 |
+
$this->options->cloneDir = trailingslashit(\WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName);
|
265 |
return $this->options->cloneDir;
|
266 |
//return trailingslashit( \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName );
|
267 |
}
|
268 |
+
return trailingslashit($this->options->cloneDir);
|
269 |
}
|
270 |
|
271 |
/**
|
272 |
* Make sure prefix contains appending underscore
|
273 |
+
*
|
274 |
* @param string $string
|
275 |
* @return string
|
276 |
*/
|
277 |
+
private function sanitizePrefix($string)
|
278 |
+
{
|
279 |
+
$lastCharacter = substr($string, -1);
|
280 |
+
if ($lastCharacter === '_') {
|
281 |
return $string;
|
282 |
}
|
283 |
return $string . '_';
|
286 |
/**
|
287 |
* Create a new staging prefix which does not already exists in database
|
288 |
*/
|
289 |
+
private function setStagingPrefix()
|
290 |
+
{
|
291 |
|
292 |
// Get & find a new prefix that does not already exist in database.
|
293 |
// Loop through up to 1000 different possible prefixes should be enough here;)
|
294 |
+
for ($i = 0; $i <= 10000; $i++) {
|
295 |
+
$this->options->prefix = isset($this->options->existingClones) ?
|
296 |
+
'wpstg' . (count($this->options->existingClones) + $i) . '_' :
|
297 |
+
'wpstg' . $i . '_';
|
298 |
|
299 |
+
$sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
|
300 |
+
$tables = $this->db->get_results($sql);
|
301 |
|
302 |
// Prefix does not exist. We can use it
|
303 |
+
if (!$tables) {
|
304 |
+
return strtolower($this->options->prefix);
|
305 |
}
|
306 |
}
|
307 |
+
$this->returnException("Fatal Error: Can not create staging prefix. '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
|
308 |
+
wp_die("Fatal Error: Can not create staging prefix. Prefix '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
|
309 |
}
|
310 |
|
311 |
/**
|
312 |
+
* Check if potential new prefix of staging site would be identical with live site.
|
313 |
* @return boolean
|
314 |
*/
|
315 |
+
private function isPrefixIdentical()
|
316 |
+
{
|
317 |
+
$db = WPStaging::getInstance()->get("wpdb");
|
318 |
|
319 |
+
$livePrefix = $db->prefix;
|
320 |
$stagingPrefix = $this->options->prefix;
|
321 |
|
322 |
+
if ($livePrefix == $stagingPrefix) {
|
323 |
return true;
|
324 |
}
|
325 |
return false;
|
328 |
/**
|
329 |
* Start the cloning job
|
330 |
*/
|
331 |
+
public function start()
|
332 |
+
{
|
333 |
+
if (!property_exists($this->options, 'currentJob') || null === $this->options->currentJob) {
|
334 |
+
$this->log("Cloning job finished");
|
335 |
return true;
|
336 |
}
|
337 |
|
338 |
+
$methodName = "job" . ucwords($this->options->currentJob);
|
339 |
|
340 |
+
if (!method_exists($this, $methodName)) {
|
341 |
+
$this->log("Can't execute job; Job's method {$methodName} is not found");
|
342 |
+
throw new JobNotFoundException($methodName);
|
343 |
}
|
344 |
|
345 |
// Call the job
|
352 |
* @param string $nextJob
|
353 |
* @return object
|
354 |
*/
|
355 |
+
private function handleJobResponse($response, $nextJob)
|
356 |
+
{
|
357 |
// Job is not done
|
358 |
+
if (true !== $response->status) {
|
359 |
return $response;
|
360 |
}
|
361 |
|
362 |
+
$this->options->currentJob = $nextJob;
|
363 |
$this->options->currentStep = 0;
|
364 |
+
$this->options->totalSteps = 0;
|
365 |
|
366 |
// Save options
|
367 |
$this->saveOptions();
|
373 |
* Clone Database
|
374 |
* @return object
|
375 |
*/
|
376 |
+
public function jobDatabase()
|
377 |
+
{
|
378 |
|
379 |
// Could be written more elegant
|
380 |
// but for xdebug purposes and breakpoints its cleaner to have separate if blocks
|
381 |
+
if (defined('WPSTGPRO_VERSION') && is_multisite()) {
|
382 |
// Is Multisite
|
383 |
+
if (empty($this->options->databaseUser) && empty($this->options->databasePassword)) {
|
384 |
$database = new muDatabase();
|
385 |
} else {
|
386 |
$database = new muDatabaseExternal();
|
388 |
} else {
|
389 |
|
390 |
// No Multisite
|
391 |
+
if (empty($this->options->databaseUser) && empty($this->options->databasePassword)) {
|
392 |
$database = new Database();
|
393 |
} else {
|
394 |
$database = new DatabaseExternal();
|
395 |
}
|
396 |
}
|
397 |
+
return $this->handleJobResponse($database->start(), "SearchReplace");
|
398 |
}
|
399 |
|
400 |
/**
|
401 |
* Search & Replace
|
402 |
* @return object
|
403 |
*/
|
404 |
+
public function jobSearchReplace()
|
405 |
+
{
|
406 |
+
if (defined('WPSTGPRO_VERSION') && is_multisite()) {
|
407 |
+
if (empty($this->options->databaseUser) && empty($this->options->databasePassword)) {
|
408 |
$searchReplace = new muSearchReplace();
|
409 |
} else {
|
410 |
$searchReplace = new muSearchReplaceExternal();
|
411 |
}
|
412 |
} else {
|
413 |
+
if (empty($this->options->databaseUser) && empty($this->options->databasePassword)) {
|
414 |
$searchReplace = new SearchReplace();
|
415 |
} else {
|
416 |
$searchReplace = new SearchReplaceExternal();
|
417 |
}
|
418 |
}
|
419 |
+
return $this->handleJobResponse($searchReplace->start(), "directories");
|
420 |
}
|
421 |
|
422 |
/**
|
423 |
* Get All Files From Selected Directories Recursively Into a File
|
424 |
* @return object
|
425 |
*/
|
426 |
+
public function jobDirectories()
|
427 |
+
{
|
428 |
+
if (defined('WPSTGPRO_VERSION') && is_multisite()) {
|
429 |
$directories = new muDirectories();
|
430 |
} else {
|
431 |
$directories = new Directories();
|
432 |
}
|
433 |
+
return $this->handleJobResponse($directories->start(), "files");
|
434 |
}
|
435 |
|
436 |
/**
|
437 |
* Copy Files
|
438 |
* @return object
|
439 |
*/
|
440 |
+
public function jobFiles()
|
441 |
+
{
|
442 |
+
if (defined('WPSTGPRO_VERSION') && is_multisite()) {
|
443 |
$files = new muFiles();
|
444 |
} else {
|
445 |
$files = new Files();
|
446 |
}
|
447 |
+
return $this->handleJobResponse($files->start(), "data");
|
448 |
}
|
449 |
|
450 |
|
452 |
* Replace Data
|
453 |
* @return object
|
454 |
*/
|
455 |
+
public function jobData()
|
456 |
+
{
|
457 |
+
if (defined('WPSTGPRO_VERSION') && is_multisite()) {
|
458 |
+
if (empty($this->options->databaseUser) && empty($this->options->databasePassword)) {
|
459 |
$data = new muData();
|
460 |
} else {
|
461 |
$data = new muDataExternal();
|
462 |
}
|
463 |
} else {
|
464 |
|
465 |
+
if (empty($this->options->databaseUser) && empty($this->options->databasePassword)) {
|
466 |
$data = new Data();
|
467 |
} else {
|
468 |
$data = new DataExternal();
|
469 |
}
|
470 |
}
|
471 |
+
return $this->handleJobResponse($data->start(), "finish");
|
472 |
}
|
473 |
|
474 |
/**
|
475 |
* Save Clone Data
|
476 |
* @return object
|
477 |
*/
|
478 |
+
public function jobFinish()
|
479 |
+
{
|
480 |
+
if (defined('WPSTGPRO_VERSION') && is_multisite()) {
|
481 |
$finish = new muFinish();
|
482 |
} else {
|
483 |
$finish = new Finish();
|
484 |
}
|
485 |
+
return $this->handleJobResponse($finish->start(), '');
|
486 |
}
|
487 |
|
488 |
}
|
Backend/Modules/Jobs/Delete.php
CHANGED
@@ -451,15 +451,6 @@ class Delete extends Job {
|
|
451 |
}
|
452 |
}
|
453 |
|
454 |
-
/**
|
455 |
-
* @return bool
|
456 |
-
*/
|
457 |
-
// public function isDirectoryDeletingFinished() {
|
458 |
-
// return (
|
459 |
-
// (false === $this->forceDeleteDirectories && (!isset( $_POST["deleteDir"] ) || '1' !== $_POST["deleteDir"])) ||
|
460 |
-
// !is_dir( $this->clone->path ) || ABSPATH === $this->job->nextDirectoryToDelete
|
461 |
-
// );
|
462 |
-
// }
|
463 |
|
464 |
/**
|
465 |
*
|
@@ -490,9 +481,6 @@ class Delete extends Job {
|
|
490 |
if( $clone["path"] == $this->clone->path ) {
|
491 |
unset( $existingClones[$name] );
|
492 |
}
|
493 |
-
// if( !is_dir( $clone["path"] ) ) {
|
494 |
-
// unset( $existingClones[$name] );
|
495 |
-
// }
|
496 |
}
|
497 |
|
498 |
if( false === update_option( "wpstg_existing_clones_beta", $existingClones ) ) {
|
451 |
}
|
452 |
}
|
453 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
454 |
|
455 |
/**
|
456 |
*
|
481 |
if( $clone["path"] == $this->clone->path ) {
|
482 |
unset( $existingClones[$name] );
|
483 |
}
|
|
|
|
|
|
|
484 |
}
|
485 |
|
486 |
if( false === update_option( "wpstg_existing_clones_beta", $existingClones ) ) {
|
Backend/Modules/Jobs/Files.php
CHANGED
@@ -2,19 +2,15 @@
|
|
2 |
|
3 |
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
|
5 |
-
|
6 |
-
use WPStaging\WPStaging;
|
7 |
use WPStaging\Utils\Logger;
|
8 |
|
9 |
-
if( !defined( "WPINC" ) ) {
|
10 |
-
die;
|
11 |
-
}
|
12 |
-
|
13 |
/**
|
14 |
* Class Files
|
15 |
* @package WPStaging\Backend\Modules\Jobs
|
16 |
*/
|
17 |
-
class Files extends JobExecutable
|
|
|
18 |
|
19 |
/**
|
20 |
* @var \SplFileObject
|
@@ -34,23 +30,24 @@ class Files extends JobExecutable {
|
|
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(
|
44 |
-
$this->file = new \SplFileObject(
|
45 |
}
|
46 |
|
47 |
// Informational logs
|
48 |
-
if(
|
49 |
-
$this->log(
|
50 |
}
|
51 |
|
52 |
$this->settings->batchSize = $this->settings->batchSize * 1000000;
|
53 |
-
$this->maxFilesPerRun
|
54 |
//$this->maxFilesPerRun = ($this->settings->cpuLoad === 'low') ? 50 : 1;
|
55 |
}
|
56 |
|
@@ -58,8 +55,9 @@ class Files extends JobExecutable {
|
|
58 |
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
59 |
* @return void
|
60 |
*/
|
61 |
-
protected function calculateTotalSteps()
|
62 |
-
|
|
|
63 |
}
|
64 |
|
65 |
/**
|
@@ -67,17 +65,18 @@ class Files extends JobExecutable {
|
|
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(
|
73 |
-
$this->log(
|
74 |
-
$this->prepareResponse(
|
75 |
return false;
|
76 |
}
|
77 |
|
78 |
// Get files and copy'em
|
79 |
-
if(
|
80 |
-
$this->prepareResponse(
|
81 |
return false;
|
82 |
}
|
83 |
|
@@ -92,59 +91,46 @@ class Files extends JobExecutable {
|
|
92 |
* Get files and copy
|
93 |
* @return bool
|
94 |
*/
|
95 |
-
private function getFilesAndCopy()
|
|
|
96 |
// Over limits threshold
|
97 |
-
if(
|
98 |
// Prepare response and save current progress
|
99 |
-
$this->prepareResponse(
|
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(
|
107 |
-
$this->file->seek(
|
108 |
}
|
109 |
|
110 |
-
$this->file->setFlags(
|
111 |
-
|
112 |
-
|
113 |
-
|
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(
|
133 |
break;
|
134 |
}
|
135 |
|
136 |
$file = str_replace(PHP_EOL, null, $this->file->fgets());
|
137 |
|
138 |
|
139 |
-
$this->copyFile(
|
140 |
}
|
141 |
|
142 |
|
143 |
-
|
144 |
$totalFiles = $this->options->copiedFiles;
|
145 |
// Log this only every 50 entries to keep the log small and to not block the rendering browser
|
146 |
-
if(
|
147 |
-
$this->log(
|
148 |
}
|
149 |
|
150 |
return true;
|
@@ -154,87 +140,88 @@ class Files extends JobExecutable {
|
|
154 |
* Checks Whether There is Any Job to Execute or Not
|
155 |
* @return bool
|
156 |
*/
|
157 |
-
private function isFinished()
|
|
|
158 |
return
|
159 |
!$this->isRunning() ||
|
160 |
$this->options->currentStep > $this->options->totalSteps ||
|
161 |
-
$this->options->copiedFiles >= $this->options->totalFiles
|
162 |
-
;
|
163 |
}
|
164 |
|
165 |
/**
|
166 |
* @param string $file
|
167 |
* @return bool
|
168 |
*/
|
169 |
-
private function copyFile(
|
|
|
170 |
|
171 |
-
$file = trim(
|
172 |
|
173 |
$file = wpstg_replace_windows_directory_separator($file);
|
174 |
|
175 |
-
$directory = dirname(
|
176 |
|
177 |
// Directory is excluded
|
178 |
-
if(
|
179 |
-
$this->debugLog(
|
180 |
return false;
|
181 |
}
|
182 |
|
183 |
// File is excluded
|
184 |
-
if(
|
185 |
-
$this->debugLog(
|
186 |
return false;
|
187 |
}
|
188 |
// Path + File is excluded
|
189 |
-
if(
|
190 |
-
$this->debugLog(
|
191 |
return false;
|
192 |
}
|
193 |
|
194 |
// Invalid file, skipping it as if succeeded
|
195 |
-
if(
|
196 |
-
$this->log(
|
197 |
return true;
|
198 |
}
|
199 |
// Invalid file, skipping it as if succeeded
|
200 |
-
if(
|
201 |
-
$this->log(
|
202 |
return true;
|
203 |
}
|
204 |
|
205 |
|
206 |
// Get file size
|
207 |
-
$fileSize = filesize(
|
208 |
|
209 |
// File is over maximum allowed file size (8MB)
|
210 |
-
if(
|
211 |
-
$this->log(
|
212 |
return false;
|
213 |
}
|
214 |
|
215 |
// Failed to get destination
|
216 |
-
if(
|
217 |
-
$this->log(
|
218 |
return false;
|
219 |
}
|
220 |
|
221 |
// File is over batch size
|
222 |
-
if(
|
223 |
-
$this->log(
|
224 |
-
return $this->copyBig(
|
225 |
}
|
226 |
|
227 |
// Attempt to copy
|
228 |
-
if(
|
229 |
$errors = error_get_last();
|
230 |
-
$this->log(
|
231 |
return false;
|
232 |
}
|
233 |
|
234 |
// Set file permissions
|
235 |
-
@chmod(
|
236 |
|
237 |
-
$this->setDirPermissions(
|
238 |
|
239 |
return true;
|
240 |
}
|
@@ -245,28 +232,29 @@ class Files extends JobExecutable {
|
|
245 |
*
|
246 |
* @return string
|
247 |
*/
|
248 |
-
protected function getWpContentPath(
|
|
|
249 |
// Get upload directory information
|
250 |
$uploads = wp_upload_dir();
|
251 |
|
252 |
// Get absolute path to wordpress uploads directory e.g srv/www/htdocs/sitename/wp-content/uploads
|
253 |
-
$uploadsAbsPath = trailingslashit(
|
254 |
|
255 |
// Get relative path to the uploads folder, e.g assets
|
256 |
$uploadsRelPath = wpstg_get_rel_upload_dir();
|
257 |
|
258 |
// Get absolute path to wp-content directory e.g srv/www/htdocs/sitename/wp-content
|
259 |
-
$wpContentDir = trailingslashit(
|
260 |
|
261 |
// Check if there is a custom uploads directory, then do a search $ replace. Do this only if custom upload path is not identical to WP_CONTENT_DIR
|
262 |
-
if(
|
263 |
//$file = str_replace( $uploadsAbsPath, ABSPATH . 'wp-content/uploads/', $file, $count );
|
264 |
-
$file = str_replace(
|
265 |
}
|
266 |
// If there is no custom upload directory do a search & replace of the custom wp-content directory
|
267 |
-
if(
|
268 |
//$file = str_replace( $wpContentDir, ABSPATH . 'wp-content/', $file );
|
269 |
-
$file = str_replace(
|
270 |
}
|
271 |
|
272 |
|
@@ -278,10 +266,11 @@ class Files extends JobExecutable {
|
|
278 |
* @param type $file
|
279 |
* @return boolean
|
280 |
*/
|
281 |
-
private function setDirPermissions(
|
282 |
-
|
283 |
-
|
284 |
-
|
|
|
285 |
}
|
286 |
return false;
|
287 |
}
|
@@ -292,20 +281,21 @@ class Files extends JobExecutable {
|
|
292 |
* @param string $file
|
293 |
* @return bool|string
|
294 |
*/
|
295 |
-
private function getDestination(
|
|
|
296 |
//$file = $this->getMultisiteUploadFolder( $file );
|
297 |
$file = wpstg_replace_windows_directory_separator($file);
|
298 |
$rootPath = wpstg_replace_windows_directory_separator(\WPStaging\WPStaging::getWPpath());
|
299 |
-
$relativePath
|
300 |
-
$destinationPath
|
301 |
-
$destinationDirectory = dirname(
|
302 |
|
303 |
-
if(
|
304 |
-
$this->log(
|
305 |
return false;
|
306 |
}
|
307 |
|
308 |
-
return $this->sanitizeDirectorySeparator(
|
309 |
}
|
310 |
|
311 |
/**
|
@@ -315,105 +305,84 @@ class Files extends JobExecutable {
|
|
315 |
* @param int $buffersize
|
316 |
* @return boolean
|
317 |
*/
|
318 |
-
private function copyBig(
|
319 |
-
|
320 |
-
$
|
|
|
321 |
|
322 |
// Try first method:
|
323 |
-
while (
|
324 |
-
if(
|
325 |
$error = true;
|
326 |
}
|
327 |
}
|
328 |
// Try second method if first one failed
|
329 |
-
if(
|
330 |
-
while (
|
331 |
-
if(
|
332 |
-
$this->log(
|
333 |
-
fclose(
|
334 |
-
fclose(
|
335 |
return false;
|
336 |
}
|
337 |
}
|
338 |
}
|
339 |
// Close any open handler
|
340 |
-
fclose(
|
341 |
-
fclose(
|
342 |
return true;
|
343 |
}
|
344 |
|
345 |
/**
|
346 |
* Check if certain file is excluded from copying process
|
347 |
*
|
348 |
-
* @param string $file
|
349 |
* @return boolean
|
350 |
*/
|
351 |
-
private function isFileExcluded(
|
|
|
352 |
|
353 |
-
$excludedFiles = (
|
354 |
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
//if( $this->isCustomDirectory() ) {
|
360 |
-
if( false === $this->isIdenticalHostname() ) {
|
361 |
-
$excludedFiles = \array_diff( $excludedFiles, array("web.config", ".htaccess") );
|
362 |
}
|
363 |
|
364 |
-
|
365 |
-
// If file name exists
|
366 |
-
if( in_array( $basenameFile, $excludedFiles ) ) {
|
367 |
return true;
|
368 |
}
|
369 |
|
370 |
-
// Check for wildcards
|
371 |
-
foreach ($excludedFiles as $pattern) {
|
372 |
-
if (wpstg_fnmatch($pattern, $basenameFile)) {
|
373 |
-
return true;
|
374 |
-
}
|
375 |
-
}
|
376 |
-
|
377 |
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
378 |
// because if the updating process fails, the staging site would not be accessable any longer
|
379 |
-
if(
|
|
|
380 |
return true;
|
381 |
}
|
382 |
|
383 |
-
|
384 |
return false;
|
385 |
}
|
386 |
|
387 |
-
/**
|
388 |
-
* Check if custom target directory is used
|
389 |
-
* @return boolean
|
390 |
-
*/
|
391 |
-
// private function isCustomDirectory() {
|
392 |
-
//
|
393 |
-
// if( empty( $this->options->cloneDir ) ) {
|
394 |
-
// return false;
|
395 |
-
// }
|
396 |
-
// return true;
|
397 |
-
// }
|
398 |
-
|
399 |
/**
|
400 |
* Check if production and staging hostname are identical
|
401 |
* If they are not identical we assume website is cloned to a subdomain and not into a subfolder
|
402 |
* @return boolean
|
403 |
*/
|
404 |
-
private function isIdenticalHostname()
|
|
|
405 |
// hostname of production site without scheme
|
406 |
-
$siteurl
|
407 |
-
$url
|
408 |
$productionHostname = $url['host'];
|
409 |
|
410 |
// hostname of staging site without scheme
|
411 |
-
$cloneUrl
|
412 |
$targetHostname = $cloneUrl['host'];
|
413 |
|
414 |
// Check if target hostname beginns with the production hostname
|
415 |
// Only compare the hostname without path
|
416 |
-
if(
|
417 |
return true;
|
418 |
}
|
419 |
return false;
|
@@ -425,10 +394,11 @@ class Files extends JobExecutable {
|
|
425 |
* @param string $file filename including ending + (part) path e.g wp-content/db.php
|
426 |
* @return boolean
|
427 |
*/
|
428 |
-
private function isFileExcludedFullPath(
|
|
|
429 |
// If path + file exists
|
430 |
-
foreach (
|
431 |
-
if(
|
432 |
return true;
|
433 |
}
|
434 |
}
|
@@ -443,8 +413,9 @@ class Files extends JobExecutable {
|
|
443 |
* @param string $path Path
|
444 |
* @return string
|
445 |
*/
|
446 |
-
private function sanitizeDirectorySeparator(
|
447 |
-
|
|
|
448 |
}
|
449 |
|
450 |
/**
|
@@ -452,17 +423,18 @@ class Files extends JobExecutable {
|
|
452 |
* @param string $directory
|
453 |
* @return bool
|
454 |
*/
|
455 |
-
private function isDirectoryExcluded(
|
|
|
456 |
// Make sure that wp-staging-pro directory / plugin is never excluded
|
457 |
-
if(
|
458 |
return false;
|
459 |
}
|
460 |
|
461 |
-
$directory = trailingslashit(
|
462 |
|
463 |
-
foreach (
|
464 |
-
$excludedDirectory = trailingslashit(
|
465 |
-
if(
|
466 |
return true;
|
467 |
}
|
468 |
}
|
@@ -475,11 +447,12 @@ class Files extends JobExecutable {
|
|
475 |
* @param string $directory
|
476 |
* @return boolean
|
477 |
*/
|
478 |
-
private function isExtraDirectory(
|
479 |
-
|
|
|
480 |
|
481 |
-
foreach (
|
482 |
-
if(
|
483 |
return true;
|
484 |
}
|
485 |
}
|
2 |
|
3 |
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
|
5 |
+
use WPStaging\Manager\FileSystem\FileManager;
|
|
|
6 |
use WPStaging\Utils\Logger;
|
7 |
|
|
|
|
|
|
|
|
|
8 |
/**
|
9 |
* Class Files
|
10 |
* @package WPStaging\Backend\Modules\Jobs
|
11 |
*/
|
12 |
+
class Files extends JobExecutable
|
13 |
+
{
|
14 |
|
15 |
/**
|
16 |
* @var \SplFileObject
|
30 |
/**
|
31 |
* Initialization
|
32 |
*/
|
33 |
+
public function initialize()
|
34 |
+
{
|
35 |
|
36 |
$this->destination = $this->options->destinationDir;
|
37 |
|
38 |
$filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
39 |
|
40 |
+
if (is_file($filePath)) {
|
41 |
+
$this->file = new \SplFileObject($filePath, 'r');
|
42 |
}
|
43 |
|
44 |
// Informational logs
|
45 |
+
if (0 == $this->options->currentStep) {
|
46 |
+
$this->log("Copying files...");
|
47 |
}
|
48 |
|
49 |
$this->settings->batchSize = $this->settings->batchSize * 1000000;
|
50 |
+
$this->maxFilesPerRun = $this->settings->fileLimit;
|
51 |
//$this->maxFilesPerRun = ($this->settings->cpuLoad === 'low') ? 50 : 1;
|
52 |
}
|
53 |
|
55 |
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
56 |
* @return void
|
57 |
*/
|
58 |
+
protected function calculateTotalSteps()
|
59 |
+
{
|
60 |
+
$this->options->totalSteps = ceil($this->options->totalFiles / $this->maxFilesPerRun);
|
61 |
}
|
62 |
|
63 |
/**
|
65 |
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
66 |
* @return bool
|
67 |
*/
|
68 |
+
protected function execute()
|
69 |
+
{
|
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 |
|
91 |
* Get files and copy
|
92 |
* @return bool
|
93 |
*/
|
94 |
+
private function getFilesAndCopy()
|
95 |
+
{
|
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 |
+
for ($i = 0; $i < $this->maxFilesPerRun; $i++) {
|
113 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
// Increment copied files
|
115 |
// Do this anytime to make sure to not stuck in the same step / files
|
116 |
$this->options->copiedFiles++;
|
117 |
|
118 |
// End of file
|
119 |
+
if ($this->file->eof()) {
|
120 |
break;
|
121 |
}
|
122 |
|
123 |
$file = str_replace(PHP_EOL, null, $this->file->fgets());
|
124 |
|
125 |
|
126 |
+
$this->copyFile($file);
|
127 |
}
|
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;
|
140 |
* Checks Whether There is Any Job to Execute or Not
|
141 |
* @return bool
|
142 |
*/
|
143 |
+
private function isFinished()
|
144 |
+
{
|
145 |
return
|
146 |
!$this->isRunning() ||
|
147 |
$this->options->currentStep > $this->options->totalSteps ||
|
148 |
+
$this->options->copiedFiles >= $this->options->totalFiles;
|
|
|
149 |
}
|
150 |
|
151 |
/**
|
152 |
* @param string $file
|
153 |
* @return bool
|
154 |
*/
|
155 |
+
private function copyFile($file)
|
156 |
+
{
|
157 |
|
158 |
+
$file = trim(\WPStaging\WPStaging::getWPpath() . $file);
|
159 |
|
160 |
$file = wpstg_replace_windows_directory_separator($file);
|
161 |
|
162 |
+
$directory = dirname($file);
|
163 |
|
164 |
// Directory is excluded
|
165 |
+
if ($this->isDirectoryExcluded($directory)) {
|
166 |
+
$this->debugLog("Skipping directory by rule: {$file}", Logger::TYPE_INFO);
|
167 |
return false;
|
168 |
}
|
169 |
|
170 |
// File is excluded
|
171 |
+
if ($this->isFileExcluded($file)) {
|
172 |
+
$this->debugLog("Skipping file by rule: {$file}", Logger::TYPE_INFO);
|
173 |
return false;
|
174 |
}
|
175 |
// Path + File is excluded
|
176 |
+
if ($this->isFileExcludedFullPath($file)) {
|
177 |
+
$this->debugLog("Skipping file by rule: {$file}", Logger::TYPE_INFO);
|
178 |
return false;
|
179 |
}
|
180 |
|
181 |
// Invalid file, skipping it as if succeeded
|
182 |
+
if (!is_file($file)) {
|
183 |
+
$this->log("File doesn't exist {$file}", Logger::TYPE_WARNING);
|
184 |
return true;
|
185 |
}
|
186 |
// Invalid file, skipping it as if succeeded
|
187 |
+
if (!is_readable($file)) {
|
188 |
+
$this->log("Can't read file {$file}", Logger::TYPE_WARNING);
|
189 |
return true;
|
190 |
}
|
191 |
|
192 |
|
193 |
// Get file size
|
194 |
+
$fileSize = filesize($file);
|
195 |
|
196 |
// File is over maximum allowed file size (8MB)
|
197 |
+
if ($fileSize >= $this->settings->maxFileSize * 1000000) {
|
198 |
+
$this->log("Skipping big file: {$file}", Logger::TYPE_INFO);
|
199 |
return false;
|
200 |
}
|
201 |
|
202 |
// Failed to get destination
|
203 |
+
if (false === ($destination = $this->getDestination($file))) {
|
204 |
+
$this->log("Can't get the destination of {$file}", Logger::TYPE_WARNING);
|
205 |
return false;
|
206 |
}
|
207 |
|
208 |
// File is over batch size
|
209 |
+
if ($fileSize >= $this->settings->batchSize) {
|
210 |
+
$this->log("Trying to copy big file: {$file} -> {$destination}", Logger::TYPE_INFO);
|
211 |
+
return $this->copyBig($file, $destination, $this->settings->batchSize);
|
212 |
}
|
213 |
|
214 |
// Attempt to copy
|
215 |
+
if (!@copy($file, $destination)) {
|
216 |
$errors = error_get_last();
|
217 |
+
$this->log("Files: Failed to copy file to destination. Error: {$errors['message']} {$file} -> {$destination}", Logger::TYPE_ERROR);
|
218 |
return false;
|
219 |
}
|
220 |
|
221 |
// Set file permissions
|
222 |
+
@chmod($destination, wpstg_get_permissions_for_file());
|
223 |
|
224 |
+
$this->setDirPermissions($destination);
|
225 |
|
226 |
return true;
|
227 |
}
|
232 |
*
|
233 |
* @return string
|
234 |
*/
|
235 |
+
protected function getWpContentPath($file)
|
236 |
+
{
|
237 |
// Get upload directory information
|
238 |
$uploads = wp_upload_dir();
|
239 |
|
240 |
// Get absolute path to wordpress uploads directory e.g srv/www/htdocs/sitename/wp-content/uploads
|
241 |
+
$uploadsAbsPath = trailingslashit($uploads['basedir']);
|
242 |
|
243 |
// Get relative path to the uploads folder, e.g assets
|
244 |
$uploadsRelPath = wpstg_get_rel_upload_dir();
|
245 |
|
246 |
// Get absolute path to wp-content directory e.g srv/www/htdocs/sitename/wp-content
|
247 |
+
$wpContentDir = trailingslashit(WP_CONTENT_DIR);
|
248 |
|
249 |
// Check if there is a custom uploads directory, then do a search $ replace. Do this only if custom upload path is not identical to WP_CONTENT_DIR
|
250 |
+
if ($uploadsAbsPath != $wpContentDir) {
|
251 |
//$file = str_replace( $uploadsAbsPath, ABSPATH . 'wp-content/uploads/', $file, $count );
|
252 |
+
$file = str_replace($uploadsAbsPath, ABSPATH . $uploadsRelPath, $file, $count);
|
253 |
}
|
254 |
// If there is no custom upload directory do a search & replace of the custom wp-content directory
|
255 |
+
if (empty($count) || $count === 0) {
|
256 |
//$file = str_replace( $wpContentDir, ABSPATH . 'wp-content/', $file );
|
257 |
+
$file = str_replace($wpContentDir, ABSPATH . 'wp-content/', $file);
|
258 |
}
|
259 |
|
260 |
|
266 |
* @param type $file
|
267 |
* @return boolean
|
268 |
*/
|
269 |
+
private function setDirPermissions($file)
|
270 |
+
{
|
271 |
+
$dir = dirname($file);
|
272 |
+
if (is_dir($dir)) {
|
273 |
+
@chmod($dir, wpstg_get_permissions_for_directory());
|
274 |
}
|
275 |
return false;
|
276 |
}
|
281 |
* @param string $file
|
282 |
* @return bool|string
|
283 |
*/
|
284 |
+
private function getDestination($file)
|
285 |
+
{
|
286 |
//$file = $this->getMultisiteUploadFolder( $file );
|
287 |
$file = wpstg_replace_windows_directory_separator($file);
|
288 |
$rootPath = wpstg_replace_windows_directory_separator(\WPStaging\WPStaging::getWPpath());
|
289 |
+
$relativePath = str_replace($rootPath, null, $file);
|
290 |
+
$destinationPath = $this->destination . $relativePath;
|
291 |
+
$destinationDirectory = dirname($destinationPath);
|
292 |
|
293 |
+
if (!is_dir($destinationDirectory) && !@mkdir($destinationDirectory, wpstg_get_permissions_for_directory(), true)) {
|
294 |
+
$this->log("Files: Can not create directory {$destinationDirectory}", Logger::TYPE_ERROR);
|
295 |
return false;
|
296 |
}
|
297 |
|
298 |
+
return $this->sanitizeDirectorySeparator($destinationPath);
|
299 |
}
|
300 |
|
301 |
/**
|
305 |
* @param int $buffersize
|
306 |
* @return boolean
|
307 |
*/
|
308 |
+
private function copyBig($src, $dst, $buffersize)
|
309 |
+
{
|
310 |
+
$src = fopen($src, 'r');
|
311 |
+
$dest = fopen($dst, 'w');
|
312 |
|
313 |
// Try first method:
|
314 |
+
while (!feof($src)) {
|
315 |
+
if (false === fwrite($dest, fread($src, $buffersize))) {
|
316 |
$error = true;
|
317 |
}
|
318 |
}
|
319 |
// Try second method if first one failed
|
320 |
+
if (isset($error) && ($error === true)) {
|
321 |
+
while (!feof($src)) {
|
322 |
+
if (false === stream_copy_to_stream($src, $dest, 1024)) {
|
323 |
+
$this->log("Can not copy file; {$src} -> {$dest}");
|
324 |
+
fclose($src);
|
325 |
+
fclose($dest);
|
326 |
return false;
|
327 |
}
|
328 |
}
|
329 |
}
|
330 |
// Close any open handler
|
331 |
+
fclose($src);
|
332 |
+
fclose($dest);
|
333 |
return true;
|
334 |
}
|
335 |
|
336 |
/**
|
337 |
* Check if certain file is excluded from copying process
|
338 |
*
|
339 |
+
* @param string $file full path + filename
|
340 |
* @return boolean
|
341 |
*/
|
342 |
+
private function isFileExcluded($file)
|
343 |
+
{
|
344 |
|
345 |
+
$excludedFiles = (array) $this->options->excludedFiles;
|
346 |
|
347 |
+
// Remove .htaccess and web.config from 'excludedFiles' if staging site is copied to a subdomain
|
348 |
+
if (false === $this->isIdenticalHostname()) {
|
349 |
+
$excludedFiles = \array_diff($excludedFiles,
|
350 |
+
array("web.config", ".htaccess"));
|
|
|
|
|
|
|
351 |
}
|
352 |
|
353 |
+
if ((new FileManager)->isFilenameExcluded($file, $excludedFiles)) {
|
|
|
|
|
354 |
return true;
|
355 |
}
|
356 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
357 |
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
358 |
// because if the updating process fails, the staging site would not be accessable any longer
|
359 |
+
if (isset($this->options->mainJob) && $this->options->mainJob == "updating"
|
360 |
+
&& stripos(strrev($file), strrev("wp-config.php")) === 0) {
|
361 |
return true;
|
362 |
}
|
363 |
|
|
|
364 |
return false;
|
365 |
}
|
366 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
367 |
/**
|
368 |
* Check if production and staging hostname are identical
|
369 |
* If they are not identical we assume website is cloned to a subdomain and not into a subfolder
|
370 |
* @return boolean
|
371 |
*/
|
372 |
+
private function isIdenticalHostname()
|
373 |
+
{
|
374 |
// hostname of production site without scheme
|
375 |
+
$siteurl = get_site_url();
|
376 |
+
$url = parse_url($siteurl);
|
377 |
$productionHostname = $url['host'];
|
378 |
|
379 |
// hostname of staging site without scheme
|
380 |
+
$cloneUrl = empty($this->options->cloneHostname) ? $url : parse_url($this->options->cloneHostname);
|
381 |
$targetHostname = $cloneUrl['host'];
|
382 |
|
383 |
// Check if target hostname beginns with the production hostname
|
384 |
// Only compare the hostname without path
|
385 |
+
if (wpstg_starts_with($productionHostname, $targetHostname)) {
|
386 |
return true;
|
387 |
}
|
388 |
return false;
|
394 |
* @param string $file filename including ending + (part) path e.g wp-content/db.php
|
395 |
* @return boolean
|
396 |
*/
|
397 |
+
private function isFileExcludedFullPath($file)
|
398 |
+
{
|
399 |
// If path + file exists
|
400 |
+
foreach ($this->options->excludedFilesFullPath as $excludedFile) {
|
401 |
+
if (false !== strpos($file, $excludedFile)) {
|
402 |
return true;
|
403 |
}
|
404 |
}
|
413 |
* @param string $path Path
|
414 |
* @return string
|
415 |
*/
|
416 |
+
private function sanitizeDirectorySeparator($path)
|
417 |
+
{
|
418 |
+
return preg_replace('/[\\\\]+/', '/', $path);
|
419 |
}
|
420 |
|
421 |
/**
|
423 |
* @param string $directory
|
424 |
* @return bool
|
425 |
*/
|
426 |
+
private function isDirectoryExcluded($directory)
|
427 |
+
{
|
428 |
// Make sure that wp-staging-pro directory / plugin is never excluded
|
429 |
+
if (false !== strpos($directory, 'wp-staging') || false !== strpos($directory, 'wp-staging-pro')) {
|
430 |
return false;
|
431 |
}
|
432 |
|
433 |
+
$directory = trailingslashit($this->sanitizeDirectorySeparator($directory));
|
434 |
|
435 |
+
foreach ($this->options->excludedDirectories as $excludedDirectory) {
|
436 |
+
$excludedDirectory = trailingslashit($this->sanitizeDirectorySeparator($excludedDirectory));
|
437 |
+
if (strpos($directory, $excludedDirectory) === 0 && !$this->isExtraDirectory($directory)) {
|
438 |
return true;
|
439 |
}
|
440 |
}
|
447 |
* @param string $directory
|
448 |
* @return boolean
|
449 |
*/
|
450 |
+
private function isExtraDirectory($directory)
|
451 |
+
{
|
452 |
+
$directory = $this->sanitizeDirectorySeparator($directory);
|
453 |
|
454 |
+
foreach ($this->options->extraDirectories as $extraDirectory) {
|
455 |
+
if (strpos($directory, $this->sanitizeDirectorySeparator($extraDirectory)) === 0) {
|
456 |
return true;
|
457 |
}
|
458 |
}
|
Backend/Modules/Jobs/Multisite/Directories.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
4 |
|
5 |
// No Direct Access
|
6 |
-
if(
|
7 |
die;
|
8 |
}
|
9 |
|
@@ -18,7 +18,8 @@ use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
|
18 |
* Class Files
|
19 |
* @package WPStaging\Backend\Modules\Directories
|
20 |
*/
|
21 |
-
class Directories extends JobExecutable
|
|
|
22 |
|
23 |
/**
|
24 |
* @var array
|
@@ -33,14 +34,15 @@ class Directories extends JobExecutable {
|
|
33 |
|
34 |
/**
|
35 |
* path to the cache file
|
36 |
-
* @var string
|
37 |
*/
|
38 |
private $filename;
|
39 |
|
40 |
/**
|
41 |
* Initialize
|
42 |
*/
|
43 |
-
public function initialize()
|
|
|
44 |
$this->filename = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
45 |
}
|
46 |
|
@@ -48,16 +50,18 @@ class Directories extends JobExecutable {
|
|
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 = $this->total + count(
|
54 |
}
|
55 |
|
56 |
/**
|
57 |
* Start Module
|
58 |
* @return object
|
59 |
*/
|
60 |
-
public function start()
|
|
|
61 |
|
62 |
// Execute steps
|
63 |
$this->run();
|
@@ -65,30 +69,31 @@ class Directories extends JobExecutable {
|
|
65 |
// Save option, progress
|
66 |
$this->saveProgress();
|
67 |
|
68 |
-
return ( object )
|
69 |
}
|
70 |
|
71 |
/**
|
72 |
-
* Step 0
|
73 |
* Get WP Root files
|
74 |
* Does not collect any sub folders
|
75 |
*/
|
76 |
-
private function getWpRootFiles()
|
|
|
77 |
|
78 |
// open file handle
|
79 |
-
$files = $this->open(
|
80 |
|
81 |
try {
|
82 |
|
83 |
// Iterate over wp root directory
|
84 |
-
$iterator = new \DirectoryIterator(
|
85 |
|
86 |
-
$this->log(
|
87 |
|
88 |
// Write path line
|
89 |
-
foreach (
|
90 |
-
if(
|
91 |
-
if(
|
92 |
$this->options->totalFiles++;
|
93 |
|
94 |
// Too much cpu time
|
@@ -96,11 +101,11 @@ class Directories extends JobExecutable {
|
|
96 |
}
|
97 |
}
|
98 |
}
|
99 |
-
} catch (
|
100 |
-
$this->returnException(
|
101 |
}
|
102 |
|
103 |
-
$this->close(
|
104 |
return true;
|
105 |
}
|
106 |
|
@@ -108,15 +113,16 @@ class Directories extends JobExecutable {
|
|
108 |
* Step 2
|
109 |
* Get WP Content Files without multisite folder wp-content/uploads/sites or wp-content/blogs.dir/
|
110 |
*/
|
111 |
-
private function getWpContentFiles()
|
|
|
112 |
|
113 |
// Skip it
|
114 |
-
if(
|
115 |
-
$this->log(
|
116 |
return true;
|
117 |
}
|
118 |
// open file handle
|
119 |
-
$files = $this->open(
|
120 |
|
121 |
/**
|
122 |
* Excluded folders relative to the folder to iterate
|
@@ -132,36 +138,36 @@ class Directories extends JobExecutable {
|
|
132 |
* Get user excluded folders
|
133 |
*/
|
134 |
$directory = array();
|
135 |
-
foreach (
|
136 |
// Windows compatibility fix
|
137 |
-
$dir
|
138 |
-
$wpContentDir = wpstg_replace_windows_directory_separator(
|
139 |
|
140 |
-
if(
|
141 |
-
$directory[] = ltrim(
|
142 |
}
|
143 |
}
|
144 |
|
145 |
-
$excludePaths = array_merge(
|
146 |
|
147 |
try {
|
148 |
|
149 |
// Iterate over content directory
|
150 |
-
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator(
|
151 |
|
152 |
// Exclude sites, uploads, plugins or themes
|
153 |
-
$iterator = new \WPStaging\Iterators\RecursiveFilterExclude(
|
154 |
|
155 |
// Recursively iterate over content directory
|
156 |
-
$iterator = new \RecursiveIteratorIterator(
|
157 |
|
158 |
-
$this->log(
|
159 |
|
160 |
// Write path line
|
161 |
-
foreach (
|
162 |
-
if(
|
163 |
$file = 'wp-content/' . $iterator->getSubPathName() . PHP_EOL;
|
164 |
-
if(
|
165 |
$this->options->totalFiles++;
|
166 |
|
167 |
// Add current file size
|
@@ -169,13 +175,13 @@ class Directories extends JobExecutable {
|
|
169 |
}
|
170 |
}
|
171 |
}
|
172 |
-
} catch (
|
173 |
-
$this->returnException(
|
174 |
//throw new \Exception( 'Error: ' . $e->getMessage() );
|
175 |
}
|
176 |
|
177 |
// close the file handler
|
178 |
-
$this->close(
|
179 |
return true;
|
180 |
}
|
181 |
|
@@ -184,31 +190,32 @@ class Directories extends JobExecutable {
|
|
184 |
* @return boolean
|
185 |
* @throws \Exception
|
186 |
*/
|
187 |
-
private function getWpIncludesFiles()
|
|
|
188 |
|
189 |
// Skip it
|
190 |
-
if(
|
191 |
-
$this->log(
|
192 |
return true;
|
193 |
}
|
194 |
|
195 |
// open file handle and attach data to end of file
|
196 |
-
$files = $this->open(
|
197 |
|
198 |
try {
|
199 |
|
200 |
// Iterate over wp-admin directory
|
201 |
-
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator(
|
202 |
|
203 |
// Recursively iterate over wp-includes directory
|
204 |
-
$iterator = new \RecursiveIteratorIterator(
|
205 |
|
206 |
-
$this->log(
|
207 |
|
208 |
// Write files
|
209 |
-
foreach (
|
210 |
-
if(
|
211 |
-
if(
|
212 |
$this->options->totalFiles++;
|
213 |
|
214 |
// Add current file size
|
@@ -216,12 +223,12 @@ class Directories extends JobExecutable {
|
|
216 |
}
|
217 |
}
|
218 |
}
|
219 |
-
} catch (
|
220 |
-
$this->returnException(
|
221 |
}
|
222 |
|
223 |
// close the file handler
|
224 |
-
$this->close(
|
225 |
return true;
|
226 |
}
|
227 |
|
@@ -230,43 +237,44 @@ class Directories extends JobExecutable {
|
|
230 |
* @return boolean
|
231 |
* @throws \Exception
|
232 |
*/
|
233 |
-
private function getWpAdminFiles()
|
|
|
234 |
|
235 |
// Skip it
|
236 |
-
if(
|
237 |
-
$this->log(
|
238 |
return true;
|
239 |
}
|
240 |
|
241 |
// open file handle and attach data to end of file
|
242 |
-
$files = $this->open(
|
243 |
|
244 |
try {
|
245 |
|
246 |
// Iterate over wp-admin directory
|
247 |
-
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator(
|
248 |
|
249 |
// Recursively iterate over content directory
|
250 |
-
$iterator = new \RecursiveIteratorIterator(
|
251 |
|
252 |
-
$this->log(
|
253 |
|
254 |
// Write path line
|
255 |
-
foreach (
|
256 |
-
if(
|
257 |
-
if(
|
258 |
$this->options->totalFiles++;
|
259 |
// Too much cpu time
|
260 |
//$this->options->totalFileSize += $iterator->getSize();
|
261 |
}
|
262 |
}
|
263 |
}
|
264 |
-
} catch (
|
265 |
-
$this->returnException(
|
266 |
}
|
267 |
|
268 |
// close the file handler
|
269 |
-
$this->close(
|
270 |
return true;
|
271 |
}
|
272 |
|
@@ -274,10 +282,11 @@ class Directories extends JobExecutable {
|
|
274 |
* Step 4
|
275 |
* Get WP Content Uploads Files multisite folder wp-content/uploads/sites or wp-content/blogs.dir/ID/files
|
276 |
*/
|
277 |
-
private function getWpContentUploadsSites()
|
|
|
278 |
|
279 |
// Skip if main site is cloned
|
280 |
-
if(
|
281 |
return true;
|
282 |
}
|
283 |
|
@@ -288,20 +297,20 @@ class Directories extends JobExecutable {
|
|
288 |
$path = $this->getAbsUploadPath();
|
289 |
|
290 |
// Skip it
|
291 |
-
if(
|
292 |
-
$this->log(
|
293 |
return true;
|
294 |
}
|
295 |
|
296 |
// Skip it
|
297 |
-
if(
|
298 |
-
$this->log(
|
299 |
return true;
|
300 |
}
|
301 |
|
302 |
|
303 |
// open file handle
|
304 |
-
$files = $this->open(
|
305 |
|
306 |
/**
|
307 |
* Excluded folders relative to the folder to iterate
|
@@ -316,34 +325,34 @@ class Directories extends JobExecutable {
|
|
316 |
* Get user excluded folders
|
317 |
*/
|
318 |
$directory = array();
|
319 |
-
foreach (
|
320 |
-
$path = wpstg_replace_windows_directory_separator(
|
321 |
-
$dir
|
322 |
-
if(
|
323 |
-
$directory[] = ltrim(
|
324 |
}
|
325 |
}
|
326 |
|
327 |
-
$excludePaths = array_merge(
|
328 |
|
329 |
try {
|
330 |
|
331 |
// Iterate over content directory
|
332 |
-
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator(
|
333 |
|
334 |
// Exclude sites, uploads, plugins or themes
|
335 |
-
$iterator = new \WPStaging\Iterators\RecursiveFilterExclude(
|
336 |
|
337 |
// Recursively iterate over content directory
|
338 |
-
$iterator = new \RecursiveIteratorIterator(
|
339 |
$uploadDir = wpstg_get_upload_dir();
|
340 |
-
$this->log(
|
341 |
|
342 |
// Write path line
|
343 |
-
foreach (
|
344 |
-
if(
|
345 |
$file = $this->getRelUploadPath() . $iterator->getSubPathName() . PHP_EOL;
|
346 |
-
if(
|
347 |
$this->options->totalFiles++;
|
348 |
|
349 |
// Add current file size
|
@@ -351,12 +360,12 @@ class Directories extends JobExecutable {
|
|
351 |
}
|
352 |
}
|
353 |
}
|
354 |
-
} catch (
|
355 |
-
$this->returnException(
|
356 |
}
|
357 |
|
358 |
// close the file handler
|
359 |
-
$this->close(
|
360 |
return true;
|
361 |
}
|
362 |
|
@@ -364,96 +373,101 @@ class Directories extends JobExecutable {
|
|
364 |
* Get absolute path to the upload folder e.g. /srv/www/wp-content/blogs.dir/ID/files or /srv/www/wp-content/uploads/sites/ID/
|
365 |
* @return type
|
366 |
*/
|
367 |
-
private function getAbsUploadPath()
|
|
|
368 |
// Check first which method is used
|
369 |
$uploads = wp_upload_dir();
|
370 |
$basedir = $uploads['basedir'];
|
371 |
|
372 |
-
return trailingslashit(
|
373 |
}
|
374 |
|
375 |
/**
|
376 |
* Get relative path to the upload folder like wp-content/uploads or wp-content/blogs.dir/2/files
|
377 |
* @return string
|
378 |
*/
|
379 |
-
private function getRelUploadPath()
|
|
|
380 |
$uploads = wp_upload_dir();
|
381 |
$basedir = $uploads['basedir'];
|
382 |
|
383 |
-
return trailingslashit(
|
384 |
}
|
385 |
|
386 |
/**
|
387 |
-
* Step 5 - x
|
388 |
* Get extra folders of the wp root level
|
389 |
* Does not collect wp-includes, wp-admin and wp-content folder
|
390 |
*/
|
391 |
-
private function getExtraFiles(
|
|
|
392 |
|
393 |
-
if(
|
394 |
return true;
|
395 |
}
|
396 |
|
397 |
// open file handle and attach data to end of file
|
398 |
-
$files = $this->open(
|
399 |
|
400 |
try {
|
401 |
|
402 |
// Iterate over extra directory
|
403 |
-
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator(
|
404 |
|
405 |
$exclude = array();
|
406 |
|
407 |
-
$iterator = new \WPStaging\Iterators\RecursiveFilterExclude(
|
408 |
// Recursively iterate over content directory
|
409 |
-
$iterator = new \RecursiveIteratorIterator(
|
410 |
|
411 |
$strings = new Strings();
|
412 |
-
$this->log(
|
413 |
|
414 |
// Write path line
|
415 |
-
foreach (
|
416 |
-
if(
|
417 |
-
$path = str_replace(
|
418 |
-
if(
|
419 |
$this->options->totalFiles++;
|
420 |
// Add current file size
|
421 |
$this->options->totalFileSize += $iterator->getSize();
|
422 |
}
|
423 |
}
|
424 |
}
|
425 |
-
} catch (
|
426 |
-
$this->returnException(
|
427 |
}
|
428 |
|
429 |
// close the file handler
|
430 |
-
$this->close(
|
431 |
return true;
|
432 |
}
|
433 |
|
434 |
/**
|
435 |
* Closes a file handle
|
436 |
*
|
437 |
-
* @param
|
438 |
* @return boolean
|
439 |
*/
|
440 |
-
public function close(
|
441 |
-
|
|
|
442 |
}
|
443 |
|
444 |
/**
|
445 |
* Opens a file in specified mode
|
446 |
*
|
447 |
-
* @param
|
448 |
-
* @param
|
449 |
* @return resource
|
450 |
* @throws Exception
|
451 |
*/
|
452 |
-
public function open(
|
|
|
453 |
|
454 |
-
$file_handle = @fopen(
|
455 |
-
if(
|
456 |
-
$this->returnException(
|
457 |
}
|
458 |
|
459 |
return $file_handle;
|
@@ -462,20 +476,21 @@ class Directories extends JobExecutable {
|
|
462 |
/**
|
463 |
* Write contents to a file
|
464 |
*
|
465 |
-
* @param
|
466 |
-
* @param
|
467 |
* @return integer
|
468 |
* @throws Exception
|
469 |
* @throws Exception
|
470 |
*/
|
471 |
-
public function write(
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
|
|
476 |
}
|
477 |
-
} elseif(
|
478 |
-
throw new \Exception(
|
479 |
}
|
480 |
|
481 |
return $write_result;
|
@@ -486,54 +501,55 @@ class Directories extends JobExecutable {
|
|
486 |
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
487 |
* @return bool
|
488 |
*/
|
489 |
-
protected function execute()
|
|
|
490 |
|
491 |
// No job left to execute
|
492 |
-
if(
|
493 |
-
$this->prepareResponse(
|
494 |
return false;
|
495 |
}
|
496 |
|
497 |
|
498 |
-
if(
|
499 |
$this->getWpRootFiles();
|
500 |
-
$this->prepareResponse(
|
501 |
return false;
|
502 |
}
|
503 |
|
504 |
-
if(
|
505 |
$this->getWpContentFiles();
|
506 |
-
$this->prepareResponse(
|
507 |
return false;
|
508 |
}
|
509 |
|
510 |
-
if(
|
511 |
$this->getWpIncludesFiles();
|
512 |
-
$this->prepareResponse(
|
513 |
return false;
|
514 |
}
|
515 |
|
516 |
-
if(
|
517 |
$this->getWpAdminFiles();
|
518 |
-
$this->prepareResponse(
|
519 |
return false;
|
520 |
}
|
521 |
|
522 |
-
if(
|
523 |
$this->getWpContentUploadsSites();
|
524 |
-
$this->prepareResponse(
|
525 |
return false;
|
526 |
}
|
527 |
|
528 |
-
if(
|
529 |
-
$this->getExtraFiles(
|
530 |
-
$this->prepareResponse(
|
531 |
return false;
|
532 |
}
|
533 |
|
534 |
|
535 |
// Prepare response
|
536 |
-
$this->prepareResponse(
|
537 |
// Not finished
|
538 |
return true;
|
539 |
}
|
@@ -542,8 +558,9 @@ class Directories extends JobExecutable {
|
|
542 |
* Checks Whether There is Any Job to Execute or Not
|
543 |
* @return bool
|
544 |
*/
|
545 |
-
protected function isFinished()
|
546 |
-
|
|
|
547 |
return true;
|
548 |
}
|
549 |
}
|
@@ -552,7 +569,8 @@ class Directories extends JobExecutable {
|
|
552 |
* Save files
|
553 |
* @return bool
|
554 |
*/
|
555 |
-
protected function saveProgress()
|
|
|
556 |
return $this->saveOptions();
|
557 |
}
|
558 |
|
@@ -560,39 +578,33 @@ class Directories extends JobExecutable {
|
|
560 |
* Get files
|
561 |
* @return void
|
562 |
*/
|
563 |
-
protected function getFiles()
|
|
|
564 |
$fileName = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
565 |
|
566 |
-
if(
|
567 |
$this->files = array();
|
568 |
return;
|
569 |
}
|
570 |
|
571 |
-
$this->files = explode(
|
572 |
}
|
573 |
|
574 |
-
/**
|
575 |
-
* Replace forward slash with backslash directory separator
|
576 |
-
*
|
577 |
-
* @param string $path Path
|
578 |
-
*
|
579 |
-
* @return string
|
580 |
-
*/
|
581 |
-
// private function sanitizeDirectorySeparator( $path ) {
|
582 |
-
// $string = str_replace( "/", "\\", $path );
|
583 |
-
// return str_replace( '\\\\', '\\', $string );
|
584 |
-
// }
|
585 |
|
586 |
/**
|
587 |
* Check if directory is excluded
|
588 |
* @param string $directory
|
589 |
* @return bool
|
590 |
*/
|
591 |
-
protected function isDirectoryExcluded(
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
if
|
|
|
|
|
|
|
|
|
596 |
return true;
|
597 |
}
|
598 |
}
|
3 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
4 |
|
5 |
// No Direct Access
|
6 |
+
if (!defined("WPINC")) {
|
7 |
die;
|
8 |
}
|
9 |
|
18 |
* Class Files
|
19 |
* @package WPStaging\Backend\Modules\Directories
|
20 |
*/
|
21 |
+
class Directories extends JobExecutable
|
22 |
+
{
|
23 |
|
24 |
/**
|
25 |
* @var array
|
34 |
|
35 |
/**
|
36 |
* path to the cache file
|
37 |
+
* @var string
|
38 |
*/
|
39 |
private $filename;
|
40 |
|
41 |
/**
|
42 |
* Initialize
|
43 |
*/
|
44 |
+
public function initialize()
|
45 |
+
{
|
46 |
$this->filename = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
47 |
}
|
48 |
|
50 |
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
51 |
* @return void
|
52 |
*/
|
53 |
+
protected function calculateTotalSteps()
|
54 |
+
{
|
55 |
|
56 |
+
$this->options->totalSteps = $this->total + count($this->options->extraDirectories);
|
57 |
}
|
58 |
|
59 |
/**
|
60 |
* Start Module
|
61 |
* @return object
|
62 |
*/
|
63 |
+
public function start()
|
64 |
+
{
|
65 |
|
66 |
// Execute steps
|
67 |
$this->run();
|
69 |
// Save option, progress
|
70 |
$this->saveProgress();
|
71 |
|
72 |
+
return ( object )$this->response;
|
73 |
}
|
74 |
|
75 |
/**
|
76 |
+
* Step 0
|
77 |
* Get WP Root files
|
78 |
* Does not collect any sub folders
|
79 |
*/
|
80 |
+
private function getWpRootFiles()
|
81 |
+
{
|
82 |
|
83 |
// open file handle
|
84 |
+
$files = $this->open($this->filename, 'a');
|
85 |
|
86 |
try {
|
87 |
|
88 |
// Iterate over wp root directory
|
89 |
+
$iterator = new \DirectoryIterator(\WPStaging\WPStaging::getWPpath());
|
90 |
|
91 |
+
$this->log("Scanning / for files");
|
92 |
|
93 |
// Write path line
|
94 |
+
foreach ($iterator as $item) {
|
95 |
+
if (!$item->isDot() && $item->isFile()) {
|
96 |
+
if ($this->write($files, $iterator->getFilename() . PHP_EOL)) {
|
97 |
$this->options->totalFiles++;
|
98 |
|
99 |
// Too much cpu time
|
101 |
}
|
102 |
}
|
103 |
}
|
104 |
+
} catch (\Exception $e) {
|
105 |
+
$this->returnException('Error: ' . $e->getMessage());
|
106 |
}
|
107 |
|
108 |
+
$this->close($files);
|
109 |
return true;
|
110 |
}
|
111 |
|
113 |
* Step 2
|
114 |
* Get WP Content Files without multisite folder wp-content/uploads/sites or wp-content/blogs.dir/
|
115 |
*/
|
116 |
+
private function getWpContentFiles()
|
117 |
+
{
|
118 |
|
119 |
// Skip it
|
120 |
+
if ($this->isDirectoryExcluded(WP_CONTENT_DIR)) {
|
121 |
+
$this->log("Skip " . WP_CONTENT_DIR);
|
122 |
return true;
|
123 |
}
|
124 |
// open file handle
|
125 |
+
$files = $this->open($this->filename, 'a');
|
126 |
|
127 |
/**
|
128 |
* Excluded folders relative to the folder to iterate
|
138 |
* Get user excluded folders
|
139 |
*/
|
140 |
$directory = array();
|
141 |
+
foreach ($this->options->excludedDirectories as $dir) {
|
142 |
// Windows compatibility fix
|
143 |
+
$dir = wpstg_replace_windows_directory_separator($dir);
|
144 |
+
$wpContentDir = wpstg_replace_windows_directory_separator(WP_CONTENT_DIR);
|
145 |
|
146 |
+
if (strpos($dir, $wpContentDir) !== false) {
|
147 |
+
$directory[] = ltrim(str_replace($wpContentDir, '', $dir), '/\\');
|
148 |
}
|
149 |
}
|
150 |
|
151 |
+
$excludePaths = array_merge($excludePaths, $directory);
|
152 |
|
153 |
try {
|
154 |
|
155 |
// Iterate over content directory
|
156 |
+
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator(WP_CONTENT_DIR);
|
157 |
|
158 |
// Exclude sites, uploads, plugins or themes
|
159 |
+
$iterator = new \WPStaging\Iterators\RecursiveFilterExclude($iterator, apply_filters('wpstg_clone_mu_excl_folders', $excludePaths));
|
160 |
|
161 |
// Recursively iterate over content directory
|
162 |
+
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::LEAVES_ONLY, \RecursiveIteratorIterator::CATCH_GET_CHILD);
|
163 |
|
164 |
+
$this->log("Scanning wp-content folder " . WP_CONTENT_DIR);
|
165 |
|
166 |
// Write path line
|
167 |
+
foreach ($iterator as $item) {
|
168 |
+
if ($item->isFile()) {
|
169 |
$file = 'wp-content/' . $iterator->getSubPathName() . PHP_EOL;
|
170 |
+
if ($this->write($files, $file)) {
|
171 |
$this->options->totalFiles++;
|
172 |
|
173 |
// Add current file size
|
175 |
}
|
176 |
}
|
177 |
}
|
178 |
+
} catch (\Exception $e) {
|
179 |
+
$this->returnException('Error: ' . $e->getMessage());
|
180 |
//throw new \Exception( 'Error: ' . $e->getMessage() );
|
181 |
}
|
182 |
|
183 |
// close the file handler
|
184 |
+
$this->close($files);
|
185 |
return true;
|
186 |
}
|
187 |
|
190 |
* @return boolean
|
191 |
* @throws \Exception
|
192 |
*/
|
193 |
+
private function getWpIncludesFiles()
|
194 |
+
{
|
195 |
|
196 |
// Skip it
|
197 |
+
if ($this->isDirectoryExcluded(\WPStaging\WPStaging::getWPpath() . 'wp-includes')) {
|
198 |
+
$this->log("Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-includes');
|
199 |
return true;
|
200 |
}
|
201 |
|
202 |
// open file handle and attach data to end of file
|
203 |
+
$files = $this->open($this->filename, 'a');
|
204 |
|
205 |
try {
|
206 |
|
207 |
// Iterate over wp-admin directory
|
208 |
+
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator(\WPStaging\WPStaging::getWPpath() . 'wp-includes/');
|
209 |
|
210 |
// Recursively iterate over wp-includes directory
|
211 |
+
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::LEAVES_ONLY, \RecursiveIteratorIterator::CATCH_GET_CHILD);
|
212 |
|
213 |
+
$this->log("Scanning /wp-includes for its sub-directories and files");
|
214 |
|
215 |
// Write files
|
216 |
+
foreach ($iterator as $item) {
|
217 |
+
if ($item->isFile()) {
|
218 |
+
if ($this->write($files, 'wp-includes/' . $iterator->getSubPathName() . PHP_EOL)) {
|
219 |
$this->options->totalFiles++;
|
220 |
|
221 |
// Add current file size
|
223 |
}
|
224 |
}
|
225 |
}
|
226 |
+
} catch (\Exception $e) {
|
227 |
+
$this->returnException('Error: ' . $e->getMessage());
|
228 |
}
|
229 |
|
230 |
// close the file handler
|
231 |
+
$this->close($files);
|
232 |
return true;
|
233 |
}
|
234 |
|
237 |
* @return boolean
|
238 |
* @throws \Exception
|
239 |
*/
|
240 |
+
private function getWpAdminFiles()
|
241 |
+
{
|
242 |
|
243 |
// Skip it
|
244 |
+
if ($this->isDirectoryExcluded(\WPStaging\WPStaging::getWPpath() . 'wp-admin/')) {
|
245 |
+
$this->log("Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-admin/');
|
246 |
return true;
|
247 |
}
|
248 |
|
249 |
// open file handle and attach data to end of file
|
250 |
+
$files = $this->open($this->filename, 'a');
|
251 |
|
252 |
try {
|
253 |
|
254 |
// Iterate over wp-admin directory
|
255 |
+
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator(\WPStaging\WPStaging::getWPpath() . 'wp-admin/');
|
256 |
|
257 |
// Recursively iterate over content directory
|
258 |
+
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::LEAVES_ONLY, \RecursiveIteratorIterator::CATCH_GET_CHILD);
|
259 |
|
260 |
+
$this->log("Scanning /wp-admin for its sub-directories and files");
|
261 |
|
262 |
// Write path line
|
263 |
+
foreach ($iterator as $item) {
|
264 |
+
if ($item->isFile()) {
|
265 |
+
if ($this->write($files, 'wp-admin/' . $iterator->getSubPathName() . PHP_EOL)) {
|
266 |
$this->options->totalFiles++;
|
267 |
// Too much cpu time
|
268 |
//$this->options->totalFileSize += $iterator->getSize();
|
269 |
}
|
270 |
}
|
271 |
}
|
272 |
+
} catch (\Exception $e) {
|
273 |
+
$this->returnException('Error: ' . $e->getMessage());
|
274 |
}
|
275 |
|
276 |
// close the file handler
|
277 |
+
$this->close($files);
|
278 |
return true;
|
279 |
}
|
280 |
|
282 |
* Step 4
|
283 |
* Get WP Content Uploads Files multisite folder wp-content/uploads/sites or wp-content/blogs.dir/ID/files
|
284 |
*/
|
285 |
+
private function getWpContentUploadsSites()
|
286 |
+
{
|
287 |
|
288 |
// Skip if main site is cloned
|
289 |
+
if (is_main_site()) {
|
290 |
return true;
|
291 |
}
|
292 |
|
297 |
$path = $this->getAbsUploadPath();
|
298 |
|
299 |
// Skip it
|
300 |
+
if (!is_dir($path)) {
|
301 |
+
$this->log("Skipping: {$path} does not exist.");
|
302 |
return true;
|
303 |
}
|
304 |
|
305 |
// Skip it
|
306 |
+
if ($this->isDirectoryExcluded($path)) {
|
307 |
+
$this->log("Skipping: {$path}");
|
308 |
return true;
|
309 |
}
|
310 |
|
311 |
|
312 |
// open file handle
|
313 |
+
$files = $this->open($this->filename, 'a');
|
314 |
|
315 |
/**
|
316 |
* Excluded folders relative to the folder to iterate
|
325 |
* Get user excluded folders
|
326 |
*/
|
327 |
$directory = array();
|
328 |
+
foreach ($this->options->excludedDirectories as $dir) {
|
329 |
+
$path = wpstg_replace_windows_directory_separator($path);
|
330 |
+
$dir = wpstg_replace_windows_directory_separator($dir);
|
331 |
+
if (strpos($dir, $path) !== false) {
|
332 |
+
$directory[] = ltrim(str_replace($path, '', $dir), '/');
|
333 |
}
|
334 |
}
|
335 |
|
336 |
+
$excludePaths = array_merge($excludePaths, $directory);
|
337 |
|
338 |
try {
|
339 |
|
340 |
// Iterate over content directory
|
341 |
+
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator($path);
|
342 |
|
343 |
// Exclude sites, uploads, plugins or themes
|
344 |
+
$iterator = new \WPStaging\Iterators\RecursiveFilterExclude($iterator, $excludePaths);
|
345 |
|
346 |
// Recursively iterate over content directory
|
347 |
+
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::LEAVES_ONLY, \RecursiveIteratorIterator::CATCH_GET_CHILD);
|
348 |
$uploadDir = wpstg_get_upload_dir();
|
349 |
+
$this->log("Scanning {$uploadDir} for its sub-directories and files...");
|
350 |
|
351 |
// Write path line
|
352 |
+
foreach ($iterator as $item) {
|
353 |
+
if ($item->isFile()) {
|
354 |
$file = $this->getRelUploadPath() . $iterator->getSubPathName() . PHP_EOL;
|
355 |
+
if ($this->write($files, $file)) {
|
356 |
$this->options->totalFiles++;
|
357 |
|
358 |
// Add current file size
|
360 |
}
|
361 |
}
|
362 |
}
|
363 |
+
} catch (\Exception $e) {
|
364 |
+
$this->returnException('Error: ' . $e->getMessage());
|
365 |
}
|
366 |
|
367 |
// close the file handler
|
368 |
+
$this->close($files);
|
369 |
return true;
|
370 |
}
|
371 |
|
373 |
* Get absolute path to the upload folder e.g. /srv/www/wp-content/blogs.dir/ID/files or /srv/www/wp-content/uploads/sites/ID/
|
374 |
* @return type
|
375 |
*/
|
376 |
+
private function getAbsUploadPath()
|
377 |
+
{
|
378 |
// Check first which method is used
|
379 |
$uploads = wp_upload_dir();
|
380 |
$basedir = $uploads['basedir'];
|
381 |
|
382 |
+
return trailingslashit($basedir);
|
383 |
}
|
384 |
|
385 |
/**
|
386 |
* Get relative path to the upload folder like wp-content/uploads or wp-content/blogs.dir/2/files
|
387 |
* @return string
|
388 |
*/
|
389 |
+
private function getRelUploadPath()
|
390 |
+
{
|
391 |
$uploads = wp_upload_dir();
|
392 |
$basedir = $uploads['basedir'];
|
393 |
|
394 |
+
return trailingslashit(str_replace(wpstg_replace_windows_directory_separator(\WPStaging\WPStaging::getWPpath()), null, wpstg_replace_windows_directory_separator($basedir)));
|
395 |
}
|
396 |
|
397 |
/**
|
398 |
+
* Step 5 - x
|
399 |
* Get extra folders of the wp root level
|
400 |
* Does not collect wp-includes, wp-admin and wp-content folder
|
401 |
*/
|
402 |
+
private function getExtraFiles($folder)
|
403 |
+
{
|
404 |
|
405 |
+
if (!is_dir($folder)) {
|
406 |
return true;
|
407 |
}
|
408 |
|
409 |
// open file handle and attach data to end of file
|
410 |
+
$files = $this->open($this->filename, 'a');
|
411 |
|
412 |
try {
|
413 |
|
414 |
// Iterate over extra directory
|
415 |
+
$iterator = new \WPStaging\Iterators\RecursiveDirectoryIterator($folder);
|
416 |
|
417 |
$exclude = array();
|
418 |
|
419 |
+
$iterator = new \WPStaging\Iterators\RecursiveFilterExclude($iterator, $exclude);
|
420 |
// Recursively iterate over content directory
|
421 |
+
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::LEAVES_ONLY, \RecursiveIteratorIterator::CATCH_GET_CHILD);
|
422 |
|
423 |
$strings = new Strings();
|
424 |
+
$this->log("Scanning {$strings->getLastElemAfterString( '/', $folder )} for its sub-directories and files");
|
425 |
|
426 |
// Write path line
|
427 |
+
foreach ($iterator as $item) {
|
428 |
+
if ($item->isFile()) {
|
429 |
+
$path = str_replace(wpstg_replace_windows_directory_separator(\WPStaging\WPStaging::getWPpath()), '', wpstg_replace_windows_directory_separator($folder)) . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL;
|
430 |
+
if ($this->write($files, $path)) {
|
431 |
$this->options->totalFiles++;
|
432 |
// Add current file size
|
433 |
$this->options->totalFileSize += $iterator->getSize();
|
434 |
}
|
435 |
}
|
436 |
}
|
437 |
+
} catch (\Exception $e) {
|
438 |
+
$this->returnException('Error: ' . $e->getMessage());
|
439 |
}
|
440 |
|
441 |
// close the file handler
|
442 |
+
$this->close($files);
|
443 |
return true;
|
444 |
}
|
445 |
|
446 |
/**
|
447 |
* Closes a file handle
|
448 |
*
|
449 |
+
* @param resource $handle File handle to close
|
450 |
* @return boolean
|
451 |
*/
|
452 |
+
public function close($handle)
|
453 |
+
{
|
454 |
+
return @fclose($handle);
|
455 |
}
|
456 |
|
457 |
/**
|
458 |
* Opens a file in specified mode
|
459 |
*
|
460 |
+
* @param string $file Path to the file to open
|
461 |
+
* @param string $mode Mode in which to open the file
|
462 |
* @return resource
|
463 |
* @throws Exception
|
464 |
*/
|
465 |
+
public function open($file, $mode)
|
466 |
+
{
|
467 |
|
468 |
+
$file_handle = @fopen($file, $mode);
|
469 |
+
if (false === $file_handle) {
|
470 |
+
$this->returnException(sprintf(__('Unable to open %s with mode %s', 'wp-staging'), $file, $mode));
|
471 |
}
|
472 |
|
473 |
return $file_handle;
|
476 |
/**
|
477 |
* Write contents to a file
|
478 |
*
|
479 |
+
* @param resource $handle File handle to write to
|
480 |
+
* @param string $content Contents to write to the file
|
481 |
* @return integer
|
482 |
* @throws Exception
|
483 |
* @throws Exception
|
484 |
*/
|
485 |
+
public function write($handle, $content)
|
486 |
+
{
|
487 |
+
$write_result = @fwrite($handle, $content);
|
488 |
+
if (false === $write_result) {
|
489 |
+
if (($meta = \stream_get_meta_data($handle))) {
|
490 |
+
throw new \Exception(sprintf(__('Unable to write to: %s', 'wp-staging'), $meta['uri']));
|
491 |
}
|
492 |
+
} elseif (strlen($content) !== $write_result) {
|
493 |
+
throw new \Exception(__('Out of disk space.', 'wp-staging'));
|
494 |
}
|
495 |
|
496 |
return $write_result;
|
501 |
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
502 |
* @return bool
|
503 |
*/
|
504 |
+
protected function execute()
|
505 |
+
{
|
506 |
|
507 |
// No job left to execute
|
508 |
+
if ($this->isFinished()) {
|
509 |
+
$this->prepareResponse(true, false);
|
510 |
return false;
|
511 |
}
|
512 |
|
513 |
|
514 |
+
if ($this->options->currentStep == 0) {
|
515 |
$this->getWpRootFiles();
|
516 |
+
$this->prepareResponse(false, true);
|
517 |
return false;
|
518 |
}
|
519 |
|
520 |
+
if ($this->options->currentStep == 1) {
|
521 |
$this->getWpContentFiles();
|
522 |
+
$this->prepareResponse(false, true);
|
523 |
return false;
|
524 |
}
|
525 |
|
526 |
+
if ($this->options->currentStep == 2) {
|
527 |
$this->getWpIncludesFiles();
|
528 |
+
$this->prepareResponse(false, true);
|
529 |
return false;
|
530 |
}
|
531 |
|
532 |
+
if ($this->options->currentStep == 3) {
|
533 |
$this->getWpAdminFiles();
|
534 |
+
$this->prepareResponse(false, true);
|
535 |
return false;
|
536 |
}
|
537 |
|
538 |
+
if ($this->options->currentStep == 4) {
|
539 |
$this->getWpContentUploadsSites();
|
540 |
+
$this->prepareResponse(false, true);
|
541 |
return false;
|
542 |
}
|
543 |
|
544 |
+
if (isset($this->options->extraDirectories[$this->options->currentStep - $this->total])) {
|
545 |
+
$this->getExtraFiles($this->options->extraDirectories[$this->options->currentStep - $this->total]);
|
546 |
+
$this->prepareResponse(false, true);
|
547 |
return false;
|
548 |
}
|
549 |
|
550 |
|
551 |
// Prepare response
|
552 |
+
$this->prepareResponse(false, true);
|
553 |
// Not finished
|
554 |
return true;
|
555 |
}
|
558 |
* Checks Whether There is Any Job to Execute or Not
|
559 |
* @return bool
|
560 |
*/
|
561 |
+
protected function isFinished()
|
562 |
+
{
|
563 |
+
if ($this->options->currentStep >= $this->options->totalSteps) {
|
564 |
return true;
|
565 |
}
|
566 |
}
|
569 |
* Save files
|
570 |
* @return bool
|
571 |
*/
|
572 |
+
protected function saveProgress()
|
573 |
+
{
|
574 |
return $this->saveOptions();
|
575 |
}
|
576 |
|
578 |
* Get files
|
579 |
* @return void
|
580 |
*/
|
581 |
+
protected function getFiles()
|
582 |
+
{
|
583 |
$fileName = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
584 |
|
585 |
+
if (false === ($this->files = @file_get_contents($fileName))) {
|
586 |
$this->files = array();
|
587 |
return;
|
588 |
}
|
589 |
|
590 |
+
$this->files = explode(PHP_EOL, $this->files);
|
591 |
}
|
592 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
593 |
|
594 |
/**
|
595 |
* Check if directory is excluded
|
596 |
* @param string $directory
|
597 |
* @return bool
|
598 |
*/
|
599 |
+
protected function isDirectoryExcluded($directory)
|
600 |
+
{
|
601 |
+
$directory = wpstg_replace_windows_directory_separator($directory);
|
602 |
+
foreach ($this->options->excludedDirectories as $excludedDirectory) {
|
603 |
+
if (empty($excludedDirectory)) {
|
604 |
+
continue;
|
605 |
+
}
|
606 |
+
$excludedDirectory = wpstg_replace_windows_directory_separator($excludedDirectory);
|
607 |
+
if (strpos(trailingslashit($directory), trailingslashit($excludedDirectory)) === 0) {
|
608 |
return true;
|
609 |
}
|
610 |
}
|
Backend/Modules/Jobs/Multisite/Files.php
CHANGED
@@ -3,13 +3,9 @@
|
|
3 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
4 |
|
5 |
use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
6 |
-
|
7 |
use WPStaging\Utils\Logger;
|
8 |
|
9 |
-
if (!defined("WPINC")) {
|
10 |
-
die;
|
11 |
-
}
|
12 |
-
|
13 |
/**
|
14 |
* Class Files
|
15 |
* @package WPStaging\Backend\Modules\Jobs
|
@@ -31,6 +27,11 @@ class Files extends JobExecutable
|
|
31 |
*/
|
32 |
private $destination;
|
33 |
|
|
|
|
|
|
|
|
|
|
|
34 |
/**
|
35 |
* Initialization
|
36 |
*/
|
@@ -167,8 +168,7 @@ class Files extends JobExecutable
|
|
167 |
|
168 |
// Directory is excluded
|
169 |
if ($this->isDirectoryExcluded($directory)) {
|
170 |
-
$this->debugLog("Skipping directory by rule: {$file}",
|
171 |
-
Logger::TYPE_INFO);
|
172 |
return false;
|
173 |
}
|
174 |
|
@@ -264,8 +264,7 @@ class Files extends JobExecutable
|
|
264 |
$destinationPath = $this->destination.$relativePath;
|
265 |
$destinationDirectory = dirname($destinationPath);
|
266 |
|
267 |
-
if (!is_dir($destinationDirectory) && !@mkdir($destinationDirectory,
|
268 |
-
wpstg_get_permissions_for_directory(), true)) {
|
269 |
$this->log("Files: Can not create directory {$destinationDirectory}",
|
270 |
Logger::TYPE_ERROR);
|
271 |
return false;
|
@@ -338,7 +337,7 @@ class Files extends JobExecutable
|
|
338 |
/**
|
339 |
* Check if certain file is excluded from copying process
|
340 |
*
|
341 |
-
* @param string $file
|
342 |
* @return boolean
|
343 |
*/
|
344 |
private function isFileExcluded($file)
|
@@ -346,27 +345,16 @@ class Files extends JobExecutable
|
|
346 |
|
347 |
$excludedFiles = (array) $this->options->excludedFiles;
|
348 |
|
349 |
-
$basenameFile = basename($file);
|
350 |
-
|
351 |
// Remove .htaccess and web.config from 'excludedFiles' if staging site is copied to a subdomain
|
352 |
if (false === $this->isIdenticalHostname()) {
|
353 |
$excludedFiles = \array_diff($excludedFiles,
|
354 |
array("web.config", ".htaccess"));
|
355 |
}
|
356 |
|
357 |
-
|
358 |
-
// Check for file name
|
359 |
-
if (in_array($basenameFile, $excludedFiles)) {
|
360 |
return true;
|
361 |
}
|
362 |
|
363 |
-
// Check for wildcard patterns like *.log or *-log*
|
364 |
-
foreach ($excludedFiles as $pattern) {
|
365 |
-
if (wpstg_fnmatch($pattern, $basenameFile)) {
|
366 |
-
return true;
|
367 |
-
}
|
368 |
-
}
|
369 |
-
|
370 |
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
371 |
// because if the updating process fails, the staging site would not be accessable any longer
|
372 |
if (isset($this->options->mainJob) && $this->options->mainJob == "updating"
|
@@ -374,7 +362,6 @@ class Files extends JobExecutable
|
|
374 |
return true;
|
375 |
}
|
376 |
|
377 |
-
|
378 |
return false;
|
379 |
}
|
380 |
|
@@ -440,8 +427,7 @@ class Files extends JobExecutable
|
|
440 |
private function isDirectoryExcluded($directory)
|
441 |
{
|
442 |
// Make sure that wp-staging-pro directory / plugin is never excluded
|
443 |
-
if (false !== strpos($directory, 'wp-staging') || false !== strpos($directory,
|
444 |
-
'wp-staging-pro')) {
|
445 |
return false;
|
446 |
}
|
447 |
|
@@ -475,4 +461,4 @@ class Files extends JobExecutable
|
|
475 |
|
476 |
return false;
|
477 |
}
|
478 |
-
}
|
3 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
4 |
|
5 |
use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
6 |
+
use WPStaging\Manager\FileSystem\FileManager;
|
7 |
use WPStaging\Utils\Logger;
|
8 |
|
|
|
|
|
|
|
|
|
9 |
/**
|
10 |
* Class Files
|
11 |
* @package WPStaging\Backend\Modules\Jobs
|
27 |
*/
|
28 |
private $destination;
|
29 |
|
30 |
+
/**
|
31 |
+
* @var object
|
32 |
+
*/
|
33 |
+
private $fileSystem;
|
34 |
+
|
35 |
/**
|
36 |
* Initialization
|
37 |
*/
|
168 |
|
169 |
// Directory is excluded
|
170 |
if ($this->isDirectoryExcluded($directory)) {
|
171 |
+
$this->debugLog("Skipping directory by rule: {$file}",Logger::TYPE_INFO);
|
|
|
172 |
return false;
|
173 |
}
|
174 |
|
264 |
$destinationPath = $this->destination.$relativePath;
|
265 |
$destinationDirectory = dirname($destinationPath);
|
266 |
|
267 |
+
if (!is_dir($destinationDirectory) && !@mkdir($destinationDirectory, wpstg_get_permissions_for_directory(), true)) {
|
|
|
268 |
$this->log("Files: Can not create directory {$destinationDirectory}",
|
269 |
Logger::TYPE_ERROR);
|
270 |
return false;
|
337 |
/**
|
338 |
* Check if certain file is excluded from copying process
|
339 |
*
|
340 |
+
* @param string $file full path + filename
|
341 |
* @return boolean
|
342 |
*/
|
343 |
private function isFileExcluded($file)
|
345 |
|
346 |
$excludedFiles = (array) $this->options->excludedFiles;
|
347 |
|
|
|
|
|
348 |
// Remove .htaccess and web.config from 'excludedFiles' if staging site is copied to a subdomain
|
349 |
if (false === $this->isIdenticalHostname()) {
|
350 |
$excludedFiles = \array_diff($excludedFiles,
|
351 |
array("web.config", ".htaccess"));
|
352 |
}
|
353 |
|
354 |
+
if ((new FileManager)->isFilenameExcluded($file, $excludedFiles)) {
|
|
|
|
|
355 |
return true;
|
356 |
}
|
357 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
358 |
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
359 |
// because if the updating process fails, the staging site would not be accessable any longer
|
360 |
if (isset($this->options->mainJob) && $this->options->mainJob == "updating"
|
362 |
return true;
|
363 |
}
|
364 |
|
|
|
365 |
return false;
|
366 |
}
|
367 |
|
427 |
private function isDirectoryExcluded($directory)
|
428 |
{
|
429 |
// Make sure that wp-staging-pro directory / plugin is never excluded
|
430 |
+
if (false !== strpos($directory, 'wp-staging') || false !== strpos($directory,'wp-staging-pro')) {
|
|
|
431 |
return false;
|
432 |
}
|
433 |
|
461 |
|
462 |
return false;
|
463 |
}
|
464 |
+
}
|
Backend/Modules/Jobs/Multisite/SearchReplace.php
CHANGED
@@ -204,16 +204,22 @@ class SearchReplace extends JobExecutable
|
|
204 |
}
|
205 |
|
206 |
/**
|
207 |
-
* Get destination
|
208 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
* @return string
|
210 |
*/
|
211 |
private function getDestinationHostname()
|
212 |
{
|
213 |
|
214 |
-
//
|
215 |
if ($this->options->mainJob === 'updating') {
|
216 |
-
//
|
217 |
if (!empty($this->options->cloneHostname)) {
|
218 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
219 |
} else {
|
@@ -221,17 +227,17 @@ class SearchReplace extends JobExecutable
|
|
221 |
}
|
222 |
}
|
223 |
|
224 |
-
//
|
225 |
if (!empty($this->options->cloneHostname)) {
|
226 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
227 |
}
|
228 |
|
229 |
-
// WP installed in sub directory under root
|
230 |
if ($this->isSubDir()) {
|
231 |
return trailingslashit($this->strings->getUrlWithoutScheme(get_home_url())) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName;
|
232 |
}
|
233 |
|
234 |
-
//
|
235 |
$multisitePath = defined('PATH_CURRENT_SITE') ? PATH_CURRENT_SITE : '/';
|
236 |
return rtrim($this->strings->getUrlWithoutScheme(get_home_url()), '/\\') . $multisitePath . $this->options->cloneDirectoryName;
|
237 |
}
|
204 |
}
|
205 |
|
206 |
/**
|
207 |
+
* Get destination hostname without scheme e.g example.com/staging or staging.example.com
|
208 |
+
*
|
209 |
+
* Conditions:
|
210 |
+
* - Main job is 'update'
|
211 |
+
* - WP installed in sub dir
|
212 |
+
* - Target hostname in advanced settings defined (Pro version only)
|
213 |
+
*
|
214 |
+
* @todo Complex conditions. Might need refactor
|
215 |
* @return string
|
216 |
*/
|
217 |
private function getDestinationHostname()
|
218 |
{
|
219 |
|
220 |
+
// Update process: Neither 'push' nor 'clone'
|
221 |
if ($this->options->mainJob === 'updating') {
|
222 |
+
// Defined and created in advanced settings with pro version
|
223 |
if (!empty($this->options->cloneHostname)) {
|
224 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
225 |
} else {
|
227 |
}
|
228 |
}
|
229 |
|
230 |
+
// Clone process: Defined and created in advanced settings with pro version
|
231 |
if (!empty($this->options->cloneHostname)) {
|
232 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
233 |
}
|
234 |
|
235 |
+
// Clone process: WP installed in sub directory under root
|
236 |
if ($this->isSubDir()) {
|
237 |
return trailingslashit($this->strings->getUrlWithoutScheme(get_home_url())) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName;
|
238 |
}
|
239 |
|
240 |
+
// Clone process: DefaultPath to root of main multisite without leading or trailing slash e.g.: wordpress
|
241 |
$multisitePath = defined('PATH_CURRENT_SITE') ? PATH_CURRENT_SITE : '/';
|
242 |
return rtrim($this->strings->getUrlWithoutScheme(get_home_url()), '/\\') . $multisitePath . $this->options->cloneDirectoryName;
|
243 |
}
|
Backend/Modules/Jobs/Multisite/SearchReplaceExternal.php
CHANGED
@@ -188,16 +188,22 @@ class SearchReplaceExternal extends JobExecutable
|
|
188 |
}
|
189 |
|
190 |
/**
|
191 |
-
* Get destination
|
192 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
* @return string
|
194 |
*/
|
195 |
private function getDestinationHostname()
|
196 |
{
|
197 |
|
198 |
-
//
|
199 |
if ($this->options->mainJob === 'updating') {
|
200 |
-
//
|
201 |
if (!empty($this->options->cloneHostname)) {
|
202 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
203 |
} else {
|
@@ -205,22 +211,21 @@ class SearchReplaceExternal extends JobExecutable
|
|
205 |
}
|
206 |
}
|
207 |
|
208 |
-
//
|
209 |
if (!empty($this->options->cloneHostname)) {
|
210 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
211 |
}
|
212 |
|
213 |
-
// WP installed in sub directory under root
|
214 |
if ($this->isSubDir()) {
|
215 |
return trailingslashit($this->strings->getUrlWithoutScheme(get_home_url())) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName;
|
216 |
}
|
217 |
|
218 |
-
//
|
219 |
$multisitePath = defined('PATH_CURRENT_SITE') ? PATH_CURRENT_SITE : '/';
|
220 |
return rtrim($this->strings->getUrlWithoutScheme($this->multisiteDomainWithoutScheme), '/\\') . $multisitePath . $this->options->cloneDirectoryName;
|
221 |
}
|
222 |
|
223 |
-
|
224 |
/**
|
225 |
* Get the install sub directory if WP is installed in sub directory
|
226 |
* @return string
|
188 |
}
|
189 |
|
190 |
/**
|
191 |
+
* Get destination hostname without scheme e.g example.com/staging or staging.example.com
|
192 |
+
*
|
193 |
+
* Conditions:
|
194 |
+
* - Main job is 'update'
|
195 |
+
* - WP installed in sub dir
|
196 |
+
* - Target hostname in advanced settings defined (Pro version only)
|
197 |
+
*
|
198 |
+
* @todo Complex conditions. Might need refactor
|
199 |
* @return string
|
200 |
*/
|
201 |
private function getDestinationHostname()
|
202 |
{
|
203 |
|
204 |
+
// Update process: Neither 'push' nor 'clone'
|
205 |
if ($this->options->mainJob === 'updating') {
|
206 |
+
// Defined and created in advanced settings with pro version
|
207 |
if (!empty($this->options->cloneHostname)) {
|
208 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
209 |
} else {
|
211 |
}
|
212 |
}
|
213 |
|
214 |
+
// Clone process: Defined and created in advanced settings with pro version
|
215 |
if (!empty($this->options->cloneHostname)) {
|
216 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
217 |
}
|
218 |
|
219 |
+
// Clone process: WP installed in sub directory under root
|
220 |
if ($this->isSubDir()) {
|
221 |
return trailingslashit($this->strings->getUrlWithoutScheme(get_home_url())) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName;
|
222 |
}
|
223 |
|
224 |
+
// Clone process: DefaultPath to root of main multisite without leading or trailing slash e.g.: wordpress
|
225 |
$multisitePath = defined('PATH_CURRENT_SITE') ? PATH_CURRENT_SITE : '/';
|
226 |
return rtrim($this->strings->getUrlWithoutScheme($this->multisiteDomainWithoutScheme), '/\\') . $multisitePath . $this->options->cloneDirectoryName;
|
227 |
}
|
228 |
|
|
|
229 |
/**
|
230 |
* Get the install sub directory if WP is installed in sub directory
|
231 |
* @return string
|
Backend/Modules/Jobs/SearchReplace.php
CHANGED
@@ -175,7 +175,7 @@ class SearchReplace extends JobExecutable
|
|
175 |
|
176 |
/**
|
177 |
* Get source Hostname depending on wheather WP has been installed in sub dir or not
|
178 |
-
* @return
|
179 |
*/
|
180 |
private function getSourceHostname()
|
181 |
{
|
@@ -189,15 +189,21 @@ class SearchReplace extends JobExecutable
|
|
189 |
}
|
190 |
|
191 |
/**
|
192 |
-
* Get destination
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
* @return string
|
194 |
*/
|
195 |
private function getDestinationHostname()
|
196 |
{
|
197 |
-
|
198 |
-
// Staging site is updated so do not change hostname
|
199 |
if ($this->options->mainJob === 'updating') {
|
200 |
-
//
|
201 |
if (!empty($this->options->cloneHostname)) {
|
202 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
203 |
} else {
|
@@ -205,17 +211,17 @@ class SearchReplace extends JobExecutable
|
|
205 |
}
|
206 |
}
|
207 |
|
208 |
-
//
|
209 |
if (!empty($this->options->cloneHostname)) {
|
210 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
211 |
}
|
212 |
|
213 |
-
// WP installed in sub directory under root
|
214 |
if ($this->isSubDir()) {
|
215 |
return $this->strings->getUrlWithoutScheme(trailingslashit($this->options->destinationHostname) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName);
|
216 |
}
|
217 |
|
218 |
-
//
|
219 |
return $this->strings->getUrlWithoutScheme(trailingslashit($this->options->destinationHostname) . $this->options->cloneDirectoryName);
|
220 |
}
|
221 |
|
175 |
|
176 |
/**
|
177 |
* Get source Hostname depending on wheather WP has been installed in sub dir or not
|
178 |
+
* @return string
|
179 |
*/
|
180 |
private function getSourceHostname()
|
181 |
{
|
189 |
}
|
190 |
|
191 |
/**
|
192 |
+
* Get destination hostname without scheme e.g example.com/staging or staging.example.com
|
193 |
+
*
|
194 |
+
* Conditions:
|
195 |
+
* - Main job is 'update'
|
196 |
+
* - WP installed in sub dir
|
197 |
+
* - Target hostname in advanced settings defined (Pro version only)
|
198 |
+
*
|
199 |
+
* @todo Complex conditions. Might need refactor
|
200 |
* @return string
|
201 |
*/
|
202 |
private function getDestinationHostname()
|
203 |
{
|
204 |
+
// Update process: Neither 'push' nor 'clone'
|
|
|
205 |
if ($this->options->mainJob === 'updating') {
|
206 |
+
// Defined and created in advanced settings with pro version
|
207 |
if (!empty($this->options->cloneHostname)) {
|
208 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
209 |
} else {
|
211 |
}
|
212 |
}
|
213 |
|
214 |
+
// Clone process: Defined and created in advanced settings with pro version
|
215 |
if (!empty($this->options->cloneHostname)) {
|
216 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
217 |
}
|
218 |
|
219 |
+
// Clone process: WP installed in sub directory under root
|
220 |
if ($this->isSubDir()) {
|
221 |
return $this->strings->getUrlWithoutScheme(trailingslashit($this->options->destinationHostname) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName);
|
222 |
}
|
223 |
|
224 |
+
// Clone process: Default
|
225 |
return $this->strings->getUrlWithoutScheme(trailingslashit($this->options->destinationHostname) . $this->options->cloneDirectoryName);
|
226 |
}
|
227 |
|
Backend/Modules/Jobs/SearchReplaceExternal.php
CHANGED
@@ -192,16 +192,21 @@ class SearchReplaceExternal extends JobExecutable
|
|
192 |
}
|
193 |
|
194 |
/**
|
195 |
-
* Get destination
|
196 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
* @return string
|
198 |
*/
|
199 |
private function getDestinationHostname()
|
200 |
{
|
201 |
-
|
202 |
-
// Staging site is updated so do not change hostname
|
203 |
if ($this->options->mainJob === 'updating') {
|
204 |
-
//
|
205 |
if (!empty($this->options->cloneHostname)) {
|
206 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
207 |
} else {
|
@@ -209,21 +214,20 @@ class SearchReplaceExternal extends JobExecutable
|
|
209 |
}
|
210 |
}
|
211 |
|
212 |
-
//
|
213 |
if (!empty($this->options->cloneHostname)) {
|
214 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
215 |
}
|
216 |
|
217 |
-
// WP installed in sub directory under root
|
218 |
if ($this->isSubDir()) {
|
219 |
return $this->strings->getUrlWithoutScheme(trailingslashit($this->options->destinationHostname) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName);
|
220 |
}
|
221 |
|
222 |
-
//
|
223 |
return $this->strings->getUrlWithoutScheme(trailingslashit($this->options->destinationHostname) . $this->options->cloneDirectoryName);
|
224 |
}
|
225 |
|
226 |
-
|
227 |
/**
|
228 |
* Get the install sub directory if WP is installed in sub directory
|
229 |
* @return string
|
192 |
}
|
193 |
|
194 |
/**
|
195 |
+
* Get destination hostname without scheme e.g example.com/staging or staging.example.com
|
196 |
+
*
|
197 |
+
* Conditions:
|
198 |
+
* - Main job is 'update'
|
199 |
+
* - WP installed in sub dir
|
200 |
+
* - Target hostname in advanced settings defined (Pro version only)
|
201 |
+
*
|
202 |
+
* @todo Complex conditions. Might need refactor
|
203 |
* @return string
|
204 |
*/
|
205 |
private function getDestinationHostname()
|
206 |
{
|
207 |
+
// Update process: Neither 'push' nor 'clone'
|
|
|
208 |
if ($this->options->mainJob === 'updating') {
|
209 |
+
// Defined and created in advanced settings with pro version
|
210 |
if (!empty($this->options->cloneHostname)) {
|
211 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
212 |
} else {
|
214 |
}
|
215 |
}
|
216 |
|
217 |
+
// Clone process: Defined and created in advanced settings with pro version
|
218 |
if (!empty($this->options->cloneHostname)) {
|
219 |
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
220 |
}
|
221 |
|
222 |
+
// Clone process: WP installed in sub directory under root
|
223 |
if ($this->isSubDir()) {
|
224 |
return $this->strings->getUrlWithoutScheme(trailingslashit($this->options->destinationHostname) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName);
|
225 |
}
|
226 |
|
227 |
+
// Clone process: Default
|
228 |
return $this->strings->getUrlWithoutScheme(trailingslashit($this->options->destinationHostname) . $this->options->cloneDirectoryName);
|
229 |
}
|
230 |
|
|
|
231 |
/**
|
232 |
* Get the install sub directory if WP is installed in sub directory
|
233 |
* @return string
|
Backend/Modules/Jobs/Updating.php
CHANGED
@@ -9,53 +9,56 @@ use WPStaging\Utils\Helper;
|
|
9 |
* Class Cloning
|
10 |
* @package WPStaging\Backend\Modules\Jobs
|
11 |
*/
|
12 |
-
class Updating extends Job
|
|
|
13 |
|
14 |
/**
|
15 |
* External Database Used
|
16 |
-
* @var bool
|
17 |
*/
|
18 |
public $isExternal;
|
19 |
|
20 |
/**
|
21 |
* Initialize is called in \Job
|
22 |
*/
|
23 |
-
public function initialize()
|
24 |
-
|
|
|
25 |
}
|
26 |
|
27 |
/**
|
28 |
* Save Chosen Cloning Settings
|
29 |
* @return bool
|
30 |
*/
|
31 |
-
public function save()
|
32 |
-
|
|
|
33 |
return false;
|
34 |
}
|
35 |
|
36 |
// Delete files to copy listing
|
37 |
-
$this->cache->delete(
|
38 |
|
39 |
// Generate Options
|
40 |
// Clone
|
41 |
//$this->options->clone = $_POST["cloneID"];
|
42 |
-
$this->options->clone
|
43 |
-
$this->options->cloneDirectoryName
|
44 |
-
$this->options->cloneNumber
|
45 |
-
$this->options->includedDirectories
|
46 |
-
$this->options->excludedDirectories
|
47 |
-
$this->options->extraDirectories
|
48 |
-
$this->options->excludedFiles
|
49 |
'.htaccess',
|
50 |
'.DS_Store',
|
51 |
-
'
|
52 |
-
'
|
53 |
-
'
|
54 |
'desktop.ini',
|
55 |
'.gitignore',
|
56 |
-
'
|
57 |
'object-cache.php',
|
58 |
-
'web.config' // Important: Windows IIS
|
59 |
|
60 |
);
|
61 |
|
@@ -72,32 +75,32 @@ class Updating extends Job {
|
|
72 |
$this->options->job = new \stdClass();
|
73 |
|
74 |
// Check if clone data already exists and use that one
|
75 |
-
if(
|
76 |
-
$this->options->cloneNumber
|
77 |
-
$this->options->databaseUser
|
78 |
-
$this->options->databasePassword
|
79 |
-
$this->options->databaseDatabase
|
80 |
-
$this->options->databaseServer
|
81 |
-
$this->options->databasePrefix
|
82 |
$this->options->destinationHostname = $this->options->existingClones[$this->options->clone]['url'];
|
83 |
-
$this->options->prefix
|
84 |
-
$helper
|
85 |
-
$this->options->homeHostname
|
86 |
} else {
|
87 |
-
wp_die(
|
88 |
}
|
89 |
|
90 |
-
$this->isExternal = (empty(
|
91 |
|
92 |
// Included Tables
|
93 |
-
if(
|
94 |
$this->options->tables = $_POST["includedTables"];
|
95 |
} else {
|
96 |
$this->options->tables = array();
|
97 |
}
|
98 |
|
99 |
// Excluded Directories
|
100 |
-
if(
|
101 |
$this->options->excludedDirectories = wpstg_urldecode($_POST["excludedDirectories"]);
|
102 |
}
|
103 |
|
@@ -110,36 +113,36 @@ class Updating extends Job {
|
|
110 |
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'peters-login-redirect',
|
111 |
);
|
112 |
|
113 |
-
$this->options->excludedDirectories = array_merge(
|
114 |
|
115 |
// Included Directories
|
116 |
-
if(
|
117 |
$this->options->includedDirectories = wpstg_urldecode($_POST["includedDirectories"]);
|
118 |
}
|
119 |
|
120 |
// Extra Directories
|
121 |
-
if(
|
122 |
$this->options->extraDirectories = wpstg_urldecode($_POST["extraDirectories"]);
|
123 |
}
|
124 |
|
125 |
$this->options->cloneDir = '';
|
126 |
-
if(
|
127 |
-
$this->options->cloneDir = wpstg_urldecode(trailingslashit(
|
128 |
}
|
129 |
|
130 |
$this->options->destinationDir = $this->getDestinationDir();
|
131 |
|
132 |
$this->options->cloneHostname = '';
|
133 |
-
if(
|
134 |
$this->options->cloneHostname = $_POST["cloneHostname"];
|
135 |
}
|
136 |
|
137 |
// Directories to Copy
|
138 |
$this->options->directoriesToCopy = array_merge(
|
139 |
-
|
140 |
);
|
141 |
|
142 |
-
array_unshift(
|
143 |
|
144 |
// Process lock state
|
145 |
$this->options->isRunning = true;
|
@@ -151,45 +154,47 @@ class Updating extends Job {
|
|
151 |
* Get Destination Directory including staging subdirectory
|
152 |
* @return type
|
153 |
*/
|
154 |
-
private function getDestinationDir()
|
155 |
-
|
156 |
-
|
|
|
157 |
}
|
158 |
//return trailingslashit( $this->options->cloneDir . $this->options->cloneDirectoryName );
|
159 |
-
return trailingslashit(
|
160 |
}
|
161 |
|
162 |
/**
|
163 |
* Check and return prefix of the staging site
|
164 |
*/
|
165 |
-
public function getStagingPrefix()
|
|
|
166 |
// prefix not defined! Happens if staging site has ben generated with older version of wpstg
|
167 |
// Try to get staging prefix from wp-config.php of staging site
|
168 |
$this->options->prefix = $this->options->existingClones[$this->options->clone]['prefix'];
|
169 |
-
if(
|
170 |
// Throw error if wp-config.php is not readable
|
171 |
-
$path
|
172 |
-
if(
|
173 |
-
$this->log(
|
174 |
-
$this->returnException(
|
175 |
-
wp_die(
|
176 |
} else {
|
177 |
// Get prefix from wp-config.php
|
178 |
-
preg_match(
|
179 |
|
180 |
-
if(
|
181 |
$this->options->prefix = $matches[1];
|
182 |
} else {
|
183 |
-
$this->returnException(
|
184 |
-
wp_die(
|
185 |
}
|
186 |
}
|
187 |
}
|
188 |
|
189 |
// Die() if staging prefix is the same as the live prefix
|
190 |
-
if(
|
191 |
-
$this->log(
|
192 |
-
wp_die(
|
193 |
}
|
194 |
|
195 |
// Else
|
@@ -200,7 +205,8 @@ class Updating extends Job {
|
|
200 |
* Start the cloning job
|
201 |
* not used but is abstract
|
202 |
*/
|
203 |
-
public function start()
|
|
|
204 |
}
|
205 |
|
206 |
}
|
9 |
* Class Cloning
|
10 |
* @package WPStaging\Backend\Modules\Jobs
|
11 |
*/
|
12 |
+
class Updating extends Job
|
13 |
+
{
|
14 |
|
15 |
/**
|
16 |
* External Database Used
|
17 |
+
* @var bool
|
18 |
*/
|
19 |
public $isExternal;
|
20 |
|
21 |
/**
|
22 |
* Initialize is called in \Job
|
23 |
*/
|
24 |
+
public function initialize()
|
25 |
+
{
|
26 |
+
$this->db = WPStaging::getInstance()->get("wpdb");
|
27 |
}
|
28 |
|
29 |
/**
|
30 |
* Save Chosen Cloning Settings
|
31 |
* @return bool
|
32 |
*/
|
33 |
+
public function save()
|
34 |
+
{
|
35 |
+
if (!isset($_POST) || !isset($_POST["cloneID"])) {
|
36 |
return false;
|
37 |
}
|
38 |
|
39 |
// Delete files to copy listing
|
40 |
+
$this->cache->delete("files_to_copy");
|
41 |
|
42 |
// Generate Options
|
43 |
// Clone
|
44 |
//$this->options->clone = $_POST["cloneID"];
|
45 |
+
$this->options->clone = preg_replace("#\W+#", '-', strtolower($_POST["cloneID"]));
|
46 |
+
$this->options->cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($this->options->clone));
|
47 |
+
$this->options->cloneNumber = 1;
|
48 |
+
$this->options->includedDirectories = array();
|
49 |
+
$this->options->excludedDirectories = array();
|
50 |
+
$this->options->extraDirectories = array();
|
51 |
+
$this->options->excludedFiles = array(
|
52 |
'.htaccess',
|
53 |
'.DS_Store',
|
54 |
+
'*.git',
|
55 |
+
'*.svn',
|
56 |
+
'*.tmp',
|
57 |
'desktop.ini',
|
58 |
'.gitignore',
|
59 |
+
'*.log',
|
60 |
'object-cache.php',
|
61 |
+
'web.config' // Important: Windows IIS configuration file. Do not copy this to the staging site is staging site is placed into subfolder
|
62 |
|
63 |
);
|
64 |
|
75 |
$this->options->job = new \stdClass();
|
76 |
|
77 |
// Check if clone data already exists and use that one
|
78 |
+
if (isset($this->options->existingClones[$this->options->clone])) {
|
79 |
+
$this->options->cloneNumber = $this->options->existingClones[$this->options->clone]['number'];
|
80 |
+
$this->options->databaseUser = $this->options->existingClones[$this->options->clone]['databaseUser'];
|
81 |
+
$this->options->databasePassword = $this->options->existingClones[$this->options->clone]['databasePassword'];
|
82 |
+
$this->options->databaseDatabase = $this->options->existingClones[$this->options->clone]['databaseDatabase'];
|
83 |
+
$this->options->databaseServer = $this->options->existingClones[$this->options->clone]['databaseServer'];
|
84 |
+
$this->options->databasePrefix = $this->options->existingClones[$this->options->clone]['databasePrefix'];
|
85 |
$this->options->destinationHostname = $this->options->existingClones[$this->options->clone]['url'];
|
86 |
+
$this->options->prefix = $this->getStagingPrefix();
|
87 |
+
$helper = new Helper();
|
88 |
+
$this->options->homeHostname = $helper->get_home_url_without_scheme();
|
89 |
} else {
|
90 |
+
wp_die('Fatal Error: Can not update clone because there is no clone data.');
|
91 |
}
|
92 |
|
93 |
+
$this->isExternal = (empty($this->options->databaseUser) && empty($this->options->databasePassword)) ? false : true;
|
94 |
|
95 |
// Included Tables
|
96 |
+
if (isset($_POST["includedTables"]) && is_array($_POST["includedTables"])) {
|
97 |
$this->options->tables = $_POST["includedTables"];
|
98 |
} else {
|
99 |
$this->options->tables = array();
|
100 |
}
|
101 |
|
102 |
// Excluded Directories
|
103 |
+
if (isset($_POST["excludedDirectories"]) && is_array($_POST["excludedDirectories"])) {
|
104 |
$this->options->excludedDirectories = wpstg_urldecode($_POST["excludedDirectories"]);
|
105 |
}
|
106 |
|
113 |
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'peters-login-redirect',
|
114 |
);
|
115 |
|
116 |
+
$this->options->excludedDirectories = array_merge($excludedDirectories, $this->options->excludedDirectories);
|
117 |
|
118 |
// Included Directories
|
119 |
+
if (isset($_POST["includedDirectories"]) && is_array($_POST["includedDirectories"])) {
|
120 |
$this->options->includedDirectories = wpstg_urldecode($_POST["includedDirectories"]);
|
121 |
}
|
122 |
|
123 |
// Extra Directories
|
124 |
+
if (isset($_POST["extraDirectories"]) && !empty($_POST["extraDirectories"])) {
|
125 |
$this->options->extraDirectories = wpstg_urldecode($_POST["extraDirectories"]);
|
126 |
}
|
127 |
|
128 |
$this->options->cloneDir = '';
|
129 |
+
if (isset($_POST["cloneDir"]) && !empty($_POST["cloneDir"])) {
|
130 |
+
$this->options->cloneDir = wpstg_urldecode(trailingslashit($_POST["cloneDir"]));
|
131 |
}
|
132 |
|
133 |
$this->options->destinationDir = $this->getDestinationDir();
|
134 |
|
135 |
$this->options->cloneHostname = '';
|
136 |
+
if (isset($_POST["cloneHostname"]) && !empty($_POST["cloneHostname"])) {
|
137 |
$this->options->cloneHostname = $_POST["cloneHostname"];
|
138 |
}
|
139 |
|
140 |
// Directories to Copy
|
141 |
$this->options->directoriesToCopy = array_merge(
|
142 |
+
$this->options->includedDirectories, $this->options->extraDirectories
|
143 |
);
|
144 |
|
145 |
+
array_unshift($this->options->directoriesToCopy, ABSPATH);
|
146 |
|
147 |
// Process lock state
|
148 |
$this->options->isRunning = true;
|
154 |
* Get Destination Directory including staging subdirectory
|
155 |
* @return type
|
156 |
*/
|
157 |
+
private function getDestinationDir()
|
158 |
+
{
|
159 |
+
if (empty($this->options->cloneDir)) {
|
160 |
+
return trailingslashit(\WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName);
|
161 |
}
|
162 |
//return trailingslashit( $this->options->cloneDir . $this->options->cloneDirectoryName );
|
163 |
+
return trailingslashit($this->options->cloneDir);
|
164 |
}
|
165 |
|
166 |
/**
|
167 |
* Check and return prefix of the staging site
|
168 |
*/
|
169 |
+
public function getStagingPrefix()
|
170 |
+
{
|
171 |
// prefix not defined! Happens if staging site has ben generated with older version of wpstg
|
172 |
// Try to get staging prefix from wp-config.php of staging site
|
173 |
$this->options->prefix = $this->options->existingClones[$this->options->clone]['prefix'];
|
174 |
+
if (empty($this->options->prefix)) {
|
175 |
// Throw error if wp-config.php is not readable
|
176 |
+
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
177 |
+
if (false === ($content = @file_get_contents($path))) {
|
178 |
+
$this->log("Can not open {$path}. Can't read contents", Logger::TYPE_ERROR);
|
179 |
+
$this->returnException("Fatal Error: Can not read {$path} to get correct table prefix. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
|
180 |
+
wp_die("Fatal Error: Can not read {$path} to get correct table prefix. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
|
181 |
} else {
|
182 |
// Get prefix from wp-config.php
|
183 |
+
preg_match("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
|
184 |
|
185 |
+
if (!empty($matches[1])) {
|
186 |
$this->options->prefix = $matches[1];
|
187 |
} else {
|
188 |
+
$this->returnException("Fatal Error: Can not detect prefix from {$path}. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
|
189 |
+
wp_die("Fatal Error: Can not detect prefix from {$path}. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
|
190 |
}
|
191 |
}
|
192 |
}
|
193 |
|
194 |
// Die() if staging prefix is the same as the live prefix
|
195 |
+
if (false === $this->isExternal && $this->db->prefix == $this->options->prefix) {
|
196 |
+
$this->log("Fatal Error: Can not update staging site. Prefix. '{$this->options->prefix}' is used for the live site. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
|
197 |
+
wp_die("Fatal Error: Can not update staging site. Prefix. '{$this->options->prefix}' is used for the live site. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
|
198 |
}
|
199 |
|
200 |
// Else
|
205 |
* Start the cloning job
|
206 |
* not used but is abstract
|
207 |
*/
|
208 |
+
public function start()
|
209 |
+
{
|
210 |
}
|
211 |
|
212 |
}
|
Backend/Modules/SystemInfo.php
CHANGED
@@ -9,7 +9,7 @@ use WPStaging\Utils;
|
|
9 |
use WPStaging\Utils\Multisite;
|
10 |
|
11 |
// No Direct Access
|
12 |
-
if(
|
13 |
die;
|
14 |
}
|
15 |
|
@@ -17,7 +17,8 @@ if( !defined( "WPINC" ) ) {
|
|
17 |
* Class SystemInfo
|
18 |
* @package WPStaging\Backend\Modules
|
19 |
*/
|
20 |
-
class SystemInfo extends InjectionAware
|
|
|
21 |
|
22 |
/**
|
23 |
* @var bool
|
@@ -33,16 +34,18 @@ class SystemInfo extends InjectionAware {
|
|
33 |
/**
|
34 |
* Initialize class
|
35 |
*/
|
36 |
-
public function initialize()
|
|
|
37 |
$this->isMultiSite = is_multisite();
|
38 |
-
$this->helper
|
39 |
}
|
40 |
|
41 |
/**
|
42 |
* Magic method
|
43 |
* @return string
|
44 |
*/
|
45 |
-
public function __toString()
|
|
|
46 |
return $this->get();
|
47 |
}
|
48 |
|
@@ -50,7 +53,8 @@ class SystemInfo extends InjectionAware {
|
|
50 |
* Get System Information as text
|
51 |
* @return string
|
52 |
*/
|
53 |
-
public function get()
|
|
|
54 |
$output = "### Begin System Info ###" . PHP_EOL . PHP_EOL;
|
55 |
|
56 |
$output .= $this->wpstaging();
|
@@ -82,7 +86,8 @@ class SystemInfo extends InjectionAware {
|
|
82 |
* @param string $string
|
83 |
* @return string
|
84 |
*/
|
85 |
-
public function header(
|
|
|
86 |
return PHP_EOL . "-- {$string}" . PHP_EOL . PHP_EOL;
|
87 |
}
|
88 |
|
@@ -92,18 +97,20 @@ class SystemInfo extends InjectionAware {
|
|
92 |
* @param string $value
|
93 |
* @return string
|
94 |
*/
|
95 |
-
public function info(
|
96 |
-
|
|
|
97 |
}
|
98 |
|
99 |
/**
|
100 |
* Theme Information
|
101 |
* @return string
|
102 |
*/
|
103 |
-
public function theme()
|
|
|
104 |
// Versions earlier than 3.4
|
105 |
-
if(
|
106 |
-
$themeData = get_theme_data(
|
107 |
return "{$themeData["Name"]} {$themeData["Version"]}";
|
108 |
}
|
109 |
|
@@ -115,129 +122,134 @@ class SystemInfo extends InjectionAware {
|
|
115 |
* Site Information
|
116 |
* @return string
|
117 |
*/
|
118 |
-
public function site()
|
119 |
-
|
120 |
-
$output
|
121 |
-
$output .= $this->info(
|
122 |
-
$output .= $this->info(
|
123 |
-
$output .= $this->info(
|
124 |
-
$output .= $this->info(
|
125 |
-
|
126 |
-
|
|
|
127 |
}
|
128 |
|
129 |
/**
|
130 |
* Multisite information
|
131 |
* @return string
|
132 |
*/
|
133 |
-
private function getMultisiteInfo()
|
134 |
-
|
|
|
135 |
return '';
|
136 |
}
|
137 |
|
138 |
$multisite = new Multisite();
|
139 |
|
140 |
-
$output = $this->info(
|
141 |
-
$output .= $this->info(
|
142 |
-
$output .= $this->info(
|
143 |
-
$output .= $this->info(
|
144 |
-
$output .= $this->info(
|
145 |
|
146 |
-
return apply_filters(
|
147 |
}
|
148 |
|
149 |
/**
|
150 |
* Wp Staging plugin Information
|
151 |
* @return string
|
152 |
*/
|
153 |
-
public function wpstaging()
|
|
|
154 |
// Get wpstg settings
|
155 |
-
$settings = ( object )
|
156 |
|
157 |
// Clones data < 1.1.6.x
|
158 |
-
$clones
|
159 |
// Clones data version > 2.x
|
160 |
-
$clonesBeta = get_option(
|
161 |
|
162 |
|
163 |
$output = "-- WP Staging Settings" . PHP_EOL . PHP_EOL;
|
164 |
-
$output .= $this->info(
|
165 |
-
$output .= $this->info(
|
166 |
-
$output .= $this->info(
|
167 |
-
$output .= $this->info(
|
168 |
-
$output .= $this->info(
|
169 |
-
$output .= $this->info(
|
170 |
|
171 |
$output .= PHP_EOL . PHP_EOL . "-- Available Sites Version < 1.1.6.x" . PHP_EOL . PHP_EOL;
|
172 |
|
173 |
-
foreach (
|
174 |
-
$output .= $this->info(
|
175 |
}
|
176 |
$output .= PHP_EOL . PHP_EOL . "-- Available Sites Version > 2.0.x" . PHP_EOL . PHP_EOL;
|
177 |
|
178 |
-
foreach (
|
179 |
|
180 |
-
$path = !empty(
|
181 |
|
182 |
-
$output .= $this->info(
|
183 |
-
$output .= $this->info(
|
184 |
-
$output .= $this->info(
|
185 |
-
$output .= $this->info(
|
186 |
-
$output .= $this->info(
|
187 |
-
$output .= $this->info(
|
188 |
-
$output .= $this->info(
|
189 |
-
$output .= $this->info(
|
190 |
}
|
191 |
|
192 |
|
193 |
-
$output .= $this->info(
|
194 |
|
195 |
$output .= '' . PHP_EOL;
|
196 |
|
197 |
|
198 |
//$output .= PHP_EOL . PHP_EOL;
|
199 |
|
200 |
-
$output .= $this->info(
|
201 |
-
$output .= $this->info(
|
202 |
-
$output .= $this->info(
|
203 |
-
$output .= $this->info(
|
204 |
-
$output .= $this->info(
|
205 |
-
$output .= $this->info(
|
206 |
|
207 |
|
208 |
-
return apply_filters(
|
209 |
}
|
210 |
|
211 |
/**
|
212 |
* Browser Information
|
213 |
* @return string
|
214 |
*/
|
215 |
-
public function browser()
|
216 |
-
|
|
|
217 |
$output .= (new Browser);
|
218 |
|
219 |
-
return apply_filters(
|
220 |
}
|
221 |
|
222 |
/**
|
223 |
* Frontpage Information when frontpage is set to "page"
|
224 |
* @return string
|
225 |
*/
|
226 |
-
public function frontPage()
|
227 |
-
|
|
|
228 |
return '';
|
229 |
}
|
230 |
|
231 |
-
$frontPageID = get_option(
|
232 |
-
$blogPageID
|
233 |
|
234 |
// Front Page
|
235 |
-
$pageFront = ($frontPageID != 0) ? get_the_title(
|
236 |
// Blog Page ID
|
237 |
-
$pageBlog
|
238 |
|
239 |
-
$output = $this->info(
|
240 |
-
$output .= $this->info(
|
241 |
|
242 |
return $output;
|
243 |
}
|
@@ -246,43 +258,44 @@ class SystemInfo extends InjectionAware {
|
|
246 |
* Check wp_remote_post() functionality
|
247 |
* @return string
|
248 |
*/
|
249 |
-
public function wpRemotePost()
|
|
|
250 |
// Make sure wp_remote_post() is working
|
251 |
$wpRemotePost = "wp_remote_post() does not work";
|
252 |
|
253 |
// Send request
|
254 |
$response = wp_remote_post(
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
);
|
262 |
|
263 |
// Validate it worked
|
264 |
-
if(
|
265 |
$wpRemotePost = "wp_remote_post() works";
|
266 |
}
|
267 |
|
268 |
-
return $this->info(
|
269 |
}
|
270 |
|
271 |
/**
|
272 |
* WordPress Configuration
|
273 |
* @return string
|
274 |
*/
|
275 |
-
public function wp()
|
276 |
-
|
277 |
-
$output
|
278 |
-
$output .= $this->info(
|
|
|
279 |
|
280 |
-
$permalinkStructure = get_option(
|
281 |
-
;
|
282 |
-
$output .= $this->info( "Permalink Structure:", ($permalinkStructure) ? $permalinkStructure : "Default" );
|
283 |
|
284 |
-
$output .= $this->info(
|
285 |
-
$output .= $this->info(
|
286 |
|
287 |
// Frontpage information
|
288 |
$output .= $this->frontPage();
|
@@ -291,29 +304,29 @@ class SystemInfo extends InjectionAware {
|
|
291 |
$output .= $this->wpRemotePost();
|
292 |
|
293 |
// Table Prefix
|
294 |
-
$wpDB
|
295 |
$tablePrefix = "DB Prefix: " . $wpDB->prefix . ' ';
|
296 |
-
$tablePrefix .= "Length: " . strlen(
|
297 |
-
$tablePrefix .= (strlen(
|
298 |
|
299 |
-
$output .= $this->info(
|
300 |
|
301 |
// Constants
|
302 |
-
$output .= $this->info(
|
303 |
-
$output .= $this->info(
|
304 |
-
if(
|
305 |
-
$output .= $this->info(
|
306 |
$uploads = wp_upload_dir();
|
307 |
-
$output .= $this->info(
|
308 |
-
if(
|
309 |
-
$output .= $this->info(
|
310 |
|
311 |
// WP Debug
|
312 |
-
$output .= $this->info(
|
313 |
-
$output .= $this->info(
|
314 |
-
$output .= $this->info(
|
315 |
|
316 |
-
return apply_filters(
|
317 |
}
|
318 |
|
319 |
/**
|
@@ -322,18 +335,19 @@ class SystemInfo extends InjectionAware {
|
|
322 |
* @param array $activePlugins
|
323 |
* @return string
|
324 |
*/
|
325 |
-
public function activePlugins(
|
326 |
-
|
|
|
327 |
|
328 |
-
foreach (
|
329 |
-
if(
|
330 |
continue;
|
331 |
}
|
332 |
|
333 |
$output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
|
334 |
}
|
335 |
|
336 |
-
return apply_filters(
|
337 |
}
|
338 |
|
339 |
/**
|
@@ -342,32 +356,34 @@ class SystemInfo extends InjectionAware {
|
|
342 |
* @param array $activePlugins
|
343 |
* @return string
|
344 |
*/
|
345 |
-
public function inactivePlugins(
|
346 |
-
|
|
|
347 |
|
348 |
-
foreach (
|
349 |
-
if(
|
350 |
continue;
|
351 |
}
|
352 |
|
353 |
$output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
|
354 |
}
|
355 |
|
356 |
-
return apply_filters(
|
357 |
}
|
358 |
|
359 |
/**
|
360 |
* Get list of active and inactive plugins
|
361 |
* @return string
|
362 |
*/
|
363 |
-
public function plugins()
|
|
|
364 |
// Get plugins and active plugins
|
365 |
-
$plugins
|
366 |
-
$activePlugins = get_option(
|
367 |
|
368 |
// Active plugins
|
369 |
-
$output = $this->activePlugins(
|
370 |
-
$output .= $this->inactivePlugins(
|
371 |
|
372 |
return $output;
|
373 |
}
|
@@ -376,28 +392,29 @@ class SystemInfo extends InjectionAware {
|
|
376 |
* Multisite Plugins
|
377 |
* @return string
|
378 |
*/
|
379 |
-
public function multiSitePlugins()
|
380 |
-
|
|
|
381 |
return '';
|
382 |
}
|
383 |
|
384 |
-
$output = $this->header(
|
385 |
|
386 |
-
$plugins
|
387 |
-
$activePlugins = get_site_option(
|
388 |
|
389 |
-
foreach (
|
390 |
-
$pluginBase = plugin_basename(
|
391 |
|
392 |
-
if(
|
393 |
continue;
|
394 |
}
|
395 |
|
396 |
-
$plugin = get_plugin_data(
|
397 |
|
398 |
$output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
|
399 |
}
|
400 |
-
unset(
|
401 |
|
402 |
return $output;
|
403 |
}
|
@@ -406,54 +423,57 @@ class SystemInfo extends InjectionAware {
|
|
406 |
* Server Information
|
407 |
* @return string
|
408 |
*/
|
409 |
-
public function server()
|
|
|
410 |
// Server Configuration
|
411 |
-
$output = $this->header(
|
412 |
|
413 |
-
$output .= $this->info(
|
414 |
-
$output .= $this->info(
|
415 |
-
$output .= $this->info(
|
416 |
|
417 |
-
return apply_filters(
|
418 |
}
|
419 |
|
420 |
/**
|
421 |
* PHP Configuration
|
422 |
* @return string
|
423 |
*/
|
424 |
-
public function php()
|
425 |
-
|
426 |
-
$output
|
427 |
-
$output .= $this->info(
|
428 |
-
$output .= $this->info(
|
429 |
-
$output .= $this->info(
|
430 |
-
$output .= $this->info(
|
431 |
-
$output .= $this->info(
|
432 |
-
$output .= $this->info(
|
433 |
-
$output .= $this->info(
|
434 |
-
|
435 |
-
|
436 |
-
$
|
437 |
-
|
438 |
-
|
|
|
439 |
}
|
440 |
|
441 |
/**
|
442 |
-
*
|
443 |
* @return string
|
444 |
*/
|
445 |
-
private function getPHPUser()
|
|
|
446 |
|
447 |
$user = '';
|
448 |
|
449 |
-
if(
|
450 |
$file = WPSTG_PLUGIN_DIR . 'Core/WPStaging.php';
|
451 |
-
$user = posix_getpwuid(
|
452 |
return isset($user['name']) ? $user['name'] : 'can not detect PHP user name';
|
453 |
}
|
454 |
|
455 |
-
if(
|
456 |
-
$user = exec(
|
457 |
return $user;
|
458 |
}
|
459 |
|
@@ -464,11 +484,12 @@ class SystemInfo extends InjectionAware {
|
|
464 |
* Check if PHP is on Safe Mode
|
465 |
* @return bool
|
466 |
*/
|
467 |
-
public function isSafeModeEnabled()
|
|
|
468 |
return (
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
}
|
473 |
|
474 |
/**
|
@@ -476,8 +497,9 @@ class SystemInfo extends InjectionAware {
|
|
476 |
* @param string $functionName
|
477 |
* @return string
|
478 |
*/
|
479 |
-
public function isSupported(
|
480 |
-
|
|
|
481 |
}
|
482 |
|
483 |
/**
|
@@ -486,11 +508,12 @@ class SystemInfo extends InjectionAware {
|
|
486 |
* @param bool $isClass
|
487 |
* @return string
|
488 |
*/
|
489 |
-
public function isInstalled(
|
490 |
-
|
491 |
-
|
|
|
492 |
} else {
|
493 |
-
return (extension_loaded(
|
494 |
}
|
495 |
}
|
496 |
|
@@ -498,9 +521,10 @@ class SystemInfo extends InjectionAware {
|
|
498 |
* Gets Installed Important PHP Extensions
|
499 |
* @return string
|
500 |
*/
|
501 |
-
public function phpExtensions()
|
|
|
502 |
// Important PHP Extensions
|
503 |
-
$version = curl_version();
|
504 |
|
505 |
$bitfields = Array(
|
506 |
'CURL_VERSION_IPV6',
|
@@ -509,37 +533,41 @@ class SystemInfo extends InjectionAware {
|
|
509 |
'CURL_VERSION_LIBZ'
|
510 |
);
|
511 |
|
512 |
-
$output = $this->header(
|
513 |
-
|
514 |
-
$output .= $this->info(
|
515 |
-
$output .= $this->info(
|
516 |
-
$output .= $this->info(
|
517 |
-
|
518 |
-
|
|
|
|
|
519 |
}
|
520 |
-
|
521 |
-
|
|
|
522 |
}
|
523 |
|
524 |
|
525 |
-
$output .= $this->info(
|
526 |
-
$output .= $this->info(
|
527 |
-
$output .= $this->info(
|
528 |
|
529 |
-
return apply_filters(
|
530 |
}
|
531 |
|
532 |
/**
|
533 |
* Check if WP is installed in subdir
|
534 |
* @return boolean
|
535 |
*/
|
536 |
-
private function isSubDir()
|
|
|
537 |
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
538 |
// This is happening much more often than you would expect
|
539 |
-
$siteurl = preg_replace(
|
540 |
-
$home
|
541 |
|
542 |
-
if(
|
543 |
return true;
|
544 |
}
|
545 |
return false;
|
@@ -554,19 +582,20 @@ class SystemInfo extends InjectionAware {
|
|
554 |
* @param array $clone
|
555 |
* @return sting
|
556 |
*/
|
557 |
-
private function getStagingPrefix(
|
|
|
558 |
// Throw error
|
559 |
-
$path
|
560 |
-
if(
|
561 |
return 'Can\'t find staging wp-config.php';
|
562 |
} else {
|
563 |
|
564 |
// Get prefix from wp-config.php
|
565 |
//preg_match_all("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
|
566 |
-
preg_match(
|
567 |
//wp_die(var_dump($matches));
|
568 |
|
569 |
-
if(
|
570 |
return $matches[1];
|
571 |
} else {
|
572 |
return 'No table_prefix in wp-config.php';
|
@@ -578,20 +607,21 @@ class SystemInfo extends InjectionAware {
|
|
578 |
* Get staging site wordpress version number
|
579 |
* @return string
|
580 |
*/
|
581 |
-
private function getStagingWpVersion(
|
|
|
582 |
|
583 |
-
if(
|
584 |
return "Error: Cannot detect WP version";
|
585 |
}
|
586 |
|
587 |
// Get version number of wp staging
|
588 |
-
$file
|
589 |
-
$versionStaging = file_get_contents(
|
590 |
|
591 |
-
preg_match(
|
592 |
|
593 |
$error = '';
|
594 |
-
if(
|
595 |
$error .= "Error: Cannot detect WP version";
|
596 |
}
|
597 |
return $matches[1];
|
9 |
use WPStaging\Utils\Multisite;
|
10 |
|
11 |
// No Direct Access
|
12 |
+
if (!defined("WPINC")) {
|
13 |
die;
|
14 |
}
|
15 |
|
17 |
* Class SystemInfo
|
18 |
* @package WPStaging\Backend\Modules
|
19 |
*/
|
20 |
+
class SystemInfo extends InjectionAware
|
21 |
+
{
|
22 |
|
23 |
/**
|
24 |
* @var bool
|
34 |
/**
|
35 |
* Initialize class
|
36 |
*/
|
37 |
+
public function initialize()
|
38 |
+
{
|
39 |
$this->isMultiSite = is_multisite();
|
40 |
+
$this->helper = new Utils\Helper();
|
41 |
}
|
42 |
|
43 |
/**
|
44 |
* Magic method
|
45 |
* @return string
|
46 |
*/
|
47 |
+
public function __toString()
|
48 |
+
{
|
49 |
return $this->get();
|
50 |
}
|
51 |
|
53 |
* Get System Information as text
|
54 |
* @return string
|
55 |
*/
|
56 |
+
public function get()
|
57 |
+
{
|
58 |
$output = "### Begin System Info ###" . PHP_EOL . PHP_EOL;
|
59 |
|
60 |
$output .= $this->wpstaging();
|
86 |
* @param string $string
|
87 |
* @return string
|
88 |
*/
|
89 |
+
public function header($string)
|
90 |
+
{
|
91 |
return PHP_EOL . "-- {$string}" . PHP_EOL . PHP_EOL;
|
92 |
}
|
93 |
|
97 |
* @param string $value
|
98 |
* @return string
|
99 |
*/
|
100 |
+
public function info($title, $value)
|
101 |
+
{
|
102 |
+
return str_pad($title, 56, ' ', STR_PAD_RIGHT) . $value . PHP_EOL;
|
103 |
}
|
104 |
|
105 |
/**
|
106 |
* Theme Information
|
107 |
* @return string
|
108 |
*/
|
109 |
+
public function theme()
|
110 |
+
{
|
111 |
// Versions earlier than 3.4
|
112 |
+
if (get_bloginfo("version") < "3.4") {
|
113 |
+
$themeData = get_theme_data(get_stylesheet_directory() . "/style.css");
|
114 |
return "{$themeData["Name"]} {$themeData["Version"]}";
|
115 |
}
|
116 |
|
122 |
* Site Information
|
123 |
* @return string
|
124 |
*/
|
125 |
+
public function site()
|
126 |
+
{
|
127 |
+
$output = $this->header("-- Site Info");
|
128 |
+
$output .= $this->info("Site URL:", site_url());
|
129 |
+
$output .= $this->info("Home URL:", $this->helper->get_home_url());
|
130 |
+
$output .= $this->info("Home Path:", get_home_path());
|
131 |
+
$output .= $this->info("ABSPATH:", ABSPATH);
|
132 |
+
$output .= $this->info("Installed in subdir:", ($this->isSubDir() ? 'Yes' : 'No'));
|
133 |
+
|
134 |
+
return apply_filters("wpstg_sysinfo_after_site_info", $output);
|
135 |
}
|
136 |
|
137 |
/**
|
138 |
* Multisite information
|
139 |
* @return string
|
140 |
*/
|
141 |
+
private function getMultisiteInfo()
|
142 |
+
{
|
143 |
+
if (!$this->isMultiSite) {
|
144 |
return '';
|
145 |
}
|
146 |
|
147 |
$multisite = new Multisite();
|
148 |
|
149 |
+
$output = $this->info("Multisite:", ($this->isMultiSite ? "Yes" : "No"));
|
150 |
+
$output .= $this->info("Multisite Blog ID:", get_current_blog_id());
|
151 |
+
$output .= $this->info("MultiSite URL:", $multisite->getHomeURL());
|
152 |
+
$output .= $this->info("MultiSite URL without scheme:", $multisite->getHomeUrlWithoutScheme());
|
153 |
+
$output .= $this->info("MultiSite is Main Site:", is_main_site() ? 'Yes' : 'No');
|
154 |
|
155 |
+
return apply_filters("wpstg_sysinfo_after_multisite_info", $output);
|
156 |
}
|
157 |
|
158 |
/**
|
159 |
* Wp Staging plugin Information
|
160 |
* @return string
|
161 |
*/
|
162 |
+
public function wpstaging()
|
163 |
+
{
|
164 |
// Get wpstg settings
|
165 |
+
$settings = ( object )get_option('wpstg_settings', array());
|
166 |
|
167 |
// Clones data < 1.1.6.x
|
168 |
+
$clones = ( object )get_option('wpstg_existing_clones', array());
|
169 |
// Clones data version > 2.x
|
170 |
+
$clonesBeta = get_option('wpstg_existing_clones_beta', array());
|
171 |
|
172 |
|
173 |
$output = "-- WP Staging Settings" . PHP_EOL . PHP_EOL;
|
174 |
+
$output .= $this->info("Query Limit:", isset($settings->queryLimit) ? $settings->queryLimit : 'undefined');
|
175 |
+
$output .= $this->info("DB Search & Replace Limit:", isset($settings->querySRLimit) ? $settings->querySRLimit : 'undefined');
|
176 |
+
$output .= $this->info("File Copy Limit:", isset($settings->fileLimit) ? $settings->fileLimit : 'undefined');
|
177 |
+
$output .= $this->info("Batch Size:", isset($settings->batchSize) ? $settings->batchSize : 'undefined');
|
178 |
+
$output .= $this->info("CPU Load:", isset($settings->cpuLoad) ? $settings->cpuLoad : 'undefined');
|
179 |
+
$output .= $this->info("WP in Subdir:", $this->isSubDir() ? 'true' : 'false');
|
180 |
|
181 |
$output .= PHP_EOL . PHP_EOL . "-- Available Sites Version < 1.1.6.x" . PHP_EOL . PHP_EOL;
|
182 |
|
183 |
+
foreach ($clones as $key => $value) {
|
184 |
+
$output .= $this->info("Site name & subfolder :", $value);
|
185 |
}
|
186 |
$output .= PHP_EOL . PHP_EOL . "-- Available Sites Version > 2.0.x" . PHP_EOL . PHP_EOL;
|
187 |
|
188 |
+
foreach ($clonesBeta as $key => $clone) {
|
189 |
|
190 |
+
$path = !empty($clone['path']) ? $clone['path'] : 'undefined';
|
191 |
|
192 |
+
$output .= $this->info("Number:", isset($clone['number']) ? $clone['number'] : 'undefined');
|
193 |
+
$output .= $this->info("directoryName:", isset($clone['directoryName']) ? $clone['directoryName'] : 'undefined');
|
194 |
+
$output .= $this->info("Path:", $path);
|
195 |
+
$output .= $this->info("URL:", isset($clone['url']) ? $clone['url'] : 'undefined');
|
196 |
+
$output .= $this->info("DB Prefix:", isset($clone['prefix']) ? $clone['prefix'] : 'undefined');
|
197 |
+
$output .= $this->info("DB Prefix wp-config.php:", $this->getStagingPrefix($clone));
|
198 |
+
$output .= $this->info("WP Staging Version:", isset($clone['version']) ? $clone['version'] : 'undefined');
|
199 |
+
$output .= $this->info("WP Version:", $this->getStagingWpVersion($path)) . PHP_EOL . PHP_EOL;
|
200 |
}
|
201 |
|
202 |
|
203 |
+
$output .= $this->info("Raw Clones Data:", json_encode(get_option('wpstg_existing_clones_beta', 'undefined')));
|
204 |
|
205 |
$output .= '' . PHP_EOL;
|
206 |
|
207 |
|
208 |
//$output .= PHP_EOL . PHP_EOL;
|
209 |
|
210 |
+
$output .= $this->info("Plugin Pro Version:", get_option('wpstgpro_version', 'undefined'));
|
211 |
+
$output .= $this->info("Plugin Free Version:", get_option('wpstg_version', 'undefined'));
|
212 |
+
$output .= $this->info("Install Date:", get_option('wpstg_installDate', 'undefined'));
|
213 |
+
$output .= $this->info("Upgraded from Pro:", get_option('wpstgpro_version_upgraded_from', 'undefined'));
|
214 |
+
$output .= $this->info("Upgraded from Free:", get_option('wpstg_version_upgraded_from', 'undefined'));
|
215 |
+
$output .= $this->info("Is Staging Site:", wpstg_is_stagingsite() ? 'true' : 'false') . PHP_EOL . PHP_EOL;
|
216 |
|
217 |
|
218 |
+
return apply_filters("wpstg_sysinfo_after_wpstaging_info", $output);
|
219 |
}
|
220 |
|
221 |
/**
|
222 |
* Browser Information
|
223 |
* @return string
|
224 |
*/
|
225 |
+
public function browser()
|
226 |
+
{
|
227 |
+
$output = $this->header("User Browser");
|
228 |
$output .= (new Browser);
|
229 |
|
230 |
+
return apply_filters("wpstg_sysinfo_after_user_browser", $output);
|
231 |
}
|
232 |
|
233 |
/**
|
234 |
* Frontpage Information when frontpage is set to "page"
|
235 |
* @return string
|
236 |
*/
|
237 |
+
public function frontPage()
|
238 |
+
{
|
239 |
+
if (get_option("show_on_front") !== "page") {
|
240 |
return '';
|
241 |
}
|
242 |
|
243 |
+
$frontPageID = get_option("page_on_front");
|
244 |
+
$blogPageID = get_option("page_for_posts");
|
245 |
|
246 |
// Front Page
|
247 |
+
$pageFront = ($frontPageID != 0) ? get_the_title($frontPageID) . " (#{$frontPageID})" : "Unset";
|
248 |
// Blog Page ID
|
249 |
+
$pageBlog = ($blogPageID != 0) ? get_the_title($blogPageID) . " (#{$blogPageID})" : "Unset";
|
250 |
|
251 |
+
$output = $this->info("Page On Front:", $pageFront);
|
252 |
+
$output .= $this->info("Page For Posts:", $pageBlog);
|
253 |
|
254 |
return $output;
|
255 |
}
|
258 |
* Check wp_remote_post() functionality
|
259 |
* @return string
|
260 |
*/
|
261 |
+
public function wpRemotePost()
|
262 |
+
{
|
263 |
// Make sure wp_remote_post() is working
|
264 |
$wpRemotePost = "wp_remote_post() does not work";
|
265 |
|
266 |
// Send request
|
267 |
$response = wp_remote_post(
|
268 |
+
"https://www.paypal.com/cgi-bin/webscr", array(
|
269 |
+
"sslverify" => false,
|
270 |
+
"timeout" => 60,
|
271 |
+
"user-agent" => "WPSTG/" . WPStaging::getVersion(),
|
272 |
+
"body" => array("cmd" => "_notify-validate")
|
273 |
+
)
|
274 |
);
|
275 |
|
276 |
// Validate it worked
|
277 |
+
if (!is_wp_error($response) && 200 <= $response["response"]["code"] && 300 > $response["response"]["code"]) {
|
278 |
$wpRemotePost = "wp_remote_post() works";
|
279 |
}
|
280 |
|
281 |
+
return $this->info("Remote Post:", $wpRemotePost);
|
282 |
}
|
283 |
|
284 |
/**
|
285 |
* WordPress Configuration
|
286 |
* @return string
|
287 |
*/
|
288 |
+
public function wp()
|
289 |
+
{
|
290 |
+
$output = $this->header("WordPress Configuration");
|
291 |
+
$output .= $this->info("Version:", get_bloginfo("version"));
|
292 |
+
$output .= $this->info("Language:", (defined("WPLANG") && WPLANG) ? WPLANG : "en_US");
|
293 |
|
294 |
+
$permalinkStructure = get_option("permalink_structure");;
|
295 |
+
$output .= $this->info("Permalink Structure:", ($permalinkStructure) ? $permalinkStructure : "Default");
|
|
|
296 |
|
297 |
+
$output .= $this->info("Active Theme:", $this->theme());
|
298 |
+
$output .= $this->info("Show On Front:", get_option("show_on_front"));
|
299 |
|
300 |
// Frontpage information
|
301 |
$output .= $this->frontPage();
|
304 |
$output .= $this->wpRemotePost();
|
305 |
|
306 |
// Table Prefix
|
307 |
+
$wpDB = $this->di->get("wpdb");
|
308 |
$tablePrefix = "DB Prefix: " . $wpDB->prefix . ' ';
|
309 |
+
$tablePrefix .= "Length: " . strlen($wpDB->prefix) . " Status: ";
|
310 |
+
$tablePrefix .= (strlen($wpDB->prefix) > 16) ? " ERROR: Too long" : " Acceptable";
|
311 |
|
312 |
+
$output .= $this->info("Table Prefix:", $tablePrefix);
|
313 |
|
314 |
// Constants
|
315 |
+
$output .= $this->info("WP Content Path:", WP_CONTENT_DIR);
|
316 |
+
$output .= $this->info("WP Plugin Dir:", WP_PLUGIN_DIR);
|
317 |
+
if (defined('UPLOADS'))
|
318 |
+
$output .= $this->info("WP UPLOADS CONST:", UPLOADS);
|
319 |
$uploads = wp_upload_dir();
|
320 |
+
$output .= $this->info("WP Uploads Dir:", $uploads['basedir']);
|
321 |
+
if (defined('WP_TEMP_DIR'))
|
322 |
+
$output .= $this->info("WP Temp Dir:", WP_TEMP_DIR);
|
323 |
|
324 |
// WP Debug
|
325 |
+
$output .= $this->info("WP_DEBUG:", (defined("WP_DEBUG")) ? WP_DEBUG ? "Enabled" : "Disabled" : "Not set");
|
326 |
+
$output .= $this->info("Memory Limit:", WP_MEMORY_LIMIT);
|
327 |
+
$output .= $this->info("Registered Post Stati:", implode(", ", \get_post_stati()));
|
328 |
|
329 |
+
return apply_filters("wpstg_sysinfo_after_wpstg_config", $output);
|
330 |
}
|
331 |
|
332 |
/**
|
335 |
* @param array $activePlugins
|
336 |
* @return string
|
337 |
*/
|
338 |
+
public function activePlugins($plugins, $activePlugins)
|
339 |
+
{
|
340 |
+
$output = $this->header("WordPress Active Plugins");
|
341 |
|
342 |
+
foreach ($plugins as $path => $plugin) {
|
343 |
+
if (!in_array($path, $activePlugins)) {
|
344 |
continue;
|
345 |
}
|
346 |
|
347 |
$output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
|
348 |
}
|
349 |
|
350 |
+
return apply_filters("wpstg_sysinfo_after_wordpress_plugins", $output);
|
351 |
}
|
352 |
|
353 |
/**
|
356 |
* @param array $activePlugins
|
357 |
* @return string
|
358 |
*/
|
359 |
+
public function inactivePlugins($plugins, $activePlugins)
|
360 |
+
{
|
361 |
+
$output = $this->header("WordPress Inactive Plugins");
|
362 |
|
363 |
+
foreach ($plugins as $path => $plugin) {
|
364 |
+
if (in_array($path, $activePlugins)) {
|
365 |
continue;
|
366 |
}
|
367 |
|
368 |
$output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
|
369 |
}
|
370 |
|
371 |
+
return apply_filters("wpstg_sysinfo_after_wordpress_plugins_inactive", $output);
|
372 |
}
|
373 |
|
374 |
/**
|
375 |
* Get list of active and inactive plugins
|
376 |
* @return string
|
377 |
*/
|
378 |
+
public function plugins()
|
379 |
+
{
|
380 |
// Get plugins and active plugins
|
381 |
+
$plugins = get_plugins();
|
382 |
+
$activePlugins = get_option("active_plugins", array());
|
383 |
|
384 |
// Active plugins
|
385 |
+
$output = $this->activePlugins($plugins, $activePlugins);
|
386 |
+
$output .= $this->inactivePlugins($plugins, $activePlugins);
|
387 |
|
388 |
return $output;
|
389 |
}
|
392 |
* Multisite Plugins
|
393 |
* @return string
|
394 |
*/
|
395 |
+
public function multiSitePlugins()
|
396 |
+
{
|
397 |
+
if (!$this->isMultiSite) {
|
398 |
return '';
|
399 |
}
|
400 |
|
401 |
+
$output = $this->header("Network Active Plugins");
|
402 |
|
403 |
+
$plugins = wp_get_active_network_plugins();
|
404 |
+
$activePlugins = get_site_option("active_sitewide_plugins", array());
|
405 |
|
406 |
+
foreach ($plugins as $pluginPath) {
|
407 |
+
$pluginBase = plugin_basename($pluginPath);
|
408 |
|
409 |
+
if (!array_key_exists($pluginBase, $activePlugins)) {
|
410 |
continue;
|
411 |
}
|
412 |
|
413 |
+
$plugin = get_plugin_data($pluginPath);
|
414 |
|
415 |
$output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
|
416 |
}
|
417 |
+
unset($plugins, $activePlugins);
|
418 |
|
419 |
return $output;
|
420 |
}
|
423 |
* Server Information
|
424 |
* @return string
|
425 |
*/
|
426 |
+
public function server()
|
427 |
+
{
|
428 |
// Server Configuration
|
429 |
+
$output = $this->header("Webserver Configuration");
|
430 |
|
431 |
+
$output .= $this->info("PHP Version:", PHP_VERSION);
|
432 |
+
$output .= $this->info("MySQL Version:", $this->di->get("wpdb")->db_version());
|
433 |
+
$output .= $this->info("Webserver Info:", $_SERVER["SERVER_SOFTWARE"]);
|
434 |
|
435 |
+
return apply_filters("wpstg_sysinfo_after_webserver_config", $output);
|
436 |
}
|
437 |
|
438 |
/**
|
439 |
* PHP Configuration
|
440 |
* @return string
|
441 |
*/
|
442 |
+
public function php()
|
443 |
+
{
|
444 |
+
$output = $this->header("PHP Configuration");
|
445 |
+
$output .= $this->info("Safe Mode:", ($this->isSafeModeEnabled() ? "Enabled" : "Disabled"));
|
446 |
+
$output .= $this->info("PHP Max Memory Limit:", ini_get("memory_limit"));
|
447 |
+
$output .= $this->info("Upload Max Size:", ini_get("upload_max_filesize"));
|
448 |
+
$output .= $this->info("Post Max Size:", ini_get("post_max_size"));
|
449 |
+
$output .= $this->info("Upload Max Filesize:", ini_get("upload_max_filesize"));
|
450 |
+
$output .= $this->info("Time Limit:", ini_get("max_execution_time"));
|
451 |
+
$output .= $this->info("Max Input Vars:", ini_get("max_input_vars"));
|
452 |
+
$output .= $this->info("PHP User:", $this->getPHPUser());
|
453 |
+
|
454 |
+
$displayErrors = ini_get("display_errors");
|
455 |
+
$output .= $this->info("Display Errors:", ($displayErrors) ? "On ({$displayErrors})" : "N/A");
|
456 |
+
|
457 |
+
return apply_filters("wpstg_sysinfo_after_php_config", $output);
|
458 |
}
|
459 |
|
460 |
/**
|
461 |
+
*
|
462 |
* @return string
|
463 |
*/
|
464 |
+
private function getPHPUser()
|
465 |
+
{
|
466 |
|
467 |
$user = '';
|
468 |
|
469 |
+
if (extension_loaded('posix') && function_exists('posix_getpwuid')) {
|
470 |
$file = WPSTG_PLUGIN_DIR . 'Core/WPStaging.php';
|
471 |
+
$user = posix_getpwuid(fileowner($file));
|
472 |
return isset($user['name']) ? $user['name'] : 'can not detect PHP user name';
|
473 |
}
|
474 |
|
475 |
+
if (function_exists('exec') && @exec('echo EXEC') == 'EXEC') {
|
476 |
+
$user = exec('whoami');
|
477 |
return $user;
|
478 |
}
|
479 |
|
484 |
* Check if PHP is on Safe Mode
|
485 |
* @return bool
|
486 |
*/
|
487 |
+
public function isSafeModeEnabled()
|
488 |
+
{
|
489 |
return (
|
490 |
+
version_compare(PHP_VERSION, "5.4.0", '<') &&
|
491 |
+
@ini_get("safe_mode")
|
492 |
+
);
|
493 |
}
|
494 |
|
495 |
/**
|
497 |
* @param string $functionName
|
498 |
* @return string
|
499 |
*/
|
500 |
+
public function isSupported($functionName)
|
501 |
+
{
|
502 |
+
return (function_exists($functionName)) ? "Supported" : "Not Supported";
|
503 |
}
|
504 |
|
505 |
/**
|
508 |
* @param bool $isClass
|
509 |
* @return string
|
510 |
*/
|
511 |
+
public function isInstalled($name, $isClass = true)
|
512 |
+
{
|
513 |
+
if (true === $isClass) {
|
514 |
+
return (class_exists($name)) ? "Installed" : "Not Installed";
|
515 |
} else {
|
516 |
+
return (extension_loaded($name)) ? "Installed" : "Not Installed";
|
517 |
}
|
518 |
}
|
519 |
|
521 |
* Gets Installed Important PHP Extensions
|
522 |
* @return string
|
523 |
*/
|
524 |
+
public function phpExtensions()
|
525 |
+
{
|
526 |
// Important PHP Extensions
|
527 |
+
$version = function_exists('curl_version') ? curl_version() : array('version' => 'Error: not available', 'ssl_version' => 'Error: not available', 'host' => 'Error: not available', 'protocols' => array(), 'features' => array());
|
528 |
|
529 |
$bitfields = Array(
|
530 |
'CURL_VERSION_IPV6',
|
533 |
'CURL_VERSION_LIBZ'
|
534 |
);
|
535 |
|
536 |
+
$output = $this->header("PHP Extensions");
|
537 |
+
|
538 |
+
$output .= $this->info("cURL:", $this->isSupported("curl_init"));
|
539 |
+
$output .= $this->info("cURL version:", $version['version']);
|
540 |
+
$output .= $this->info("cURL ssl version number:", $version['ssl_version']);
|
541 |
+
$output .= $this->info("cURL host:", $version['host']);
|
542 |
+
|
543 |
+
foreach ($version['protocols'] as $protocols) {
|
544 |
+
$output .= $this->info("cURL protocols:", $protocols);
|
545 |
}
|
546 |
+
|
547 |
+
foreach ($bitfields as $feature) {
|
548 |
+
$output .= $feature . ($version['features'] & constant($feature) ? ' yes' : ' no') . PHP_EOL;
|
549 |
}
|
550 |
|
551 |
|
552 |
+
$output .= $this->info("fsockopen:", $this->isSupported("fsockopen"));
|
553 |
+
$output .= $this->info("SOAP Client:", $this->isInstalled("SoapClient"));
|
554 |
+
$output .= $this->info("Suhosin:", $this->isInstalled("suhosin", false));
|
555 |
|
556 |
+
return apply_filters("wpstg_sysinfo_after_php_ext", $output);
|
557 |
}
|
558 |
|
559 |
/**
|
560 |
* Check if WP is installed in subdir
|
561 |
* @return boolean
|
562 |
*/
|
563 |
+
private function isSubDir()
|
564 |
+
{
|
565 |
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
566 |
// This is happening much more often than you would expect
|
567 |
+
$siteurl = preg_replace('#^https?://#', '', rtrim(get_option('siteurl'), '/'));
|
568 |
+
$home = preg_replace('#^https?://#', '', rtrim(get_option('home'), '/'));
|
569 |
|
570 |
+
if ($home !== $siteurl) {
|
571 |
return true;
|
572 |
}
|
573 |
return false;
|
582 |
* @param array $clone
|
583 |
* @return sting
|
584 |
*/
|
585 |
+
private function getStagingPrefix($clone = array())
|
586 |
+
{
|
587 |
// Throw error
|
588 |
+
$path = ABSPATH . $clone['directoryName'] . DIRECTORY_SEPARATOR . "wp-config.php";
|
589 |
+
if (false === ($content = @file_get_contents($path))) {
|
590 |
return 'Can\'t find staging wp-config.php';
|
591 |
} else {
|
592 |
|
593 |
// Get prefix from wp-config.php
|
594 |
//preg_match_all("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
|
595 |
+
preg_match("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
|
596 |
//wp_die(var_dump($matches));
|
597 |
|
598 |
+
if (!empty($matches[1])) {
|
599 |
return $matches[1];
|
600 |
} else {
|
601 |
return 'No table_prefix in wp-config.php';
|
607 |
* Get staging site wordpress version number
|
608 |
* @return string
|
609 |
*/
|
610 |
+
private function getStagingWpVersion($path)
|
611 |
+
{
|
612 |
|
613 |
+
if ($path === 'undefined') {
|
614 |
return "Error: Cannot detect WP version";
|
615 |
}
|
616 |
|
617 |
// Get version number of wp staging
|
618 |
+
$file = trailingslashit($path) . 'wp-includes/version.php';
|
619 |
+
$versionStaging = file_get_contents($file);
|
620 |
|
621 |
+
preg_match("/\\\$wp_version.*=.*'(.*)';/", $versionStaging, $matches);
|
622 |
|
623 |
$error = '';
|
624 |
+
if (empty($matches[1])) {
|
625 |
$error .= "Error: Cannot detect WP version";
|
626 |
}
|
627 |
return $matches[1];
|
Backend/Notices/Notices.php
CHANGED
@@ -153,9 +153,9 @@ class Notices {
|
|
153 |
}
|
154 |
|
155 |
// Beta
|
156 |
-
if( false === get_option( "wpstg_beta" ) || "no" !== get_option( "wpstg_beta" ) ) {
|
157 |
require_once "{$viewsNoticesPath}beta.php";
|
158 |
-
}
|
159 |
|
160 |
// WP Staging Pro and Free can not be activated both
|
161 |
if( false !== ( $deactivatedNoticeID = get_transient( "wp_staging_deactivated_notice_id" ) ) ) {
|
153 |
}
|
154 |
|
155 |
// Beta
|
156 |
+
/*if( false === get_option( "wpstg_beta" ) || "no" !== get_option( "wpstg_beta" ) ) {
|
157 |
require_once "{$viewsNoticesPath}beta.php";
|
158 |
+
}*/
|
159 |
|
160 |
// WP Staging Pro and Free can not be activated both
|
161 |
if( false !== ( $deactivatedNoticeID = get_transient( "wp_staging_deactivated_notice_id" ) ) ) {
|
Backend/Optimizer/wp-staging-optimizer.php
CHANGED
@@ -45,11 +45,6 @@ function wpstg_get_plugins_dir()
|
|
45 |
function wpstg_is_enabled_optimizer()
|
46 |
{
|
47 |
|
48 |
-
// Activate the Optimizer all the times.
|
49 |
-
// Until now we never had any issue with the Optimizer so keep the optimizer activated to make sure user does not disable it accidentally
|
50 |
-
// @todo remove this function in wp staging settings
|
51 |
-
return true;
|
52 |
-
|
53 |
$status = ( object )get_option('wpstg_settings');
|
54 |
|
55 |
if ($status && isset($status->optimizer) && $status->optimizer == 1) {
|
45 |
function wpstg_is_enabled_optimizer()
|
46 |
{
|
47 |
|
|
|
|
|
|
|
|
|
|
|
48 |
$status = ( object )get_option('wpstg_settings');
|
49 |
|
50 |
if ($status && isset($status->optimizer) && $status->optimizer == 1) {
|
Backend/public/css/wpstg-admin.css
CHANGED
@@ -245,11 +245,17 @@
|
|
245 |
color: #eee;
|
246 |
}
|
247 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
.wpstg-clone {
|
249 |
-
|
250 |
-
|
251 |
-
padding: 5px 10px;
|
252 |
-
width: 400px;
|
253 |
position: relative;
|
254 |
overflow: hidden;
|
255 |
transition: border-color .2s ease-in-out;
|
@@ -367,18 +373,21 @@
|
|
367 |
width: 500px;
|
368 |
}
|
369 |
|
370 |
-
#wpstg-home-link,
|
371 |
#wpstg-try-again {
|
372 |
display: none;
|
373 |
}
|
374 |
|
|
|
|
|
|
|
375 |
|
376 |
-
|
377 |
content: url('../img/loading.gif');
|
378 |
-
margin-top
|
|
|
379 |
}
|
380 |
|
381 |
-
|
382 |
display:block;
|
383 |
content:"Finished";
|
384 |
background-color:#00c89a;
|
@@ -390,19 +399,6 @@
|
|
390 |
margin-top:0px;
|
391 |
border-radius: 3px;
|
392 |
}
|
393 |
-
.wpstg-loader {
|
394 |
-
content: url('../img/loading.gif');
|
395 |
-
margin-top:-5px;
|
396 |
-
}
|
397 |
-
|
398 |
-
.wpstg-loader.wpstg-finished {
|
399 |
-
content:"Finished";
|
400 |
-
background-color:#00c89a;
|
401 |
-
color:white;
|
402 |
-
padding:2px;
|
403 |
-
margin-top:0px;
|
404 |
-
max-width:60px;
|
405 |
-
}
|
406 |
|
407 |
#wpstg-workflow {
|
408 |
max-width: 650px;
|
@@ -539,6 +535,10 @@
|
|
539 |
top: 2px;
|
540 |
}
|
541 |
|
|
|
|
|
|
|
|
|
542 |
#wpstg-workflow #wpstg-start-cloning {
|
543 |
display: inline-block;
|
544 |
margin-left: 5px;
|
@@ -648,6 +648,7 @@
|
|
648 |
padding:20px;
|
649 |
border: 1px solid #fff;
|
650 |
max-width: 600px;
|
|
|
651 |
}
|
652 |
|
653 |
.wpstg-header{
|
@@ -664,7 +665,7 @@
|
|
664 |
font-weight: bold;
|
665 |
}
|
666 |
|
667 |
-
|
668 |
height: 300px;
|
669 |
overflow: scroll;
|
670 |
max-width: 650px;
|
@@ -859,6 +860,10 @@
|
|
859 |
color:white;
|
860 |
}
|
861 |
|
|
|
|
|
|
|
|
|
862 |
.wpstg-bold{
|
863 |
font-weight: 600;
|
864 |
}
|
@@ -1101,3 +1106,118 @@
|
|
1101 |
.wpstg-pointer {
|
1102 |
cursor: pointer;
|
1103 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
245 |
color: #eee;
|
246 |
}
|
247 |
|
248 |
+
.wpstg-box {
|
249 |
+
margin: 10px 0;
|
250 |
+
padding: 10px;
|
251 |
+
position: relative;
|
252 |
+
overflow: hidden;
|
253 |
+
transition: border-color .2s ease-in-out;
|
254 |
+
}
|
255 |
+
|
256 |
.wpstg-clone {
|
257 |
+
margin-bottom: 1px;
|
258 |
+
padding: 10px 10px;
|
|
|
|
|
259 |
position: relative;
|
260 |
overflow: hidden;
|
261 |
transition: border-color .2s ease-in-out;
|
373 |
width: 500px;
|
374 |
}
|
375 |
|
|
|
376 |
#wpstg-try-again {
|
377 |
display: none;
|
378 |
}
|
379 |
|
380 |
+
#wpstg-home-link {
|
381 |
+
float: right;
|
382 |
+
}
|
383 |
|
384 |
+
.wpstg-loader {
|
385 |
content: url('../img/loading.gif');
|
386 |
+
margin-top:5px;
|
387 |
+
display: none;
|
388 |
}
|
389 |
|
390 |
+
.wpstg-loader.wpstg-finished {
|
391 |
display:block;
|
392 |
content:"Finished";
|
393 |
background-color:#00c89a;
|
399 |
margin-top:0px;
|
400 |
border-radius: 3px;
|
401 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
402 |
|
403 |
#wpstg-workflow {
|
404 |
max-width: 650px;
|
535 |
top: 2px;
|
536 |
}
|
537 |
|
538 |
+
.wpstg-db-table:hover{
|
539 |
+
background-color:#f0f8ff;
|
540 |
+
}
|
541 |
+
|
542 |
#wpstg-workflow #wpstg-start-cloning {
|
543 |
display: inline-block;
|
544 |
margin-left: 5px;
|
648 |
padding:20px;
|
649 |
border: 1px solid #fff;
|
650 |
max-width: 600px;
|
651 |
+
margin-top:10px;
|
652 |
}
|
653 |
|
654 |
.wpstg-header{
|
665 |
font-weight: bold;
|
666 |
}
|
667 |
|
668 |
+
.wpstg-log-details{
|
669 |
height: 300px;
|
670 |
overflow: scroll;
|
671 |
max-width: 650px;
|
860 |
color:white;
|
861 |
}
|
862 |
|
863 |
+
.wpstg-staging-info li{
|
864 |
+
margin-bottom: 2px;
|
865 |
+
}
|
866 |
+
|
867 |
.wpstg-bold{
|
868 |
font-weight: 600;
|
869 |
}
|
1106 |
.wpstg-pointer {
|
1107 |
cursor: pointer;
|
1108 |
}
|
1109 |
+
|
1110 |
+
|
1111 |
+
.wpstg--tab--header ul {
|
1112 |
+
display: flex;
|
1113 |
+
}
|
1114 |
+
|
1115 |
+
.wpstg--tab--header ul li {
|
1116 |
+
margin-right: 1em;
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
.wpstg--tab--header ul li:last-child {
|
1120 |
+
margin-right: 0;
|
1121 |
+
}
|
1122 |
+
|
1123 |
+
.wpstg--tab--header a {
|
1124 |
+
min-width: 150px;
|
1125 |
+
text-align: center;
|
1126 |
+
cursor: pointer;
|
1127 |
+
display: inline-block;
|
1128 |
+
padding: 1em 1.25em;
|
1129 |
+
border-bottom: .5em solid transparent;
|
1130 |
+
border: solid 1px;
|
1131 |
+
}
|
1132 |
+
|
1133 |
+
.wpstg--tab--header a.wpstg--tab--active {
|
1134 |
+
border-bottom: .5em solid #25A1F0;
|
1135 |
+
color: #25A1F0;
|
1136 |
+
}
|
1137 |
+
|
1138 |
+
.wpstg--tab--content {
|
1139 |
+
display: none;
|
1140 |
+
}
|
1141 |
+
|
1142 |
+
.wpstg--tab--active {
|
1143 |
+
display: block;
|
1144 |
+
}
|
1145 |
+
|
1146 |
+
.wpstg--text--strong,
|
1147 |
+
.wpstg--text--strong * {
|
1148 |
+
font-weight: bold !important;
|
1149 |
+
}
|
1150 |
+
|
1151 |
+
.wpstg--text--danger {
|
1152 |
+
color: #a94442;
|
1153 |
+
}
|
1154 |
+
|
1155 |
+
.wpstg--tooltip {
|
1156 |
+
position: relative;
|
1157 |
+
display: inline-block;
|
1158 |
+
border-bottom: 1px dotted black;
|
1159 |
+
margin-left: 10px;
|
1160 |
+
}
|
1161 |
+
|
1162 |
+
.wpstg--tooltip .wpstg--tooltiptext {
|
1163 |
+
visibility: hidden;
|
1164 |
+
width: 300px;
|
1165 |
+
background-color: #ffffff;
|
1166 |
+
color: #505050;
|
1167 |
+
text-align: left;
|
1168 |
+
padding: 20px;
|
1169 |
+
border: 1px solid #e8e8e8;
|
1170 |
+
border-radius: 3px;
|
1171 |
+
position: absolute;
|
1172 |
+
z-index: 1;
|
1173 |
+
-webkit-box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.75);
|
1174 |
+
-moz-box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.75);
|
1175 |
+
box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.75);
|
1176 |
+
}
|
1177 |
+
|
1178 |
+
.wpstg--tooltip:hover .wpstg--tooltiptext {
|
1179 |
+
visibility: visible;
|
1180 |
+
}
|
1181 |
+
|
1182 |
+
.wpstg--tooltiptext-snapshots {
|
1183 |
+
width: 120px;
|
1184 |
+
top: 100%;
|
1185 |
+
left: -150%;
|
1186 |
+
margin-left: -60px; /* Use half of the width (120/2 = 60), to center the tooltip */
|
1187 |
+
margin-top:10px;
|
1188 |
+
}
|
1189 |
+
/**
|
1190 |
+
Tooltip top arrow
|
1191 |
+
*/
|
1192 |
+
.wpstg--tooltip .wpstg--tooltiptext-snapshots::after {
|
1193 |
+
content: " ";
|
1194 |
+
position: absolute;
|
1195 |
+
bottom: 100%; /* At the top of the tooltip */
|
1196 |
+
left: 50%;
|
1197 |
+
margin-left: 25px;
|
1198 |
+
border-width: 5px;
|
1199 |
+
border-style: solid;
|
1200 |
+
border-color: transparent transparent white transparent;
|
1201 |
+
}
|
1202 |
+
|
1203 |
+
.wpstg--snaphot-restore-table tr {
|
1204 |
+
line-height: 12px;
|
1205 |
+
}
|
1206 |
+
|
1207 |
+
.wpstg-float-left{
|
1208 |
+
float: left;
|
1209 |
+
}
|
1210 |
+
|
1211 |
+
.wpstg-beta-notice{
|
1212 |
+
background-color: #b0e8b0;
|
1213 |
+
border-radius: 3px;
|
1214 |
+
padding: 7px;
|
1215 |
+
margin-bottom: 20px;
|
1216 |
+
}
|
1217 |
+
|
1218 |
+
#wpstg-snapshot-name {
|
1219 |
+
font-size: 1.875em;
|
1220 |
+
font-weight: 600;
|
1221 |
+
}
|
1222 |
+
|
1223 |
+
|
Backend/public/js/wpstg-admin.js
CHANGED
@@ -1,28 +1,25 @@
|
|
1 |
"use strict";
|
2 |
|
3 |
-
var WPStaging = (function ($)
|
4 |
-
{
|
5 |
var that = {
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
|
16 |
/**
|
17 |
* Get / Set Cache for Selector
|
18 |
* @param {String} selector
|
19 |
* @returns {*}
|
20 |
*/
|
21 |
-
cache.get = function (selector)
|
22 |
-
{
|
23 |
// It is already cached!
|
24 |
-
if ($.inArray(selector, cache.elements) !== -1)
|
25 |
-
{
|
26 |
return cache.elements[selector];
|
27 |
}
|
28 |
|
@@ -36,8 +33,7 @@ var WPStaging = (function ($)
|
|
36 |
* Refreshes given cache
|
37 |
* @param {String} selector
|
38 |
*/
|
39 |
-
cache.refresh = function (selector)
|
40 |
-
{
|
41 |
selector.elements[selector] = jQuery(selector);
|
42 |
};
|
43 |
|
@@ -45,43 +41,70 @@ var WPStaging = (function ($)
|
|
45 |
* Show and Log Error Message
|
46 |
* @param {String} message
|
47 |
*/
|
48 |
-
var showError = function (message)
|
49 |
-
{
|
50 |
cache.get("#wpstg-try-again").css("display", "inline-block");
|
51 |
cache.get("#wpstg-cancel-cloning").text("Reset");
|
52 |
cache.get("#wpstg-resume-cloning").show();
|
53 |
cache.get("#wpstg-error-wrapper").show();
|
54 |
cache.get("#wpstg-error-details").show().html(message);
|
55 |
cache.get("#wpstg-removing-clone").removeClass("loading");
|
56 |
-
cache.get("
|
57 |
};
|
58 |
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
.
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
};
|
72 |
|
|
|
73 |
/**
|
74 |
* Common Elements
|
75 |
*/
|
76 |
-
var elements = function ()
|
77 |
-
{
|
78 |
var $workFlow = cache.get("#wpstg-workflow"),
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
|
83 |
-
if (2 < window.devicePixelRatio)
|
84 |
-
{
|
85 |
urlSpinner += "-2x";
|
86 |
}
|
87 |
|
@@ -89,228 +112,169 @@ var WPStaging = (function ($)
|
|
89 |
|
90 |
ajaxSpinner = "<img src=''" + urlSpinner + "' alt='' class='ajax-spinner general-spinner' />";
|
91 |
|
92 |
-
var getBaseValues = function() {
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
};
|
99 |
|
100 |
$workFlow
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
cache.get("#wpstg_select_tables_cloning .wpstg-db-table").prop("selected", false);
|
134 |
-
cache.get(".wpstg-button-unselect").text("Select All");
|
135 |
-
cache.get(".wpstg-db-table-checkboxes").prop("checked", false);
|
136 |
-
isAllChecked = false;
|
137 |
-
}
|
138 |
-
})
|
139 |
-
|
140 |
-
/**
|
141 |
-
* Select tables with certain tbl prefix
|
142 |
-
* @param obj e
|
143 |
-
* @returns {undefined}
|
144 |
-
*/
|
145 |
-
// .on("click", ".wpstg-button-select", function (e) {
|
146 |
-
// e.preventDefault();
|
147 |
-
// $(".wpstg-db-table input").each(function () {
|
148 |
-
//
|
149 |
-
// if (wpstg.isMultisite == 1) {
|
150 |
-
// if ($(this).attr('name').match("^" + wpstg.tblprefix + "([^0-9])_*")) {
|
151 |
-
// $(this).prop("checked", true);
|
152 |
-
// } else {
|
153 |
-
// $(this).prop("checked", false);
|
154 |
-
// }
|
155 |
-
// }
|
156 |
-
//
|
157 |
-
// if (wpstg.isMultisite == 0) {
|
158 |
-
// if ($(this).attr('name').match("^" + wpstg.tblprefix)) {
|
159 |
-
// $(this).prop("checked", true);
|
160 |
-
// } else {
|
161 |
-
// $(this).prop("checked", false);
|
162 |
-
// }
|
163 |
-
// }
|
164 |
-
// })
|
165 |
-
// })
|
166 |
-
/**
|
167 |
-
* Select tables with certain tbl prefix | NEW
|
168 |
-
* @param obj e
|
169 |
-
* @returns {undefined}
|
170 |
-
*/
|
171 |
-
.on("click", ".wpstg-button-select", function (e) {
|
172 |
-
e.preventDefault();
|
173 |
-
$("#wpstg_select_tables_cloning .wpstg-db-table").each(function () {
|
174 |
-
if (wpstg.isMultisite == 1) {
|
175 |
-
if ($(this).attr('name').match("^" + wpstg.tblprefix + "([^0-9])_*")) {
|
176 |
-
$(this).prop("selected", "selected");
|
177 |
-
} else {
|
178 |
-
$(this).prop("selected", false);
|
179 |
-
}
|
180 |
}
|
|
|
181 |
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
}
|
188 |
}
|
189 |
-
})
|
190 |
-
})
|
191 |
-
// Expand Directories
|
192 |
-
.on("click", ".wpstg-expand-dirs", function (e) {
|
193 |
-
e.preventDefault();
|
194 |
-
|
195 |
-
var $this = $(this);
|
196 |
-
|
197 |
-
if (!$this.hasClass("disabled"))
|
198 |
-
{
|
199 |
-
$this.siblings(".wpstg-subdir").slideToggle();
|
200 |
}
|
201 |
})
|
202 |
-
|
203 |
-
|
204 |
-
|
|
|
205 |
|
206 |
-
|
207 |
-
{
|
208 |
-
$directory.parents(".wpstg-dir").children(".wpstg-check-dir").prop("checked", true);
|
209 |
-
$directory.find(".wpstg-expand-dirs").removeClass("disabled");
|
210 |
-
$directory.find(".wpstg-subdir .wpstg-check-dir").prop("checked", true);
|
211 |
-
}
|
212 |
-
else
|
213 |
-
{
|
214 |
-
$directory.find(".wpstg-dir .wpstg-check-dir").prop("checked", false);
|
215 |
-
$directory.find(".wpstg-expand-dirs, .wpstg-check-subdirs").addClass("disabled");
|
216 |
-
$directory.find(".wpstg-check-subdirs").data("action", "check").text("check");
|
217 |
-
//$directory.children(".wpstg-subdir").slideUp();
|
218 |
-
}
|
219 |
-
})
|
220 |
-
// When a directory name is Selected
|
221 |
-
.on("change", "href.wpstg-check-dir", function () {
|
222 |
-
var $directory = $(this).parent(".wpstg-dir");
|
223 |
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
|
241 |
-
|
242 |
-
|
243 |
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
}
|
249 |
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
},
|
259 |
-
function (response)
|
260 |
-
{
|
261 |
-
if (response.status === "success")
|
262 |
-
{
|
263 |
-
cache.get("#wpstg-new-clone-id").removeClass("wpstg-error-input");
|
264 |
-
cache.get("#wpstg-start-cloning").removeAttr("disabled");
|
265 |
-
cache.get("#wpstg-clone-id-error").text('').hide();
|
266 |
-
}
|
267 |
-
else
|
268 |
-
{
|
269 |
-
cache.get("#wpstg-new-clone-id").addClass("wpstg-error-input");
|
270 |
-
cache.get("#wpstg-start-cloning").prop("disabled", true);
|
271 |
-
cache.get("#wpstg-clone-id-error").text(response.message).show();
|
272 |
-
}
|
273 |
-
}
|
274 |
-
);
|
275 |
},
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
287 |
return;
|
288 |
-
|
289 |
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
|
296 |
-
|
297 |
path = path.replace(/\/+$/g, '') + '/' + slug + '/';
|
298 |
-
|
299 |
|
300 |
-
|
301 |
uri = uri.replace(/\/+$/g, '') + '/' + slug;
|
302 |
-
|
303 |
|
304 |
|
305 |
-
|
306 |
-
|
307 |
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
|
315 |
cloneActions();
|
316 |
};
|
@@ -318,161 +282,159 @@ var WPStaging = (function ($)
|
|
318 |
/**
|
319 |
* Clone actions
|
320 |
*/
|
321 |
-
var cloneActions = function ()
|
322 |
-
{
|
323 |
var $workFlow = cache.get("#wpstg-workflow");
|
324 |
|
325 |
$workFlow
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
}
|
332 |
-
|
333 |
-
var $this = $(this);
|
334 |
|
335 |
-
|
336 |
-
$this.prop("disabled", true);
|
337 |
|
338 |
-
|
339 |
-
|
340 |
|
341 |
-
|
342 |
-
|
343 |
|
344 |
-
|
|
|
345 |
|
346 |
-
|
347 |
-
})
|
348 |
-
// Resume cloning
|
349 |
-
.on("click", "#wpstg-resume-cloning", function () {
|
350 |
|
351 |
-
|
|
|
|
|
|
|
|
|
|
|
352 |
|
353 |
-
|
354 |
|
355 |
-
|
356 |
-
//that.progressBar = 0;
|
357 |
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
|
362 |
-
|
363 |
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
|
|
368 |
|
369 |
-
|
370 |
|
371 |
-
|
372 |
-
|
373 |
|
374 |
-
|
375 |
|
376 |
-
|
377 |
-
|
378 |
|
379 |
-
|
380 |
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
|
|
385 |
|
386 |
-
|
387 |
|
388 |
-
|
389 |
-
|
390 |
|
391 |
-
|
392 |
|
393 |
-
|
394 |
-
|
395 |
|
396 |
-
|
397 |
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
|
|
403 |
|
404 |
-
|
405 |
|
406 |
-
|
407 |
|
408 |
-
|
409 |
|
410 |
-
|
411 |
-
{
|
412 |
-
action: "wpstg_confirm_delete_clone",
|
413 |
-
nonce: wpstg.nonce,
|
414 |
-
clone: $(this).data("clone")
|
415 |
-
},
|
416 |
-
function (response)
|
417 |
{
|
|
|
|
|
|
|
|
|
|
|
418 |
cache.get("#wpstg-removing-clone").html(response);
|
419 |
|
420 |
$existingClones.children("img").remove();
|
421 |
|
422 |
-
cache.get("
|
423 |
},
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
|
|
430 |
|
431 |
-
|
432 |
|
433 |
-
|
434 |
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
|
447 |
-
|
448 |
|
449 |
-
|
450 |
|
451 |
-
|
452 |
-
{
|
453 |
-
action: "wpstg_scanning",
|
454 |
-
clone: clone,
|
455 |
-
nonce: wpstg.nonce
|
456 |
-
},
|
457 |
-
function (response)
|
458 |
{
|
459 |
-
|
460 |
-
|
|
|
|
|
|
|
|
|
461 |
showError(
|
462 |
-
|
463 |
-
|
464 |
}
|
465 |
|
466 |
$workFlow.removeClass("loading").html(response);
|
467 |
|
468 |
cache.get(".wpstg-current-step")
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
},
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
};
|
477 |
|
478 |
/**
|
@@ -482,15 +444,12 @@ var WPStaging = (function ($)
|
|
482 |
* @param {String} dataType
|
483 |
* @param {Boolean} showErrors
|
484 |
*/
|
485 |
-
var ajax = function (data, callback, dataType, showErrors, tryCount)
|
486 |
-
|
487 |
-
if ("undefined" === typeof (dataType))
|
488 |
-
{
|
489 |
dataType = "json";
|
490 |
}
|
491 |
|
492 |
-
if (false !== showErrors)
|
493 |
-
{
|
494 |
showErrors = true;
|
495 |
}
|
496 |
|
@@ -520,53 +479,47 @@ var WPStaging = (function ($)
|
|
520 |
} else {
|
521 |
var errorCode = "undefined" === typeof (xhr.status) ? "Unknown" : xhr.status;
|
522 |
showError(
|
523 |
-
|
524 |
-
|
525 |
}
|
526 |
|
527 |
|
528 |
-
|
529 |
},
|
530 |
success: function (data) {
|
531 |
-
if ("function" === typeof (callback))
|
532 |
-
{
|
533 |
callback(data);
|
534 |
}
|
535 |
},
|
536 |
statusCode: {
|
537 |
404: function (data) {
|
538 |
if (tryCount >= retryLimit) {
|
539 |
-
showError("Error 404 - Can't find ajax request URL! Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report.");
|
540 |
}
|
541 |
},
|
542 |
500: function () {
|
543 |
if (tryCount >= retryLimit) {
|
544 |
-
showError("Fatal Error 500 - Internal server error while processing the request! Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report.");
|
545 |
}
|
546 |
-
// var obj = new Object();
|
547 |
-
// obj.status = false;
|
548 |
-
// obj.error = 'custom error';
|
549 |
-
// return JSON.stringify(obj);
|
550 |
},
|
551 |
504: function () {
|
552 |
if (tryCount > retryLimit) {
|
553 |
-
showError("Error 504 - It looks like your server is rate limiting ajax requests. Please try to resume after a minute. If this still not works try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report.\n\ ");
|
554 |
}
|
555 |
|
556 |
},
|
557 |
502: function () {
|
558 |
if (tryCount >= retryLimit) {
|
559 |
-
showError("Error 502 - It looks like your server is rate limiting ajax requests. Please try to resume after a minute. If this still not works try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report.\n\ ");
|
560 |
}
|
561 |
},
|
562 |
503: function () {
|
563 |
if (tryCount >= retryLimit) {
|
564 |
-
showError("Error 503 - It looks like your server is rate limiting ajax requests. Please try to resume after a minute. If this still not works try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report.\n\ ");
|
565 |
}
|
566 |
},
|
567 |
429: function () {
|
568 |
if (tryCount >= retryLimit) {
|
569 |
-
showError("Error 429 - It looks like your server is rate limiting ajax requests. Please try to resume after a minute. If this still not works try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report.\n\ ");
|
570 |
}
|
571 |
},
|
572 |
403: function () {
|
@@ -581,112 +534,103 @@ var WPStaging = (function ($)
|
|
581 |
/**
|
582 |
* Next / Previous Step Clicks to Navigate Through Staging Job
|
583 |
*/
|
584 |
-
var stepButtons = function ()
|
585 |
-
|
586 |
var $workFlow = cache.get("#wpstg-workflow");
|
587 |
|
588 |
$workFlow
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
if ($this.data("action") === "wpstg_update") {
|
597 |
-
// Update Clone - confirmed
|
598 |
-
if (!confirm("STOP! This will overwrite your staging site with all selected data from the live site! This should be used only if you want to clone again your production site. Are you sure you want to do this? \n\nMake sure to exclude all tables and folders which you do not want to overwrite, first! \n\nDo not necessarily cancel the updating process! This can break your staging site. \n\n\Make sure you have a backop of your staging website before you proceed."))
|
599 |
-
{
|
600 |
-
return false;
|
601 |
-
}
|
602 |
|
|
|
|
|
|
|
|
|
603 |
}
|
604 |
|
|
|
605 |
|
606 |
-
// Button is disabled
|
607 |
-
if ($this.attr("disabled"))
|
608 |
-
{
|
609 |
-
return false;
|
610 |
-
}
|
611 |
|
612 |
-
|
613 |
-
|
|
|
|
|
614 |
|
615 |
-
|
616 |
-
|
617 |
-
action: $this.data("action"),
|
618 |
-
nonce: wpstg.nonce
|
619 |
-
};
|
620 |
|
621 |
-
|
622 |
-
|
|
|
|
|
|
|
623 |
|
624 |
-
|
|
|
625 |
|
626 |
-
|
627 |
|
628 |
-
|
629 |
-
ajax(
|
630 |
-
that.data,
|
631 |
-
function (response) {
|
632 |
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
"Something went wrong!<br/><br/> Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low '" +
|
638 |
-
"and try again. If that does not help, " +
|
639 |
-
"<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
|
640 |
-
);
|
641 |
-
}
|
642 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
643 |
|
644 |
-
if (response.length < 1)
|
645 |
-
{
|
646 |
-
showError(
|
647 |
-
"Something went wrong! No response. Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low '" +
|
648 |
-
"and try again. If that does not help, " +
|
649 |
-
"<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
|
650 |
-
);
|
651 |
-
}
|
652 |
|
653 |
-
|
654 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
655 |
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
|
661 |
-
|
662 |
-
|
663 |
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
};
|
676 |
|
677 |
/**
|
678 |
* Get Included (Checked) Database Tables
|
679 |
* @returns {Array}
|
680 |
*/
|
681 |
-
var getIncludedTables = function ()
|
682 |
-
{
|
683 |
var includedTables = [];
|
684 |
|
685 |
-
// $(".wpstg-db-table input:checked").each(function () {
|
686 |
-
// includedTables.push(this.name);
|
687 |
-
// });
|
688 |
$("#wpstg_select_tables_cloning option:selected").each(function () {
|
689 |
-
//console.log(this);
|
690 |
includedTables.push(this.value);
|
691 |
});
|
692 |
|
@@ -698,16 +642,12 @@ var WPStaging = (function ($)
|
|
698 |
* Not used anymore!
|
699 |
* @returns {Array}
|
700 |
*/
|
701 |
-
var getExcludedTables = function ()
|
702 |
-
{
|
703 |
var excludedTables = [];
|
704 |
|
705 |
$(".wpstg-db-table input:not(:checked)").each(function () {
|
706 |
excludedTables.push(this.name);
|
707 |
});
|
708 |
-
// $("#wpstg_select_tables_cloning option:not(:selected)").each(function () {
|
709 |
-
// excludedTables.push(this.name);
|
710 |
-
// });
|
711 |
|
712 |
return excludedTables;
|
713 |
};
|
@@ -716,8 +656,7 @@ var WPStaging = (function ($)
|
|
716 |
* Get Included Directories
|
717 |
* @returns {Array}
|
718 |
*/
|
719 |
-
var getIncludedDirectories = function ()
|
720 |
-
{
|
721 |
var includedDirectories = [];
|
722 |
|
723 |
$(".wpstg-dir input:checked.wpstg-root").each(function () {
|
@@ -732,8 +671,7 @@ var WPStaging = (function ($)
|
|
732 |
* Get Excluded Directories
|
733 |
* @returns {Array}
|
734 |
*/
|
735 |
-
var getExcludedDirectories = function ()
|
736 |
-
{
|
737 |
var excludedDirectories = [];
|
738 |
|
739 |
$(".wpstg-dir input:not(:checked).wpstg-root").each(function () {
|
@@ -749,8 +687,7 @@ var WPStaging = (function ($)
|
|
749 |
* All directories except wp-content, wp-admin, wp-includes
|
750 |
* @returns {Array}
|
751 |
*/
|
752 |
-
var getIncludedExtraDirectories = function ()
|
753 |
-
{
|
754 |
// Add directories from the root level
|
755 |
var extraDirectories = [];
|
756 |
$(".wpstg-dir input:checked.wpstg-extra").each(function () {
|
@@ -768,33 +705,12 @@ var WPStaging = (function ($)
|
|
768 |
return extraDirectories.concat(extraCustomDirectories);
|
769 |
};
|
770 |
|
771 |
-
/**
|
772 |
-
* Get Included Extra Directories
|
773 |
-
* @returns {Array}
|
774 |
-
*/
|
775 |
-
// var getIncludedExtraDirectories = function ()
|
776 |
-
// {
|
777 |
-
// var extraDirectories = [];
|
778 |
-
//
|
779 |
-
// if (!$("#wpstg_extraDirectories").val()) {
|
780 |
-
// return extraDirectories;
|
781 |
-
// }
|
782 |
-
//
|
783 |
-
// var extraDirectories = $("#wpstg_extraDirectories").val().split(/\r?\n/);
|
784 |
-
// console.log(extraDirectories);
|
785 |
-
//
|
786 |
-
// //excludedDirectories.push($this.val());
|
787 |
-
//
|
788 |
-
// return extraDirectories;
|
789 |
-
// };
|
790 |
|
791 |
/**
|
792 |
* Get Cloning Step Data
|
793 |
*/
|
794 |
-
var getCloningData = function ()
|
795 |
-
|
796 |
-
if ("wpstg_cloning" !== that.data.action && "wpstg_update" !== that.data.action)
|
797 |
-
{
|
798 |
return;
|
799 |
}
|
800 |
|
@@ -813,48 +729,44 @@ var WPStaging = (function ($)
|
|
813 |
var cloneDir = $("#wpstg_clone_dir").val();
|
814 |
that.data.cloneDir = encodeURIComponent($.trim(cloneDir));
|
815 |
that.data.cloneHostname = $("#wpstg_clone_hostname").val();
|
816 |
-
//console.log(that.data);
|
817 |
|
818 |
};
|
819 |
|
820 |
/**
|
821 |
* Loads Overview (first step) of Staging Job
|
822 |
*/
|
823 |
-
var loadOverview = function ()
|
824 |
-
{
|
825 |
var $workFlow = cache.get("#wpstg-workflow");
|
826 |
|
827 |
$workFlow.addClass("loading");
|
828 |
|
829 |
ajax(
|
830 |
-
{
|
831 |
-
action: "wpstg_overview",
|
832 |
-
nonce: wpstg.nonce
|
833 |
-
},
|
834 |
-
function (response) {
|
835 |
-
|
836 |
-
if (response.length < 1)
|
837 |
{
|
838 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
839 |
"Something went wrong! No response. Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
|
840 |
-
|
841 |
-
|
842 |
|
843 |
-
|
844 |
|
845 |
-
|
846 |
-
|
847 |
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
};
|
852 |
|
853 |
/**
|
854 |
* Load Tabs
|
855 |
*/
|
856 |
-
var tabs = function ()
|
857 |
-
{
|
858 |
|
859 |
cache.get("#wpstg-workflow").on("click", ".wpstg-tab-header", function (e) {
|
860 |
e.preventDefault();
|
@@ -866,17 +778,13 @@ var WPStaging = (function ($)
|
|
866 |
|
867 |
$section.slideToggle();
|
868 |
|
869 |
-
if ($this.hasClass("expand"))
|
870 |
-
{
|
871 |
$this.find(".wpstg-tab-triangle").html("▼");
|
872 |
-
}
|
873 |
-
else
|
874 |
-
{
|
875 |
$this.find(".wpstg-tab-triangle").html("►");
|
876 |
}
|
877 |
|
878 |
|
879 |
-
|
880 |
});
|
881 |
};
|
882 |
|
@@ -884,176 +792,154 @@ var WPStaging = (function ($)
|
|
884 |
* Delete Clone
|
885 |
* @param {String} clone
|
886 |
*/
|
887 |
-
var deleteClone = function (clone)
|
888 |
-
{
|
889 |
|
890 |
var deleteDir = $("#deleteDirectory:checked").data("deletepath");
|
891 |
|
892 |
ajax(
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
// Error
|
904 |
-
if ("undefined" !== typeof response.error && "undefined" !== typeof response.message) {
|
905 |
-
showError(
|
906 |
-
"Something went wrong! Error: " + response.message + ". Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
|
907 |
-
);
|
908 |
-
console.log(response.message);
|
909 |
-
}
|
910 |
|
911 |
-
|
912 |
-
|
913 |
|
914 |
-
|
915 |
|
916 |
-
|
917 |
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
}
|
922 |
|
923 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
924 |
return;
|
925 |
}
|
926 |
-
}
|
927 |
-
// continue
|
928 |
-
if (true !== response)
|
929 |
-
{
|
930 |
-
deleteClone(clone);
|
931 |
-
return;
|
932 |
-
}
|
933 |
|
934 |
-
|
935 |
);
|
936 |
};
|
937 |
|
938 |
/**
|
939 |
* Cancel Cloning Process
|
940 |
*/
|
941 |
-
var cancelCloning = function ()
|
942 |
-
{
|
943 |
|
944 |
that.timer('stop');
|
945 |
|
946 |
|
947 |
-
if (true === that.isFinished)
|
948 |
-
{
|
949 |
return true;
|
950 |
}
|
951 |
|
952 |
ajax(
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
960 |
|
|
|
|
|
|
|
|
|
|
|
961 |
|
962 |
-
if (response && "undefined" !== typeof (response.delete) && response.delete === "finished") {
|
963 |
-
cache.get("#wpstg-loader").hide();
|
964 |
// Load overview
|
965 |
loadOverview();
|
966 |
-
return;
|
967 |
-
}
|
968 |
-
|
969 |
-
if (true !== response)
|
970 |
-
{
|
971 |
-
// continue
|
972 |
-
cancelCloning();
|
973 |
-
return;
|
974 |
}
|
975 |
-
|
976 |
-
// Load overview
|
977 |
-
loadOverview();
|
978 |
-
}
|
979 |
);
|
980 |
};
|
981 |
|
982 |
/**
|
983 |
* Cancel Cloning Process
|
984 |
*/
|
985 |
-
var cancelCloningUpdate = function ()
|
986 |
-
|
987 |
-
if (true === that.isFinished)
|
988 |
-
{
|
989 |
return true;
|
990 |
}
|
991 |
|
992 |
ajax(
|
993 |
-
|
994 |
-
|
995 |
-
|
996 |
-
|
997 |
-
|
998 |
-
|
999 |
-
{
|
1000 |
|
1001 |
|
1002 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1003 |
// Load overview
|
1004 |
loadOverview();
|
1005 |
-
return;
|
1006 |
}
|
1007 |
-
|
1008 |
-
if (true !== response)
|
1009 |
-
{
|
1010 |
-
// continue
|
1011 |
-
cancelCloningUpdate();
|
1012 |
-
return;
|
1013 |
-
}
|
1014 |
-
|
1015 |
-
// Load overview
|
1016 |
-
loadOverview();
|
1017 |
-
}
|
1018 |
);
|
1019 |
};
|
1020 |
|
1021 |
/**
|
1022 |
* Cancel Cloning Process
|
1023 |
*/
|
1024 |
-
var restart = function ()
|
1025 |
-
|
1026 |
-
if (true === that.isFinished)
|
1027 |
-
{
|
1028 |
return true;
|
1029 |
}
|
1030 |
|
1031 |
ajax(
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1040 |
|
1041 |
-
if (response && "undefined" !== typeof (response.delete) && response.delete === "finished") {
|
1042 |
// Load overview
|
1043 |
loadOverview();
|
1044 |
-
return;
|
1045 |
-
}
|
1046 |
-
|
1047 |
-
if (true !== response)
|
1048 |
-
{
|
1049 |
-
// continue
|
1050 |
-
cancelCloningUpdate();
|
1051 |
-
return;
|
1052 |
}
|
1053 |
-
|
1054 |
-
// Load overview
|
1055 |
-
loadOverview();
|
1056 |
-
}
|
1057 |
);
|
1058 |
};
|
1059 |
|
@@ -1062,7 +948,7 @@ var WPStaging = (function ($)
|
|
1062 |
* @returns void
|
1063 |
*/
|
1064 |
var logscroll = function () {
|
1065 |
-
var $div = cache.get("
|
1066 |
if ("undefined" !== typeof ($div[0])) {
|
1067 |
$div.scrollTop($div[0].scrollHeight);
|
1068 |
}
|
@@ -1073,8 +959,7 @@ var WPStaging = (function ($)
|
|
1073 |
* @param string log
|
1074 |
* @returns void
|
1075 |
*/
|
1076 |
-
var getLogs = function (log)
|
1077 |
-
{
|
1078 |
if (log != null && "undefined" !== typeof (log)) {
|
1079 |
if (log.constructor === Array) {
|
1080 |
$.each(log, function (index, value) {
|
@@ -1082,13 +967,13 @@ var WPStaging = (function ($)
|
|
1082 |
return;
|
1083 |
}
|
1084 |
if (value.type === 'ERROR') {
|
1085 |
-
cache.get("
|
1086 |
} else {
|
1087 |
-
cache.get("
|
1088 |
}
|
1089 |
})
|
1090 |
} else {
|
1091 |
-
cache.get("
|
1092 |
}
|
1093 |
}
|
1094 |
logscroll();
|
@@ -1101,33 +986,60 @@ var WPStaging = (function ($)
|
|
1101 |
*/
|
1102 |
var checkDiskSpace = function () {
|
1103 |
cache.get("#wpstg-check-space").on("click", function (e) {
|
1104 |
-
cache.get("
|
1105 |
console.log("check disk space");
|
1106 |
ajax(
|
1107 |
-
{
|
1108 |
-
action: "wpstg_check_disk_space",
|
1109 |
-
nonce: wpstg.nonce
|
1110 |
-
},
|
1111 |
-
function (response)
|
1112 |
-
{
|
1113 |
-
if (false === response)
|
1114 |
{
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
|
|
|
|
|
|
|
|
|
|
1119 |
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
);
|
1128 |
});
|
1129 |
}
|
1130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1131 |
|
1132 |
/**
|
1133 |
* Count up processing execution time
|
@@ -1173,11 +1085,12 @@ var WPStaging = (function ($)
|
|
1173 |
*/
|
1174 |
that.startCloning = (function () {
|
1175 |
|
|
|
|
|
1176 |
// Register function for checking disk space
|
1177 |
checkDiskSpace();
|
1178 |
|
1179 |
-
if ("wpstg_cloning" !== that.data.action && "wpstg_update" !== that.data.action)
|
1180 |
-
{
|
1181 |
return;
|
1182 |
}
|
1183 |
|
@@ -1188,12 +1101,11 @@ var WPStaging = (function ($)
|
|
1188 |
|
1189 |
// Functions
|
1190 |
// Start
|
1191 |
-
function start()
|
1192 |
-
{
|
1193 |
|
1194 |
console.log("Starting cloning process...");
|
1195 |
|
1196 |
-
cache.get("
|
1197 |
cache.get("#wpstg-cancel-cloning").text('Cancel');
|
1198 |
cache.get("#wpstg-resume-cloning").hide();
|
1199 |
cache.get("#wpstg-error-details").hide();
|
@@ -1210,113 +1122,79 @@ var WPStaging = (function ($)
|
|
1210 |
}
|
1211 |
|
1212 |
|
1213 |
-
|
1214 |
/**
|
1215 |
* Start ajax processing
|
1216 |
* @returns string
|
1217 |
*/
|
1218 |
var processing = function () {
|
1219 |
|
1220 |
-
if (true === that.isCancelled)
|
1221 |
-
{
|
1222 |
return false;
|
1223 |
}
|
1224 |
|
1225 |
-
|
1226 |
-
|
1227 |
-
//console.log("Start ajax processing");
|
1228 |
-
|
1229 |
-
// Show loader gif
|
1230 |
-
cache.get("#wpstg-loader").show();
|
1231 |
-
cache.get(".wpstg-loader").show();
|
1232 |
|
1233 |
// Show logging window
|
1234 |
-
cache.get('
|
1235 |
|
1236 |
WPStaging.ajax(
|
1237 |
-
{
|
1238 |
-
action: "wpstg_processing",
|
1239 |
-
nonce: wpstg.nonce,
|
1240 |
-
excludedTables: getExcludedTables(),
|
1241 |
-
includedDirectories: getIncludedDirectories(),
|
1242 |
-
excludedDirectories: getExcludedDirectories(),
|
1243 |
-
extraDirectories: getIncludedExtraDirectories()
|
1244 |
-
},
|
1245 |
-
function (response)
|
1246 |
-
{
|
1247 |
-
// Undefined Error
|
1248 |
-
if (false === response)
|
1249 |
{
|
1250 |
-
|
1251 |
-
|
1252 |
-
|
1253 |
-
|
1254 |
-
|
1255 |
-
|
1256 |
-
}
|
1257 |
-
|
1258 |
-
// Throw Error
|
1259 |
-
if ("undefined" !== typeof (response.error) && response.error) {
|
1260 |
-
console.log(response.message);
|
1261 |
-
showError(
|
1262 |
-
"Something went wrong! Error: " + response.message + ". Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
|
1263 |
-
);
|
1264 |
|
1265 |
-
|
1266 |
-
}
|
1267 |
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
|
1272 |
-
|
1273 |
-
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
|
1280 |
-
|
|
|
|
|
|
|
|
|
1281 |
processing();
|
1282 |
-
}
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
|
1287 |
-
|
1288 |
-
|
1289 |
-
|
1290 |
-
} else if ('finished' === response.status || ("undefined" !== typeof (response.job_done) && response.job_done)) {
|
1291 |
-
finish(response);
|
1292 |
-
}
|
1293 |
-
;
|
1294 |
-
},
|
1295 |
-
"json",
|
1296 |
-
false
|
1297 |
-
);
|
1298 |
};
|
1299 |
|
1300 |
// Finish
|
1301 |
-
function finish(response)
|
1302 |
-
{
|
1303 |
|
1304 |
-
if (true === that.getLogs)
|
1305 |
-
{
|
1306 |
getLogs();
|
1307 |
}
|
1308 |
|
1309 |
progressBar(response);
|
1310 |
|
1311 |
// Add Log
|
1312 |
-
if ("undefined" !== typeof (response.last_msg))
|
1313 |
-
{
|
1314 |
getLogs(response.last_msg);
|
1315 |
}
|
1316 |
|
1317 |
console.log("Cloning process finished");
|
1318 |
|
1319 |
-
cache.get("
|
1320 |
cache.get("#wpstg-processing-header").html('Processing Complete');
|
1321 |
$("#wpstg-processing-status").text("Succesfully finished");
|
1322 |
|
@@ -1339,12 +1217,13 @@ var WPStaging = (function ($)
|
|
1339 |
that.timer('stop');
|
1340 |
|
1341 |
|
1342 |
-
cache.get("
|
1343 |
cache.get("#wpstg-processing-header").html('Processing Complete');
|
1344 |
|
1345 |
return false;
|
1346 |
|
1347 |
}
|
|
|
1348 |
/**
|
1349 |
* Add percentage progress bar
|
1350 |
* @param object response
|
@@ -1354,10 +1233,6 @@ var WPStaging = (function ($)
|
|
1354 |
if ("undefined" === typeof (response.percentage))
|
1355 |
return false;
|
1356 |
|
1357 |
-
// //if (restart){
|
1358 |
-
// cache.get("#wpstg-db-progress").width('1%');
|
1359 |
-
// //}
|
1360 |
-
|
1361 |
if (response.job === 'database') {
|
1362 |
cache.get("#wpstg-progress-db").width(response.percentage * 0.2 + '%').html(response.percentage + '%');
|
1363 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Step 1 of 4 Cloning Database Tables...');
|
@@ -1401,6 +1276,7 @@ var WPStaging = (function ($)
|
|
1401 |
elements();
|
1402 |
stepButtons();
|
1403 |
tabs();
|
|
|
1404 |
});
|
1405 |
|
1406 |
/**
|
@@ -1412,6 +1288,365 @@ var WPStaging = (function ($)
|
|
1412 |
that.getLogs = getLogs;
|
1413 |
that.loadOverview = loadOverview;
|
1414 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1415 |
return that;
|
1416 |
})(jQuery);
|
1417 |
|
@@ -1425,11 +1660,16 @@ jQuery(document).ready(function () {
|
|
1425 |
jQuery(document).ready(function ($) {
|
1426 |
|
1427 |
$('#wpstg-report-issue-button').click(function (e) {
|
1428 |
-
console.log('report issue');
|
1429 |
$('.wpstg-report-issue-form').toggleClass('wpstg-report-show');
|
1430 |
e.preventDefault();
|
1431 |
});
|
1432 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1433 |
$('#wpstg-report-cancel').click(function (e) {
|
1434 |
$('.wpstg-report-issue-form').removeClass('wpstg-report-show');
|
1435 |
e.preventDefault();
|
1 |
"use strict";
|
2 |
|
3 |
+
var WPStaging = (function ($) {
|
|
|
4 |
var that = {
|
5 |
+
isCancelled: false,
|
6 |
+
isFinished: false,
|
7 |
+
getLogs: false,
|
8 |
+
time: 1,
|
9 |
+
executionTime: false,
|
10 |
+
progressBar: 0
|
11 |
+
},
|
12 |
+
cache = {elements: []},
|
13 |
+
timeout, ajaxSpinner;
|
14 |
|
15 |
/**
|
16 |
* Get / Set Cache for Selector
|
17 |
* @param {String} selector
|
18 |
* @returns {*}
|
19 |
*/
|
20 |
+
cache.get = function (selector) {
|
|
|
21 |
// It is already cached!
|
22 |
+
if ($.inArray(selector, cache.elements) !== -1) {
|
|
|
23 |
return cache.elements[selector];
|
24 |
}
|
25 |
|
33 |
* Refreshes given cache
|
34 |
* @param {String} selector
|
35 |
*/
|
36 |
+
cache.refresh = function (selector) {
|
|
|
37 |
selector.elements[selector] = jQuery(selector);
|
38 |
};
|
39 |
|
41 |
* Show and Log Error Message
|
42 |
* @param {String} message
|
43 |
*/
|
44 |
+
var showError = function (message) {
|
|
|
45 |
cache.get("#wpstg-try-again").css("display", "inline-block");
|
46 |
cache.get("#wpstg-cancel-cloning").text("Reset");
|
47 |
cache.get("#wpstg-resume-cloning").show();
|
48 |
cache.get("#wpstg-error-wrapper").show();
|
49 |
cache.get("#wpstg-error-details").show().html(message);
|
50 |
cache.get("#wpstg-removing-clone").removeClass("loading");
|
51 |
+
cache.get(".wpstg-loader").hide();
|
52 |
};
|
53 |
|
54 |
+
/**
|
55 |
+
*
|
56 |
+
* @param response the error object
|
57 |
+
* @param prependMessage Overwrite default error message at beginning
|
58 |
+
* @param appendMessage Overwrite default error message at end
|
59 |
+
* @returns void
|
60 |
+
*/
|
61 |
+
|
62 |
+
var showAjaxFatalError = function (response, prependMessage, appendMessage) {
|
63 |
+
prependMessage = prependMessage ? prependMessage + '<br/><br/>' : 'Something went wrong! <br/><br/>';
|
64 |
+
appendMessage = appendMessage ? appendMessage + '<br/><br/>' : '<br/><br/>Please try the <a href=\'https://wp-staging.com/docs/wp-staging-settings-for-small-servers/\' target=\'_blank\'>WP Staging Small Server Settings</a> or submit an error report and contact us.';
|
65 |
+
|
66 |
+
if (response === false) {
|
67 |
+
showError(prependMessage + ' Error: No response.' + appendMessage);
|
68 |
+
return;
|
69 |
+
}
|
70 |
+
|
71 |
+
if (typeof response.error !== 'undefined' && response.error) {
|
72 |
+
console.error(response.message);
|
73 |
+
showError(prependMessage + ' Error: ' + response.message + appendMessage);
|
74 |
+
return;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
/** Hide and reset previous thrown visible errors */
|
79 |
+
var resetErrors = function () {
|
80 |
+
cache.get("#wpstg-error-details").hide().html('');
|
81 |
+
}
|
82 |
+
|
83 |
+
var slugify = function (url) {
|
84 |
+
return url.toString()
|
85 |
+
.toLowerCase()
|
86 |
+
.normalize('NFD')
|
87 |
+
.replace(/[\u0300-\u036f]/g, '')
|
88 |
+
.replace(/\s+/g, '-')
|
89 |
+
.replace(/&/g, '-and-')
|
90 |
+
.replace(/[^a-z0-9\-]/g, '')
|
91 |
+
.replace(/-+/g, '-')
|
92 |
+
.replace(/^-*/, '')
|
93 |
+
.replace(/-*$/, '')
|
94 |
+
;
|
95 |
};
|
96 |
|
97 |
+
|
98 |
/**
|
99 |
* Common Elements
|
100 |
*/
|
101 |
+
var elements = function () {
|
|
|
102 |
var $workFlow = cache.get("#wpstg-workflow"),
|
103 |
+
isAllChecked = true,
|
104 |
+
urlSpinner = ajaxurl.replace("/admin-ajax.php", '') + "/images/spinner",
|
105 |
+
timer;
|
106 |
|
107 |
+
if (2 < window.devicePixelRatio) {
|
|
|
108 |
urlSpinner += "-2x";
|
109 |
}
|
110 |
|
112 |
|
113 |
ajaxSpinner = "<img src=''" + urlSpinner + "' alt='' class='ajax-spinner general-spinner' />";
|
114 |
|
115 |
+
var getBaseValues = function () {
|
116 |
+
var path = $('#wpstg-use-target-dir').data('base-path');
|
117 |
+
var uri = $('#wpstg-use-target-hostname').data('base-uri');
|
118 |
+
return {
|
119 |
+
path
|
120 |
+
};
|
121 |
};
|
122 |
|
123 |
$workFlow
|
124 |
+
// Check / Un-check All Database Tables New
|
125 |
+
.on("click", ".wpstg-button-unselect", function (e) {
|
126 |
+
e.preventDefault();
|
127 |
+
|
128 |
+
if (false === isAllChecked) {
|
129 |
+
console.log('true');
|
130 |
+
cache.get("#wpstg_select_tables_cloning .wpstg-db-table").prop("selected", "selected");
|
131 |
+
cache.get(".wpstg-button-unselect").text("Unselect All");
|
132 |
+
cache.get(".wpstg-db-table-checkboxes").prop("checked", true);
|
133 |
+
isAllChecked = true;
|
134 |
+
} else {
|
135 |
+
console.log('false');
|
136 |
+
cache.get("#wpstg_select_tables_cloning .wpstg-db-table").prop("selected", false);
|
137 |
+
cache.get(".wpstg-button-unselect").text("Select All");
|
138 |
+
cache.get(".wpstg-db-table-checkboxes").prop("checked", false);
|
139 |
+
isAllChecked = false;
|
140 |
+
}
|
141 |
+
})
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Select tables with certain tbl prefix | NEW
|
145 |
+
* @param obj e
|
146 |
+
* @returns {undefined}
|
147 |
+
*/
|
148 |
+
.on("click", ".wpstg-button-select", function (e) {
|
149 |
+
e.preventDefault();
|
150 |
+
$("#wpstg_select_tables_cloning .wpstg-db-table").each(function () {
|
151 |
+
if (wpstg.isMultisite == 1) {
|
152 |
+
if ($(this).attr('name').match("^" + wpstg.tblprefix + "([^0-9])_*")) {
|
153 |
+
$(this).prop("selected", "selected");
|
154 |
+
} else {
|
155 |
+
$(this).prop("selected", false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
}
|
157 |
+
}
|
158 |
|
159 |
+
if (wpstg.isMultisite == 0) {
|
160 |
+
if ($(this).attr('name').match("^" + wpstg.tblprefix)) {
|
161 |
+
$(this).prop("selected", "selected");
|
162 |
+
} else {
|
163 |
+
$(this).prop("selected", false);
|
|
|
164 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
}
|
166 |
})
|
167 |
+
})
|
168 |
+
// Expand Directories
|
169 |
+
.on("click", ".wpstg-expand-dirs", function (e) {
|
170 |
+
e.preventDefault();
|
171 |
|
172 |
+
var $this = $(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
|
174 |
+
if (!$this.hasClass("disabled")) {
|
175 |
+
$this.siblings(".wpstg-subdir").slideToggle();
|
176 |
+
}
|
177 |
+
})
|
178 |
+
// When a directory checkbox is Selected
|
179 |
+
.on("change", "input.wpstg-check-dir", function () {
|
180 |
+
var $directory = $(this).parent(".wpstg-dir");
|
181 |
+
|
182 |
+
if (this.checked) {
|
183 |
+
$directory.parents(".wpstg-dir").children(".wpstg-check-dir").prop("checked", true);
|
184 |
+
$directory.find(".wpstg-expand-dirs").removeClass("disabled");
|
185 |
+
$directory.find(".wpstg-subdir .wpstg-check-dir").prop("checked", true);
|
186 |
+
} else {
|
187 |
+
$directory.find(".wpstg-dir .wpstg-check-dir").prop("checked", false);
|
188 |
+
$directory.find(".wpstg-expand-dirs, .wpstg-check-subdirs").addClass("disabled");
|
189 |
+
$directory.find(".wpstg-check-subdirs").data("action", "check").text("check");
|
190 |
+
}
|
191 |
+
})
|
192 |
+
// When a directory name is Selected
|
193 |
+
.on("change", "href.wpstg-check-dir", function () {
|
194 |
+
var $directory = $(this).parent(".wpstg-dir");
|
195 |
+
|
196 |
+
if (this.checked) {
|
197 |
+
$directory.parents(".wpstg-dir").children(".wpstg-check-dir").prop("checked", true);
|
198 |
+
$directory.find(".wpstg-expand-dirs").removeClass("disabled");
|
199 |
+
$directory.find(".wpstg-subdir .wpstg-check-dir").prop("checked", true);
|
200 |
+
} else {
|
201 |
+
$directory.find(".wpstg-dir .wpstg-check-dir").prop("checked", false);
|
202 |
+
$directory.find(".wpstg-expand-dirs, .wpstg-check-subdirs").addClass("disabled");
|
203 |
+
$directory.find(".wpstg-check-subdirs").data("action", "check").text("check");
|
204 |
+
}
|
205 |
+
})
|
206 |
+
// Check the max length of the clone name and if the clone name already exists
|
207 |
+
.on("keyup", "#wpstg-new-clone-id", function () {
|
208 |
|
209 |
+
// Hide previous errors
|
210 |
+
document.getElementById('wpstg-error-details').style.display = "none";
|
211 |
|
212 |
+
// This request was already sent, clear it up!
|
213 |
+
if ("number" === typeof (timer)) {
|
214 |
+
clearInterval(timer);
|
215 |
+
}
|
|
|
216 |
|
217 |
+
var cloneID = this.value;
|
218 |
+
|
219 |
+
timer = setTimeout(
|
220 |
+
function () {
|
221 |
+
ajax(
|
222 |
+
{
|
223 |
+
action: "wpstg_check_clone",
|
224 |
+
cloneID: cloneID
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
},
|
226 |
+
function (response) {
|
227 |
+
if (response.status === "success") {
|
228 |
+
cache.get("#wpstg-new-clone-id").removeClass("wpstg-error-input");
|
229 |
+
cache.get("#wpstg-start-cloning").removeAttr("disabled");
|
230 |
+
cache.get("#wpstg-clone-id-error").text('').hide();
|
231 |
+
} else {
|
232 |
+
cache.get("#wpstg-new-clone-id").addClass("wpstg-error-input");
|
233 |
+
cache.get("#wpstg-start-cloning").prop("disabled", true);
|
234 |
+
cache.get("#wpstg-clone-id-error").text(response.message).show();
|
235 |
+
}
|
236 |
+
}
|
237 |
+
);
|
238 |
+
},
|
239 |
+
500
|
240 |
+
);
|
241 |
+
})
|
242 |
+
// Restart cloning process
|
243 |
+
.on("click", "#wpstg-start-cloning", function () {
|
244 |
+
resetErrors();
|
245 |
+
that.isCancelled = false;
|
246 |
+
that.getLogs = false;
|
247 |
+
that.progressBar = 0;
|
248 |
+
})
|
249 |
+
.on('input', '#wpstg-new-clone-id', function () {
|
250 |
+
if ($('#wpstg-clone-directory').length < 1) {
|
251 |
return;
|
252 |
+
}
|
253 |
|
254 |
+
var slug = slugify(this.value);
|
255 |
+
var $targetDir = $('#wpstg-use-target-dir');
|
256 |
+
var $targetUri = $('#wpstg-use-target-hostname');
|
257 |
+
var path = $targetDir.data('base-path');
|
258 |
+
var uri = $targetUri.data('base-uri');
|
259 |
|
260 |
+
if (path) {
|
261 |
path = path.replace(/\/+$/g, '') + '/' + slug + '/';
|
262 |
+
}
|
263 |
|
264 |
+
if (uri) {
|
265 |
uri = uri.replace(/\/+$/g, '') + '/' + slug;
|
266 |
+
}
|
267 |
|
268 |
|
269 |
+
$('.wpstg-use-target-dir--value').text(path);
|
270 |
+
$('.wpstg-use-target-hostname--value').text(uri);
|
271 |
|
272 |
+
$targetDir.attr('data-path', path);
|
273 |
+
$targetUri.attr('data-uri', uri);
|
274 |
+
$('#wpstg_clone_dir').attr('placeholder', path);
|
275 |
+
$('#wpstg_clone_hostname').attr('placeholder', uri);
|
276 |
+
})
|
277 |
+
;
|
278 |
|
279 |
cloneActions();
|
280 |
};
|
282 |
/**
|
283 |
* Clone actions
|
284 |
*/
|
285 |
+
var cloneActions = function () {
|
|
|
286 |
var $workFlow = cache.get("#wpstg-workflow");
|
287 |
|
288 |
$workFlow
|
289 |
+
// Cancel cloning
|
290 |
+
.on("click", "#wpstg-cancel-cloning", function () {
|
291 |
+
if (!confirm("Are you sure you want to cancel cloning process?")) {
|
292 |
+
return false;
|
293 |
+
}
|
|
|
|
|
|
|
294 |
|
295 |
+
var $this = $(this);
|
|
|
296 |
|
297 |
+
$("#wpstg-try-again, #wpstg-home-link").hide();
|
298 |
+
$this.prop("disabled", true);
|
299 |
|
300 |
+
that.isCancelled = true;
|
301 |
+
that.progressBar = 0;
|
302 |
|
303 |
+
$("#wpstg-processing-status").text("Please wait...this can take up a while.");
|
304 |
+
$(".wpstg-loader, #wpstg-show-log-button").hide();
|
305 |
|
306 |
+
$this.parent().append(ajaxSpinner);
|
|
|
|
|
|
|
307 |
|
308 |
+
cancelCloning();
|
309 |
+
})
|
310 |
+
// Resume cloning
|
311 |
+
.on("click", "#wpstg-resume-cloning", function () {
|
312 |
+
resetErrors();
|
313 |
+
var $this = $(this);
|
314 |
|
315 |
+
$("#wpstg-try-again, #wpstg-home-link").hide();
|
316 |
|
317 |
+
that.isCancelled = false;
|
|
|
318 |
|
319 |
+
$("#wpstg-processing-status").text("Try to resume cloning process...");
|
320 |
+
$("#wpstg-error-details").hide();
|
321 |
+
$(".wpstg-loader").show();
|
322 |
|
323 |
+
$this.parent().append(ajaxSpinner);
|
324 |
|
325 |
+
that.startCloning();
|
326 |
+
})
|
327 |
+
// Cancel update cloning
|
328 |
+
.on("click", "#wpstg-cancel-cloning-update", function () {
|
329 |
+
resetErrors();
|
330 |
|
331 |
+
var $this = $(this);
|
332 |
|
333 |
+
$("#wpstg-try-again, #wpstg-home-link").hide();
|
334 |
+
$this.prop("disabled", true);
|
335 |
|
336 |
+
that.isCancelled = true;
|
337 |
|
338 |
+
$("#wpstg-cloning-result").text("Please wait...this can take up a while.");
|
339 |
+
$(".wpstg-loader, #wpstg-show-log-button").hide();
|
340 |
|
341 |
+
$this.parent().append(ajaxSpinner);
|
342 |
|
343 |
+
cancelCloningUpdate();
|
344 |
+
})
|
345 |
+
// Restart cloning
|
346 |
+
.on("click", "#wpstg-restart-cloning", function () {
|
347 |
+
resetErrors();
|
348 |
|
349 |
+
var $this = $(this);
|
350 |
|
351 |
+
$("#wpstg-try-again, #wpstg-home-link").hide();
|
352 |
+
$this.prop("disabled", true);
|
353 |
|
354 |
+
that.isCancelled = true;
|
355 |
|
356 |
+
$("#wpstg-cloning-result").text("Please wait...this can take up a while.");
|
357 |
+
$(".wpstg-loader, #wpstg-show-log-button").hide();
|
358 |
|
359 |
+
$this.parent().append(ajaxSpinner);
|
360 |
|
361 |
+
restart();
|
362 |
+
})
|
363 |
+
// Delete clone - confirmation
|
364 |
+
.on("click", ".wpstg-remove-clone[data-clone]", function (e) {
|
365 |
+
resetErrors();
|
366 |
+
e.preventDefault();
|
367 |
|
368 |
+
var $existingClones = cache.get("#wpstg-existing-clones");
|
369 |
|
370 |
+
$workFlow.removeClass('active');
|
371 |
|
372 |
+
cache.get(".wpstg-loader").show();
|
373 |
|
374 |
+
ajax(
|
|
|
|
|
|
|
|
|
|
|
|
|
375 |
{
|
376 |
+
action: "wpstg_confirm_delete_clone",
|
377 |
+
nonce: wpstg.nonce,
|
378 |
+
clone: $(this).data("clone")
|
379 |
+
},
|
380 |
+
function (response) {
|
381 |
cache.get("#wpstg-removing-clone").html(response);
|
382 |
|
383 |
$existingClones.children("img").remove();
|
384 |
|
385 |
+
cache.get(".wpstg-loader").hide();
|
386 |
},
|
387 |
+
"HTML"
|
388 |
+
);
|
389 |
+
})
|
390 |
+
// Delete clone - confirmed
|
391 |
+
.on("click", "#wpstg-remove-clone", function (e) {
|
392 |
+
resetErrors();
|
393 |
+
e.preventDefault();
|
394 |
|
395 |
+
cache.get("#wpstg-removing-clone").addClass("loading");
|
396 |
|
397 |
+
cache.get(".wpstg-loader").show();
|
398 |
|
399 |
+
deleteClone($(this).data("clone"));
|
400 |
+
})
|
401 |
+
// Cancel deleting clone
|
402 |
+
.on("click", "#wpstg-cancel-removing", function (e) {
|
403 |
+
e.preventDefault();
|
404 |
+
$(".wpstg-clone").removeClass("active");
|
405 |
+
cache.get("#wpstg-removing-clone").html('');
|
406 |
+
})
|
407 |
+
// Update
|
408 |
+
.on("click", ".wpstg-execute-clone", function (e) {
|
409 |
+
e.preventDefault();
|
410 |
|
411 |
+
var clone = $(this).data("clone");
|
412 |
|
413 |
+
$workFlow.addClass("loading");
|
414 |
|
415 |
+
ajax(
|
|
|
|
|
|
|
|
|
|
|
|
|
416 |
{
|
417 |
+
action: "wpstg_scanning",
|
418 |
+
clone: clone,
|
419 |
+
nonce: wpstg.nonce
|
420 |
+
},
|
421 |
+
function (response) {
|
422 |
+
if (response.length < 1) {
|
423 |
showError(
|
424 |
+
"Something went wrong! Error: No response. Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report and contact us."
|
425 |
+
);
|
426 |
}
|
427 |
|
428 |
$workFlow.removeClass("loading").html(response);
|
429 |
|
430 |
cache.get(".wpstg-current-step")
|
431 |
+
.removeClass("wpstg-current-step")
|
432 |
+
.next("li")
|
433 |
+
.addClass("wpstg-current-step");
|
434 |
},
|
435 |
+
"HTML"
|
436 |
+
);
|
437 |
+
});
|
438 |
};
|
439 |
|
440 |
/**
|
444 |
* @param {String} dataType
|
445 |
* @param {Boolean} showErrors
|
446 |
*/
|
447 |
+
var ajax = function (data, callback, dataType, showErrors, tryCount) {
|
448 |
+
if ("undefined" === typeof (dataType)) {
|
|
|
|
|
449 |
dataType = "json";
|
450 |
}
|
451 |
|
452 |
+
if (false !== showErrors) {
|
|
|
453 |
showErrors = true;
|
454 |
}
|
455 |
|
479 |
} else {
|
480 |
var errorCode = "undefined" === typeof (xhr.status) ? "Unknown" : xhr.status;
|
481 |
showError(
|
482 |
+
"Fatal Error: " + errorCode + " Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report and contact us."
|
483 |
+
);
|
484 |
}
|
485 |
|
486 |
|
|
|
487 |
},
|
488 |
success: function (data) {
|
489 |
+
if ("function" === typeof (callback)) {
|
|
|
490 |
callback(data);
|
491 |
}
|
492 |
},
|
493 |
statusCode: {
|
494 |
404: function (data) {
|
495 |
if (tryCount >= retryLimit) {
|
496 |
+
showError("Error 404 - Can't find ajax request URL! Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report and contact us.");
|
497 |
}
|
498 |
},
|
499 |
500: function () {
|
500 |
if (tryCount >= retryLimit) {
|
501 |
+
showError("Fatal Error 500 - Internal server error while processing the request! Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report and contact us.");
|
502 |
}
|
|
|
|
|
|
|
|
|
503 |
},
|
504 |
504: function () {
|
505 |
if (tryCount > retryLimit) {
|
506 |
+
showError("Error 504 - It looks like your server is rate limiting ajax requests. Please try to resume after a minute. If this still not works try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report and contact us.\n\ ");
|
507 |
}
|
508 |
|
509 |
},
|
510 |
502: function () {
|
511 |
if (tryCount >= retryLimit) {
|
512 |
+
showError("Error 502 - It looks like your server is rate limiting ajax requests. Please try to resume after a minute. If this still not works try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report and contact us.\n\ ");
|
513 |
}
|
514 |
},
|
515 |
503: function () {
|
516 |
if (tryCount >= retryLimit) {
|
517 |
+
showError("Error 503 - It looks like your server is rate limiting ajax requests. Please try to resume after a minute. If this still not works try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report and contact us.\n\ ");
|
518 |
}
|
519 |
},
|
520 |
429: function () {
|
521 |
if (tryCount >= retryLimit) {
|
522 |
+
showError("Error 429 - It looks like your server is rate limiting ajax requests. Please try to resume after a minute. If this still not works try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report and contact us.\n\ ");
|
523 |
}
|
524 |
},
|
525 |
403: function () {
|
534 |
/**
|
535 |
* Next / Previous Step Clicks to Navigate Through Staging Job
|
536 |
*/
|
537 |
+
var stepButtons = function () {
|
538 |
+
|
539 |
var $workFlow = cache.get("#wpstg-workflow");
|
540 |
|
541 |
$workFlow
|
542 |
+
// Next Button
|
543 |
+
.on("click", ".wpstg-next-step-link", function (e) {
|
544 |
+
e.preventDefault();
|
545 |
|
546 |
+
var $this = $(this);
|
547 |
+
var isScan = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
548 |
|
549 |
+
if ($this.data("action") === "wpstg_update") {
|
550 |
+
// Update Clone - confirmed
|
551 |
+
if (!confirm("STOP! This will overwrite your staging site with all selected data from the live site! This should be used only if you want to clone again your production site. Are you sure you want to do this? \n\nMake sure to exclude all tables and folders which you do not want to overwrite, first! \n\nDo not necessarily cancel the updating process! This can break your staging site. \n\n\Make sure you have a backop of your staging website before you proceed.")) {
|
552 |
+
return false;
|
553 |
}
|
554 |
|
555 |
+
}
|
556 |
|
|
|
|
|
|
|
|
|
|
|
557 |
|
558 |
+
// Button is disabled
|
559 |
+
if ($this.attr("disabled")) {
|
560 |
+
return false;
|
561 |
+
}
|
562 |
|
563 |
+
// Add loading overlay
|
564 |
+
$workFlow.addClass("loading");
|
|
|
|
|
|
|
565 |
|
566 |
+
// Prepare data
|
567 |
+
that.data = {
|
568 |
+
action: $this.data("action"),
|
569 |
+
nonce: wpstg.nonce
|
570 |
+
};
|
571 |
|
572 |
+
// Cloning data
|
573 |
+
getCloningData();
|
574 |
|
575 |
+
console.log(that.data);
|
576 |
|
577 |
+
isScan = ("wpstg_scanning" === that.action);
|
|
|
|
|
|
|
578 |
|
579 |
+
// Send ajax request
|
580 |
+
ajax(
|
581 |
+
that.data,
|
582 |
+
function (response) {
|
|
|
|
|
|
|
|
|
|
|
583 |
|
584 |
+
// Undefined Error
|
585 |
+
if (false === response) {
|
586 |
+
showError(
|
587 |
+
"Something went wrong!<br/><br/> Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low '" +
|
588 |
+
"and try again. If that does not help, " +
|
589 |
+
"<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
|
590 |
+
);
|
591 |
+
}
|
592 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
593 |
|
594 |
+
if (response.length < 1) {
|
595 |
+
showError(
|
596 |
+
"Something went wrong! No response. Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low '" +
|
597 |
+
"and try again. If that does not help, " +
|
598 |
+
"<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
|
599 |
+
);
|
600 |
+
}
|
601 |
+
|
602 |
+
// Styling of elements
|
603 |
+
$workFlow.removeClass("loading").html(response);
|
604 |
|
605 |
+
cache.get(".wpstg-current-step")
|
606 |
+
.removeClass("wpstg-current-step")
|
607 |
+
.next("li")
|
608 |
+
.addClass("wpstg-current-step");
|
609 |
|
610 |
+
// Start cloning
|
611 |
+
that.startCloning();
|
612 |
|
613 |
+
},
|
614 |
+
"HTML"
|
615 |
+
);
|
616 |
+
})
|
617 |
+
// Previous Button
|
618 |
+
.on("click", ".wpstg-prev-step-link", function (e) {
|
619 |
+
e.preventDefault();
|
620 |
+
cache.get(".wpstg-loader").removeClass('wpstg-finished');
|
621 |
+
cache.get(".wpstg-loader").hide();
|
622 |
+
loadOverview();
|
623 |
+
});
|
624 |
};
|
625 |
|
626 |
/**
|
627 |
* Get Included (Checked) Database Tables
|
628 |
* @returns {Array}
|
629 |
*/
|
630 |
+
var getIncludedTables = function () {
|
|
|
631 |
var includedTables = [];
|
632 |
|
|
|
|
|
|
|
633 |
$("#wpstg_select_tables_cloning option:selected").each(function () {
|
|
|
634 |
includedTables.push(this.value);
|
635 |
});
|
636 |
|
642 |
* Not used anymore!
|
643 |
* @returns {Array}
|
644 |
*/
|
645 |
+
var getExcludedTables = function () {
|
|
|
646 |
var excludedTables = [];
|
647 |
|
648 |
$(".wpstg-db-table input:not(:checked)").each(function () {
|
649 |
excludedTables.push(this.name);
|
650 |
});
|
|
|
|
|
|
|
651 |
|
652 |
return excludedTables;
|
653 |
};
|
656 |
* Get Included Directories
|
657 |
* @returns {Array}
|
658 |
*/
|
659 |
+
var getIncludedDirectories = function () {
|
|
|
660 |
var includedDirectories = [];
|
661 |
|
662 |
$(".wpstg-dir input:checked.wpstg-root").each(function () {
|
671 |
* Get Excluded Directories
|
672 |
* @returns {Array}
|
673 |
*/
|
674 |
+
var getExcludedDirectories = function () {
|
|
|
675 |
var excludedDirectories = [];
|
676 |
|
677 |
$(".wpstg-dir input:not(:checked).wpstg-root").each(function () {
|
687 |
* All directories except wp-content, wp-admin, wp-includes
|
688 |
* @returns {Array}
|
689 |
*/
|
690 |
+
var getIncludedExtraDirectories = function () {
|
|
|
691 |
// Add directories from the root level
|
692 |
var extraDirectories = [];
|
693 |
$(".wpstg-dir input:checked.wpstg-extra").each(function () {
|
705 |
return extraDirectories.concat(extraCustomDirectories);
|
706 |
};
|
707 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
708 |
|
709 |
/**
|
710 |
* Get Cloning Step Data
|
711 |
*/
|
712 |
+
var getCloningData = function () {
|
713 |
+
if ("wpstg_cloning" !== that.data.action && "wpstg_update" !== that.data.action) {
|
|
|
|
|
714 |
return;
|
715 |
}
|
716 |
|
729 |
var cloneDir = $("#wpstg_clone_dir").val();
|
730 |
that.data.cloneDir = encodeURIComponent($.trim(cloneDir));
|
731 |
that.data.cloneHostname = $("#wpstg_clone_hostname").val();
|
|
|
732 |
|
733 |
};
|
734 |
|
735 |
/**
|
736 |
* Loads Overview (first step) of Staging Job
|
737 |
*/
|
738 |
+
var loadOverview = function () {
|
|
|
739 |
var $workFlow = cache.get("#wpstg-workflow");
|
740 |
|
741 |
$workFlow.addClass("loading");
|
742 |
|
743 |
ajax(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
744 |
{
|
745 |
+
action: "wpstg_overview",
|
746 |
+
nonce: wpstg.nonce
|
747 |
+
},
|
748 |
+
function (response) {
|
749 |
+
|
750 |
+
if (response.length < 1) {
|
751 |
+
showError(
|
752 |
"Something went wrong! No response. Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
|
753 |
+
);
|
754 |
+
}
|
755 |
|
756 |
+
var $currentStep = cache.get(".wpstg-current-step");
|
757 |
|
758 |
+
// Styling of elements
|
759 |
+
$workFlow.removeClass("loading").html(response);
|
760 |
|
761 |
+
},
|
762 |
+
"HTML"
|
763 |
+
);
|
764 |
};
|
765 |
|
766 |
/**
|
767 |
* Load Tabs
|
768 |
*/
|
769 |
+
var tabs = function () {
|
|
|
770 |
|
771 |
cache.get("#wpstg-workflow").on("click", ".wpstg-tab-header", function (e) {
|
772 |
e.preventDefault();
|
778 |
|
779 |
$section.slideToggle();
|
780 |
|
781 |
+
if ($this.hasClass("expand")) {
|
|
|
782 |
$this.find(".wpstg-tab-triangle").html("▼");
|
783 |
+
} else {
|
|
|
|
|
784 |
$this.find(".wpstg-tab-triangle").html("►");
|
785 |
}
|
786 |
|
787 |
|
|
|
788 |
});
|
789 |
};
|
790 |
|
792 |
* Delete Clone
|
793 |
* @param {String} clone
|
794 |
*/
|
795 |
+
var deleteClone = function (clone) {
|
|
|
796 |
|
797 |
var deleteDir = $("#deleteDirectory:checked").data("deletepath");
|
798 |
|
799 |
ajax(
|
800 |
+
{
|
801 |
+
action: "wpstg_delete_clone",
|
802 |
+
clone: clone,
|
803 |
+
nonce: wpstg.nonce,
|
804 |
+
excludedTables: getExcludedTables(),
|
805 |
+
deleteDir: deleteDir
|
806 |
+
},
|
807 |
+
function (response) {
|
808 |
+
if (response) {
|
809 |
+
showAjaxFatalError(response);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
810 |
|
811 |
+
// Finished
|
812 |
+
if ("undefined" !== typeof response.delete && response.delete === 'finished') {
|
813 |
|
814 |
+
cache.get("#wpstg-removing-clone").removeClass("loading").html('');
|
815 |
|
816 |
+
$(".wpstg-clone#" + clone).remove();
|
817 |
|
818 |
+
if ($(".wpstg-clone").length < 1) {
|
819 |
+
cache.get("#wpstg-existing-clones").find("h3").text('');
|
820 |
+
}
|
|
|
821 |
|
822 |
+
cache.get(".wpstg-loader").hide();
|
823 |
+
return;
|
824 |
+
}
|
825 |
+
}
|
826 |
+
// continue
|
827 |
+
if (true !== response) {
|
828 |
+
deleteClone(clone);
|
829 |
return;
|
830 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
831 |
|
832 |
+
}
|
833 |
);
|
834 |
};
|
835 |
|
836 |
/**
|
837 |
* Cancel Cloning Process
|
838 |
*/
|
839 |
+
var cancelCloning = function () {
|
|
|
840 |
|
841 |
that.timer('stop');
|
842 |
|
843 |
|
844 |
+
if (true === that.isFinished) {
|
|
|
845 |
return true;
|
846 |
}
|
847 |
|
848 |
ajax(
|
849 |
+
{
|
850 |
+
action: "wpstg_cancel_clone",
|
851 |
+
clone: that.data.cloneID,
|
852 |
+
nonce: wpstg.nonce
|
853 |
+
},
|
854 |
+
function (response) {
|
855 |
+
|
856 |
+
|
857 |
+
if (response && "undefined" !== typeof (response.delete) && response.delete === "finished") {
|
858 |
+
cache.get(".wpstg-loader").hide();
|
859 |
+
// Load overview
|
860 |
+
loadOverview();
|
861 |
+
return;
|
862 |
+
}
|
863 |
|
864 |
+
if (true !== response) {
|
865 |
+
// continue
|
866 |
+
cancelCloning();
|
867 |
+
return;
|
868 |
+
}
|
869 |
|
|
|
|
|
870 |
// Load overview
|
871 |
loadOverview();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
872 |
}
|
|
|
|
|
|
|
|
|
873 |
);
|
874 |
};
|
875 |
|
876 |
/**
|
877 |
* Cancel Cloning Process
|
878 |
*/
|
879 |
+
var cancelCloningUpdate = function () {
|
880 |
+
if (true === that.isFinished) {
|
|
|
|
|
881 |
return true;
|
882 |
}
|
883 |
|
884 |
ajax(
|
885 |
+
{
|
886 |
+
action: "wpstg_cancel_update",
|
887 |
+
clone: that.data.cloneID,
|
888 |
+
nonce: wpstg.nonce
|
889 |
+
},
|
890 |
+
function (response) {
|
|
|
891 |
|
892 |
|
893 |
+
if (response && "undefined" !== typeof (response.delete) && response.delete === "finished") {
|
894 |
+
// Load overview
|
895 |
+
loadOverview();
|
896 |
+
return;
|
897 |
+
}
|
898 |
+
|
899 |
+
if (true !== response) {
|
900 |
+
// continue
|
901 |
+
cancelCloningUpdate();
|
902 |
+
return;
|
903 |
+
}
|
904 |
+
|
905 |
// Load overview
|
906 |
loadOverview();
|
|
|
907 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
908 |
);
|
909 |
};
|
910 |
|
911 |
/**
|
912 |
* Cancel Cloning Process
|
913 |
*/
|
914 |
+
var restart = function () {
|
915 |
+
if (true === that.isFinished) {
|
|
|
|
|
916 |
return true;
|
917 |
}
|
918 |
|
919 |
ajax(
|
920 |
+
{
|
921 |
+
action: "wpstg_restart",
|
922 |
+
//clone: that.data.cloneID,
|
923 |
+
nonce: wpstg.nonce
|
924 |
+
},
|
925 |
+
function (response) {
|
926 |
+
|
927 |
|
928 |
+
if (response && "undefined" !== typeof (response.delete) && response.delete === "finished") {
|
929 |
+
// Load overview
|
930 |
+
loadOverview();
|
931 |
+
return;
|
932 |
+
}
|
933 |
+
|
934 |
+
if (true !== response) {
|
935 |
+
// continue
|
936 |
+
cancelCloningUpdate();
|
937 |
+
return;
|
938 |
+
}
|
939 |
|
|
|
940 |
// Load overview
|
941 |
loadOverview();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
942 |
}
|
|
|
|
|
|
|
|
|
943 |
);
|
944 |
};
|
945 |
|
948 |
* @returns void
|
949 |
*/
|
950 |
var logscroll = function () {
|
951 |
+
var $div = cache.get(".wpstg-log-details");
|
952 |
if ("undefined" !== typeof ($div[0])) {
|
953 |
$div.scrollTop($div[0].scrollHeight);
|
954 |
}
|
959 |
* @param string log
|
960 |
* @returns void
|
961 |
*/
|
962 |
+
var getLogs = function (log) {
|
|
|
963 |
if (log != null && "undefined" !== typeof (log)) {
|
964 |
if (log.constructor === Array) {
|
965 |
$.each(log, function (index, value) {
|
967 |
return;
|
968 |
}
|
969 |
if (value.type === 'ERROR') {
|
970 |
+
cache.get(".wpstg-log-details").append('<span style="color:red;">[' + value.type + ']</span>-' + '[' + value.date + '] ' + value.message + '</br>');
|
971 |
} else {
|
972 |
+
cache.get(".wpstg-log-details").append('[' + value.type + ']-' + '[' + value.date + '] ' + value.message + '</br>');
|
973 |
}
|
974 |
})
|
975 |
} else {
|
976 |
+
cache.get(".wpstg-log-details").append('[' + log.type + ']-' + '[' + log.date + '] ' + log.message + '</br>');
|
977 |
}
|
978 |
}
|
979 |
logscroll();
|
986 |
*/
|
987 |
var checkDiskSpace = function () {
|
988 |
cache.get("#wpstg-check-space").on("click", function (e) {
|
989 |
+
cache.get(".wpstg-loader").show();
|
990 |
console.log("check disk space");
|
991 |
ajax(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
992 |
{
|
993 |
+
action: "wpstg_check_disk_space",
|
994 |
+
nonce: wpstg.nonce
|
995 |
+
},
|
996 |
+
function (response) {
|
997 |
+
if (false === response) {
|
998 |
+
cache.get("#wpstg-clone-id-error").text('Can not detect required disk space').show();
|
999 |
+
cache.get(".wpstg-loader").hide();
|
1000 |
+
return;
|
1001 |
+
}
|
1002 |
|
1003 |
+
// Show required disk space
|
1004 |
+
cache.get("#wpstg-clone-id-error").html('Estimated necessary disk space: ' + response.usedspace + '<br> <span style="color:#444;">Before you proceed ensure your account has enough free disk space to hold the entire instance of the production site. You can check the available space from your hosting account (cPanel or similar).</span>').show();
|
1005 |
+
cache.get(".wpstg-loader").hide();
|
1006 |
+
},
|
1007 |
+
"json",
|
1008 |
+
false
|
1009 |
+
);
|
|
|
1010 |
});
|
1011 |
}
|
1012 |
|
1013 |
+
var mainTabs = function () {
|
1014 |
+
$('.wpstg--tab--header a[data-target]').on('click', function () {
|
1015 |
+
var $this = $(this);
|
1016 |
+
var target = $this.attr('data-target');
|
1017 |
+
var $wrapper = $this.parents('.wpstg--tab--wrapper');
|
1018 |
+
var $menuItems = $wrapper.find('.wpstg--tab--header a[data-target]');
|
1019 |
+
var $contents = $wrapper.find('.wpstg--tab--contents > .wpstg--tab--content');
|
1020 |
+
|
1021 |
+
$contents.filter('.wpstg--tab--active:not(.wpstg--tab--active' + target + ')').removeClass('wpstg--tab--active');
|
1022 |
+
$menuItems.not($this).removeClass('wpstg--tab--active');
|
1023 |
+
$this.addClass('wpstg--tab--active');
|
1024 |
+
$(target).addClass('wpstg--tab--active');
|
1025 |
+
|
1026 |
+
if ('#wpstg--tab--snapshot' === target) {
|
1027 |
+
that.snapshots.init();
|
1028 |
+
}
|
1029 |
+
});
|
1030 |
+
};
|
1031 |
+
|
1032 |
+
/**
|
1033 |
+
* Show or hide animated loading icon
|
1034 |
+
* @param isLoading bool
|
1035 |
+
*/
|
1036 |
+
var isLoading = function (isLoading) {
|
1037 |
+
if (!isLoading || isLoading === false) {
|
1038 |
+
cache.get(".wpstg-loader").hide();
|
1039 |
+
} else {
|
1040 |
+
cache.get(".wpstg-loader").show();
|
1041 |
+
}
|
1042 |
+
};
|
1043 |
|
1044 |
/**
|
1045 |
* Count up processing execution time
|
1085 |
*/
|
1086 |
that.startCloning = (function () {
|
1087 |
|
1088 |
+
resetErrors();
|
1089 |
+
|
1090 |
// Register function for checking disk space
|
1091 |
checkDiskSpace();
|
1092 |
|
1093 |
+
if ("wpstg_cloning" !== that.data.action && "wpstg_update" !== that.data.action) {
|
|
|
1094 |
return;
|
1095 |
}
|
1096 |
|
1101 |
|
1102 |
// Functions
|
1103 |
// Start
|
1104 |
+
function start() {
|
|
|
1105 |
|
1106 |
console.log("Starting cloning process...");
|
1107 |
|
1108 |
+
cache.get(".wpstg-loader").show();
|
1109 |
cache.get("#wpstg-cancel-cloning").text('Cancel');
|
1110 |
cache.get("#wpstg-resume-cloning").hide();
|
1111 |
cache.get("#wpstg-error-details").hide();
|
1122 |
}
|
1123 |
|
1124 |
|
|
|
1125 |
/**
|
1126 |
* Start ajax processing
|
1127 |
* @returns string
|
1128 |
*/
|
1129 |
var processing = function () {
|
1130 |
|
1131 |
+
if (true === that.isCancelled) {
|
|
|
1132 |
return false;
|
1133 |
}
|
1134 |
|
1135 |
+
isLoading(true);
|
|
|
|
|
|
|
|
|
|
|
|
|
1136 |
|
1137 |
// Show logging window
|
1138 |
+
cache.get('.wpstg-log-details').show();
|
1139 |
|
1140 |
WPStaging.ajax(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1141 |
{
|
1142 |
+
action: "wpstg_processing",
|
1143 |
+
nonce: wpstg.nonce,
|
1144 |
+
excludedTables: getExcludedTables(),
|
1145 |
+
includedDirectories: getIncludedDirectories(),
|
1146 |
+
excludedDirectories: getExcludedDirectories(),
|
1147 |
+
extraDirectories: getIncludedExtraDirectories()
|
1148 |
+
},
|
1149 |
+
function (response) {
|
|
|
|
|
|
|
|
|
|
|
|
|
1150 |
|
1151 |
+
showAjaxFatalError(response);
|
|
|
1152 |
|
1153 |
+
// Add Log messages
|
1154 |
+
if ("undefined" !== typeof (response.last_msg) && response.last_msg) {
|
1155 |
+
getLogs(response.last_msg);
|
1156 |
+
}
|
1157 |
+
// Continue processing
|
1158 |
+
if (false === response.status) {
|
1159 |
+
progressBar(response);
|
1160 |
+
|
1161 |
+
setTimeout(function () {
|
1162 |
+
cache.get(".wpstg-loader").show();
|
1163 |
+
processing();
|
1164 |
+
}, wpstg.delayReq);
|
1165 |
+
|
1166 |
+
} else if (true === response.status && 'finished' !== response.status) {
|
1167 |
+
cache.get("#wpstg-error-details").hide();
|
1168 |
+
cache.get("#wpstg-error-wrapper").hide();
|
1169 |
+
progressBar(response, true);
|
1170 |
processing();
|
1171 |
+
} else if ('finished' === response.status || ("undefined" !== typeof (response.job_done) && response.job_done)) {
|
1172 |
+
finish(response);
|
1173 |
+
}
|
1174 |
+
;
|
1175 |
+
},
|
1176 |
+
"json",
|
1177 |
+
false
|
1178 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1179 |
};
|
1180 |
|
1181 |
// Finish
|
1182 |
+
function finish(response) {
|
|
|
1183 |
|
1184 |
+
if (true === that.getLogs) {
|
|
|
1185 |
getLogs();
|
1186 |
}
|
1187 |
|
1188 |
progressBar(response);
|
1189 |
|
1190 |
// Add Log
|
1191 |
+
if ("undefined" !== typeof (response.last_msg)) {
|
|
|
1192 |
getLogs(response.last_msg);
|
1193 |
}
|
1194 |
|
1195 |
console.log("Cloning process finished");
|
1196 |
|
1197 |
+
cache.get(".wpstg-loader").hide();
|
1198 |
cache.get("#wpstg-processing-header").html('Processing Complete');
|
1199 |
$("#wpstg-processing-status").text("Succesfully finished");
|
1200 |
|
1217 |
that.timer('stop');
|
1218 |
|
1219 |
|
1220 |
+
cache.get(".wpstg-loader").hide();
|
1221 |
cache.get("#wpstg-processing-header").html('Processing Complete');
|
1222 |
|
1223 |
return false;
|
1224 |
|
1225 |
}
|
1226 |
+
|
1227 |
/**
|
1228 |
* Add percentage progress bar
|
1229 |
* @param object response
|
1233 |
if ("undefined" === typeof (response.percentage))
|
1234 |
return false;
|
1235 |
|
|
|
|
|
|
|
|
|
1236 |
if (response.job === 'database') {
|
1237 |
cache.get("#wpstg-progress-db").width(response.percentage * 0.2 + '%').html(response.percentage + '%');
|
1238 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Step 1 of 4 Cloning Database Tables...');
|
1276 |
elements();
|
1277 |
stepButtons();
|
1278 |
tabs();
|
1279 |
+
mainTabs();
|
1280 |
});
|
1281 |
|
1282 |
/**
|
1288 |
that.getLogs = getLogs;
|
1289 |
that.loadOverview = loadOverview;
|
1290 |
|
1291 |
+
that.snapshots = {
|
1292 |
+
init() {
|
1293 |
+
this.fetchListing();
|
1294 |
+
this.create();
|
1295 |
+
this.delete();
|
1296 |
+
this.restore();
|
1297 |
+
this.export();
|
1298 |
+
this.edit();
|
1299 |
+
},
|
1300 |
+
fetchListing() {
|
1301 |
+
isLoading(true);
|
1302 |
+
resetErrors();
|
1303 |
+
that.ajax(
|
1304 |
+
{
|
1305 |
+
action: 'wpstg--snapshots--listing',
|
1306 |
+
nonce: wpstg.nonce,
|
1307 |
+
},
|
1308 |
+
function (response) {
|
1309 |
+
showAjaxFatalError(response, '', 'Submit an error report.');
|
1310 |
+
cache.get('#wpstg--tab--snapshot').html(response);
|
1311 |
+
isLoading(false);
|
1312 |
+
},
|
1313 |
+
);
|
1314 |
+
},
|
1315 |
+
delete() {
|
1316 |
+
$('#wpstg--tab--snapshot')
|
1317 |
+
.off('click', '.wpstg-delete-snapshot[data-id]')
|
1318 |
+
.on('click', '.wpstg-delete-snapshot[data-id]', function (e) {
|
1319 |
+
e.preventDefault();
|
1320 |
+
resetErrors();
|
1321 |
+
isLoading(true);
|
1322 |
+
cache.get('#wpstg-existing-snapshots').hide();
|
1323 |
+
var id = this.getAttribute('data-id');
|
1324 |
+
that.ajax(
|
1325 |
+
{
|
1326 |
+
action: 'wpstg--snapshots--delete--confirm',
|
1327 |
+
id: id,
|
1328 |
+
nonce: wpstg.nonce,
|
1329 |
+
},
|
1330 |
+
function (response) {
|
1331 |
+
showAjaxFatalError(response, '', ' Please submit an error report by using the REPORT ISSUE button.');
|
1332 |
+
isLoading(false);
|
1333 |
+
cache.get('#wpstg-delete-confirmation').html(response);
|
1334 |
+
},
|
1335 |
+
);
|
1336 |
+
})
|
1337 |
+
// Delete final confirmation page
|
1338 |
+
.off('click', '#wpstg-delete-snapshot')
|
1339 |
+
.on('click', '#wpstg-delete-snapshot', function (e) {
|
1340 |
+
e.preventDefault();
|
1341 |
+
resetErrors();
|
1342 |
+
isLoading(true);
|
1343 |
+
var id = this.getAttribute('data-id');
|
1344 |
+
that.ajax(
|
1345 |
+
{
|
1346 |
+
action: 'wpstg--snapshots--delete',
|
1347 |
+
id: id,
|
1348 |
+
nonce: wpstg.nonce,
|
1349 |
+
},
|
1350 |
+
function (response) {
|
1351 |
+
showAjaxFatalError(response, '', ' Please submit an error report by using the REPORT ISSUE button.');
|
1352 |
+
that.snapshots.fetchListing();
|
1353 |
+
isLoading(false);
|
1354 |
+
},
|
1355 |
+
);
|
1356 |
+
})
|
1357 |
+
.off('click', '#wpstg-cancel-snapshot-delete')
|
1358 |
+
.on('click', '#wpstg-cancel-snapshot-delete', function (e) {
|
1359 |
+
e.preventDefault();
|
1360 |
+
isLoading(false);
|
1361 |
+
var id = this.getAttribute('data-id');
|
1362 |
+
that.snapshots.fetchListing();
|
1363 |
+
})
|
1364 |
+
;
|
1365 |
+
},
|
1366 |
+
create() {
|
1367 |
+
var createSnapshot = function (name, notes) {
|
1368 |
+
isLoading(true);
|
1369 |
+
resetErrors();
|
1370 |
+
WPStaging.ajax(
|
1371 |
+
{
|
1372 |
+
action: 'wpstg--snapshots--create',
|
1373 |
+
nonce: wpstg.nonce,
|
1374 |
+
name,
|
1375 |
+
notes,
|
1376 |
+
},
|
1377 |
+
function (response) {
|
1378 |
+
if (typeof response === 'undefined') {
|
1379 |
+
setTimeout(function () {
|
1380 |
+
createSnapshot(name, notes);
|
1381 |
+
}, wpstg.delayReq);
|
1382 |
+
return;
|
1383 |
+
}
|
1384 |
+
|
1385 |
+
showAjaxFatalError(response, '', 'Submit an error report and contact us.');
|
1386 |
+
|
1387 |
+
if (typeof response.last_msg !== 'undefined' && response.last_msg) {
|
1388 |
+
getLogs(response.last_msg);
|
1389 |
+
}
|
1390 |
+
|
1391 |
+
if (response.status === false) {
|
1392 |
+
createSnapshot(name, notes);
|
1393 |
+
} else if (response.status === true) {
|
1394 |
+
isLoading(false);
|
1395 |
+
$('#wpstg--progress--status').text('Snapshot successfully created!');
|
1396 |
+
that.snapshots.fetchListing();
|
1397 |
+
} else {
|
1398 |
+
setTimeout(function () {
|
1399 |
+
createSnapshot(name, notes);
|
1400 |
+
}, wpstg.delayReq);
|
1401 |
+
}
|
1402 |
+
},
|
1403 |
+
'json',
|
1404 |
+
false
|
1405 |
+
);
|
1406 |
+
};
|
1407 |
+
// Add snapshot name and notes
|
1408 |
+
$('#wpstg--tab--snapshot')
|
1409 |
+
.off('click', '#wpstg-new-snapshot')
|
1410 |
+
.on('click', '#wpstg-new-snapshot', async function(e) {
|
1411 |
+
resetErrors();
|
1412 |
+
e.preventDefault();
|
1413 |
+
|
1414 |
+
const { value: formValues } = await Swal.fire({
|
1415 |
+
title: '',
|
1416 |
+
html: `
|
1417 |
+
<label id="wpstg-snapshot-name">Snapshot Name</label>
|
1418 |
+
<input id="wpstg-snapshot-name-input" class="swal2-input" placeholder="Name your snapshot for better distinction">
|
1419 |
+
<label>Additional Notes</label>
|
1420 |
+
<textarea id="wpstg-snapshot-notes-textarea" class="swal2-textarea" placeholder="Add an optional description e.g.: 'before push of staging site', 'before updating plugin XY'"></textarea>
|
1421 |
+
`,
|
1422 |
+
focusConfirm: false,
|
1423 |
+
confirmButtonText: 'Take New Snapshot',
|
1424 |
+
showCancelButton: true,
|
1425 |
+
preConfirm: () => ({
|
1426 |
+
name: document.getElementById('wpstg-snapshot-name-input').value || null,
|
1427 |
+
notes: document.getElementById('wpstg-snapshot-notes-textarea').value || null,
|
1428 |
+
}),
|
1429 |
+
});
|
1430 |
+
|
1431 |
+
if (!formValues) {
|
1432 |
+
return;
|
1433 |
+
}
|
1434 |
+
|
1435 |
+
that.ajax(
|
1436 |
+
{
|
1437 |
+
action: 'wpstg--snapshots--create--progress',
|
1438 |
+
nonce: wpstg.nonce,
|
1439 |
+
},
|
1440 |
+
function (response) {
|
1441 |
+
showAjaxFatalError(response, '', 'Submit an error report and contact us.');
|
1442 |
+
cache.get('#wpstg--tab--snapshot').html(response);
|
1443 |
+
createSnapshot(formValues.name, formValues.notes);
|
1444 |
+
},
|
1445 |
+
);
|
1446 |
+
})
|
1447 |
+
;
|
1448 |
+
},
|
1449 |
+
restore() {
|
1450 |
+
var restoreSnapshot = function (id, isReset) {
|
1451 |
+
isLoading(true);
|
1452 |
+
resetErrors();
|
1453 |
+
|
1454 |
+
if (typeof isReset === 'undefined') {
|
1455 |
+
isReset = false;
|
1456 |
+
}
|
1457 |
+
|
1458 |
+
WPStaging.ajax(
|
1459 |
+
{
|
1460 |
+
action: 'wpstg--snapshots--restore',
|
1461 |
+
nonce: wpstg.nonce,
|
1462 |
+
id: id,
|
1463 |
+
isReset: isReset,
|
1464 |
+
},
|
1465 |
+
function (response) {
|
1466 |
+
if (typeof response === 'undefined') {
|
1467 |
+
setTimeout(function () {
|
1468 |
+
restoreSnapshot(id);
|
1469 |
+
}, wpstg.delayReq);
|
1470 |
+
return;
|
1471 |
+
}
|
1472 |
+
|
1473 |
+
showAjaxFatalError(response, '', 'Submit an error report and contact us.');
|
1474 |
+
|
1475 |
+
if (typeof response.last_msg !== 'undefined' && response.last_msg) {
|
1476 |
+
getLogs(response.last_msg);
|
1477 |
+
}
|
1478 |
+
|
1479 |
+
if (response.status === false || response.job_done === false) {
|
1480 |
+
restoreSnapshot(id);
|
1481 |
+
} else if (response.status === true && response.job_done === true) {
|
1482 |
+
isLoading(false);
|
1483 |
+
$('#wpstg--progress--status').text('Snapshot successfully restored');
|
1484 |
+
} else {
|
1485 |
+
setTimeout(function () {
|
1486 |
+
restoreSnapshot(id);
|
1487 |
+
}, wpstg.delayReq);
|
1488 |
+
}
|
1489 |
+
},
|
1490 |
+
'json',
|
1491 |
+
false
|
1492 |
+
);
|
1493 |
+
};
|
1494 |
+
|
1495 |
+
// Force delete if snapshot tables do not exist
|
1496 |
+
$('#wpstg-error-wrapper')
|
1497 |
+
.off('click', '#wpstg-snapshot-force-delete')
|
1498 |
+
.on('click', '#wpstg-snapshot-force-delete', function (e) {
|
1499 |
+
e.preventDefault();
|
1500 |
+
resetErrors();
|
1501 |
+
isLoading(true);
|
1502 |
+
var id = this.getAttribute('data-id');
|
1503 |
+
|
1504 |
+
if (!confirm("Do you want to delete this snapshot " + id + " from the listed snapshots?")) {
|
1505 |
+
isLoading(false);
|
1506 |
+
return false;
|
1507 |
+
}
|
1508 |
+
|
1509 |
+
that.ajax(
|
1510 |
+
{
|
1511 |
+
action: 'wpstg--snapshots--delete',
|
1512 |
+
id: id,
|
1513 |
+
force: 1,
|
1514 |
+
nonce: wpstg.nonce,
|
1515 |
+
},
|
1516 |
+
function (response) {
|
1517 |
+
showAjaxFatalError(response, '', ' Please submit an error report by using the REPORT ISSUE button.');
|
1518 |
+
that.snapshots.fetchListing();
|
1519 |
+
isLoading(false);
|
1520 |
+
},
|
1521 |
+
);
|
1522 |
+
})
|
1523 |
+
|
1524 |
+
$('#wpstg--tab--snapshot')
|
1525 |
+
.off('click', '.wpstg--snapshot--restore[data-id]')
|
1526 |
+
.on('click', '.wpstg--snapshot--restore[data-id]', function (e) {
|
1527 |
+
e.preventDefault();
|
1528 |
+
resetErrors();
|
1529 |
+
that.ajax(
|
1530 |
+
{
|
1531 |
+
action: 'wpstg--snapshots--restore--confirm',
|
1532 |
+
nonce: wpstg.nonce,
|
1533 |
+
id: $(this).data('id'),
|
1534 |
+
},
|
1535 |
+
function (data) {
|
1536 |
+
cache.get('#wpstg--tab--snapshot').html(data);
|
1537 |
+
},
|
1538 |
+
);
|
1539 |
+
})
|
1540 |
+
.off('click', '#wpstg--snapshot--restore--cancel')
|
1541 |
+
.on('click', '#wpstg--snapshot--restore--cancel', function (e) {
|
1542 |
+
resetErrors();
|
1543 |
+
e.preventDefault();
|
1544 |
+
that.snapshots.fetchListing();
|
1545 |
+
})
|
1546 |
+
.off('click', '#wpstg--snapshot--restore[data-id]')
|
1547 |
+
.on('click', '#wpstg--snapshot--restore[data-id]', function (e) {
|
1548 |
+
e.preventDefault();
|
1549 |
+
resetErrors();
|
1550 |
+
var id = $(this).data('id');
|
1551 |
+
|
1552 |
+
that.ajax(
|
1553 |
+
{
|
1554 |
+
action: 'wpstg--snapshots--restore--progress',
|
1555 |
+
nonce: wpstg.nonce,
|
1556 |
+
id: id,
|
1557 |
+
},
|
1558 |
+
function (response) {
|
1559 |
+
showAjaxFatalError(response, '', 'Submit an error report and contact us.');
|
1560 |
+
cache.get('#wpstg--tab--snapshot').html(response);
|
1561 |
+
restoreSnapshot(id, true);
|
1562 |
+
},
|
1563 |
+
);
|
1564 |
+
})
|
1565 |
+
;
|
1566 |
+
},
|
1567 |
+
export() {
|
1568 |
+
function download(url) {
|
1569 |
+
var a = document.createElement('a');
|
1570 |
+
a.style.display = 'none';
|
1571 |
+
a.href = url;
|
1572 |
+
document.body.appendChild(a);
|
1573 |
+
a.click();
|
1574 |
+
document.body.removeChild(a);
|
1575 |
+
}
|
1576 |
+
|
1577 |
+
$('#wpstg--tab--snapshot')
|
1578 |
+
.off('click', '.wpstg--snapshot--export')
|
1579 |
+
.on('click', '.wpstg--snapshot--export', function (e) {
|
1580 |
+
e.preventDefault();
|
1581 |
+
isLoading(true);
|
1582 |
+
that.ajax(
|
1583 |
+
{
|
1584 |
+
action: 'wpstg--snapshots--export',
|
1585 |
+
nonce: wpstg.nonce,
|
1586 |
+
id: $(this).data('id'),
|
1587 |
+
},
|
1588 |
+
function (response) {
|
1589 |
+
showAjaxFatalError(response, '', 'Submit an error report and contact us.');
|
1590 |
+
isLoading(false);
|
1591 |
+
if (response && response.success && response.data && response.data.length > 0) {
|
1592 |
+
download(response.data);
|
1593 |
+
}
|
1594 |
+
},
|
1595 |
+
);
|
1596 |
+
})
|
1597 |
+
;
|
1598 |
+
},
|
1599 |
+
// Edit snapshots name and notes
|
1600 |
+
edit() {
|
1601 |
+
$('#wpstg--tab--snapshot')
|
1602 |
+
.off('click', '.wpstg--snapshot--edit[data-id]')
|
1603 |
+
.on('click', '.wpstg--snapshot--edit[data-id]', async function(e) {
|
1604 |
+
e.preventDefault();
|
1605 |
+
console.log('edit');
|
1606 |
+
|
1607 |
+
const $this = $(this);
|
1608 |
+
const name = $this.data('name');
|
1609 |
+
const notes = $this.data('notes');
|
1610 |
+
|
1611 |
+
const { value: formValues } = await Swal.fire({
|
1612 |
+
title: '',
|
1613 |
+
html: `
|
1614 |
+
<label id="wpstg-snapshot-name">Snapshot Name</label>
|
1615 |
+
<input id="wpstg-snapshot-name-input" class="swal2-input" value="${name}">
|
1616 |
+
<label>Additional Notes</label>
|
1617 |
+
<textarea id="wpstg-snapshot-notes-textarea" class="swal2-textarea">${notes}</textarea>
|
1618 |
+
`,
|
1619 |
+
focusConfirm: false,
|
1620 |
+
confirmButtonText: 'Update Snapshot',
|
1621 |
+
showCancelButton: true,
|
1622 |
+
preConfirm: () => ({
|
1623 |
+
name: document.getElementById('wpstg-snapshot-name-input').value || null,
|
1624 |
+
notes: document.getElementById('wpstg-snapshot-notes-textarea').value || null,
|
1625 |
+
}),
|
1626 |
+
});
|
1627 |
+
|
1628 |
+
if (!formValues) {
|
1629 |
+
return;
|
1630 |
+
}
|
1631 |
+
|
1632 |
+
that.ajax(
|
1633 |
+
{
|
1634 |
+
action: 'wpstg--snapshots--edit',
|
1635 |
+
nonce: wpstg.nonce,
|
1636 |
+
id: $this.data('id'),
|
1637 |
+
name: formValues.name,
|
1638 |
+
notes: formValues.notes,
|
1639 |
+
},
|
1640 |
+
function(response) {
|
1641 |
+
showAjaxFatalError(response, '', 'Submit an error report.');
|
1642 |
+
that.snapshots.fetchListing();
|
1643 |
+
},
|
1644 |
+
);
|
1645 |
+
})
|
1646 |
+
;
|
1647 |
+
},
|
1648 |
+
};
|
1649 |
+
|
1650 |
return that;
|
1651 |
})(jQuery);
|
1652 |
|
1660 |
jQuery(document).ready(function ($) {
|
1661 |
|
1662 |
$('#wpstg-report-issue-button').click(function (e) {
|
|
|
1663 |
$('.wpstg-report-issue-form').toggleClass('wpstg-report-show');
|
1664 |
e.preventDefault();
|
1665 |
});
|
1666 |
|
1667 |
+
$('body').on('click', '#wpstg-snapshots-report-issue-button', function (e) {
|
1668 |
+
$('.wpstg-report-issue-form').toggleClass('wpstg-report-show');
|
1669 |
+
console.log('test');
|
1670 |
+
e.preventDefault();
|
1671 |
+
});
|
1672 |
+
|
1673 |
$('#wpstg-report-cancel').click(function (e) {
|
1674 |
$('.wpstg-report-issue-form').removeClass('wpstg-report-show');
|
1675 |
e.preventDefault();
|
Backend/views/clone/ajax/start.php
CHANGED
@@ -39,50 +39,46 @@
|
|
39 |
echo sprintf( __( 'WP Staging successfully created a staging site in a sub-directory of your main site accessable from:<br><strong><a href="%1$s" target="_blank" id="wpstg-clone-url-1">%1$s</a></strong>', 'wp-staging' ), $url );
|
40 |
?>
|
41 |
<br>
|
42 |
-
<?php //echo __('Open and access the staging site: ', 'wp-staging')?>
|
43 |
<br>
|
44 |
-
<a href="
|
45 |
-
|
46 |
</a>
|
47 |
-
|
48 |
-
<?php
|
49 |
-
</a>//-->
|
50 |
-
<a href="" class="wpstg-link-btn button-primary" id="wpstg-home-link">
|
51 |
-
<?php echo __("Start again", "wp-staging")?>
|
52 |
</a>
|
53 |
<div id="wpstg-success-notice">
|
54 |
-
<h3
|
55 |
-
<?php _e("
|
56 |
</h3>
|
57 |
<ul>
|
58 |
<li>
|
59 |
-
<strong>1.
|
60 |
<br>
|
61 |
-
Usually
|
62 |
<br>
|
63 |
<p>
|
64 |
-
If Apache
|
65 |
<br>
|
66 |
<strong>Staging Site > wp-admin > Settings > Permalinks</strong></a>
|
67 |
<br/><br/>
|
68 |
-
If
|
69 |
</p>
|
70 |
<p>
|
71 |
-
<strong><a href="https://wp-staging.com/docs/activate-permalinks-staging-site/?utm_source=wpstg_admin&utm_medium=finish_screen&utm_campaign=tutorial" target="_blank">Read
|
72 |
</p>
|
73 |
</li>
|
74 |
<li>
|
75 |
-
<strong>2. Verify that you are REALLY working on your staging site and NOT on your production site if you are
|
76 |
<br>
|
77 |
Your main and your staging site are both reachable under the same domain so
|
78 |
<br>
|
79 |
-
|
80 |
<p>
|
81 |
-
To
|
82 |
<br><br>
|
83 |
<img src="<?php echo $this->url . "/img/admin_dashboard.png" ?>">
|
84 |
<br>
|
85 |
-
On the fronpage the name also changed to <br>
|
86 |
<strong style="font-style:italic;">
|
87 |
"STAGING - <span class="wpstg-clone-name"><?php echo get_bloginfo("name")?></span>"
|
88 |
</strong>.
|
@@ -96,4 +92,4 @@
|
|
96 |
<div id="wpstg-error-details"></div>
|
97 |
</div>
|
98 |
|
99 |
-
<div
|
39 |
echo sprintf( __( 'WP Staging successfully created a staging site in a sub-directory of your main site accessable from:<br><strong><a href="%1$s" target="_blank" id="wpstg-clone-url-1">%1$s</a></strong>', 'wp-staging' ), $url );
|
40 |
?>
|
41 |
<br>
|
|
|
42 |
<br>
|
43 |
+
<a href="" class="wpstg-link-btn wpstg-blue-primary" id="wpstg-home-link">
|
44 |
+
<?php echo __("BACK", "wp-staging")?>
|
45 |
</a>
|
46 |
+
<a href="<?php echo $url; ?>" id="wpstg-clone-url" target="_blank" class="wpstg-link-btn wpstg-blue-primary">
|
47 |
+
<?php _e('Open Staging Site', 'wp-staging') ?><span style="font-size: 10px;"><?php _e('(Login with your admin credentials)', 'wp-staging') ?></span>
|
|
|
|
|
|
|
48 |
</a>
|
49 |
<div id="wpstg-success-notice">
|
50 |
+
<h3>
|
51 |
+
<?php _e("Please read this first:", "wp-staging")?>
|
52 |
</h3>
|
53 |
<ul>
|
54 |
<li>
|
55 |
+
<strong>1. Post name permalinks on your <span style="font-style:italic;">staging site</span> have been disabled for technical reasons. </strong>
|
56 |
<br>
|
57 |
+
Usually this will not affect your staging website. In 99% of all cases you do not need to activate permalinks.
|
58 |
<br>
|
59 |
<p>
|
60 |
+
If Apache is the webserver there is a good chance that permalinks can be activated without further modifications. Try to activate them from <br/>
|
61 |
<br>
|
62 |
<strong>Staging Site > wp-admin > Settings > Permalinks</strong></a>
|
63 |
<br/><br/>
|
64 |
+
If this does not work or Nginx webserver is used there might be some modifications needed in the files .htaccess (Apache) or *.conf (Nginx).
|
65 |
</p>
|
66 |
<p>
|
67 |
+
<strong><a href="https://wp-staging.com/docs/activate-permalinks-staging-site/?utm_source=wpstg_admin&utm_medium=finish_screen&utm_campaign=tutorial" target="_blank">Read this tutorial</a> to learn how to enable permalinks on the staging site.</strong>
|
68 |
</p>
|
69 |
</li>
|
70 |
<li>
|
71 |
+
<strong>2. Verify that you are REALLY working on your staging site and NOT on your production site if you are not 100% sure! </strong>
|
72 |
<br>
|
73 |
Your main and your staging site are both reachable under the same domain so
|
74 |
<br>
|
75 |
+
this can be confusing.
|
76 |
<p>
|
77 |
+
To make it more clear when you work on the staging site WP Staging changed the color of the admin bar:
|
78 |
<br><br>
|
79 |
<img src="<?php echo $this->url . "/img/admin_dashboard.png" ?>">
|
80 |
<br>
|
81 |
+
On the fronpage the site name also changed to <br>
|
82 |
<strong style="font-style:italic;">
|
83 |
"STAGING - <span class="wpstg-clone-name"><?php echo get_bloginfo("name")?></span>"
|
84 |
</strong>.
|
92 |
<div id="wpstg-error-details"></div>
|
93 |
</div>
|
94 |
|
95 |
+
<div class="wpstg-log-details"></div>
|
Backend/views/clone/ajax/update.php
CHANGED
@@ -30,4 +30,4 @@
|
|
30 |
<div id="wpstg-error-details"></div>
|
31 |
</div>
|
32 |
|
33 |
-
<div
|
30 |
<div id="wpstg-error-details"></div>
|
31 |
</div>
|
32 |
|
33 |
+
<div class="wpstg-log-details"></div>
|
Backend/views/clone/single-site/index.php
CHANGED
@@ -16,9 +16,6 @@
|
|
16 |
<i class="wpstg-icon-issue"></i><?php echo __( "Report Issue", "wp-staging" ); ?>
|
17 |
</button>
|
18 |
</li>
|
19 |
-
<li>
|
20 |
-
<span id="wpstg-loader" style="display:none;"></span>
|
21 |
-
</li>
|
22 |
</ul>
|
23 |
|
24 |
<div id="wpstg-workflow"></div>
|
16 |
<i class="wpstg-icon-issue"></i><?php echo __( "Report Issue", "wp-staging" ); ?>
|
17 |
</button>
|
18 |
</li>
|
|
|
|
|
|
|
19 |
</ul>
|
20 |
|
21 |
<div id="wpstg-workflow"></div>
|
Backend/views/notices/beta.php
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
<div class="wpstg_beta_notice wpstg-error" style="box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);">
|
2 |
<p>
|
3 |
<?php _e("WP Staging is well tested and we did a lot to catch every possible error but
|
1 |
+
<!-- Not used any longer. So can be used for other purposes in the future //-->
|
2 |
<div class="wpstg_beta_notice wpstg-error" style="box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);">
|
3 |
<p>
|
4 |
<?php _e("WP Staging is well tested and we did a lot to catch every possible error but
|
Backend/views/notices/wp-version-compatible-message.php
CHANGED
@@ -10,4 +10,4 @@
|
|
10 |
);
|
11 |
?>
|
12 |
</p>
|
13 |
-
</div>
|
10 |
);
|
11 |
?>
|
12 |
</p>
|
13 |
+
</div>
|
Core/Utils/Logger.php
CHANGED
@@ -1,19 +1,20 @@
|
|
1 |
<?php
|
2 |
-
namespace WPStaging\Utils;
|
3 |
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
|
|
9 |
|
10 |
-
use
|
|
|
11 |
|
12 |
/**
|
13 |
* Class Logger
|
14 |
* @package WPStaging\Utils
|
15 |
*/
|
16 |
-
class Logger
|
17 |
{
|
18 |
const TYPE_ERROR = "ERROR";
|
19 |
|
@@ -24,18 +25,18 @@ class Logger
|
|
24 |
const TYPE_WARNING = "WARNING";
|
25 |
|
26 |
const TYPE_INFO = "INFO";
|
27 |
-
|
28 |
const TYPE_DEBUG = "DEBUG";
|
29 |
|
30 |
/**
|
31 |
* Log directory (full path)
|
32 |
-
* @var
|
33 |
*/
|
34 |
private $logDir;
|
35 |
|
36 |
/**
|
37 |
* Log file extension
|
38 |
-
* @var
|
39 |
*/
|
40 |
private $logExtension = "log";
|
41 |
|
@@ -47,14 +48,16 @@ class Logger
|
|
47 |
|
48 |
/**
|
49 |
* Forced filename for the log
|
50 |
-
* @var null|
|
51 |
*/
|
52 |
private $fileName = null;
|
53 |
|
54 |
/**
|
55 |
* Logger constructor.
|
56 |
-
*
|
57 |
-
* @param null|
|
|
|
|
|
58 |
* @throws \Exception
|
59 |
*/
|
60 |
public function __construct($logDir = null, $logExtension = null)
|
@@ -69,7 +72,7 @@ class Logger
|
|
69 |
{
|
70 |
|
71 |
$this->logDir = \WPStaging\WPStaging::getContentDir() . "logs" . DIRECTORY_SEPARATOR;
|
72 |
-
|
73 |
}
|
74 |
|
75 |
// Set log extension
|
@@ -86,31 +89,33 @@ class Logger
|
|
86 |
}
|
87 |
|
88 |
/**
|
89 |
-
* @param
|
90 |
-
* @param
|
|
|
|
|
|
|
91 |
*/
|
92 |
-
public function log($message, $
|
93 |
{
|
94 |
-
$this->add($message, $
|
95 |
$this->commit();
|
96 |
}
|
97 |
|
98 |
/**
|
99 |
-
* @param
|
100 |
-
* @param
|
101 |
*/
|
102 |
public function add($message, $type = self::TYPE_ERROR)
|
103 |
-
{
|
104 |
-
|
105 |
$this->messages[] = array(
|
106 |
"type" => $type,
|
107 |
"date" => date("Y/m/d H:i:s"),
|
108 |
"message" => $message
|
109 |
-
|
110 |
}
|
111 |
|
112 |
/**
|
113 |
-
* @return null|
|
114 |
*/
|
115 |
public function getFileName()
|
116 |
{
|
@@ -118,7 +123,7 @@ class Logger
|
|
118 |
}
|
119 |
|
120 |
/**
|
121 |
-
* @param
|
122 |
*/
|
123 |
public function setFileName($fileName)
|
124 |
{
|
@@ -151,8 +156,9 @@ class Logger
|
|
151 |
}
|
152 |
|
153 |
/**
|
154 |
-
* @param null|
|
155 |
-
*
|
|
|
156 |
*/
|
157 |
public function read($file = null)
|
158 |
{
|
@@ -160,8 +166,9 @@ class Logger
|
|
160 |
}
|
161 |
|
162 |
/**
|
163 |
-
* @param null|
|
164 |
-
*
|
|
|
165 |
*/
|
166 |
public function getLogFile($fileName = null)
|
167 |
{
|
@@ -176,7 +183,9 @@ class Logger
|
|
176 |
|
177 |
/**
|
178 |
* Delete a log file
|
179 |
-
*
|
|
|
|
|
180 |
* @return bool
|
181 |
* @throws \Exception
|
182 |
*/
|
@@ -193,7 +202,7 @@ class Logger
|
|
193 |
}
|
194 |
|
195 |
/**
|
196 |
-
* @return
|
197 |
*/
|
198 |
public function getLogDir()
|
199 |
{
|
@@ -201,13 +210,13 @@ class Logger
|
|
201 |
}
|
202 |
|
203 |
/**
|
204 |
-
* @return
|
205 |
*/
|
206 |
public function getLogExtension()
|
207 |
{
|
208 |
return $this->logExtension;
|
209 |
}
|
210 |
-
|
211 |
/**
|
212 |
* Get last element of logging data array
|
213 |
* @return string
|
@@ -222,13 +231,78 @@ class Logger
|
|
222 |
return $this->messages[]=array_pop($this->messages);
|
223 |
}
|
224 |
}
|
225 |
-
|
226 |
/**
|
227 |
* Get running time in seconds
|
228 |
* @return int
|
229 |
*/
|
230 |
-
public function getRunningTime()
|
|
|
231 |
$str_time = $this->messages[0]["date"];
|
232 |
return $str_time;
|
233 |
}
|
234 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<?php
|
|
|
2 |
|
3 |
+
/**
|
4 |
+
* This class is not PSR-3 compliant. Currently just added the basic functionality to make the "change" easier
|
5 |
+
* in the future. For now, there are just few things to make transition easy.
|
6 |
+
*/
|
7 |
+
|
8 |
+
namespace WPStaging\Utils;
|
9 |
|
10 |
+
use Psr\Log\LoggerInterface;
|
11 |
+
use Psr\Log\LogLevel;
|
12 |
|
13 |
/**
|
14 |
* Class Logger
|
15 |
* @package WPStaging\Utils
|
16 |
*/
|
17 |
+
class Logger implements LoggerInterface
|
18 |
{
|
19 |
const TYPE_ERROR = "ERROR";
|
20 |
|
25 |
const TYPE_WARNING = "WARNING";
|
26 |
|
27 |
const TYPE_INFO = "INFO";
|
28 |
+
|
29 |
const TYPE_DEBUG = "DEBUG";
|
30 |
|
31 |
/**
|
32 |
* Log directory (full path)
|
33 |
+
* @var Strings
|
34 |
*/
|
35 |
private $logDir;
|
36 |
|
37 |
/**
|
38 |
* Log file extension
|
39 |
+
* @var Strings
|
40 |
*/
|
41 |
private $logExtension = "log";
|
42 |
|
48 |
|
49 |
/**
|
50 |
* Forced filename for the log
|
51 |
+
* @var null|Strings
|
52 |
*/
|
53 |
private $fileName = null;
|
54 |
|
55 |
/**
|
56 |
* Logger constructor.
|
57 |
+
*
|
58 |
+
* @param null|Strings $logDir
|
59 |
+
* @param null|Strings $logExtension
|
60 |
+
*
|
61 |
* @throws \Exception
|
62 |
*/
|
63 |
public function __construct($logDir = null, $logExtension = null)
|
72 |
{
|
73 |
|
74 |
$this->logDir = \WPStaging\WPStaging::getContentDir() . "logs" . DIRECTORY_SEPARATOR;
|
75 |
+
|
76 |
}
|
77 |
|
78 |
// Set log extension
|
89 |
}
|
90 |
|
91 |
/**
|
92 |
+
* @param Strings $level
|
93 |
+
* @param Strings $message
|
94 |
+
* @param array $context
|
95 |
+
*
|
96 |
+
* @return void
|
97 |
*/
|
98 |
+
public function log($level, $message, array $context = [])
|
99 |
{
|
100 |
+
$this->add($message, $level);
|
101 |
$this->commit();
|
102 |
}
|
103 |
|
104 |
/**
|
105 |
+
* @param Strings $message
|
106 |
+
* @param Strings $type
|
107 |
*/
|
108 |
public function add($message, $type = self::TYPE_ERROR)
|
109 |
+
{
|
|
|
110 |
$this->messages[] = array(
|
111 |
"type" => $type,
|
112 |
"date" => date("Y/m/d H:i:s"),
|
113 |
"message" => $message
|
114 |
+
);
|
115 |
}
|
116 |
|
117 |
/**
|
118 |
+
* @return null|Strings
|
119 |
*/
|
120 |
public function getFileName()
|
121 |
{
|
123 |
}
|
124 |
|
125 |
/**
|
126 |
+
* @param Strings $fileName
|
127 |
*/
|
128 |
public function setFileName($fileName)
|
129 |
{
|
156 |
}
|
157 |
|
158 |
/**
|
159 |
+
* @param null|Strings $file
|
160 |
+
*
|
161 |
+
* @return Strings
|
162 |
*/
|
163 |
public function read($file = null)
|
164 |
{
|
166 |
}
|
167 |
|
168 |
/**
|
169 |
+
* @param null|Strings $fileName
|
170 |
+
*
|
171 |
+
* @return Strings
|
172 |
*/
|
173 |
public function getLogFile($fileName = null)
|
174 |
{
|
183 |
|
184 |
/**
|
185 |
* Delete a log file
|
186 |
+
*
|
187 |
+
* @param Strings $logFileName
|
188 |
+
*
|
189 |
* @return bool
|
190 |
* @throws \Exception
|
191 |
*/
|
202 |
}
|
203 |
|
204 |
/**
|
205 |
+
* @return Strings
|
206 |
*/
|
207 |
public function getLogDir()
|
208 |
{
|
210 |
}
|
211 |
|
212 |
/**
|
213 |
+
* @return Strings
|
214 |
*/
|
215 |
public function getLogExtension()
|
216 |
{
|
217 |
return $this->logExtension;
|
218 |
}
|
219 |
+
|
220 |
/**
|
221 |
* Get last element of logging data array
|
222 |
* @return string
|
231 |
return $this->messages[]=array_pop($this->messages);
|
232 |
}
|
233 |
}
|
234 |
+
|
235 |
/**
|
236 |
* Get running time in seconds
|
237 |
* @return int
|
238 |
*/
|
239 |
+
public function getRunningTime()
|
240 |
+
{
|
241 |
$str_time = $this->messages[0]["date"];
|
242 |
return $str_time;
|
243 |
}
|
244 |
+
|
245 |
+
/**
|
246 |
+
* @inheritDoc
|
247 |
+
*/
|
248 |
+
public function emergency($message, array $context = [])
|
249 |
+
{
|
250 |
+
$this->add($message, LogLevel::EMERGENCY);
|
251 |
+
}
|
252 |
+
|
253 |
+
/**
|
254 |
+
* @inheritDoc
|
255 |
+
*/
|
256 |
+
public function alert($message, array $context = [])
|
257 |
+
{
|
258 |
+
$this->add($message, LogLevel::ALERT);
|
259 |
+
}
|
260 |
+
|
261 |
+
/**
|
262 |
+
* @inheritDoc
|
263 |
+
*/
|
264 |
+
public function critical($message, array $context = [])
|
265 |
+
{
|
266 |
+
$this->add($message, LogLevel::CRITICAL);
|
267 |
+
}
|
268 |
+
|
269 |
+
/**
|
270 |
+
* @inheritDoc
|
271 |
+
*/
|
272 |
+
public function error($message, array $context = [])
|
273 |
+
{
|
274 |
+
$this->add($message, LogLevel::ERROR);
|
275 |
+
}
|
276 |
+
|
277 |
+
/**
|
278 |
+
* @inheritDoc
|
279 |
+
*/
|
280 |
+
public function warning($message, array $context = [])
|
281 |
+
{
|
282 |
+
$this->add($message, LogLevel::WARNING);
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* @inheritDoc
|
287 |
+
*/
|
288 |
+
public function notice($message, array $context = [])
|
289 |
+
{
|
290 |
+
$this->add($message, LogLevel::NOTICE);
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* @inheritDoc
|
295 |
+
*/
|
296 |
+
public function info($message, array $context = [])
|
297 |
+
{
|
298 |
+
$this->add($message, LogLevel::INFO);
|
299 |
+
}
|
300 |
+
|
301 |
+
/**
|
302 |
+
* @inheritDoc
|
303 |
+
*/
|
304 |
+
public function debug($message, array $context = [])
|
305 |
+
{
|
306 |
+
$this->add($message, LogLevel::DEBUG);
|
307 |
+
}
|
308 |
+
}
|
Core/Utils/functions.php
CHANGED
@@ -523,52 +523,6 @@ function wpstg_chown($file, $owner)
|
|
523 |
return true;
|
524 |
}
|
525 |
|
526 |
-
/**
|
527 |
-
* Checks if the passed string would match the given shell wildcard pattern.
|
528 |
-
* This function emulates [[fnmatch()]], which may be unavailable at certain environment, using PCRE.
|
529 |
-
* @param string $pattern the shell wildcard pattern.
|
530 |
-
* @param string $string the tested string.
|
531 |
-
* @param array $options options for matching. Valid options are:
|
532 |
-
*
|
533 |
-
* - caseSensitive: bool, whether pattern should be case sensitive. Defaults to `true`.
|
534 |
-
* - escape: bool, whether backslash escaping is enabled. Defaults to `true`.
|
535 |
-
* - filePath: bool, whether slashes in string only matches slashes in the given pattern. Defaults to `false`.
|
536 |
-
*
|
537 |
-
* @return bool whether the string matches pattern or not.
|
538 |
-
*/
|
539 |
-
function wpstg_fnmatch($pattern, $string, $options = array())
|
540 |
-
{
|
541 |
-
if ($pattern === '*' && empty($options['filePath'])) {
|
542 |
-
return true;
|
543 |
-
}
|
544 |
-
$replacements = array(
|
545 |
-
'\\\\\\\\' => '\\\\',
|
546 |
-
'\\\\\\*' => '[*]',
|
547 |
-
'\\\\\\?' => '[?]',
|
548 |
-
'\*' => '.*',
|
549 |
-
'\?' => '.',
|
550 |
-
'\[\!' => '[^',
|
551 |
-
'\[' => '[',
|
552 |
-
'\]' => ']',
|
553 |
-
'\-' => '-',
|
554 |
-
);
|
555 |
-
if (isset($options['escape']) && !$options['escape']) {
|
556 |
-
unset($replacements['\\\\\\\\']);
|
557 |
-
unset($replacements['\\\\\\*']);
|
558 |
-
unset($replacements['\\\\\\?']);
|
559 |
-
}
|
560 |
-
if (!empty($options['filePath'])) {
|
561 |
-
$replacements['\*'] = '[^/\\\\]*';
|
562 |
-
$replacements['\?'] = '[^/\\\\]';
|
563 |
-
}
|
564 |
-
$pattern = strtr(preg_quote($pattern, '#'), $replacements);
|
565 |
-
$pattern = '#^' . $pattern . '$#us';
|
566 |
-
if (isset($options['caseSensitive']) && !$options['caseSensitive']) {
|
567 |
-
$pattern .= 'i';
|
568 |
-
}
|
569 |
-
return preg_match($pattern, $string) === 1;
|
570 |
-
}
|
571 |
-
|
572 |
/*
|
573 |
* Check if website is installed locally
|
574 |
* @return boolean
|
@@ -589,7 +543,7 @@ function wpstg_is_local()
|
|
589 |
/**
|
590 |
* Get absolute path to plugins dir.
|
591 |
* Take into account custom user made path modifications
|
592 |
-
* A function with the name wpstg_get_plugins_dir() already exists in
|
593 |
* must-use plugin wp-staging-optimizer.php so we've created this one that does the same job.
|
594 |
*
|
595 |
* @return string
|
523 |
return true;
|
524 |
}
|
525 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
526 |
/*
|
527 |
* Check if website is installed locally
|
528 |
* @return boolean
|
543 |
/**
|
544 |
* Get absolute path to plugins dir.
|
545 |
* Take into account custom user made path modifications
|
546 |
+
* A function with the name wpstg_get_plugins_dir() already exists in
|
547 |
* must-use plugin wp-staging-optimizer.php so we've created this one that does the same job.
|
548 |
*
|
549 |
* @return string
|
Core/WPStaging.php
CHANGED
@@ -13,12 +13,12 @@ require_once __DIR__ . DIRECTORY_SEPARATOR . "Utils" . DIRECTORY_SEPARATOR . "Au
|
|
13 |
use WPStaging\Backend\Administrator;
|
14 |
use WPStaging\DTO\Settings;
|
15 |
use WPStaging\Frontend\Frontend;
|
|
|
16 |
use WPStaging\Utils\Autoloader;
|
17 |
use WPStaging\Utils\Cache;
|
18 |
use WPStaging\Utils\Loader;
|
19 |
use WPStaging\Utils\Logger;
|
20 |
-
use WPStaging\
|
21 |
-
use WPStaging\Cron\Cron;
|
22 |
|
23 |
/**
|
24 |
* Class WPStaging
|
@@ -62,7 +62,6 @@ final class WPStaging {
|
|
62 |
|
63 |
$this->registerMain();
|
64 |
$this->registerNamespaces();
|
65 |
-
$this->loadLanguages();
|
66 |
$this->loadDependencies();
|
67 |
$this->defineHooks();
|
68 |
$this->initCron();
|
@@ -184,6 +183,22 @@ final class WPStaging {
|
|
184 |
wp_enqueue_script(
|
185 |
"wpstg-admin-pro-script", $this->url . "Backend/Pro/public/js/wpstg-admin-pro.js", array("jquery"), $this->getVersion(), false
|
186 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
}
|
188 |
|
189 |
// Load admin css files
|
@@ -318,6 +333,12 @@ final class WPStaging {
|
|
318 |
|
319 |
$this->set( "settings", new Settings() );
|
320 |
|
|
|
|
|
|
|
|
|
|
|
|
|
321 |
if( is_admin() ) {
|
322 |
new Administrator( $this );
|
323 |
} else {
|
@@ -358,6 +379,15 @@ final class WPStaging {
|
|
358 |
return (isset( $this->services[$name] )) ? $this->services[$name] : null;
|
359 |
}
|
360 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
361 |
/**
|
362 |
* @return string
|
363 |
*/
|
@@ -439,37 +469,6 @@ final class WPStaging {
|
|
439 |
return $delay;
|
440 |
}
|
441 |
|
442 |
-
/**
|
443 |
-
* Load language file
|
444 |
-
*/
|
445 |
-
public function loadLanguages() {
|
446 |
-
$languagesDirectory = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $this->slug . DIRECTORY_SEPARATOR . "languages" . DIRECTORY_SEPARATOR;
|
447 |
-
|
448 |
-
// Set filter for plugins languages directory
|
449 |
-
$languagesDirectory = apply_filters( "wpstg_languages_directory", $languagesDirectory );
|
450 |
-
|
451 |
-
// Traditional WP plugin locale filter
|
452 |
-
$locale = apply_filters( "plugin_locale", get_locale(), "wp-staging" );
|
453 |
-
$moFile = sprintf( '%1$s-%2$s.mo', "wp-staging", $locale );
|
454 |
-
|
455 |
-
// Setup paths to current locale file
|
456 |
-
$moFileLocal = $languagesDirectory . $moFile;
|
457 |
-
$moFileGlobal = WP_LANG_DIR . DIRECTORY_SEPARATOR . "wp-staging" . DIRECTORY_SEPARATOR . $moFile;
|
458 |
-
|
459 |
-
// Global file (/wp-content/languages/wp-staging/wpstg)
|
460 |
-
if( file_exists( $moFileGlobal ) ) {
|
461 |
-
load_textdomain( "wp-staging", $moFileGlobal );
|
462 |
-
}
|
463 |
-
// Local file (/wp-content/plugins/wp-staging/languages/)
|
464 |
-
elseif( file_exists( $moFileLocal ) ) {
|
465 |
-
load_textdomain( "wp-staging", $moFileLocal );
|
466 |
-
}
|
467 |
-
// Default file
|
468 |
-
else {
|
469 |
-
load_plugin_textdomain( "wp-staging", false, $languagesDirectory );
|
470 |
-
}
|
471 |
-
}
|
472 |
-
|
473 |
/**
|
474 |
* Initialize licensing functions
|
475 |
* @return boolean
|
13 |
use WPStaging\Backend\Administrator;
|
14 |
use WPStaging\DTO\Settings;
|
15 |
use WPStaging\Frontend\Frontend;
|
16 |
+
use WPStaging\Service\Container\Container;
|
17 |
use WPStaging\Utils\Autoloader;
|
18 |
use WPStaging\Utils\Cache;
|
19 |
use WPStaging\Utils\Loader;
|
20 |
use WPStaging\Utils\Logger;
|
21 |
+
use WPStaging\Service\PluginFactory;
|
|
|
22 |
|
23 |
/**
|
24 |
* Class WPStaging
|
62 |
|
63 |
$this->registerMain();
|
64 |
$this->registerNamespaces();
|
|
|
65 |
$this->loadDependencies();
|
66 |
$this->defineHooks();
|
67 |
$this->initCron();
|
183 |
wp_enqueue_script(
|
184 |
"wpstg-admin-pro-script", $this->url . "Backend/Pro/public/js/wpstg-admin-pro.js", array("jquery"), $this->getVersion(), false
|
185 |
);
|
186 |
+
|
187 |
+
// Sweet Alert
|
188 |
+
wp_enqueue_script(
|
189 |
+
'wpstg-admin-pro-sweetalerts',
|
190 |
+
$this->url . 'Backend/Pro/public/vendor/sweetalert2/sweetalert2.all.min.js',
|
191 |
+
[],
|
192 |
+
$this->getVersion(),
|
193 |
+
true
|
194 |
+
);
|
195 |
+
|
196 |
+
wp_enqueue_style(
|
197 |
+
'wpstg-admin-pro-sweetalerts',
|
198 |
+
$this->url . 'Backend/Pro/public/vendor/sweetalert2/wordpress-admin.min.css',
|
199 |
+
[],
|
200 |
+
$this->getVersion()
|
201 |
+
);
|
202 |
}
|
203 |
|
204 |
// Load admin css files
|
333 |
|
334 |
$this->set( "settings", new Settings() );
|
335 |
|
336 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
337 |
+
$plugin = PluginFactory::make(Plugin::class);
|
338 |
+
$plugin->init();
|
339 |
+
$this->set(Plugin::class, $plugin);
|
340 |
+
|
341 |
+
// Set Administrator
|
342 |
if( is_admin() ) {
|
343 |
new Administrator( $this );
|
344 |
} else {
|
379 |
return (isset( $this->services[$name] )) ? $this->services[$name] : null;
|
380 |
}
|
381 |
|
382 |
+
/**
|
383 |
+
* @return Container
|
384 |
+
*/
|
385 |
+
public static function getContainer()
|
386 |
+
{
|
387 |
+
/** @noinspection NullPointerExceptionInspection */
|
388 |
+
return self::$instance->get(Plugin::class)->getContainer();
|
389 |
+
}
|
390 |
+
|
391 |
/**
|
392 |
* @return string
|
393 |
*/
|
469 |
return $delay;
|
470 |
}
|
471 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
472 |
/**
|
473 |
* Initialize licensing functions
|
474 |
* @return boolean
|
Frontend/Frontend.php
CHANGED
@@ -9,80 +9,78 @@ use WPStaging\Frontend\loginForm;
|
|
9 |
* Class Frontend
|
10 |
* @package WPStaging\Frontend
|
11 |
*/
|
12 |
-
class Frontend extends InjectionAware
|
|
|
13 |
|
14 |
/**
|
15 |
* @var object
|
16 |
*/
|
17 |
private $settings;
|
18 |
|
19 |
-
/**
|
20 |
-
*
|
21 |
-
* @var string
|
22 |
-
*/
|
23 |
-
private $loginSlug;
|
24 |
-
|
25 |
/**
|
26 |
* Frontend initialization.
|
27 |
*/
|
28 |
-
public function initialize()
|
|
|
29 |
$this->defineHooks();
|
30 |
|
31 |
-
$this->settings = json_decode(
|
32 |
|
33 |
-
$this->loginSlug = isset( $this->settings->loginSlug ) ? $this->settings->loginSlug : '';
|
34 |
}
|
35 |
|
36 |
/**
|
37 |
* Define Hooks
|
38 |
*/
|
39 |
-
private function defineHooks()
|
|
|
40 |
// Get loader
|
41 |
-
$loader = $this->di->get(
|
42 |
-
$loader->addAction(
|
43 |
-
$loader->addFilter(
|
44 |
}
|
45 |
|
46 |
/**
|
47 |
* Change admin_bar site_name
|
48 |
*
|
49 |
-
* @global object $wp_admin_bar
|
50 |
* @return void
|
|
|
51 |
*/
|
52 |
-
public function changeSiteName()
|
|
|
53 |
global $wp_admin_bar;
|
54 |
-
if(
|
55 |
// Main Title
|
56 |
-
$wp_admin_bar->add_menu(
|
57 |
-
'id'
|
58 |
-
'title' => is_admin() ? ('STAGING - ' . get_bloginfo(
|
59 |
-
'href'
|
60 |
-
)
|
61 |
}
|
62 |
}
|
63 |
|
64 |
/**
|
65 |
* Check permissions for the page to decide whether or not to disable the page
|
66 |
*/
|
67 |
-
public function checkPermissions()
|
|
|
68 |
$this->resetPermaLinks();
|
69 |
|
70 |
-
if(
|
71 |
|
72 |
$args = array(
|
73 |
-
'echo'
|
74 |
// Default 'redirect' value takes the user back to the request URI.
|
75 |
-
'redirect'
|
76 |
-
'form_id'
|
77 |
-
'label_username' => __(
|
78 |
-
'label_password' => __(
|
79 |
-
'label_remember' => __(
|
80 |
-
'label_log_in'
|
81 |
-
'id_username'
|
82 |
-
'id_password'
|
83 |
-
'id_remember'
|
84 |
-
'id_submit'
|
85 |
-
'remember'
|
86 |
'value_username' => '',
|
87 |
// Set 'value_remember' to true to default the "Remember me" checkbox to checked.
|
88 |
'value_remember' => false,
|
@@ -93,7 +91,7 @@ class Frontend extends InjectionAware {
|
|
93 |
* Lines below are not used at the moment but are fully functional
|
94 |
*/
|
95 |
$login = new loginForm();
|
96 |
-
$login->renderForm(
|
97 |
die();
|
98 |
}
|
99 |
}
|
@@ -102,7 +100,8 @@ class Frontend extends InjectionAware {
|
|
102 |
* Get path to wp-login.php
|
103 |
* @return string
|
104 |
*/
|
105 |
-
private function getLoginUrl()
|
|
|
106 |
return get_site_url() . '/wp-login.php';
|
107 |
}
|
108 |
|
@@ -110,38 +109,34 @@ class Frontend extends InjectionAware {
|
|
110 |
* Check if the page should be blocked
|
111 |
* @return bool
|
112 |
*/
|
113 |
-
private function
|
114 |
{
|
115 |
-
|
|
|
|
|
|
|
|
|
116 |
if (!wpstg_is_stagingsite()) {
|
117 |
return false;
|
118 |
}
|
119 |
|
120 |
-
// Allow access for
|
121 |
if (current_user_can('manage_options')) {
|
122 |
return false;
|
123 |
}
|
124 |
|
125 |
-
// Simple check
|
126 |
if (!defined('WPSTGPRO_VERSION')) {
|
127 |
-
return (
|
128 |
-
(!isset($this->settings->disableAdminLogin) || '1' !== $this->settings->disableAdminLogin) &&
|
129 |
-
(!current_user_can("manage_options") && !$this->isLoginPage() && !is_admin())
|
130 |
-
);
|
131 |
}
|
132 |
|
133 |
-
// Allow access for
|
134 |
-
if (!empty($this->settings->userRoles) &&
|
135 |
-
(in_array('all', $this->settings->userRoles) && !$this->isLoginPage() && !is_admin())
|
136 |
-
) {
|
137 |
return false;
|
138 |
}
|
139 |
|
140 |
-
//
|
141 |
-
if (
|
142 |
-
(!isset($this->settings->userRoles) || !is_array($this->settings->userRoles)) &&
|
143 |
-
(!current_user_can('manage_options') && !$this->isLoginPage() && !is_admin())
|
144 |
-
) {
|
145 |
return true;
|
146 |
}
|
147 |
|
@@ -161,46 +156,45 @@ class Frontend extends InjectionAware {
|
|
161 |
* Check if it is a staging site
|
162 |
* @return bool
|
163 |
*/
|
164 |
-
private function isStagingSite()
|
165 |
-
|
|
|
166 |
}
|
167 |
|
168 |
/**
|
169 |
* Check if it is the login page
|
170 |
* @return bool
|
171 |
*/
|
172 |
-
private function isLoginPage()
|
|
|
173 |
|
174 |
-
return (
|
175 |
-
in_array( $GLOBALS["pagenow"], array("wp-login.php") ) ||
|
176 |
-
in_array( $this->loginSlug, $_GET ) ||
|
177 |
-
array_key_exists( $this->loginSlug, $_GET )
|
178 |
-
);
|
179 |
}
|
180 |
|
181 |
/**
|
182 |
* Reset permalink structure of the clone to default; index.php?p=123
|
183 |
*/
|
184 |
-
private function resetPermaLinks()
|
185 |
-
|
186 |
-
|
|
|
187 |
return;
|
188 |
}
|
189 |
|
190 |
// Do nothing
|
191 |
-
if(defined('WPSTGPRO_VERSION')) {
|
192 |
if (isset($this->settings->keepPermalinks) && $this->settings->keepPermalinks === "1") {
|
193 |
return;
|
194 |
}
|
195 |
}
|
196 |
|
197 |
-
// $wp_rewrite is not available before the init hook. So we need to use the global
|
198 |
global $wp_rewrite;
|
199 |
-
$wp_rewrite->set_permalink_structure(
|
200 |
|
201 |
flush_rewrite_rules();
|
202 |
|
203 |
-
update_option(
|
204 |
}
|
205 |
|
206 |
-
}
|
9 |
* Class Frontend
|
10 |
* @package WPStaging\Frontend
|
11 |
*/
|
12 |
+
class Frontend extends InjectionAware
|
13 |
+
{
|
14 |
|
15 |
/**
|
16 |
* @var object
|
17 |
*/
|
18 |
private $settings;
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
/**
|
21 |
* Frontend initialization.
|
22 |
*/
|
23 |
+
public function initialize()
|
24 |
+
{
|
25 |
$this->defineHooks();
|
26 |
|
27 |
+
$this->settings = json_decode(json_encode(get_option("wpstg_settings", array())));
|
28 |
|
|
|
29 |
}
|
30 |
|
31 |
/**
|
32 |
* Define Hooks
|
33 |
*/
|
34 |
+
private function defineHooks()
|
35 |
+
{
|
36 |
// Get loader
|
37 |
+
$loader = $this->di->get("loader");
|
38 |
+
$loader->addAction("init", $this, "checkPermissions");
|
39 |
+
$loader->addFilter("wp_before_admin_bar_render", $this, "changeSiteName");
|
40 |
}
|
41 |
|
42 |
/**
|
43 |
* Change admin_bar site_name
|
44 |
*
|
|
|
45 |
* @return void
|
46 |
+
* @global object $wp_admin_bar
|
47 |
*/
|
48 |
+
public function changeSiteName()
|
49 |
+
{
|
50 |
global $wp_admin_bar;
|
51 |
+
if ($this->isStagingSite()) {
|
52 |
// Main Title
|
53 |
+
$wp_admin_bar->add_menu(array(
|
54 |
+
'id' => 'site-name',
|
55 |
+
'title' => is_admin() ? ('STAGING - ' . get_bloginfo('name')) : ('STAGING - ' . get_bloginfo('name') . ' Dashboard'),
|
56 |
+
'href' => is_admin() ? home_url('/') : admin_url(),
|
57 |
+
));
|
58 |
}
|
59 |
}
|
60 |
|
61 |
/**
|
62 |
* Check permissions for the page to decide whether or not to disable the page
|
63 |
*/
|
64 |
+
public function checkPermissions()
|
65 |
+
{
|
66 |
$this->resetPermaLinks();
|
67 |
|
68 |
+
if ($this->isLoginRequired()) {
|
69 |
|
70 |
$args = array(
|
71 |
+
'echo' => true,
|
72 |
// Default 'redirect' value takes the user back to the request URI.
|
73 |
+
'redirect' => (is_ssl() ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'],
|
74 |
+
'form_id' => 'loginform',
|
75 |
+
'label_username' => __('Username or Email Address'),
|
76 |
+
'label_password' => __('Password'),
|
77 |
+
'label_remember' => __('Remember Me'),
|
78 |
+
'label_log_in' => __('Log In'),
|
79 |
+
'id_username' => 'user_login',
|
80 |
+
'id_password' => 'user_pass',
|
81 |
+
'id_remember' => 'rememberme',
|
82 |
+
'id_submit' => 'wp-submit',
|
83 |
+
'remember' => true,
|
84 |
'value_username' => '',
|
85 |
// Set 'value_remember' to true to default the "Remember me" checkbox to checked.
|
86 |
'value_remember' => false,
|
91 |
* Lines below are not used at the moment but are fully functional
|
92 |
*/
|
93 |
$login = new loginForm();
|
94 |
+
$login->renderForm($args);
|
95 |
die();
|
96 |
}
|
97 |
}
|
100 |
* Get path to wp-login.php
|
101 |
* @return string
|
102 |
*/
|
103 |
+
private function getLoginUrl()
|
104 |
+
{
|
105 |
return get_site_url() . '/wp-login.php';
|
106 |
}
|
107 |
|
109 |
* Check if the page should be blocked
|
110 |
* @return bool
|
111 |
*/
|
112 |
+
private function isLoginRequired()
|
113 |
{
|
114 |
+
|
115 |
+
if ($this->isLoginPage() || is_admin()) {
|
116 |
+
return false;
|
117 |
+
}
|
118 |
+
|
119 |
if (!wpstg_is_stagingsite()) {
|
120 |
return false;
|
121 |
}
|
122 |
|
123 |
+
// Allow access for administrator
|
124 |
if (current_user_can('manage_options')) {
|
125 |
return false;
|
126 |
}
|
127 |
|
128 |
+
// Simple check (free version only)
|
129 |
if (!defined('WPSTGPRO_VERSION')) {
|
130 |
+
return (!isset($this->settings->disableAdminLogin) || '1' !== $this->settings->disableAdminLogin);
|
|
|
|
|
|
|
131 |
}
|
132 |
|
133 |
+
// Allow access for wp staging user role "all"
|
134 |
+
if (!empty($this->settings->userRoles) && in_array('all', $this->settings->userRoles)) {
|
|
|
|
|
135 |
return false;
|
136 |
}
|
137 |
|
138 |
+
// Allow access only for administratorss if no user roles are defined
|
139 |
+
if (!isset($this->settings->userRoles) || !is_array($this->settings->userRoles)) {
|
|
|
|
|
|
|
140 |
return true;
|
141 |
}
|
142 |
|
156 |
* Check if it is a staging site
|
157 |
* @return bool
|
158 |
*/
|
159 |
+
private function isStagingSite()
|
160 |
+
{
|
161 |
+
return ("true" === get_option("wpstg_is_staging_site"));
|
162 |
}
|
163 |
|
164 |
/**
|
165 |
* Check if it is the login page
|
166 |
* @return bool
|
167 |
*/
|
168 |
+
private function isLoginPage()
|
169 |
+
{
|
170 |
|
171 |
+
return (in_array($GLOBALS["pagenow"], array("wp-login.php")));
|
|
|
|
|
|
|
|
|
172 |
}
|
173 |
|
174 |
/**
|
175 |
* Reset permalink structure of the clone to default; index.php?p=123
|
176 |
*/
|
177 |
+
private function resetPermaLinks()
|
178 |
+
{
|
179 |
+
// Do nothing
|
180 |
+
if (!$this->isStagingSite() || "true" === get_option("wpstg_rmpermalinks_executed")) {
|
181 |
return;
|
182 |
}
|
183 |
|
184 |
// Do nothing
|
185 |
+
if (defined('WPSTGPRO_VERSION')) {
|
186 |
if (isset($this->settings->keepPermalinks) && $this->settings->keepPermalinks === "1") {
|
187 |
return;
|
188 |
}
|
189 |
}
|
190 |
|
191 |
+
// $wp_rewrite is not available before the init hook. So we need to use the global variable
|
192 |
global $wp_rewrite;
|
193 |
+
$wp_rewrite->set_permalink_structure(null);
|
194 |
|
195 |
flush_rewrite_rules();
|
196 |
|
197 |
+
update_option("wpstg_rmpermalinks_executed", "true");
|
198 |
}
|
199 |
|
200 |
+
}
|
Manager/Database/TableDto.php
ADDED
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; type-hints & return types
|
5 |
+
|
6 |
+
namespace WPStaging\Manager\Database;
|
7 |
+
|
8 |
+
use DateTime;
|
9 |
+
use WPStaging\Service\Interfaces\HydrateableInterface;
|
10 |
+
use WPStaging\Service\Utils\FileSize;
|
11 |
+
|
12 |
+
class TableDto implements HydrateableInterface
|
13 |
+
{
|
14 |
+
/** @var string */
|
15 |
+
private $name;
|
16 |
+
|
17 |
+
/** @var int */
|
18 |
+
private $rows;
|
19 |
+
|
20 |
+
/** @var int */
|
21 |
+
private $size;
|
22 |
+
|
23 |
+
/** @var int */
|
24 |
+
private $autoIncrement;
|
25 |
+
|
26 |
+
/** @var DateTime */
|
27 |
+
private $createdAt;
|
28 |
+
|
29 |
+
/** @var DateTime */
|
30 |
+
private $updatedAt;
|
31 |
+
|
32 |
+
public function hydrate(array $data = [])
|
33 |
+
{
|
34 |
+
$this->setName($data['Name']);
|
35 |
+
|
36 |
+
$this->setRows(isset($data['Rows'])? (int) $data['Rows'] : 0);
|
37 |
+
$this->setAutoIncrement(isset($data['Auto_increment'])? $data['Auto_increment'] : null);
|
38 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
39 |
+
$this->setCreatedAt(new DateTime(isset($data['Create_time'])? $data['Create_time'] : ''));
|
40 |
+
if (isset($data['Update_time']) && $data['Update_time']) {
|
41 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
42 |
+
$this->setUpdatedAt(new DateTime($data['Update_time']));
|
43 |
+
}
|
44 |
+
|
45 |
+
if (isset($data['Data_length'], $data['Index_length'])) {
|
46 |
+
$size = (int) $data['Data_length'] + (int) $data['Index_length'];
|
47 |
+
$this->setSize($size);
|
48 |
+
}
|
49 |
+
|
50 |
+
return $this;
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @return string
|
55 |
+
*/
|
56 |
+
public function getName()
|
57 |
+
{
|
58 |
+
return $this->name;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* @param string $name
|
63 |
+
*/
|
64 |
+
public function setName($name)
|
65 |
+
{
|
66 |
+
$this->name = $name;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @return int
|
71 |
+
*/
|
72 |
+
public function getRows()
|
73 |
+
{
|
74 |
+
return $this->rows;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* @param int $rows
|
79 |
+
*/
|
80 |
+
public function setRows($rows)
|
81 |
+
{
|
82 |
+
$this->rows = $rows;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* @return int
|
87 |
+
*/
|
88 |
+
public function getSize()
|
89 |
+
{
|
90 |
+
return $this->size;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* @param int $size
|
95 |
+
*/
|
96 |
+
public function setSize($size)
|
97 |
+
{
|
98 |
+
$this->size = $size;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* @return int|null
|
103 |
+
*/
|
104 |
+
public function getAutoIncrement()
|
105 |
+
{
|
106 |
+
return $this->autoIncrement;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* @param int|null $autoIncrement
|
111 |
+
*/
|
112 |
+
public function setAutoIncrement($autoIncrement)
|
113 |
+
{
|
114 |
+
$this->autoIncrement = $autoIncrement;
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* @return DateTime
|
119 |
+
*/
|
120 |
+
public function getCreatedAt()
|
121 |
+
{
|
122 |
+
return $this->createdAt;
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* @param DateTime $createdAt
|
127 |
+
*/
|
128 |
+
public function setCreatedAt($createdAt)
|
129 |
+
{
|
130 |
+
$this->createdAt = $createdAt;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* @return DateTime|null
|
135 |
+
*/
|
136 |
+
public function getUpdatedAt()
|
137 |
+
{
|
138 |
+
return $this->updatedAt;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* @param DateTime $updatedAt
|
143 |
+
*/
|
144 |
+
public function setUpdatedAt($updatedAt)
|
145 |
+
{
|
146 |
+
$this->updatedAt = $updatedAt;
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* @return string
|
151 |
+
*/
|
152 |
+
public function getHumanReadableSize()
|
153 |
+
{
|
154 |
+
return (new FileSize)->humanReadable($this->size);
|
155 |
+
}
|
156 |
+
}
|
Manager/Database/TableManager.php
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x type-hints & return types
|
5 |
+
|
6 |
+
namespace WPStaging\Manager\Database;
|
7 |
+
|
8 |
+
use WPStaging\Service\Adapter\Database;
|
9 |
+
use WPStaging\Service\Collection\Collection;
|
10 |
+
|
11 |
+
class TableManager
|
12 |
+
{
|
13 |
+
/** @var Database */
|
14 |
+
private $database;
|
15 |
+
|
16 |
+
public function __construct()
|
17 |
+
{
|
18 |
+
$this->database = new Database;
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @param string|null $prefix
|
23 |
+
*
|
24 |
+
* @return TableDto[]|Collection|null
|
25 |
+
*/
|
26 |
+
public function findStartsWith($prefix = null)
|
27 |
+
{
|
28 |
+
$tables = $this->database->find('SHOW TABLE STATUS LIKE "' . $this->provideSqlPrefix($prefix) . '%"');
|
29 |
+
if (!$tables) {
|
30 |
+
return null;
|
31 |
+
}
|
32 |
+
|
33 |
+
$collection = new Collection(TableDto::class);
|
34 |
+
foreach ($tables as $table) {
|
35 |
+
$collection->attach((new TableDto)->hydrate((array) $table));
|
36 |
+
}
|
37 |
+
return $collection;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* @param string|null $prefix
|
42 |
+
* @return string
|
43 |
+
*/
|
44 |
+
private function provideSqlPrefix($prefix = null)
|
45 |
+
{
|
46 |
+
return $this->database->provideSqlPrefix($prefix);
|
47 |
+
}
|
48 |
+
}
|
Manager/FileSystem/FileManager.php
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; return types && type-hints
|
5 |
+
|
6 |
+
namespace WPStaging\Manager\FileSystem;
|
7 |
+
|
8 |
+
class FileManager
|
9 |
+
{
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @param string $file full path + filename
|
13 |
+
* @param array $excludedFiles List of filenames. Can be wildcard pattern like data.php, data*.php, *.php, .php
|
14 |
+
* @return boolean
|
15 |
+
*/
|
16 |
+
public function isFilenameExcluded($file, $excludedFiles)
|
17 |
+
{
|
18 |
+
$filename = basename($file);
|
19 |
+
|
20 |
+
// Regular filenames
|
21 |
+
if (in_array($filename, $excludedFiles, true)) {
|
22 |
+
return true;
|
23 |
+
}
|
24 |
+
|
25 |
+
// Wildcards
|
26 |
+
foreach ($excludedFiles as $pattern) {
|
27 |
+
if ($this->isPatternMatching($pattern, $filename)) {
|
28 |
+
return true;
|
29 |
+
}
|
30 |
+
}
|
31 |
+
return false;
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Checks if the passed string would match the given shell wildcard pattern.
|
36 |
+
* This function emulates [[fnmatch()]], which may be unavailable at certain environment, using PCRE.
|
37 |
+
* @param string $pattern the shell wildcard pattern.
|
38 |
+
* @param string $string the tested string.
|
39 |
+
* @param array $options options for matching. Valid options are:
|
40 |
+
*
|
41 |
+
* - caseSensitive: bool, whether pattern should be case sensitive. Defaults to `true`.
|
42 |
+
* - escape: bool, whether backslash escaping is enabled. Defaults to `true`.
|
43 |
+
* - filePath: bool, whether slashes in string only matches slashes in the given pattern. Defaults to `false`.
|
44 |
+
*
|
45 |
+
* @return bool whether the string matches pattern or not.
|
46 |
+
*/
|
47 |
+
protected function isPatternMatching($pattern, $string, $options = [])
|
48 |
+
{
|
49 |
+
if ($pattern === '*' && empty($options['filePath'])) {
|
50 |
+
return true;
|
51 |
+
}
|
52 |
+
|
53 |
+
$replacements = [
|
54 |
+
'\\\\\\\\' => '\\\\',
|
55 |
+
'\\\\\\*' => '[*]',
|
56 |
+
'\\\\\\?' => '[?]',
|
57 |
+
'\*' => '.*',
|
58 |
+
'\?' => '.',
|
59 |
+
'\[\!' => '[^',
|
60 |
+
'\[' => '[',
|
61 |
+
'\]' => ']',
|
62 |
+
'\-' => '-',
|
63 |
+
];
|
64 |
+
|
65 |
+
if (isset($options['escape']) && !$options['escape']) {
|
66 |
+
unset($replacements['\\\\\\\\']);
|
67 |
+
unset($replacements['\\\\\\*']);
|
68 |
+
unset($replacements['\\\\\\?']);
|
69 |
+
}
|
70 |
+
|
71 |
+
if (!empty($options['filePath'])) {
|
72 |
+
$replacements['\*'] = '[^/\\\\]*';
|
73 |
+
$replacements['\?'] = '[^/\\\\]';
|
74 |
+
}
|
75 |
+
|
76 |
+
$pattern = strtr(preg_quote($pattern, '#'), $replacements);
|
77 |
+
$pattern = '#^' . $pattern . '$#us';
|
78 |
+
if (isset($options['caseSensitive']) && !$options['caseSensitive']) {
|
79 |
+
$pattern .= 'i';
|
80 |
+
}
|
81 |
+
|
82 |
+
return 1 === preg_match($pattern, $string);
|
83 |
+
}
|
84 |
+
}
|
Manager/SnapshotManager.php
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Manager;
|
4 |
+
|
5 |
+
use WPStaging\Repository\SnapshotRepository;
|
6 |
+
|
7 |
+
class SnapshotManager
|
8 |
+
{
|
9 |
+
/**
|
10 |
+
* @param string $prefix
|
11 |
+
* @return bool
|
12 |
+
*/
|
13 |
+
public function deleteByPrefix($prefix)
|
14 |
+
{
|
15 |
+
$repository = new SnapshotRepository;
|
16 |
+
|
17 |
+
$snapshots = $repository->findAll();
|
18 |
+
if (!$snapshots) {
|
19 |
+
return true;
|
20 |
+
}
|
21 |
+
|
22 |
+
$snapshots->removeById($prefix);
|
23 |
+
if ($repository->save($snapshots)) {
|
24 |
+
return true;
|
25 |
+
}
|
26 |
+
|
27 |
+
return false;
|
28 |
+
}
|
29 |
+
}
|
Plugin.php
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging;
|
4 |
+
|
5 |
+
use WPStaging\Service\AbstractPlugin;
|
6 |
+
|
7 |
+
class Plugin extends AbstractPlugin
|
8 |
+
{
|
9 |
+
/**
|
10 |
+
* TODO; remove the demonstration
|
11 |
+
* @noinspection PhpUnused
|
12 |
+
*/
|
13 |
+
public function onActivation()
|
14 |
+
{
|
15 |
+
}
|
16 |
+
|
17 |
+
/**
|
18 |
+
* TODO; remove the demonstration
|
19 |
+
* @noinspection PhpUnused
|
20 |
+
*/
|
21 |
+
public function onDeactivate()
|
22 |
+
{
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* TODO; remove the demonstration
|
27 |
+
* @noinspection PhpUnused
|
28 |
+
* This needs to be static due to how register_uninstall_hook() works
|
29 |
+
*/
|
30 |
+
public static function onUninstall()
|
31 |
+
{
|
32 |
+
}
|
33 |
+
}
|
Service/AbstractPlugin.php
ADDED
@@ -0,0 +1,175 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service;
|
4 |
+
|
5 |
+
use WPStaging\Service\Adapter\Directory;
|
6 |
+
use WPStaging\Service\Adapter\Hooks;
|
7 |
+
use WPStaging\Service\Container\Container;
|
8 |
+
use WPStaging\WPStaging;
|
9 |
+
|
10 |
+
abstract class AbstractPlugin implements PluginInterface
|
11 |
+
{
|
12 |
+
const APP_DEV = 'dev';
|
13 |
+
const APP_PROD = 'prod';
|
14 |
+
|
15 |
+
/** @var Container */
|
16 |
+
protected $container;
|
17 |
+
|
18 |
+
/** @var array */
|
19 |
+
protected $components = [];
|
20 |
+
|
21 |
+
public function __construct(Container $container = null)
|
22 |
+
{
|
23 |
+
if ($container) {
|
24 |
+
$this->setContainer($container);
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
public function setContainer(Container $container)
|
29 |
+
{
|
30 |
+
$this->container = $container;
|
31 |
+
}
|
32 |
+
|
33 |
+
public function init()
|
34 |
+
{
|
35 |
+
if (!$this->container) {
|
36 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
37 |
+
throw new InvalidPluginException(static::class);
|
38 |
+
}
|
39 |
+
|
40 |
+
$this->initDependencies();
|
41 |
+
$this->registerLifeCycle();
|
42 |
+
$this->loadLanguages();
|
43 |
+
|
44 |
+
/** @var Hooks $hooks */
|
45 |
+
$hooks = $this->container->get(Hooks::class);
|
46 |
+
|
47 |
+
foreach ($this->components as $id => $options) {
|
48 |
+
$this->container->setInitialized($id, $options);
|
49 |
+
}
|
50 |
+
|
51 |
+
$hooks->init();
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* @noinspection PhpUnused
|
56 |
+
* @param string $id
|
57 |
+
* @param array $options
|
58 |
+
*/
|
59 |
+
public function addComponent($id, array $options = [])
|
60 |
+
{
|
61 |
+
if (array_key_exists($id, $this->components)) {
|
62 |
+
return;
|
63 |
+
}
|
64 |
+
|
65 |
+
$this->components[$id] = $options;
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @noinspection PhpUnused
|
70 |
+
* @param string $id
|
71 |
+
*/
|
72 |
+
public function removeComponent($id)
|
73 |
+
{
|
74 |
+
$key = array_search($id, $this->components, true);
|
75 |
+
if (false === $key) {
|
76 |
+
return;
|
77 |
+
}
|
78 |
+
|
79 |
+
unset($this->components[$key]);
|
80 |
+
$this->container->remove($id);
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* @return string|null
|
85 |
+
*/
|
86 |
+
public function getSlug()
|
87 |
+
{
|
88 |
+
return $this->container->getParameter('slug');
|
89 |
+
}
|
90 |
+
|
91 |
+
public function getDomain()
|
92 |
+
{
|
93 |
+
return $this->container->getParameter('domain');
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* WP Staging Version Number
|
98 |
+
* @return string|null
|
99 |
+
*/
|
100 |
+
public function getVersion()
|
101 |
+
{
|
102 |
+
if (!function_exists('get_plugin_data')) {
|
103 |
+
return null;
|
104 |
+
}
|
105 |
+
|
106 |
+
/** @var Directory|null $directory */
|
107 |
+
$directory = $this->container->get(Directory::class);
|
108 |
+
$pluginFile = $directory->getPluginDirectory() . $this->getSlug() . '.php';
|
109 |
+
$data = get_plugin_data($pluginFile);
|
110 |
+
|
111 |
+
// TODO PHP7.0; return $data['Version'] ?? WPStaging::getVersion();
|
112 |
+
return isset($data['Version']) && $data['Version']? $data['Version'] : WPStaging::getVersion();
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* @noinspection PhpUnused
|
117 |
+
* @return Container
|
118 |
+
*/
|
119 |
+
public function getContainer()
|
120 |
+
{
|
121 |
+
return $this->container;
|
122 |
+
}
|
123 |
+
|
124 |
+
private function loadLanguages()
|
125 |
+
{
|
126 |
+
/** @noinspection NullPointerExceptionInspection */
|
127 |
+
$languagesDirectory = $this->container->get(Directory::class)->getPluginDirectory() . 'languages/';
|
128 |
+
|
129 |
+
// Set filter for plugins languages directory
|
130 |
+
$languagesDirectory = apply_filters($this->getSlug() . '_languages_directory', $languagesDirectory);
|
131 |
+
|
132 |
+
// Traditional WP plugin locale filter
|
133 |
+
$locale = apply_filters('plugin_locale', get_user_locale(), 'wp-staging');
|
134 |
+
$moFile = sprintf('%1$s-%2$s.mo', 'wp-staging', $locale);
|
135 |
+
|
136 |
+
// Setup paths to current locale file
|
137 |
+
$moFileLocal = $languagesDirectory . $moFile;
|
138 |
+
$moFileGlobal = sprintf('%s/wp-staging/%s', WP_LANG_DIR, $moFile);
|
139 |
+
|
140 |
+
if (file_exists($moFileGlobal)) {
|
141 |
+
load_textdomain('wp-staging', $moFileGlobal);
|
142 |
+
}
|
143 |
+
elseif (file_exists($moFileLocal)) {
|
144 |
+
load_textdomain('wp-staging', $moFileLocal);
|
145 |
+
}
|
146 |
+
else {
|
147 |
+
load_plugin_textdomain('wp-staging', false, $languagesDirectory);
|
148 |
+
}
|
149 |
+
}
|
150 |
+
|
151 |
+
private function initDependencies()
|
152 |
+
{
|
153 |
+
$this->container->set(Hooks::class, new Hooks);
|
154 |
+
$this->container->set(Directory::class, new Directory($this->getSlug()));
|
155 |
+
}
|
156 |
+
|
157 |
+
private function registerLifeCycle()
|
158 |
+
{
|
159 |
+
/** @noinspection NullPointerExceptionInspection */
|
160 |
+
$file = $this->container->get(Directory::class)->getPluginDirectory() . $this->getSlug() . '.php';
|
161 |
+
|
162 |
+
if (method_exists($this, 'onActivation')) {
|
163 |
+
register_activation_hook($file, [$this, 'onActivation']);
|
164 |
+
}
|
165 |
+
|
166 |
+
if (method_exists($this, 'onDeactivate')) {
|
167 |
+
register_deactivation_hook($file, [$this, 'onDeactivate']);
|
168 |
+
}
|
169 |
+
|
170 |
+
if (method_exists($this, 'onUninstall')) {
|
171 |
+
// $this does not work hence the usage of get_called_class()
|
172 |
+
register_uninstall_hook($file, [static::class, 'onUninstall']);
|
173 |
+
}
|
174 |
+
}
|
175 |
+
}
|
Service/Adapter/Database.php
ADDED
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* IMPORTANT use only named queries or WP queries
|
4 |
+
*/
|
5 |
+
/** @noinspection PhpUndefinedClassInspection */
|
6 |
+
|
7 |
+
namespace WPStaging\Service\Adapter;
|
8 |
+
|
9 |
+
use wpdb;
|
10 |
+
use WPStaging\Service\Adapter\Database\InterfaceDatabase;
|
11 |
+
use WPStaging\Service\Adapter\Database\WpDbAdapter;
|
12 |
+
use SplObjectStorage;
|
13 |
+
|
14 |
+
class Database
|
15 |
+
{
|
16 |
+
/** @var InterfaceDatabase */
|
17 |
+
private $client;
|
18 |
+
|
19 |
+
/** @var WpDbAdapter */
|
20 |
+
private $wpdba;
|
21 |
+
|
22 |
+
/** @var wpdb */
|
23 |
+
private $wpdb;
|
24 |
+
|
25 |
+
public function __construct()
|
26 |
+
{
|
27 |
+
global $wpdb;
|
28 |
+
$this->wpdb = $wpdb;
|
29 |
+
$this->wpdba = new WpDbAdapter($this->wpdb);
|
30 |
+
$this->client = $this->wpdba;
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @return InterfaceDatabase|null
|
35 |
+
*/
|
36 |
+
public function getClient()
|
37 |
+
{
|
38 |
+
return $this->client;
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @return WpDbAdapter
|
43 |
+
* @noinspection PhpUnused
|
44 |
+
*/
|
45 |
+
public function getWpdba()
|
46 |
+
{
|
47 |
+
return $this->wpdba;
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* @return string
|
52 |
+
*/
|
53 |
+
public function getPrefix()
|
54 |
+
{
|
55 |
+
return $this->wpdb->prefix;
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* @param string|null $prefix
|
60 |
+
*
|
61 |
+
* @return string|string[]
|
62 |
+
*/
|
63 |
+
public function provideSqlPrefix($prefix = null)
|
64 |
+
{
|
65 |
+
if (!$prefix) {
|
66 |
+
$prefix = $this->getPrefix();
|
67 |
+
}
|
68 |
+
return str_replace('_', '\_', $prefix);
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* @return string
|
73 |
+
* @noinspection PhpUnused
|
74 |
+
*/
|
75 |
+
public function getCharset()
|
76 |
+
{
|
77 |
+
return $this->wpdb->get_charset_collate();
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @param string $statement
|
82 |
+
*
|
83 |
+
* @return bool
|
84 |
+
*/
|
85 |
+
public function exec($statement)
|
86 |
+
{
|
87 |
+
return (bool)$this->client->exec($statement);
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* @param string $sql
|
92 |
+
* @param array $conditions
|
93 |
+
*
|
94 |
+
* @return SplObjectStorage|null
|
95 |
+
*/
|
96 |
+
public function find($sql, array $conditions = [])
|
97 |
+
{
|
98 |
+
return $this->client->find($sql, $conditions);
|
99 |
+
}
|
100 |
+
}
|
Service/Adapter/Database/AbstractDatabase.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Adapter\Database;
|
4 |
+
|
5 |
+
abstract class AbstractDatabase implements InterfaceDatabase
|
6 |
+
{
|
7 |
+
|
8 |
+
}
|
Service/Adapter/Database/DatabaseException.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Adapter\Database;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
|
7 |
+
class DatabaseException extends Exception
|
8 |
+
{
|
9 |
+
|
10 |
+
public function __construct($message = '')
|
11 |
+
{
|
12 |
+
parent::__construct($message);
|
13 |
+
}
|
14 |
+
}
|
Service/Adapter/Database/DatabaseQueryDto.php
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Adapter\Database;
|
4 |
+
|
5 |
+
|
6 |
+
class DatabaseQueryDto
|
7 |
+
{
|
8 |
+
/** @var string */
|
9 |
+
private $tableName;
|
10 |
+
|
11 |
+
/** @var array */
|
12 |
+
private $data = [];
|
13 |
+
|
14 |
+
/** @var array */
|
15 |
+
private $dataValueMap = [];
|
16 |
+
|
17 |
+
/** @var array */
|
18 |
+
private $conditions = [];
|
19 |
+
|
20 |
+
/** @var array */
|
21 |
+
private $conditionsValueMap = [];
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @return string
|
25 |
+
*/
|
26 |
+
public function getTableName()
|
27 |
+
{
|
28 |
+
return $this->tableName;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @param string $tableName
|
33 |
+
*/
|
34 |
+
public function setTableName($tableName)
|
35 |
+
{
|
36 |
+
$this->tableName = $tableName;
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* @return array
|
41 |
+
*/
|
42 |
+
public function getData()
|
43 |
+
{
|
44 |
+
return $this->data;
|
45 |
+
}
|
46 |
+
|
47 |
+
public function setData(array $data = [])
|
48 |
+
{
|
49 |
+
$this->data = $data;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @return array
|
54 |
+
*/
|
55 |
+
public function getDataValueMap()
|
56 |
+
{
|
57 |
+
return $this->dataValueMap;
|
58 |
+
}
|
59 |
+
|
60 |
+
public function setDataValueMap(array $dataValueMap = [])
|
61 |
+
{
|
62 |
+
$this->dataValueMap = $dataValueMap;
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* @return array
|
67 |
+
*/
|
68 |
+
public function getConditions()
|
69 |
+
{
|
70 |
+
return $this->conditions;
|
71 |
+
}
|
72 |
+
|
73 |
+
public function setConditions(array $conditions = [])
|
74 |
+
{
|
75 |
+
$this->conditions = $conditions;
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* @return array
|
80 |
+
*/
|
81 |
+
public function getConditionsValueMap()
|
82 |
+
{
|
83 |
+
return $this->conditionsValueMap;
|
84 |
+
}
|
85 |
+
|
86 |
+
public function setConditionsValueMap(array $conditionsValueMap = [])
|
87 |
+
{
|
88 |
+
$this->conditionsValueMap = $conditionsValueMap;
|
89 |
+
}
|
90 |
+
}
|
Service/Adapter/Database/InterfaceDatabase.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Adapter\Database;
|
4 |
+
|
5 |
+
use SplObjectStorage;
|
6 |
+
|
7 |
+
interface InterfaceDatabase
|
8 |
+
{
|
9 |
+
/**
|
10 |
+
* @return object
|
11 |
+
*/
|
12 |
+
public function getClient();
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @param string $sql
|
16 |
+
* @param array $conditions
|
17 |
+
*
|
18 |
+
* @return SplObjectStorage|null
|
19 |
+
*/
|
20 |
+
public function find($sql, array $conditions = []);
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @param string $sql
|
24 |
+
* @param array $conditions
|
25 |
+
*
|
26 |
+
* @return object|null
|
27 |
+
*/
|
28 |
+
public function findOne($sql, array $conditions = []);
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @param DatabaseQueryDto $queryDto
|
32 |
+
*
|
33 |
+
* @return bool
|
34 |
+
*/
|
35 |
+
public function insert(DatabaseQueryDto $queryDto);
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @param DatabaseQueryDto $queryDto
|
39 |
+
*
|
40 |
+
* @return bool
|
41 |
+
*/
|
42 |
+
public function update(DatabaseQueryDto $queryDto);
|
43 |
+
|
44 |
+
/**
|
45 |
+
* @param string $tableName
|
46 |
+
* @param array $condition
|
47 |
+
*
|
48 |
+
* @return bool|int
|
49 |
+
*/
|
50 |
+
public function delete($tableName, array $condition = []);
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @param string $sql
|
54 |
+
*
|
55 |
+
* @return bool|int
|
56 |
+
*/
|
57 |
+
public function exec($sql);
|
58 |
+
|
59 |
+
}
|
Service/Adapter/Database/WpDbAdapter.php
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Adapter\Database;
|
4 |
+
|
5 |
+
use SplObjectStorage;
|
6 |
+
use wpdb;
|
7 |
+
|
8 |
+
class WpDbAdapter extends AbstractDatabase
|
9 |
+
{
|
10 |
+
/** @var wpdb */
|
11 |
+
private $client;
|
12 |
+
|
13 |
+
public function __construct(wpdb $wpdb)
|
14 |
+
{
|
15 |
+
$this->client = $wpdb;
|
16 |
+
}
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @inheritDoc
|
20 |
+
*/
|
21 |
+
public function getClient()
|
22 |
+
{
|
23 |
+
return $this->client;
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @inheritDoc
|
28 |
+
*/
|
29 |
+
public function find($sql, array $conditions = [])
|
30 |
+
{
|
31 |
+
$records = $this->getResults($sql, $conditions);
|
32 |
+
|
33 |
+
if (!$records) {
|
34 |
+
return null;
|
35 |
+
}
|
36 |
+
|
37 |
+
$collection = new SplObjectStorage;
|
38 |
+
foreach($records as $record) {
|
39 |
+
$collection->attach($record);
|
40 |
+
}
|
41 |
+
|
42 |
+
return $collection;
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @inheritDoc
|
47 |
+
*/
|
48 |
+
public function findOne($sql, array $conditions = [])
|
49 |
+
{
|
50 |
+
$records = $this->getResults($sql, $conditions);
|
51 |
+
|
52 |
+
if (!$records) {
|
53 |
+
return null;
|
54 |
+
}
|
55 |
+
|
56 |
+
return reset($records);
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @inheritDoc
|
61 |
+
*/
|
62 |
+
public function insert(DatabaseQueryDto $queryDto)
|
63 |
+
{
|
64 |
+
// TODO: Implement insert() method.
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* @inheritDoc
|
69 |
+
*/
|
70 |
+
public function update(DatabaseQueryDto $queryDto)
|
71 |
+
{
|
72 |
+
// TODO: Implement update() method.
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* @inheritDoc
|
77 |
+
*/
|
78 |
+
public function delete($tableName, array $condition = [])
|
79 |
+
{
|
80 |
+
// TODO: Implement delete() method.
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* @inheritDoc
|
85 |
+
*/
|
86 |
+
public function exec($sql)
|
87 |
+
{
|
88 |
+
return $this->client->query($sql);
|
89 |
+
}
|
90 |
+
|
91 |
+
private function getResults($sql, array $conditions = [])
|
92 |
+
{
|
93 |
+
if (!$conditions) {
|
94 |
+
$response = $this->client->get_results($sql);
|
95 |
+
}
|
96 |
+
else {
|
97 |
+
$response = $this->client->get_results($this->client->prepare($sql, $conditions));
|
98 |
+
}
|
99 |
+
|
100 |
+
return $response ? array_values((array)$response) : null;
|
101 |
+
}
|
102 |
+
}
|
Service/Adapter/DateTimeAdapter.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
//TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Adapter;
|
6 |
+
|
7 |
+
use DateTime as CoreDateTime;
|
8 |
+
|
9 |
+
class DateTimeAdapter
|
10 |
+
{
|
11 |
+
public function getDateTimeFormat()
|
12 |
+
{
|
13 |
+
$dateFormat = get_option('date_format');
|
14 |
+
$timeFormat = 'H:i:s';
|
15 |
+
|
16 |
+
if (!$dateFormat) {
|
17 |
+
$dateFormat = 'Y/m/d';
|
18 |
+
}
|
19 |
+
|
20 |
+
$dateFormat = str_replace('F', 'M', $dateFormat);
|
21 |
+
|
22 |
+
return $dateFormat . ' ' . $timeFormat;
|
23 |
+
}
|
24 |
+
|
25 |
+
// TODO PHP7.0; public function transformWpDateTimeFormat(DateTime $dateTime): string
|
26 |
+
/**
|
27 |
+
* @param CoreDateTime $dateTime
|
28 |
+
* @return string
|
29 |
+
*/
|
30 |
+
public function transformToWpFormat(CoreDateTime $dateTime)
|
31 |
+
{
|
32 |
+
return $dateTime->format($this->getDateTimeFormat());
|
33 |
+
}
|
34 |
+
}
|
Service/Adapter/Directory.php
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Adapter;
|
4 |
+
|
5 |
+
use RuntimeException;
|
6 |
+
|
7 |
+
class Directory
|
8 |
+
{
|
9 |
+
/** @var string */
|
10 |
+
private $slug;
|
11 |
+
|
12 |
+
/** @var string|null */
|
13 |
+
private $uploadDir;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @param string $slug
|
17 |
+
*/
|
18 |
+
public function __construct($slug)
|
19 |
+
{
|
20 |
+
$this->slug = $slug;
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @return string
|
25 |
+
*/
|
26 |
+
public function getPluginDirectory()
|
27 |
+
{
|
28 |
+
return sprintf('%s/%s/', WP_PLUGIN_DIR, $this->slug);
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @noinspection PhpUnused
|
33 |
+
* @return string
|
34 |
+
*/
|
35 |
+
public function getCacheDirectory()
|
36 |
+
{
|
37 |
+
// TODO implement
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* @noinspection PhpUnused
|
42 |
+
* @return string
|
43 |
+
*/
|
44 |
+
public function getLogDirectory()
|
45 |
+
{
|
46 |
+
// TODO implement
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Relative Path
|
51 |
+
* @noinspection PhpUnused
|
52 |
+
* @return string
|
53 |
+
*/
|
54 |
+
public function getUploadsDirectory()
|
55 |
+
{
|
56 |
+
if ($this->uploadDir) {
|
57 |
+
return $this->uploadDir;
|
58 |
+
}
|
59 |
+
|
60 |
+
// Get upload directory information. Default is ABSPATH . 'wp-content/uploads'
|
61 |
+
// Can be customized by populating the db option upload_path or the constant UPLOADS
|
62 |
+
// If both are defined WordPress will uses the value of the UPLOADS constant
|
63 |
+
$dir = wp_upload_dir();
|
64 |
+
|
65 |
+
// TODO RPoC
|
66 |
+
if ($dir['error']) {
|
67 |
+
throw new RuntimeException($dir['error']);
|
68 |
+
}
|
69 |
+
|
70 |
+
// Get absolute path to wordpress uploads directory e.g /var/www/wp-content/uploads/
|
71 |
+
$this->uploadDir = trailingslashit($dir['basedir']);
|
72 |
+
return $this->uploadDir;
|
73 |
+
}
|
74 |
+
}
|
Service/Adapter/Dto/HookDto.php
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Adapter\Dto;
|
4 |
+
|
5 |
+
class HookDto
|
6 |
+
{
|
7 |
+
const DEFAULT_PRIORITY = 10;
|
8 |
+
|
9 |
+
/** @var string */
|
10 |
+
private $hook;
|
11 |
+
|
12 |
+
/** @var object */
|
13 |
+
private $component;
|
14 |
+
|
15 |
+
/** @var string */
|
16 |
+
private $callback;
|
17 |
+
|
18 |
+
/** @var int */
|
19 |
+
private $priority = 10;
|
20 |
+
|
21 |
+
/** @var int */
|
22 |
+
private $acceptedArgs = 0;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @return string|null
|
26 |
+
*/
|
27 |
+
public function getHook()
|
28 |
+
{
|
29 |
+
return $this->hook;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @param string $hook
|
34 |
+
*/
|
35 |
+
public function setHook($hook)
|
36 |
+
{
|
37 |
+
$this->hook = $hook;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* @return object|null
|
42 |
+
*/
|
43 |
+
public function getComponent()
|
44 |
+
{
|
45 |
+
return $this->component;
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @param object $component
|
50 |
+
*/
|
51 |
+
public function setComponent($component)
|
52 |
+
{
|
53 |
+
$this->component = $component;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* @return string|null
|
58 |
+
*/
|
59 |
+
public function getCallback()
|
60 |
+
{
|
61 |
+
return $this->callback;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @param string $callback
|
66 |
+
*/
|
67 |
+
public function setCallback($callback)
|
68 |
+
{
|
69 |
+
$this->callback = $callback;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* @return int
|
74 |
+
*/
|
75 |
+
public function getPriority()
|
76 |
+
{
|
77 |
+
return $this->priority?: self::DEFAULT_PRIORITY;
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @param int $priority
|
82 |
+
*/
|
83 |
+
public function setPriority($priority)
|
84 |
+
{
|
85 |
+
$this->priority = $priority;
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* @return int
|
90 |
+
*/
|
91 |
+
public function getAcceptedArgs()
|
92 |
+
{
|
93 |
+
return (int)$this->acceptedArgs;
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* @param $acceptedArgs
|
98 |
+
*/
|
99 |
+
public function setAcceptedArgs($acceptedArgs)
|
100 |
+
{
|
101 |
+
$this->acceptedArgs = $acceptedArgs;
|
102 |
+
}
|
103 |
+
}
|
Service/Adapter/Dto/JedDto.php
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Adapter\Dto;
|
6 |
+
|
7 |
+
use JsonSerializable;
|
8 |
+
|
9 |
+
class JedDto implements JsonSerializable
|
10 |
+
{
|
11 |
+
/** @var string */
|
12 |
+
private $domain;
|
13 |
+
|
14 |
+
/** @var string */
|
15 |
+
private $language;
|
16 |
+
|
17 |
+
/** @var string */
|
18 |
+
private $pluralForms;
|
19 |
+
|
20 |
+
/** @var array */
|
21 |
+
private $translations = [];
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @return array
|
25 |
+
*/
|
26 |
+
public function toArray()
|
27 |
+
{
|
28 |
+
$settings = [
|
29 |
+
'' => [
|
30 |
+
'domain' => $this->domain,
|
31 |
+
'lang' => $this->language,
|
32 |
+
'plural_forms' => $this->pluralForms,
|
33 |
+
],
|
34 |
+
];
|
35 |
+
|
36 |
+
/** @noinspection AdditionOperationOnArraysInspection */
|
37 |
+
return $settings + $this->translations;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* @return array
|
42 |
+
*/
|
43 |
+
public function jsonSerialize()
|
44 |
+
{
|
45 |
+
return $this->toArray();
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @return string
|
50 |
+
*/
|
51 |
+
public function getDomain()
|
52 |
+
{
|
53 |
+
return $this->domain;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* @param string $domain
|
58 |
+
*/
|
59 |
+
public function setDomain($domain)
|
60 |
+
{
|
61 |
+
$this->domain = $domain;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @return string
|
66 |
+
*/
|
67 |
+
public function getLanguage()
|
68 |
+
{
|
69 |
+
return $this->language;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* @param string $language
|
74 |
+
*/
|
75 |
+
public function setLanguage($language)
|
76 |
+
{
|
77 |
+
$this->language = $language;
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @return string
|
82 |
+
*/
|
83 |
+
public function getPluralForms()
|
84 |
+
{
|
85 |
+
return $this->pluralForms;
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* @param string $pluralForms
|
90 |
+
*/
|
91 |
+
public function setPluralForms($pluralForms)
|
92 |
+
{
|
93 |
+
$this->pluralForms = $pluralForms;
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* @return array
|
98 |
+
*/
|
99 |
+
public function getTranslations()
|
100 |
+
{
|
101 |
+
return $this->translations;
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* @param array $translations
|
106 |
+
*/
|
107 |
+
public function setTranslations(array $translations = [])
|
108 |
+
{
|
109 |
+
$this->translations = $translations;
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* @param string $key
|
114 |
+
* @param array $translations
|
115 |
+
*/
|
116 |
+
public function addTranslations($key, array $translations)
|
117 |
+
{
|
118 |
+
$this->translations[$key] = $translations;
|
119 |
+
}
|
120 |
+
}
|
Service/Adapter/Hooks.php
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Adapter;
|
4 |
+
|
5 |
+
use WPStaging\Service\Adapter\Dto\HookDto;
|
6 |
+
|
7 |
+
final class Hooks
|
8 |
+
{
|
9 |
+
/** @var HookDto[]|array */
|
10 |
+
private $actions = [];
|
11 |
+
|
12 |
+
/** @var HookDto[]|array */
|
13 |
+
private $filters = [];
|
14 |
+
|
15 |
+
/** @noinspection PhpUnused */
|
16 |
+
public function addAction(HookDto $dto)
|
17 |
+
{
|
18 |
+
$this->actions[] = $dto;
|
19 |
+
}
|
20 |
+
|
21 |
+
/** @noinspection PhpUnused */
|
22 |
+
public function addFilter(HookDto $dto)
|
23 |
+
{
|
24 |
+
$this->filters[] = $dto;
|
25 |
+
}
|
26 |
+
|
27 |
+
public function init()
|
28 |
+
{
|
29 |
+
foreach ($this->filters as $filter) {
|
30 |
+
add_filter(
|
31 |
+
$filter->getHook(),
|
32 |
+
[$filter->getComponent(), $filter->getCallback()],
|
33 |
+
$filter->getPriority(),
|
34 |
+
$filter->getAcceptedArgs()
|
35 |
+
);
|
36 |
+
}
|
37 |
+
|
38 |
+
foreach ($this->actions as $action) {
|
39 |
+
add_action(
|
40 |
+
$action->getHook(),
|
41 |
+
[$action->getComponent(), $action->getCallback()],
|
42 |
+
$action->getPriority(),
|
43 |
+
$action->getAcceptedArgs()
|
44 |
+
);
|
45 |
+
}
|
46 |
+
}
|
47 |
+
}
|
Service/Adapter/Translation.php
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Adapter;
|
6 |
+
|
7 |
+
use Translations;
|
8 |
+
use NOOP_Translations;
|
9 |
+
use Translation_Entry;
|
10 |
+
use WPStaging\Service\Adapter\Dto\JedDto;
|
11 |
+
|
12 |
+
class Translation
|
13 |
+
{
|
14 |
+
const DEFAULT_LANGUAGE = 'en';
|
15 |
+
|
16 |
+
const DEFAULT_PLURAL_FORMS = 'nplurals=2; plural=n != 1;';
|
17 |
+
|
18 |
+
/** @var string */
|
19 |
+
private $domain;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @param string $domain
|
23 |
+
*/
|
24 |
+
public function __construct($domain)
|
25 |
+
{
|
26 |
+
$this->domain = $domain;
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @return JedDto
|
31 |
+
*/
|
32 |
+
public function toJed()
|
33 |
+
{
|
34 |
+
$translations = $this->provideTranslations();
|
35 |
+
|
36 |
+
$jed = new JedDto;
|
37 |
+
$jed->setDomain($this->domain);
|
38 |
+
$jed->setLanguage($this->getLanguage($translations->headers));
|
39 |
+
$jed->setPluralForms($this->getPluralForms($translations->headers));
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @var string $key
|
43 |
+
* @var Translation_Entry $value
|
44 |
+
*/
|
45 |
+
foreach($translations->entries as $key => $value) {
|
46 |
+
$jed->addTranslations($key, $value->translations);
|
47 |
+
}
|
48 |
+
|
49 |
+
return $jed;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @return Translations|NOOP_Translations
|
54 |
+
*/
|
55 |
+
private function provideTranslations()
|
56 |
+
{
|
57 |
+
return get_translations_for_domain($this->domain);
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @param array $headers
|
62 |
+
* @return string
|
63 |
+
*/
|
64 |
+
private function getLanguage(array $headers = [])
|
65 |
+
{
|
66 |
+
if (isset($headers['Language']) && $headers['Language']) {
|
67 |
+
return strtolower($headers['Language']);
|
68 |
+
}
|
69 |
+
|
70 |
+
return self::DEFAULT_LANGUAGE;
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* @param array $headers
|
75 |
+
* @return string
|
76 |
+
*/
|
77 |
+
private function getPluralForms(array $headers = [])
|
78 |
+
{
|
79 |
+
if (isset($headers['Plural-Forms']) && $headers['Plural-Forms']) {
|
80 |
+
return (string) $headers['Plural-Forms'];
|
81 |
+
}
|
82 |
+
|
83 |
+
return self::DEFAULT_PLURAL_FORMS;
|
84 |
+
}
|
85 |
+
}
|
Service/Collection/Collection.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
//TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Collection;
|
6 |
+
|
7 |
+
use SplObjectStorage;
|
8 |
+
use JsonSerializable;
|
9 |
+
use WPStaging\Service\Interfaces\ArrayableInterface;
|
10 |
+
use WPStaging\Service\Interfaces\HydrateableInterface;
|
11 |
+
|
12 |
+
class Collection extends SplObjectStorage implements JsonSerializable
|
13 |
+
{
|
14 |
+
/** @var string */
|
15 |
+
protected $storedClass;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @param string $storedClass
|
19 |
+
*/
|
20 |
+
public function __construct($storedClass)
|
21 |
+
{
|
22 |
+
$this->storedClass = $storedClass;
|
23 |
+
}
|
24 |
+
|
25 |
+
public function toArray()
|
26 |
+
{
|
27 |
+
$collection = [];
|
28 |
+
/** @var ArrayableInterface $item */
|
29 |
+
foreach ($this as $item) {
|
30 |
+
if (method_exists($item, 'toArray')) {
|
31 |
+
$collection[] = $item->toArray();
|
32 |
+
} else {
|
33 |
+
$collection[] = $item;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
return $collection;
|
38 |
+
}
|
39 |
+
|
40 |
+
public function attachAllByArray(array $data = [])
|
41 |
+
{
|
42 |
+
foreach ($data as $item) {
|
43 |
+
if ($item instanceof $this->storedClass) {
|
44 |
+
$this->attach($item);
|
45 |
+
continue;
|
46 |
+
}
|
47 |
+
|
48 |
+
/** @var HydrateableInterface $object */
|
49 |
+
$object = new $this->storedClass;
|
50 |
+
$object->hydrate((array) $item);
|
51 |
+
$this->attach($object);
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
public function jsonSerialize()
|
56 |
+
{
|
57 |
+
return $this->toArray();
|
58 |
+
}
|
59 |
+
}
|
Service/Collection/OptionCollection.php
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php /** @noinspection PhpUndefinedClassInspection */
|
2 |
+
|
3 |
+
//TODO PHP7.x; declare(strict_types=1);
|
4 |
+
//TODO PHP7.x type-hints & return types
|
5 |
+
|
6 |
+
namespace WPStaging\Service\Collection;
|
7 |
+
|
8 |
+
use JsonSerializable;
|
9 |
+
use WPStaging\Pro\Component\Job\Database\JobCreateSnapshot;
|
10 |
+
use WPStaging\Service\Entity\AbstractEntity;
|
11 |
+
use WPStaging\Service\Entity\IdentifyableEntityInterface;
|
12 |
+
|
13 |
+
class OptionCollection extends Collection implements JsonSerializable
|
14 |
+
{
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @param string $id
|
18 |
+
*
|
19 |
+
* @return bool
|
20 |
+
*/
|
21 |
+
public function doesIncludeId($id)
|
22 |
+
{
|
23 |
+
// We could use following for simplicity but not that performable
|
24 |
+
// return array_key_exists($id, $this->toArray());
|
25 |
+
/** @var IdentifyableEntityInterface $item */
|
26 |
+
foreach ($this as $item) {
|
27 |
+
if ($id === $item->getId()) {
|
28 |
+
return true;
|
29 |
+
}
|
30 |
+
}
|
31 |
+
|
32 |
+
return false;
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @param string $id
|
37 |
+
*
|
38 |
+
* @return AbstractEntity|null
|
39 |
+
* @noinspection PhpUnused
|
40 |
+
*/
|
41 |
+
public function findById($id)
|
42 |
+
{
|
43 |
+
/** @var AbstractEntity $item */
|
44 |
+
foreach ($this as $item) {
|
45 |
+
if ($id === $item->getId()) {
|
46 |
+
return $item;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
return null;
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @param string $id
|
55 |
+
*/
|
56 |
+
public function removeById($id)
|
57 |
+
{
|
58 |
+
$item = $this->findById($id);
|
59 |
+
if (!$item) {
|
60 |
+
return;
|
61 |
+
}
|
62 |
+
// TODO RPoC
|
63 |
+
delete_transient(JobCreateSnapshot::TRANSIENT_PREFIX . $id);
|
64 |
+
$this->detach($item);
|
65 |
+
}
|
66 |
+
|
67 |
+
public function filterByPrefix($prefix)
|
68 |
+
{
|
69 |
+
/** @var AbstractEntity $item */
|
70 |
+
foreach ($this as $item) {
|
71 |
+
if (0 !== strpos($item->getId(), $prefix)) {
|
72 |
+
$this->detach($item);
|
73 |
+
}
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
public function sortBy($key, $sort = SORT_DESC)
|
78 |
+
{
|
79 |
+
$array = $this->toArray();
|
80 |
+
$columns = array_column($array, $key);
|
81 |
+
array_multisort($columns, $sort, $array);
|
82 |
+
$this->removeAll($this);
|
83 |
+
$this->attachAllByArray($array);
|
84 |
+
}
|
85 |
+
}
|
Service/Command/CommandInterface.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Command;
|
4 |
+
|
5 |
+
interface CommandInterface
|
6 |
+
{
|
7 |
+
/**
|
8 |
+
* @return void
|
9 |
+
*/
|
10 |
+
public function execute();
|
11 |
+
}
|
Service/Command/HandlerInterface.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Command;
|
4 |
+
|
5 |
+
interface HandlerInterface
|
6 |
+
{
|
7 |
+
public function addCommand(CommandInterface $command);
|
8 |
+
|
9 |
+
public function handle();
|
10 |
+
}
|
Service/Component/AbstractComponent.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// TODO PHP7.x; declare(strict_types=1);
|
3 |
+
// TODO PHP7.x; return type hints
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Component;
|
6 |
+
|
7 |
+
use WPStaging\Service\Adapter\Dto\HookDto;
|
8 |
+
use WPStaging\Service\Adapter\Hooks;
|
9 |
+
|
10 |
+
abstract class AbstractComponent implements ComponentInterface
|
11 |
+
{
|
12 |
+
/** @var Hooks */
|
13 |
+
private $hooks;
|
14 |
+
|
15 |
+
public function __construct(Hooks $hooks)
|
16 |
+
{
|
17 |
+
$this->hooks = $hooks;
|
18 |
+
$this->registerHooks();
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @param string $action
|
23 |
+
* @param string $method
|
24 |
+
* @param int $acceptedArgs
|
25 |
+
* @param int $priority
|
26 |
+
* @noinspection PhpUnused
|
27 |
+
*/
|
28 |
+
public function addAction($action, $method, $acceptedArgs = 0, $priority = 10)
|
29 |
+
{
|
30 |
+
$dto = $this->generateDto($action, $method, $acceptedArgs, $priority);
|
31 |
+
$this->hooks->addAction($dto);
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* @param string $action
|
36 |
+
* @param string $method
|
37 |
+
* @param int $acceptedArgs
|
38 |
+
* @param int $priority
|
39 |
+
* @noinspection PhpUnused
|
40 |
+
*/
|
41 |
+
public function addFilter($action, $method, $acceptedArgs = 0, $priority = 10)
|
42 |
+
{
|
43 |
+
$dto = $this->generateDto($action, $method, $acceptedArgs, $priority);
|
44 |
+
$this->hooks->addFilter($dto);
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* @param string $action
|
49 |
+
* @param string $method
|
50 |
+
* @param int $acceptedArgs
|
51 |
+
* @param int $priority
|
52 |
+
*
|
53 |
+
* @return HookDto
|
54 |
+
*/
|
55 |
+
private function generateDto($action, $method, $acceptedArgs = 0, $priority = 10)
|
56 |
+
{
|
57 |
+
$dto = new HookDto;
|
58 |
+
$dto->setHook($action);
|
59 |
+
$dto->setComponent($this);
|
60 |
+
$dto->setCallback($method);
|
61 |
+
$dto->setAcceptedArgs($acceptedArgs);
|
62 |
+
$dto->setPriority($priority);
|
63 |
+
|
64 |
+
return $dto;
|
65 |
+
}
|
66 |
+
}
|
Service/Component/AbstractTemplateComponent.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; type-hints && return types
|
5 |
+
|
6 |
+
namespace WPStaging\Service\Component;
|
7 |
+
|
8 |
+
use WPStaging\Service\Adapter\Hooks;
|
9 |
+
use WPStaging\Service\TemplateEngine\TemplateEngine;
|
10 |
+
|
11 |
+
abstract class AbstractTemplateComponent extends AbstractComponent implements RenderableComponentInterface
|
12 |
+
{
|
13 |
+
use AjaxTrait;
|
14 |
+
|
15 |
+
/** @var TemplateEngine */
|
16 |
+
protected $templateEngine;
|
17 |
+
|
18 |
+
public function __construct(Hooks $hooks, TemplateEngine $templateEngine)
|
19 |
+
{
|
20 |
+
parent::__construct($hooks);
|
21 |
+
$this->templateEngine = $templateEngine;
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @param string $path
|
26 |
+
* @param array $params
|
27 |
+
*
|
28 |
+
* @return string
|
29 |
+
*/
|
30 |
+
public function renderTemplate($path, array $params = [])
|
31 |
+
{
|
32 |
+
return $this->templateEngine->render($path, $params);
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @return string
|
37 |
+
*/
|
38 |
+
public function getSlug()
|
39 |
+
{
|
40 |
+
return $this->templateEngine->getSlug();
|
41 |
+
}
|
42 |
+
}
|
Service/Component/AjaxTrait.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Component;
|
6 |
+
|
7 |
+
trait AjaxTrait
|
8 |
+
{
|
9 |
+
public function isAjax()
|
10 |
+
{
|
11 |
+
return defined('DOING_AJAX') && DOING_AJAX;
|
12 |
+
}
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @param string|null $action
|
16 |
+
* @param string|null $key
|
17 |
+
*
|
18 |
+
* @return bool
|
19 |
+
*/
|
20 |
+
public function isSecureAjax($action = null, $key = null)
|
21 |
+
{
|
22 |
+
$_action = $action;
|
23 |
+
if (null === $_action) {
|
24 |
+
$_action = -1;
|
25 |
+
}
|
26 |
+
|
27 |
+
$_key = $key;
|
28 |
+
if (null === $_key) {
|
29 |
+
$_key = false;
|
30 |
+
}
|
31 |
+
|
32 |
+
return $this->isAjax() && (bool) check_ajax_referer($_action, $_key, false);
|
33 |
+
}
|
34 |
+
}
|
Service/Component/ComponentInterface.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// TODO PHP7.x; declare(strict_types=1);
|
3 |
+
// TODO PHP7.x; return type hints
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Component;
|
6 |
+
|
7 |
+
interface ComponentInterface
|
8 |
+
{
|
9 |
+
public function registerHooks();
|
10 |
+
}
|
Service/Component/RenderableComponentInterface.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// TODO PHP7.x; declare(strict_types=1);
|
3 |
+
// TODO PHP7.x; return type hints
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Component;
|
6 |
+
|
7 |
+
interface RenderableComponentInterface
|
8 |
+
{
|
9 |
+
public function render();
|
10 |
+
}
|
Service/Container/AbstractContainerAware.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Component;
|
4 |
+
|
5 |
+
use WPStaging\Service\Container\Container;
|
6 |
+
|
7 |
+
abstract class AbstractContainerAware
|
8 |
+
{
|
9 |
+
/** @var Container */
|
10 |
+
protected $container;
|
11 |
+
|
12 |
+
public function __construct(Container $container)
|
13 |
+
{
|
14 |
+
$this->container = $container;
|
15 |
+
}
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @param string $id
|
19 |
+
*
|
20 |
+
* @return null|object
|
21 |
+
*/
|
22 |
+
protected function get($id)
|
23 |
+
{
|
24 |
+
return $this->container->get($id);
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @return string|null
|
29 |
+
*/
|
30 |
+
protected function getSlug()
|
31 |
+
{
|
32 |
+
return $this->container->getParameter('slug');
|
33 |
+
}
|
34 |
+
}
|
Service/Container/Container.php
ADDED
@@ -0,0 +1,350 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Container;
|
4 |
+
|
5 |
+
use ReflectionClass;
|
6 |
+
use ReflectionException;
|
7 |
+
use ReflectionParameter;
|
8 |
+
|
9 |
+
class Container implements ContainerInterface
|
10 |
+
{
|
11 |
+
/** @var array */
|
12 |
+
private $container = [];
|
13 |
+
|
14 |
+
/** @var array */
|
15 |
+
private $parameters = [];
|
16 |
+
|
17 |
+
/** @var array */
|
18 |
+
private $mapping = [];
|
19 |
+
|
20 |
+
public function __construct(array $config = [])
|
21 |
+
{
|
22 |
+
$this->setContainerByConfig($config);
|
23 |
+
$this->setParametersByConfig($config);
|
24 |
+
$this->setMappingByConfig($config);
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @noinspection PhpDocMissingThrowsInspection
|
29 |
+
* @param string $id
|
30 |
+
*
|
31 |
+
* @return $this|mixed|object|null
|
32 |
+
*/
|
33 |
+
public function get($id)
|
34 |
+
{
|
35 |
+
if (self::class === $id) {
|
36 |
+
return $this;
|
37 |
+
}
|
38 |
+
|
39 |
+
if (!$this->has($id)) {
|
40 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
41 |
+
return $this->loadClass($id);
|
42 |
+
}
|
43 |
+
|
44 |
+
if (is_object($this->container[$id])) {
|
45 |
+
return $this->container[$id];
|
46 |
+
}
|
47 |
+
|
48 |
+
if (is_callable($this->container[$id])) {
|
49 |
+
$this->container[$id] = $this->container[$id]();
|
50 |
+
}
|
51 |
+
|
52 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
53 |
+
$this->loadClass($id);
|
54 |
+
|
55 |
+
return $this->container[$id];
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* @param string $id
|
60 |
+
* @param object|callable|null $value
|
61 |
+
*/
|
62 |
+
public function set($id, $value = null)
|
63 |
+
{
|
64 |
+
$this->container[$id] = $value;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* @param string $id
|
69 |
+
*/
|
70 |
+
public function remove($id)
|
71 |
+
{
|
72 |
+
if (!$this->has($id)) {
|
73 |
+
return;
|
74 |
+
}
|
75 |
+
|
76 |
+
unset($this->container[$id]);
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* @param string $id
|
81 |
+
*
|
82 |
+
* @return bool
|
83 |
+
*/
|
84 |
+
public function has($id)
|
85 |
+
{
|
86 |
+
return isset($this->container[$id]);
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* @noinspection PhpUnused
|
91 |
+
* @param string $id
|
92 |
+
* @param array $options
|
93 |
+
*/
|
94 |
+
public function setInitialized($id, array $options = [])
|
95 |
+
{
|
96 |
+
$this->container[$id] = $options;
|
97 |
+
$this->get($id);
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* @noinspection PhpUnused
|
102 |
+
* @param string $key
|
103 |
+
* @param mixed $value
|
104 |
+
*/
|
105 |
+
public function setParameter($key, $value)
|
106 |
+
{
|
107 |
+
$this->parameters[$key] = $value;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* @param string|null $key
|
112 |
+
* @param mixed|null $default
|
113 |
+
*
|
114 |
+
* @return mixed|null
|
115 |
+
*/
|
116 |
+
public function getParameter($key = null, $default = null)
|
117 |
+
{
|
118 |
+
if (null === $key) {
|
119 |
+
return $this->parameters;
|
120 |
+
}
|
121 |
+
|
122 |
+
if ($this->hasParameter($key)) {
|
123 |
+
return $this->parameters[$key];
|
124 |
+
}
|
125 |
+
|
126 |
+
if (false === strpos($key, '.')) {
|
127 |
+
return $default;
|
128 |
+
}
|
129 |
+
|
130 |
+
$params = $this->parameters;
|
131 |
+
foreach (explode('.', $key) as $segment) {
|
132 |
+
if (!is_array($params) || !$this->hasParameter($segment)) {
|
133 |
+
return $default;
|
134 |
+
}
|
135 |
+
|
136 |
+
$items = &$items[$segment];
|
137 |
+
}
|
138 |
+
|
139 |
+
return $params;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* @param string $key
|
144 |
+
*
|
145 |
+
* @return bool
|
146 |
+
*/
|
147 |
+
public function hasParameter($key)
|
148 |
+
{
|
149 |
+
return isset($this->parameters[$key]);
|
150 |
+
}
|
151 |
+
|
152 |
+
private function setContainerByConfig(array $config = [])
|
153 |
+
{
|
154 |
+
if (!isset($config['services'])) {
|
155 |
+
return;
|
156 |
+
}
|
157 |
+
|
158 |
+
foreach ($config['services'] as $key => $value) {
|
159 |
+
if (is_int($key) && is_string($value)) {
|
160 |
+
$key = $value;
|
161 |
+
}
|
162 |
+
$this->container[$key] = $value;
|
163 |
+
}
|
164 |
+
}
|
165 |
+
|
166 |
+
private function setParametersByConfig(array $config = [])
|
167 |
+
{
|
168 |
+
if (!isset($config['params'])) {
|
169 |
+
return;
|
170 |
+
}
|
171 |
+
|
172 |
+
foreach ($config['params'] as $key => $value) {
|
173 |
+
$this->parameters[$key] = $value;
|
174 |
+
}
|
175 |
+
}
|
176 |
+
|
177 |
+
private function setMappingByConfig(array $config = [])
|
178 |
+
{
|
179 |
+
if (!isset($config['mapping'])) {
|
180 |
+
return;
|
181 |
+
}
|
182 |
+
|
183 |
+
foreach ($config['mapping'] as $key => $value) {
|
184 |
+
if (is_scalar($value)) {
|
185 |
+
$this->mapping[$key] = $value;
|
186 |
+
}
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* @param string $id
|
192 |
+
*
|
193 |
+
* @return object|string
|
194 |
+
* @throws InvalidConstructorParamException
|
195 |
+
* @throws ReflectionException
|
196 |
+
*/
|
197 |
+
private function resolve($id)
|
198 |
+
{
|
199 |
+
if (!class_exists($id)) {
|
200 |
+
return $id;
|
201 |
+
}
|
202 |
+
|
203 |
+
$reflection = $this->getReflection($id);
|
204 |
+
|
205 |
+
if (!$reflection) {
|
206 |
+
return $id;
|
207 |
+
}
|
208 |
+
|
209 |
+
return $this->newInstance($reflection);
|
210 |
+
}
|
211 |
+
|
212 |
+
private function getReflection($class)
|
213 |
+
{
|
214 |
+
try {
|
215 |
+
return new ReflectionClass($class);
|
216 |
+
}
|
217 |
+
catch (ReflectionException $e) {
|
218 |
+
return null;
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
/**
|
223 |
+
* @param ReflectionClass|null $reflection
|
224 |
+
*
|
225 |
+
* @return null|object
|
226 |
+
* @throws InvalidConstructorParamException
|
227 |
+
* @throws ReflectionException
|
228 |
+
*/
|
229 |
+
private function newInstance($reflection = null)
|
230 |
+
{
|
231 |
+
if (!$reflection) {
|
232 |
+
return null;
|
233 |
+
}
|
234 |
+
|
235 |
+
if (!$reflection->getConstructor()) {
|
236 |
+
return $reflection->newInstance();
|
237 |
+
}
|
238 |
+
|
239 |
+
$params = $reflection->getConstructor()->getParameters();
|
240 |
+
// TODO PHP7.0; $this->container[$reflection->getName()] ?? [];
|
241 |
+
if (isset($this->container[$reflection->getName()]) && is_array($this->container[$reflection->getName()])) {
|
242 |
+
$options = $this->container[$reflection->getName()];
|
243 |
+
}
|
244 |
+
else {
|
245 |
+
$options = [];
|
246 |
+
}
|
247 |
+
|
248 |
+
$args = [];
|
249 |
+
foreach ($params as $param) {
|
250 |
+
$args[] = $this->getConstructorParam($param, $options);
|
251 |
+
}
|
252 |
+
|
253 |
+
return $reflection->newInstanceArgs($args);
|
254 |
+
}
|
255 |
+
|
256 |
+
/**
|
257 |
+
* @param ReflectionParameter $param
|
258 |
+
* @param array $options
|
259 |
+
*
|
260 |
+
* @return mixed|object|null
|
261 |
+
* @throws InvalidConstructorParamException
|
262 |
+
* @throws ReflectionException
|
263 |
+
*/
|
264 |
+
private function getConstructorParam(ReflectionParameter $param, array $options = [])
|
265 |
+
{
|
266 |
+
if ($param->getClass()) {
|
267 |
+
return $this->getConstructorParamClass($param->getClass());
|
268 |
+
}
|
269 |
+
|
270 |
+
// Check param values
|
271 |
+
if (isset($options[$param->getName()])) {
|
272 |
+
return $this->getConstructorParamValue($options[$param->getName()]);
|
273 |
+
}
|
274 |
+
|
275 |
+
if (isset($this->parameters[$param->getName()])) {
|
276 |
+
return $this->getConstructorParamValue($this->parameters[$param->getName()]);
|
277 |
+
}
|
278 |
+
|
279 |
+
|
280 |
+
if ($param->isDefaultValueAvailable()) {
|
281 |
+
return $param->getDefaultValue();
|
282 |
+
}
|
283 |
+
|
284 |
+
if ($param->getType() && $param->getType()->allowsNull()) {
|
285 |
+
return null;
|
286 |
+
}
|
287 |
+
|
288 |
+
throw new InvalidConstructorParamException($param->getName());
|
289 |
+
}
|
290 |
+
|
291 |
+
private function getConstructorParamClass(ReflectionClass $class)
|
292 |
+
{
|
293 |
+
if (isset($this->mapping[$class->getName()])) {
|
294 |
+
return $this->get($this->mapping[$class->getName()]);
|
295 |
+
}
|
296 |
+
|
297 |
+
return $this->get($class->getName());
|
298 |
+
}
|
299 |
+
|
300 |
+
/**
|
301 |
+
* @param null|array|string $value
|
302 |
+
*
|
303 |
+
* @return null|object|array|string
|
304 |
+
*/
|
305 |
+
private function getConstructorParamValue($value = null)
|
306 |
+
{
|
307 |
+
if (!is_string($value)) {
|
308 |
+
return $value;
|
309 |
+
}
|
310 |
+
|
311 |
+
if (class_exists($value)) {
|
312 |
+
return $this->get($value);
|
313 |
+
}
|
314 |
+
|
315 |
+
if (!preg_match_all('#{{(.*?)}}#', $value, $matches)) {
|
316 |
+
return $value;
|
317 |
+
}
|
318 |
+
|
319 |
+
$replace = [];
|
320 |
+
|
321 |
+
foreach ($matches[1] as $key) {
|
322 |
+
$replace[] = $this->getParameter($key);
|
323 |
+
}
|
324 |
+
|
325 |
+
return str_replace($matches[0], $replace, $value);
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* @param string $id
|
330 |
+
*
|
331 |
+
* @return object|null
|
332 |
+
* @throws InvalidConstructorParamException
|
333 |
+
* @throws ReflectionException
|
334 |
+
*/
|
335 |
+
private function loadClass($id)
|
336 |
+
{
|
337 |
+
if (isset($this->mapping[$id])) {
|
338 |
+
$id = $this->mapping[$id];
|
339 |
+
}
|
340 |
+
|
341 |
+
if (!class_exists($id)) {
|
342 |
+
return null;
|
343 |
+
}
|
344 |
+
|
345 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
346 |
+
$this->container[$id] = $this->resolve($id);
|
347 |
+
|
348 |
+
return $this->container[$id];
|
349 |
+
}
|
350 |
+
}
|
Service/Container/ContainerInterface.php
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Container;
|
4 |
+
|
5 |
+
interface ContainerInterface
|
6 |
+
{
|
7 |
+
/**
|
8 |
+
* @param string $id
|
9 |
+
*
|
10 |
+
* @return object|null
|
11 |
+
*/
|
12 |
+
public function get($id);
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @param string $id
|
16 |
+
* @param null|string|array|object|int|float|bool $value
|
17 |
+
*
|
18 |
+
* @return void
|
19 |
+
*/
|
20 |
+
public function set($id, $value = null);
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @param string $id
|
24 |
+
*
|
25 |
+
* @return bool
|
26 |
+
*/
|
27 |
+
public function has($id);
|
28 |
+
}
|
Service/Container/InvalidConstructorParamException.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Container;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
use Throwable;
|
7 |
+
|
8 |
+
class InvalidConstructorParamException extends Exception
|
9 |
+
{
|
10 |
+
|
11 |
+
public function __construct($message = '', $code = 0, Throwable $previous = null)
|
12 |
+
{
|
13 |
+
$message = sprintf('Invalid Constructor Parameter $%s', $message);
|
14 |
+
parent::__construct($message, $code, $previous);
|
15 |
+
}
|
16 |
+
}
|
Service/Dto/AbstractDto.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
//TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
|
6 |
+
namespace WPStaging\Service\Dto;
|
7 |
+
|
8 |
+
|
9 |
+
use JsonSerializable;
|
10 |
+
use WPStaging\Service\Traits\ArrayableTrait;
|
11 |
+
|
12 |
+
abstract class AbstractDto implements JsonSerializable
|
13 |
+
{
|
14 |
+
use ArrayableTrait;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @inheritDoc
|
18 |
+
*/
|
19 |
+
public function jsonSerialize()
|
20 |
+
{
|
21 |
+
return $this->toArray();
|
22 |
+
}
|
23 |
+
}
|
Service/Entity/AbstractEntity.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
//TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Entity;
|
6 |
+
|
7 |
+
use Serializable;
|
8 |
+
use JsonSerializable;
|
9 |
+
use WPStaging\Service\Interfaces\ArrayableInterface;
|
10 |
+
use WPStaging\Service\Interfaces\HydrateableInterface;
|
11 |
+
use WPStaging\Service\Traits\ArrayableTrait;
|
12 |
+
use WPStaging\Service\Traits\HydrateTrait;
|
13 |
+
|
14 |
+
abstract class AbstractEntity implements Serializable, JsonSerializable, ArrayableInterface, HydrateableInterface
|
15 |
+
{
|
16 |
+
use ArrayableTrait;
|
17 |
+
use HydrateTrait;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @inheritDoc
|
21 |
+
*/
|
22 |
+
public function serialize()
|
23 |
+
{
|
24 |
+
return serialize($this->toArray());
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @inheritDoc
|
29 |
+
*/
|
30 |
+
public function unserialize($serialized)
|
31 |
+
{
|
32 |
+
$this->hydrate(unserialize($serialized));
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @inheritDoc
|
37 |
+
*/
|
38 |
+
public function jsonSerialize()
|
39 |
+
{
|
40 |
+
return $this->toArray();
|
41 |
+
}
|
42 |
+
}
|
Service/Entity/EntityException.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Entity;
|
6 |
+
|
7 |
+
use RuntimeException;
|
8 |
+
|
9 |
+
class EntityException extends RuntimeException
|
10 |
+
{
|
11 |
+
|
12 |
+
}
|
Service/Entity/IdentifyableEntityInterface.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Entity;
|
6 |
+
|
7 |
+
interface IdentifyableEntityInterface
|
8 |
+
{
|
9 |
+
/**
|
10 |
+
* @return string
|
11 |
+
*/
|
12 |
+
public function getId();
|
13 |
+
}
|
Service/Interfaces/ArrayableInterface.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; type-hints & return types
|
5 |
+
|
6 |
+
namespace WPStaging\Service\Interfaces;
|
7 |
+
|
8 |
+
interface ArrayableInterface
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* @return array
|
12 |
+
*/
|
13 |
+
public function toArray();
|
14 |
+
}
|
Service/Interfaces/HydrateableInterface.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; type-hints & return types
|
5 |
+
|
6 |
+
namespace WPStaging\Service\Interfaces;
|
7 |
+
|
8 |
+
interface HydrateableInterface
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* @param array $data
|
12 |
+
*
|
13 |
+
* @return self
|
14 |
+
*/
|
15 |
+
public function hydrate(array $data = []);
|
16 |
+
}
|
Service/InvalidPluginException.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
use Throwable;
|
7 |
+
|
8 |
+
class InvalidPluginException extends Exception
|
9 |
+
{
|
10 |
+
|
11 |
+
public function __construct($message = '', $code = 0, Throwable $previous = null)
|
12 |
+
{
|
13 |
+
$message = sprintf('Plugin %s must implement PluginInterface', $message);
|
14 |
+
parent::__construct($message, $code, $previous);
|
15 |
+
}
|
16 |
+
}
|
Service/PluginFactory.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service;
|
4 |
+
|
5 |
+
use WPStaging\Service\Container\Container;
|
6 |
+
|
7 |
+
class PluginFactory implements PluginFactoryInterface
|
8 |
+
{
|
9 |
+
/**
|
10 |
+
* @param string $pluginClass
|
11 |
+
*
|
12 |
+
* @return PluginInterface
|
13 |
+
* @throws InvalidPluginException
|
14 |
+
*/
|
15 |
+
public static function make($pluginClass)
|
16 |
+
{
|
17 |
+
/** @noinspection PhpIncludeInspection */
|
18 |
+
$config = require plugin_dir_path(__FILE__) . '../config.php';
|
19 |
+
$container = new Container($config?: []);
|
20 |
+
|
21 |
+
/** @var PluginInterface $plugin */
|
22 |
+
$plugin = new $pluginClass($container);
|
23 |
+
|
24 |
+
if (!$plugin instanceof PluginInterface) {
|
25 |
+
throw new InvalidPluginException($pluginClass);
|
26 |
+
}
|
27 |
+
|
28 |
+
if (!isset($config['components'])) {
|
29 |
+
return $plugin;
|
30 |
+
}
|
31 |
+
|
32 |
+
foreach ($config['components'] as $id => $options) {
|
33 |
+
if (is_string($id) && is_array($options)) {
|
34 |
+
$plugin->addComponent($id, $options);
|
35 |
+
continue;
|
36 |
+
}
|
37 |
+
|
38 |
+
$plugin->addComponent($options);
|
39 |
+
}
|
40 |
+
|
41 |
+
return $plugin;
|
42 |
+
}
|
43 |
+
}
|
Service/PluginFactoryInterface.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service;
|
4 |
+
|
5 |
+
interface PluginFactoryInterface
|
6 |
+
{
|
7 |
+
/**
|
8 |
+
* @param string $pluginClass
|
9 |
+
*
|
10 |
+
* @return AbstractPlugin
|
11 |
+
*/
|
12 |
+
public static function make($pluginClass);
|
13 |
+
}
|
Service/PluginInterface.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service;
|
4 |
+
|
5 |
+
use WPStaging\Service\Container\Container;
|
6 |
+
|
7 |
+
interface PluginInterface
|
8 |
+
{
|
9 |
+
public function setContainer(Container $container);
|
10 |
+
|
11 |
+
public function init();
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @param string $id
|
15 |
+
* @param array $options
|
16 |
+
*/
|
17 |
+
public function addComponent($id, array $options = []);
|
18 |
+
|
19 |
+
public function removeComponent($id);
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @return string|null
|
23 |
+
*/
|
24 |
+
public function getSlug();
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @return Container
|
28 |
+
*/
|
29 |
+
public function getContainer();
|
30 |
+
}
|
Service/TemplateEngine/TemplateEngine.php
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// TODO PHP7.x; declare(strict_types=1);
|
3 |
+
// TODO PHP7.x; type-hints & return types;
|
4 |
+
|
5 |
+
namespace WPStaging\Service\TemplateEngine;
|
6 |
+
|
7 |
+
use DateTime;
|
8 |
+
use WPStaging\Service\Adapter\DateTimeAdapter;
|
9 |
+
use WPStaging\Service\Adapter\Directory;
|
10 |
+
|
11 |
+
class TemplateEngine implements TemplateEngineInterface
|
12 |
+
{
|
13 |
+
|
14 |
+
/** @var string */
|
15 |
+
private $slug;
|
16 |
+
|
17 |
+
/** @var string */
|
18 |
+
private $path;
|
19 |
+
|
20 |
+
/** @var string */
|
21 |
+
private $url;
|
22 |
+
|
23 |
+
/** @var string */
|
24 |
+
private $domain;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* TemplateEngine constructor.
|
28 |
+
*
|
29 |
+
* @param Directory $directory
|
30 |
+
* @param string $slug
|
31 |
+
* @param string $domain
|
32 |
+
*/
|
33 |
+
public function __construct(Directory $directory, $slug, $domain)
|
34 |
+
{
|
35 |
+
$this->slug = $slug;
|
36 |
+
$this->domain = $domain;
|
37 |
+
$this->path = $directory->getPluginDirectory() . 'template/';
|
38 |
+
$this->url = plugin_dir_url($directory->getPluginDirectory() . $slug . '.php') . 'public/';
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @return string
|
43 |
+
* @noinspection PhpUnused
|
44 |
+
*/
|
45 |
+
public function getSlug()
|
46 |
+
{
|
47 |
+
return $this->slug;
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* @return string
|
52 |
+
*/
|
53 |
+
public function getDomain()
|
54 |
+
{
|
55 |
+
return $this->domain;
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* @param string $domain
|
60 |
+
*/
|
61 |
+
public function setDomain($domain)
|
62 |
+
{
|
63 |
+
$this->domain = $domain;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* @return string
|
68 |
+
* @noinspection PhpUnused
|
69 |
+
*/
|
70 |
+
public function getPath()
|
71 |
+
{
|
72 |
+
return $this->path;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* @param string $path
|
77 |
+
* @noinspection PhpUnused
|
78 |
+
*/
|
79 |
+
public function setPath($path)
|
80 |
+
{
|
81 |
+
$this->path = $path;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* @return string
|
86 |
+
* @noinspection PhpUnused
|
87 |
+
*/
|
88 |
+
public function getUrl()
|
89 |
+
{
|
90 |
+
return $this->url;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* @param string $url
|
95 |
+
* @noinspection PhpUnused
|
96 |
+
*/
|
97 |
+
public function setUrl($url)
|
98 |
+
{
|
99 |
+
$this->url = $url;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* @param string $path
|
104 |
+
* @param array $params
|
105 |
+
*
|
106 |
+
* @return string
|
107 |
+
*/
|
108 |
+
public function render($path, array $params = [])
|
109 |
+
{
|
110 |
+
$fullPath = $this->path . $path;
|
111 |
+
if (!file_exists($fullPath)) {
|
112 |
+
throw new TemplateEngineException('Template not found: ' . $fullPath);
|
113 |
+
}
|
114 |
+
|
115 |
+
extract($params, EXTR_SKIP);
|
116 |
+
ob_start();
|
117 |
+
|
118 |
+
/** @noinspection PhpIncludeInspection */
|
119 |
+
require $fullPath;
|
120 |
+
$result = ob_get_clean();
|
121 |
+
|
122 |
+
return (string)$result;
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* @return string
|
127 |
+
* @noinspection PhpUnused
|
128 |
+
*/
|
129 |
+
protected function getDateTimeFormat()
|
130 |
+
{
|
131 |
+
return (new DateTimeAdapter)->getDateTimeFormat();
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* @param DateTime|null $dateTime
|
136 |
+
*
|
137 |
+
* @return string
|
138 |
+
*/
|
139 |
+
protected function transformToWpFormat(DateTime $dateTime = null)
|
140 |
+
{
|
141 |
+
if (!$dateTime) {
|
142 |
+
return '';
|
143 |
+
}
|
144 |
+
return (new DateTimeAdapter)->transformToWpFormat($dateTime);
|
145 |
+
}
|
146 |
+
}
|
Service/TemplateEngine/TemplateEngineException.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// TODO PHP7.x; declare(strict_types=1);
|
3 |
+
|
4 |
+
namespace WPStaging\Service\TemplateEngine;
|
5 |
+
|
6 |
+
use RuntimeException;
|
7 |
+
|
8 |
+
class TemplateEngineException extends RuntimeException
|
9 |
+
{
|
10 |
+
|
11 |
+
}
|
Service/TemplateEngine/TemplateEngineInterface.php
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// TODO PHP7.x declare(strict_types=1);
|
3 |
+
// TODO PHP7.x; type-hints & return types;
|
4 |
+
|
5 |
+
namespace WPStaging\Service\TemplateEngine;
|
6 |
+
|
7 |
+
interface TemplateEngineInterface
|
8 |
+
{
|
9 |
+
|
10 |
+
public function render($path, array $params = []);
|
11 |
+
}
|
Service/Traits/ArrayableTrait.php
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Traits;
|
6 |
+
|
7 |
+
use DateTime;
|
8 |
+
use ReflectionClass;
|
9 |
+
use ReflectionProperty;
|
10 |
+
use WPStaging\Service\Adapter\DateTimeAdapter;
|
11 |
+
|
12 |
+
trait ArrayableTrait
|
13 |
+
{
|
14 |
+
/**
|
15 |
+
* @return array
|
16 |
+
* @noinspection PhpDocMissingThrowsInspection
|
17 |
+
*/
|
18 |
+
public function toArray()
|
19 |
+
{
|
20 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
21 |
+
$reflection = new ReflectionClass($this);
|
22 |
+
$props = $reflection->getProperties(
|
23 |
+
ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE
|
24 |
+
);
|
25 |
+
|
26 |
+
$data = [];
|
27 |
+
/** @var ReflectionProperty $prop */
|
28 |
+
foreach($props as $prop) {
|
29 |
+
$prop->setAccessible(true);
|
30 |
+
$value = $prop->getValue($this);
|
31 |
+
|
32 |
+
if ($value instanceof DateTime) {
|
33 |
+
$value = (new DateTimeAdapter)->transformToWpFormat($value);
|
34 |
+
}
|
35 |
+
|
36 |
+
$data[$prop->getName()] = $value;
|
37 |
+
}
|
38 |
+
|
39 |
+
return $data;
|
40 |
+
}
|
41 |
+
}
|
Service/Traits/HydrateTrait.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x type-hints & return types
|
5 |
+
|
6 |
+
namespace WPStaging\Service\Traits;
|
7 |
+
|
8 |
+
use DateTime;
|
9 |
+
use ReflectionException;
|
10 |
+
use ReflectionMethod;
|
11 |
+
use WPStaging\Service\Entity\EntityException;
|
12 |
+
|
13 |
+
trait HydrateTrait
|
14 |
+
{
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @param array $data
|
18 |
+
* @return $this
|
19 |
+
* @noinspection PhpDocMissingThrowsInspection
|
20 |
+
*/
|
21 |
+
public function hydrate(array $data = [])
|
22 |
+
{
|
23 |
+
foreach ($data as $key => $value) {
|
24 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
25 |
+
$this->hydrateByMethod('set' . ucfirst($key), $value);
|
26 |
+
}
|
27 |
+
|
28 |
+
return $this;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @param string $method
|
33 |
+
* @param mixed $value
|
34 |
+
*
|
35 |
+
* @throws ReflectionException
|
36 |
+
*/
|
37 |
+
private function hydrateByMethod($method, $value)
|
38 |
+
{
|
39 |
+
if (!method_exists($this, $method)) {
|
40 |
+
return;
|
41 |
+
}
|
42 |
+
|
43 |
+
/** @noinspection CallableParameterUseCaseInTypeContextInspection */
|
44 |
+
$method = new ReflectionMethod($this, $method);
|
45 |
+
|
46 |
+
$params = $method->getParameters();
|
47 |
+
|
48 |
+
if (!isset($params[0]) || count($params) > 1) {
|
49 |
+
throw new EntityException(sprintf(
|
50 |
+
'Class %s setter method %s does not have a first parameter or has more than one parameter',
|
51 |
+
static::class,
|
52 |
+
$method
|
53 |
+
));
|
54 |
+
}
|
55 |
+
|
56 |
+
$param = $params[0];
|
57 |
+
|
58 |
+
if ($value && !$value instanceof DateTime && $param->getClass() && 'DateTime' === $param->getClass()->getName()) {
|
59 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
60 |
+
$value = new DateTime(str_replace(',', null, $value));
|
61 |
+
}
|
62 |
+
|
63 |
+
$method->invoke($this, $value);
|
64 |
+
}
|
65 |
+
}
|
Service/Utils/FileSize.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Utils;
|
6 |
+
|
7 |
+
class FileSize
|
8 |
+
{
|
9 |
+
public function humanReadable($bytes)
|
10 |
+
{
|
11 |
+
$value = floor(log($bytes) / log(1024));
|
12 |
+
$sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
13 |
+
return sprintf('%.02F', $bytes / pow(1024, $value)) * 1 . ' ' . $sizes[$value];
|
14 |
+
}
|
15 |
+
}
|
Service/Utils/FileSystem.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Utils;
|
6 |
+
|
7 |
+
class FileSystem
|
8 |
+
{
|
9 |
+
/*
|
10 |
+
* Makes sure all paths contain linux separator (/) which works fine on all windows systems, too
|
11 |
+
* Windows understands both / and \
|
12 |
+
*/
|
13 |
+
public function compatiblePath($path)
|
14 |
+
{
|
15 |
+
if ('/' === DIRECTORY_SEPARATOR) {
|
16 |
+
return $path;
|
17 |
+
}
|
18 |
+
|
19 |
+
return str_replace('/', DIRECTORY_SEPARATOR, $path);
|
20 |
+
}
|
21 |
+
|
22 |
+
public function replaceWindowsDirSeparator($path)
|
23 |
+
{
|
24 |
+
return preg_replace('/[\\\\]+/', '/', $path);
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @param string $dir
|
29 |
+
* @return bool True if directory is empty. False if empty or does not exist
|
30 |
+
*/
|
31 |
+
public function isEmptyDir($dir)
|
32 |
+
{
|
33 |
+
if (!is_dir($dir)) {
|
34 |
+
return false;
|
35 |
+
}
|
36 |
+
|
37 |
+
return false === (new FilesystemIterator($dir))->valid();
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Delete files and folder. Deals with directories recursively
|
42 |
+
*
|
43 |
+
* @param string $fullPath
|
44 |
+
*/
|
45 |
+
public function deleteFiles($fullPath)
|
46 |
+
{
|
47 |
+
if (is_file($fullPath)) {
|
48 |
+
unlink($fullPath);
|
49 |
+
return;
|
50 |
+
}
|
51 |
+
|
52 |
+
if (!is_dir($fullPath) || $this->isEmptyDir($fullPath)) {
|
53 |
+
return;
|
54 |
+
}
|
55 |
+
|
56 |
+
$di = new RecursiveDirectoryIterator($fullPath, FilesystemIterator::SKIP_DOTS);
|
57 |
+
$ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST);
|
58 |
+
foreach ($ri as $file) {
|
59 |
+
$this->deleteFiles($file);
|
60 |
+
}
|
61 |
+
|
62 |
+
rmdir($fullPath);
|
63 |
+
}
|
64 |
+
}
|
Service/Utils/WpDefaultDirectories.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
|
5 |
+
namespace WPStaging\Service\Utils;
|
6 |
+
|
7 |
+
// TODO PHP7.1; constant visibility
|
8 |
+
class WpDefaultDirectories
|
9 |
+
{
|
10 |
+
const WP_ADMIN = 'wp-admin';
|
11 |
+
const WP_INCLUDES = 'wp-includes';
|
12 |
+
const WP_CONTENT = 'wp-content';
|
13 |
+
const SITES = 'sites';
|
14 |
+
const MULTI_OLD_UPLOADS_DIR = 'blogs.dir';
|
15 |
+
const MULTI_UPLOADS_DIR = 'sites';
|
16 |
+
}
|
config.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @example 'services' or 'components' key can have parameters such as;
|
4 |
+
* `Foo::class => ['slug' => '{{slug}}'],`
|
5 |
+
* `slug` key matches the class constructor variable name (order does not matter) such as `__construct($slug)`
|
6 |
+
* `{{slug}}` value matches the `params.slug` of this file.
|
7 |
+
*
|
8 |
+
* **IMPORTANT TOPICS**
|
9 |
+
* 1. Order of params does not matter as we check & match variable names
|
10 |
+
* 2. Not all params in constructor needs to be defined, only the ones we want
|
11 |
+
* 3. Hand-typed variables are allowed; `Foo::class => ['slug' => 'bar'],`
|
12 |
+
*/
|
13 |
+
|
14 |
+
use Psr\Log\LoggerInterface;
|
15 |
+
use WPStaging\Component\Snapshot\AjaxConfirmDelete as SnapshotAjaxConfirmDelete;
|
16 |
+
use WPStaging\Component\Snapshot\AjaxConfirmRestore as SnapshotAjaxConfirmRestore;
|
17 |
+
use WPStaging\Component\Snapshot\AjaxCreate as SnapshotAjaxCreate;
|
18 |
+
use WPStaging\Component\Snapshot\AjaxCreateProgress as SnapshotAjaxCreateProgress;
|
19 |
+
use WPStaging\Component\Snapshot\AjaxDelete as SnapshotAjaxDelete;
|
20 |
+
use WPStaging\Component\Snapshot\AjaxEdit as SnapshotAjaxEdit;
|
21 |
+
use WPStaging\Component\Snapshot\AjaxExport as SnapshotAjaxExport;
|
22 |
+
use WPStaging\Component\Snapshot\AjaxListing as SnapshotAjaxListing;
|
23 |
+
use WPStaging\Component\Snapshot\AjaxRestore as SnapshotAjaxRestore;
|
24 |
+
use WPStaging\Component\Snapshot\AjaxRestoreProgress as SnapshotAjaxRestoreProgress;
|
25 |
+
use WPStaging\Service\TemplateEngine\TemplateEngine;
|
26 |
+
use WPStaging\Utils\Logger;
|
27 |
+
|
28 |
+
return [
|
29 |
+
// Params we can use all around the application with easy access and without duplication / WET; keep it DRY!
|
30 |
+
'params' => [
|
31 |
+
'slug' => 'wp-staging',
|
32 |
+
'domain' => 'wp-staging',
|
33 |
+
],
|
34 |
+
// Services are not initialized, they are only initialized once when they are requested. If they are already
|
35 |
+
// initialized when requested, the same instance would be used.
|
36 |
+
'services' => [
|
37 |
+
TemplateEngine::class,
|
38 |
+
],
|
39 |
+
// Components are initialized upon plugin init / as soon as the Container is set; such as a class that sets;
|
40 |
+
// Ajax Request, Adds a Menu, Form etc. needs to be initialized without being requested hence they go here!
|
41 |
+
'components' => [
|
42 |
+
SnapshotAjaxListing::class,
|
43 |
+
SnapshotAjaxConfirmDelete::class,
|
44 |
+
SnapshotAjaxDelete::class,
|
45 |
+
SnapshotAjaxCreateProgress::class,
|
46 |
+
SnapshotAjaxCreate::class,
|
47 |
+
SnapshotAjaxConfirmRestore::class,
|
48 |
+
SnapshotAjaxRestoreProgress::class,
|
49 |
+
SnapshotAjaxRestore::class,
|
50 |
+
SnapshotAjaxExport::class,
|
51 |
+
SnapshotAjaxEdit::class,
|
52 |
+
],
|
53 |
+
// Map specific interfaces to specific classes.
|
54 |
+
// If you map LoggerInterface::class to Logger::class, when you use LoggerInterface as a dependency,
|
55 |
+
// it will load / pass Logger class instead
|
56 |
+
'mapping' => [
|
57 |
+
LoggerInterface::class => Logger::class,
|
58 |
+
],
|
59 |
+
];
|
install.php
CHANGED
@@ -2,9 +2,7 @@
|
|
2 |
|
3 |
namespace WPStaging;
|
4 |
|
5 |
-
use WPStaging\WPStaging;
|
6 |
use WPStaging\Backend\Optimizer\Optimizer;
|
7 |
-
use WPStaging\Cron\Cron;
|
8 |
use WPStaging\Utils\IISWebConfig;
|
9 |
use WPStaging\Utils\Htaccess;
|
10 |
use WPStaging\Utils\Filesystem;
|
@@ -13,6 +11,9 @@ use WPStaging\Utils\Filesystem;
|
|
13 |
if (!defined('ABSPATH'))
|
14 |
exit;
|
15 |
|
|
|
|
|
|
|
16 |
/**
|
17 |
* Install Class
|
18 |
*
|
@@ -47,7 +48,7 @@ class Install
|
|
47 |
private function installOptimizer()
|
48 |
{
|
49 |
|
50 |
-
// Install Optimizer
|
51 |
$optimizer = new Optimizer();
|
52 |
$optimizer->installOptimizer();
|
53 |
|
2 |
|
3 |
namespace WPStaging;
|
4 |
|
|
|
5 |
use WPStaging\Backend\Optimizer\Optimizer;
|
|
|
6 |
use WPStaging\Utils\IISWebConfig;
|
7 |
use WPStaging\Utils\Htaccess;
|
8 |
use WPStaging\Utils\Filesystem;
|
11 |
if (!defined('ABSPATH'))
|
12 |
exit;
|
13 |
|
14 |
+
// TODO; remove previous auto-loader, use composer based instead!
|
15 |
+
require_once __DIR__ . '/vendor/autoload.php';
|
16 |
+
|
17 |
/**
|
18 |
* Install Class
|
19 |
*
|
48 |
private function installOptimizer()
|
49 |
{
|
50 |
|
51 |
+
// Install Optimizer
|
52 |
$optimizer = new Optimizer();
|
53 |
$optimizer->installOptimizer();
|
54 |
|
readme.txt
CHANGED
@@ -9,7 +9,7 @@ License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
|
9 |
Tags: staging, duplication, cloning, clone, migration, sandbox, test site, testing, backup, post, admin, administration, duplicate posts
|
10 |
Requires at least: 3.6+
|
11 |
Tested up to: 5.3
|
12 |
-
Stable tag: 2.6.
|
13 |
Requires PHP: 5.3
|
14 |
|
15 |
A duplicator plugin - clone/move, duplicate & migrate live websites to independent staging and development sites that are accessible by authorized users only.
|
@@ -153,6 +153,14 @@ https://wp-staging.com
|
|
153 |
|
154 |
== Changelog ==
|
155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
= 2.6.8 =
|
157 |
* Fix: If server is windows it will result in missing files after cloning and can lead to fatal errors of the staging site
|
158 |
|
@@ -234,15 +242,9 @@ Complete changelog: [https://wp-staging.com/wp-staging-changelog](https://wp-sta
|
|
234 |
== Upgrade Notice ==
|
235 |
* Install this version for supporting latest WordPress version
|
236 |
|
237 |
-
*
|
238 |
-
*
|
239 |
-
*
|
240 |
-
* New:
|
241 |
-
* New:
|
242 |
-
* New:
|
243 |
-
* Fix: Fatal error: Invalid serialization data for DateTime object #91
|
244 |
-
* Fix: Add missing string language location
|
245 |
-
* Fix: Function fnmatch() not available in all systems
|
246 |
-
* Fix: Warning in staging site after initial cloning in db row rewrite_rules
|
247 |
-
* Fix: Wrong staging site is selected when delete function is executed and there are more then 10 staging sites
|
248 |
-
* Fix: Fatal error: Cannot redeclare wpstgpro_overwrite_nonce() and wpstg_overwrite_nonce() after activating pro version on top of this free one
|
9 |
Tags: staging, duplication, cloning, clone, migration, sandbox, test site, testing, backup, post, admin, administration, duplicate posts
|
10 |
Requires at least: 3.6+
|
11 |
Tested up to: 5.3
|
12 |
+
Stable tag: 2.6.9
|
13 |
Requires PHP: 5.3
|
14 |
|
15 |
A duplicator plugin - clone/move, duplicate & migrate live websites to independent staging and development sites that are accessible by authorized users only.
|
153 |
|
154 |
== Changelog ==
|
155 |
|
156 |
+
= 2.6.9 =
|
157 |
+
* Fix: Can not login to staging site under certain circumstances
|
158 |
+
* Fix: Use user selected language setting instead global site based one
|
159 |
+
* Fix: Fatal Error: curl_version() not defined in SystemInfo.php
|
160 |
+
* New: Refactored structure for easier maintenance
|
161 |
+
* New: Core support for WP Staging snapshots
|
162 |
+
* New: Implementing of UnitTests
|
163 |
+
|
164 |
= 2.6.8 =
|
165 |
* Fix: If server is windows it will result in missing files after cloning and can lead to fatal errors of the staging site
|
166 |
|
242 |
== Upgrade Notice ==
|
243 |
* Install this version for supporting latest WordPress version
|
244 |
|
245 |
+
* Fix: Can not login to staging site under certain circumstances
|
246 |
+
* Fix: Use user selected language setting instead global site based one
|
247 |
+
* Fix: Fatal Error: curl_version() not defined in SystemInfo.php
|
248 |
+
* New: Refactored structure for easier maintenance
|
249 |
+
* New: Core support for WP Staging snapshots
|
250 |
+
* New: Implementing of UnitTests
|
|
|
|
|
|
|
|
|
|
|
|
uninstall.php
CHANGED
@@ -18,6 +18,9 @@ if (!defined('WP_UNINSTALL_PLUGIN')) {
|
|
18 |
exit;
|
19 |
}
|
20 |
|
|
|
|
|
|
|
21 |
class uninstall
|
22 |
{
|
23 |
|
18 |
exit;
|
19 |
}
|
20 |
|
21 |
+
// TODO; remove previous auto-loader, use composer based instead!
|
22 |
+
require_once __DIR__ . '/vendor/autoload.php';
|
23 |
+
|
24 |
class uninstall
|
25 |
{
|
26 |
|
vendor/autoload.php
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// autoload.php @generated by Composer
|
4 |
+
|
5 |
+
require_once __DIR__ . '/composer/autoload_real.php';
|
6 |
+
|
7 |
+
return ComposerAutoloaderInitc2c8fce0bd7d21d1b2bc76515b028e91::getLoader();
|
vendor/composer/ClassLoader.php
ADDED
@@ -0,0 +1,445 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Composer.
|
5 |
+
*
|
6 |
+
* (c) Nils Adermann <naderman@naderman.de>
|
7 |
+
* Jordi Boggiano <j.boggiano@seld.be>
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
namespace Composer\Autoload;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
17 |
+
*
|
18 |
+
* $loader = new \Composer\Autoload\ClassLoader();
|
19 |
+
*
|
20 |
+
* // register classes with namespaces
|
21 |
+
* $loader->add('Symfony\Component', __DIR__.'/component');
|
22 |
+
* $loader->add('Symfony', __DIR__.'/framework');
|
23 |
+
*
|
24 |
+
* // activate the autoloader
|
25 |
+
* $loader->register();
|
26 |
+
*
|
27 |
+
* // to enable searching the include path (eg. for PEAR packages)
|
28 |
+
* $loader->setUseIncludePath(true);
|
29 |
+
*
|
30 |
+
* In this example, if you try to use a class in the Symfony\Component
|
31 |
+
* namespace or one of its children (Symfony\Component\Console for instance),
|
32 |
+
* the autoloader will first look for the class under the component/
|
33 |
+
* directory, and it will then fallback to the framework/ directory if not
|
34 |
+
* found before giving up.
|
35 |
+
*
|
36 |
+
* This class is loosely based on the Symfony UniversalClassLoader.
|
37 |
+
*
|
38 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
39 |
+
* @author Jordi Boggiano <j.boggiano@seld.be>
|
40 |
+
* @see http://www.php-fig.org/psr/psr-0/
|
41 |
+
* @see http://www.php-fig.org/psr/psr-4/
|
42 |
+
*/
|
43 |
+
class ClassLoader
|
44 |
+
{
|
45 |
+
// PSR-4
|
46 |
+
private $prefixLengthsPsr4 = array();
|
47 |
+
private $prefixDirsPsr4 = array();
|
48 |
+
private $fallbackDirsPsr4 = array();
|
49 |
+
|
50 |
+
// PSR-0
|
51 |
+
private $prefixesPsr0 = array();
|
52 |
+
private $fallbackDirsPsr0 = array();
|
53 |
+
|
54 |
+
private $useIncludePath = false;
|
55 |
+
private $classMap = array();
|
56 |
+
private $classMapAuthoritative = false;
|
57 |
+
private $missingClasses = array();
|
58 |
+
private $apcuPrefix;
|
59 |
+
|
60 |
+
public function getPrefixes()
|
61 |
+
{
|
62 |
+
if (!empty($this->prefixesPsr0)) {
|
63 |
+
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
64 |
+
}
|
65 |
+
|
66 |
+
return array();
|
67 |
+
}
|
68 |
+
|
69 |
+
public function getPrefixesPsr4()
|
70 |
+
{
|
71 |
+
return $this->prefixDirsPsr4;
|
72 |
+
}
|
73 |
+
|
74 |
+
public function getFallbackDirs()
|
75 |
+
{
|
76 |
+
return $this->fallbackDirsPsr0;
|
77 |
+
}
|
78 |
+
|
79 |
+
public function getFallbackDirsPsr4()
|
80 |
+
{
|
81 |
+
return $this->fallbackDirsPsr4;
|
82 |
+
}
|
83 |
+
|
84 |
+
public function getClassMap()
|
85 |
+
{
|
86 |
+
return $this->classMap;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* @param array $classMap Class to filename map
|
91 |
+
*/
|
92 |
+
public function addClassMap(array $classMap)
|
93 |
+
{
|
94 |
+
if ($this->classMap) {
|
95 |
+
$this->classMap = array_merge($this->classMap, $classMap);
|
96 |
+
} else {
|
97 |
+
$this->classMap = $classMap;
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Registers a set of PSR-0 directories for a given prefix, either
|
103 |
+
* appending or prepending to the ones previously set for this prefix.
|
104 |
+
*
|
105 |
+
* @param string $prefix The prefix
|
106 |
+
* @param array|string $paths The PSR-0 root directories
|
107 |
+
* @param bool $prepend Whether to prepend the directories
|
108 |
+
*/
|
109 |
+
public function add($prefix, $paths, $prepend = false)
|
110 |
+
{
|
111 |
+
if (!$prefix) {
|
112 |
+
if ($prepend) {
|
113 |
+
$this->fallbackDirsPsr0 = array_merge(
|
114 |
+
(array) $paths,
|
115 |
+
$this->fallbackDirsPsr0
|
116 |
+
);
|
117 |
+
} else {
|
118 |
+
$this->fallbackDirsPsr0 = array_merge(
|
119 |
+
$this->fallbackDirsPsr0,
|
120 |
+
(array) $paths
|
121 |
+
);
|
122 |
+
}
|
123 |
+
|
124 |
+
return;
|
125 |
+
}
|
126 |
+
|
127 |
+
$first = $prefix[0];
|
128 |
+
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
129 |
+
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
130 |
+
|
131 |
+
return;
|
132 |
+
}
|
133 |
+
if ($prepend) {
|
134 |
+
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
135 |
+
(array) $paths,
|
136 |
+
$this->prefixesPsr0[$first][$prefix]
|
137 |
+
);
|
138 |
+
} else {
|
139 |
+
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
140 |
+
$this->prefixesPsr0[$first][$prefix],
|
141 |
+
(array) $paths
|
142 |
+
);
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Registers a set of PSR-4 directories for a given namespace, either
|
148 |
+
* appending or prepending to the ones previously set for this namespace.
|
149 |
+
*
|
150 |
+
* @param string $prefix The prefix/namespace, with trailing '\\'
|
151 |
+
* @param array|string $paths The PSR-4 base directories
|
152 |
+
* @param bool $prepend Whether to prepend the directories
|
153 |
+
*
|
154 |
+
* @throws \InvalidArgumentException
|
155 |
+
*/
|
156 |
+
public function addPsr4($prefix, $paths, $prepend = false)
|
157 |
+
{
|
158 |
+
if (!$prefix) {
|
159 |
+
// Register directories for the root namespace.
|
160 |
+
if ($prepend) {
|
161 |
+
$this->fallbackDirsPsr4 = array_merge(
|
162 |
+
(array) $paths,
|
163 |
+
$this->fallbackDirsPsr4
|
164 |
+
);
|
165 |
+
} else {
|
166 |
+
$this->fallbackDirsPsr4 = array_merge(
|
167 |
+
$this->fallbackDirsPsr4,
|
168 |
+
(array) $paths
|
169 |
+
);
|
170 |
+
}
|
171 |
+
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
172 |
+
// Register directories for a new namespace.
|
173 |
+
$length = strlen($prefix);
|
174 |
+
if ('\\' !== $prefix[$length - 1]) {
|
175 |
+
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
176 |
+
}
|
177 |
+
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
178 |
+
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
179 |
+
} elseif ($prepend) {
|
180 |
+
// Prepend directories for an already registered namespace.
|
181 |
+
$this->prefixDirsPsr4[$prefix] = array_merge(
|
182 |
+
(array) $paths,
|
183 |
+
$this->prefixDirsPsr4[$prefix]
|
184 |
+
);
|
185 |
+
} else {
|
186 |
+
// Append directories for an already registered namespace.
|
187 |
+
$this->prefixDirsPsr4[$prefix] = array_merge(
|
188 |
+
$this->prefixDirsPsr4[$prefix],
|
189 |
+
(array) $paths
|
190 |
+
);
|
191 |
+
}
|
192 |
+
}
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Registers a set of PSR-0 directories for a given prefix,
|
196 |
+
* replacing any others previously set for this prefix.
|
197 |
+
*
|
198 |
+
* @param string $prefix The prefix
|
199 |
+
* @param array|string $paths The PSR-0 base directories
|
200 |
+
*/
|
201 |
+
public function set($prefix, $paths)
|
202 |
+
{
|
203 |
+
if (!$prefix) {
|
204 |
+
$this->fallbackDirsPsr0 = (array) $paths;
|
205 |
+
} else {
|
206 |
+
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Registers a set of PSR-4 directories for a given namespace,
|
212 |
+
* replacing any others previously set for this namespace.
|
213 |
+
*
|
214 |
+
* @param string $prefix The prefix/namespace, with trailing '\\'
|
215 |
+
* @param array|string $paths The PSR-4 base directories
|
216 |
+
*
|
217 |
+
* @throws \InvalidArgumentException
|
218 |
+
*/
|
219 |
+
public function setPsr4($prefix, $paths)
|
220 |
+
{
|
221 |
+
if (!$prefix) {
|
222 |
+
$this->fallbackDirsPsr4 = (array) $paths;
|
223 |
+
} else {
|
224 |
+
$length = strlen($prefix);
|
225 |
+
if ('\\' !== $prefix[$length - 1]) {
|
226 |
+
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
227 |
+
}
|
228 |
+
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
229 |
+
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
230 |
+
}
|
231 |
+
}
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Turns on searching the include path for class files.
|
235 |
+
*
|
236 |
+
* @param bool $useIncludePath
|
237 |
+
*/
|
238 |
+
public function setUseIncludePath($useIncludePath)
|
239 |
+
{
|
240 |
+
$this->useIncludePath = $useIncludePath;
|
241 |
+
}
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Can be used to check if the autoloader uses the include path to check
|
245 |
+
* for classes.
|
246 |
+
*
|
247 |
+
* @return bool
|
248 |
+
*/
|
249 |
+
public function getUseIncludePath()
|
250 |
+
{
|
251 |
+
return $this->useIncludePath;
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Turns off searching the prefix and fallback directories for classes
|
256 |
+
* that have not been registered with the class map.
|
257 |
+
*
|
258 |
+
* @param bool $classMapAuthoritative
|
259 |
+
*/
|
260 |
+
public function setClassMapAuthoritative($classMapAuthoritative)
|
261 |
+
{
|
262 |
+
$this->classMapAuthoritative = $classMapAuthoritative;
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Should class lookup fail if not found in the current class map?
|
267 |
+
*
|
268 |
+
* @return bool
|
269 |
+
*/
|
270 |
+
public function isClassMapAuthoritative()
|
271 |
+
{
|
272 |
+
return $this->classMapAuthoritative;
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
277 |
+
*
|
278 |
+
* @param string|null $apcuPrefix
|
279 |
+
*/
|
280 |
+
public function setApcuPrefix($apcuPrefix)
|
281 |
+
{
|
282 |
+
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* The APCu prefix in use, or null if APCu caching is not enabled.
|
287 |
+
*
|
288 |
+
* @return string|null
|
289 |
+
*/
|
290 |
+
public function getApcuPrefix()
|
291 |
+
{
|
292 |
+
return $this->apcuPrefix;
|
293 |
+
}
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Registers this instance as an autoloader.
|
297 |
+
*
|
298 |
+
* @param bool $prepend Whether to prepend the autoloader or not
|
299 |
+
*/
|
300 |
+
public function register($prepend = false)
|
301 |
+
{
|
302 |
+
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* Unregisters this instance as an autoloader.
|
307 |
+
*/
|
308 |
+
public function unregister()
|
309 |
+
{
|
310 |
+
spl_autoload_unregister(array($this, 'loadClass'));
|
311 |
+
}
|
312 |
+
|
313 |
+
/**
|
314 |
+
* Loads the given class or interface.
|
315 |
+
*
|
316 |
+
* @param string $class The name of the class
|
317 |
+
* @return bool|null True if loaded, null otherwise
|
318 |
+
*/
|
319 |
+
public function loadClass($class)
|
320 |
+
{
|
321 |
+
if ($file = $this->findFile($class)) {
|
322 |
+
includeFile($file);
|
323 |
+
|
324 |
+
return true;
|
325 |
+
}
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Finds the path to the file where the class is defined.
|
330 |
+
*
|
331 |
+
* @param string $class The name of the class
|
332 |
+
*
|
333 |
+
* @return string|false The path if found, false otherwise
|
334 |
+
*/
|
335 |
+
public function findFile($class)
|
336 |
+
{
|
337 |
+
// class map lookup
|
338 |
+
if (isset($this->classMap[$class])) {
|
339 |
+
return $this->classMap[$class];
|
340 |
+
}
|
341 |
+
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
342 |
+
return false;
|
343 |
+
}
|
344 |
+
if (null !== $this->apcuPrefix) {
|
345 |
+
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
346 |
+
if ($hit) {
|
347 |
+
return $file;
|
348 |
+
}
|
349 |
+
}
|
350 |
+
|
351 |
+
$file = $this->findFileWithExtension($class, '.php');
|
352 |
+
|
353 |
+
// Search for Hack files if we are running on HHVM
|
354 |
+
if (false === $file && defined('HHVM_VERSION')) {
|
355 |
+
$file = $this->findFileWithExtension($class, '.hh');
|
356 |
+
}
|
357 |
+
|
358 |
+
if (null !== $this->apcuPrefix) {
|
359 |
+
apcu_add($this->apcuPrefix.$class, $file);
|
360 |
+
}
|
361 |
+
|
362 |
+
if (false === $file) {
|
363 |
+
// Remember that this class does not exist.
|
364 |
+
$this->missingClasses[$class] = true;
|
365 |
+
}
|
366 |
+
|
367 |
+
return $file;
|
368 |
+
}
|
369 |
+
|
370 |
+
private function findFileWithExtension($class, $ext)
|
371 |
+
{
|
372 |
+
// PSR-4 lookup
|
373 |
+
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
374 |
+
|
375 |
+
$first = $class[0];
|
376 |
+
if (isset($this->prefixLengthsPsr4[$first])) {
|
377 |
+
$subPath = $class;
|
378 |
+
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
379 |
+
$subPath = substr($subPath, 0, $lastPos);
|
380 |
+
$search = $subPath.'\\';
|
381 |
+
if (isset($this->prefixDirsPsr4[$search])) {
|
382 |
+
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
383 |
+
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
384 |
+
if (file_exists($file = $dir . $pathEnd)) {
|
385 |
+
return $file;
|
386 |
+
}
|
387 |
+
}
|
388 |
+
}
|
389 |
+
}
|
390 |
+
}
|
391 |
+
|
392 |
+
// PSR-4 fallback dirs
|
393 |
+
foreach ($this->fallbackDirsPsr4 as $dir) {
|
394 |
+
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
395 |
+
return $file;
|
396 |
+
}
|
397 |
+
}
|
398 |
+
|
399 |
+
// PSR-0 lookup
|
400 |
+
if (false !== $pos = strrpos($class, '\\')) {
|
401 |
+
// namespaced class name
|
402 |
+
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
403 |
+
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
404 |
+
} else {
|
405 |
+
// PEAR-like class name
|
406 |
+
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
407 |
+
}
|
408 |
+
|
409 |
+
if (isset($this->prefixesPsr0[$first])) {
|
410 |
+
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
411 |
+
if (0 === strpos($class, $prefix)) {
|
412 |
+
foreach ($dirs as $dir) {
|
413 |
+
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
414 |
+
return $file;
|
415 |
+
}
|
416 |
+
}
|
417 |
+
}
|
418 |
+
}
|
419 |
+
}
|
420 |
+
|
421 |
+
// PSR-0 fallback dirs
|
422 |
+
foreach ($this->fallbackDirsPsr0 as $dir) {
|
423 |
+
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
424 |
+
return $file;
|
425 |
+
}
|
426 |
+
}
|
427 |
+
|
428 |
+
// PSR-0 include paths.
|
429 |
+
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
430 |
+
return $file;
|
431 |
+
}
|
432 |
+
|
433 |
+
return false;
|
434 |
+
}
|
435 |
+
}
|
436 |
+
|
437 |
+
/**
|
438 |
+
* Scope isolated include.
|
439 |
+
*
|
440 |
+
* Prevents access to $this/self from included files.
|
441 |
+
*/
|
442 |
+
function includeFile($file)
|
443 |
+
{
|
444 |
+
include $file;
|
445 |
+
}
|
vendor/composer/LICENSE
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
2 |
+
Upstream-Name: Composer
|
3 |
+
Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be>
|
4 |
+
Source: https://github.com/composer/composer
|
5 |
+
|
6 |
+
Files: *
|
7 |
+
Copyright: 2016, Nils Adermann <naderman@naderman.de>
|
8 |
+
2016, Jordi Boggiano <j.boggiano@seld.be>
|
9 |
+
License: Expat
|
10 |
+
|
11 |
+
Files: src/Composer/Util/TlsHelper.php
|
12 |
+
Copyright: 2016, Nils Adermann <naderman@naderman.de>
|
13 |
+
2016, Jordi Boggiano <j.boggiano@seld.be>
|
14 |
+
2013, Evan Coury <me@evancoury.com>
|
15 |
+
License: Expat and BSD-2-Clause
|
16 |
+
|
17 |
+
License: BSD-2-Clause
|
18 |
+
Redistribution and use in source and binary forms, with or without modification,
|
19 |
+
are permitted provided that the following conditions are met:
|
20 |
+
.
|
21 |
+
* Redistributions of source code must retain the above copyright notice,
|
22 |
+
this list of conditions and the following disclaimer.
|
23 |
+
.
|
24 |
+
* Redistributions in binary form must reproduce the above copyright notice,
|
25 |
+
this list of conditions and the following disclaimer in the documentation
|
26 |
+
and/or other materials provided with the distribution.
|
27 |
+
.
|
28 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
29 |
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
30 |
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
31 |
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
32 |
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
33 |
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
34 |
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
35 |
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
36 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
37 |
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
38 |
+
|
39 |
+
License: Expat
|
40 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
41 |
+
of this software and associated documentation files (the "Software"), to deal
|
42 |
+
in the Software without restriction, including without limitation the rights
|
43 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
44 |
+
copies of the Software, and to permit persons to whom the Software is furnished
|
45 |
+
to do so, subject to the following conditions:
|
46 |
+
.
|
47 |
+
The above copyright notice and this permission notice shall be included in all
|
48 |
+
copies or substantial portions of the Software.
|
49 |
+
.
|
50 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
51 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
52 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
53 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
54 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
55 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
56 |
+
THE SOFTWARE.
|
vendor/composer/autoload_classmap.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// autoload_classmap.php @generated by Composer
|
4 |
+
|
5 |
+
$vendorDir = dirname(dirname(__FILE__));
|
6 |
+
$baseDir = dirname($vendorDir);
|
7 |
+
|
8 |
+
return array(
|
9 |
+
);
|
vendor/composer/autoload_namespaces.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// autoload_namespaces.php @generated by Composer
|
4 |
+
|
5 |
+
$vendorDir = dirname(dirname(__FILE__));
|
6 |
+
$baseDir = dirname($vendorDir);
|
7 |
+
|
8 |
+
return array(
|
9 |
+
);
|
vendor/composer/autoload_psr4.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// autoload_psr4.php @generated by Composer
|
4 |
+
|
5 |
+
$vendorDir = dirname(dirname(__FILE__));
|
6 |
+
$baseDir = dirname($vendorDir);
|
7 |
+
|
8 |
+
return array(
|
9 |
+
'WPStaging\\Test\\' => array($baseDir . '/../tests/unit'),
|
10 |
+
'WPStaging\\' => array($baseDir . '/'),
|
11 |
+
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
|
12 |
+
);
|
vendor/composer/autoload_real.php
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// autoload_real.php @generated by Composer
|
4 |
+
|
5 |
+
class ComposerAutoloaderInitc2c8fce0bd7d21d1b2bc76515b028e91
|
6 |
+
{
|
7 |
+
private static $loader;
|
8 |
+
|
9 |
+
public static function loadClassLoader($class)
|
10 |
+
{
|
11 |
+
if ('Composer\Autoload\ClassLoader' === $class) {
|
12 |
+
require __DIR__ . '/ClassLoader.php';
|
13 |
+
}
|
14 |
+
}
|
15 |
+
|
16 |
+
public static function getLoader()
|
17 |
+
{
|
18 |
+
if (null !== self::$loader) {
|
19 |
+
return self::$loader;
|
20 |
+
}
|
21 |
+
|
22 |
+
spl_autoload_register(array('ComposerAutoloaderInitc2c8fce0bd7d21d1b2bc76515b028e91', 'loadClassLoader'), true, true);
|
23 |
+
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
24 |
+
spl_autoload_unregister(array('ComposerAutoloaderInitc2c8fce0bd7d21d1b2bc76515b028e91', 'loadClassLoader'));
|
25 |
+
|
26 |
+
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
27 |
+
if ($useStaticLoader) {
|
28 |
+
require_once __DIR__ . '/autoload_static.php';
|
29 |
+
|
30 |
+
call_user_func(\Composer\Autoload\ComposerStaticInitc2c8fce0bd7d21d1b2bc76515b028e91::getInitializer($loader));
|
31 |
+
} else {
|
32 |
+
$map = require __DIR__ . '/autoload_namespaces.php';
|
33 |
+
foreach ($map as $namespace => $path) {
|
34 |
+
$loader->set($namespace, $path);
|
35 |
+
}
|
36 |
+
|
37 |
+
$map = require __DIR__ . '/autoload_psr4.php';
|
38 |
+
foreach ($map as $namespace => $path) {
|
39 |
+
$loader->setPsr4($namespace, $path);
|
40 |
+
}
|
41 |
+
|
42 |
+
$classMap = require __DIR__ . '/autoload_classmap.php';
|
43 |
+
if ($classMap) {
|
44 |
+
$loader->addClassMap($classMap);
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
$loader->register(true);
|
49 |
+
|
50 |
+
return $loader;
|
51 |
+
}
|
52 |
+
}
|
vendor/composer/autoload_static.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// autoload_static.php @generated by Composer
|
4 |
+
|
5 |
+
namespace Composer\Autoload;
|
6 |
+
|
7 |
+
class ComposerStaticInitc2c8fce0bd7d21d1b2bc76515b028e91
|
8 |
+
{
|
9 |
+
public static $prefixLengthsPsr4 = array (
|
10 |
+
'W' =>
|
11 |
+
array (
|
12 |
+
'WPStaging\\' => 10,
|
13 |
+
),
|
14 |
+
'P' =>
|
15 |
+
array (
|
16 |
+
'Psr\\Log\\' => 8,
|
17 |
+
),
|
18 |
+
);
|
19 |
+
|
20 |
+
public static $prefixDirsPsr4 = array (
|
21 |
+
'WPStaging\\Test\\' =>
|
22 |
+
array (
|
23 |
+
0 => __DIR__ . '/../..' . '/../tests/unit',
|
24 |
+
),
|
25 |
+
'WPStaging\\' =>
|
26 |
+
array (
|
27 |
+
0 => __DIR__ . '/../..' . '/',
|
28 |
+
),
|
29 |
+
'Psr\\Log\\' =>
|
30 |
+
array (
|
31 |
+
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
|
32 |
+
),
|
33 |
+
);
|
34 |
+
|
35 |
+
public static function getInitializer(ClassLoader $loader)
|
36 |
+
{
|
37 |
+
return \Closure::bind(function () use ($loader) {
|
38 |
+
$loader->prefixLengthsPsr4 = ComposerStaticInitc2c8fce0bd7d21d1b2bc76515b028e91::$prefixLengthsPsr4;
|
39 |
+
$loader->prefixDirsPsr4 = ComposerStaticInitc2c8fce0bd7d21d1b2bc76515b028e91::$prefixDirsPsr4;
|
40 |
+
|
41 |
+
}, null, ClassLoader::class);
|
42 |
+
}
|
43 |
+
}
|
vendor/composer/installed.json
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
{
|
3 |
+
"name": "psr/log",
|
4 |
+
"version": "1.1.2",
|
5 |
+
"version_normalized": "1.1.2.0",
|
6 |
+
"source": {
|
7 |
+
"type": "git",
|
8 |
+
"url": "https://github.com/php-fig/log.git",
|
9 |
+
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
|
10 |
+
},
|
11 |
+
"dist": {
|
12 |
+
"type": "zip",
|
13 |
+
"url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
|
14 |
+
"reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
|
15 |
+
"shasum": ""
|
16 |
+
},
|
17 |
+
"require": {
|
18 |
+
"php": ">=5.3.0"
|
19 |
+
},
|
20 |
+
"time": "2019-11-01T11:05:21+00:00",
|
21 |
+
"type": "library",
|
22 |
+
"extra": {
|
23 |
+
"branch-alias": {
|
24 |
+
"dev-master": "1.1.x-dev"
|
25 |
+
}
|
26 |
+
},
|
27 |
+
"installation-source": "dist",
|
28 |
+
"autoload": {
|
29 |
+
"psr-4": {
|
30 |
+
"Psr\\Log\\": "Psr/Log/"
|
31 |
+
}
|
32 |
+
},
|
33 |
+
"notification-url": "https://packagist.org/downloads/",
|
34 |
+
"license": [
|
35 |
+
"MIT"
|
36 |
+
],
|
37 |
+
"authors": [
|
38 |
+
{
|
39 |
+
"name": "PHP-FIG",
|
40 |
+
"homepage": "http://www.php-fig.org/"
|
41 |
+
}
|
42 |
+
],
|
43 |
+
"description": "Common interface for logging libraries",
|
44 |
+
"homepage": "https://github.com/php-fig/log",
|
45 |
+
"keywords": [
|
46 |
+
"log",
|
47 |
+
"psr",
|
48 |
+
"psr-3"
|
49 |
+
]
|
50 |
+
}
|
51 |
+
]
|
vendor/psr/log/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Copyright (c) 2012 PHP Framework Interoperability Group
|
2 |
+
|
3 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4 |
+
of this software and associated documentation files (the "Software"), to deal
|
5 |
+
in the Software without restriction, including without limitation the rights
|
6 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7 |
+
copies of the Software, and to permit persons to whom the Software is
|
8 |
+
furnished to do so, subject to the following conditions:
|
9 |
+
|
10 |
+
The above copyright notice and this permission notice shall be included in
|
11 |
+
all copies or substantial portions of the Software.
|
12 |
+
|
13 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19 |
+
THE SOFTWARE.
|
vendor/psr/log/Psr/Log/AbstractLogger.php
ADDED
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* This is a simple Logger implementation that other Loggers can inherit from.
|
7 |
+
*
|
8 |
+
* It simply delegates all log-level-specific methods to the `log` method to
|
9 |
+
* reduce boilerplate code that a simple Logger that does the same thing with
|
10 |
+
* messages regardless of the error level has to implement.
|
11 |
+
*/
|
12 |
+
abstract class AbstractLogger implements LoggerInterface
|
13 |
+
{
|
14 |
+
/**
|
15 |
+
* System is unusable.
|
16 |
+
*
|
17 |
+
* @param string $message
|
18 |
+
* @param array $context
|
19 |
+
*
|
20 |
+
* @return void
|
21 |
+
*/
|
22 |
+
public function emergency($message, array $context = array())
|
23 |
+
{
|
24 |
+
$this->log(LogLevel::EMERGENCY, $message, $context);
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Action must be taken immediately.
|
29 |
+
*
|
30 |
+
* Example: Entire website down, database unavailable, etc. This should
|
31 |
+
* trigger the SMS alerts and wake you up.
|
32 |
+
*
|
33 |
+
* @param string $message
|
34 |
+
* @param array $context
|
35 |
+
*
|
36 |
+
* @return void
|
37 |
+
*/
|
38 |
+
public function alert($message, array $context = array())
|
39 |
+
{
|
40 |
+
$this->log(LogLevel::ALERT, $message, $context);
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Critical conditions.
|
45 |
+
*
|
46 |
+
* Example: Application component unavailable, unexpected exception.
|
47 |
+
*
|
48 |
+
* @param string $message
|
49 |
+
* @param array $context
|
50 |
+
*
|
51 |
+
* @return void
|
52 |
+
*/
|
53 |
+
public function critical($message, array $context = array())
|
54 |
+
{
|
55 |
+
$this->log(LogLevel::CRITICAL, $message, $context);
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Runtime errors that do not require immediate action but should typically
|
60 |
+
* be logged and monitored.
|
61 |
+
*
|
62 |
+
* @param string $message
|
63 |
+
* @param array $context
|
64 |
+
*
|
65 |
+
* @return void
|
66 |
+
*/
|
67 |
+
public function error($message, array $context = array())
|
68 |
+
{
|
69 |
+
$this->log(LogLevel::ERROR, $message, $context);
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Exceptional occurrences that are not errors.
|
74 |
+
*
|
75 |
+
* Example: Use of deprecated APIs, poor use of an API, undesirable things
|
76 |
+
* that are not necessarily wrong.
|
77 |
+
*
|
78 |
+
* @param string $message
|
79 |
+
* @param array $context
|
80 |
+
*
|
81 |
+
* @return void
|
82 |
+
*/
|
83 |
+
public function warning($message, array $context = array())
|
84 |
+
{
|
85 |
+
$this->log(LogLevel::WARNING, $message, $context);
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Normal but significant events.
|
90 |
+
*
|
91 |
+
* @param string $message
|
92 |
+
* @param array $context
|
93 |
+
*
|
94 |
+
* @return void
|
95 |
+
*/
|
96 |
+
public function notice($message, array $context = array())
|
97 |
+
{
|
98 |
+
$this->log(LogLevel::NOTICE, $message, $context);
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Interesting events.
|
103 |
+
*
|
104 |
+
* Example: User logs in, SQL logs.
|
105 |
+
*
|
106 |
+
* @param string $message
|
107 |
+
* @param array $context
|
108 |
+
*
|
109 |
+
* @return void
|
110 |
+
*/
|
111 |
+
public function info($message, array $context = array())
|
112 |
+
{
|
113 |
+
$this->log(LogLevel::INFO, $message, $context);
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Detailed debug information.
|
118 |
+
*
|
119 |
+
* @param string $message
|
120 |
+
* @param array $context
|
121 |
+
*
|
122 |
+
* @return void
|
123 |
+
*/
|
124 |
+
public function debug($message, array $context = array())
|
125 |
+
{
|
126 |
+
$this->log(LogLevel::DEBUG, $message, $context);
|
127 |
+
}
|
128 |
+
}
|
vendor/psr/log/Psr/Log/InvalidArgumentException.php
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log;
|
4 |
+
|
5 |
+
class InvalidArgumentException extends \InvalidArgumentException
|
6 |
+
{
|
7 |
+
}
|
vendor/psr/log/Psr/Log/LogLevel.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Describes log levels.
|
7 |
+
*/
|
8 |
+
class LogLevel
|
9 |
+
{
|
10 |
+
const EMERGENCY = 'emergency';
|
11 |
+
const ALERT = 'alert';
|
12 |
+
const CRITICAL = 'critical';
|
13 |
+
const ERROR = 'error';
|
14 |
+
const WARNING = 'warning';
|
15 |
+
const NOTICE = 'notice';
|
16 |
+
const INFO = 'info';
|
17 |
+
const DEBUG = 'debug';
|
18 |
+
}
|
vendor/psr/log/Psr/Log/LoggerAwareInterface.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Describes a logger-aware instance.
|
7 |
+
*/
|
8 |
+
interface LoggerAwareInterface
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* Sets a logger instance on the object.
|
12 |
+
*
|
13 |
+
* @param LoggerInterface $logger
|
14 |
+
*
|
15 |
+
* @return void
|
16 |
+
*/
|
17 |
+
public function setLogger(LoggerInterface $logger);
|
18 |
+
}
|
vendor/psr/log/Psr/Log/LoggerAwareTrait.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Basic Implementation of LoggerAwareInterface.
|
7 |
+
*/
|
8 |
+
trait LoggerAwareTrait
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* The logger instance.
|
12 |
+
*
|
13 |
+
* @var LoggerInterface
|
14 |
+
*/
|
15 |
+
protected $logger;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Sets a logger.
|
19 |
+
*
|
20 |
+
* @param LoggerInterface $logger
|
21 |
+
*/
|
22 |
+
public function setLogger(LoggerInterface $logger)
|
23 |
+
{
|
24 |
+
$this->logger = $logger;
|
25 |
+
}
|
26 |
+
}
|
vendor/psr/log/Psr/Log/LoggerInterface.php
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Describes a logger instance.
|
7 |
+
*
|
8 |
+
* The message MUST be a string or object implementing __toString().
|
9 |
+
*
|
10 |
+
* The message MAY contain placeholders in the form: {foo} where foo
|
11 |
+
* will be replaced by the context data in key "foo".
|
12 |
+
*
|
13 |
+
* The context array can contain arbitrary data. The only assumption that
|
14 |
+
* can be made by implementors is that if an Exception instance is given
|
15 |
+
* to produce a stack trace, it MUST be in a key named "exception".
|
16 |
+
*
|
17 |
+
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
|
18 |
+
* for the full interface specification.
|
19 |
+
*/
|
20 |
+
interface LoggerInterface
|
21 |
+
{
|
22 |
+
/**
|
23 |
+
* System is unusable.
|
24 |
+
*
|
25 |
+
* @param string $message
|
26 |
+
* @param array $context
|
27 |
+
*
|
28 |
+
* @return void
|
29 |
+
*/
|
30 |
+
public function emergency($message, array $context = array());
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Action must be taken immediately.
|
34 |
+
*
|
35 |
+
* Example: Entire website down, database unavailable, etc. This should
|
36 |
+
* trigger the SMS alerts and wake you up.
|
37 |
+
*
|
38 |
+
* @param string $message
|
39 |
+
* @param array $context
|
40 |
+
*
|
41 |
+
* @return void
|
42 |
+
*/
|
43 |
+
public function alert($message, array $context = array());
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Critical conditions.
|
47 |
+
*
|
48 |
+
* Example: Application component unavailable, unexpected exception.
|
49 |
+
*
|
50 |
+
* @param string $message
|
51 |
+
* @param array $context
|
52 |
+
*
|
53 |
+
* @return void
|
54 |
+
*/
|
55 |
+
public function critical($message, array $context = array());
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Runtime errors that do not require immediate action but should typically
|
59 |
+
* be logged and monitored.
|
60 |
+
*
|
61 |
+
* @param string $message
|
62 |
+
* @param array $context
|
63 |
+
*
|
64 |
+
* @return void
|
65 |
+
*/
|
66 |
+
public function error($message, array $context = array());
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Exceptional occurrences that are not errors.
|
70 |
+
*
|
71 |
+
* Example: Use of deprecated APIs, poor use of an API, undesirable things
|
72 |
+
* that are not necessarily wrong.
|
73 |
+
*
|
74 |
+
* @param string $message
|
75 |
+
* @param array $context
|
76 |
+
*
|
77 |
+
* @return void
|
78 |
+
*/
|
79 |
+
public function warning($message, array $context = array());
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Normal but significant events.
|
83 |
+
*
|
84 |
+
* @param string $message
|
85 |
+
* @param array $context
|
86 |
+
*
|
87 |
+
* @return void
|
88 |
+
*/
|
89 |
+
public function notice($message, array $context = array());
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Interesting events.
|
93 |
+
*
|
94 |
+
* Example: User logs in, SQL logs.
|
95 |
+
*
|
96 |
+
* @param string $message
|
97 |
+
* @param array $context
|
98 |
+
*
|
99 |
+
* @return void
|
100 |
+
*/
|
101 |
+
public function info($message, array $context = array());
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Detailed debug information.
|
105 |
+
*
|
106 |
+
* @param string $message
|
107 |
+
* @param array $context
|
108 |
+
*
|
109 |
+
* @return void
|
110 |
+
*/
|
111 |
+
public function debug($message, array $context = array());
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Logs with an arbitrary level.
|
115 |
+
*
|
116 |
+
* @param mixed $level
|
117 |
+
* @param string $message
|
118 |
+
* @param array $context
|
119 |
+
*
|
120 |
+
* @return void
|
121 |
+
*
|
122 |
+
* @throws \Psr\Log\InvalidArgumentException
|
123 |
+
*/
|
124 |
+
public function log($level, $message, array $context = array());
|
125 |
+
}
|
vendor/psr/log/Psr/Log/LoggerTrait.php
ADDED
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* This is a simple Logger trait that classes unable to extend AbstractLogger
|
7 |
+
* (because they extend another class, etc) can include.
|
8 |
+
*
|
9 |
+
* It simply delegates all log-level-specific methods to the `log` method to
|
10 |
+
* reduce boilerplate code that a simple Logger that does the same thing with
|
11 |
+
* messages regardless of the error level has to implement.
|
12 |
+
*/
|
13 |
+
trait LoggerTrait
|
14 |
+
{
|
15 |
+
/**
|
16 |
+
* System is unusable.
|
17 |
+
*
|
18 |
+
* @param string $message
|
19 |
+
* @param array $context
|
20 |
+
*
|
21 |
+
* @return void
|
22 |
+
*/
|
23 |
+
public function emergency($message, array $context = array())
|
24 |
+
{
|
25 |
+
$this->log(LogLevel::EMERGENCY, $message, $context);
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Action must be taken immediately.
|
30 |
+
*
|
31 |
+
* Example: Entire website down, database unavailable, etc. This should
|
32 |
+
* trigger the SMS alerts and wake you up.
|
33 |
+
*
|
34 |
+
* @param string $message
|
35 |
+
* @param array $context
|
36 |
+
*
|
37 |
+
* @return void
|
38 |
+
*/
|
39 |
+
public function alert($message, array $context = array())
|
40 |
+
{
|
41 |
+
$this->log(LogLevel::ALERT, $message, $context);
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Critical conditions.
|
46 |
+
*
|
47 |
+
* Example: Application component unavailable, unexpected exception.
|
48 |
+
*
|
49 |
+
* @param string $message
|
50 |
+
* @param array $context
|
51 |
+
*
|
52 |
+
* @return void
|
53 |
+
*/
|
54 |
+
public function critical($message, array $context = array())
|
55 |
+
{
|
56 |
+
$this->log(LogLevel::CRITICAL, $message, $context);
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Runtime errors that do not require immediate action but should typically
|
61 |
+
* be logged and monitored.
|
62 |
+
*
|
63 |
+
* @param string $message
|
64 |
+
* @param array $context
|
65 |
+
*
|
66 |
+
* @return void
|
67 |
+
*/
|
68 |
+
public function error($message, array $context = array())
|
69 |
+
{
|
70 |
+
$this->log(LogLevel::ERROR, $message, $context);
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Exceptional occurrences that are not errors.
|
75 |
+
*
|
76 |
+
* Example: Use of deprecated APIs, poor use of an API, undesirable things
|
77 |
+
* that are not necessarily wrong.
|
78 |
+
*
|
79 |
+
* @param string $message
|
80 |
+
* @param array $context
|
81 |
+
*
|
82 |
+
* @return void
|
83 |
+
*/
|
84 |
+
public function warning($message, array $context = array())
|
85 |
+
{
|
86 |
+
$this->log(LogLevel::WARNING, $message, $context);
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Normal but significant events.
|
91 |
+
*
|
92 |
+
* @param string $message
|
93 |
+
* @param array $context
|
94 |
+
*
|
95 |
+
* @return void
|
96 |
+
*/
|
97 |
+
public function notice($message, array $context = array())
|
98 |
+
{
|
99 |
+
$this->log(LogLevel::NOTICE, $message, $context);
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Interesting events.
|
104 |
+
*
|
105 |
+
* Example: User logs in, SQL logs.
|
106 |
+
*
|
107 |
+
* @param string $message
|
108 |
+
* @param array $context
|
109 |
+
*
|
110 |
+
* @return void
|
111 |
+
*/
|
112 |
+
public function info($message, array $context = array())
|
113 |
+
{
|
114 |
+
$this->log(LogLevel::INFO, $message, $context);
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Detailed debug information.
|
119 |
+
*
|
120 |
+
* @param string $message
|
121 |
+
* @param array $context
|
122 |
+
*
|
123 |
+
* @return void
|
124 |
+
*/
|
125 |
+
public function debug($message, array $context = array())
|
126 |
+
{
|
127 |
+
$this->log(LogLevel::DEBUG, $message, $context);
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Logs with an arbitrary level.
|
132 |
+
*
|
133 |
+
* @param mixed $level
|
134 |
+
* @param string $message
|
135 |
+
* @param array $context
|
136 |
+
*
|
137 |
+
* @return void
|
138 |
+
*
|
139 |
+
* @throws \Psr\Log\InvalidArgumentException
|
140 |
+
*/
|
141 |
+
abstract public function log($level, $message, array $context = array());
|
142 |
+
}
|
vendor/psr/log/Psr/Log/NullLogger.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* This Logger can be used to avoid conditional log calls.
|
7 |
+
*
|
8 |
+
* Logging should always be optional, and if no logger is provided to your
|
9 |
+
* library creating a NullLogger instance to have something to throw logs at
|
10 |
+
* is a good way to avoid littering your code with `if ($this->logger) { }`
|
11 |
+
* blocks.
|
12 |
+
*/
|
13 |
+
class NullLogger extends AbstractLogger
|
14 |
+
{
|
15 |
+
/**
|
16 |
+
* Logs with an arbitrary level.
|
17 |
+
*
|
18 |
+
* @param mixed $level
|
19 |
+
* @param string $message
|
20 |
+
* @param array $context
|
21 |
+
*
|
22 |
+
* @return void
|
23 |
+
*
|
24 |
+
* @throws \Psr\Log\InvalidArgumentException
|
25 |
+
*/
|
26 |
+
public function log($level, $message, array $context = array())
|
27 |
+
{
|
28 |
+
// noop
|
29 |
+
}
|
30 |
+
}
|
vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log\Test;
|
4 |
+
|
5 |
+
use Psr\Log\LoggerInterface;
|
6 |
+
use Psr\Log\LogLevel;
|
7 |
+
use PHPUnit\Framework\TestCase;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Provides a base test class for ensuring compliance with the LoggerInterface.
|
11 |
+
*
|
12 |
+
* Implementors can extend the class and implement abstract methods to run this
|
13 |
+
* as part of their test suite.
|
14 |
+
*/
|
15 |
+
abstract class LoggerInterfaceTest extends TestCase
|
16 |
+
{
|
17 |
+
/**
|
18 |
+
* @return LoggerInterface
|
19 |
+
*/
|
20 |
+
abstract public function getLogger();
|
21 |
+
|
22 |
+
/**
|
23 |
+
* This must return the log messages in order.
|
24 |
+
*
|
25 |
+
* The simple formatting of the messages is: "<LOG LEVEL> <MESSAGE>".
|
26 |
+
*
|
27 |
+
* Example ->error('Foo') would yield "error Foo".
|
28 |
+
*
|
29 |
+
* @return string[]
|
30 |
+
*/
|
31 |
+
abstract public function getLogs();
|
32 |
+
|
33 |
+
public function testImplements()
|
34 |
+
{
|
35 |
+
$this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger());
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @dataProvider provideLevelsAndMessages
|
40 |
+
*/
|
41 |
+
public function testLogsAtAllLevels($level, $message)
|
42 |
+
{
|
43 |
+
$logger = $this->getLogger();
|
44 |
+
$logger->{$level}($message, array('user' => 'Bob'));
|
45 |
+
$logger->log($level, $message, array('user' => 'Bob'));
|
46 |
+
|
47 |
+
$expected = array(
|
48 |
+
$level.' message of level '.$level.' with context: Bob',
|
49 |
+
$level.' message of level '.$level.' with context: Bob',
|
50 |
+
);
|
51 |
+
$this->assertEquals($expected, $this->getLogs());
|
52 |
+
}
|
53 |
+
|
54 |
+
public function provideLevelsAndMessages()
|
55 |
+
{
|
56 |
+
return array(
|
57 |
+
LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'),
|
58 |
+
LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'),
|
59 |
+
LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'),
|
60 |
+
LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'),
|
61 |
+
LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'),
|
62 |
+
LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'),
|
63 |
+
LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'),
|
64 |
+
LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'),
|
65 |
+
);
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @expectedException \Psr\Log\InvalidArgumentException
|
70 |
+
*/
|
71 |
+
public function testThrowsOnInvalidLevel()
|
72 |
+
{
|
73 |
+
$logger = $this->getLogger();
|
74 |
+
$logger->log('invalid level', 'Foo');
|
75 |
+
}
|
76 |
+
|
77 |
+
public function testContextReplacement()
|
78 |
+
{
|
79 |
+
$logger = $this->getLogger();
|
80 |
+
$logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar'));
|
81 |
+
|
82 |
+
$expected = array('info {Message {nothing} Bob Bar a}');
|
83 |
+
$this->assertEquals($expected, $this->getLogs());
|
84 |
+
}
|
85 |
+
|
86 |
+
public function testObjectCastToString()
|
87 |
+
{
|
88 |
+
if (method_exists($this, 'createPartialMock')) {
|
89 |
+
$dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString'));
|
90 |
+
} else {
|
91 |
+
$dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString'));
|
92 |
+
}
|
93 |
+
$dummy->expects($this->once())
|
94 |
+
->method('__toString')
|
95 |
+
->will($this->returnValue('DUMMY'));
|
96 |
+
|
97 |
+
$this->getLogger()->warning($dummy);
|
98 |
+
|
99 |
+
$expected = array('warning DUMMY');
|
100 |
+
$this->assertEquals($expected, $this->getLogs());
|
101 |
+
}
|
102 |
+
|
103 |
+
public function testContextCanContainAnything()
|
104 |
+
{
|
105 |
+
$closed = fopen('php://memory', 'r');
|
106 |
+
fclose($closed);
|
107 |
+
|
108 |
+
$context = array(
|
109 |
+
'bool' => true,
|
110 |
+
'null' => null,
|
111 |
+
'string' => 'Foo',
|
112 |
+
'int' => 0,
|
113 |
+
'float' => 0.5,
|
114 |
+
'nested' => array('with object' => new DummyTest),
|
115 |
+
'object' => new \DateTime,
|
116 |
+
'resource' => fopen('php://memory', 'r'),
|
117 |
+
'closed' => $closed,
|
118 |
+
);
|
119 |
+
|
120 |
+
$this->getLogger()->warning('Crazy context data', $context);
|
121 |
+
|
122 |
+
$expected = array('warning Crazy context data');
|
123 |
+
$this->assertEquals($expected, $this->getLogs());
|
124 |
+
}
|
125 |
+
|
126 |
+
public function testContextExceptionKeyCanBeExceptionOrOtherValues()
|
127 |
+
{
|
128 |
+
$logger = $this->getLogger();
|
129 |
+
$logger->warning('Random message', array('exception' => 'oops'));
|
130 |
+
$logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail')));
|
131 |
+
|
132 |
+
$expected = array(
|
133 |
+
'warning Random message',
|
134 |
+
'critical Uncaught Exception!'
|
135 |
+
);
|
136 |
+
$this->assertEquals($expected, $this->getLogs());
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
class DummyTest
|
141 |
+
{
|
142 |
+
public function __toString()
|
143 |
+
{
|
144 |
+
return 'DummyTest';
|
145 |
+
}
|
146 |
+
}
|
vendor/psr/log/Psr/Log/Test/TestLogger.php
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Psr\Log\Test;
|
4 |
+
|
5 |
+
use Psr\Log\AbstractLogger;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Used for testing purposes.
|
9 |
+
*
|
10 |
+
* It records all records and gives you access to them for verification.
|
11 |
+
*
|
12 |
+
* @method bool hasEmergency($record)
|
13 |
+
* @method bool hasAlert($record)
|
14 |
+
* @method bool hasCritical($record)
|
15 |
+
* @method bool hasError($record)
|
16 |
+
* @method bool hasWarning($record)
|
17 |
+
* @method bool hasNotice($record)
|
18 |
+
* @method bool hasInfo($record)
|
19 |
+
* @method bool hasDebug($record)
|
20 |
+
*
|
21 |
+
* @method bool hasEmergencyRecords()
|
22 |
+
* @method bool hasAlertRecords()
|
23 |
+
* @method bool hasCriticalRecords()
|
24 |
+
* @method bool hasErrorRecords()
|
25 |
+
* @method bool hasWarningRecords()
|
26 |
+
* @method bool hasNoticeRecords()
|
27 |
+
* @method bool hasInfoRecords()
|
28 |
+
* @method bool hasDebugRecords()
|
29 |
+
*
|
30 |
+
* @method bool hasEmergencyThatContains($message)
|
31 |
+
* @method bool hasAlertThatContains($message)
|
32 |
+
* @method bool hasCriticalThatContains($message)
|
33 |
+
* @method bool hasErrorThatContains($message)
|
34 |
+
* @method bool hasWarningThatContains($message)
|
35 |
+
* @method bool hasNoticeThatContains($message)
|
36 |
+
* @method bool hasInfoThatContains($message)
|
37 |
+
* @method bool hasDebugThatContains($message)
|
38 |
+
*
|
39 |
+
* @method bool hasEmergencyThatMatches($message)
|
40 |
+
* @method bool hasAlertThatMatches($message)
|
41 |
+
* @method bool hasCriticalThatMatches($message)
|
42 |
+
* @method bool hasErrorThatMatches($message)
|
43 |
+
* @method bool hasWarningThatMatches($message)
|
44 |
+
* @method bool hasNoticeThatMatches($message)
|
45 |
+
* @method bool hasInfoThatMatches($message)
|
46 |
+
* @method bool hasDebugThatMatches($message)
|
47 |
+
*
|
48 |
+
* @method bool hasEmergencyThatPasses($message)
|
49 |
+
* @method bool hasAlertThatPasses($message)
|
50 |
+
* @method bool hasCriticalThatPasses($message)
|
51 |
+
* @method bool hasErrorThatPasses($message)
|
52 |
+
* @method bool hasWarningThatPasses($message)
|
53 |
+
* @method bool hasNoticeThatPasses($message)
|
54 |
+
* @method bool hasInfoThatPasses($message)
|
55 |
+
* @method bool hasDebugThatPasses($message)
|
56 |
+
*/
|
57 |
+
class TestLogger extends AbstractLogger
|
58 |
+
{
|
59 |
+
/**
|
60 |
+
* @var array
|
61 |
+
*/
|
62 |
+
public $records = [];
|
63 |
+
|
64 |
+
public $recordsByLevel = [];
|
65 |
+
|
66 |
+
/**
|
67 |
+
* @inheritdoc
|
68 |
+
*/
|
69 |
+
public function log($level, $message, array $context = [])
|
70 |
+
{
|
71 |
+
$record = [
|
72 |
+
'level' => $level,
|
73 |
+
'message' => $message,
|
74 |
+
'context' => $context,
|
75 |
+
];
|
76 |
+
|
77 |
+
$this->recordsByLevel[$record['level']][] = $record;
|
78 |
+
$this->records[] = $record;
|
79 |
+
}
|
80 |
+
|
81 |
+
public function hasRecords($level)
|
82 |
+
{
|
83 |
+
return isset($this->recordsByLevel[$level]);
|
84 |
+
}
|
85 |
+
|
86 |
+
public function hasRecord($record, $level)
|
87 |
+
{
|
88 |
+
if (is_string($record)) {
|
89 |
+
$record = ['message' => $record];
|
90 |
+
}
|
91 |
+
return $this->hasRecordThatPasses(function ($rec) use ($record) {
|
92 |
+
if ($rec['message'] !== $record['message']) {
|
93 |
+
return false;
|
94 |
+
}
|
95 |
+
if (isset($record['context']) && $rec['context'] !== $record['context']) {
|
96 |
+
return false;
|
97 |
+
}
|
98 |
+
return true;
|
99 |
+
}, $level);
|
100 |
+
}
|
101 |
+
|
102 |
+
public function hasRecordThatContains($message, $level)
|
103 |
+
{
|
104 |
+
return $this->hasRecordThatPasses(function ($rec) use ($message) {
|
105 |
+
return strpos($rec['message'], $message) !== false;
|
106 |
+
}, $level);
|
107 |
+
}
|
108 |
+
|
109 |
+
public function hasRecordThatMatches($regex, $level)
|
110 |
+
{
|
111 |
+
return $this->hasRecordThatPasses(function ($rec) use ($regex) {
|
112 |
+
return preg_match($regex, $rec['message']) > 0;
|
113 |
+
}, $level);
|
114 |
+
}
|
115 |
+
|
116 |
+
public function hasRecordThatPasses(callable $predicate, $level)
|
117 |
+
{
|
118 |
+
if (!isset($this->recordsByLevel[$level])) {
|
119 |
+
return false;
|
120 |
+
}
|
121 |
+
foreach ($this->recordsByLevel[$level] as $i => $rec) {
|
122 |
+
if (call_user_func($predicate, $rec, $i)) {
|
123 |
+
return true;
|
124 |
+
}
|
125 |
+
}
|
126 |
+
return false;
|
127 |
+
}
|
128 |
+
|
129 |
+
public function __call($method, $args)
|
130 |
+
{
|
131 |
+
if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
|
132 |
+
$genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
|
133 |
+
$level = strtolower($matches[2]);
|
134 |
+
if (method_exists($this, $genericMethod)) {
|
135 |
+
$args[] = $level;
|
136 |
+
return call_user_func_array([$this, $genericMethod], $args);
|
137 |
+
}
|
138 |
+
}
|
139 |
+
throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()');
|
140 |
+
}
|
141 |
+
|
142 |
+
public function reset()
|
143 |
+
{
|
144 |
+
$this->records = [];
|
145 |
+
$this->recordsByLevel = [];
|
146 |
+
}
|
147 |
+
}
|
vendor/psr/log/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
PSR Log
|
2 |
+
=======
|
3 |
+
|
4 |
+
This repository holds all interfaces/classes/traits related to
|
5 |
+
[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md).
|
6 |
+
|
7 |
+
Note that this is not a logger of its own. It is merely an interface that
|
8 |
+
describes a logger. See the specification for more details.
|
9 |
+
|
10 |
+
Installation
|
11 |
+
------------
|
12 |
+
|
13 |
+
```bash
|
14 |
+
composer require psr/log
|
15 |
+
```
|
16 |
+
|
17 |
+
Usage
|
18 |
+
-----
|
19 |
+
|
20 |
+
If you need a logger, you can use the interface like this:
|
21 |
+
|
22 |
+
```php
|
23 |
+
<?php
|
24 |
+
|
25 |
+
use Psr\Log\LoggerInterface;
|
26 |
+
|
27 |
+
class Foo
|
28 |
+
{
|
29 |
+
private $logger;
|
30 |
+
|
31 |
+
public function __construct(LoggerInterface $logger = null)
|
32 |
+
{
|
33 |
+
$this->logger = $logger;
|
34 |
+
}
|
35 |
+
|
36 |
+
public function doSomething()
|
37 |
+
{
|
38 |
+
if ($this->logger) {
|
39 |
+
$this->logger->info('Doing work');
|
40 |
+
}
|
41 |
+
|
42 |
+
try {
|
43 |
+
$this->doSomethingElse();
|
44 |
+
} catch (Exception $exception) {
|
45 |
+
$this->logger->error('Oh no!', array('exception' => $exception));
|
46 |
+
}
|
47 |
+
|
48 |
+
// do something useful
|
49 |
+
}
|
50 |
+
}
|
51 |
+
```
|
52 |
+
|
53 |
+
You can then pick one of the implementations of the interface to get a logger.
|
54 |
+
|
55 |
+
If you want to implement the interface, you can require this package and
|
56 |
+
implement `Psr\Log\LoggerInterface` in your code. Please read the
|
57 |
+
[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
|
58 |
+
for details.
|
vendor/psr/log/composer.json
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "psr/log",
|
3 |
+
"description": "Common interface for logging libraries",
|
4 |
+
"keywords": ["psr", "psr-3", "log"],
|
5 |
+
"homepage": "https://github.com/php-fig/log",
|
6 |
+
"license": "MIT",
|
7 |
+
"authors": [
|
8 |
+
{
|
9 |
+
"name": "PHP-FIG",
|
10 |
+
"homepage": "http://www.php-fig.org/"
|
11 |
+
}
|
12 |
+
],
|
13 |
+
"require": {
|
14 |
+
"php": ">=5.3.0"
|
15 |
+
},
|
16 |
+
"autoload": {
|
17 |
+
"psr-4": {
|
18 |
+
"Psr\\Log\\": "Psr/Log/"
|
19 |
+
}
|
20 |
+
},
|
21 |
+
"extra": {
|
22 |
+
"branch-alias": {
|
23 |
+
"dev-master": "1.1.x-dev"
|
24 |
+
}
|
25 |
+
}
|
26 |
+
}
|
wp-staging.php
CHANGED
@@ -7,7 +7,7 @@
|
|
7 |
* Author: WP-Staging
|
8 |
* Author URI: https://wp-staging.com
|
9 |
* Contributors: ReneHermi, ilgityildirim
|
10 |
-
* Version: 2.6.
|
11 |
* Text Domain: wp-staging
|
12 |
* Domain Path: /languages/
|
13 |
*
|
@@ -39,7 +39,7 @@ if (!defined('WPSTG_PLUGIN_SLUG')) {
|
|
39 |
|
40 |
// Plugin Version
|
41 |
if (!defined('WPSTG_VERSION')) {
|
42 |
-
define('WPSTG_VERSION', '2.6.
|
43 |
}
|
44 |
|
45 |
// Compatible up to WordPress Version
|
@@ -47,7 +47,7 @@ if (!defined('WPSTG_COMPATIBLE')) {
|
|
47 |
define('WPSTG_COMPATIBLE', '5.3.2');
|
48 |
}
|
49 |
|
50 |
-
//
|
51 |
if (!defined('WPSTG_PLUGIN_DIR')) {
|
52 |
define('WPSTG_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
53 |
}
|
@@ -118,6 +118,9 @@ $plugin_requirements = new Wpstg_Requirements_Check(array(
|
|
118 |
|
119 |
if ($plugin_requirements->passes()) {
|
120 |
|
|
|
|
|
|
|
121 |
$wpStaging = \WPStaging\WPStaging::getInstance();
|
122 |
|
123 |
/**
|
7 |
* Author: WP-Staging
|
8 |
* Author URI: https://wp-staging.com
|
9 |
* Contributors: ReneHermi, ilgityildirim
|
10 |
+
* Version: 2.6.9
|
11 |
* Text Domain: wp-staging
|
12 |
* Domain Path: /languages/
|
13 |
*
|
39 |
|
40 |
// Plugin Version
|
41 |
if (!defined('WPSTG_VERSION')) {
|
42 |
+
define('WPSTG_VERSION', '2.6.9');
|
43 |
}
|
44 |
|
45 |
// Compatible up to WordPress Version
|
47 |
define('WPSTG_COMPATIBLE', '5.3.2');
|
48 |
}
|
49 |
|
50 |
+
// Absolute path to plugin
|
51 |
if (!defined('WPSTG_PLUGIN_DIR')) {
|
52 |
define('WPSTG_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
53 |
}
|
118 |
|
119 |
if ($plugin_requirements->passes()) {
|
120 |
|
121 |
+
// TODO; remove previous auto-loader, use composer based instead!
|
122 |
+
require_once __DIR__ .'/vendor/autoload.php';
|
123 |
+
|
124 |
$wpStaging = \WPStaging\WPStaging::getInstance();
|
125 |
|
126 |
/**
|