Version Description
- New: Compatible up to WordPress 5.4.2
- Fix: Remove beta notice
- Fix: Error if views are cloned
- Fix: Fatal error if WordPress is older than 4.5
- Fix: Merge pro/free version
- Fix: Step switching logic does not work properly
- Fix: Fix progress bar when certains steps are skipped
- Fix: Change german translation for REPORT ISSUE
Download this release
Release Info
Developer | ReneHermi |
Plugin | WP Staging – DB & File Duplicator & Migration |
Version | 2.7.4 |
Comparing to | |
See all releases |
Code changes from version 2.7.3 to 2.7.4
- Backend/Administrator.php +302 -240
- Backend/Modules/Jobs/Cloning.php +49 -32
- Backend/Modules/Jobs/Data.php +43 -107
- Backend/Modules/Jobs/DataExternal.php +374 -449
- Backend/Modules/Jobs/Database.php +0 -8
- Backend/Modules/Jobs/DatabaseExternal.php +109 -147
- Backend/Modules/Jobs/Files.php +4 -0
- Backend/Modules/Jobs/Multisite/Data.php +51 -81
- Backend/Modules/Jobs/Multisite/DataExternal.php +126 -160
- Backend/Modules/Jobs/Multisite/Database.php +0 -63
- Backend/Modules/Jobs/Multisite/DatabaseExternal.php +133 -122
- Backend/Modules/Jobs/Multisite/Files.php +4 -0
- Backend/Modules/Jobs/PreserveDataFirstStep.php +125 -0
- Backend/Modules/Jobs/PreserveDataSecondStep.php +108 -0
- Backend/Modules/Jobs/Scan.php +37 -69
- Backend/Modules/Jobs/SearchReplace.php +2 -3
- Backend/Modules/Jobs/SearchReplaceExternal.php +1 -0
- Backend/Modules/SystemInfo.php +2 -1
- Backend/public/css/wpstg-admin.css +1 -1
- Backend/public/js/wpstg-admin.js +62 -10
- Backend/views/_main/report-issue.php +8 -5
- Backend/views/clone/ajax/scan.php +2 -3
- Backend/views/clone/ajax/single-overview.php +7 -1
- Backend/views/clone/single-site/index.php +4 -4
- Command/Database/Export/ExportCommand.php +86 -0
- Command/Database/Export/ExportDto.php +261 -0
- Command/Database/Export/ExportException.php +13 -0
- Command/Database/Export/ExportHandler.php +80 -0
- Command/Database/Snapshot/AbstractSnapshotCommand.php +73 -0
- Command/Database/Snapshot/CreateSnapshotCommand.php +101 -0
- Command/Database/Snapshot/DeleteSnapshotCommand.php +48 -0
- Command/Database/Snapshot/SnapshotCommandException.php +8 -0
- Command/Database/Snapshot/SnapshotDto.php +126 -0
- Command/Database/Snapshot/SnapshotHandler.php +48 -0
- Command/Database/Snapshot/UpdateSnapshotCommand.php +55 -0
- Command/Database/SnapshotFactory.php +77 -0
- Core/Utils/Report.php +75 -75
- Core/Utils/functions.php +3 -3
- Core/WPStaging.php +52 -51
- Service/Adapter/SourceDatabase.php +55 -0
- Service/Permalinks/PermalinksPurge.php +23 -0
- Service/Utils/FileSystem.php +4 -0
- Service/Utils/Strings.php +26 -0
- languages/wp-staging-de_DE.po +3 -3
- readme.txt +18 -2
- vendor/autoload.php +1 -1
- vendor/composer/autoload_real.php +4 -4
- vendor/composer/autoload_static.php +3 -3
- wp-staging.php +1 -1
Backend/Administrator.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
namespace WPStaging\Backend;
|
4 |
|
5 |
// No Direct Access
|
6 |
-
if(
|
7 |
die;
|
8 |
}
|
9 |
|
@@ -30,7 +30,8 @@ use WPStaging\Backend\Pro\Modules\Jobs\Processing;
|
|
30 |
* Class Administrator
|
31 |
* @package WPStaging\Backend
|
32 |
*/
|
33 |
-
class Administrator extends InjectionAware
|
|
|
34 |
|
35 |
/**
|
36 |
* @var string
|
@@ -42,17 +43,27 @@ class Administrator extends InjectionAware {
|
|
42 |
*/
|
43 |
private $url;
|
44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
/**
|
46 |
* Initialize class
|
47 |
*/
|
48 |
-
public function initialize()
|
|
|
49 |
$this->defineHooks();
|
50 |
|
51 |
// Path to backend
|
52 |
-
$this->path = plugin_dir_path(
|
53 |
|
54 |
// URL to public backend folder
|
55 |
-
$this->url = plugin_dir_url(
|
56 |
|
57 |
// Load plugins meta data
|
58 |
$this->loadMeta();
|
@@ -61,72 +72,75 @@ class Administrator extends InjectionAware {
|
|
61 |
/**
|
62 |
* Load plugn meta data
|
63 |
*/
|
64 |
-
public function loadMeta()
|
|
|
65 |
$run = new \WPStaging\Backend\Pluginmeta\Pluginmeta();
|
66 |
}
|
67 |
|
68 |
/**
|
69 |
* Define Hooks
|
70 |
*/
|
71 |
-
private function defineHooks()
|
|
|
72 |
// Get loader
|
73 |
-
$loader = $this->di->get(
|
74 |
|
75 |
$Activation = new \WPStaging\Backend\Activation\Activation();
|
76 |
|
77 |
-
if(!defined('WPSTGPRO_VERSION')) {
|
78 |
$Welcome = new Activation\Welcome();
|
79 |
}
|
80 |
|
81 |
-
$loader->addAction(
|
82 |
-
$loader->addAction(
|
83 |
-
$loader->addAction(
|
84 |
-
$loader->addAction(
|
85 |
-
$loader->addAction(
|
86 |
-
$loader->addAction(
|
87 |
-
$loader->addAction(
|
88 |
-
$loader->addAction(
|
89 |
|
90 |
-
if(!defined('WPSTGPRO_VERSION')){
|
91 |
-
add_filter(
|
92 |
}
|
93 |
|
94 |
// Ajax Requests
|
95 |
-
$loader->addAction(
|
96 |
-
$loader->addAction(
|
97 |
-
$loader->addAction(
|
98 |
-
$loader->addAction(
|
99 |
-
$loader->addAction(
|
100 |
-
$loader->addAction(
|
101 |
-
$loader->addAction(
|
102 |
-
$loader->addAction(
|
103 |
-
$loader->addAction(
|
104 |
-
$loader->addAction(
|
105 |
-
$loader->addAction(
|
106 |
-
$loader->addAction(
|
107 |
-
$loader->addAction(
|
108 |
-
$loader->addAction(
|
109 |
-
$loader->addAction(
|
110 |
-
$loader->addAction(
|
111 |
-
$loader->addAction(
|
112 |
-
$loader->addAction(
|
113 |
-
$loader->addAction(
|
114 |
-
$loader->addAction(
|
115 |
-
$loader->addAction(
|
116 |
-
$loader->addAction(
|
117 |
-
$loader->addAction(
|
118 |
-
$loader->addAction(
|
119 |
|
120 |
|
121 |
// Ajax hooks pro Version
|
122 |
-
$loader->addAction(
|
123 |
-
$loader->addAction(
|
124 |
}
|
125 |
|
126 |
/**
|
127 |
* Load Feedback Form on plugins.php
|
128 |
*/
|
129 |
-
public function loadFeedbackForm()
|
|
|
130 |
$form = new Feedback\Feedback();
|
131 |
$load = $form->loadForm();
|
132 |
}
|
@@ -134,7 +148,8 @@ class Administrator extends InjectionAware {
|
|
134 |
/**
|
135 |
* Send Feedback form via mail
|
136 |
*/
|
137 |
-
public function sendFeedback()
|
|
|
138 |
$form = new Feedback\Feedback();
|
139 |
$send = $form->sendMail();
|
140 |
}
|
@@ -142,8 +157,9 @@ class Administrator extends InjectionAware {
|
|
142 |
/**
|
143 |
* Register options form elements
|
144 |
*/
|
145 |
-
public function setOptionFormElements()
|
146 |
-
|
|
|
147 |
}
|
148 |
|
149 |
/**
|
@@ -164,23 +180,32 @@ class Administrator extends InjectionAware {
|
|
164 |
* @param array $data
|
165 |
* @return array
|
166 |
*/
|
167 |
-
public function sanitizeOptions(
|
168 |
-
|
|
|
169 |
|
170 |
-
add_settings_error(
|
171 |
|
172 |
-
return apply_filters(
|
173 |
}
|
174 |
|
175 |
/**
|
176 |
* @param array $data
|
177 |
* @return array
|
178 |
*/
|
179 |
-
private function sanitizeData(
|
|
|
180 |
$sanitized = array();
|
181 |
|
182 |
-
foreach (
|
183 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
184 |
}
|
185 |
|
186 |
return $sanitized;
|
@@ -238,18 +263,20 @@ class Administrator extends InjectionAware {
|
|
238 |
/**
|
239 |
* Settings Page
|
240 |
*/
|
241 |
-
public function getSettingsPage()
|
|
|
242 |
// Tabs
|
243 |
-
$tabs = new Tabs(
|
244 |
-
"general" => __(
|
245 |
-
|
246 |
|
247 |
|
248 |
$this->di
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
|
|
253 |
|
254 |
|
255 |
require_once "{$this->path}views/settings/main-settings.php";
|
@@ -258,9 +285,10 @@ class Administrator extends InjectionAware {
|
|
258 |
/**
|
259 |
* Clone Page
|
260 |
*/
|
261 |
-
public function getClonePage()
|
|
|
262 |
// Existing clones
|
263 |
-
$availableClones = get_option(
|
264 |
|
265 |
require_once "{$this->path}views/clone/index.php";
|
266 |
}
|
@@ -268,9 +296,9 @@ class Administrator extends InjectionAware {
|
|
268 |
/**
|
269 |
* Welcome Page
|
270 |
*/
|
271 |
-
public function getWelcomePage()
|
272 |
-
|
273 |
-
{
|
274 |
return;
|
275 |
}
|
276 |
require_once "{$this->path}views/welcome/welcome.php";
|
@@ -279,16 +307,17 @@ class Administrator extends InjectionAware {
|
|
279 |
/**
|
280 |
* Tools Page
|
281 |
*/
|
282 |
-
public function getToolsPage()
|
|
|
283 |
// Tabs
|
284 |
-
$tabs = new Tabs(
|
285 |
-
"import_export" => __(
|
286 |
-
"system_info"
|
287 |
-
|
288 |
|
289 |
-
$this->di->set(
|
290 |
|
291 |
-
$this->di->set(
|
292 |
|
293 |
require_once "{$this->path}views/tools/index.php";
|
294 |
}
|
@@ -296,49 +325,51 @@ class Administrator extends InjectionAware {
|
|
296 |
/**
|
297 |
* System Information Download
|
298 |
*/
|
299 |
-
public function systemInfoDownload()
|
300 |
-
|
|
|
301 |
return;
|
302 |
}
|
303 |
|
304 |
nocache_headers();
|
305 |
-
header(
|
306 |
-
header(
|
307 |
-
echo wp_strip_all_tags(
|
308 |
}
|
309 |
|
310 |
/**
|
311 |
* Import JSON settings file
|
312 |
*/
|
313 |
-
public function import()
|
314 |
-
|
|
|
315 |
return;
|
316 |
}
|
317 |
|
318 |
-
if(
|
319 |
return;
|
320 |
}
|
321 |
|
322 |
-
if(
|
323 |
return;
|
324 |
}
|
325 |
|
326 |
-
$fileExtension = explode(
|
327 |
-
$fileExtension = end(
|
328 |
-
if(
|
329 |
-
wp_die(
|
330 |
}
|
331 |
|
332 |
|
333 |
$importFile = $_FILES["import_file"]["tmp_name"];
|
334 |
|
335 |
-
if(
|
336 |
-
wp_die(
|
337 |
}
|
338 |
|
339 |
-
update_option(
|
340 |
|
341 |
-
wp_safe_redirect(
|
342 |
|
343 |
return;
|
344 |
}
|
@@ -346,35 +377,36 @@ class Administrator extends InjectionAware {
|
|
346 |
/**
|
347 |
* Export settings to JSON file
|
348 |
*/
|
349 |
-
public function export()
|
350 |
-
|
|
|
351 |
return;
|
352 |
}
|
353 |
|
354 |
-
if(
|
355 |
return;
|
356 |
}
|
357 |
|
358 |
-
if(
|
359 |
return;
|
360 |
}
|
361 |
|
362 |
-
$settings = get_option(
|
363 |
|
364 |
-
ignore_user_abort(
|
365 |
|
366 |
-
if(
|
367 |
-
set_time_limit(
|
368 |
}
|
369 |
|
370 |
-
$fileName = apply_filters(
|
371 |
|
372 |
nocache_headers();
|
373 |
-
header(
|
374 |
-
header(
|
375 |
-
header(
|
376 |
|
377 |
-
echo json_encode(
|
378 |
}
|
379 |
|
380 |
/**
|
@@ -383,26 +415,27 @@ class Administrator extends InjectionAware {
|
|
383 |
* @param array $vars
|
384 |
* @return string
|
385 |
*/
|
386 |
-
public function render(
|
|
|
387 |
$fullPath = $this->path . "views" . DIRECTORY_SEPARATOR;
|
388 |
-
$fullPath = str_replace(
|
389 |
|
390 |
-
if(
|
391 |
return "Can't render : {$fullPath} either file doesn't exist or can't read it";
|
392 |
}
|
393 |
|
394 |
-
$contents = @file_get_contents(
|
395 |
|
396 |
// Variables are set
|
397 |
-
if(
|
398 |
$vars = array_combine(
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
);
|
404 |
|
405 |
-
$contents = str_replace(
|
406 |
}
|
407 |
|
408 |
return $contents;
|
@@ -411,8 +444,9 @@ class Administrator extends InjectionAware {
|
|
411 |
/**
|
412 |
* Restart cloning process
|
413 |
*/
|
414 |
-
public function ajaxRestart()
|
415 |
-
|
|
|
416 |
|
417 |
$process = new ProcessLock();
|
418 |
$process->restart();
|
@@ -421,19 +455,20 @@ class Administrator extends InjectionAware {
|
|
421 |
/**
|
422 |
* Ajax Overview
|
423 |
*/
|
424 |
-
public function ajaxOverview()
|
425 |
-
|
|
|
426 |
|
427 |
// Existing clones
|
428 |
-
$availableClones = get_option(
|
429 |
|
430 |
// Get license data
|
431 |
-
$license = get_option(
|
432 |
|
433 |
// Get db
|
434 |
-
$db = WPStaging::getInstance()->get(
|
435 |
|
436 |
-
if(
|
437 |
require_once "{$this->path}Pro/views/single-overview-pro.php";
|
438 |
} else {
|
439 |
require_once "{$this->path}views/clone/ajax/single-overview.php";
|
@@ -445,14 +480,15 @@ class Administrator extends InjectionAware {
|
|
445 |
/**
|
446 |
* Ajax Scan
|
447 |
*/
|
448 |
-
public function ajaxScan()
|
449 |
-
|
|
|
450 |
|
451 |
// Check first if there is already a process running
|
452 |
$processLock = new ProcessLock();
|
453 |
$processLock->isRunning();
|
454 |
|
455 |
-
$db = WPStaging::getInstance()->get(
|
456 |
|
457 |
// Scan
|
458 |
$scan = new Scan();
|
@@ -469,44 +505,46 @@ class Administrator extends InjectionAware {
|
|
469 |
/**
|
470 |
* Ajax Check Clone Name
|
471 |
*/
|
472 |
-
public function ajaxCheckCloneName()
|
473 |
-
|
474 |
-
$
|
475 |
-
$
|
|
|
476 |
|
477 |
-
$clonePath = trailingslashit(
|
478 |
|
479 |
// Check clone name length
|
480 |
-
if(
|
481 |
-
echo wp_send_json(
|
482 |
-
"status"
|
483 |
"message" => "Clone name must be between 1 - 16 characters"
|
484 |
-
)
|
485 |
-
} elseif(
|
486 |
-
echo wp_send_json(
|
487 |
-
"status"
|
488 |
"message" => "Clone name is already in use, please choose another clone name."
|
489 |
-
)
|
490 |
-
} elseif(
|
491 |
-
echo wp_send_json(
|
492 |
-
"status"
|
493 |
"message" => "Clone directory " . $clonePath . " already exists. Use another clone name."
|
494 |
-
)
|
495 |
}
|
496 |
|
497 |
-
echo wp_send_json(
|
498 |
}
|
499 |
|
500 |
/**
|
501 |
* Ajax Start Updating Clone (Basically just layout and saving data)
|
502 |
*/
|
503 |
-
public function ajaxUpdateProcess()
|
504 |
-
|
|
|
505 |
|
506 |
$cloning = new Updating();
|
507 |
|
508 |
-
if(
|
509 |
-
wp_die(
|
510 |
}
|
511 |
|
512 |
require_once "{$this->path}views/clone/ajax/update.php";
|
@@ -517,8 +555,9 @@ class Administrator extends InjectionAware {
|
|
517 |
/**
|
518 |
* Ajax Start Clone (Basically just layout and saving data)
|
519 |
*/
|
520 |
-
public function ajaxStartClone()
|
521 |
-
|
|
|
522 |
|
523 |
// Check first if there is already a process running
|
524 |
$processLock = new ProcessLock();
|
@@ -526,8 +565,8 @@ class Administrator extends InjectionAware {
|
|
526 |
|
527 |
$cloning = new Cloning();
|
528 |
|
529 |
-
if(
|
530 |
-
wp_die(
|
531 |
}
|
532 |
|
533 |
require_once "{$this->path}views/clone/ajax/start.php";
|
@@ -538,8 +577,9 @@ class Administrator extends InjectionAware {
|
|
538 |
/**
|
539 |
* Ajax Clone Database
|
540 |
*/
|
541 |
-
public function ajaxCloneDatabase()
|
542 |
-
|
|
|
543 |
|
544 |
$cloning = new Cloning();
|
545 |
|
@@ -547,58 +587,63 @@ class Administrator extends InjectionAware {
|
|
547 |
//http_response_code(504);
|
548 |
//wp_send_json( '<html><body><head></head><body>test</body></html>' );
|
549 |
|
550 |
-
wp_send_json(
|
551 |
}
|
552 |
|
553 |
/**
|
554 |
* Ajax Prepare Directories (get listing of files)
|
555 |
*/
|
556 |
-
public function ajaxPrepareDirectories()
|
557 |
-
|
|
|
558 |
|
559 |
$cloning = new Cloning();
|
560 |
|
561 |
-
wp_send_json(
|
562 |
}
|
563 |
|
564 |
/**
|
565 |
* Ajax Clone Files
|
566 |
*/
|
567 |
-
public function ajaxCopyFiles()
|
568 |
-
|
|
|
569 |
|
570 |
$cloning = new Cloning();
|
571 |
|
572 |
-
wp_send_json(
|
573 |
}
|
574 |
|
575 |
/**
|
576 |
* Ajax Replace Data
|
577 |
*/
|
578 |
-
public function ajaxReplaceData()
|
579 |
-
|
|
|
580 |
|
581 |
$cloning = new Cloning();
|
582 |
|
583 |
-
wp_send_json(
|
584 |
}
|
585 |
|
586 |
/**
|
587 |
* Ajax Finish
|
588 |
*/
|
589 |
-
public function ajaxFinish()
|
590 |
-
|
|
|
591 |
|
592 |
$cloning = new Cloning();
|
593 |
|
594 |
-
wp_send_json(
|
595 |
}
|
596 |
|
597 |
/**
|
598 |
* Ajax Delete Confirmation
|
599 |
*/
|
600 |
-
public function ajaxDeleteConfirmation()
|
601 |
-
|
|
|
602 |
|
603 |
$delete = new Delete();
|
604 |
$delete->setData();
|
@@ -615,40 +660,44 @@ class Administrator extends InjectionAware {
|
|
615 |
/**
|
616 |
* Delete clone
|
617 |
*/
|
618 |
-
public function ajaxDeleteClone()
|
619 |
-
|
|
|
620 |
|
621 |
$delete = new Delete();
|
622 |
|
623 |
-
wp_send_json(
|
624 |
}
|
625 |
|
626 |
/**
|
627 |
* Delete clone
|
628 |
*/
|
629 |
-
public function ajaxCancelClone()
|
630 |
-
|
|
|
631 |
|
632 |
$cancel = new Cancel();
|
633 |
|
634 |
-
wp_send_json(
|
635 |
}
|
636 |
|
637 |
/**
|
638 |
* Cancel updating process / Do not delete clone!
|
639 |
*/
|
640 |
-
public function ajaxCancelUpdate()
|
641 |
-
|
|
|
642 |
|
643 |
$cancel = new CancelUpdate();
|
644 |
-
wp_send_json(
|
645 |
}
|
646 |
|
647 |
/**
|
648 |
* Admin Messages
|
649 |
*/
|
650 |
-
public function messages()
|
651 |
-
|
|
|
652 |
|
653 |
$run = $notice->messages();
|
654 |
}
|
@@ -657,9 +706,10 @@ class Administrator extends InjectionAware {
|
|
657 |
* Ajax Hide Poll
|
658 |
* @return mixed boolean | json
|
659 |
*/
|
660 |
-
public function ajaxHidePoll()
|
661 |
-
|
662 |
-
|
|
|
663 |
}
|
664 |
return wp_send_json();
|
665 |
}
|
@@ -668,9 +718,10 @@ class Administrator extends InjectionAware {
|
|
668 |
* Ajax Hide Rating
|
669 |
* @return mixed bool | json
|
670 |
*/
|
671 |
-
public function ajaxHideRating()
|
672 |
-
|
673 |
-
|
|
|
674 |
}
|
675 |
return wp_send_json();
|
676 |
}
|
@@ -679,36 +730,40 @@ class Administrator extends InjectionAware {
|
|
679 |
* Ajax Hide Rating and show it again after one week
|
680 |
* @return mixed bool | json
|
681 |
*/
|
682 |
-
public function ajaxHideLaterRating()
|
683 |
-
|
684 |
-
|
685 |
-
|
|
|
686 |
}
|
687 |
-
return wp_send_json(
|
688 |
}
|
689 |
|
690 |
/**
|
691 |
* Ajax Hide Beta
|
692 |
*/
|
693 |
-
public function ajaxHideBeta()
|
694 |
-
|
|
|
695 |
}
|
696 |
|
697 |
/**
|
698 |
* Clone logs
|
699 |
*/
|
700 |
-
public function ajaxLogs()
|
701 |
-
|
|
|
702 |
|
703 |
$logs = new Logs();
|
704 |
-
wp_send_json(
|
705 |
}
|
706 |
|
707 |
/**
|
708 |
* Ajax Checks Free Disk Space
|
709 |
*/
|
710 |
-
public function ajaxCheckFreeSpace()
|
711 |
-
|
|
|
712 |
|
713 |
$scan = new Scan();
|
714 |
return $scan->hasFreeDiskSpace();
|
@@ -718,10 +773,11 @@ class Administrator extends InjectionAware {
|
|
718 |
* Ajax Start Push Changes Process
|
719 |
* Start with the module Scan
|
720 |
*/
|
721 |
-
public function ajaxPushScan()
|
722 |
-
|
|
|
723 |
|
724 |
-
if(
|
725 |
return false;
|
726 |
}
|
727 |
|
@@ -741,99 +797,105 @@ class Administrator extends InjectionAware {
|
|
741 |
/**
|
742 |
* Ajax Start Pushing. Needs WP Staging Pro
|
743 |
*/
|
744 |
-
public function ajaxPushProcessing()
|
745 |
-
|
|
|
746 |
|
747 |
-
if(
|
748 |
return false;
|
749 |
}
|
750 |
|
751 |
// Start the process
|
752 |
$processing = new Processing();
|
753 |
-
wp_send_json(
|
754 |
}
|
755 |
|
756 |
/**
|
757 |
* License Page
|
758 |
*/
|
759 |
-
public function getLicensePage()
|
|
|
760 |
|
761 |
// Get license data
|
762 |
-
$license = get_option(
|
763 |
|
764 |
require_once "{$this->path}Pro/views/licensing.php";
|
765 |
}
|
766 |
|
767 |
/**
|
768 |
* Send mail via ajax
|
769 |
-
* @param
|
770 |
*/
|
771 |
-
public function ajaxSendReport(
|
|
|
772 |
// Set params
|
773 |
-
if(
|
774 |
-
$args = stripslashes_deep(
|
775 |
}
|
776 |
// Set e-mail
|
777 |
$email = null;
|
778 |
-
if(
|
779 |
-
$email = trim(
|
|
|
|
|
|
|
|
|
|
|
|
|
780 |
}
|
781 |
|
782 |
// Set message
|
783 |
$message = null;
|
784 |
-
if(
|
785 |
-
$message = trim(
|
786 |
}
|
787 |
|
788 |
// Set syslog
|
789 |
$syslog = false;
|
790 |
-
if(
|
791 |
-
$syslog = ( bool )
|
792 |
}
|
793 |
|
794 |
// Set terms
|
795 |
$terms = false;
|
796 |
-
if(
|
797 |
-
$terms = ( bool )
|
798 |
}
|
799 |
|
800 |
-
$report = new Report(
|
801 |
-
$errors = $report->send(
|
802 |
|
803 |
-
echo json_encode(
|
804 |
exit;
|
805 |
}
|
806 |
|
807 |
/**
|
808 |
* Connect to external database for testing correct credentials
|
809 |
*/
|
810 |
-
public function ajaxDatabaseConnect()
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
$
|
817 |
-
$password = !empty( $args['databasePassword'] ) ? $args['databasePassword'] : '';
|
818 |
-
$database = !empty( $args['databaseDatabase'] ) ? $args['databaseDatabase'] : '';
|
819 |
-
$server = !empty( $args['databaseServer'] ) ? $args['databaseServer'] : 'localhost';
|
820 |
|
821 |
-
$db = new \wpdb(
|
822 |
|
823 |
// Can not connect to mysql
|
824 |
-
if(
|
825 |
-
echo json_encode(
|
826 |
exit;
|
827 |
}
|
828 |
|
829 |
// Can not connect to database
|
830 |
-
$db->select(
|
831 |
-
if(
|
832 |
$error = isset($db->error->errors['db_select_fail']) ? $db->error->errors['db_select_fail'] : "Error: Can't select {database} Either it does not exist or you don't have privileges to access it.";
|
833 |
-
echo json_encode(
|
834 |
exit;
|
835 |
}
|
836 |
-
echo json_encode(
|
837 |
exit;
|
838 |
}
|
839 |
|
3 |
namespace WPStaging\Backend;
|
4 |
|
5 |
// No Direct Access
|
6 |
+
if (!defined("WPINC")) {
|
7 |
die;
|
8 |
}
|
9 |
|
30 |
* Class Administrator
|
31 |
* @package WPStaging\Backend
|
32 |
*/
|
33 |
+
class Administrator extends InjectionAware
|
34 |
+
{
|
35 |
|
36 |
/**
|
37 |
* @var string
|
43 |
*/
|
44 |
private $url;
|
45 |
|
46 |
+
/**
|
47 |
+
* @var array
|
48 |
+
* All options here will only be stored in the database as integers. Decimal points and separators will be removed
|
49 |
+
*/
|
50 |
+
private static $integerOptions = [
|
51 |
+
'queryLimit',
|
52 |
+
'querySRLimit'
|
53 |
+
];
|
54 |
+
|
55 |
/**
|
56 |
* Initialize class
|
57 |
*/
|
58 |
+
public function initialize()
|
59 |
+
{
|
60 |
$this->defineHooks();
|
61 |
|
62 |
// Path to backend
|
63 |
+
$this->path = plugin_dir_path(__FILE__);
|
64 |
|
65 |
// URL to public backend folder
|
66 |
+
$this->url = plugin_dir_url(__FILE__) . "public/";
|
67 |
|
68 |
// Load plugins meta data
|
69 |
$this->loadMeta();
|
72 |
/**
|
73 |
* Load plugn meta data
|
74 |
*/
|
75 |
+
public function loadMeta()
|
76 |
+
{
|
77 |
$run = new \WPStaging\Backend\Pluginmeta\Pluginmeta();
|
78 |
}
|
79 |
|
80 |
/**
|
81 |
* Define Hooks
|
82 |
*/
|
83 |
+
private function defineHooks()
|
84 |
+
{
|
85 |
// Get loader
|
86 |
+
$loader = $this->di->get("loader");
|
87 |
|
88 |
$Activation = new \WPStaging\Backend\Activation\Activation();
|
89 |
|
90 |
+
if (!defined('WPSTGPRO_VERSION')) {
|
91 |
$Welcome = new Activation\Welcome();
|
92 |
}
|
93 |
|
94 |
+
$loader->addAction("activated_plugin", $Activation, 'deactivate_other_instances');
|
95 |
+
$loader->addAction("admin_menu", $this, "addMenu", 10);
|
96 |
+
$loader->addAction("admin_init", $this, "setOptionFormElements");
|
97 |
+
$loader->addAction("admin_init", $this, "upgrade");
|
98 |
+
$loader->addAction("admin_post_wpstg_download_sysinfo", $this, "systemInfoDownload");
|
99 |
+
$loader->addAction("admin_post_wpstg_export", $this, "export");
|
100 |
+
$loader->addAction("admin_post_wpstg_import_settings", $this, "import");
|
101 |
+
$loader->addAction("admin_notices", $this, "messages");
|
102 |
|
103 |
+
if (!defined('WPSTGPRO_VERSION')) {
|
104 |
+
add_filter('admin_footer', array($this, 'loadFeedbackForm'));
|
105 |
}
|
106 |
|
107 |
// Ajax Requests
|
108 |
+
$loader->addAction("wp_ajax_wpstg_overview", $this, "ajaxOverview");
|
109 |
+
$loader->addAction("wp_ajax_wpstg_scanning", $this, "ajaxScan");
|
110 |
+
$loader->addAction("wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName");
|
111 |
+
$loader->addAction("wp_ajax_wpstg_restart", $this, "ajaxRestart");
|
112 |
+
$loader->addAction("wp_ajax_wpstg_update", $this, "ajaxUpdateProcess");
|
113 |
+
$loader->addAction("wp_ajax_wpstg_cloning", $this, "ajaxStartClone");
|
114 |
+
$loader->addAction("wp_ajax_wpstg_processing", $this, "ajaxCloneDatabase");
|
115 |
+
$loader->addAction("wp_ajax_wpstg_database_connect", $this, "ajaxDatabaseConnect");
|
116 |
+
$loader->addAction("wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories");
|
117 |
+
$loader->addAction("wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles");
|
118 |
+
$loader->addAction("wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData");
|
119 |
+
$loader->addAction("wp_ajax_wpstg_clone_finish", $this, "ajaxFinish");
|
120 |
+
$loader->addAction("wp_ajax_wpstg_confirm_delete_clone", $this, "ajaxDeleteConfirmation");
|
121 |
+
$loader->addAction("wp_ajax_wpstg_delete_clone", $this, "ajaxDeleteClone");
|
122 |
+
$loader->addAction("wp_ajax_wpstg_cancel_clone", $this, "ajaxCancelClone");
|
123 |
+
$loader->addAction("wp_ajax_wpstg_cancel_update", $this, "ajaxCancelUpdate");
|
124 |
+
$loader->addAction("wp_ajax_wpstg_hide_poll", $this, "ajaxHidePoll");
|
125 |
+
$loader->addAction("wp_ajax_wpstg_hide_rating", $this, "ajaxHideRating");
|
126 |
+
$loader->addAction("wp_ajax_wpstg_hide_later", $this, "ajaxHideLaterRating");
|
127 |
+
$loader->addAction("wp_ajax_wpstg_hide_beta", $this, "ajaxHideBeta");
|
128 |
+
$loader->addAction("wp_ajax_wpstg_logs", $this, "ajaxLogs");
|
129 |
+
$loader->addAction("wp_ajax_wpstg_check_disk_space", $this, "ajaxCheckFreeSpace");
|
130 |
+
$loader->addAction("wp_ajax_wpstg_send_report", $this, "ajaxSendReport");
|
131 |
+
$loader->addAction("wp_ajax_wpstg_send_feedback", $this, "sendFeedback");
|
132 |
|
133 |
|
134 |
// Ajax hooks pro Version
|
135 |
+
$loader->addAction("wp_ajax_wpstg_scan", $this, "ajaxPushScan");
|
136 |
+
$loader->addAction("wp_ajax_wpstg_push_processing", $this, "ajaxPushProcessing");
|
137 |
}
|
138 |
|
139 |
/**
|
140 |
* Load Feedback Form on plugins.php
|
141 |
*/
|
142 |
+
public function loadFeedbackForm()
|
143 |
+
{
|
144 |
$form = new Feedback\Feedback();
|
145 |
$load = $form->loadForm();
|
146 |
}
|
148 |
/**
|
149 |
* Send Feedback form via mail
|
150 |
*/
|
151 |
+
public function sendFeedback()
|
152 |
+
{
|
153 |
$form = new Feedback\Feedback();
|
154 |
$send = $form->sendMail();
|
155 |
}
|
157 |
/**
|
158 |
* Register options form elements
|
159 |
*/
|
160 |
+
public function setOptionFormElements()
|
161 |
+
{
|
162 |
+
register_setting("wpstg_settings", "wpstg_settings", array($this, "sanitizeOptions"));
|
163 |
}
|
164 |
|
165 |
/**
|
180 |
* @param array $data
|
181 |
* @return array
|
182 |
*/
|
183 |
+
public function sanitizeOptions($data = array())
|
184 |
+
{
|
185 |
+
$sanitized = $this->sanitizeData($data);
|
186 |
|
187 |
+
add_settings_error("wpstg-notices", '', __("Settings updated.", "wp-staging"), "updated");
|
188 |
|
189 |
+
return apply_filters("wpstg-settings", $sanitized, $data);
|
190 |
}
|
191 |
|
192 |
/**
|
193 |
* @param array $data
|
194 |
* @return array
|
195 |
*/
|
196 |
+
private function sanitizeData($data = array())
|
197 |
+
{
|
198 |
$sanitized = array();
|
199 |
|
200 |
+
foreach ($data as $key => $value) {
|
201 |
+
if (is_array($value)) {
|
202 |
+
$sanitized[$key] = $this->sanitizeData($value);
|
203 |
+
} //Removing comma separators and decimal points
|
204 |
+
else if (in_array($key, self::$integerOptions, true)) {
|
205 |
+
$sanitized[$key] = preg_replace('/\D/', '', htmlspecialchars($value));
|
206 |
+
} else {
|
207 |
+
$sanitized[$key] = htmlspecialchars($value);
|
208 |
+
}
|
209 |
}
|
210 |
|
211 |
return $sanitized;
|
263 |
/**
|
264 |
* Settings Page
|
265 |
*/
|
266 |
+
public function getSettingsPage()
|
267 |
+
{
|
268 |
// Tabs
|
269 |
+
$tabs = new Tabs(array(
|
270 |
+
"general" => __("General", "wp-staging")
|
271 |
+
));
|
272 |
|
273 |
|
274 |
$this->di
|
275 |
+
// Set tabs
|
276 |
+
->set("tabs", $tabs)
|
277 |
+
// Forms
|
278 |
+
->set("forms", new FormSettings($tabs))
|
279 |
+
;
|
280 |
|
281 |
|
282 |
require_once "{$this->path}views/settings/main-settings.php";
|
285 |
/**
|
286 |
* Clone Page
|
287 |
*/
|
288 |
+
public function getClonePage()
|
289 |
+
{
|
290 |
// Existing clones
|
291 |
+
$availableClones = get_option("wpstg_existing_clones_beta", array());
|
292 |
|
293 |
require_once "{$this->path}views/clone/index.php";
|
294 |
}
|
296 |
/**
|
297 |
* Welcome Page
|
298 |
*/
|
299 |
+
public function getWelcomePage()
|
300 |
+
{
|
301 |
+
if (defined('WPSTGPRO_VERSION')) {
|
302 |
return;
|
303 |
}
|
304 |
require_once "{$this->path}views/welcome/welcome.php";
|
307 |
/**
|
308 |
* Tools Page
|
309 |
*/
|
310 |
+
public function getToolsPage()
|
311 |
+
{
|
312 |
// Tabs
|
313 |
+
$tabs = new Tabs(array(
|
314 |
+
"import_export" => __("Import/Export", "wp-staging"),
|
315 |
+
"system_info" => __("System Info", "wp-staging")
|
316 |
+
));
|
317 |
|
318 |
+
$this->di->set("tabs", $tabs);
|
319 |
|
320 |
+
$this->di->set("systemInfo", new SystemInfo($this->di));
|
321 |
|
322 |
require_once "{$this->path}views/tools/index.php";
|
323 |
}
|
325 |
/**
|
326 |
* System Information Download
|
327 |
*/
|
328 |
+
public function systemInfoDownload()
|
329 |
+
{
|
330 |
+
if (!current_user_can("update_plugins")) {
|
331 |
return;
|
332 |
}
|
333 |
|
334 |
nocache_headers();
|
335 |
+
header("Content-Type: text/plain");
|
336 |
+
header('Content-Disposition: attachment; filename="wpstg-system-info.txt"');
|
337 |
+
echo wp_strip_all_tags(new SystemInfo($this->di));
|
338 |
}
|
339 |
|
340 |
/**
|
341 |
* Import JSON settings file
|
342 |
*/
|
343 |
+
public function import()
|
344 |
+
{
|
345 |
+
if (empty($_POST["wpstg_import_nonce"])) {
|
346 |
return;
|
347 |
}
|
348 |
|
349 |
+
if (!wp_verify_nonce($_POST["wpstg_import_nonce"], "wpstg_import_nonce")) {
|
350 |
return;
|
351 |
}
|
352 |
|
353 |
+
if (!current_user_can("update_plugins")) {
|
354 |
return;
|
355 |
}
|
356 |
|
357 |
+
$fileExtension = explode('.', $_FILES["import_file"]["name"]);
|
358 |
+
$fileExtension = end($fileExtension);
|
359 |
+
if ("json" !== $fileExtension) {
|
360 |
+
wp_die("Please upload a valid .json file", "wp-staging");
|
361 |
}
|
362 |
|
363 |
|
364 |
$importFile = $_FILES["import_file"]["tmp_name"];
|
365 |
|
366 |
+
if (empty($importFile)) {
|
367 |
+
wp_die(__("Please upload a file to import", "wp-staging"));
|
368 |
}
|
369 |
|
370 |
+
update_option("wpstg_settings", json_decode(file_get_contents($importFile, true)));
|
371 |
|
372 |
+
wp_safe_redirect(admin_url("admin.php?page=wpstg-tools&wpstg-message=settings-imported"));
|
373 |
|
374 |
return;
|
375 |
}
|
377 |
/**
|
378 |
* Export settings to JSON file
|
379 |
*/
|
380 |
+
public function export()
|
381 |
+
{
|
382 |
+
if (empty($_POST["wpstg_export_nonce"])) {
|
383 |
return;
|
384 |
}
|
385 |
|
386 |
+
if (!wp_verify_nonce($_POST["wpstg_export_nonce"], "wpstg_export_nonce")) {
|
387 |
return;
|
388 |
}
|
389 |
|
390 |
+
if (!current_user_can("manage_options")) {
|
391 |
return;
|
392 |
}
|
393 |
|
394 |
+
$settings = get_option("wpstg_settings", array());
|
395 |
|
396 |
+
ignore_user_abort(true);
|
397 |
|
398 |
+
if (!in_array("set_time_limit", explode(',', ini_get("disable_functions"))) && !@ini_get("safe_mode")) {
|
399 |
+
set_time_limit(0);
|
400 |
}
|
401 |
|
402 |
+
$fileName = apply_filters("wpstg_settings_export_filename", "wpstg-settings-export-" . date("m-d-Y")) . ".json";
|
403 |
|
404 |
nocache_headers();
|
405 |
+
header("Content-Type: application/json; charset=utf-8");
|
406 |
+
header("Content-Disposition: attachment; filename={$fileName}");
|
407 |
+
header("Expires: 0");
|
408 |
|
409 |
+
echo json_encode($settings);
|
410 |
}
|
411 |
|
412 |
/**
|
415 |
* @param array $vars
|
416 |
* @return string
|
417 |
*/
|
418 |
+
public function render($file, $vars = array())
|
419 |
+
{
|
420 |
$fullPath = $this->path . "views" . DIRECTORY_SEPARATOR;
|
421 |
+
$fullPath = str_replace(array('/', "\\"), DIRECTORY_SEPARATOR, $fullPath . $file . ".php");
|
422 |
|
423 |
+
if (!file_exists($fullPath) || !is_readable($fullPath)) {
|
424 |
return "Can't render : {$fullPath} either file doesn't exist or can't read it";
|
425 |
}
|
426 |
|
427 |
+
$contents = @file_get_contents($fullPath);
|
428 |
|
429 |
// Variables are set
|
430 |
+
if (count($vars) > 0) {
|
431 |
$vars = array_combine(
|
432 |
+
array_map(function ($key) {
|
433 |
+
return "{{" . $key . "}}";
|
434 |
+
}, array_keys($vars)
|
435 |
+
), $vars
|
436 |
);
|
437 |
|
438 |
+
$contents = str_replace(array_keys($vars), array_values($vars), $contents);
|
439 |
}
|
440 |
|
441 |
return $contents;
|
444 |
/**
|
445 |
* Restart cloning process
|
446 |
*/
|
447 |
+
public function ajaxRestart()
|
448 |
+
{
|
449 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
450 |
|
451 |
$process = new ProcessLock();
|
452 |
$process->restart();
|
455 |
/**
|
456 |
* Ajax Overview
|
457 |
*/
|
458 |
+
public function ajaxOverview()
|
459 |
+
{
|
460 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
461 |
|
462 |
// Existing clones
|
463 |
+
$availableClones = get_option("wpstg_existing_clones_beta", array());
|
464 |
|
465 |
// Get license data
|
466 |
+
$license = get_option('wpstg_license_status');
|
467 |
|
468 |
// Get db
|
469 |
+
$db = WPStaging::getInstance()->get('wpdb');
|
470 |
|
471 |
+
if (\WPStaging\WPStaging::getSlug() === 'wp-staging-pro') {
|
472 |
require_once "{$this->path}Pro/views/single-overview-pro.php";
|
473 |
} else {
|
474 |
require_once "{$this->path}views/clone/ajax/single-overview.php";
|
480 |
/**
|
481 |
* Ajax Scan
|
482 |
*/
|
483 |
+
public function ajaxScan()
|
484 |
+
{
|
485 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
486 |
|
487 |
// Check first if there is already a process running
|
488 |
$processLock = new ProcessLock();
|
489 |
$processLock->isRunning();
|
490 |
|
491 |
+
$db = WPStaging::getInstance()->get('wpdb');
|
492 |
|
493 |
// Scan
|
494 |
$scan = new Scan();
|
505 |
/**
|
506 |
* Ajax Check Clone Name
|
507 |
*/
|
508 |
+
public function ajaxCheckCloneName()
|
509 |
+
{
|
510 |
+
$cloneName = sanitize_key($_POST["cloneID"]);
|
511 |
+
$cloneNameLength = strlen($cloneName);
|
512 |
+
$clones = get_option("wpstg_existing_clones_beta", array());
|
513 |
|
514 |
+
$clonePath = trailingslashit(get_home_path()) . $cloneName;
|
515 |
|
516 |
// Check clone name length
|
517 |
+
if ($cloneNameLength < 1 || $cloneNameLength > 16) {
|
518 |
+
echo wp_send_json(array(
|
519 |
+
"status" => "failed",
|
520 |
"message" => "Clone name must be between 1 - 16 characters"
|
521 |
+
));
|
522 |
+
} elseif (array_key_exists($cloneName, $clones)) {
|
523 |
+
echo wp_send_json(array(
|
524 |
+
"status" => "failed",
|
525 |
"message" => "Clone name is already in use, please choose another clone name."
|
526 |
+
));
|
527 |
+
} elseif (is_dir($clonePath) && !wpstg_is_empty_dir($clonePath)) {
|
528 |
+
echo wp_send_json(array(
|
529 |
+
"status" => "failed",
|
530 |
"message" => "Clone directory " . $clonePath . " already exists. Use another clone name."
|
531 |
+
));
|
532 |
}
|
533 |
|
534 |
+
echo wp_send_json(array("status" => "success"));
|
535 |
}
|
536 |
|
537 |
/**
|
538 |
* Ajax Start Updating Clone (Basically just layout and saving data)
|
539 |
*/
|
540 |
+
public function ajaxUpdateProcess()
|
541 |
+
{
|
542 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
543 |
|
544 |
$cloning = new Updating();
|
545 |
|
546 |
+
if (!$cloning->save()) {
|
547 |
+
wp_die('can not save clone data');
|
548 |
}
|
549 |
|
550 |
require_once "{$this->path}views/clone/ajax/update.php";
|
555 |
/**
|
556 |
* Ajax Start Clone (Basically just layout and saving data)
|
557 |
*/
|
558 |
+
public function ajaxStartClone()
|
559 |
+
{
|
560 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
561 |
|
562 |
// Check first if there is already a process running
|
563 |
$processLock = new ProcessLock();
|
565 |
|
566 |
$cloning = new Cloning();
|
567 |
|
568 |
+
if (!$cloning->save()) {
|
569 |
+
wp_die('can not save clone data');
|
570 |
}
|
571 |
|
572 |
require_once "{$this->path}views/clone/ajax/start.php";
|
577 |
/**
|
578 |
* Ajax Clone Database
|
579 |
*/
|
580 |
+
public function ajaxCloneDatabase()
|
581 |
+
{
|
582 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
583 |
|
584 |
$cloning = new Cloning();
|
585 |
|
587 |
//http_response_code(504);
|
588 |
//wp_send_json( '<html><body><head></head><body>test</body></html>' );
|
589 |
|
590 |
+
wp_send_json($cloning->start());
|
591 |
}
|
592 |
|
593 |
/**
|
594 |
* Ajax Prepare Directories (get listing of files)
|
595 |
*/
|
596 |
+
public function ajaxPrepareDirectories()
|
597 |
+
{
|
598 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
599 |
|
600 |
$cloning = new Cloning();
|
601 |
|
602 |
+
wp_send_json($cloning->start());
|
603 |
}
|
604 |
|
605 |
/**
|
606 |
* Ajax Clone Files
|
607 |
*/
|
608 |
+
public function ajaxCopyFiles()
|
609 |
+
{
|
610 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
611 |
|
612 |
$cloning = new Cloning();
|
613 |
|
614 |
+
wp_send_json($cloning->start());
|
615 |
}
|
616 |
|
617 |
/**
|
618 |
* Ajax Replace Data
|
619 |
*/
|
620 |
+
public function ajaxReplaceData()
|
621 |
+
{
|
622 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
623 |
|
624 |
$cloning = new Cloning();
|
625 |
|
626 |
+
wp_send_json($cloning->start());
|
627 |
}
|
628 |
|
629 |
/**
|
630 |
* Ajax Finish
|
631 |
*/
|
632 |
+
public function ajaxFinish()
|
633 |
+
{
|
634 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
635 |
|
636 |
$cloning = new Cloning();
|
637 |
|
638 |
+
wp_send_json($cloning->start());
|
639 |
}
|
640 |
|
641 |
/**
|
642 |
* Ajax Delete Confirmation
|
643 |
*/
|
644 |
+
public function ajaxDeleteConfirmation()
|
645 |
+
{
|
646 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
647 |
|
648 |
$delete = new Delete();
|
649 |
$delete->setData();
|
660 |
/**
|
661 |
* Delete clone
|
662 |
*/
|
663 |
+
public function ajaxDeleteClone()
|
664 |
+
{
|
665 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
666 |
|
667 |
$delete = new Delete();
|
668 |
|
669 |
+
wp_send_json($delete->start());
|
670 |
}
|
671 |
|
672 |
/**
|
673 |
* Delete clone
|
674 |
*/
|
675 |
+
public function ajaxCancelClone()
|
676 |
+
{
|
677 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
678 |
|
679 |
$cancel = new Cancel();
|
680 |
|
681 |
+
wp_send_json($cancel->start());
|
682 |
}
|
683 |
|
684 |
/**
|
685 |
* Cancel updating process / Do not delete clone!
|
686 |
*/
|
687 |
+
public function ajaxCancelUpdate()
|
688 |
+
{
|
689 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
690 |
|
691 |
$cancel = new CancelUpdate();
|
692 |
+
wp_send_json($cancel->start());
|
693 |
}
|
694 |
|
695 |
/**
|
696 |
* Admin Messages
|
697 |
*/
|
698 |
+
public function messages()
|
699 |
+
{
|
700 |
+
$notice = new Notices($this->path, $this->url);
|
701 |
|
702 |
$run = $notice->messages();
|
703 |
}
|
706 |
* Ajax Hide Poll
|
707 |
* @return mixed boolean | json
|
708 |
*/
|
709 |
+
public function ajaxHidePoll()
|
710 |
+
{
|
711 |
+
if (false !== update_option("wpstg_poll", "no")) {
|
712 |
+
wp_send_json(true);
|
713 |
}
|
714 |
return wp_send_json();
|
715 |
}
|
718 |
* Ajax Hide Rating
|
719 |
* @return mixed bool | json
|
720 |
*/
|
721 |
+
public function ajaxHideRating()
|
722 |
+
{
|
723 |
+
if (false !== update_option("wpstg_rating", "no")) {
|
724 |
+
wp_send_json(true);
|
725 |
}
|
726 |
return wp_send_json();
|
727 |
}
|
730 |
* Ajax Hide Rating and show it again after one week
|
731 |
* @return mixed bool | json
|
732 |
*/
|
733 |
+
public function ajaxHideLaterRating()
|
734 |
+
{
|
735 |
+
$date = date('Y-m-d', strtotime(date('Y-m-d') . ' + 7 days'));
|
736 |
+
if (false !== update_option('wpstg_rating', $date)) {
|
737 |
+
wp_send_json(true);
|
738 |
}
|
739 |
+
return wp_send_json(false);
|
740 |
}
|
741 |
|
742 |
/**
|
743 |
* Ajax Hide Beta
|
744 |
*/
|
745 |
+
public function ajaxHideBeta()
|
746 |
+
{
|
747 |
+
wp_send_json(update_option("wpstg_beta", "no"));
|
748 |
}
|
749 |
|
750 |
/**
|
751 |
* Clone logs
|
752 |
*/
|
753 |
+
public function ajaxLogs()
|
754 |
+
{
|
755 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
756 |
|
757 |
$logs = new Logs();
|
758 |
+
wp_send_json($logs->start());
|
759 |
}
|
760 |
|
761 |
/**
|
762 |
* Ajax Checks Free Disk Space
|
763 |
*/
|
764 |
+
public function ajaxCheckFreeSpace()
|
765 |
+
{
|
766 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
767 |
|
768 |
$scan = new Scan();
|
769 |
return $scan->hasFreeDiskSpace();
|
773 |
* Ajax Start Push Changes Process
|
774 |
* Start with the module Scan
|
775 |
*/
|
776 |
+
public function ajaxPushScan()
|
777 |
+
{
|
778 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
779 |
|
780 |
+
if (!class_exists('WPStaging\Backend\Pro\Modules\Jobs\Scan')) {
|
781 |
return false;
|
782 |
}
|
783 |
|
797 |
/**
|
798 |
* Ajax Start Pushing. Needs WP Staging Pro
|
799 |
*/
|
800 |
+
public function ajaxPushProcessing()
|
801 |
+
{
|
802 |
+
check_ajax_referer("wpstg_ajax_nonce", "nonce");
|
803 |
|
804 |
+
if (!class_exists('WPStaging\Backend\Pro\Modules\Jobs\Processing')) {
|
805 |
return false;
|
806 |
}
|
807 |
|
808 |
// Start the process
|
809 |
$processing = new Processing();
|
810 |
+
wp_send_json($processing->start());
|
811 |
}
|
812 |
|
813 |
/**
|
814 |
* License Page
|
815 |
*/
|
816 |
+
public function getLicensePage()
|
817 |
+
{
|
818 |
|
819 |
// Get license data
|
820 |
+
$license = get_option('wpstg_license_status');
|
821 |
|
822 |
require_once "{$this->path}Pro/views/licensing.php";
|
823 |
}
|
824 |
|
825 |
/**
|
826 |
* Send mail via ajax
|
827 |
+
* @param array $args
|
828 |
*/
|
829 |
+
public function ajaxSendReport($args = array())
|
830 |
+
{
|
831 |
// Set params
|
832 |
+
if (empty($args)) {
|
833 |
+
$args = stripslashes_deep($_POST);
|
834 |
}
|
835 |
// Set e-mail
|
836 |
$email = null;
|
837 |
+
if (isset($args['wpstg_email'])) {
|
838 |
+
$email = trim($args['wpstg_email']);
|
839 |
+
}
|
840 |
+
|
841 |
+
// Set hosting provider
|
842 |
+
$provider = null;
|
843 |
+
if (isset($args['wpstg_provider'])) {
|
844 |
+
$provider = trim($args['wpstg_provider']);
|
845 |
}
|
846 |
|
847 |
// Set message
|
848 |
$message = null;
|
849 |
+
if (isset($args['wpstg_message'])) {
|
850 |
+
$message = trim($args['wpstg_message']);
|
851 |
}
|
852 |
|
853 |
// Set syslog
|
854 |
$syslog = false;
|
855 |
+
if (isset($args['wpstg_syslog'])) {
|
856 |
+
$syslog = ( bool )$args['wpstg_syslog'];
|
857 |
}
|
858 |
|
859 |
// Set terms
|
860 |
$terms = false;
|
861 |
+
if (isset($args['wpstg_terms'])) {
|
862 |
+
$terms = ( bool )$args['wpstg_terms'];
|
863 |
}
|
864 |
|
865 |
+
$report = new Report($this->di);
|
866 |
+
$errors = $report->send($email, $message, $terms, $syslog, $provider);
|
867 |
|
868 |
+
echo json_encode(array('errors' => $errors));
|
869 |
exit;
|
870 |
}
|
871 |
|
872 |
/**
|
873 |
* Connect to external database for testing correct credentials
|
874 |
*/
|
875 |
+
public function ajaxDatabaseConnect()
|
876 |
+
{
|
877 |
+
$args = $_POST;
|
878 |
+
$user = !empty($args['databaseUser']) ? $args['databaseUser'] : '';
|
879 |
+
$password = !empty($args['databasePassword']) ? $args['databasePassword'] : '';
|
880 |
+
$database = !empty($args['databaseDatabase']) ? $args['databaseDatabase'] : '';
|
881 |
+
$server = !empty($args['databaseServer']) ? $args['databaseServer'] : 'localhost';
|
|
|
|
|
|
|
882 |
|
883 |
+
$db = new \wpdb($user, stripslashes($password), $database, $server);
|
884 |
|
885 |
// Can not connect to mysql
|
886 |
+
if (!empty($db->error->errors['db_connect_fail']['0'])) {
|
887 |
+
echo json_encode(array('errors' => $db->error->errors['db_connect_fail']['0']));
|
888 |
exit;
|
889 |
}
|
890 |
|
891 |
// Can not connect to database
|
892 |
+
$db->select($database);
|
893 |
+
if (!$db->ready) {
|
894 |
$error = isset($db->error->errors['db_select_fail']) ? $db->error->errors['db_select_fail'] : "Error: Can't select {database} Either it does not exist or you don't have privileges to access it.";
|
895 |
+
echo json_encode(array('errors' => $error));
|
896 |
exit;
|
897 |
}
|
898 |
+
echo json_encode(array('success' => 'true'));
|
899 |
exit;
|
900 |
}
|
901 |
|
Backend/Modules/Jobs/Cloning.php
CHANGED
@@ -14,7 +14,6 @@ use WPStaging\Backend\Modules\Jobs\Multisite\Finish as muFinish;
|
|
14 |
use WPStaging\Backend\Modules\Jobs\Multisite\Directories as muDirectories;
|
15 |
use WPStaging\Backend\Modules\Jobs\Multisite\Files as muFiles;
|
16 |
use WPStaging\Utils\Helper;
|
17 |
-
|
18 |
/**
|
19 |
* Class Cloning
|
20 |
* @package WPStaging\Backend\Modules\Jobs
|
@@ -22,6 +21,11 @@ use WPStaging\Utils\Helper;
|
|
22 |
class Cloning extends Job
|
23 |
{
|
24 |
|
|
|
|
|
|
|
|
|
|
|
25 |
/**
|
26 |
* Initialize is called in \Job
|
27 |
*/
|
@@ -105,16 +109,16 @@ class Cloning extends Job
|
|
105 |
// Excluded Directories TOTAL
|
106 |
// Do not copy these folders and plugins
|
107 |
$excludedDirectories = array(
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
);
|
114 |
|
115 |
$this->options->excludedDirectories = array_merge($excludedDirectories, wpstg_urldecode($this->options->excludedDirectories));
|
116 |
|
117 |
-
array_unshift($this->options->directoriesToCopy,
|
118 |
|
119 |
// Included Directories
|
120 |
if (isset($_POST["includedDirectories"]) && is_array($_POST["includedDirectories"])) {
|
@@ -142,7 +146,7 @@ class Cloning extends Job
|
|
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"])) {
|
@@ -176,6 +180,13 @@ class Cloning extends Job
|
|
176 |
return $this->saveOptions();
|
177 |
}
|
178 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
179 |
|
180 |
/**
|
181 |
* Save clone data initially
|
@@ -192,7 +203,7 @@ class Cloning extends Job
|
|
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,
|
@@ -212,7 +223,7 @@ class Cloning extends Job
|
|
212 |
|
213 |
/**
|
214 |
* Get destination Hostname depending on wheather WP has been installed in sub dir or not
|
215 |
-
* @return
|
216 |
*/
|
217 |
private function getDestinationUrl()
|
218 |
{
|
@@ -249,19 +260,19 @@ class Cloning extends Job
|
|
249 |
|
250 |
/**
|
251 |
* Get Destination Directory including staging subdirectory
|
252 |
-
* @return
|
253 |
*/
|
254 |
private function getDestinationDir()
|
255 |
{
|
256 |
// Throw fatal error
|
257 |
-
if (!empty($this->options->cloneDir) & (trailingslashit($this->options->cloneDir) === ( string )trailingslashit(
|
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(
|
265 |
return $this->options->cloneDir;
|
266 |
}
|
267 |
return trailingslashit($this->options->cloneDir);
|
@@ -283,12 +294,12 @@ class Cloning extends Job
|
|
283 |
}
|
284 |
|
285 |
/**
|
286 |
-
* Create a new staging prefix
|
287 |
*/
|
288 |
private function setStagingPrefix()
|
289 |
{
|
290 |
|
291 |
-
// Get & find a new prefix that does not already exist in database.
|
292 |
// Loop through up to 1000 different possible prefixes should be enough here;)
|
293 |
for ($i = 0; $i <= 10000; $i++) {
|
294 |
$this->options->prefix = isset($this->options->existingClones) ?
|
@@ -307,22 +318,6 @@ class Cloning extends Job
|
|
307 |
wp_die("Fatal Error: Can not create staging prefix. Prefix '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
|
308 |
}
|
309 |
|
310 |
-
/**
|
311 |
-
* Check if potential new prefix of staging site would be identical with live site.
|
312 |
-
* @return boolean
|
313 |
-
*/
|
314 |
-
private function isPrefixIdentical()
|
315 |
-
{
|
316 |
-
$db = WPStaging::getInstance()->get("wpdb");
|
317 |
-
|
318 |
-
$livePrefix = $db->prefix;
|
319 |
-
$stagingPrefix = $this->options->prefix;
|
320 |
-
|
321 |
-
if ($livePrefix == $stagingPrefix) {
|
322 |
-
return true;
|
323 |
-
}
|
324 |
-
return false;
|
325 |
-
}
|
326 |
|
327 |
/**
|
328 |
* Start the cloning job
|
@@ -341,6 +336,10 @@ class Cloning extends Job
|
|
341 |
throw new JobNotFoundException($methodName);
|
342 |
}
|
343 |
|
|
|
|
|
|
|
|
|
344 |
// Call the job
|
345 |
return $this->{$methodName}();
|
346 |
}
|
@@ -367,6 +366,15 @@ class Cloning extends Job
|
|
367 |
return $response;
|
368 |
}
|
369 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
/**
|
371 |
* Clone Database
|
372 |
* @return object
|
@@ -412,7 +420,16 @@ class Cloning extends Job
|
|
412 |
$searchReplace = new SearchReplaceExternal();
|
413 |
}
|
414 |
}
|
415 |
-
return $this->handleJobResponse($searchReplace->start(), "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
416 |
}
|
417 |
|
418 |
/**
|
14 |
use WPStaging\Backend\Modules\Jobs\Multisite\Directories as muDirectories;
|
15 |
use WPStaging\Backend\Modules\Jobs\Multisite\Files as muFiles;
|
16 |
use WPStaging\Utils\Helper;
|
|
|
17 |
/**
|
18 |
* Class Cloning
|
19 |
* @package WPStaging\Backend\Modules\Jobs
|
21 |
class Cloning extends Job
|
22 |
{
|
23 |
|
24 |
+
/**
|
25 |
+
* @var object
|
26 |
+
*/
|
27 |
+
private $db;
|
28 |
+
|
29 |
/**
|
30 |
* Initialize is called in \Job
|
31 |
*/
|
109 |
// Excluded Directories TOTAL
|
110 |
// Do not copy these folders and plugins
|
111 |
$excludedDirectories = array(
|
112 |
+
WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
|
113 |
+
WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
|
114 |
+
WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-super-cache',
|
115 |
+
WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'peters-login-redirect',
|
116 |
+
WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-spamshield',
|
117 |
);
|
118 |
|
119 |
$this->options->excludedDirectories = array_merge($excludedDirectories, wpstg_urldecode($this->options->excludedDirectories));
|
120 |
|
121 |
+
array_unshift($this->options->directoriesToCopy, WPStaging::getWPpath());
|
122 |
|
123 |
// Included Directories
|
124 |
if (isset($_POST["includedDirectories"]) && is_array($_POST["includedDirectories"])) {
|
146 |
}
|
147 |
$this->options->databasePassword = '';
|
148 |
if (isset($_POST["databasePassword"]) && !empty($_POST["databasePassword"])) {
|
149 |
+
$this->options->databasePassword = stripslashes($_POST["databasePassword"]);
|
150 |
}
|
151 |
$this->options->databaseDatabase = '';
|
152 |
if (isset($_POST["databaseDatabase"]) && !empty($_POST["databaseDatabase"])) {
|
180 |
return $this->saveOptions();
|
181 |
}
|
182 |
|
183 |
+
/**
|
184 |
+
* @return bool
|
185 |
+
*/
|
186 |
+
private function enteredDatabaseSameAsLiveDatabase()
|
187 |
+
{
|
188 |
+
return $this->options->databaseServer === DB_HOST && $this->options->databaseDatabase == DB_NAME;
|
189 |
+
}
|
190 |
|
191 |
/**
|
192 |
* Save clone data initially
|
203 |
"url" => $this->getDestinationUrl(),
|
204 |
"number" => $this->options->cloneNumber,
|
205 |
"version" => WPStaging::getVersion(),
|
206 |
+
"status" => "unfinished or broken (?)",
|
207 |
"prefix" => $this->options->prefix,
|
208 |
"datetime" => time(),
|
209 |
"databaseUser" => $this->options->databaseUser,
|
223 |
|
224 |
/**
|
225 |
* Get destination Hostname depending on wheather WP has been installed in sub dir or not
|
226 |
+
* @return string
|
227 |
*/
|
228 |
private function getDestinationUrl()
|
229 |
{
|
260 |
|
261 |
/**
|
262 |
* Get Destination Directory including staging subdirectory
|
263 |
+
* @return string
|
264 |
*/
|
265 |
private function getDestinationDir()
|
266 |
{
|
267 |
// Throw fatal error
|
268 |
+
if (!empty($this->options->cloneDir) & (trailingslashit($this->options->cloneDir) === ( string )trailingslashit(WPStaging::getWPpath()))) {
|
269 |
$this->returnException('Error: Target Directory must be different from the root of the production website.');
|
270 |
die();
|
271 |
}
|
272 |
|
273 |
// No custom clone dir so clone path will be in subfolder of root
|
274 |
if (empty($this->options->cloneDir)) {
|
275 |
+
$this->options->cloneDir = trailingslashit(WPStaging::getWPpath() . $this->options->cloneDirectoryName);
|
276 |
return $this->options->cloneDir;
|
277 |
}
|
278 |
return trailingslashit($this->options->cloneDir);
|
294 |
}
|
295 |
|
296 |
/**
|
297 |
+
* Create a new staging prefix that does not already exists in database
|
298 |
*/
|
299 |
private function setStagingPrefix()
|
300 |
{
|
301 |
|
302 |
+
// Get & find a new prefix that does not already exist in database.
|
303 |
// Loop through up to 1000 different possible prefixes should be enough here;)
|
304 |
for ($i = 0; $i <= 10000; $i++) {
|
305 |
$this->options->prefix = isset($this->options->existingClones) ?
|
318 |
wp_die("Fatal Error: Can not create staging prefix. Prefix '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
|
319 |
}
|
320 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
321 |
|
322 |
/**
|
323 |
* Start the cloning job
|
336 |
throw new JobNotFoundException($methodName);
|
337 |
}
|
338 |
|
339 |
+
if ($this->enteredDatabaseSameAsLiveDatabase() && $this->options->databasePrefix === $this->db->prefix) {
|
340 |
+
$this->returnException('Entered table prefix for staging and production database can not be identical! Please start over and change the table prefix.');
|
341 |
+
}
|
342 |
+
|
343 |
// Call the job
|
344 |
return $this->{$methodName}();
|
345 |
}
|
366 |
return $response;
|
367 |
}
|
368 |
|
369 |
+
/**
|
370 |
+
* Copy data from staging site to temporary column to use it later
|
371 |
+
* @return object
|
372 |
+
*/
|
373 |
+
public function jobPreserveDataFirstStep(){
|
374 |
+
$preserve = new PreserveDataFirstStep();
|
375 |
+
return $this->handleJobResponse($preserve->start(), 'database');
|
376 |
+
}
|
377 |
+
|
378 |
/**
|
379 |
* Clone Database
|
380 |
* @return object
|
420 |
$searchReplace = new SearchReplaceExternal();
|
421 |
}
|
422 |
}
|
423 |
+
return $this->handleJobResponse($searchReplace->start(), "PreserveDataSecondStep");
|
424 |
+
}
|
425 |
+
|
426 |
+
/**
|
427 |
+
* Copy tmp data back to staging site
|
428 |
+
* @return object
|
429 |
+
*/
|
430 |
+
public function jobPreserveDataSecondStep(){
|
431 |
+
$preserve = new PreserveDataSecondStep();
|
432 |
+
return $this->handleJobResponse($preserve->start(), 'directories');
|
433 |
}
|
434 |
|
435 |
/**
|
Backend/Modules/Jobs/Data.php
CHANGED
@@ -79,7 +79,7 @@ class Data extends JobExecutable
|
|
79 |
*/
|
80 |
protected function calculateTotalSteps()
|
81 |
{
|
82 |
-
$this->options->totalSteps =
|
83 |
}
|
84 |
|
85 |
/**
|
@@ -181,7 +181,7 @@ class Data extends JobExecutable
|
|
181 |
* @param string $table
|
182 |
* @return boolean
|
183 |
*/
|
184 |
-
protected function
|
185 |
{
|
186 |
if ($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table) {
|
187 |
$this->log("Preparing Data: Table {$table} does not exist.", Logger::TYPE_INFO);
|
@@ -234,8 +234,8 @@ class Data extends JobExecutable
|
|
234 |
|
235 |
/**
|
236 |
* Copy files with symlink support
|
237 |
-
* @param
|
238 |
-
* @param
|
239 |
* @return boolean
|
240 |
*/
|
241 |
protected function copy($source, $destination)
|
@@ -262,12 +262,11 @@ class Data extends JobExecutable
|
|
262 |
|
263 |
/**
|
264 |
* Make sure wp-config.php contains correct db credentials
|
265 |
-
* @param
|
266 |
* @return boolean
|
267 |
*/
|
268 |
protected function alterWpConfig($source)
|
269 |
{
|
270 |
-
$content = file_get_contents($source);
|
271 |
|
272 |
if (false === ($content = file_get_contents($source))) {
|
273 |
return false;
|
@@ -300,7 +299,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
300 |
|
301 |
/**
|
302 |
* Check if wp-config.php contains important constants
|
303 |
-
* @param
|
304 |
* @return boolean
|
305 |
*/
|
306 |
protected function isValidWpConfig($source)
|
@@ -310,8 +309,6 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
310 |
return false;
|
311 |
}
|
312 |
|
313 |
-
$content = file_get_contents($source);
|
314 |
-
|
315 |
if (false === ($content = file_get_contents($source))) {
|
316 |
return false;
|
317 |
}
|
@@ -355,7 +352,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
355 |
$this->log("Preparing Data Step1: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO);
|
356 |
|
357 |
// Skip - Table does not exist
|
358 |
-
if (false === $this->
|
359 |
return true;
|
360 |
}
|
361 |
// Skip - Table is not selected or updated
|
@@ -392,7 +389,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
392 |
$this->log("Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}");
|
393 |
|
394 |
// Skip - Table does not exist
|
395 |
-
if (false === $this->
|
396 |
$this->log("Preparing Data Step2: Skipping");
|
397 |
return true;
|
398 |
}
|
@@ -402,7 +399,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
402 |
return true;
|
403 |
}
|
404 |
|
405 |
-
$
|
406 |
$this->db->prepare(
|
407 |
"DELETE FROM `{$this->prefix}options` WHERE `option_name` = %s;", 'wpstg_is_staging_site'
|
408 |
)
|
@@ -410,13 +407,12 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
410 |
|
411 |
|
412 |
// No errors but no option name such as wpstg_is_staging_site
|
413 |
-
//if( '' === $this->db->last_error && 0 == $result ) {
|
414 |
$insert = $this->db->query(
|
415 |
$this->db->prepare(
|
416 |
"INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_is_staging_site',%s)", "true"
|
417 |
)
|
418 |
);
|
419 |
-
|
420 |
// All good
|
421 |
if ($insert) {
|
422 |
$this->log("Preparing Data Step2: Successful", Logger::TYPE_INFO);
|
@@ -443,7 +439,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
443 |
}
|
444 |
|
445 |
// Skip - Table does not exist
|
446 |
-
if (false === $this->
|
447 |
$this->log("Preparing Data Step3: Skipping");
|
448 |
return true;
|
449 |
}
|
@@ -478,7 +474,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
478 |
$this->log("Preparing Data Step4: Updating db prefix in {$this->prefix}usermeta. ");
|
479 |
|
480 |
// Skip - Table does not exist
|
481 |
-
if (false === $this->
|
482 |
return true;
|
483 |
}
|
484 |
|
@@ -534,7 +530,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
534 |
$content = str_replace($this->homeUrl, $this->getStagingSiteUrl(), $content);
|
535 |
|
536 |
if (false === @wpstg_put_contents($path, $content)) {
|
537 |
-
$this->log("Preparing Data Step5: Failed to update
|
538 |
return false;
|
539 |
}
|
540 |
|
@@ -606,7 +602,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
606 |
$this->log("Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}");
|
607 |
|
608 |
// Skip - Table does not exist
|
609 |
-
if (false === $this->
|
610 |
$this->log("Preparing Data Step7: Skipping Table {$this->prefix}'options' does not exist");
|
611 |
return true;
|
612 |
}
|
@@ -649,7 +645,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
649 |
}
|
650 |
|
651 |
// Skip - Table does not exist
|
652 |
-
if (false === $this->
|
653 |
$this->log("Preparing Data Step8: Skipping");
|
654 |
return true;
|
655 |
}
|
@@ -685,7 +681,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
685 |
|
686 |
$this->log("Preparing Data Step9: Set staging site to noindex");
|
687 |
|
688 |
-
if (false === $this->
|
689 |
return true;
|
690 |
}
|
691 |
|
@@ -736,7 +732,6 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
736 |
$pattern = "/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*(.*)\s*\);.*/";
|
737 |
|
738 |
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1] . " Changed by WP-Staging";
|
739 |
-
//$replace.= " // Changed by WP-Staging";
|
740 |
|
741 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
742 |
$this->log("Preparing Data: Failed to update WP_HOME", Logger::TYPE_ERROR);
|
@@ -779,7 +774,6 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
779 |
$pattern = "/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*(.*)\s*\);.*/";
|
780 |
|
781 |
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1] . " Changed by WP-Staging";
|
782 |
-
//$replace.= " // Changed by WP-Staging";
|
783 |
|
784 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
785 |
$this->log("Preparing Data Step11: Failed to update WP_SITEURL to " . $this->getStagingSiteUrl(), Logger::TYPE_ERROR);
|
@@ -807,7 +801,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
807 |
$this->log("Preparing Data Step12: Updating db prefix in {$this->prefix}options.");
|
808 |
|
809 |
// Skip - Table does not exist
|
810 |
-
if (false === $this->
|
811 |
return true;
|
812 |
}
|
813 |
|
@@ -817,7 +811,6 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
817 |
return true;
|
818 |
}
|
819 |
|
820 |
-
$notice = !empty($this->db->last_error) ? 'Last error: ' . $this->db->last_error : '';
|
821 |
|
822 |
// Filter the rows below. Do not update them!
|
823 |
$filters = array(
|
@@ -861,7 +854,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
861 |
$this->log("Preparing Data Step13: Updating upload_path {$this->prefix}options.");
|
862 |
|
863 |
// Skip - Table does not exist
|
864 |
-
if (false === $this->
|
865 |
return true;
|
866 |
}
|
867 |
|
@@ -882,11 +875,6 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
882 |
|
883 |
$this->log("Updating upload_path in {$this->prefix}options. {$error}");
|
884 |
|
885 |
-
// $updateOptions = $this->db->query(
|
886 |
-
// $this->db->prepare(
|
887 |
-
// "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'upload_path'", $newUploadPath
|
888 |
-
// )
|
889 |
-
// );
|
890 |
// remove upload_path value and use UPLOADS constant instead. (upload_path is deprecated and should not be used any longer)
|
891 |
$updateOptions = $this->db->query(
|
892 |
$this->db->prepare(
|
@@ -926,7 +914,6 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
926 |
$pattern = "/define\s*\(\s*['\"]WP_CACHE['\"]\s*,\s*(.*)\s*\);.*/";
|
927 |
|
928 |
$replace = "define('WP_CACHE',false); // " . $matches[1] . " Changed by WP-Staging";
|
929 |
-
//$replace.= " // Changed by WP-Staging";
|
930 |
|
931 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
932 |
$this->log("Preparing Data: Failed to change WP_CACHE", Logger::TYPE_ERROR);
|
@@ -1118,7 +1105,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1118 |
$table = $this->prefix . 'options';
|
1119 |
|
1120 |
// Skip - Table does not exist
|
1121 |
-
if (false === $this->
|
1122 |
return true;
|
1123 |
}
|
1124 |
|
@@ -1136,76 +1123,31 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1136 |
}
|
1137 |
|
1138 |
/**
|
1139 |
-
*
|
1140 |
* @return bool
|
1141 |
*/
|
1142 |
-
|
1143 |
-
// $this->log( "Preparing Data Step20: Preserve Data in " . $this->prefix . "options" );
|
1144 |
-
//
|
1145 |
-
// // Skip - Table does not exist
|
1146 |
-
// if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
1147 |
-
// return true;
|
1148 |
-
// }
|
1149 |
-
//
|
1150 |
-
// // Skip - Table is not selected or updated
|
1151 |
-
// if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
1152 |
-
// $this->log( "Preparing Data Step20: Skipped" );
|
1153 |
-
// return true;
|
1154 |
-
// }
|
1155 |
-
//
|
1156 |
-
// $sql = '';
|
1157 |
-
//
|
1158 |
-
// $preserved_option_names = array('wpstg_existing_clones_beta');
|
1159 |
-
//
|
1160 |
-
// $preserved_option_names = apply_filters( 'wpstg_preserved_options_cloning', $preserved_option_names );
|
1161 |
-
// $preserved_options_escaped = esc_sql( $preserved_option_names );
|
1162 |
-
//
|
1163 |
-
// $preserved_options_data = array();
|
1164 |
-
//
|
1165 |
-
// // Get preserved data in wp_options tables
|
1166 |
-
// $table = $this->db->prefix . 'options';
|
1167 |
-
// $preserved_options_data[$this->prefix . 'options'] = $this->db->get_results(
|
1168 |
-
// sprintf(
|
1169 |
-
// "SELECT * FROM `{$table}` WHERE `option_name` IN ('%s')", implode( "','", $preserved_options_escaped )
|
1170 |
-
// ), ARRAY_A
|
1171 |
-
// );
|
1172 |
-
//
|
1173 |
-
// // Create preserved data queries for options tables
|
1174 |
-
// foreach ( $preserved_options_data as $key => $value ) {
|
1175 |
-
// if( false === empty( $value ) ) {
|
1176 |
-
// foreach ( $value as $option ) {
|
1177 |
-
// $sql .= $this->db->prepare(
|
1178 |
-
// "DELETE FROM `{$key}` WHERE `option_name` = %s;\n", $option['option_name']
|
1179 |
-
// );
|
1180 |
-
//
|
1181 |
-
// $sql .= $this->db->prepare(
|
1182 |
-
// "INSERT INTO `{$key}` ( `option_id`, `option_name`, `option_value`, `autoload` ) VALUES ( NULL , %s, %s, %s );\n", $option['option_name'], $option['option_value'], $option['autoload']
|
1183 |
-
// );
|
1184 |
-
// }
|
1185 |
-
// }
|
1186 |
-
// }
|
1187 |
-
//
|
1188 |
-
// $this->debugLog( "Preparing Data Step20: Preserve values " . json_encode( $preserved_options_data ), Logger::TYPE_INFO );
|
1189 |
-
//
|
1190 |
-
// $this->executeSql( $sql );
|
1191 |
-
//
|
1192 |
-
// $this->log( "Preparing Data Step20: Successful!" );
|
1193 |
-
// return true;
|
1194 |
-
// }
|
1195 |
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
*/
|
1200 |
-
private function executeSql($sqlbatch)
|
1201 |
-
{
|
1202 |
-
$queries = array_filter(explode(";\n", $sqlbatch));
|
1203 |
|
1204 |
-
|
1205 |
-
|
1206 |
-
$this->log("Data Crunching Warning: Can not execute query {$query}", Logger::TYPE_WARNING);
|
1207 |
-
}
|
1208 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1209 |
return true;
|
1210 |
}
|
1211 |
|
@@ -1235,11 +1177,9 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1235 |
return false;
|
1236 |
}
|
1237 |
|
1238 |
-
$customSlug = str_replace(wpstg_replace_windows_directory_separator(
|
1239 |
-
|
1240 |
-
$newUploadPath = $this->options->destinationDir . $customSlug;
|
1241 |
|
1242 |
-
return $
|
1243 |
}
|
1244 |
|
1245 |
/**
|
@@ -1269,10 +1209,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1269 |
$siteurl = preg_replace('#^https?://#', '', rtrim(get_option('siteurl'), '/'));
|
1270 |
$home = preg_replace('#^https?://#', '', rtrim(get_option('home'), '/'));
|
1271 |
|
1272 |
-
|
1273 |
-
return true;
|
1274 |
-
}
|
1275 |
-
return false;
|
1276 |
}
|
1277 |
|
1278 |
/**
|
@@ -1288,8 +1225,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1288 |
return '';
|
1289 |
}
|
1290 |
|
1291 |
-
|
1292 |
-
return str_replace('/', '', $dir);
|
1293 |
}
|
1294 |
|
1295 |
}
|
79 |
*/
|
80 |
protected function calculateTotalSteps()
|
81 |
{
|
82 |
+
$this->options->totalSteps = 20;
|
83 |
}
|
84 |
|
85 |
/**
|
181 |
* @param string $table
|
182 |
* @return boolean
|
183 |
*/
|
184 |
+
protected function tableExists($table)
|
185 |
{
|
186 |
if ($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table) {
|
187 |
$this->log("Preparing Data: Table {$table} does not exist.", Logger::TYPE_INFO);
|
234 |
|
235 |
/**
|
236 |
* Copy files with symlink support
|
237 |
+
* @param string $source
|
238 |
+
* @param string $destination
|
239 |
* @return boolean
|
240 |
*/
|
241 |
protected function copy($source, $destination)
|
262 |
|
263 |
/**
|
264 |
* Make sure wp-config.php contains correct db credentials
|
265 |
+
* @param string $source
|
266 |
* @return boolean
|
267 |
*/
|
268 |
protected function alterWpConfig($source)
|
269 |
{
|
|
|
270 |
|
271 |
if (false === ($content = file_get_contents($source))) {
|
272 |
return false;
|
299 |
|
300 |
/**
|
301 |
* Check if wp-config.php contains important constants
|
302 |
+
* @param string $source
|
303 |
* @return boolean
|
304 |
*/
|
305 |
protected function isValidWpConfig($source)
|
309 |
return false;
|
310 |
}
|
311 |
|
|
|
|
|
312 |
if (false === ($content = file_get_contents($source))) {
|
313 |
return false;
|
314 |
}
|
352 |
$this->log("Preparing Data Step1: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO);
|
353 |
|
354 |
// Skip - Table does not exist
|
355 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
356 |
return true;
|
357 |
}
|
358 |
// Skip - Table is not selected or updated
|
389 |
$this->log("Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}");
|
390 |
|
391 |
// Skip - Table does not exist
|
392 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
393 |
$this->log("Preparing Data Step2: Skipping");
|
394 |
return true;
|
395 |
}
|
399 |
return true;
|
400 |
}
|
401 |
|
402 |
+
$this->db->query(
|
403 |
$this->db->prepare(
|
404 |
"DELETE FROM `{$this->prefix}options` WHERE `option_name` = %s;", 'wpstg_is_staging_site'
|
405 |
)
|
407 |
|
408 |
|
409 |
// No errors but no option name such as wpstg_is_staging_site
|
|
|
410 |
$insert = $this->db->query(
|
411 |
$this->db->prepare(
|
412 |
"INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_is_staging_site',%s)", "true"
|
413 |
)
|
414 |
);
|
415 |
+
|
416 |
// All good
|
417 |
if ($insert) {
|
418 |
$this->log("Preparing Data Step2: Successful", Logger::TYPE_INFO);
|
439 |
}
|
440 |
|
441 |
// Skip - Table does not exist
|
442 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
443 |
$this->log("Preparing Data Step3: Skipping");
|
444 |
return true;
|
445 |
}
|
474 |
$this->log("Preparing Data Step4: Updating db prefix in {$this->prefix}usermeta. ");
|
475 |
|
476 |
// Skip - Table does not exist
|
477 |
+
if (false === $this->tableExists($this->prefix . 'usermeta')) {
|
478 |
return true;
|
479 |
}
|
480 |
|
530 |
$content = str_replace($this->homeUrl, $this->getStagingSiteUrl(), $content);
|
531 |
|
532 |
if (false === @wpstg_put_contents($path, $content)) {
|
533 |
+
$this->log("Preparing Data Step5: Failed to update table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR);
|
534 |
return false;
|
535 |
}
|
536 |
|
602 |
$this->log("Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}");
|
603 |
|
604 |
// Skip - Table does not exist
|
605 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
606 |
$this->log("Preparing Data Step7: Skipping Table {$this->prefix}'options' does not exist");
|
607 |
return true;
|
608 |
}
|
645 |
}
|
646 |
|
647 |
// Skip - Table does not exist
|
648 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
649 |
$this->log("Preparing Data Step8: Skipping");
|
650 |
return true;
|
651 |
}
|
681 |
|
682 |
$this->log("Preparing Data Step9: Set staging site to noindex");
|
683 |
|
684 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
685 |
return true;
|
686 |
}
|
687 |
|
732 |
$pattern = "/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*(.*)\s*\);.*/";
|
733 |
|
734 |
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1] . " Changed by WP-Staging";
|
|
|
735 |
|
736 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
737 |
$this->log("Preparing Data: Failed to update WP_HOME", Logger::TYPE_ERROR);
|
774 |
$pattern = "/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*(.*)\s*\);.*/";
|
775 |
|
776 |
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1] . " Changed by WP-Staging";
|
|
|
777 |
|
778 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
779 |
$this->log("Preparing Data Step11: Failed to update WP_SITEURL to " . $this->getStagingSiteUrl(), Logger::TYPE_ERROR);
|
801 |
$this->log("Preparing Data Step12: Updating db prefix in {$this->prefix}options.");
|
802 |
|
803 |
// Skip - Table does not exist
|
804 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
805 |
return true;
|
806 |
}
|
807 |
|
811 |
return true;
|
812 |
}
|
813 |
|
|
|
814 |
|
815 |
// Filter the rows below. Do not update them!
|
816 |
$filters = array(
|
854 |
$this->log("Preparing Data Step13: Updating upload_path {$this->prefix}options.");
|
855 |
|
856 |
// Skip - Table does not exist
|
857 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
858 |
return true;
|
859 |
}
|
860 |
|
875 |
|
876 |
$this->log("Updating upload_path in {$this->prefix}options. {$error}");
|
877 |
|
|
|
|
|
|
|
|
|
|
|
878 |
// remove upload_path value and use UPLOADS constant instead. (upload_path is deprecated and should not be used any longer)
|
879 |
$updateOptions = $this->db->query(
|
880 |
$this->db->prepare(
|
914 |
$pattern = "/define\s*\(\s*['\"]WP_CACHE['\"]\s*,\s*(.*)\s*\);.*/";
|
915 |
|
916 |
$replace = "define('WP_CACHE',false); // " . $matches[1] . " Changed by WP-Staging";
|
|
|
917 |
|
918 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
919 |
$this->log("Preparing Data: Failed to change WP_CACHE", Logger::TYPE_ERROR);
|
1105 |
$table = $this->prefix . 'options';
|
1106 |
|
1107 |
// Skip - Table does not exist
|
1108 |
+
if (false === $this->tableExists($table)) {
|
1109 |
return true;
|
1110 |
}
|
1111 |
|
1123 |
}
|
1124 |
|
1125 |
/**
|
1126 |
+
* Delete all listed staging sites from cloned site in initial cloning. Useful if a cloned site is cloned again. E.g. for dev > staging > production setup
|
1127 |
* @return bool
|
1128 |
*/
|
1129 |
+
protected function step20(){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1130 |
|
1131 |
+
if ($this->options->mainJob === 'updating'){
|
1132 |
+
return true;
|
1133 |
+
}
|
|
|
|
|
|
|
|
|
1134 |
|
1135 |
+
if( false === $this->tableExists( $this->prefix . 'options' ) ) {
|
1136 |
+
return true;
|
|
|
|
|
1137 |
}
|
1138 |
+
|
1139 |
+
$step = "Preparing Data Step20:";
|
1140 |
+
$this->log( $step . " Reset wp staging site data" );
|
1141 |
+
|
1142 |
+
$result = $this->db->query(
|
1143 |
+
$this->db->prepare( "UPDATE {$this->prefix}options SET `option_value` = %s WHERE `option_name` = %s", serialize(array()), 'wpstg_existing_clones_beta'
|
1144 |
+
)
|
1145 |
+
);
|
1146 |
+
|
1147 |
+
if (false === $result){
|
1148 |
+
$this->log( $step . "Failed to reset wp staging site data." );
|
1149 |
+
}
|
1150 |
+
|
1151 |
return true;
|
1152 |
}
|
1153 |
|
1177 |
return false;
|
1178 |
}
|
1179 |
|
1180 |
+
$customSlug = str_replace(wpstg_replace_windows_directory_separator(WPStaging::getWPpath()), '', wpstg_replace_windows_directory_separator($uploadPath));
|
|
|
|
|
1181 |
|
1182 |
+
return $this->options->destinationDir . $customSlug;
|
1183 |
}
|
1184 |
|
1185 |
/**
|
1209 |
$siteurl = preg_replace('#^https?://#', '', rtrim(get_option('siteurl'), '/'));
|
1210 |
$home = preg_replace('#^https?://#', '', rtrim(get_option('home'), '/'));
|
1211 |
|
1212 |
+
return $home !== $siteurl;
|
|
|
|
|
|
|
1213 |
}
|
1214 |
|
1215 |
/**
|
1225 |
return '';
|
1226 |
}
|
1227 |
|
1228 |
+
return str_replace(array($home, '/'), '', $siteurl);
|
|
|
1229 |
}
|
1230 |
|
1231 |
}
|
Backend/Modules/Jobs/DataExternal.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
|
5 |
// No Direct Access
|
6 |
-
if(
|
7 |
die;
|
8 |
}
|
9 |
|
@@ -16,7 +16,8 @@ use WPStaging\Utils\Strings;
|
|
16 |
* Class Data
|
17 |
* @package WPStaging\Backend\Modules\Jobs
|
18 |
*/
|
19 |
-
class DataExternal extends JobExecutable
|
|
|
20 |
|
21 |
/**
|
22 |
* @var \wpdb
|
@@ -43,19 +44,20 @@ class DataExternal extends JobExecutable {
|
|
43 |
/**
|
44 |
* Initialize
|
45 |
*/
|
46 |
-
public function initialize()
|
47 |
-
|
48 |
-
$this->
|
49 |
-
$this->
|
50 |
-
$this->
|
|
|
51 |
|
52 |
$this->getTables();
|
53 |
|
54 |
-
$helper
|
55 |
$this->homeUrl = $helper->get_home_url();
|
56 |
|
57 |
// Fix current step
|
58 |
-
if(
|
59 |
$this->options->currentStep = 0;
|
60 |
}
|
61 |
}
|
@@ -63,18 +65,20 @@ class DataExternal extends JobExecutable {
|
|
63 |
/**
|
64 |
* Get database object to interact with
|
65 |
*/
|
66 |
-
private function getStagingDB()
|
67 |
-
|
|
|
68 |
}
|
69 |
|
70 |
/**
|
71 |
* Get a list of tables to copy
|
72 |
*/
|
73 |
-
private function getTables()
|
74 |
-
|
|
|
75 |
$this->tables = array();
|
76 |
-
foreach (
|
77 |
-
$this->tables[] = $this->options->prefix . $strings->str_replace_first(
|
78 |
}
|
79 |
}
|
80 |
|
@@ -82,7 +86,8 @@ class DataExternal extends JobExecutable {
|
|
82 |
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
83 |
* @return void
|
84 |
*/
|
85 |
-
protected function calculateTotalSteps()
|
|
|
86 |
$this->options->totalSteps = 20;
|
87 |
}
|
88 |
|
@@ -90,14 +95,15 @@ class DataExternal extends JobExecutable {
|
|
90 |
* Start Module
|
91 |
* @return object
|
92 |
*/
|
93 |
-
public function start()
|
|
|
94 |
// Execute steps
|
95 |
$this->run();
|
96 |
|
97 |
// Save option, progress
|
98 |
$this->saveOptions();
|
99 |
|
100 |
-
return ( object )
|
101 |
}
|
102 |
|
103 |
/**
|
@@ -105,30 +111,31 @@ class DataExternal extends JobExecutable {
|
|
105 |
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
106 |
* @return bool
|
107 |
*/
|
108 |
-
protected function execute()
|
|
|
109 |
// Fatal error. Let this happen never and break here immediately
|
110 |
-
if(
|
111 |
return false;
|
112 |
}
|
113 |
|
114 |
// Over limits threshold
|
115 |
-
if(
|
116 |
// Prepare response and save current progress
|
117 |
-
$this->prepareResponse(
|
118 |
$this->saveOptions();
|
119 |
return false;
|
120 |
}
|
121 |
|
122 |
// No more steps, finished
|
123 |
-
if(
|
124 |
-
$this->prepareResponse(
|
125 |
return false;
|
126 |
}
|
127 |
|
128 |
// Execute step
|
129 |
$stepMethodName = "step" . $this->options->currentStep;
|
130 |
-
if(
|
131 |
-
$this->prepareResponse(
|
132 |
return false;
|
133 |
}
|
134 |
|
@@ -143,19 +150,20 @@ class DataExternal extends JobExecutable {
|
|
143 |
* Checks Whether There is Any Job to Execute or Not
|
144 |
* @return bool
|
145 |
*/
|
146 |
-
protected function isFinished()
|
|
|
147 |
return
|
148 |
!$this->isRunning() ||
|
149 |
$this->options->currentStep > $this->options->totalSteps ||
|
150 |
-
!method_exists($this, "step" . $this->options->currentStep)
|
151 |
-
;
|
152 |
}
|
153 |
|
154 |
/**
|
155 |
* Check if current operation is done on the root folder or on the live DB
|
156 |
* @return boolean
|
157 |
*/
|
158 |
-
protected function isRoot()
|
|
|
159 |
|
160 |
// Prefix is the same as the one of live site
|
161 |
// $wpdb = WPStaging::getInstance()->get( "wpdb" );
|
@@ -163,13 +171,13 @@ class DataExternal extends JobExecutable {
|
|
163 |
// return true;
|
164 |
// }
|
165 |
// CloneName is empty
|
166 |
-
$name = ( array )
|
167 |
-
if(
|
168 |
return true;
|
169 |
}
|
170 |
|
171 |
// Live Path === Staging path
|
172 |
-
if(
|
173 |
return true;
|
174 |
}
|
175 |
|
@@ -181,9 +189,10 @@ class DataExternal extends JobExecutable {
|
|
181 |
* @param string $table
|
182 |
* @return boolean
|
183 |
*/
|
184 |
-
protected function
|
185 |
-
|
186 |
-
|
|
|
187 |
return false;
|
188 |
}
|
189 |
return true;
|
@@ -194,39 +203,40 @@ class DataExternal extends JobExecutable {
|
|
194 |
* copy default wp-config.php if production site uses bedrock or any other boilerplate solution that stores wp default config data elsewhere.
|
195 |
* @return boolean
|
196 |
*/
|
197 |
-
protected function step0()
|
198 |
-
|
|
|
199 |
|
200 |
-
$dir = trailingslashit(
|
201 |
|
202 |
$source = $dir . 'wp-config.php';
|
203 |
|
204 |
$destination = $this->options->destinationDir . 'wp-config.php';
|
205 |
|
206 |
// Check if there is already a valid wp-config.php in root of staging site
|
207 |
-
if(
|
208 |
return true;
|
209 |
}
|
210 |
|
211 |
// Check if there is a valid wp-config.php outside root of wp production site
|
212 |
-
if(
|
213 |
// Copy it to staging site
|
214 |
-
if(
|
215 |
return true;
|
216 |
}
|
217 |
}
|
218 |
|
219 |
// No valid wp-config.php found so let's copy wp stagings default wp-config.php to staging site
|
220 |
$source = WPSTG_PLUGIN_DIR . "Backend/helpers/wp-config.php";
|
221 |
-
if(
|
222 |
// add missing db credentials to wp-config.php
|
223 |
-
if(
|
224 |
-
$this->log(
|
225 |
return false;
|
226 |
}
|
227 |
}
|
228 |
|
229 |
-
$this->log(
|
230 |
return true;
|
231 |
}
|
232 |
|
@@ -236,21 +246,22 @@ class DataExternal extends JobExecutable {
|
|
236 |
* @param type $destination
|
237 |
* @return boolean
|
238 |
*/
|
239 |
-
protected function copy(
|
|
|
240 |
// Copy symbolic link
|
241 |
-
if(
|
242 |
-
$this->log(
|
243 |
-
if(
|
244 |
$errors = error_get_last();
|
245 |
-
$this->log(
|
246 |
return false;
|
247 |
}
|
248 |
}
|
249 |
|
250 |
// Copy file
|
251 |
-
if(
|
252 |
$errors = error_get_last();
|
253 |
-
$this->log(
|
254 |
return false;
|
255 |
}
|
256 |
|
@@ -262,10 +273,10 @@ class DataExternal extends JobExecutable {
|
|
262 |
* @param type $source
|
263 |
* @return boolean
|
264 |
*/
|
265 |
-
protected function alterWpConfig(
|
266 |
-
|
267 |
|
268 |
-
if(
|
269 |
return false;
|
270 |
}
|
271 |
|
@@ -284,10 +295,10 @@ define( 'DB_CHARSET', '" . DB_CHARSET . "' );\r\n
|
|
284 |
/** The Database Collate type. Don't change this if in doubt. */\r\n
|
285 |
define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
286 |
|
287 |
-
$content = str_replace(
|
288 |
|
289 |
-
if(
|
290 |
-
$this->log(
|
291 |
return false;
|
292 |
}
|
293 |
|
@@ -299,43 +310,43 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
299 |
* @param type $source
|
300 |
* @return boolean
|
301 |
*/
|
302 |
-
protected function isValidWpConfig(
|
|
|
303 |
|
304 |
-
if(
|
305 |
return false;
|
306 |
}
|
307 |
|
308 |
-
$content = file_get_contents( $source );
|
309 |
|
310 |
-
if(
|
311 |
return false;
|
312 |
}
|
313 |
|
314 |
// Get DB_NAME from wp-config.php
|
315 |
-
preg_match(
|
316 |
|
317 |
-
if(
|
318 |
return false;
|
319 |
}
|
320 |
|
321 |
// Get DB_USER from wp-config.php
|
322 |
-
preg_match(
|
323 |
|
324 |
-
if(
|
325 |
return false;
|
326 |
}
|
327 |
|
328 |
// Get DB_PASSWORD from wp-config.php
|
329 |
-
preg_match(
|
330 |
|
331 |
-
if(
|
332 |
return false;
|
333 |
}
|
334 |
|
335 |
// Get DB_HOST from wp-config.php
|
336 |
-
preg_match(
|
337 |
|
338 |
-
if(
|
339 |
return false;
|
340 |
}
|
341 |
return true;
|
@@ -345,35 +356,35 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
345 |
* Replace "siteurl" and "home"
|
346 |
* @return bool
|
347 |
*/
|
348 |
-
protected function step1()
|
349 |
-
|
|
|
350 |
|
351 |
// Skip - Table does not exist
|
352 |
-
if(
|
353 |
return true;
|
354 |
}
|
355 |
// Skip - Table is not selected or updated
|
356 |
-
if(
|
357 |
-
$this->log(
|
358 |
return true;
|
359 |
}
|
360 |
|
361 |
-
$this->log(
|
362 |
// Replace URLs
|
363 |
$result = $this->db->query(
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
);
|
368 |
|
369 |
|
370 |
-
|
371 |
// All good
|
372 |
-
if(
|
373 |
return true;
|
374 |
}
|
375 |
|
376 |
-
$this->log(
|
377 |
return true;
|
378 |
}
|
379 |
|
@@ -381,42 +392,43 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
381 |
* Update "wpstg_is_staging_site"
|
382 |
* @return bool
|
383 |
*/
|
384 |
-
protected function step2()
|
|
|
385 |
|
386 |
-
$this->log(
|
387 |
|
388 |
// Skip - Table does not exist
|
389 |
-
if(
|
390 |
-
$this->log(
|
391 |
return true;
|
392 |
}
|
393 |
// Skip - Table is not selected or updated
|
394 |
-
if(
|
395 |
-
$this->log(
|
396 |
return true;
|
397 |
}
|
398 |
|
399 |
-
$
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
);
|
404 |
|
405 |
|
406 |
// No errors but no option name such as wpstg_is_staging_site
|
407 |
$insert = $this->db->query(
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
);
|
412 |
|
413 |
// All good
|
414 |
-
if(
|
415 |
-
$this->log(
|
416 |
return true;
|
417 |
}
|
418 |
|
419 |
-
$this->log(
|
420 |
return false;
|
421 |
}
|
422 |
|
@@ -424,36 +436,37 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
424 |
* Update rewrite_rules
|
425 |
* @return bool
|
426 |
*/
|
427 |
-
protected function step3()
|
|
|
428 |
|
429 |
-
$this->log(
|
430 |
|
431 |
// Keep Permalinks
|
432 |
-
if(
|
433 |
-
$this->log(
|
434 |
return true;
|
435 |
}
|
436 |
|
437 |
// Skip - Table does not exist
|
438 |
-
if(
|
439 |
-
$this->log(
|
440 |
return true;
|
441 |
}
|
442 |
|
443 |
// Skip - Table is not selected or updated
|
444 |
-
if(
|
445 |
-
$this->log(
|
446 |
return true;
|
447 |
}
|
448 |
|
449 |
$result = $this->db->query(
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
);
|
454 |
|
455 |
// All good
|
456 |
-
if(
|
457 |
return true;
|
458 |
}
|
459 |
|
@@ -465,36 +478,35 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
465 |
* Update Table Prefix in wp_usermeta and wp_options
|
466 |
* @return bool
|
467 |
*/
|
468 |
-
protected function step4()
|
469 |
-
|
|
|
470 |
|
471 |
// Skip - Table does not exist
|
472 |
-
if(
|
473 |
return true;
|
474 |
}
|
475 |
|
476 |
// Skip - Table is not selected or updated
|
477 |
-
if(
|
478 |
-
$this->log(
|
479 |
return true;
|
480 |
}
|
481 |
|
482 |
|
483 |
-
|
484 |
$update = $this->db->query(
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
);
|
489 |
|
490 |
-
if(
|
491 |
-
$this->log(
|
492 |
-
$this->returnException(
|
493 |
return false;
|
494 |
}
|
495 |
|
496 |
|
497 |
-
|
498 |
return true;
|
499 |
}
|
500 |
|
@@ -502,30 +514,31 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
502 |
* Update Table prefix in wp-config.php
|
503 |
* @return bool
|
504 |
*/
|
505 |
-
protected function step5()
|
|
|
506 |
$path = $this->options->destinationDir . "wp-config.php";
|
507 |
|
508 |
-
$this->log(
|
509 |
-
if(
|
510 |
-
$this->log(
|
511 |
return false;
|
512 |
}
|
513 |
|
514 |
// Replace table prefix
|
515 |
-
$pattern
|
516 |
$replacement = '$table_prefix = \'' . $this->prefix . '\'; // Changed by WP Staging';
|
517 |
-
$content
|
518 |
|
519 |
-
if(
|
520 |
-
$this->log(
|
521 |
return false;
|
522 |
}
|
523 |
|
524 |
// Replace URLs
|
525 |
-
$content = str_replace(
|
526 |
|
527 |
-
if(
|
528 |
-
$this->log(
|
529 |
return false;
|
530 |
}
|
531 |
|
@@ -591,30 +604,31 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
591 |
* Update wpstg_rmpermalinks_executed
|
592 |
* @return bool
|
593 |
*/
|
594 |
-
protected function step7()
|
|
|
595 |
|
596 |
-
$this->log(
|
597 |
|
598 |
// Skip - Table does not exist
|
599 |
-
if(
|
600 |
-
$this->log(
|
601 |
return true;
|
602 |
}
|
603 |
|
604 |
// Skip - Table is not selected or updated
|
605 |
-
if(
|
606 |
-
$this->log(
|
607 |
return true;
|
608 |
}
|
609 |
|
610 |
$result = $this->db->query(
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
);
|
615 |
|
616 |
|
617 |
-
$this->Log(
|
618 |
return true;
|
619 |
}
|
620 |
|
@@ -622,41 +636,42 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
622 |
* Update permalink_structure
|
623 |
* @return bool
|
624 |
*/
|
625 |
-
protected function step8()
|
|
|
626 |
|
627 |
-
$this->log(
|
628 |
|
629 |
// Keep Permalinks
|
630 |
-
if(
|
631 |
-
$this->log(
|
632 |
return true;
|
633 |
}
|
634 |
|
635 |
// Skip - Table does not exist
|
636 |
-
if(
|
637 |
-
$this->log(
|
638 |
return true;
|
639 |
}
|
640 |
|
641 |
// Skip - Table is not selected or updated
|
642 |
-
if(
|
643 |
-
$this->log(
|
644 |
return true;
|
645 |
}
|
646 |
|
647 |
$result = $this->db->query(
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
);
|
652 |
|
653 |
// All good
|
654 |
-
if(
|
655 |
-
$this->Log(
|
656 |
return true;
|
657 |
}
|
658 |
|
659 |
-
$this->log(
|
660 |
return true;
|
661 |
}
|
662 |
|
@@ -664,33 +679,34 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
664 |
* Update blog_public option to not allow staging site to be indexed by search engines
|
665 |
* @return bool
|
666 |
*/
|
667 |
-
protected function step9()
|
|
|
668 |
|
669 |
-
$this->log(
|
670 |
|
671 |
-
if(
|
672 |
return true;
|
673 |
}
|
674 |
|
675 |
// Skip - Table is not selected or updated
|
676 |
-
if(
|
677 |
-
$this->log(
|
678 |
return true;
|
679 |
}
|
680 |
|
681 |
$result = $this->db->query(
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
);
|
686 |
|
687 |
// All good
|
688 |
-
if(
|
689 |
-
$this->Log(
|
690 |
return true;
|
691 |
}
|
692 |
|
693 |
-
$this->log(
|
694 |
return true;
|
695 |
}
|
696 |
|
@@ -698,21 +714,22 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
698 |
* Update WP_HOME in wp-config.php
|
699 |
* @return bool
|
700 |
*/
|
701 |
-
protected function step10()
|
|
|
702 |
$path = $this->options->destinationDir . "wp-config.php";
|
703 |
|
704 |
-
$this->log(
|
705 |
|
706 |
-
if(
|
707 |
-
$this->log(
|
708 |
return false;
|
709 |
}
|
710 |
|
711 |
|
712 |
// Get WP_HOME from wp-config.php
|
713 |
-
preg_match(
|
714 |
|
715 |
-
if(
|
716 |
$matches[1];
|
717 |
|
718 |
$pattern = "/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*(.*)\s*\);.*/";
|
@@ -720,19 +737,19 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
720 |
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
721 |
//$replace.= " // Changed by WP-Staging";
|
722 |
|
723 |
-
if(
|
724 |
-
$this->log(
|
725 |
return false;
|
726 |
}
|
727 |
} else {
|
728 |
-
$this->log(
|
729 |
}
|
730 |
|
731 |
-
if(
|
732 |
-
$this->log(
|
733 |
return false;
|
734 |
}
|
735 |
-
$this->Log(
|
736 |
return true;
|
737 |
}
|
738 |
|
@@ -740,21 +757,22 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
740 |
* Update WP_SITEURL in wp-config.php
|
741 |
* @return bool
|
742 |
*/
|
743 |
-
protected function step11()
|
|
|
744 |
$path = $this->options->destinationDir . "wp-config.php";
|
745 |
|
746 |
-
$this->log(
|
747 |
|
748 |
-
if(
|
749 |
-
$this->log(
|
750 |
return false;
|
751 |
}
|
752 |
|
753 |
|
754 |
// Get WP_SITEURL from wp-config.php
|
755 |
-
preg_match(
|
756 |
|
757 |
-
if(
|
758 |
$matches[1];
|
759 |
|
760 |
$pattern = "/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*(.*)\s*\);.*/";
|
@@ -762,114 +780,50 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
762 |
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
763 |
//$replace.= " // Changed by WP-Staging";
|
764 |
|
765 |
-
if(
|
766 |
-
$this->log(
|
767 |
return false;
|
768 |
}
|
769 |
} else {
|
770 |
-
$this->log(
|
771 |
}
|
772 |
|
773 |
|
774 |
-
if(
|
775 |
-
$this->log(
|
776 |
return false;
|
777 |
}
|
778 |
-
$this->Log(
|
779 |
return true;
|
780 |
}
|
781 |
|
782 |
-
/**
|
783 |
-
* Set true WP_DEBUG & WP_DEBUG_DISPLAY in wp-config.php
|
784 |
-
* @return bool
|
785 |
-
*/
|
786 |
-
// protected function step12() {
|
787 |
-
// $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
788 |
-
//
|
789 |
-
// $this->log( "Preparing Data Step12: Set WP_DEBUG to true in wp-config.php." );
|
790 |
-
//
|
791 |
-
// if( false === ($content = file_get_contents( $path )) ) {
|
792 |
-
// $this->log( "Preparing Data Step12: Failed to update WP_DEBUG in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
793 |
-
// return false;
|
794 |
-
// }
|
795 |
-
//
|
796 |
-
//
|
797 |
-
// // Get WP_DEBUG from wp-config.php
|
798 |
-
// preg_match( "/define\s*\(\s*'WP_DEBUG'\s*,\s*(.*)\s*\);/", $content, $matches );
|
799 |
-
//
|
800 |
-
// // Found it!
|
801 |
-
// if( !empty( $matches[1] ) ) {
|
802 |
-
// $matches[1];
|
803 |
-
//
|
804 |
-
// $pattern = "/define\s*\(\s*'WP_DEBUG'\s*,\s*(.*)\s*\);/";
|
805 |
-
//
|
806 |
-
// $replace = "define('WP_DEBUG',true); // " . $matches[1];
|
807 |
-
// $replace.= " // Changed by WP-Staging";
|
808 |
-
//
|
809 |
-
// if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
810 |
-
// $this->log( "Preparing Data Step12: Failed to update WP_DEBUG", Logger::TYPE_ERROR );
|
811 |
-
// return false;
|
812 |
-
// }
|
813 |
-
// } else {
|
814 |
-
// $this->log( "Preparing Data Step12: WP_DEBUG not defined in wp-config.php. Skip it." );
|
815 |
-
// }
|
816 |
-
//
|
817 |
-
//
|
818 |
-
//
|
819 |
-
// // Get WP_DEBUG_DISPLAY
|
820 |
-
// preg_match( "/define\s*\(\s*'WP_DEBUG_DISPLAY'\s*,\s*(.*)\s*\);/", $content, $matches );
|
821 |
-
//
|
822 |
-
// // Found it!
|
823 |
-
// if( !empty( $matches[1] ) ) {
|
824 |
-
// $matches[1];
|
825 |
-
//
|
826 |
-
// $pattern = "/define\s*\(\s*'WP_DEBUG_DISPLAY'\s*,\s*(.*)\s*\);/";
|
827 |
-
//
|
828 |
-
// $replace = "define('WP_DEBUG_DISPLAY',true); // " . $matches[1];
|
829 |
-
// $replace.= " // Changed by WP-Staging";
|
830 |
-
//
|
831 |
-
// if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
832 |
-
// $this->log( "Preparing Data Step12: Failed to update WP_DEBUG", Logger::TYPE_ERROR );
|
833 |
-
// return false;
|
834 |
-
// }
|
835 |
-
// } else {
|
836 |
-
// $this->log( "Preparing Data Step12: WP_DEBUG not defined in wp-config.php. Skip it." );
|
837 |
-
// }
|
838 |
-
//
|
839 |
-
//
|
840 |
-
// if( false === @wpstg_put_contents( $path, $content ) ) {
|
841 |
-
// $this->log( "Preparing Data Step12: Failed to update WP_DEBUG. Can't save content in wp-config.php", Logger::TYPE_ERROR );
|
842 |
-
// return false;
|
843 |
-
// }
|
844 |
-
// $this->Log( "Preparing Data: Finished Step 12 successfully" );
|
845 |
-
// return true;
|
846 |
-
// }
|
847 |
|
848 |
/**
|
849 |
* Update Table Prefix in wp_options
|
850 |
* @return bool
|
851 |
*/
|
852 |
-
protected function step12()
|
853 |
-
|
|
|
854 |
|
855 |
// Skip - Table does not exist
|
856 |
-
if(
|
857 |
return true;
|
858 |
}
|
859 |
|
860 |
// Skip, prefixes are identical. No change needed
|
861 |
-
if(
|
862 |
-
$this->log(
|
863 |
return true;
|
864 |
}
|
865 |
|
866 |
// Skip - Table is not selected or updated
|
867 |
-
if(
|
868 |
-
$this->log(
|
869 |
return true;
|
870 |
}
|
871 |
|
872 |
-
$notice = !empty(
|
873 |
|
874 |
//$this->log( "Updating option_name in {$this->prefix}options. {$notice}" );
|
875 |
// Filter the rows below. Do not update them!
|
@@ -879,25 +833,25 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
879 |
'wp_mail_smtp_debug',
|
880 |
);
|
881 |
|
882 |
-
$filters = apply_filters(
|
883 |
|
884 |
$where = "";
|
885 |
-
foreach (
|
886 |
$where .= " AND option_name <> '" . $filter . "'";
|
887 |
}
|
888 |
|
889 |
$updateOptions = $this->db->query(
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
);
|
894 |
|
895 |
-
if(
|
896 |
-
$this->log(
|
897 |
-
$this->returnException(
|
898 |
return false;
|
899 |
}
|
900 |
-
$this->Log(
|
901 |
return true;
|
902 |
}
|
903 |
|
@@ -905,42 +859,43 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
905 |
* Change upload_path in wp_options (if it is defined)
|
906 |
* @return bool
|
907 |
*/
|
908 |
-
protected function step13()
|
909 |
-
|
|
|
910 |
|
911 |
// Skip - Table does not exist
|
912 |
-
if(
|
913 |
return true;
|
914 |
}
|
915 |
|
916 |
$newUploadPath = $this->getNewUploadPath();
|
917 |
|
918 |
-
if(
|
919 |
-
$this->log(
|
920 |
return true;
|
921 |
}
|
922 |
|
923 |
// Skip - Table is not selected or updated
|
924 |
-
if(
|
925 |
-
$this->log(
|
926 |
return true;
|
927 |
}
|
928 |
|
929 |
-
$error = isset(
|
930 |
|
931 |
-
$this->log(
|
932 |
|
933 |
$updateOptions = $this->db->query(
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
);
|
938 |
|
939 |
-
if(
|
940 |
-
$this->log(
|
941 |
return true;
|
942 |
}
|
943 |
-
$this->Log(
|
944 |
return true;
|
945 |
}
|
946 |
|
@@ -948,40 +903,41 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
948 |
* Update WP_CACHE in wp-config.php
|
949 |
* @return bool
|
950 |
*/
|
951 |
-
protected function step14()
|
|
|
952 |
$path = $this->options->destinationDir . "wp-config.php";
|
953 |
|
954 |
-
$this->log(
|
955 |
|
956 |
-
if(
|
957 |
-
$this->log(
|
958 |
return false;
|
959 |
}
|
960 |
|
961 |
|
962 |
// Get WP_CACHE from wp-config.php
|
963 |
-
preg_match(
|
964 |
|
965 |
-
if(
|
966 |
|
967 |
$pattern = "/define\s*\(\s*['\"]WP_CACHE['\"]\s*,\s*(.*)\s*\);.*/";
|
968 |
|
969 |
$replace = "define('WP_CACHE',false); // " . $matches[1];
|
970 |
//$replace.= " // Changed by WP-Staging";
|
971 |
|
972 |
-
if(
|
973 |
-
$this->log(
|
974 |
return false;
|
975 |
}
|
976 |
} else {
|
977 |
-
$this->log(
|
978 |
}
|
979 |
|
980 |
-
if(
|
981 |
-
$this->log(
|
982 |
return false;
|
983 |
}
|
984 |
-
$this->Log(
|
985 |
return true;
|
986 |
}
|
987 |
|
@@ -989,21 +945,22 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
989 |
* Update database credentials in wp-config.php
|
990 |
* @return bool
|
991 |
*/
|
992 |
-
protected function step15()
|
|
|
993 |
$path = $this->options->destinationDir . "wp-config.php";
|
994 |
|
995 |
-
$this->log(
|
996 |
|
997 |
-
if(
|
998 |
-
$this->log(
|
999 |
return false;
|
1000 |
}
|
1001 |
|
1002 |
|
1003 |
// Get DB_NAME from wp-config.php
|
1004 |
-
preg_match(
|
1005 |
|
1006 |
-
if(
|
1007 |
$matches[1];
|
1008 |
|
1009 |
$pattern = "/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*(.*)\s*\);.*/";
|
@@ -1011,17 +968,17 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1011 |
$replace = "define('DB_NAME','{$this->options->databaseDatabase}'); // " . $matches[1];
|
1012 |
//$replace.= " // Changed by WP-Staging";
|
1013 |
|
1014 |
-
if(
|
1015 |
-
$this->log(
|
1016 |
return false;
|
1017 |
}
|
1018 |
} else {
|
1019 |
-
$this->log(
|
1020 |
}
|
1021 |
// Get DB_USER from wp-config.php
|
1022 |
-
preg_match(
|
1023 |
|
1024 |
-
if(
|
1025 |
$matches[1];
|
1026 |
|
1027 |
$pattern = "/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*(.*)\s*\);.*/";
|
@@ -1029,35 +986,39 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1029 |
$replace = "define('DB_USER','{$this->options->databaseUser}'); // " . $matches[1];
|
1030 |
//$replace.= " // Changed by WP-Staging";
|
1031 |
|
1032 |
-
if(
|
1033 |
-
$this->log(
|
1034 |
return false;
|
1035 |
}
|
1036 |
} else {
|
1037 |
-
$this->log(
|
1038 |
}
|
1039 |
// Get DB_PASSWORD from wp-config.php
|
1040 |
-
preg_match(
|
1041 |
|
1042 |
-
if(
|
1043 |
$matches[1];
|
1044 |
|
1045 |
$pattern = "/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*(.*)\s*\);.*/";
|
1046 |
|
1047 |
-
|
|
|
|
|
|
|
|
|
1048 |
//$replace.= " // Changed by WP-Staging";
|
1049 |
|
1050 |
-
if(
|
1051 |
-
$this->log(
|
1052 |
return false;
|
1053 |
}
|
1054 |
} else {
|
1055 |
-
$this->log(
|
1056 |
}
|
1057 |
// Get DB_HOST from wp-config.php
|
1058 |
-
preg_match(
|
1059 |
|
1060 |
-
if(
|
1061 |
$matches[1];
|
1062 |
|
1063 |
$pattern = "/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*(.*)\s*\);.*/";
|
@@ -1065,20 +1026,20 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1065 |
$replace = "define('DB_HOST','{$this->options->databaseServer}'); // " . $matches[1];
|
1066 |
//$replace.= " // Changed by WP-Staging";
|
1067 |
|
1068 |
-
if(
|
1069 |
-
$this->log(
|
1070 |
return false;
|
1071 |
}
|
1072 |
} else {
|
1073 |
-
$this->log(
|
1074 |
}
|
1075 |
|
1076 |
|
1077 |
-
if(
|
1078 |
-
$this->log(
|
1079 |
return false;
|
1080 |
}
|
1081 |
-
$this->Log(
|
1082 |
return true;
|
1083 |
}
|
1084 |
|
@@ -1086,39 +1047,40 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1086 |
* Remove UPLOADS constant in wp-config.php to reset default image folder
|
1087 |
* @return bool
|
1088 |
*/
|
1089 |
-
protected function step16()
|
|
|
1090 |
$path = $this->options->destinationDir . "wp-config.php";
|
1091 |
|
1092 |
-
$this->log(
|
1093 |
|
1094 |
-
if(
|
1095 |
-
$this->log(
|
1096 |
return false;
|
1097 |
}
|
1098 |
|
1099 |
|
1100 |
// Get UPLOADS from wp-config.php
|
1101 |
-
preg_match(
|
1102 |
|
1103 |
-
if(
|
1104 |
|
1105 |
$pattern = "/define\s*\(\s*'UPLOADS'\s*,\s*(.*)\s*\);/";
|
1106 |
|
1107 |
$replace = "";
|
1108 |
|
1109 |
-
if(
|
1110 |
-
$this->log(
|
1111 |
return false;
|
1112 |
}
|
1113 |
} else {
|
1114 |
-
$this->log(
|
1115 |
}
|
1116 |
|
1117 |
-
if(
|
1118 |
-
$this->log(
|
1119 |
return false;
|
1120 |
}
|
1121 |
-
$this->Log(
|
1122 |
return true;
|
1123 |
}
|
1124 |
|
@@ -1127,49 +1089,50 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1127 |
* This is important when a custom uploads folder is used
|
1128 |
* @return bool
|
1129 |
*/
|
1130 |
-
protected function step17()
|
1131 |
-
|
1132 |
-
$this->
|
1133 |
-
|
1134 |
-
|
|
|
1135 |
return false;
|
1136 |
}
|
1137 |
// Get UPLOADS from wp-config.php if there is already one
|
1138 |
-
preg_match(
|
1139 |
// TODO RPoC; DRY
|
1140 |
$uploadFolder = wpstg_get_rel_upload_dir();
|
1141 |
$uploadFolder = ltrim($uploadFolder, '/');
|
1142 |
$uploadFolder = rtrim($uploadFolder, '/');
|
1143 |
-
if(
|
1144 |
$pattern = "/define\s*\(\s*'UPLOADS'\s*,\s*(.*)\s*\);/";
|
1145 |
|
1146 |
$replace = "define('UPLOADS', '" . $uploadFolder . "');";
|
1147 |
-
if(
|
1148 |
-
$this->log(
|
1149 |
return false;
|
1150 |
}
|
1151 |
} else {
|
1152 |
-
$this->log(
|
1153 |
// Find line with ABSPATH and add UPLOADS constant above
|
1154 |
-
preg_match(
|
1155 |
-
if(
|
1156 |
$matches[0];
|
1157 |
$pattern = "/if\s*\(\s*\s*!\s*defined\s*\(\s*['\"]ABSPATH['\"]\s*(.*)\s*\)\s*\)/";
|
1158 |
$replace = "define('UPLOADS', '" . $uploadFolder . "'); \n" .
|
1159 |
-
|
1160 |
-
if(
|
1161 |
-
$this->log(
|
1162 |
return false;
|
1163 |
}
|
1164 |
} else {
|
1165 |
-
$this->log(
|
1166 |
}
|
1167 |
}
|
1168 |
-
if(
|
1169 |
-
$this->log(
|
1170 |
return false;
|
1171 |
}
|
1172 |
-
$this->Log(
|
1173 |
return true;
|
1174 |
}
|
1175 |
|
@@ -1177,25 +1140,26 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1177 |
* Save hostname of parent production site in option_name wpstg_connection
|
1178 |
* @return boolean
|
1179 |
*/
|
1180 |
-
protected function step18()
|
|
|
1181 |
|
1182 |
$table = $this->prefix . 'options';
|
1183 |
|
1184 |
$siteurl = get_site_url();
|
1185 |
|
1186 |
-
$connection = json_encode(
|
1187 |
|
1188 |
$data = array(
|
1189 |
-
'option_name'
|
1190 |
'option_value' => $connection
|
1191 |
);
|
1192 |
|
1193 |
$format = array('%s', '%s');
|
1194 |
|
1195 |
-
$result = $this->db->replace(
|
1196 |
|
1197 |
-
if(
|
1198 |
-
$this->Log(
|
1199 |
}
|
1200 |
return true;
|
1201 |
}
|
@@ -1205,97 +1169,54 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1205 |
* This option is used to determine if the staging website has not been loaded initiall for executing certain custom actions from \WPStaging\initActions()
|
1206 |
* @return boolean
|
1207 |
*/
|
1208 |
-
protected function step19()
|
|
|
1209 |
|
1210 |
$table = $this->prefix . 'options';
|
1211 |
|
1212 |
// Skip - Table does not exist
|
1213 |
-
if(
|
1214 |
return true;
|
1215 |
}
|
1216 |
|
1217 |
$result = $this->db->query(
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
1221 |
);
|
1222 |
|
1223 |
-
if(
|
1224 |
-
$this->Log(
|
1225 |
}
|
1226 |
return true;
|
1227 |
}
|
1228 |
|
1229 |
/**
|
1230 |
-
*
|
1231 |
* @return bool
|
1232 |
*/
|
1233 |
-
protected function step20()
|
1234 |
-
$this->log( "Preparing Data Step20: Preserve Data in " . $this->prefix . "options" );
|
1235 |
|
1236 |
-
|
1237 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
1238 |
return true;
|
1239 |
}
|
1240 |
|
1241 |
-
|
1242 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
1243 |
-
$this->log( "Preparing Data Step20: Skipped" );
|
1244 |
return true;
|
1245 |
}
|
1246 |
|
1247 |
-
$
|
1248 |
-
|
1249 |
-
$preserved_option_names = array('wpstg_existing_clones_beta');
|
1250 |
|
1251 |
-
$
|
1252 |
-
|
1253 |
-
|
1254 |
-
$preserved_options_data = array();
|
1255 |
-
|
1256 |
-
// Get preserved data in wp_options tables
|
1257 |
-
$table = $this->db->prefix . 'options';
|
1258 |
-
$preserved_options_data[$this->prefix . 'options'] = $this->db->get_results(
|
1259 |
-
sprintf(
|
1260 |
-
"SELECT * FROM `{$table}` WHERE `option_name` IN ('%s')", implode( "','", $preserved_options_escaped )
|
1261 |
-
), ARRAY_A
|
1262 |
);
|
1263 |
|
1264 |
-
|
1265 |
-
|
1266 |
-
if( false === empty( $value ) ) {
|
1267 |
-
foreach ( $value as $option ) {
|
1268 |
-
$sql .= $this->db->prepare(
|
1269 |
-
"DELETE FROM `{$key}` WHERE `option_name` = %s;\n", $option['option_name']
|
1270 |
-
);
|
1271 |
-
|
1272 |
-
$sql .= $this->db->prepare(
|
1273 |
-
"INSERT INTO `{$key}` ( `option_id`, `option_name`, `option_value`, `autoload` ) VALUES ( NULL , %s, %s, %s );\n", $option['option_name'], $option['option_value'], $option['autoload']
|
1274 |
-
);
|
1275 |
-
}
|
1276 |
-
}
|
1277 |
}
|
1278 |
|
1279 |
-
$this->debugLog( "Preparing Data Step20: Preserve values " . json_encode( $preserved_options_data ), Logger::TYPE_INFO );
|
1280 |
-
|
1281 |
-
$this->executeSql( $sql );
|
1282 |
-
|
1283 |
-
$this->log( "Preparing Data Step20: Successful!" );
|
1284 |
-
return true;
|
1285 |
-
}
|
1286 |
-
|
1287 |
-
/**
|
1288 |
-
* Execute a batch of sql queries
|
1289 |
-
* @param string $sqlbatch
|
1290 |
-
*/
|
1291 |
-
private function executeSql( $sqlbatch ) {
|
1292 |
-
$queries = array_filter( explode( ";\n", $sqlbatch ) );
|
1293 |
-
|
1294 |
-
foreach ( $queries as $query ) {
|
1295 |
-
if( false === $this->db->query( $query ) ) {
|
1296 |
-
$this->log( "Data Crunching Warning: Can not execute query {$query}", Logger::TYPE_WARNING );
|
1297 |
-
}
|
1298 |
-
}
|
1299 |
return true;
|
1300 |
}
|
1301 |
|
@@ -1303,14 +1224,15 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1303 |
* Get upload path
|
1304 |
* @return boolean|string
|
1305 |
*/
|
1306 |
-
protected function getNewUploadPath()
|
1307 |
-
|
|
|
1308 |
|
1309 |
-
if(
|
1310 |
return false;
|
1311 |
}
|
1312 |
|
1313 |
-
$customSlug = str_replace(
|
1314 |
|
1315 |
$newUploadPath = $this->options->destinationDir . $customSlug;
|
1316 |
|
@@ -1321,28 +1243,30 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1321 |
* Return URL to staging site
|
1322 |
* @return string
|
1323 |
*/
|
1324 |
-
protected function getStagingSiteUrl()
|
1325 |
-
|
|
|
1326 |
return $this->options->cloneHostname;
|
1327 |
}
|
1328 |
-
if(
|
1329 |
-
return trailingslashit(
|
1330 |
}
|
1331 |
|
1332 |
-
return trailingslashit(
|
1333 |
}
|
1334 |
|
1335 |
/**
|
1336 |
* Check if WP is installed in subdir
|
1337 |
* @return boolean
|
1338 |
*/
|
1339 |
-
protected function isSubDir()
|
|
|
1340 |
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
1341 |
// This is happening much more often than you would expect
|
1342 |
-
$siteurl = preg_replace(
|
1343 |
-
$home
|
1344 |
|
1345 |
-
if(
|
1346 |
return true;
|
1347 |
}
|
1348 |
return false;
|
@@ -1352,16 +1276,17 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1352 |
* Get the install sub directory if WP is installed in sub directory
|
1353 |
* @return string
|
1354 |
*/
|
1355 |
-
protected function getSubDir()
|
1356 |
-
|
1357 |
-
$
|
|
|
1358 |
|
1359 |
-
if(
|
1360 |
return '';
|
1361 |
}
|
1362 |
|
1363 |
-
$dir = str_replace(
|
1364 |
-
return str_replace(
|
1365 |
}
|
1366 |
|
1367 |
}
|
3 |
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
|
5 |
// No Direct Access
|
6 |
+
if (!defined("WPINC")) {
|
7 |
die;
|
8 |
}
|
9 |
|
16 |
* Class Data
|
17 |
* @package WPStaging\Backend\Modules\Jobs
|
18 |
*/
|
19 |
+
class DataExternal extends JobExecutable
|
20 |
+
{
|
21 |
|
22 |
/**
|
23 |
* @var \wpdb
|
44 |
/**
|
45 |
* Initialize
|
46 |
*/
|
47 |
+
public function initialize()
|
48 |
+
{
|
49 |
+
$this->db = $this->getStagingDB();
|
50 |
+
$this->productionDb = WPStaging::getInstance()->get("wpdb");
|
51 |
+
$this->prefix = $this->options->prefix;
|
52 |
+
$this->db->prefix = $this->options->databasePrefix;
|
53 |
|
54 |
$this->getTables();
|
55 |
|
56 |
+
$helper = new Helper();
|
57 |
$this->homeUrl = $helper->get_home_url();
|
58 |
|
59 |
// Fix current step
|
60 |
+
if (0 == $this->options->currentStep) {
|
61 |
$this->options->currentStep = 0;
|
62 |
}
|
63 |
}
|
65 |
/**
|
66 |
* Get database object to interact with
|
67 |
*/
|
68 |
+
private function getStagingDB()
|
69 |
+
{
|
70 |
+
return new \wpdb($this->options->databaseUser, $this->options->databasePassword, $this->options->databaseDatabase, $this->options->databaseServer);
|
71 |
}
|
72 |
|
73 |
/**
|
74 |
* Get a list of tables to copy
|
75 |
*/
|
76 |
+
private function getTables()
|
77 |
+
{
|
78 |
+
$strings = new Strings();
|
79 |
$this->tables = array();
|
80 |
+
foreach ($this->options->tables as $table) {
|
81 |
+
$this->tables[] = $this->options->prefix . $strings->str_replace_first($this->productionDb->prefix, null, $table);
|
82 |
}
|
83 |
}
|
84 |
|
86 |
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
87 |
* @return void
|
88 |
*/
|
89 |
+
protected function calculateTotalSteps()
|
90 |
+
{
|
91 |
$this->options->totalSteps = 20;
|
92 |
}
|
93 |
|
95 |
* Start Module
|
96 |
* @return object
|
97 |
*/
|
98 |
+
public function start()
|
99 |
+
{
|
100 |
// Execute steps
|
101 |
$this->run();
|
102 |
|
103 |
// Save option, progress
|
104 |
$this->saveOptions();
|
105 |
|
106 |
+
return ( object )$this->response;
|
107 |
}
|
108 |
|
109 |
/**
|
111 |
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
112 |
* @return bool
|
113 |
*/
|
114 |
+
protected function execute()
|
115 |
+
{
|
116 |
// Fatal error. Let this happen never and break here immediately
|
117 |
+
if ($this->isRoot()) {
|
118 |
return false;
|
119 |
}
|
120 |
|
121 |
// Over limits threshold
|
122 |
+
if ($this->isOverThreshold()) {
|
123 |
// Prepare response and save current progress
|
124 |
+
$this->prepareResponse(false, false);
|
125 |
$this->saveOptions();
|
126 |
return false;
|
127 |
}
|
128 |
|
129 |
// No more steps, finished
|
130 |
+
if ($this->isFinished()) {
|
131 |
+
$this->prepareResponse(true, false);
|
132 |
return false;
|
133 |
}
|
134 |
|
135 |
// Execute step
|
136 |
$stepMethodName = "step" . $this->options->currentStep;
|
137 |
+
if (!$this->{$stepMethodName}()) {
|
138 |
+
$this->prepareResponse(false, false);
|
139 |
return false;
|
140 |
}
|
141 |
|
150 |
* Checks Whether There is Any Job to Execute or Not
|
151 |
* @return bool
|
152 |
*/
|
153 |
+
protected function isFinished()
|
154 |
+
{
|
155 |
return
|
156 |
!$this->isRunning() ||
|
157 |
$this->options->currentStep > $this->options->totalSteps ||
|
158 |
+
!method_exists($this, "step" . $this->options->currentStep);
|
|
|
159 |
}
|
160 |
|
161 |
/**
|
162 |
* Check if current operation is done on the root folder or on the live DB
|
163 |
* @return boolean
|
164 |
*/
|
165 |
+
protected function isRoot()
|
166 |
+
{
|
167 |
|
168 |
// Prefix is the same as the one of live site
|
169 |
// $wpdb = WPStaging::getInstance()->get( "wpdb" );
|
171 |
// return true;
|
172 |
// }
|
173 |
// CloneName is empty
|
174 |
+
$name = ( array )$this->options->cloneDirectoryName;
|
175 |
+
if (empty($name)) {
|
176 |
return true;
|
177 |
}
|
178 |
|
179 |
// Live Path === Staging path
|
180 |
+
if ($this->homeUrl . $this->options->cloneDirectoryName === $this->homeUrl) {
|
181 |
return true;
|
182 |
}
|
183 |
|
189 |
* @param string $table
|
190 |
* @return boolean
|
191 |
*/
|
192 |
+
protected function tableExists($table)
|
193 |
+
{
|
194 |
+
if ($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table) {
|
195 |
+
$this->log("Table {$table} does not exist", Logger::TYPE_ERROR);
|
196 |
return false;
|
197 |
}
|
198 |
return true;
|
203 |
* copy default wp-config.php if production site uses bedrock or any other boilerplate solution that stores wp default config data elsewhere.
|
204 |
* @return boolean
|
205 |
*/
|
206 |
+
protected function step0()
|
207 |
+
{
|
208 |
+
$this->log("Preparing Data Step0: Copy wp-config.php file", Logger::TYPE_INFO);
|
209 |
|
210 |
+
$dir = trailingslashit(dirname(ABSPATH));
|
211 |
|
212 |
$source = $dir . 'wp-config.php';
|
213 |
|
214 |
$destination = $this->options->destinationDir . 'wp-config.php';
|
215 |
|
216 |
// Check if there is already a valid wp-config.php in root of staging site
|
217 |
+
if ($this->isValidWpConfig($destination)) {
|
218 |
return true;
|
219 |
}
|
220 |
|
221 |
// Check if there is a valid wp-config.php outside root of wp production site
|
222 |
+
if ($this->isValidWpConfig($source)) {
|
223 |
// Copy it to staging site
|
224 |
+
if ($this->copy($source, $destination)) {
|
225 |
return true;
|
226 |
}
|
227 |
}
|
228 |
|
229 |
// No valid wp-config.php found so let's copy wp stagings default wp-config.php to staging site
|
230 |
$source = WPSTG_PLUGIN_DIR . "Backend/helpers/wp-config.php";
|
231 |
+
if ($this->copy($source, $destination)) {
|
232 |
// add missing db credentials to wp-config.php
|
233 |
+
if (!$this->alterWpConfig($destination)) {
|
234 |
+
$this->log("Preparing Data Step0: Can not alter db credentials in wp-config.php", Logger::TYPE_INFO);
|
235 |
return false;
|
236 |
}
|
237 |
}
|
238 |
|
239 |
+
$this->log("Preparing Data Step0: Successful", Logger::TYPE_INFO);
|
240 |
return true;
|
241 |
}
|
242 |
|
246 |
* @param type $destination
|
247 |
* @return boolean
|
248 |
*/
|
249 |
+
protected function copy($source, $destination)
|
250 |
+
{
|
251 |
// Copy symbolic link
|
252 |
+
if (is_link($source)) {
|
253 |
+
$this->log("Preparing Data: Symbolic link found...", Logger::TYPE_INFO);
|
254 |
+
if (!@copy(readlink($source), $destination)) {
|
255 |
$errors = error_get_last();
|
256 |
+
$this->log("Preparing Data: Failed to copy {$source} Error: {$errors['message']} {$source} -> {$destination}", Logger::TYPE_ERROR);
|
257 |
return false;
|
258 |
}
|
259 |
}
|
260 |
|
261 |
// Copy file
|
262 |
+
if (!@copy($source, $destination)) {
|
263 |
$errors = error_get_last();
|
264 |
+
$this->log("Preparing Data Step0: Failed to copy {$source}! Error: {$errors['message']} {$source} -> {$destination}", Logger::TYPE_ERROR);
|
265 |
return false;
|
266 |
}
|
267 |
|
273 |
* @param type $source
|
274 |
* @return boolean
|
275 |
*/
|
276 |
+
protected function alterWpConfig($source)
|
277 |
+
{
|
278 |
|
279 |
+
if (false === ($content = file_get_contents($source))) {
|
280 |
return false;
|
281 |
}
|
282 |
|
295 |
/** The Database Collate type. Don't change this if in doubt. */\r\n
|
296 |
define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
297 |
|
298 |
+
$content = str_replace($search, $replace, $content);
|
299 |
|
300 |
+
if (false === @wpstg_put_contents($source, $content)) {
|
301 |
+
$this->log("Preparing Data: Can't save wp-config.php", Logger::TYPE_ERROR);
|
302 |
return false;
|
303 |
}
|
304 |
|
310 |
* @param type $source
|
311 |
* @return boolean
|
312 |
*/
|
313 |
+
protected function isValidWpConfig($source)
|
314 |
+
{
|
315 |
|
316 |
+
if (!is_file($source) && !is_link($source)) {
|
317 |
return false;
|
318 |
}
|
319 |
|
|
|
320 |
|
321 |
+
if (false === ($content = file_get_contents($source))) {
|
322 |
return false;
|
323 |
}
|
324 |
|
325 |
// Get DB_NAME from wp-config.php
|
326 |
+
preg_match("/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
327 |
|
328 |
+
if (empty($matches[1])) {
|
329 |
return false;
|
330 |
}
|
331 |
|
332 |
// Get DB_USER from wp-config.php
|
333 |
+
preg_match("/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
334 |
|
335 |
+
if (empty($matches[1])) {
|
336 |
return false;
|
337 |
}
|
338 |
|
339 |
// Get DB_PASSWORD from wp-config.php
|
340 |
+
preg_match("/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
341 |
|
342 |
+
if (empty($matches[1])) {
|
343 |
return false;
|
344 |
}
|
345 |
|
346 |
// Get DB_HOST from wp-config.php
|
347 |
+
preg_match("/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
348 |
|
349 |
+
if (empty($matches[1])) {
|
350 |
return false;
|
351 |
}
|
352 |
return true;
|
356 |
* Replace "siteurl" and "home"
|
357 |
* @return bool
|
358 |
*/
|
359 |
+
protected function step1()
|
360 |
+
{
|
361 |
+
$this->log("Preparing Data Step1: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO);
|
362 |
|
363 |
// Skip - Table does not exist
|
364 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
365 |
return true;
|
366 |
}
|
367 |
// Skip - Table is not selected or updated
|
368 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
369 |
+
$this->log("Preparing Data Step1: Skipping");
|
370 |
return true;
|
371 |
}
|
372 |
|
373 |
+
$this->log("Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl());
|
374 |
// Replace URLs
|
375 |
$result = $this->db->query(
|
376 |
+
$this->db->prepare(
|
377 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->getStagingSiteUrl()
|
378 |
+
)
|
379 |
);
|
380 |
|
381 |
|
|
|
382 |
// All good
|
383 |
+
if ($result) {
|
384 |
return true;
|
385 |
}
|
386 |
|
387 |
+
$this->log("Preparing Data Step1: Skip updating siteurl and homeurl in {$this->prefix}options. Probably already did! {$this->db->last_error}", Logger::TYPE_WARNING);
|
388 |
return true;
|
389 |
}
|
390 |
|
392 |
* Update "wpstg_is_staging_site"
|
393 |
* @return bool
|
394 |
*/
|
395 |
+
protected function step2()
|
396 |
+
{
|
397 |
|
398 |
+
$this->log("Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}");
|
399 |
|
400 |
// Skip - Table does not exist
|
401 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
402 |
+
$this->log("Preparing Data Step2: Skipping");
|
403 |
return true;
|
404 |
}
|
405 |
// Skip - Table is not selected or updated
|
406 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
407 |
+
$this->log("Preparing Data Step2: Skipping");
|
408 |
return true;
|
409 |
}
|
410 |
|
411 |
+
$this->db->query(
|
412 |
+
$this->db->prepare(
|
413 |
+
"DELETE FROM `{$this->prefix}options` WHERE `option_name` = %s;", 'wpstg_is_staging_site'
|
414 |
+
)
|
415 |
);
|
416 |
|
417 |
|
418 |
// No errors but no option name such as wpstg_is_staging_site
|
419 |
$insert = $this->db->query(
|
420 |
+
$this->db->prepare(
|
421 |
+
"INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_is_staging_site',%s)", "true"
|
422 |
+
)
|
423 |
);
|
424 |
|
425 |
// All good
|
426 |
+
if ($insert) {
|
427 |
+
$this->log("Preparing Data Step2: Successful", Logger::TYPE_INFO);
|
428 |
return true;
|
429 |
}
|
430 |
|
431 |
+
$this->log("Preparing Data Step2: Failed to update wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
|
432 |
return false;
|
433 |
}
|
434 |
|
436 |
* Update rewrite_rules
|
437 |
* @return bool
|
438 |
*/
|
439 |
+
protected function step3()
|
440 |
+
{
|
441 |
|
442 |
+
$this->log("Preparing Data Step3: Updating rewrite_rules in {$this->prefix}options {$this->db->last_error}");
|
443 |
|
444 |
// Keep Permalinks
|
445 |
+
if (isset($this->settings->keepPermalinks) && $this->settings->keepPermalinks === "1") {
|
446 |
+
$this->log("Preparing Data Step3: Skipping");
|
447 |
return true;
|
448 |
}
|
449 |
|
450 |
// Skip - Table does not exist
|
451 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
452 |
+
$this->log("Preparing Data Step3: Skipping");
|
453 |
return true;
|
454 |
}
|
455 |
|
456 |
// Skip - Table is not selected or updated
|
457 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
458 |
+
$this->log("Preparing Data Step3: Skipping");
|
459 |
return true;
|
460 |
}
|
461 |
|
462 |
$result = $this->db->query(
|
463 |
+
$this->db->prepare(
|
464 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'rewrite_rules'", ' '
|
465 |
+
)
|
466 |
);
|
467 |
|
468 |
// All good
|
469 |
+
if ($result) {
|
470 |
return true;
|
471 |
}
|
472 |
|
478 |
* Update Table Prefix in wp_usermeta and wp_options
|
479 |
* @return bool
|
480 |
*/
|
481 |
+
protected function step4()
|
482 |
+
{
|
483 |
+
$this->log("Preparing Data Step4: Updating db prefix in {$this->prefix}usermeta. ");
|
484 |
|
485 |
// Skip - Table does not exist
|
486 |
+
if (false === $this->tableExists($this->prefix . 'usermeta')) {
|
487 |
return true;
|
488 |
}
|
489 |
|
490 |
// Skip - Table is not selected or updated
|
491 |
+
if (!in_array($this->prefix . 'usermeta', $this->tables)) {
|
492 |
+
$this->log("Preparing Data Step4: Skipping");
|
493 |
return true;
|
494 |
}
|
495 |
|
496 |
|
|
|
497 |
$update = $this->db->query(
|
498 |
+
$this->db->prepare(
|
499 |
+
"UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->productionDb->prefix, $this->prefix, $this->productionDb->prefix . "_%"
|
500 |
+
)
|
501 |
);
|
502 |
|
503 |
+
if (false === $update) {
|
504 |
+
$this->log("Preparing Data Step4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR);
|
505 |
+
$this->returnException("Preparing Data Step4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}");
|
506 |
return false;
|
507 |
}
|
508 |
|
509 |
|
|
|
510 |
return true;
|
511 |
}
|
512 |
|
514 |
* Update Table prefix in wp-config.php
|
515 |
* @return bool
|
516 |
*/
|
517 |
+
protected function step5()
|
518 |
+
{
|
519 |
$path = $this->options->destinationDir . "wp-config.php";
|
520 |
|
521 |
+
$this->log("Preparing Data Step5: Updating table_prefix in {$path} to " . $this->prefix);
|
522 |
+
if (false === ($content = file_get_contents($path))) {
|
523 |
+
$this->log("Preparing Data Step5: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR);
|
524 |
return false;
|
525 |
}
|
526 |
|
527 |
// Replace table prefix
|
528 |
+
$pattern = '/\$table_prefix\s*=\s*(.*).*/';
|
529 |
$replacement = '$table_prefix = \'' . $this->prefix . '\'; // Changed by WP Staging';
|
530 |
+
$content = preg_replace($pattern, $replacement, $content);
|
531 |
|
532 |
+
if (null === $content) {
|
533 |
+
$this->log("Preparing Data Step5: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR);
|
534 |
return false;
|
535 |
}
|
536 |
|
537 |
// Replace URLs
|
538 |
+
$content = str_replace($this->homeUrl, $this->getStagingSiteUrl(), $content);
|
539 |
|
540 |
+
if (false === @wpstg_put_contents($path, $content)) {
|
541 |
+
$this->log("Preparing Data Step5: Failed to update table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR);
|
542 |
return false;
|
543 |
}
|
544 |
|
604 |
* Update wpstg_rmpermalinks_executed
|
605 |
* @return bool
|
606 |
*/
|
607 |
+
protected function step7()
|
608 |
+
{
|
609 |
|
610 |
+
$this->log("Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}");
|
611 |
|
612 |
// Skip - Table does not exist
|
613 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
614 |
+
$this->log("Preparing Data Step7: Skipping Table {$this->prefix}'options' does not exist");
|
615 |
return true;
|
616 |
}
|
617 |
|
618 |
// Skip - Table is not selected or updated
|
619 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
620 |
+
$this->log("Preparing Data Step7: Skipping");
|
621 |
return true;
|
622 |
}
|
623 |
|
624 |
$result = $this->db->query(
|
625 |
+
$this->db->prepare(
|
626 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_rmpermalinks_executed'", ' '
|
627 |
+
)
|
628 |
);
|
629 |
|
630 |
|
631 |
+
$this->Log("Preparing Data Step7: Finished successfully");
|
632 |
return true;
|
633 |
}
|
634 |
|
636 |
* Update permalink_structure
|
637 |
* @return bool
|
638 |
*/
|
639 |
+
protected function step8()
|
640 |
+
{
|
641 |
|
642 |
+
$this->log("Preparing Data Step8: Updating permalink_structure in {$this->prefix}options {$this->db->last_error}");
|
643 |
|
644 |
// Keep Permalinks
|
645 |
+
if (isset($this->settings->keepPermalinks) && $this->settings->keepPermalinks === "1") {
|
646 |
+
$this->log("Preparing Data Step8: Skipping");
|
647 |
return true;
|
648 |
}
|
649 |
|
650 |
// Skip - Table does not exist
|
651 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
652 |
+
$this->log("Preparing Data Step8: Skipping");
|
653 |
return true;
|
654 |
}
|
655 |
|
656 |
// Skip - Table is not selected or updated
|
657 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
658 |
+
$this->log("Preparing Data Step8: Skipping");
|
659 |
return true;
|
660 |
}
|
661 |
|
662 |
$result = $this->db->query(
|
663 |
+
$this->db->prepare(
|
664 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'permalink_structure'", ' '
|
665 |
+
)
|
666 |
);
|
667 |
|
668 |
// All good
|
669 |
+
if ($result) {
|
670 |
+
$this->Log("Preparing Data Step8: Finished successfully");
|
671 |
return true;
|
672 |
}
|
673 |
|
674 |
+
$this->log("Failed to update permalink_structure in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
|
675 |
return true;
|
676 |
}
|
677 |
|
679 |
* Update blog_public option to not allow staging site to be indexed by search engines
|
680 |
* @return bool
|
681 |
*/
|
682 |
+
protected function step9()
|
683 |
+
{
|
684 |
|
685 |
+
$this->log("Preparing Data Step9: Set staging site to noindex");
|
686 |
|
687 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
688 |
return true;
|
689 |
}
|
690 |
|
691 |
// Skip - Table is not selected or updated
|
692 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
693 |
+
$this->log("Preparing Data Step9: Skipping");
|
694 |
return true;
|
695 |
}
|
696 |
|
697 |
$result = $this->db->query(
|
698 |
+
$this->db->prepare(
|
699 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'blog_public'", '0'
|
700 |
+
)
|
701 |
);
|
702 |
|
703 |
// All good
|
704 |
+
if ($result) {
|
705 |
+
$this->Log("Preparing Data Step9: Finished successfully");
|
706 |
return true;
|
707 |
}
|
708 |
|
709 |
+
$this->log("Can not update staging site to noindex. Possible already done!", Logger::TYPE_WARNING);
|
710 |
return true;
|
711 |
}
|
712 |
|
714 |
* Update WP_HOME in wp-config.php
|
715 |
* @return bool
|
716 |
*/
|
717 |
+
protected function step10()
|
718 |
+
{
|
719 |
$path = $this->options->destinationDir . "wp-config.php";
|
720 |
|
721 |
+
$this->log("Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl());
|
722 |
|
723 |
+
if (false === ($content = file_get_contents($path))) {
|
724 |
+
$this->log("Preparing Data Step10: Failed to update WP_HOME in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
725 |
return false;
|
726 |
}
|
727 |
|
728 |
|
729 |
// Get WP_HOME from wp-config.php
|
730 |
+
preg_match("/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
731 |
|
732 |
+
if (!empty($matches[1])) {
|
733 |
$matches[1];
|
734 |
|
735 |
$pattern = "/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*(.*)\s*\);.*/";
|
737 |
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
738 |
//$replace.= " // Changed by WP-Staging";
|
739 |
|
740 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
741 |
+
$this->log("Preparing Data: Failed to update WP_HOME", Logger::TYPE_ERROR);
|
742 |
return false;
|
743 |
}
|
744 |
} else {
|
745 |
+
$this->log("Preparing Data Step10: WP_HOME not defined in wp-config.php. Skipping this step.");
|
746 |
}
|
747 |
|
748 |
+
if (false === @wpstg_put_contents($path, $content)) {
|
749 |
+
$this->log("Preparing Data Step10: Failed to update WP_HOME. Can't save contents", Logger::TYPE_ERROR);
|
750 |
return false;
|
751 |
}
|
752 |
+
$this->Log("Preparing Data Step10: Finished successfully");
|
753 |
return true;
|
754 |
}
|
755 |
|
757 |
* Update WP_SITEURL in wp-config.php
|
758 |
* @return bool
|
759 |
*/
|
760 |
+
protected function step11()
|
761 |
+
{
|
762 |
$path = $this->options->destinationDir . "wp-config.php";
|
763 |
|
764 |
+
$this->log("Preparing Data Step11: Updating WP_SITEURL in wp-config.php to " . $this->getStagingSiteUrl());
|
765 |
|
766 |
+
if (false === ($content = file_get_contents($path))) {
|
767 |
+
$this->log("Preparing Data Step11: Failed to update WP_SITEURL in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
768 |
return false;
|
769 |
}
|
770 |
|
771 |
|
772 |
// Get WP_SITEURL from wp-config.php
|
773 |
+
preg_match("/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
774 |
|
775 |
+
if (!empty($matches[1])) {
|
776 |
$matches[1];
|
777 |
|
778 |
$pattern = "/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*(.*)\s*\);.*/";
|
780 |
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
781 |
//$replace.= " // Changed by WP-Staging";
|
782 |
|
783 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
784 |
+
$this->log("Preparing Data Step11: Failed to update WP_SITEURL", Logger::TYPE_ERROR);
|
785 |
return false;
|
786 |
}
|
787 |
} else {
|
788 |
+
$this->log("Preparing Data Step11: WP_SITEURL not defined in wp-config.php. Skipping this step.");
|
789 |
}
|
790 |
|
791 |
|
792 |
+
if (false === @wpstg_put_contents($path, $content)) {
|
793 |
+
$this->log("Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR);
|
794 |
return false;
|
795 |
}
|
796 |
+
$this->Log("Preparing Data Step11: Finished successfully");
|
797 |
return true;
|
798 |
}
|
799 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
800 |
|
801 |
/**
|
802 |
* Update Table Prefix in wp_options
|
803 |
* @return bool
|
804 |
*/
|
805 |
+
protected function step12()
|
806 |
+
{
|
807 |
+
$this->log("Preparing Data Step12: Updating db prefix in {$this->prefix}options.");
|
808 |
|
809 |
// Skip - Table does not exist
|
810 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
811 |
return true;
|
812 |
}
|
813 |
|
814 |
// Skip, prefixes are identical. No change needed
|
815 |
+
if ($this->productionDb->prefix === $this->prefix) {
|
816 |
+
$this->log("Preparing Data Step12: Skipped");
|
817 |
return true;
|
818 |
}
|
819 |
|
820 |
// Skip - Table is not selected or updated
|
821 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
822 |
+
$this->log("Preparing Data Step12: Skipping");
|
823 |
return true;
|
824 |
}
|
825 |
|
826 |
+
$notice = !empty($this->db->last_error) ? 'Last error: ' . $this->db->last_error : '';
|
827 |
|
828 |
//$this->log( "Updating option_name in {$this->prefix}options. {$notice}" );
|
829 |
// Filter the rows below. Do not update them!
|
833 |
'wp_mail_smtp_debug',
|
834 |
);
|
835 |
|
836 |
+
$filters = apply_filters('wpstg_data_excl_rows', $filters);
|
837 |
|
838 |
$where = "";
|
839 |
+
foreach ($filters as $filter) {
|
840 |
$where .= " AND option_name <> '" . $filter . "'";
|
841 |
}
|
842 |
|
843 |
$updateOptions = $this->db->query(
|
844 |
+
$this->db->prepare(
|
845 |
+
"UPDATE IGNORE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s" . $where, $this->productionDb->prefix, $this->prefix, $this->productionDb->prefix . "_%"
|
846 |
+
)
|
847 |
);
|
848 |
|
849 |
+
if (false === $updateOptions) {
|
850 |
+
$this->log("Preparing Data Step12: Failed to update option_name in {$this->prefix}options. Error: {$this->db->last_error}", Logger::TYPE_ERROR);
|
851 |
+
$this->returnException(" Preparing Data Step12: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}");
|
852 |
return false;
|
853 |
}
|
854 |
+
$this->Log("Preparing Data Step12: Finished successfully");
|
855 |
return true;
|
856 |
}
|
857 |
|
859 |
* Change upload_path in wp_options (if it is defined)
|
860 |
* @return bool
|
861 |
*/
|
862 |
+
protected function step13()
|
863 |
+
{
|
864 |
+
$this->log("Preparing Data Step13: Updating upload_path {$this->prefix}options.");
|
865 |
|
866 |
// Skip - Table does not exist
|
867 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
868 |
return true;
|
869 |
}
|
870 |
|
871 |
$newUploadPath = $this->getNewUploadPath();
|
872 |
|
873 |
+
if (false === $newUploadPath) {
|
874 |
+
$this->log("Preparing Data Step13: Skipped");
|
875 |
return true;
|
876 |
}
|
877 |
|
878 |
// Skip - Table is not selected or updated
|
879 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
880 |
+
$this->log("Preparing Data Step13: Skipped");
|
881 |
return true;
|
882 |
}
|
883 |
|
884 |
+
$error = isset($this->db->last_error) ? 'Last error: ' . $this->db->last_error : '';
|
885 |
|
886 |
+
$this->log("Updating upload_path in {$this->prefix}options. {$error}");
|
887 |
|
888 |
$updateOptions = $this->db->query(
|
889 |
+
$this->db->prepare(
|
890 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'upload_path'", $newUploadPath
|
891 |
+
)
|
892 |
);
|
893 |
|
894 |
+
if (false === $updateOptions) {
|
895 |
+
$this->log("Preparing Data Step13: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR);
|
896 |
return true;
|
897 |
}
|
898 |
+
$this->Log("Preparing Data Step 13: Finished successfully");
|
899 |
return true;
|
900 |
}
|
901 |
|
903 |
* Update WP_CACHE in wp-config.php
|
904 |
* @return bool
|
905 |
*/
|
906 |
+
protected function step14()
|
907 |
+
{
|
908 |
$path = $this->options->destinationDir . "wp-config.php";
|
909 |
|
910 |
+
$this->log("Preparing Data Step14: Set WP_CACHE in wp-config.php to false");
|
911 |
|
912 |
+
if (false === ($content = file_get_contents($path))) {
|
913 |
+
$this->log("Preparing Data Step14: Failed to update WP_CACHE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
914 |
return false;
|
915 |
}
|
916 |
|
917 |
|
918 |
// Get WP_CACHE from wp-config.php
|
919 |
+
preg_match("/define\s*\(\s*['\"]WP_CACHE['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
920 |
|
921 |
+
if (!empty($matches[1])) {
|
922 |
|
923 |
$pattern = "/define\s*\(\s*['\"]WP_CACHE['\"]\s*,\s*(.*)\s*\);.*/";
|
924 |
|
925 |
$replace = "define('WP_CACHE',false); // " . $matches[1];
|
926 |
//$replace.= " // Changed by WP-Staging";
|
927 |
|
928 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
929 |
+
$this->log("Preparing Data: Failed to change WP_CACHE", Logger::TYPE_ERROR);
|
930 |
return false;
|
931 |
}
|
932 |
} else {
|
933 |
+
$this->log("Preparing Data Step14: WP_CACHE not defined in wp-config.php. Skipping this step.");
|
934 |
}
|
935 |
|
936 |
+
if (false === @wpstg_put_contents($path, $content)) {
|
937 |
+
$this->log("Preparing Data Step14: Failed to update WP_CACHE. Can't save contents", Logger::TYPE_ERROR);
|
938 |
return false;
|
939 |
}
|
940 |
+
$this->Log("Preparing Data Step14: Finished successfully");
|
941 |
return true;
|
942 |
}
|
943 |
|
945 |
* Update database credentials in wp-config.php
|
946 |
* @return bool
|
947 |
*/
|
948 |
+
protected function step15()
|
949 |
+
{
|
950 |
$path = $this->options->destinationDir . "wp-config.php";
|
951 |
|
952 |
+
$this->log("Preparing Data Step15: Change database credentials in wp-config.php");
|
953 |
|
954 |
+
if (false === ($content = file_get_contents($path))) {
|
955 |
+
$this->log("Preparing Data Step15: Failed to update database credentials in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
956 |
return false;
|
957 |
}
|
958 |
|
959 |
|
960 |
// Get DB_NAME from wp-config.php
|
961 |
+
preg_match("/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
962 |
|
963 |
+
if (!empty($matches[1])) {
|
964 |
$matches[1];
|
965 |
|
966 |
$pattern = "/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*(.*)\s*\);.*/";
|
968 |
$replace = "define('DB_NAME','{$this->options->databaseDatabase}'); // " . $matches[1];
|
969 |
//$replace.= " // Changed by WP-Staging";
|
970 |
|
971 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
972 |
+
$this->log("Preparing Data: Failed to change DB_NAME", Logger::TYPE_ERROR);
|
973 |
return false;
|
974 |
}
|
975 |
} else {
|
976 |
+
$this->log("Preparing Data Step15: DB_NAME not defined in wp-config.php. Skipped this step.");
|
977 |
}
|
978 |
// Get DB_USER from wp-config.php
|
979 |
+
preg_match("/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
980 |
|
981 |
+
if (!empty($matches[1])) {
|
982 |
$matches[1];
|
983 |
|
984 |
$pattern = "/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*(.*)\s*\);.*/";
|
986 |
$replace = "define('DB_USER','{$this->options->databaseUser}'); // " . $matches[1];
|
987 |
//$replace.= " // Changed by WP-Staging";
|
988 |
|
989 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
990 |
+
$this->log("Preparing Data: Failed to change DB_USER", Logger::TYPE_ERROR);
|
991 |
return false;
|
992 |
}
|
993 |
} else {
|
994 |
+
$this->log("Preparing Data Step15: DB_USER not defined in wp-config.php. Skipped this step.");
|
995 |
}
|
996 |
// Get DB_PASSWORD from wp-config.php
|
997 |
+
preg_match("/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
998 |
|
999 |
+
if (!empty($matches[1])) {
|
1000 |
$matches[1];
|
1001 |
|
1002 |
$pattern = "/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*(.*)\s*\);.*/";
|
1003 |
|
1004 |
+
//We need to escape ',$ and \ for preg_replace. As the string will later be interpreted as a PHP string, we
|
1005 |
+
//need to escape \ twice.
|
1006 |
+
$escapedPassword = addcslashes(addcslashes($this->options->databasePassword, "\\"), "'$\\");
|
1007 |
+
|
1008 |
+
$replace = "define('DB_PASSWORD','{$escapedPassword}'); // Changed by WP Staging";
|
1009 |
//$replace.= " // Changed by WP-Staging";
|
1010 |
|
1011 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1012 |
+
$this->log("Preparing Data: Failed to change DB_PASSWORD", Logger::TYPE_ERROR);
|
1013 |
return false;
|
1014 |
}
|
1015 |
} else {
|
1016 |
+
$this->log("Preparing Data Step15: DB_PASSWORD not defined in wp-config.php. Skipped this step.");
|
1017 |
}
|
1018 |
// Get DB_HOST from wp-config.php
|
1019 |
+
preg_match("/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
1020 |
|
1021 |
+
if (!empty($matches[1])) {
|
1022 |
$matches[1];
|
1023 |
|
1024 |
$pattern = "/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*(.*)\s*\);.*/";
|
1026 |
$replace = "define('DB_HOST','{$this->options->databaseServer}'); // " . $matches[1];
|
1027 |
//$replace.= " // Changed by WP-Staging";
|
1028 |
|
1029 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1030 |
+
$this->log("Preparing Data: Failed to change DB_HOST", Logger::TYPE_ERROR);
|
1031 |
return false;
|
1032 |
}
|
1033 |
} else {
|
1034 |
+
$this->log("Preparing Data Step15: DB_HOST not defined in wp-config.php. Skipped this step.");
|
1035 |
}
|
1036 |
|
1037 |
|
1038 |
+
if (false === @wpstg_put_contents($path, $content)) {
|
1039 |
+
$this->log("Preparing Data Step15: Failed to update database credentials in wp-config.php. Can't save contents", Logger::TYPE_ERROR);
|
1040 |
return false;
|
1041 |
}
|
1042 |
+
$this->Log("Preparing Data: Finished Step 15 successfully");
|
1043 |
return true;
|
1044 |
}
|
1045 |
|
1047 |
* Remove UPLOADS constant in wp-config.php to reset default image folder
|
1048 |
* @return bool
|
1049 |
*/
|
1050 |
+
protected function step16()
|
1051 |
+
{
|
1052 |
$path = $this->options->destinationDir . "wp-config.php";
|
1053 |
|
1054 |
+
$this->log("Preparing Data Step16: Remove UPLOADS in wp-config.php");
|
1055 |
|
1056 |
+
if (false === ($content = file_get_contents($path))) {
|
1057 |
+
$this->log("Preparing Data Step16: Failed to get UPLOADS in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
1058 |
return false;
|
1059 |
}
|
1060 |
|
1061 |
|
1062 |
// Get UPLOADS from wp-config.php
|
1063 |
+
preg_match("/define\s*\(\s*['\"]UPLOADS['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
1064 |
|
1065 |
+
if (!empty($matches[0])) {
|
1066 |
|
1067 |
$pattern = "/define\s*\(\s*'UPLOADS'\s*,\s*(.*)\s*\);/";
|
1068 |
|
1069 |
$replace = "";
|
1070 |
|
1071 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1072 |
+
$this->log("Preparing Data: Failed to change UPLOADS", Logger::TYPE_ERROR);
|
1073 |
return false;
|
1074 |
}
|
1075 |
} else {
|
1076 |
+
$this->log("Preparing Data Step16: UPLOADS not defined in wp-config.php. Skipping this step.");
|
1077 |
}
|
1078 |
|
1079 |
+
if (false === @wpstg_put_contents($path, $content)) {
|
1080 |
+
$this->log("Preparing Data Step16: Failed to update UPLOADS. Can't save contents", Logger::TYPE_ERROR);
|
1081 |
return false;
|
1082 |
}
|
1083 |
+
$this->Log("Preparing Data Step16: Finished successfully");
|
1084 |
return true;
|
1085 |
}
|
1086 |
|
1089 |
* This is important when a custom uploads folder is used
|
1090 |
* @return bool
|
1091 |
*/
|
1092 |
+
protected function step17()
|
1093 |
+
{
|
1094 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
1095 |
+
$this->log("Preparing Data Step17: Update UPLOADS constant in wp-config.php");
|
1096 |
+
if (false === ($content = file_get_contents($path))) {
|
1097 |
+
$this->log("Preparing Data Step17: Failed to get UPLOADS in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
1098 |
return false;
|
1099 |
}
|
1100 |
// Get UPLOADS from wp-config.php if there is already one
|
1101 |
+
preg_match("/define\s*\(\s*['\"]UPLOADS['\"]\s*,\s*(.*)\s*\);/", $content, $matches);
|
1102 |
// TODO RPoC; DRY
|
1103 |
$uploadFolder = wpstg_get_rel_upload_dir();
|
1104 |
$uploadFolder = ltrim($uploadFolder, '/');
|
1105 |
$uploadFolder = rtrim($uploadFolder, '/');
|
1106 |
+
if (!empty($matches[0])) {
|
1107 |
$pattern = "/define\s*\(\s*'UPLOADS'\s*,\s*(.*)\s*\);/";
|
1108 |
|
1109 |
$replace = "define('UPLOADS', '" . $uploadFolder . "');";
|
1110 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1111 |
+
$this->log("Preparing Data Step17: Failed to change UPLOADS", Logger::TYPE_ERROR);
|
1112 |
return false;
|
1113 |
}
|
1114 |
} else {
|
1115 |
+
$this->log("Preparing Data Step17: UPLOADS not defined in wp-config.php. Creating new entry.");
|
1116 |
// Find line with ABSPATH and add UPLOADS constant above
|
1117 |
+
preg_match("/if\s*\(\s*\s*!\s*defined\s*\(\s*['\"]ABSPATH['\"]\s*(.*)\s*\)\s*\)/", $content, $matches);
|
1118 |
+
if (!empty($matches[0])) {
|
1119 |
$matches[0];
|
1120 |
$pattern = "/if\s*\(\s*\s*!\s*defined\s*\(\s*['\"]ABSPATH['\"]\s*(.*)\s*\)\s*\)/";
|
1121 |
$replace = "define('UPLOADS', '" . $uploadFolder . "'); \n" .
|
1122 |
+
"if ( ! defined( 'ABSPATH' ) )";
|
1123 |
+
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1124 |
+
$this->log("Preparing Data Step 17: Failed to change UPLOADS", Logger::TYPE_ERROR);
|
1125 |
return false;
|
1126 |
}
|
1127 |
} else {
|
1128 |
+
$this->log("Preparing Data Step 17: Can not add UPLOAD constant to wp-config.php. Can not find free position to add it.", Logger::TYPE_ERROR);
|
1129 |
}
|
1130 |
}
|
1131 |
+
if (false === @wpstg_put_contents($path, $content)) {
|
1132 |
+
$this->log("Preparing Data Step17: Failed to update UPLOADS. Can't save contents", Logger::TYPE_ERROR);
|
1133 |
return false;
|
1134 |
}
|
1135 |
+
$this->Log("Preparing Data Step17: Finished successfully");
|
1136 |
return true;
|
1137 |
}
|
1138 |
|
1140 |
* Save hostname of parent production site in option_name wpstg_connection
|
1141 |
* @return boolean
|
1142 |
*/
|
1143 |
+
protected function step18()
|
1144 |
+
{
|
1145 |
|
1146 |
$table = $this->prefix . 'options';
|
1147 |
|
1148 |
$siteurl = get_site_url();
|
1149 |
|
1150 |
+
$connection = json_encode(array('prodHostname' => $siteurl));
|
1151 |
|
1152 |
$data = array(
|
1153 |
+
'option_name' => 'wpstg_connection',
|
1154 |
'option_value' => $connection
|
1155 |
);
|
1156 |
|
1157 |
$format = array('%s', '%s');
|
1158 |
|
1159 |
+
$result = $this->db->replace($table, $data, $format);
|
1160 |
|
1161 |
+
if (false === $result) {
|
1162 |
+
$this->Log("Preparing Data Step18: Could not save {$siteurl} in {$table}", Logger::TYPE_ERROR);
|
1163 |
}
|
1164 |
return true;
|
1165 |
}
|
1169 |
* This option is used to determine if the staging website has not been loaded initiall for executing certain custom actions from \WPStaging\initActions()
|
1170 |
* @return boolean
|
1171 |
*/
|
1172 |
+
protected function step19()
|
1173 |
+
{
|
1174 |
|
1175 |
$table = $this->prefix . 'options';
|
1176 |
|
1177 |
// Skip - Table does not exist
|
1178 |
+
if (false === $this->tableExists($table)) {
|
1179 |
return true;
|
1180 |
}
|
1181 |
|
1182 |
$result = $this->db->query(
|
1183 |
+
$this->db->prepare(
|
1184 |
+
"INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_execute',%s) ON DUPLICATE KEY UPDATE option_value = %s", "true", "true"
|
1185 |
+
)
|
1186 |
);
|
1187 |
|
1188 |
+
if (false === $result) {
|
1189 |
+
$this->Log("Preparing Data Step19: Could not save wpstg_execute in {$table}", Logger::TYPE_ERROR);
|
1190 |
}
|
1191 |
return true;
|
1192 |
}
|
1193 |
|
1194 |
/**
|
1195 |
+
* Delete all listed staging sites from cloned site in initial cloning. Useful if a cloned site is cloned again. E.g. for dev > staging > production setup
|
1196 |
* @return bool
|
1197 |
*/
|
1198 |
+
protected function step20(){
|
|
|
1199 |
|
1200 |
+
if ($this->options->mainJob === 'updating'){
|
|
|
1201 |
return true;
|
1202 |
}
|
1203 |
|
1204 |
+
if( false === $this->tableExists( $this->prefix . 'options' ) ) {
|
|
|
|
|
1205 |
return true;
|
1206 |
}
|
1207 |
|
1208 |
+
$step = "Preparing Data Step20:";
|
1209 |
+
$this->log( $step . " Reset wp staging site data" );
|
|
|
1210 |
|
1211 |
+
$result = $this->db->query(
|
1212 |
+
$this->db->prepare( "UPDATE {$this->prefix}options SET `option_value` = %s WHERE `option_name` = %s", serialize(array()), 'wpstg_existing_clones_beta'
|
1213 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1214 |
);
|
1215 |
|
1216 |
+
if (false === $result){
|
1217 |
+
$this->log( $step . "Failed to reset wp staging site data." );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1218 |
}
|
1219 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1220 |
return true;
|
1221 |
}
|
1222 |
|
1224 |
* Get upload path
|
1225 |
* @return boolean|string
|
1226 |
*/
|
1227 |
+
protected function getNewUploadPath()
|
1228 |
+
{
|
1229 |
+
$uploadPath = get_option('upload_path');
|
1230 |
|
1231 |
+
if (!$uploadPath) {
|
1232 |
return false;
|
1233 |
}
|
1234 |
|
1235 |
+
$customSlug = str_replace(\WPStaging\WPStaging::getWPpath(), '', $uploadPath);
|
1236 |
|
1237 |
$newUploadPath = $this->options->destinationDir . $customSlug;
|
1238 |
|
1243 |
* Return URL to staging site
|
1244 |
* @return string
|
1245 |
*/
|
1246 |
+
protected function getStagingSiteUrl()
|
1247 |
+
{
|
1248 |
+
if (!empty($this->options->cloneHostname)) {
|
1249 |
return $this->options->cloneHostname;
|
1250 |
}
|
1251 |
+
if ($this->isSubDir()) {
|
1252 |
+
return trailingslashit($this->homeUrl) . trailingslashit($this->getSubDir()) . $this->options->cloneDirectoryName;
|
1253 |
}
|
1254 |
|
1255 |
+
return trailingslashit($this->homeUrl) . $this->options->cloneDirectoryName;
|
1256 |
}
|
1257 |
|
1258 |
/**
|
1259 |
* Check if WP is installed in subdir
|
1260 |
* @return boolean
|
1261 |
*/
|
1262 |
+
protected function isSubDir()
|
1263 |
+
{
|
1264 |
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
1265 |
// This is happening much more often than you would expect
|
1266 |
+
$siteurl = preg_replace('#^https?://#', '', rtrim(get_option('siteurl'), '/'));
|
1267 |
+
$home = preg_replace('#^https?://#', '', rtrim(get_option('home'), '/'));
|
1268 |
|
1269 |
+
if ($home !== $siteurl) {
|
1270 |
return true;
|
1271 |
}
|
1272 |
return false;
|
1276 |
* Get the install sub directory if WP is installed in sub directory
|
1277 |
* @return string
|
1278 |
*/
|
1279 |
+
protected function getSubDir()
|
1280 |
+
{
|
1281 |
+
$home = get_option('home');
|
1282 |
+
$siteurl = get_option('siteurl');
|
1283 |
|
1284 |
+
if (empty($home) || empty($siteurl)) {
|
1285 |
return '';
|
1286 |
}
|
1287 |
|
1288 |
+
$dir = str_replace($home, '', $siteurl);
|
1289 |
+
return str_replace('/', '', $dir);
|
1290 |
}
|
1291 |
|
1292 |
}
|
Backend/Modules/Jobs/Database.php
CHANGED
@@ -92,14 +92,6 @@ class Database extends JobExecutable {
|
|
92 |
return false;
|
93 |
}
|
94 |
|
95 |
-
// Table is excluded
|
96 |
-
// if (in_array($this->options->tables[$this->options->currentStep]->name, $this->options->excludedTables))
|
97 |
-
// {
|
98 |
-
// $this->prepareResponse();
|
99 |
-
// return true;
|
100 |
-
// }
|
101 |
-
// Copy table
|
102 |
-
//if (!$this->copyTable($this->options->tables[$this->options->currentStep]->name))
|
103 |
if( !$this->copyTable( $this->options->tables[$this->options->currentStep] ) ) {
|
104 |
// Prepare Response
|
105 |
$this->prepareResponse( false, false );
|
92 |
return false;
|
93 |
}
|
94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
if( !$this->copyTable( $this->options->tables[$this->options->currentStep] ) ) {
|
96 |
// Prepare Response
|
97 |
$this->prepareResponse( false, false );
|
Backend/Modules/Jobs/DatabaseExternal.php
CHANGED
@@ -3,22 +3,19 @@
|
|
3 |
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
|
5 |
// No Direct Access
|
6 |
-
if(
|
7 |
die;
|
8 |
}
|
9 |
|
10 |
use WPStaging\WPStaging;
|
11 |
use WPStaging\Utils\Strings;
|
12 |
-
use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
13 |
-
|
14 |
-
//use WPStaging\Utils\MySQL;
|
15 |
-
//use WPStaging\Utils\MySQLi;
|
16 |
|
17 |
/**
|
18 |
* Class Database
|
19 |
* @package WPStaging\Backend\Modules\Jobs
|
20 |
*/
|
21 |
-
class DatabaseExternal extends JobExecutable
|
|
|
22 |
|
23 |
/**
|
24 |
* @var int
|
@@ -36,27 +33,15 @@ class DatabaseExternal extends JobExecutable {
|
|
36 |
*/
|
37 |
private $stagingDb;
|
38 |
|
39 |
-
/**
|
40 |
-
* The database client
|
41 |
-
* @var obj
|
42 |
-
*/
|
43 |
-
//private $mysql;
|
44 |
-
|
45 |
/**
|
46 |
* Initialize
|
47 |
*/
|
48 |
-
public function initialize()
|
49 |
-
|
|
|
50 |
$this->stagingDb = $this->getExternalDBConnection();
|
51 |
-
$this->total
|
52 |
$this->isFatalError();
|
53 |
-
|
54 |
-
// Get database client
|
55 |
-
// if( empty( $this->db->use_mysqli ) ) {
|
56 |
-
// $this->mysql = new MySQL( $this->db );
|
57 |
-
// } else {
|
58 |
-
// $this->mysql = new MySQLi( $this->db );
|
59 |
-
// }
|
60 |
}
|
61 |
|
62 |
/**
|
@@ -65,23 +50,22 @@ class DatabaseExternal extends JobExecutable {
|
|
65 |
*/
|
66 |
private function getExternalDBConnection() {
|
67 |
|
68 |
-
$db = new \wpdb( $this->options->databaseUser,
|
69 |
|
70 |
// Can not connect to mysql
|
71 |
-
if(
|
72 |
-
$this->returnException(
|
73 |
return false;
|
74 |
}
|
75 |
|
76 |
// Can not connect to database
|
77 |
-
$db->select(
|
78 |
-
if(
|
79 |
-
$error = isset(
|
80 |
-
$this->returnException(
|
81 |
exit;
|
82 |
}
|
83 |
|
84 |
-
|
85 |
return $db;
|
86 |
}
|
87 |
|
@@ -90,9 +74,10 @@ class DatabaseExternal extends JobExecutable {
|
|
90 |
* and mainJob is not updating the clone
|
91 |
* @return boolean
|
92 |
*/
|
93 |
-
private function isFatalError()
|
|
|
94 |
$path = trailingslashit($this->options->cloneDir);
|
95 |
-
if(
|
96 |
$this->returnException(" Can not continue for security purposes. Directory {$path} is not empty! Use FTP or a file manager plugin and make sure it does not contain any files. ");
|
97 |
}
|
98 |
return false;
|
@@ -102,7 +87,8 @@ class DatabaseExternal extends JobExecutable {
|
|
102 |
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
103 |
* @return void
|
104 |
*/
|
105 |
-
protected function calculateTotalSteps()
|
|
|
106 |
$this->options->totalSteps = ($this->total === 0) ? 1 : $this->total;
|
107 |
}
|
108 |
|
@@ -111,36 +97,33 @@ class DatabaseExternal extends JobExecutable {
|
|
111 |
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
112 |
* @return bool
|
113 |
*/
|
114 |
-
protected function execute()
|
115 |
-
|
116 |
-
|
117 |
// Over limits threshold
|
118 |
-
if(
|
119 |
// Prepare response and save current progress
|
120 |
-
$this->prepareResponse(
|
121 |
$this->saveOptions();
|
122 |
return false;
|
123 |
}
|
124 |
|
125 |
// No more steps, finished
|
126 |
if (!$this->isRunning() || $this->options->currentStep > $this->total) {
|
127 |
-
$this->prepareResponse(
|
128 |
return false;
|
129 |
}
|
130 |
|
131 |
// Copy table
|
132 |
-
if(
|
133 |
-
|
134 |
-
$this->prepareResponse( false, false );
|
135 |
|
136 |
-
//
|
137 |
return true;
|
138 |
}
|
139 |
|
140 |
-
// Prepare Response
|
141 |
$this->prepareResponse();
|
142 |
|
143 |
-
//
|
144 |
return true;
|
145 |
}
|
146 |
|
@@ -148,10 +131,9 @@ class DatabaseExternal extends JobExecutable {
|
|
148 |
* Get new prefix for the staging site
|
149 |
* @return string
|
150 |
*/
|
151 |
-
private function getStagingPrefix()
|
152 |
-
|
153 |
-
$this->options->prefix = !empty(
|
154 |
-
|
155 |
return $this->options->prefix;
|
156 |
}
|
157 |
|
@@ -160,25 +142,26 @@ class DatabaseExternal extends JobExecutable {
|
|
160 |
* @param string $tableName
|
161 |
* @return bool
|
162 |
*/
|
163 |
-
private function copyTable(
|
|
|
164 |
|
165 |
-
$strings
|
166 |
-
$tableName
|
167 |
-
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first(
|
168 |
|
169 |
// Drop table if necessary
|
170 |
-
$this->dropTable(
|
171 |
|
172 |
// Save current job
|
173 |
-
$this->setJob(
|
174 |
|
175 |
// Beginning of the job
|
176 |
-
if(
|
177 |
return true;
|
178 |
}
|
179 |
|
180 |
// Copy data
|
181 |
-
$this->copyData(
|
182 |
|
183 |
// Finish the step
|
184 |
return $this->finishStep();
|
@@ -188,13 +171,14 @@ class DatabaseExternal extends JobExecutable {
|
|
188 |
* Set the job
|
189 |
* @param string $table
|
190 |
*/
|
191 |
-
private function setJob(
|
192 |
-
|
|
|
193 |
return;
|
194 |
}
|
195 |
|
196 |
$this->options->job->current = $table;
|
197 |
-
$this->options->job->start
|
198 |
}
|
199 |
|
200 |
/**
|
@@ -203,43 +187,43 @@ class DatabaseExternal extends JobExecutable {
|
|
203 |
* @param string $old
|
204 |
* @return bool
|
205 |
*/
|
206 |
-
private function startJob(
|
207 |
-
|
208 |
-
if(
|
209 |
return false;
|
210 |
}
|
211 |
|
212 |
-
if(
|
213 |
return true;
|
214 |
}
|
215 |
|
216 |
// Table does not exist
|
217 |
-
|
218 |
-
|
219 |
-
if( !$result || 0 === $result ) {
|
220 |
return true;
|
221 |
}
|
222 |
|
223 |
-
$this->log(
|
224 |
-
$sql = $this->
|
225 |
|
226 |
// Replace table prefix to the new one
|
227 |
-
$sql = str_replace(
|
|
|
228 |
|
229 |
// Make constraint unique to prevent error:(errno: 121 "Duplicate key on write or update")
|
230 |
$sql = wpstg_unique_constraint($sql);
|
231 |
|
232 |
$this->stagingDb->query('SET FOREIGN_KEY_CHECKS=0;');
|
233 |
|
234 |
-
if(
|
235 |
-
$this->returnException(
|
236 |
}
|
237 |
|
238 |
// Count amount of tables to insert with next step
|
239 |
$this->options->job->total = 0;
|
240 |
-
$this->options->job->total = ( int )
|
241 |
|
242 |
-
if(
|
243 |
$this->finishStep();
|
244 |
return false;
|
245 |
}
|
@@ -247,42 +231,18 @@ class DatabaseExternal extends JobExecutable {
|
|
247 |
return true;
|
248 |
}
|
249 |
|
250 |
-
/**
|
251 |
-
* Change create statements according to MySQL version
|
252 |
-
* @since 1.0.0
|
253 |
-
*/
|
254 |
-
// private function adaptCreateStatement( $create ) {
|
255 |
-
//
|
256 |
-
// $fromDbVersion = $this->stagingDb->get_var("SELECT VERSION()");
|
257 |
-
//
|
258 |
-
// $toDbVersion = $this->db->get_var("SELECT VERSION()");
|
259 |
-
//
|
260 |
-
// // If same version, all is good
|
261 |
-
// if( version_compare( $fromDbVersion, $toDbVersion ) == 0 ) {
|
262 |
-
// return $create;
|
263 |
-
// }
|
264 |
-
//
|
265 |
-
// // Change from unicode 5.2 (520) to "normal" utf8mb4 unicode on MySQL versions before 5.6
|
266 |
-
// if( version_compare( $toDbVersion, '5.6', '<' ) ) {
|
267 |
-
// $create = str_replace( 'utf8mb4_unicode_520_ci', 'utf8mb4_unicode_ci', $create );
|
268 |
-
// $create = str_replace( 'utf8_unicode_520_ci', 'utf8_unicode_ci', $create );
|
269 |
-
// }
|
270 |
-
//
|
271 |
-
// return $create;
|
272 |
-
// }
|
273 |
-
|
274 |
/**
|
275 |
* Get MySQL query create table
|
276 |
*
|
277 |
-
* @param
|
278 |
* @return array
|
279 |
*/
|
280 |
-
private function
|
281 |
-
|
282 |
-
$row = $this->db->get_results(
|
283 |
|
284 |
// Get create table
|
285 |
-
if(
|
286 |
return $row[0]['Create Table'];
|
287 |
}
|
288 |
return array();
|
@@ -293,37 +253,37 @@ class DatabaseExternal extends JobExecutable {
|
|
293 |
* @param string $new
|
294 |
* @param string $old
|
295 |
*/
|
296 |
-
private function copyData(
|
|
|
297 |
|
298 |
$rows = $this->options->job->start + $this->settings->queryLimit;
|
299 |
$this->log(
|
300 |
-
|
301 |
);
|
302 |
|
303 |
$limitation = '';
|
304 |
|
305 |
-
if(
|
306 |
$limitation = " LIMIT {$this->settings->queryLimit} OFFSET {$this->options->job->start}";
|
307 |
}
|
308 |
|
309 |
// Get data from production site
|
310 |
-
$rows = $this->db->get_results(
|
311 |
|
312 |
// Start transaction
|
313 |
-
$this->stagingDb->query(
|
314 |
-
$this->stagingDb->query(
|
315 |
-
$this->stagingDb->query(
|
316 |
|
317 |
// Copy into staging site
|
318 |
-
foreach (
|
319 |
-
$escaped_values = $this->mysqlEscapeMimic(
|
320 |
-
$values
|
321 |
-
$this->stagingDb->query(
|
322 |
}
|
323 |
// Commit transaction
|
324 |
-
$this->stagingDb->query(
|
325 |
-
$this->stagingDb->query(
|
326 |
-
|
327 |
|
328 |
// Set new offset
|
329 |
$this->options->job->start += $this->settings->queryLimit;
|
@@ -333,15 +293,16 @@ class DatabaseExternal extends JobExecutable {
|
|
333 |
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
334 |
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
335 |
* @access public
|
336 |
-
* @param
|
337 |
* @return string
|
338 |
*/
|
339 |
-
private function mysqlEscapeMimic(
|
340 |
-
|
341 |
-
|
|
|
342 |
}
|
343 |
-
if(
|
344 |
-
return str_replace(
|
345 |
}
|
346 |
|
347 |
return $input;
|
@@ -352,19 +313,20 @@ class DatabaseExternal extends JobExecutable {
|
|
352 |
* @param string $table
|
353 |
* @return boolean
|
354 |
*/
|
355 |
-
private function isExcludedTable(
|
|
|
356 |
|
357 |
-
$customTables
|
358 |
$defaultTables = array('blogs', 'blog_versions');
|
359 |
|
360 |
-
$tables = array_merge(
|
361 |
|
362 |
$excludedTables = array();
|
363 |
-
foreach (
|
364 |
$excludedTables[] = $this->options->prefix . $value;
|
365 |
}
|
366 |
|
367 |
-
if(
|
368 |
return true;
|
369 |
}
|
370 |
return false;
|
@@ -373,14 +335,15 @@ class DatabaseExternal extends JobExecutable {
|
|
373 |
/**
|
374 |
* Finish the step
|
375 |
*/
|
376 |
-
private function finishStep()
|
|
|
377 |
// This job is not finished yet
|
378 |
-
if(
|
379 |
return false;
|
380 |
}
|
381 |
|
382 |
// Add it to cloned tables listing
|
383 |
-
$this->options->clonedTables[] = isset(
|
384 |
|
385 |
// Reset job
|
386 |
$this->options->job = new \stdClass();
|
@@ -392,17 +355,18 @@ class DatabaseExternal extends JobExecutable {
|
|
392 |
* Drop table if necessary
|
393 |
* @param string $new
|
394 |
*/
|
395 |
-
private function dropTable(
|
396 |
-
|
|
|
397 |
|
398 |
-
if(
|
399 |
return;
|
400 |
}
|
401 |
|
402 |
-
$this->log(
|
403 |
-
$this->stagingDb->query(
|
404 |
-
$this->stagingDb->query(
|
405 |
-
$this->stagingDb->query(
|
406 |
}
|
407 |
|
408 |
/**
|
@@ -411,16 +375,14 @@ class DatabaseExternal extends JobExecutable {
|
|
411 |
* @param string $old
|
412 |
* @return bool
|
413 |
*/
|
414 |
-
private function shouldDropTable(
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
(
|
420 |
-
!isset( $this->options->job->current ) ||
|
421 |
-
!isset( $this->options->job->start ) ||
|
422 |
0 == $this->options->job->start
|
423 |
-
|
424 |
return true;
|
425 |
}
|
426 |
return false;
|
3 |
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
|
5 |
// No Direct Access
|
6 |
+
if (!defined("WPINC")) {
|
7 |
die;
|
8 |
}
|
9 |
|
10 |
use WPStaging\WPStaging;
|
11 |
use WPStaging\Utils\Strings;
|
|
|
|
|
|
|
|
|
12 |
|
13 |
/**
|
14 |
* Class Database
|
15 |
* @package WPStaging\Backend\Modules\Jobs
|
16 |
*/
|
17 |
+
class DatabaseExternal extends JobExecutable
|
18 |
+
{
|
19 |
|
20 |
/**
|
21 |
* @var int
|
33 |
*/
|
34 |
private $stagingDb;
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
/**
|
37 |
* Initialize
|
38 |
*/
|
39 |
+
public function initialize()
|
40 |
+
{
|
41 |
+
$this->db = WPStaging::getInstance()->get("wpdb");
|
42 |
$this->stagingDb = $this->getExternalDBConnection();
|
43 |
+
$this->total = count($this->options->tables);
|
44 |
$this->isFatalError();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
}
|
46 |
|
47 |
/**
|
50 |
*/
|
51 |
private function getExternalDBConnection() {
|
52 |
|
53 |
+
$db = new \wpdb( $this->options->databaseUser, $this->options->databasePassword, $this->options->databaseDatabase, $this->options->databaseServer );
|
54 |
|
55 |
// Can not connect to mysql
|
56 |
+
if (!empty($db->error->errors['db_connect_fail']['0'])) {
|
57 |
+
$this->returnException("Can not connect to external database {$this->options->databaseDatabase}");
|
58 |
return false;
|
59 |
}
|
60 |
|
61 |
// Can not connect to database
|
62 |
+
$db->select($this->options->databaseDatabase);
|
63 |
+
if (!$db->ready) {
|
64 |
+
$error = isset($db->error->errors['db_select_fail']) ? $db->error->errors['db_select_fail'] : "Error: Can't select {database} Either it does not exist or you don't have privileges to access it.";
|
65 |
+
$this->returnException($error);
|
66 |
exit;
|
67 |
}
|
68 |
|
|
|
69 |
return $db;
|
70 |
}
|
71 |
|
74 |
* and mainJob is not updating the clone
|
75 |
* @return boolean
|
76 |
*/
|
77 |
+
private function isFatalError()
|
78 |
+
{
|
79 |
$path = trailingslashit($this->options->cloneDir);
|
80 |
+
if (isset($this->options->mainJob) && $this->options->mainJob !== 'updating' && (is_dir($path) && !wpstg_is_empty_dir($path))) {
|
81 |
$this->returnException(" Can not continue for security purposes. Directory {$path} is not empty! Use FTP or a file manager plugin and make sure it does not contain any files. ");
|
82 |
}
|
83 |
return false;
|
87 |
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
88 |
* @return void
|
89 |
*/
|
90 |
+
protected function calculateTotalSteps()
|
91 |
+
{
|
92 |
$this->options->totalSteps = ($this->total === 0) ? 1 : $this->total;
|
93 |
}
|
94 |
|
97 |
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
98 |
* @return bool
|
99 |
*/
|
100 |
+
protected function execute()
|
101 |
+
{
|
|
|
102 |
// Over limits threshold
|
103 |
+
if ($this->isOverThreshold()) {
|
104 |
// Prepare response and save current progress
|
105 |
+
$this->prepareResponse(false, false);
|
106 |
$this->saveOptions();
|
107 |
return false;
|
108 |
}
|
109 |
|
110 |
// No more steps, finished
|
111 |
if (!$this->isRunning() || $this->options->currentStep > $this->total) {
|
112 |
+
$this->prepareResponse(true, false);
|
113 |
return false;
|
114 |
}
|
115 |
|
116 |
// Copy table
|
117 |
+
if (isset($this->options->tables[$this->options->currentStep]) && !$this->copyTable($this->options->tables[$this->options->currentStep])) {
|
118 |
+
$this->prepareResponse(false, false);
|
|
|
119 |
|
120 |
+
// Continue execution
|
121 |
return true;
|
122 |
}
|
123 |
|
|
|
124 |
$this->prepareResponse();
|
125 |
|
126 |
+
// Continue execution
|
127 |
return true;
|
128 |
}
|
129 |
|
131 |
* Get new prefix for the staging site
|
132 |
* @return string
|
133 |
*/
|
134 |
+
private function getStagingPrefix()
|
135 |
+
{
|
136 |
+
$this->options->prefix = !empty($this->options->databasePrefix) ? $this->options->databasePrefix : $this->db->prefix;
|
|
|
137 |
return $this->options->prefix;
|
138 |
}
|
139 |
|
142 |
* @param string $tableName
|
143 |
* @return bool
|
144 |
*/
|
145 |
+
private function copyTable($tableName)
|
146 |
+
{
|
147 |
|
148 |
+
$strings = new Strings();
|
149 |
+
$tableName = is_object($tableName) ? $tableName->name : $tableName;
|
150 |
+
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first($this->db->prefix, null, $tableName);
|
151 |
|
152 |
// Drop table if necessary
|
153 |
+
$this->dropTable($newTableName);
|
154 |
|
155 |
// Save current job
|
156 |
+
$this->setJob($newTableName);
|
157 |
|
158 |
// Beginning of the job
|
159 |
+
if (!$this->startJob($newTableName, $tableName)) {
|
160 |
return true;
|
161 |
}
|
162 |
|
163 |
// Copy data
|
164 |
+
$this->copyData($newTableName, $tableName);
|
165 |
|
166 |
// Finish the step
|
167 |
return $this->finishStep();
|
171 |
* Set the job
|
172 |
* @param string $table
|
173 |
*/
|
174 |
+
private function setJob($table)
|
175 |
+
{
|
176 |
+
if (isset($this->options->job->current)) {
|
177 |
return;
|
178 |
}
|
179 |
|
180 |
$this->options->job->current = $table;
|
181 |
+
$this->options->job->start = 0;
|
182 |
}
|
183 |
|
184 |
/**
|
187 |
* @param string $old
|
188 |
* @return bool
|
189 |
*/
|
190 |
+
private function startJob($new, $old)
|
191 |
+
{
|
192 |
+
if ($this->isExcludedTable($new)) {
|
193 |
return false;
|
194 |
}
|
195 |
|
196 |
+
if (0 != $this->options->job->start) {
|
197 |
return true;
|
198 |
}
|
199 |
|
200 |
// Table does not exist
|
201 |
+
$result = $this->db->query("SHOW TABLES LIKE '{$old}'");
|
202 |
+
if (!$result || 0 === $result) {
|
|
|
203 |
return true;
|
204 |
}
|
205 |
|
206 |
+
$this->log("DB External Copy: CREATE table {$this->options->databaseDatabase}.{$new}");
|
207 |
+
$sql = $this->getTableCreateStatement($old);
|
208 |
|
209 |
// Replace table prefix to the new one
|
210 |
+
$sql = str_replace("CREATE TABLE `{$old}`", "CREATE TABLE `{$new}`", $sql);
|
211 |
+
|
212 |
|
213 |
// Make constraint unique to prevent error:(errno: 121 "Duplicate key on write or update")
|
214 |
$sql = wpstg_unique_constraint($sql);
|
215 |
|
216 |
$this->stagingDb->query('SET FOREIGN_KEY_CHECKS=0;');
|
217 |
|
218 |
+
if (false === $this->stagingDb->query($sql)) {
|
219 |
+
$this->returnException("DB External Copy - Fatal Error: {$this->stagingDb->last_error} Query: {$sql}");
|
220 |
}
|
221 |
|
222 |
// Count amount of tables to insert with next step
|
223 |
$this->options->job->total = 0;
|
224 |
+
$this->options->job->total = ( int )$this->db->get_var("SELECT COUNT(1) FROM `{$this->db->dbname}`.`{$old}`");
|
225 |
|
226 |
+
if (0 == $this->options->job->total) {
|
227 |
$this->finishStep();
|
228 |
return false;
|
229 |
}
|
231 |
return true;
|
232 |
}
|
233 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
/**
|
235 |
* Get MySQL query create table
|
236 |
*
|
237 |
+
* @param string $table_name Table name
|
238 |
* @return array
|
239 |
*/
|
240 |
+
private function getTableCreateStatement($tableName)
|
241 |
+
{
|
242 |
+
$row = $this->db->get_results("SHOW CREATE TABLE `{$tableName}`", ARRAY_A);
|
243 |
|
244 |
// Get create table
|
245 |
+
if (isset($row[0]['Create Table'])) {
|
246 |
return $row[0]['Create Table'];
|
247 |
}
|
248 |
return array();
|
253 |
* @param string $new
|
254 |
* @param string $old
|
255 |
*/
|
256 |
+
private function copyData($new, $old)
|
257 |
+
{
|
258 |
|
259 |
$rows = $this->options->job->start + $this->settings->queryLimit;
|
260 |
$this->log(
|
261 |
+
"DB External Copy: INSERT {$this->db->dbname}.{$old} as {$this->options->databaseDatabase}.{$new} from {$this->options->job->start} to {$rows} records"
|
262 |
);
|
263 |
|
264 |
$limitation = '';
|
265 |
|
266 |
+
if (0 < ( int )$this->settings->queryLimit) {
|
267 |
$limitation = " LIMIT {$this->settings->queryLimit} OFFSET {$this->options->job->start}";
|
268 |
}
|
269 |
|
270 |
// Get data from production site
|
271 |
+
$rows = $this->db->get_results("SELECT * FROM `{$old}` {$limitation}", ARRAY_A);
|
272 |
|
273 |
// Start transaction
|
274 |
+
$this->stagingDb->query('SET autocommit=0;');
|
275 |
+
$this->stagingDb->query('SET FOREIGN_KEY_CHECKS=0;');
|
276 |
+
$this->stagingDb->query('START TRANSACTION;');
|
277 |
|
278 |
// Copy into staging site
|
279 |
+
foreach ($rows as $row) {
|
280 |
+
$escaped_values = $this->mysqlEscapeMimic(array_values($row));
|
281 |
+
$values = implode("', '", $escaped_values);
|
282 |
+
$this->stagingDb->query("INSERT INTO `{$new}` VALUES ('{$values}')");
|
283 |
}
|
284 |
// Commit transaction
|
285 |
+
$this->stagingDb->query('COMMIT;');
|
286 |
+
$this->stagingDb->query('SET autocommit=1;');
|
|
|
287 |
|
288 |
// Set new offset
|
289 |
$this->options->job->start += $this->settings->queryLimit;
|
293 |
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
294 |
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
295 |
* @access public
|
296 |
+
* @param string $input The string to escape.
|
297 |
* @return string
|
298 |
*/
|
299 |
+
private function mysqlEscapeMimic($input)
|
300 |
+
{
|
301 |
+
if (is_array($input)) {
|
302 |
+
return array_map(__METHOD__, $input);
|
303 |
}
|
304 |
+
if (!empty($input) && is_string($input)) {
|
305 |
+
return str_replace(array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $input);
|
306 |
}
|
307 |
|
308 |
return $input;
|
313 |
* @param string $table
|
314 |
* @return boolean
|
315 |
*/
|
316 |
+
private function isExcludedTable($table)
|
317 |
+
{
|
318 |
|
319 |
+
$customTables = apply_filters('wpstg_clone_database_tables_exclude', array());
|
320 |
$defaultTables = array('blogs', 'blog_versions');
|
321 |
|
322 |
+
$tables = array_merge($customTables, $defaultTables);
|
323 |
|
324 |
$excludedTables = array();
|
325 |
+
foreach ($tables as $key => $value) {
|
326 |
$excludedTables[] = $this->options->prefix . $value;
|
327 |
}
|
328 |
|
329 |
+
if (in_array($table, $excludedTables)) {
|
330 |
return true;
|
331 |
}
|
332 |
return false;
|
335 |
/**
|
336 |
* Finish the step
|
337 |
*/
|
338 |
+
private function finishStep()
|
339 |
+
{
|
340 |
// This job is not finished yet
|
341 |
+
if ($this->options->job->total > $this->options->job->start) {
|
342 |
return false;
|
343 |
}
|
344 |
|
345 |
// Add it to cloned tables listing
|
346 |
+
$this->options->clonedTables[] = isset($this->options->tables[$this->options->currentStep]) ? $this->options->tables[$this->options->currentStep] : false;
|
347 |
|
348 |
// Reset job
|
349 |
$this->options->job = new \stdClass();
|
355 |
* Drop table if necessary
|
356 |
* @param string $new
|
357 |
*/
|
358 |
+
private function dropTable($new)
|
359 |
+
{
|
360 |
+
$old = $this->stagingDb->get_var($this->stagingDb->prepare("SHOW TABLES LIKE %s", $new));
|
361 |
|
362 |
+
if (!$this->shouldDropTable($new, $old)) {
|
363 |
return;
|
364 |
}
|
365 |
|
366 |
+
$this->log("DB External Copy: {$new} already exists, dropping it first");
|
367 |
+
$this->stagingDb->query("SET FOREIGN_KEY_CHECKS=0");
|
368 |
+
$this->stagingDb->query("DROP TABLE {$new}");
|
369 |
+
$this->stagingDb->query("SET FOREIGN_KEY_CHECKS=1");
|
370 |
}
|
371 |
|
372 |
/**
|
375 |
* @param string $old
|
376 |
* @return bool
|
377 |
*/
|
378 |
+
private function shouldDropTable($new, $old)
|
379 |
+
{
|
380 |
+
if ($old === $new &&
|
381 |
+
(
|
382 |
+
!isset($this->options->job->current) ||
|
383 |
+
!isset($this->options->job->start) ||
|
|
|
|
|
384 |
0 == $this->options->job->start
|
385 |
+
)) {
|
386 |
return true;
|
387 |
}
|
388 |
return false;
|
Backend/Modules/Jobs/Files.php
CHANGED
@@ -310,6 +310,10 @@ class Files extends JobExecutable
|
|
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))) {
|
310 |
$src = fopen($src, 'r');
|
311 |
$dest = fopen($dst, 'w');
|
312 |
|
313 |
+
if (!$src || !$dest) {
|
314 |
+
return false;
|
315 |
+
}
|
316 |
+
|
317 |
// Try first method:
|
318 |
while (!feof($src)) {
|
319 |
if (false === fwrite($dest, fread($src, $buffersize))) {
|
Backend/Modules/Jobs/Multisite/Data.php
CHANGED
@@ -149,7 +149,6 @@ class Data extends JobExecutable
|
|
149 |
{
|
150 |
|
151 |
// Prefix is the same as the one of live site
|
152 |
-
//$wpdb = WPStaging::getInstance()->get( "wpdb" );
|
153 |
if ($this->db->prefix === $this->prefix) {
|
154 |
return true;
|
155 |
}
|
@@ -173,7 +172,7 @@ class Data extends JobExecutable
|
|
173 |
* @param string $table
|
174 |
* @return boolean
|
175 |
*/
|
176 |
-
protected function
|
177 |
{
|
178 |
if ($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table) {
|
179 |
$this->log("Table {$table} does not exist", Logger::TYPE_ERROR);
|
@@ -299,7 +298,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
299 |
|
300 |
/**
|
301 |
* Check if wp-config.php contains important constants
|
302 |
-
* @param
|
303 |
* @return boolean
|
304 |
*/
|
305 |
protected function isValidWpConfig($source)
|
@@ -310,7 +309,6 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
310 |
return false;
|
311 |
}
|
312 |
|
313 |
-
$content = file_get_contents($source);
|
314 |
|
315 |
if (false === ($content = file_get_contents($source))) {
|
316 |
$this->log("Preparing Data Step0: Can not read {$source}", Logger::TYPE_INFO);
|
@@ -360,7 +358,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
360 |
$this->log("Preparing Data Step1: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO);
|
361 |
|
362 |
// Skip - Table does not exist
|
363 |
-
if (false === $this->
|
364 |
return true;
|
365 |
}
|
366 |
// Skip - Table is not selected or updated
|
@@ -397,7 +395,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
397 |
$this->log("Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}");
|
398 |
|
399 |
// Skip - Table does not exist
|
400 |
-
if (false === $this->
|
401 |
$this->log("Preparing Data Step2: Skipping");
|
402 |
return true;
|
403 |
}
|
@@ -448,7 +446,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
448 |
}
|
449 |
|
450 |
// Skip - Table does not exist
|
451 |
-
if (false === $this->
|
452 |
return true;
|
453 |
}
|
454 |
|
@@ -482,7 +480,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
482 |
$this->log("Preparing Data Step4: Updating db prefix in {$this->prefix}usermeta. ");
|
483 |
|
484 |
// Skip - Table does not exist
|
485 |
-
if (false === $this->
|
486 |
return true;
|
487 |
}
|
488 |
|
@@ -548,7 +546,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
548 |
$content = str_replace($this->multisiteHomeDomain, $this->getStagingSiteUrl(), $content);
|
549 |
|
550 |
if (false === @wpstg_put_contents($path, $content)) {
|
551 |
-
$this->log("Preparing Data Step5: Failed to update
|
552 |
return false;
|
553 |
}
|
554 |
|
@@ -620,7 +618,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
620 |
$this->log("Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}");
|
621 |
|
622 |
// Skip - Table does not exist
|
623 |
-
if (false === $this->
|
624 |
$this->log("Preparing Data Step7: Skipping Table {$this->prefix}'options' does not exist");
|
625 |
return true;
|
626 |
}
|
@@ -663,7 +661,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
663 |
}
|
664 |
|
665 |
// Skip - Table does not exist
|
666 |
-
if (false === $this->
|
667 |
$this->log("Preparing Data Step8: Skipping");
|
668 |
return true;
|
669 |
}
|
@@ -699,7 +697,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
699 |
|
700 |
$this->log("Preparing Data Step9: Set staging site to noindex");
|
701 |
|
702 |
-
if (false === $this->
|
703 |
return true;
|
704 |
}
|
705 |
|
@@ -750,7 +748,6 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
750 |
$pattern = "/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*(.*)\s*\);.*/";
|
751 |
|
752 |
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1] . " Changed by WP-Staging";
|
753 |
-
//$replace.= " // Changed by WP-Staging";
|
754 |
|
755 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
756 |
$this->log("Preparing Data: Failed to update WP_HOME", Logger::TYPE_ERROR);
|
@@ -793,7 +790,6 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
793 |
$pattern = "/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*(.*)\s*\);.*/";
|
794 |
|
795 |
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1] . " Changed by WP-Staging";
|
796 |
-
//$replace.= " // Changed by WP-Staging";
|
797 |
|
798 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
799 |
$this->log("Preparing Data Step11: Failed to update WP_SITEURL to " . $this->getStagingSiteUrl(), Logger::TYPE_ERROR);
|
@@ -910,7 +906,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
910 |
|
911 |
$this->log("Data Crunching Step14: Updating active_plugins");
|
912 |
|
913 |
-
if (false === $this->
|
914 |
$this->log('Data Crunching Step14: Fatal Error ' . $this->prefix . 'options does not exist');
|
915 |
$this->returnException('Data Crunching Step14: Fatal Error ' . $this->prefix . 'options does not exist');
|
916 |
return false;
|
@@ -968,7 +964,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
968 |
$this->log("Preparing Data Step15: Updating db prefix in {$this->prefix}options.");
|
969 |
|
970 |
// Skip - Table does not exist
|
971 |
-
if (false === $this->
|
972 |
return true;
|
973 |
}
|
974 |
|
@@ -1020,7 +1016,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1020 |
$this->log("Preparing Data Step16: Updating upload_path {$this->prefix}options.");
|
1021 |
|
1022 |
// Skip - Table does not exist
|
1023 |
-
if (false === $this->
|
1024 |
return true;
|
1025 |
}
|
1026 |
|
@@ -1184,11 +1180,13 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1184 |
*/
|
1185 |
protected function step20()
|
1186 |
{
|
|
|
1187 |
|
1188 |
$table = $this->prefix . 'options';
|
1189 |
|
1190 |
// Skip - Table does not exist
|
1191 |
-
if (false === $this->
|
|
|
1192 |
return true;
|
1193 |
}
|
1194 |
|
@@ -1205,82 +1203,24 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1205 |
return true;
|
1206 |
}
|
1207 |
|
1208 |
-
/**
|
1209 |
-
* Preserve data and prevents data in wp_options from beeing cloned to staging site
|
1210 |
-
* @return bool
|
1211 |
-
*/
|
1212 |
-
protected function step21()
|
1213 |
-
{
|
1214 |
-
$this->log("Preparing Data Step21: Preserve Data in " . $this->prefix . "options");
|
1215 |
-
|
1216 |
-
// Skip - Table does not exist
|
1217 |
-
if (false === $this->isTable($this->prefix . 'options')) {
|
1218 |
-
return true;
|
1219 |
-
}
|
1220 |
-
|
1221 |
-
// Skip - Table is not selected or updated
|
1222 |
-
if (!in_array($this->prefix . 'options', $this->tables)) {
|
1223 |
-
$this->log("Preparing Data Step21: Skipped");
|
1224 |
-
return true;
|
1225 |
-
}
|
1226 |
-
|
1227 |
-
$sql = '';
|
1228 |
-
|
1229 |
-
$preserved_option_names = array('wpstg_existing_clones_beta');
|
1230 |
-
|
1231 |
-
$preserved_option_names = apply_filters('wpstg_preserved_options_cloning', $preserved_option_names);
|
1232 |
-
$preserved_options_escaped = esc_sql($preserved_option_names);
|
1233 |
-
|
1234 |
-
$preserved_options_data = array();
|
1235 |
-
|
1236 |
-
// Get preserved data in wp_options tables
|
1237 |
-
$table = $this->db->prefix . 'options';
|
1238 |
-
$preserved_options_data[$this->prefix . 'options'] = $this->db->get_results(
|
1239 |
-
sprintf(
|
1240 |
-
"SELECT * FROM `{$table}` WHERE `option_name` IN ('%s')", implode("','", $preserved_options_escaped)
|
1241 |
-
), ARRAY_A
|
1242 |
-
);
|
1243 |
-
|
1244 |
-
// Create preserved data queries for options tables
|
1245 |
-
foreach ($preserved_options_data as $key => $value) {
|
1246 |
-
if (false === empty($value)) {
|
1247 |
-
foreach ($value as $option) {
|
1248 |
-
$sql .= $this->db->prepare(
|
1249 |
-
"DELETE FROM `{$key}` WHERE `option_name` = %s;\n", $option['option_name']
|
1250 |
-
);
|
1251 |
-
|
1252 |
-
$sql .= $this->db->prepare(
|
1253 |
-
"INSERT INTO `{$key}` ( `option_id`, `option_name`, `option_value`, `autoload` ) VALUES ( NULL , %s, %s, %s );\n", $option['option_name'], $option['option_value'], $option['autoload']
|
1254 |
-
);
|
1255 |
-
}
|
1256 |
-
}
|
1257 |
-
}
|
1258 |
-
|
1259 |
-
$this->debugLog("Preparing Data Step21: Preserve values " . json_encode($preserved_options_data), Logger::TYPE_INFO);
|
1260 |
-
|
1261 |
-
$this->executeSql($sql);
|
1262 |
-
|
1263 |
-
$this->log("Preparing Data Step21: Successful!");
|
1264 |
-
return true;
|
1265 |
-
}
|
1266 |
-
|
1267 |
/**
|
1268 |
* Check if there is a multisite super administrator.
|
1269 |
* If not add it to _usermeta
|
1270 |
* @return bool
|
1271 |
*/
|
1272 |
-
protected function
|
1273 |
{
|
1274 |
-
$
|
|
|
1275 |
|
1276 |
// Skip - Table does not exist
|
1277 |
-
if (false === $this->
|
1278 |
return true;
|
1279 |
}
|
1280 |
|
1281 |
// Skip - Table is not selected or updated
|
1282 |
if (!in_array($this->prefix . 'usermeta', $this->tables)) {
|
1283 |
-
$this->log(
|
1284 |
return true;
|
1285 |
}
|
1286 |
|
@@ -1314,6 +1254,7 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1314 |
return true;
|
1315 |
}
|
1316 |
|
|
|
1317 |
/**
|
1318 |
* Execute a batch of sql queries
|
1319 |
* @param string $sqlbatch
|
@@ -1330,6 +1271,35 @@ define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
|
1330 |
return true;
|
1331 |
}
|
1332 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1333 |
/**
|
1334 |
* Get relative path to the uploads media folder of multisite e.g.
|
1335 |
* wp-content/uploads/sites/SITEID or old wordpress structure wp-content/blogs.dir/SITEID/files
|
149 |
{
|
150 |
|
151 |
// Prefix is the same as the one of live site
|
|
|
152 |
if ($this->db->prefix === $this->prefix) {
|
153 |
return true;
|
154 |
}
|
172 |
* @param string $table
|
173 |
* @return boolean
|
174 |
*/
|
175 |
+
protected function tableExists($table)
|
176 |
{
|
177 |
if ($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table) {
|
178 |
$this->log("Table {$table} does not exist", Logger::TYPE_ERROR);
|
298 |
|
299 |
/**
|
300 |
* Check if wp-config.php contains important constants
|
301 |
+
* @param string $source
|
302 |
* @return boolean
|
303 |
*/
|
304 |
protected function isValidWpConfig($source)
|
309 |
return false;
|
310 |
}
|
311 |
|
|
|
312 |
|
313 |
if (false === ($content = file_get_contents($source))) {
|
314 |
$this->log("Preparing Data Step0: Can not read {$source}", Logger::TYPE_INFO);
|
358 |
$this->log("Preparing Data Step1: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO);
|
359 |
|
360 |
// Skip - Table does not exist
|
361 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
362 |
return true;
|
363 |
}
|
364 |
// Skip - Table is not selected or updated
|
395 |
$this->log("Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}");
|
396 |
|
397 |
// Skip - Table does not exist
|
398 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
399 |
$this->log("Preparing Data Step2: Skipping");
|
400 |
return true;
|
401 |
}
|
446 |
}
|
447 |
|
448 |
// Skip - Table does not exist
|
449 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
450 |
return true;
|
451 |
}
|
452 |
|
480 |
$this->log("Preparing Data Step4: Updating db prefix in {$this->prefix}usermeta. ");
|
481 |
|
482 |
// Skip - Table does not exist
|
483 |
+
if (false === $this->tableExists($this->prefix . 'usermeta')) {
|
484 |
return true;
|
485 |
}
|
486 |
|
546 |
$content = str_replace($this->multisiteHomeDomain, $this->getStagingSiteUrl(), $content);
|
547 |
|
548 |
if (false === @wpstg_put_contents($path, $content)) {
|
549 |
+
$this->log("Preparing Data Step5: Failed to update table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR);
|
550 |
return false;
|
551 |
}
|
552 |
|
618 |
$this->log("Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}");
|
619 |
|
620 |
// Skip - Table does not exist
|
621 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
622 |
$this->log("Preparing Data Step7: Skipping Table {$this->prefix}'options' does not exist");
|
623 |
return true;
|
624 |
}
|
661 |
}
|
662 |
|
663 |
// Skip - Table does not exist
|
664 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
665 |
$this->log("Preparing Data Step8: Skipping");
|
666 |
return true;
|
667 |
}
|
697 |
|
698 |
$this->log("Preparing Data Step9: Set staging site to noindex");
|
699 |
|
700 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
701 |
return true;
|
702 |
}
|
703 |
|
748 |
$pattern = "/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*(.*)\s*\);.*/";
|
749 |
|
750 |
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1] . " Changed by WP-Staging";
|
|
|
751 |
|
752 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
753 |
$this->log("Preparing Data: Failed to update WP_HOME", Logger::TYPE_ERROR);
|
790 |
$pattern = "/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*(.*)\s*\);.*/";
|
791 |
|
792 |
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1] . " Changed by WP-Staging";
|
|
|
793 |
|
794 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
795 |
$this->log("Preparing Data Step11: Failed to update WP_SITEURL to " . $this->getStagingSiteUrl(), Logger::TYPE_ERROR);
|
906 |
|
907 |
$this->log("Data Crunching Step14: Updating active_plugins");
|
908 |
|
909 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
910 |
$this->log('Data Crunching Step14: Fatal Error ' . $this->prefix . 'options does not exist');
|
911 |
$this->returnException('Data Crunching Step14: Fatal Error ' . $this->prefix . 'options does not exist');
|
912 |
return false;
|
964 |
$this->log("Preparing Data Step15: Updating db prefix in {$this->prefix}options.");
|
965 |
|
966 |
// Skip - Table does not exist
|
967 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
968 |
return true;
|
969 |
}
|
970 |
|
1016 |
$this->log("Preparing Data Step16: Updating upload_path {$this->prefix}options.");
|
1017 |
|
1018 |
// Skip - Table does not exist
|
1019 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
1020 |
return true;
|
1021 |
}
|
1022 |
|
1180 |
*/
|
1181 |
protected function step20()
|
1182 |
{
|
1183 |
+
$this->log("Preparing Data Step20: Preserve Data in " . $this->prefix . "options");
|
1184 |
|
1185 |
$table = $this->prefix . 'options';
|
1186 |
|
1187 |
// Skip - Table does not exist
|
1188 |
+
if (false === $this->tableExists($table)) {
|
1189 |
+
$this->log("Preparing Data Step21: Preserve Data in " . $this->prefix . "options");
|
1190 |
return true;
|
1191 |
}
|
1192 |
|
1203 |
return true;
|
1204 |
}
|
1205 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1206 |
/**
|
1207 |
* Check if there is a multisite super administrator.
|
1208 |
* If not add it to _usermeta
|
1209 |
* @return bool
|
1210 |
*/
|
1211 |
+
protected function step21()
|
1212 |
{
|
1213 |
+
$step = "Preparing Data Step21: ";
|
1214 |
+
$this->log($step . "Add network administrators");
|
1215 |
|
1216 |
// Skip - Table does not exist
|
1217 |
+
if (false === $this->tableExists($this->prefix . 'usermeta')) {
|
1218 |
return true;
|
1219 |
}
|
1220 |
|
1221 |
// Skip - Table is not selected or updated
|
1222 |
if (!in_array($this->prefix . 'usermeta', $this->tables)) {
|
1223 |
+
$this->log($step . "Skipping");
|
1224 |
return true;
|
1225 |
}
|
1226 |
|
1254 |
return true;
|
1255 |
}
|
1256 |
|
1257 |
+
|
1258 |
/**
|
1259 |
* Execute a batch of sql queries
|
1260 |
* @param string $sqlbatch
|
1271 |
return true;
|
1272 |
}
|
1273 |
|
1274 |
+
/**
|
1275 |
+
* Delete all listed staging sites from cloned site on initial cloning. Useful if a cloned site is cloned again. E.g. for dev > staging > production setup
|
1276 |
+
* @return bool
|
1277 |
+
*/
|
1278 |
+
protected function step22(){
|
1279 |
+
|
1280 |
+
if ($this->options->mainJob === 'updating'){
|
1281 |
+
return true;
|
1282 |
+
}
|
1283 |
+
|
1284 |
+
if( false === $this->tableExists( $this->prefix . 'options' ) ) {
|
1285 |
+
return true;
|
1286 |
+
}
|
1287 |
+
|
1288 |
+
$step = "Preparing Data Step22:";
|
1289 |
+
$this->log( $step . " Reset wp staging site data" );
|
1290 |
+
|
1291 |
+
$result = $this->db->query(
|
1292 |
+
$this->db->prepare( "UPDATE {$this->prefix}options SET `option_value` = %s WHERE `option_name` = %s", serialize(array()), 'wpstg_existing_clones_beta'
|
1293 |
+
)
|
1294 |
+
);
|
1295 |
+
|
1296 |
+
if (false === $result){
|
1297 |
+
$this->log( $step . "Failed to reset wp staging site data." );
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
return true;
|
1301 |
+
}
|
1302 |
+
|
1303 |
/**
|
1304 |
* Get relative path to the uploads media folder of multisite e.g.
|
1305 |
* wp-content/uploads/sites/SITEID or old wordpress structure wp-content/blogs.dir/SITEID/files
|
Backend/Modules/Jobs/Multisite/DataExternal.php
CHANGED
@@ -9,8 +9,6 @@ if (!defined("WPINC")) {
|
|
9 |
|
10 |
use WPStaging\Utils\Logger;
|
11 |
use WPStaging\WPStaging;
|
12 |
-
use WPStaging\Utils\Helper;
|
13 |
-
use WPStaging\Utils\Multisite;
|
14 |
use WPStaging\Utils\Strings;
|
15 |
use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
16 |
|
@@ -41,10 +39,10 @@ class DataExternal extends JobExecutable
|
|
41 |
*/
|
42 |
public function initialize()
|
43 |
{
|
44 |
-
$this->db
|
45 |
$this->productionDb = WPStaging::getInstance()->get("wpdb");
|
46 |
-
$this->prefix
|
47 |
-
$this->db->prefix
|
48 |
|
49 |
$this->getTables();
|
50 |
|
@@ -59,7 +57,7 @@ class DataExternal extends JobExecutable
|
|
59 |
*/
|
60 |
private function getStagingDB()
|
61 |
{
|
62 |
-
return new \wpdb($this->options->databaseUser,
|
63 |
}
|
64 |
|
65 |
/**
|
@@ -67,14 +65,14 @@ class DataExternal extends JobExecutable
|
|
67 |
*/
|
68 |
private function getTables()
|
69 |
{
|
70 |
-
$strings
|
71 |
$this->tables = array();
|
72 |
foreach ($this->options->tables as $table) {
|
73 |
-
$this->tables[] = $this->options->prefix
|
74 |
}
|
75 |
// Add extra global tables from main multisite (wpstgx_users and wpstgx_usermeta)
|
76 |
-
$this->tables[] = $this->options->prefix
|
77 |
-
$this->tables[] = $this->options->prefix
|
78 |
}
|
79 |
|
80 |
/**
|
@@ -128,7 +126,7 @@ class DataExternal extends JobExecutable
|
|
128 |
}
|
129 |
|
130 |
// Execute step
|
131 |
-
$stepMethodName = "step"
|
132 |
if (!$this->{$stepMethodName}()) {
|
133 |
$this->prepareResponse(false, false);
|
134 |
return false;
|
@@ -150,8 +148,7 @@ class DataExternal extends JobExecutable
|
|
150 |
return
|
151 |
!$this->isRunning() ||
|
152 |
$this->options->currentStep > $this->options->totalSteps ||
|
153 |
-
!method_exists($this, "step"
|
154 |
-
;
|
155 |
}
|
156 |
|
157 |
/**
|
@@ -185,7 +182,7 @@ class DataExternal extends JobExecutable
|
|
185 |
* @param string $table
|
186 |
* @return boolean
|
187 |
*/
|
188 |
-
protected function
|
189 |
{
|
190 |
if ($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table) {
|
191 |
$this->log("Table {$table} does not exist", Logger::TYPE_ERROR);
|
@@ -205,9 +202,9 @@ class DataExternal extends JobExecutable
|
|
205 |
|
206 |
$dir = trailingslashit(dirname(ABSPATH));
|
207 |
|
208 |
-
$source = $dir.'wp-config.php';
|
209 |
|
210 |
-
$destination = $this->options->destinationDir.'wp-config.php';
|
211 |
|
212 |
// Check if there is already a valid wp-config.php in root of staging site
|
213 |
if ($this->isValidWpConfig($destination)) {
|
@@ -225,7 +222,7 @@ class DataExternal extends JobExecutable
|
|
225 |
}
|
226 |
|
227 |
// No valid wp-config.php found so let's copy wp stagings default wp-config.php to staging site
|
228 |
-
$source = WPSTG_PLUGIN_DIR."Backend/helpers/wp-config.php";
|
229 |
|
230 |
$this->log("Preparing Data Step0: Copy default wp-config.php file from source {$source} to {$destination}", Logger::TYPE_INFO);
|
231 |
|
@@ -287,17 +284,17 @@ class DataExternal extends JobExecutable
|
|
287 |
$search = "// ** MySQL settings ** //";
|
288 |
|
289 |
$replace = "// ** MySQL settings ** //\r\n
|
290 |
-
define( 'DB_NAME', '".DB_NAME."' );\r\n
|
291 |
/** MySQL database username */\r\n
|
292 |
-
define( 'DB_USER', '".DB_USER."' );\r\n
|
293 |
/** MySQL database password */\r\n
|
294 |
-
define( 'DB_PASSWORD', '".DB_PASSWORD."' );\r\n
|
295 |
/** MySQL hostname */\r\n
|
296 |
-
define( 'DB_HOST', '".DB_HOST."' );\r\n
|
297 |
/** Database Charset to use in creating database tables. */\r\n
|
298 |
-
define( 'DB_CHARSET', '".DB_CHARSET."' );\r\n
|
299 |
/** The Database Collate type. Don't change this if in doubt. */\r\n
|
300 |
-
define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
301 |
|
302 |
$content = str_replace($search, $replace, $content);
|
303 |
|
@@ -372,16 +369,16 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
372 |
$this->log("Preparing Data Step1: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO);
|
373 |
|
374 |
// Skip - Table does not exist
|
375 |
-
if (false === $this->
|
376 |
return true;
|
377 |
}
|
378 |
// Skip - Table is not selected or updated
|
379 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
380 |
$this->log("Preparing Data Step1: Skipping");
|
381 |
return true;
|
382 |
}
|
383 |
|
384 |
-
$this->log("Preparing Data Step1: Updating siteurl and homeurl to "
|
385 |
// Replace URLs
|
386 |
$result = $this->db->query(
|
387 |
$this->db->prepare(
|
@@ -390,7 +387,6 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
390 |
);
|
391 |
|
392 |
|
393 |
-
|
394 |
// All good
|
395 |
if ($result) {
|
396 |
return true;
|
@@ -410,12 +406,12 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
410 |
$this->log("Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}");
|
411 |
|
412 |
// Skip - Table does not exist
|
413 |
-
if (false === $this->
|
414 |
$this->log("Preparing Data Step2: Skipping");
|
415 |
return true;
|
416 |
}
|
417 |
// Skip - Table is not selected or updated
|
418 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
419 |
$this->log("Preparing Data Step2: Skipping");
|
420 |
return true;
|
421 |
}
|
@@ -461,12 +457,12 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
461 |
}
|
462 |
|
463 |
// Skip - Table does not exist
|
464 |
-
if (false === $this->
|
465 |
return true;
|
466 |
}
|
467 |
|
468 |
// Skip - Table is not selected or updated
|
469 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
470 |
$this->log("Preparing Data Step3: Skipping");
|
471 |
return true;
|
472 |
}
|
@@ -495,18 +491,17 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
495 |
$this->log("Preparing Data Step4: Updating db prefix in {$this->prefix}usermeta. ");
|
496 |
|
497 |
// Skip - Table does not exist
|
498 |
-
if (false === $this->
|
499 |
return true;
|
500 |
}
|
501 |
|
502 |
// Skip - Table is not selected or updated
|
503 |
-
if (!in_array($this->prefix.'usermeta', $this->tables)) {
|
504 |
$this->log("Preparing Data Step4: Skipping");
|
505 |
return true;
|
506 |
}
|
507 |
|
508 |
|
509 |
-
|
510 |
// Skip - Target prefix is the same as production site prefix
|
511 |
if ($this->db->prefix === $this->prefix) {
|
512 |
$this->log("Preparing Data Step4: Target prefix equals production site prefix. Skipping");
|
@@ -517,7 +512,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
517 |
$this->debugLog("Preparing Data Step4: UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, {$this->productionDb->base_prefix}, {$this->prefix}) WHERE meta_key LIKE {$this->productionDb->base_prefix}_%");
|
518 |
$update = $this->db->query(
|
519 |
$this->db->prepare(
|
520 |
-
"UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->productionDb->base_prefix, $this->prefix, $this->productionDb->base_prefix."_%"
|
521 |
)
|
522 |
);
|
523 |
|
@@ -529,7 +524,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
529 |
$this->debugLog("Preparing Data Step4: UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, {$this->db->prefix}, {$this->prefix}) WHERE meta_key LIKE {$this->db->prefix}_%");
|
530 |
$update = $this->db->query(
|
531 |
$this->db->prepare(
|
532 |
-
"UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix."_%"
|
533 |
)
|
534 |
);
|
535 |
|
@@ -547,18 +542,18 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
547 |
*/
|
548 |
protected function step5()
|
549 |
{
|
550 |
-
$path = $this->options->destinationDir."wp-config.php";
|
551 |
|
552 |
-
$this->log("Preparing Data Step5: Updating table_prefix in {$path} to "
|
553 |
if (false === ($content = file_get_contents($path))) {
|
554 |
$this->log("Preparing Data Step5: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR);
|
555 |
return false;
|
556 |
}
|
557 |
|
558 |
// Replace table prefix
|
559 |
-
$pattern
|
560 |
-
$replacement = '$table_prefix = \''
|
561 |
-
$content
|
562 |
|
563 |
if (null === $content) {
|
564 |
$this->log("Preparing Data Step5: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR);
|
@@ -569,7 +564,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
569 |
$content = str_replace($this->multisiteHomeDomain, $this->getStagingSiteUrl(), $content);
|
570 |
|
571 |
if (false === @wpstg_put_contents($path, $content)) {
|
572 |
-
$this->log("Preparing Data Step5: Failed to update $table_prefix in {$path} to "
|
573 |
return false;
|
574 |
}
|
575 |
|
@@ -591,7 +586,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
591 |
return true;
|
592 |
}
|
593 |
|
594 |
-
$path = $this->options->destinationDir."index.php";
|
595 |
|
596 |
if (false === ($content = file_get_contents($path))) {
|
597 |
$this->log("Preparing Data Step6: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR);
|
@@ -609,11 +604,10 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
609 |
|
610 |
$pattern = "/require(.*) dirname(.*) __FILE__ (.*) \. '(.*)wp-blog-header.php'(.*);.*/";
|
611 |
|
612 |
-
$replace = "require( dirname( __FILE__ ) . '/wp-blog-header.php' ); // "
|
613 |
//$replace.= " // Changed by WP-Staging";
|
614 |
|
615 |
|
616 |
-
|
617 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
618 |
$this->log("Preparing Data: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR);
|
619 |
return false;
|
@@ -637,12 +631,12 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
637 |
$this->log("Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}");
|
638 |
|
639 |
// Skip - Table does not exist
|
640 |
-
if (false === $this->
|
641 |
return true;
|
642 |
}
|
643 |
|
644 |
// Skip - Table is not selected or updated
|
645 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
646 |
$this->log("Preparing Data Step7: Skipping");
|
647 |
return true;
|
648 |
}
|
@@ -674,12 +668,12 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
674 |
}
|
675 |
|
676 |
// Skip - Table does not exist
|
677 |
-
if (false === $this->
|
678 |
return true;
|
679 |
}
|
680 |
|
681 |
// Skip - Table is not selected or updated
|
682 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
683 |
$this->log("Preparing Data Step8: Skipping");
|
684 |
return true;
|
685 |
}
|
@@ -709,12 +703,12 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
709 |
|
710 |
$this->log("Preparing Data Step9: Set staging site to noindex");
|
711 |
|
712 |
-
if (false === $this->
|
713 |
return true;
|
714 |
}
|
715 |
|
716 |
// Skip - Table is not selected or updated
|
717 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
718 |
$this->log("Preparing Data Step9: Skipping");
|
719 |
return true;
|
720 |
}
|
@@ -741,9 +735,9 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
741 |
*/
|
742 |
protected function step10()
|
743 |
{
|
744 |
-
$path = $this->options->destinationDir."wp-config.php";
|
745 |
|
746 |
-
$this->log("Preparing Data Step10: Updating WP_HOME in wp-config.php to "
|
747 |
|
748 |
if (false === ($content = file_get_contents($path))) {
|
749 |
$this->log("Preparing Data Step10: Failed to update WP_HOME in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
@@ -759,7 +753,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
759 |
|
760 |
$pattern = "/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*(.*)\s*\);.*/";
|
761 |
|
762 |
-
$replace = "define('WP_HOME','"
|
763 |
//$replace .= " // Changed by WP-Staging";
|
764 |
|
765 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
@@ -784,9 +778,9 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
784 |
*/
|
785 |
protected function step11()
|
786 |
{
|
787 |
-
$path = $this->options->destinationDir."wp-config.php";
|
788 |
|
789 |
-
$this->log("Preparing Data Step11: Updating WP_SITEURL in wp-config.php to "
|
790 |
|
791 |
if (false === ($content = file_get_contents($path))) {
|
792 |
$this->log("Preparing Data Step11: Failed to update WP_SITEURL in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
@@ -802,7 +796,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
802 |
|
803 |
$pattern = "/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*(.*)\s*\);.*/";
|
804 |
|
805 |
-
$replace = "define('WP_SITEURL','"
|
806 |
//$replace .= " // Changed by WP-Staging";
|
807 |
|
808 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
@@ -828,7 +822,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
828 |
*/
|
829 |
protected function step12()
|
830 |
{
|
831 |
-
$path = $this->options->destinationDir."wp-config.php";
|
832 |
|
833 |
$this->log("Preparing Data Step12: Updating WP_ALLOW_MULTISITE in wp-config.php to false");
|
834 |
|
@@ -846,7 +840,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
846 |
|
847 |
$pattern = "/define\s*\(\s*['\"]WP_ALLOW_MULTISITE['\"]\s*,\s*(.*)\s*\);.*/";
|
848 |
|
849 |
-
$replace = "define('WP_ALLOW_MULTISITE',false); // "
|
850 |
//$replace .= " // Changed by WP-Staging";
|
851 |
|
852 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
@@ -872,7 +866,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
872 |
*/
|
873 |
protected function step13()
|
874 |
{
|
875 |
-
$path = $this->options->destinationDir."wp-config.php";
|
876 |
|
877 |
$this->log("Preparing Data Step13: Updating MULTISITE in wp-config.php to false");
|
878 |
|
@@ -890,7 +884,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
890 |
|
891 |
$pattern = "/define\s*\(\s*['\"]MULTISITE['\"]\s*,\s*(.*)\s*\);.*/";
|
892 |
|
893 |
-
$replace = "define('MULTISITE',false); // "
|
894 |
//$replace .= " // Changed by WP-Staging";
|
895 |
|
896 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
@@ -920,14 +914,14 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
920 |
|
921 |
$this->log("Data Crunching Step14: Updating active_plugins");
|
922 |
|
923 |
-
if (false === $this->
|
924 |
-
$this->log('Data Crunching Step14: Fatal Error '
|
925 |
-
$this->returnException('Data Crunching Step14: Fatal Error '
|
926 |
return false;
|
927 |
}
|
928 |
|
929 |
// Skip - Table is not selected or updated
|
930 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
931 |
$this->log("Preparing Data Step14: Skipping");
|
932 |
return true;
|
933 |
}
|
@@ -948,7 +942,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
948 |
}
|
949 |
|
950 |
$active_sitewide_plugins = unserialize($active_sitewide_plugins);
|
951 |
-
$active_plugins
|
952 |
|
953 |
$all_plugins = array_merge($active_plugins, array_keys($active_sitewide_plugins));
|
954 |
|
@@ -957,7 +951,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
957 |
|
958 |
// Update active_plugins
|
959 |
$update = $this->db->query(
|
960 |
-
"UPDATE {$this->prefix}options SET option_value = '".serialize($all_plugins)."' WHERE option_name = 'active_plugins'"
|
961 |
);
|
962 |
|
963 |
if (false === $update) {
|
@@ -978,12 +972,12 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
978 |
$this->log("Preparing Data Step15: Updating db prefix in {$this->prefix}options.");
|
979 |
|
980 |
// Skip - Table does not exist
|
981 |
-
if (false === $this->
|
982 |
return true;
|
983 |
}
|
984 |
|
985 |
// Skip - Table is not selected or updated
|
986 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
987 |
$this->log("Preparing Data Step4: Skipping");
|
988 |
return true;
|
989 |
}
|
@@ -1002,12 +996,12 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1002 |
|
1003 |
$where = "";
|
1004 |
foreach ($filters as $filter) {
|
1005 |
-
$where .= " AND option_name <> '"
|
1006 |
}
|
1007 |
|
1008 |
$updateOptions = $this->db->query(
|
1009 |
$this->db->prepare(
|
1010 |
-
"UPDATE IGNORE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s"
|
1011 |
)
|
1012 |
);
|
1013 |
|
@@ -1030,7 +1024,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1030 |
$this->log("Preparing Data Step16: Updating upload_path {$this->prefix}options.");
|
1031 |
|
1032 |
// Skip - Table does not exist
|
1033 |
-
if (false === $this->
|
1034 |
return true;
|
1035 |
}
|
1036 |
|
@@ -1042,13 +1036,13 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1042 |
}
|
1043 |
|
1044 |
// Skip - Table is not selected or updated
|
1045 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
1046 |
$this->log("Preparing Data Step16: Skipping");
|
1047 |
return true;
|
1048 |
}
|
1049 |
|
1050 |
-
$error = isset($this->db->last_error) ? 'Last error: '
|
1051 |
-
|
1052 |
|
1053 |
$this->log("Updating upload_path in {$this->prefix}options. {$error}");
|
1054 |
|
@@ -1072,7 +1066,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1072 |
*/
|
1073 |
protected function step17()
|
1074 |
{
|
1075 |
-
$path = $this->options->destinationDir."wp-config.php";
|
1076 |
|
1077 |
$this->log("Preparing Data Step17: Set WP_CACHE in wp-config.php to false");
|
1078 |
|
@@ -1090,7 +1084,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1090 |
|
1091 |
$pattern = "/define\s*\(\s*['\"]WP_CACHE['\"]\s*,\s*(.*)\s*\);.*/";
|
1092 |
|
1093 |
-
$replace = "define('WP_CACHE',false); // "
|
1094 |
//$replace.= " // Changed by WP-Staging";
|
1095 |
|
1096 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
@@ -1115,7 +1109,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1115 |
*/
|
1116 |
protected function step18()
|
1117 |
{
|
1118 |
-
$path
|
1119 |
$this->log("Preparing Data Step18: Update UPLOADS constant in wp-config.php");
|
1120 |
if (false === ($content = file_get_contents($path))) {
|
1121 |
$this->log("Preparing Data Step18: Failed to get UPLOADS in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
@@ -1127,7 +1121,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1127 |
if (!empty($matches[0])) {
|
1128 |
$pattern = "/define\s*\(\s*'UPLOADS'\s*,\s*(.*)\s*\);/";
|
1129 |
|
1130 |
-
$replace = "define('UPLOADS', '"
|
1131 |
$this->log("Preparing Data Step18: Change UPLOADS constant in wp-config.php to {$uploadFolder}.");
|
1132 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1133 |
$this->log("Preparing Data Step 18: Failed to change UPLOADS", Logger::TYPE_ERROR);
|
@@ -1140,7 +1134,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1140 |
if (!empty($matches[0])) {
|
1141 |
$matches[0];
|
1142 |
$pattern = "/if\s*\(\s*\s*!\s*defined\s*\(\s*['\"]ABSPATH['\"]\s*(.*)\s*\)\s*\)/";
|
1143 |
-
$replace = "define('UPLOADS', '"
|
1144 |
"if ( ! defined( 'ABSPATH' ) )";
|
1145 |
$this->log("Preparing Data Step18: Change UPLOADS constant in wp-config.php to {$uploadFolder}.");
|
1146 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
@@ -1165,7 +1159,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1165 |
*/
|
1166 |
protected function step19()
|
1167 |
{
|
1168 |
-
$path = $this->options->destinationDir."wp-config.php";
|
1169 |
|
1170 |
$this->log("Preparing Data Step19: Change database credentials in wp-config.php");
|
1171 |
|
@@ -1183,8 +1177,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1183 |
|
1184 |
$pattern = "/define\s*\(\s*'DB_NAME'\s*,\s*(.*)\s*\);.*/";
|
1185 |
|
1186 |
-
$replace = "define('DB_NAME','{$this->options->databaseDatabase}'); // "
|
1187 |
-
//$replace.= " // Changed by WP-Staging";
|
1188 |
|
1189 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1190 |
$this->log("Preparing Data: Failed to change DB_NAME", Logger::TYPE_ERROR);
|
@@ -1201,7 +1194,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1201 |
|
1202 |
$pattern = "/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*(.*)\s*\);.*/";
|
1203 |
|
1204 |
-
$replace = "define('DB_USER','{$this->options->databaseUser}'); // "
|
1205 |
//$replace.= " // Changed by WP-Staging";
|
1206 |
|
1207 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
@@ -1219,8 +1212,10 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1219 |
|
1220 |
$pattern = "/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*(.*)\s*\);.*/";
|
1221 |
|
1222 |
-
|
1223 |
-
|
|
|
|
|
1224 |
|
1225 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1226 |
$this->log("Preparing Data: Failed to change DB_PASSWORD", Logger::TYPE_ERROR);
|
@@ -1237,7 +1232,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1237 |
|
1238 |
$pattern = "/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*(.*)\s*\);.*/";
|
1239 |
|
1240 |
-
$replace = "define('DB_HOST','{$this->options->databaseServer}'); // "
|
1241 |
//$replace.= " // Changed by WP-Staging";
|
1242 |
|
1243 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
@@ -1264,7 +1259,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1264 |
protected function step20()
|
1265 |
{
|
1266 |
|
1267 |
-
$table = $this->prefix.'options';
|
1268 |
|
1269 |
$siteurl = get_site_url();
|
1270 |
|
@@ -1287,16 +1282,16 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1287 |
|
1288 |
/**
|
1289 |
* Add option_name wpstg_execute and set it to true
|
1290 |
-
* This option is used to determine if the staging website has not been loaded
|
1291 |
* @return boolean
|
1292 |
*/
|
1293 |
protected function step21()
|
1294 |
{
|
1295 |
|
1296 |
-
$table = $this->prefix.'options';
|
1297 |
|
1298 |
// Skip - Table does not exist
|
1299 |
-
if (false === $this->
|
1300 |
return true;
|
1301 |
}
|
1302 |
|
@@ -1313,80 +1308,22 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1313 |
return true;
|
1314 |
}
|
1315 |
|
1316 |
-
/**
|
1317 |
-
* Preserve data and prevents data in wp_options from beeing cloned to staging site
|
1318 |
-
* @return bool
|
1319 |
-
*/
|
1320 |
-
protected function step22()
|
1321 |
-
{
|
1322 |
-
$this->log("Preparing Data Step22: Preserve Data in ".$this->prefix."options");
|
1323 |
-
|
1324 |
-
// Skip - Table does not exist
|
1325 |
-
if (false === $this->isTable($this->prefix.'options')) {
|
1326 |
-
return true;
|
1327 |
-
}
|
1328 |
-
|
1329 |
-
// Skip - Table is not selected or updated
|
1330 |
-
if (!in_array($this->prefix.'options', $this->tables)) {
|
1331 |
-
$this->log("Preparing Data Step22: Skipped");
|
1332 |
-
return true;
|
1333 |
-
}
|
1334 |
-
|
1335 |
-
$sql = '';
|
1336 |
-
|
1337 |
-
$preserved_option_names = array('wpstg_existing_clones_beta');
|
1338 |
-
|
1339 |
-
$preserved_option_names = apply_filters('wpstg_preserved_options_cloning', $preserved_option_names);
|
1340 |
-
$preserved_options_escaped = esc_sql($preserved_option_names);
|
1341 |
-
|
1342 |
-
$preserved_options_data = array();
|
1343 |
-
|
1344 |
-
// Get preserved data in wp_options tables
|
1345 |
-
$table = $this->db->prefix.'options';
|
1346 |
-
$preserved_options_data[$this->prefix.'options'] = $this->db->get_results(
|
1347 |
-
sprintf(
|
1348 |
-
"SELECT * FROM `{$table}` WHERE `option_name` IN ('%s')", implode("','", $preserved_options_escaped)
|
1349 |
-
), ARRAY_A
|
1350 |
-
);
|
1351 |
-
|
1352 |
-
// Create preserved data queries for options tables
|
1353 |
-
foreach ($preserved_options_data as $key => $value) {
|
1354 |
-
if (false === empty($value)) {
|
1355 |
-
foreach ($value as $option) {
|
1356 |
-
$sql .= $this->db->prepare(
|
1357 |
-
"DELETE FROM `{$key}` WHERE `option_name` = %s;\n", $option['option_name']
|
1358 |
-
);
|
1359 |
-
|
1360 |
-
$sql .= $this->db->prepare(
|
1361 |
-
"INSERT INTO `{$key}` ( `option_id`, `option_name`, `option_value`, `autoload` ) VALUES ( NULL , %s, %s, %s );\n", $option['option_name'], $option['option_value'], $option['autoload']
|
1362 |
-
);
|
1363 |
-
}
|
1364 |
-
}
|
1365 |
-
}
|
1366 |
-
|
1367 |
-
$this->debugLog("Preparing Data Step22: Preserve values ".json_encode($preserved_options_data), Logger::TYPE_INFO);
|
1368 |
-
|
1369 |
-
$this->executeSql($sql);
|
1370 |
-
|
1371 |
-
$this->log("Preparing Data Step22: Successful!");
|
1372 |
-
return true;
|
1373 |
-
}
|
1374 |
|
1375 |
/**
|
1376 |
* Check if there is a multisite super administrator and add it to usermeta
|
1377 |
* @return bool
|
1378 |
*/
|
1379 |
-
protected function
|
1380 |
{
|
1381 |
$this->log("Preparing Data Step23: Add network administrators");
|
1382 |
|
1383 |
// Skip - Table does not exist
|
1384 |
-
if (false === $this->
|
1385 |
return true;
|
1386 |
}
|
1387 |
|
1388 |
// Skip - Table is not selected or updated
|
1389 |
-
if (!in_array($this->prefix.'usermeta', $this->tables)) {
|
1390 |
$this->log("Preparing Data Step23: Skipping");
|
1391 |
return true;
|
1392 |
}
|
@@ -1411,8 +1348,8 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1411 |
|
1412 |
// Add new capability
|
1413 |
$sql .= $this->db->prepare(
|
1414 |
-
"INSERT INTO `{$this->prefix}usermeta` ( `umeta_id`, `user_id`, `meta_key`, `meta_value` ) VALUES ( NULL , %s, %s, %s );\n", $userId, $this->prefix.'capabilities', serialize(array(
|
1415 |
-
|
1416 |
);
|
1417 |
}
|
1418 |
if (!empty($sql)) {
|
@@ -1437,6 +1374,35 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1437 |
return true;
|
1438 |
}
|
1439 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1440 |
/**
|
1441 |
* Get relative path to the uploads media folder of multisite e.g.
|
1442 |
* wp-content/uploads/sites/SITEID or old wordpress structure wp-content/blogs.dir/SITEID/files
|
@@ -1449,7 +1415,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1449 |
$uploads = wp_upload_dir();
|
1450 |
$basedir = $uploads['basedir'];
|
1451 |
// Get relative upload path
|
1452 |
-
$relDir
|
1453 |
return $relDir;
|
1454 |
}
|
1455 |
|
@@ -1467,7 +1433,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1467 |
|
1468 |
$customSlug = str_replace(wpstg_replace_windows_directory_separator(\WPStaging\WPStaging::getWPpath()), '', wpstg_replace_windows_directory_separator($uploadPath));
|
1469 |
|
1470 |
-
$newUploadPath = wpstg_replace_windows_directory_separator(\WPStaging\WPStaging::getWPpath())
|
1471 |
|
1472 |
return $newUploadPath;
|
1473 |
}
|
@@ -1484,12 +1450,12 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1484 |
}
|
1485 |
|
1486 |
if ($this->isSubDir()) {
|
1487 |
-
return trailingslashit($this->multisiteHomeDomain).trailingslashit($this->getSubDir())
|
1488 |
}
|
1489 |
|
1490 |
// Get the path to the main multisite without appending and trailingslash e.g. wordpress
|
1491 |
$multisitePath = defined('PATH_CURRENT_SITE') ? PATH_CURRENT_SITE : '/';
|
1492 |
-
$url
|
1493 |
|
1494 |
return $url;
|
1495 |
}
|
@@ -1503,7 +1469,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1503 |
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
1504 |
// This is happening much more often than you would expect
|
1505 |
$siteurl = preg_replace('#^https?://#', '', rtrim(get_option('siteurl'), '/'));
|
1506 |
-
$home
|
1507 |
|
1508 |
if ($home !== $siteurl) {
|
1509 |
return true;
|
@@ -1517,7 +1483,7 @@ define( 'DB_COLLATE', '".DB_COLLATE."' );\r\n";
|
|
1517 |
*/
|
1518 |
protected function getSubDir()
|
1519 |
{
|
1520 |
-
$home
|
1521 |
$siteurl = get_option('siteurl');
|
1522 |
|
1523 |
if (empty($home) || empty($siteurl)) {
|
9 |
|
10 |
use WPStaging\Utils\Logger;
|
11 |
use WPStaging\WPStaging;
|
|
|
|
|
12 |
use WPStaging\Utils\Strings;
|
13 |
use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
14 |
|
39 |
*/
|
40 |
public function initialize()
|
41 |
{
|
42 |
+
$this->db = $this->getStagingDB();
|
43 |
$this->productionDb = WPStaging::getInstance()->get("wpdb");
|
44 |
+
$this->prefix = $this->options->prefix;
|
45 |
+
$this->db->prefix = $this->options->databasePrefix;
|
46 |
|
47 |
$this->getTables();
|
48 |
|
57 |
*/
|
58 |
private function getStagingDB()
|
59 |
{
|
60 |
+
return new \wpdb($this->options->databaseUser, $this->options->databasePassword, $this->options->databaseDatabase, $this->options->databaseServer);
|
61 |
}
|
62 |
|
63 |
/**
|
65 |
*/
|
66 |
private function getTables()
|
67 |
{
|
68 |
+
$strings = new Strings();
|
69 |
$this->tables = array();
|
70 |
foreach ($this->options->tables as $table) {
|
71 |
+
$this->tables[] = $this->options->prefix . $strings->str_replace_first($this->productionDb->prefix, null, $table);
|
72 |
}
|
73 |
// Add extra global tables from main multisite (wpstgx_users and wpstgx_usermeta)
|
74 |
+
$this->tables[] = $this->options->prefix . $strings->str_replace_first($this->productionDb->prefix, null, 'users');
|
75 |
+
$this->tables[] = $this->options->prefix . $strings->str_replace_first($this->productionDb->prefix, null, 'usermeta');
|
76 |
}
|
77 |
|
78 |
/**
|
126 |
}
|
127 |
|
128 |
// Execute step
|
129 |
+
$stepMethodName = "step" . $this->options->currentStep;
|
130 |
if (!$this->{$stepMethodName}()) {
|
131 |
$this->prepareResponse(false, false);
|
132 |
return false;
|
148 |
return
|
149 |
!$this->isRunning() ||
|
150 |
$this->options->currentStep > $this->options->totalSteps ||
|
151 |
+
!method_exists($this, "step" . $this->options->currentStep);
|
|
|
152 |
}
|
153 |
|
154 |
/**
|
182 |
* @param string $table
|
183 |
* @return boolean
|
184 |
*/
|
185 |
+
protected function tableExists($table)
|
186 |
{
|
187 |
if ($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table) {
|
188 |
$this->log("Table {$table} does not exist", Logger::TYPE_ERROR);
|
202 |
|
203 |
$dir = trailingslashit(dirname(ABSPATH));
|
204 |
|
205 |
+
$source = $dir . 'wp-config.php';
|
206 |
|
207 |
+
$destination = $this->options->destinationDir . 'wp-config.php';
|
208 |
|
209 |
// Check if there is already a valid wp-config.php in root of staging site
|
210 |
if ($this->isValidWpConfig($destination)) {
|
222 |
}
|
223 |
|
224 |
// No valid wp-config.php found so let's copy wp stagings default wp-config.php to staging site
|
225 |
+
$source = WPSTG_PLUGIN_DIR . "Backend/helpers/wp-config.php";
|
226 |
|
227 |
$this->log("Preparing Data Step0: Copy default wp-config.php file from source {$source} to {$destination}", Logger::TYPE_INFO);
|
228 |
|
284 |
$search = "// ** MySQL settings ** //";
|
285 |
|
286 |
$replace = "// ** MySQL settings ** //\r\n
|
287 |
+
define( 'DB_NAME', '" . DB_NAME . "' );\r\n
|
288 |
/** MySQL database username */\r\n
|
289 |
+
define( 'DB_USER', '" . DB_USER . "' );\r\n
|
290 |
/** MySQL database password */\r\n
|
291 |
+
define( 'DB_PASSWORD', '" . DB_PASSWORD . "' );\r\n
|
292 |
/** MySQL hostname */\r\n
|
293 |
+
define( 'DB_HOST', '" . DB_HOST . "' );\r\n
|
294 |
/** Database Charset to use in creating database tables. */\r\n
|
295 |
+
define( 'DB_CHARSET', '" . DB_CHARSET . "' );\r\n
|
296 |
/** The Database Collate type. Don't change this if in doubt. */\r\n
|
297 |
+
define( 'DB_COLLATE', '" . DB_COLLATE . "' );\r\n";
|
298 |
|
299 |
$content = str_replace($search, $replace, $content);
|
300 |
|
369 |
$this->log("Preparing Data Step1: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO);
|
370 |
|
371 |
// Skip - Table does not exist
|
372 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
373 |
return true;
|
374 |
}
|
375 |
// Skip - Table is not selected or updated
|
376 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
377 |
$this->log("Preparing Data Step1: Skipping");
|
378 |
return true;
|
379 |
}
|
380 |
|
381 |
+
$this->log("Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl());
|
382 |
// Replace URLs
|
383 |
$result = $this->db->query(
|
384 |
$this->db->prepare(
|
387 |
);
|
388 |
|
389 |
|
|
|
390 |
// All good
|
391 |
if ($result) {
|
392 |
return true;
|
406 |
$this->log("Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}");
|
407 |
|
408 |
// Skip - Table does not exist
|
409 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
410 |
$this->log("Preparing Data Step2: Skipping");
|
411 |
return true;
|
412 |
}
|
413 |
// Skip - Table is not selected or updated
|
414 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
415 |
$this->log("Preparing Data Step2: Skipping");
|
416 |
return true;
|
417 |
}
|
457 |
}
|
458 |
|
459 |
// Skip - Table does not exist
|
460 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
461 |
return true;
|
462 |
}
|
463 |
|
464 |
// Skip - Table is not selected or updated
|
465 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
466 |
$this->log("Preparing Data Step3: Skipping");
|
467 |
return true;
|
468 |
}
|
491 |
$this->log("Preparing Data Step4: Updating db prefix in {$this->prefix}usermeta. ");
|
492 |
|
493 |
// Skip - Table does not exist
|
494 |
+
if (false === $this->tableExists($this->prefix . 'usermeta')) {
|
495 |
return true;
|
496 |
}
|
497 |
|
498 |
// Skip - Table is not selected or updated
|
499 |
+
if (!in_array($this->prefix . 'usermeta', $this->tables)) {
|
500 |
$this->log("Preparing Data Step4: Skipping");
|
501 |
return true;
|
502 |
}
|
503 |
|
504 |
|
|
|
505 |
// Skip - Target prefix is the same as production site prefix
|
506 |
if ($this->db->prefix === $this->prefix) {
|
507 |
$this->log("Preparing Data Step4: Target prefix equals production site prefix. Skipping");
|
512 |
$this->debugLog("Preparing Data Step4: UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, {$this->productionDb->base_prefix}, {$this->prefix}) WHERE meta_key LIKE {$this->productionDb->base_prefix}_%");
|
513 |
$update = $this->db->query(
|
514 |
$this->db->prepare(
|
515 |
+
"UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->productionDb->base_prefix, $this->prefix, $this->productionDb->base_prefix . "_%"
|
516 |
)
|
517 |
);
|
518 |
|
524 |
$this->debugLog("Preparing Data Step4: UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, {$this->db->prefix}, {$this->prefix}) WHERE meta_key LIKE {$this->db->prefix}_%");
|
525 |
$update = $this->db->query(
|
526 |
$this->db->prepare(
|
527 |
+
"UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
|
528 |
)
|
529 |
);
|
530 |
|
542 |
*/
|
543 |
protected function step5()
|
544 |
{
|
545 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
546 |
|
547 |
+
$this->log("Preparing Data Step5: Updating table_prefix in {$path} to " . $this->prefix);
|
548 |
if (false === ($content = file_get_contents($path))) {
|
549 |
$this->log("Preparing Data Step5: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR);
|
550 |
return false;
|
551 |
}
|
552 |
|
553 |
// Replace table prefix
|
554 |
+
$pattern = '/\$table_prefix\s*=\s*(.*).*/';
|
555 |
+
$replacement = '$table_prefix = \'' . $this->prefix . '\'; // Changed by WP Staging';
|
556 |
+
$content = preg_replace($pattern, $replacement, $content);
|
557 |
|
558 |
if (null === $content) {
|
559 |
$this->log("Preparing Data Step5: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR);
|
564 |
$content = str_replace($this->multisiteHomeDomain, $this->getStagingSiteUrl(), $content);
|
565 |
|
566 |
if (false === @wpstg_put_contents($path, $content)) {
|
567 |
+
$this->log("Preparing Data Step5: Failed to update $table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR);
|
568 |
return false;
|
569 |
}
|
570 |
|
586 |
return true;
|
587 |
}
|
588 |
|
589 |
+
$path = $this->options->destinationDir . "index.php";
|
590 |
|
591 |
if (false === ($content = file_get_contents($path))) {
|
592 |
$this->log("Preparing Data Step6: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR);
|
604 |
|
605 |
$pattern = "/require(.*) dirname(.*) __FILE__ (.*) \. '(.*)wp-blog-header.php'(.*);.*/";
|
606 |
|
607 |
+
$replace = "require( dirname( __FILE__ ) . '/wp-blog-header.php' ); // " . $matches[0];
|
608 |
//$replace.= " // Changed by WP-Staging";
|
609 |
|
610 |
|
|
|
611 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
612 |
$this->log("Preparing Data: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR);
|
613 |
return false;
|
631 |
$this->log("Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}");
|
632 |
|
633 |
// Skip - Table does not exist
|
634 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
635 |
return true;
|
636 |
}
|
637 |
|
638 |
// Skip - Table is not selected or updated
|
639 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
640 |
$this->log("Preparing Data Step7: Skipping");
|
641 |
return true;
|
642 |
}
|
668 |
}
|
669 |
|
670 |
// Skip - Table does not exist
|
671 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
672 |
return true;
|
673 |
}
|
674 |
|
675 |
// Skip - Table is not selected or updated
|
676 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
677 |
$this->log("Preparing Data Step8: Skipping");
|
678 |
return true;
|
679 |
}
|
703 |
|
704 |
$this->log("Preparing Data Step9: Set staging site to noindex");
|
705 |
|
706 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
707 |
return true;
|
708 |
}
|
709 |
|
710 |
// Skip - Table is not selected or updated
|
711 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
712 |
$this->log("Preparing Data Step9: Skipping");
|
713 |
return true;
|
714 |
}
|
735 |
*/
|
736 |
protected function step10()
|
737 |
{
|
738 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
739 |
|
740 |
+
$this->log("Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl());
|
741 |
|
742 |
if (false === ($content = file_get_contents($path))) {
|
743 |
$this->log("Preparing Data Step10: Failed to update WP_HOME in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
753 |
|
754 |
$pattern = "/define\s*\(\s*['\"]WP_HOME['\"]\s*,\s*(.*)\s*\);.*/";
|
755 |
|
756 |
+
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
757 |
//$replace .= " // Changed by WP-Staging";
|
758 |
|
759 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
778 |
*/
|
779 |
protected function step11()
|
780 |
{
|
781 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
782 |
|
783 |
+
$this->log("Preparing Data Step11: Updating WP_SITEURL in wp-config.php to " . $this->getStagingSiteUrl());
|
784 |
|
785 |
if (false === ($content = file_get_contents($path))) {
|
786 |
$this->log("Preparing Data Step11: Failed to update WP_SITEURL in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
796 |
|
797 |
$pattern = "/define\s*\(\s*['\"]WP_SITEURL['\"]\s*,\s*(.*)\s*\);.*/";
|
798 |
|
799 |
+
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
800 |
//$replace .= " // Changed by WP-Staging";
|
801 |
|
802 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
822 |
*/
|
823 |
protected function step12()
|
824 |
{
|
825 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
826 |
|
827 |
$this->log("Preparing Data Step12: Updating WP_ALLOW_MULTISITE in wp-config.php to false");
|
828 |
|
840 |
|
841 |
$pattern = "/define\s*\(\s*['\"]WP_ALLOW_MULTISITE['\"]\s*,\s*(.*)\s*\);.*/";
|
842 |
|
843 |
+
$replace = "define('WP_ALLOW_MULTISITE',false); // " . $matches[1];
|
844 |
//$replace .= " // Changed by WP-Staging";
|
845 |
|
846 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
866 |
*/
|
867 |
protected function step13()
|
868 |
{
|
869 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
870 |
|
871 |
$this->log("Preparing Data Step13: Updating MULTISITE in wp-config.php to false");
|
872 |
|
884 |
|
885 |
$pattern = "/define\s*\(\s*['\"]MULTISITE['\"]\s*,\s*(.*)\s*\);.*/";
|
886 |
|
887 |
+
$replace = "define('MULTISITE',false); // " . $matches[1];
|
888 |
//$replace .= " // Changed by WP-Staging";
|
889 |
|
890 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
914 |
|
915 |
$this->log("Data Crunching Step14: Updating active_plugins");
|
916 |
|
917 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
918 |
+
$this->log('Data Crunching Step14: Fatal Error ' . $this->prefix . 'options does not exist');
|
919 |
+
$this->returnException('Data Crunching Step14: Fatal Error ' . $this->prefix . 'options does not exist');
|
920 |
return false;
|
921 |
}
|
922 |
|
923 |
// Skip - Table is not selected or updated
|
924 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
925 |
$this->log("Preparing Data Step14: Skipping");
|
926 |
return true;
|
927 |
}
|
942 |
}
|
943 |
|
944 |
$active_sitewide_plugins = unserialize($active_sitewide_plugins);
|
945 |
+
$active_plugins = unserialize($active_plugins);
|
946 |
|
947 |
$all_plugins = array_merge($active_plugins, array_keys($active_sitewide_plugins));
|
948 |
|
951 |
|
952 |
// Update active_plugins
|
953 |
$update = $this->db->query(
|
954 |
+
"UPDATE {$this->prefix}options SET option_value = '" . serialize($all_plugins) . "' WHERE option_name = 'active_plugins'"
|
955 |
);
|
956 |
|
957 |
if (false === $update) {
|
972 |
$this->log("Preparing Data Step15: Updating db prefix in {$this->prefix}options.");
|
973 |
|
974 |
// Skip - Table does not exist
|
975 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
976 |
return true;
|
977 |
}
|
978 |
|
979 |
// Skip - Table is not selected or updated
|
980 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
981 |
$this->log("Preparing Data Step4: Skipping");
|
982 |
return true;
|
983 |
}
|
996 |
|
997 |
$where = "";
|
998 |
foreach ($filters as $filter) {
|
999 |
+
$where .= " AND option_name <> '" . $filter . "'";
|
1000 |
}
|
1001 |
|
1002 |
$updateOptions = $this->db->query(
|
1003 |
$this->db->prepare(
|
1004 |
+
"UPDATE IGNORE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s" . $where, $this->productionDb->prefix, $this->prefix, $this->productionDb->prefix . "_%"
|
1005 |
)
|
1006 |
);
|
1007 |
|
1024 |
$this->log("Preparing Data Step16: Updating upload_path {$this->prefix}options.");
|
1025 |
|
1026 |
// Skip - Table does not exist
|
1027 |
+
if (false === $this->tableExists($this->prefix . 'options')) {
|
1028 |
return true;
|
1029 |
}
|
1030 |
|
1036 |
}
|
1037 |
|
1038 |
// Skip - Table is not selected or updated
|
1039 |
+
if (!in_array($this->prefix . 'options', $this->tables)) {
|
1040 |
$this->log("Preparing Data Step16: Skipping");
|
1041 |
return true;
|
1042 |
}
|
1043 |
|
1044 |
+
$error = isset($this->db->last_error) ? 'Last error: ' . $this->db->last_error
|
1045 |
+
: '';
|
1046 |
|
1047 |
$this->log("Updating upload_path in {$this->prefix}options. {$error}");
|
1048 |
|
1066 |
*/
|
1067 |
protected function step17()
|
1068 |
{
|
1069 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
1070 |
|
1071 |
$this->log("Preparing Data Step17: Set WP_CACHE in wp-config.php to false");
|
1072 |
|
1084 |
|
1085 |
$pattern = "/define\s*\(\s*['\"]WP_CACHE['\"]\s*,\s*(.*)\s*\);.*/";
|
1086 |
|
1087 |
+
$replace = "define('WP_CACHE',false); // " . $matches[1];
|
1088 |
//$replace.= " // Changed by WP-Staging";
|
1089 |
|
1090 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1109 |
*/
|
1110 |
protected function step18()
|
1111 |
{
|
1112 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
1113 |
$this->log("Preparing Data Step18: Update UPLOADS constant in wp-config.php");
|
1114 |
if (false === ($content = file_get_contents($path))) {
|
1115 |
$this->log("Preparing Data Step18: Failed to get UPLOADS in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR);
|
1121 |
if (!empty($matches[0])) {
|
1122 |
$pattern = "/define\s*\(\s*'UPLOADS'\s*,\s*(.*)\s*\);/";
|
1123 |
|
1124 |
+
$replace = "define('UPLOADS', '" . $uploadFolder . "');";
|
1125 |
$this->log("Preparing Data Step18: Change UPLOADS constant in wp-config.php to {$uploadFolder}.");
|
1126 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1127 |
$this->log("Preparing Data Step 18: Failed to change UPLOADS", Logger::TYPE_ERROR);
|
1134 |
if (!empty($matches[0])) {
|
1135 |
$matches[0];
|
1136 |
$pattern = "/if\s*\(\s*\s*!\s*defined\s*\(\s*['\"]ABSPATH['\"]\s*(.*)\s*\)\s*\)/";
|
1137 |
+
$replace = "define('UPLOADS', '" . $uploadFolder . "'); \n" .
|
1138 |
"if ( ! defined( 'ABSPATH' ) )";
|
1139 |
$this->log("Preparing Data Step18: Change UPLOADS constant in wp-config.php to {$uploadFolder}.");
|
1140 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1159 |
*/
|
1160 |
protected function step19()
|
1161 |
{
|
1162 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
1163 |
|
1164 |
$this->log("Preparing Data Step19: Change database credentials in wp-config.php");
|
1165 |
|
1177 |
|
1178 |
$pattern = "/define\s*\(\s*'DB_NAME'\s*,\s*(.*)\s*\);.*/";
|
1179 |
|
1180 |
+
$replace = "define('DB_NAME','{$this->options->databaseDatabase}'); // " . $matches[1];
|
|
|
1181 |
|
1182 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1183 |
$this->log("Preparing Data: Failed to change DB_NAME", Logger::TYPE_ERROR);
|
1194 |
|
1195 |
$pattern = "/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*(.*)\s*\);.*/";
|
1196 |
|
1197 |
+
$replace = "define('DB_USER','{$this->options->databaseUser}'); // " . $matches[1];
|
1198 |
//$replace.= " // Changed by WP-Staging";
|
1199 |
|
1200 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1212 |
|
1213 |
$pattern = "/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*(.*)\s*\);.*/";
|
1214 |
|
1215 |
+
//We need to escape ',$ and \ for preg_replace. As the string will later be interpreted as a PHP string, we
|
1216 |
+
//need to escape \ twice.
|
1217 |
+
$escapedPassword = addcslashes(addcslashes($this->options->databasePassword, "\\"), "'$\\");
|
1218 |
+
$replace = "define('DB_PASSWORD','{$escapedPassword}');";
|
1219 |
|
1220 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1221 |
$this->log("Preparing Data: Failed to change DB_PASSWORD", Logger::TYPE_ERROR);
|
1232 |
|
1233 |
$pattern = "/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*(.*)\s*\);.*/";
|
1234 |
|
1235 |
+
$replace = "define('DB_HOST','{$this->options->databaseServer}'); // " . $matches[1];
|
1236 |
//$replace.= " // Changed by WP-Staging";
|
1237 |
|
1238 |
if (null === ($content = preg_replace(array($pattern), $replace, $content))) {
|
1259 |
protected function step20()
|
1260 |
{
|
1261 |
|
1262 |
+
$table = $this->prefix . 'options';
|
1263 |
|
1264 |
$siteurl = get_site_url();
|
1265 |
|
1282 |
|
1283 |
/**
|
1284 |
* Add option_name wpstg_execute and set it to true
|
1285 |
+
* This option is used to determine if the staging website has not been loaded initially for executing certain custom actions from \WPStaging\initActions()
|
1286 |
* @return boolean
|
1287 |
*/
|
1288 |
protected function step21()
|
1289 |
{
|
1290 |
|
1291 |
+
$table = $this->prefix . 'options';
|
1292 |
|
1293 |
// Skip - Table does not exist
|
1294 |
+
if (false === $this->tableExists($table)) {
|
1295 |
return true;
|
1296 |
}
|
1297 |
|
1308 |
return true;
|
1309 |
}
|
1310 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1311 |
|
1312 |
/**
|
1313 |
* Check if there is a multisite super administrator and add it to usermeta
|
1314 |
* @return bool
|
1315 |
*/
|
1316 |
+
protected function step22()
|
1317 |
{
|
1318 |
$this->log("Preparing Data Step23: Add network administrators");
|
1319 |
|
1320 |
// Skip - Table does not exist
|
1321 |
+
if (false === $this->tableExists($this->prefix . 'usermeta')) {
|
1322 |
return true;
|
1323 |
}
|
1324 |
|
1325 |
// Skip - Table is not selected or updated
|
1326 |
+
if (!in_array($this->prefix . 'usermeta', $this->tables)) {
|
1327 |
$this->log("Preparing Data Step23: Skipping");
|
1328 |
return true;
|
1329 |
}
|
1348 |
|
1349 |
// Add new capability
|
1350 |
$sql .= $this->db->prepare(
|
1351 |
+
"INSERT INTO `{$this->prefix}usermeta` ( `umeta_id`, `user_id`, `meta_key`, `meta_value` ) VALUES ( NULL , %s, %s, %s );\n", $userId, $this->prefix . 'capabilities', serialize(array(
|
1352 |
+
'administrator' => true))
|
1353 |
);
|
1354 |
}
|
1355 |
if (!empty($sql)) {
|
1374 |
return true;
|
1375 |
}
|
1376 |
|
1377 |
+
/**
|
1378 |
+
* Delete all listed staging sites from cloned site on initial cloning. Useful if a cloned site is cloned again. E.g. for dev > staging > production setup
|
1379 |
+
* @return bool
|
1380 |
+
*/
|
1381 |
+
protected function step23(){
|
1382 |
+
|
1383 |
+
if ($this->options->mainJob === 'updating'){
|
1384 |
+
return true;
|
1385 |
+
}
|
1386 |
+
|
1387 |
+
if( false === $this->tableExists( $this->prefix . 'options' ) ) {
|
1388 |
+
return true;
|
1389 |
+
}
|
1390 |
+
|
1391 |
+
$step = "Preparing Data Step23:";
|
1392 |
+
$this->log( $step . " Reset wp staging site data" );
|
1393 |
+
|
1394 |
+
$result = $this->db->query(
|
1395 |
+
$this->db->prepare( "UPDATE {$this->prefix}options SET `option_value` = %s WHERE `option_name` = %s", serialize(array()), 'wpstg_existing_clones_beta'
|
1396 |
+
)
|
1397 |
+
);
|
1398 |
+
|
1399 |
+
if (false === $result){
|
1400 |
+
$this->log( $step . "Failed to reset wp staging site data." );
|
1401 |
+
}
|
1402 |
+
|
1403 |
+
return true;
|
1404 |
+
}
|
1405 |
+
|
1406 |
/**
|
1407 |
* Get relative path to the uploads media folder of multisite e.g.
|
1408 |
* wp-content/uploads/sites/SITEID or old wordpress structure wp-content/blogs.dir/SITEID/files
|
1415 |
$uploads = wp_upload_dir();
|
1416 |
$basedir = $uploads['basedir'];
|
1417 |
// Get relative upload path
|
1418 |
+
$relDir = str_replace(wpstg_replace_windows_directory_separator(ABSPATH), null, wpstg_replace_windows_directory_separator($basedir));
|
1419 |
return $relDir;
|
1420 |
}
|
1421 |
|
1433 |
|
1434 |
$customSlug = str_replace(wpstg_replace_windows_directory_separator(\WPStaging\WPStaging::getWPpath()), '', wpstg_replace_windows_directory_separator($uploadPath));
|
1435 |
|
1436 |
+
$newUploadPath = wpstg_replace_windows_directory_separator(\WPStaging\WPStaging::getWPpath()) . $this->options->cloneDirectoryName . '/' . $customSlug;
|
1437 |
|
1438 |
return $newUploadPath;
|
1439 |
}
|
1450 |
}
|
1451 |
|
1452 |
if ($this->isSubDir()) {
|
1453 |
+
return trailingslashit($this->multisiteHomeDomain) . trailingslashit($this->getSubDir()) . $this->options->cloneDirectoryName;
|
1454 |
}
|
1455 |
|
1456 |
// Get the path to the main multisite without appending and trailingslash e.g. wordpress
|
1457 |
$multisitePath = defined('PATH_CURRENT_SITE') ? PATH_CURRENT_SITE : '/';
|
1458 |
+
$url = rtrim($this->multisiteHomeDomain, '/\\') . $multisitePath . $this->options->cloneDirectoryName;
|
1459 |
|
1460 |
return $url;
|
1461 |
}
|
1469 |
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
1470 |
// This is happening much more often than you would expect
|
1471 |
$siteurl = preg_replace('#^https?://#', '', rtrim(get_option('siteurl'), '/'));
|
1472 |
+
$home = preg_replace('#^https?://#', '', rtrim(get_option('home'), '/'));
|
1473 |
|
1474 |
if ($home !== $siteurl) {
|
1475 |
return true;
|
1483 |
*/
|
1484 |
protected function getSubDir()
|
1485 |
{
|
1486 |
+
$home = get_option('home');
|
1487 |
$siteurl = get_option('siteurl');
|
1488 |
|
1489 |
if (empty($home) || empty($siteurl)) {
|
Backend/Modules/Jobs/Multisite/Database.php
CHANGED
@@ -171,69 +171,6 @@ class Database extends JobExecutable {
|
|
171 |
return $this->finishStep();
|
172 |
}
|
173 |
|
174 |
-
/**
|
175 |
-
* Copy multisite global user table wp_users to wpstgX_users
|
176 |
-
* @return bool
|
177 |
-
*/
|
178 |
-
// private function copyWpUsers() {
|
179 |
-
//// $strings = new Strings();
|
180 |
-
//// $tableName = $this->db->base_prefix . 'users';
|
181 |
-
//// $newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
182 |
-
//
|
183 |
-
// $tableName = $this->db->base_prefix . 'users';
|
184 |
-
// $newTableName = $this->getStagingPrefix() . 'users';
|
185 |
-
//
|
186 |
-
// $this->log( "DB Copy: Try to create table {$newTableName}" );
|
187 |
-
//
|
188 |
-
// // Drop table if necessary
|
189 |
-
// $this->dropTable( $newTableName );
|
190 |
-
//
|
191 |
-
// // Save current job
|
192 |
-
// $this->setJob( $newTableName );
|
193 |
-
//
|
194 |
-
// // Beginning of the job
|
195 |
-
// if( !$this->startJob( $newTableName, $tableName ) ) {
|
196 |
-
// return true;
|
197 |
-
// }
|
198 |
-
//
|
199 |
-
// // Copy data
|
200 |
-
// $this->copyData( $newTableName, $tableName );
|
201 |
-
//
|
202 |
-
// // Finish the step
|
203 |
-
// return $this->finishStep();
|
204 |
-
// }
|
205 |
-
|
206 |
-
/**
|
207 |
-
* Copy multisite global user table wp_usermeta to wpstgX_users
|
208 |
-
* @return bool
|
209 |
-
*/
|
210 |
-
// private function copyWpUsermeta() {
|
211 |
-
//// $strings = new Strings();
|
212 |
-
//// $tableName = $this->db->base_prefix . 'usermeta';
|
213 |
-
//// $newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
214 |
-
// $tableName = $this->db->base_prefix . 'usermeta';
|
215 |
-
// $newTableName = $this->getStagingPrefix() . 'usermeta';
|
216 |
-
//
|
217 |
-
// $this->log( "DB Copy: Try to create table {$newTableName}" );
|
218 |
-
//
|
219 |
-
//
|
220 |
-
// // Drop table if necessary
|
221 |
-
// $this->dropTable( $newTableName );
|
222 |
-
//
|
223 |
-
// // Save current job
|
224 |
-
// $this->setJob( $newTableName );
|
225 |
-
//
|
226 |
-
// // Beginning of the job
|
227 |
-
// if( !$this->startJob( $newTableName, $tableName ) ) {
|
228 |
-
// return true;
|
229 |
-
// }
|
230 |
-
// // Copy data
|
231 |
-
// $this->copyData( $newTableName, $tableName );
|
232 |
-
//
|
233 |
-
// // Finish the step
|
234 |
-
// return $this->finishStep();
|
235 |
-
// }
|
236 |
-
|
237 |
/**
|
238 |
* Copy data from old table to new table
|
239 |
* @param string $new
|
171 |
return $this->finishStep();
|
172 |
}
|
173 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
/**
|
175 |
* Copy data from old table to new table
|
176 |
* @param string $new
|
Backend/Modules/Jobs/Multisite/DatabaseExternal.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
4 |
|
5 |
// No Direct Access
|
6 |
-
if(
|
7 |
die;
|
8 |
}
|
9 |
|
@@ -15,7 +15,8 @@ use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
|
15 |
* Class Database
|
16 |
* @package WPStaging\Backend\Modules\Jobs
|
17 |
*/
|
18 |
-
class DatabaseExternal extends JobExecutable
|
|
|
19 |
|
20 |
/**
|
21 |
* @var int
|
@@ -42,35 +43,36 @@ class DatabaseExternal extends JobExecutable {
|
|
42 |
/**
|
43 |
* Initialize
|
44 |
*/
|
45 |
-
public function initialize()
|
46 |
-
|
|
|
47 |
$this->stagingDb = $this->getExternalDBConnection();
|
48 |
$this->getTables();
|
49 |
// Add 2 more tables to total count because we need to copy two more tables from the main multisite installation wp_users and wp_usermeta
|
50 |
-
$this->total
|
51 |
$this->isFatalError();
|
52 |
-
$this->strings
|
53 |
}
|
54 |
|
55 |
/**
|
56 |
* Get external db object
|
57 |
* @return mixed db | false
|
58 |
*/
|
59 |
-
private function getExternalDBConnection()
|
60 |
-
|
61 |
-
$db = new \wpdb( $this->options->databaseUser,
|
62 |
|
63 |
// Can not connect to mysql
|
64 |
-
if(
|
65 |
-
$this->returnException(
|
66 |
return false;
|
67 |
}
|
68 |
|
69 |
// Can not connect to database
|
70 |
-
$db->select(
|
71 |
-
if(
|
72 |
-
$error = isset(
|
73 |
-
$this->returnException(
|
74 |
exit;
|
75 |
}
|
76 |
return $db;
|
@@ -82,14 +84,14 @@ class DatabaseExternal extends JobExecutable {
|
|
82 |
*
|
83 |
* return void
|
84 |
*/
|
85 |
-
private function getTables()
|
86 |
-
|
87 |
-
if(
|
88 |
-
array_push(
|
89 |
$this->saveOptions();
|
90 |
}
|
91 |
-
if(
|
92 |
-
array_push(
|
93 |
$this->saveOptions();
|
94 |
}
|
95 |
}
|
@@ -99,9 +101,10 @@ class DatabaseExternal extends JobExecutable {
|
|
99 |
* and mainJob is not updating the clone
|
100 |
* @return boolean
|
101 |
*/
|
102 |
-
private function isFatalError()
|
103 |
-
|
104 |
-
|
|
|
105 |
$this->returnException(" Can not continue for security purposes. Directory {$path} is not empty! Use FTP or a file manager plugin and make sure it does not contain any files. ");
|
106 |
}
|
107 |
return false;
|
@@ -111,7 +114,8 @@ class DatabaseExternal extends JobExecutable {
|
|
111 |
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
112 |
* @return void
|
113 |
*/
|
114 |
-
protected function calculateTotalSteps()
|
|
|
115 |
$this->options->totalSteps = ($this->total === 0) ? 1 : $this->total;
|
116 |
}
|
117 |
|
@@ -120,27 +124,26 @@ class DatabaseExternal extends JobExecutable {
|
|
120 |
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
121 |
* @return bool
|
122 |
*/
|
123 |
-
protected function execute()
|
124 |
-
|
125 |
-
|
126 |
// Over limits threshold
|
127 |
-
if(
|
128 |
// Prepare response and save current progress
|
129 |
-
$this->prepareResponse(
|
130 |
$this->saveOptions();
|
131 |
return false;
|
132 |
}
|
133 |
|
134 |
// No more steps, finished
|
135 |
if (!$this->isRunning() || $this->options->currentStep > $this->total) {
|
136 |
-
$this->prepareResponse(
|
137 |
return false;
|
138 |
}
|
139 |
|
140 |
// Copy table
|
141 |
-
if(
|
142 |
// Prepare Response
|
143 |
-
$this->prepareResponse(
|
144 |
|
145 |
// Not finished
|
146 |
return true;
|
@@ -157,10 +160,9 @@ class DatabaseExternal extends JobExecutable {
|
|
157 |
* Get new prefix for the staging site
|
158 |
* @return string
|
159 |
*/
|
160 |
-
private function getStagingPrefix()
|
161 |
-
|
162 |
-
$this->options->prefix = !empty(
|
163 |
-
|
164 |
return $this->options->prefix;
|
165 |
}
|
166 |
|
@@ -169,33 +171,34 @@ class DatabaseExternal extends JobExecutable {
|
|
169 |
* @param string $tableName
|
170 |
* @return bool
|
171 |
*/
|
172 |
-
private function copyTable(
|
|
|
173 |
|
174 |
-
$tableName
|
175 |
-
$newTableName = $this->getStagingPrefix() . $this->strings->str_replace_first(
|
176 |
|
177 |
// Get wp_users from main site
|
178 |
-
if(
|
179 |
$tableName = $this->db->base_prefix . 'users';
|
180 |
}
|
181 |
// Get wp_usermeta from main site
|
182 |
-
if(
|
183 |
$tableName = $this->db->base_prefix . 'usermeta';
|
184 |
}
|
185 |
|
186 |
// Drop table if necessary
|
187 |
-
$this->dropTable(
|
188 |
|
189 |
// Save current job
|
190 |
-
$this->setJob(
|
191 |
|
192 |
// Beginning of the job
|
193 |
-
if(
|
194 |
return true;
|
195 |
}
|
196 |
|
197 |
// Copy data
|
198 |
-
$this->copyData(
|
199 |
|
200 |
// Finish the step
|
201 |
return $this->finishStep();
|
@@ -205,13 +208,14 @@ class DatabaseExternal extends JobExecutable {
|
|
205 |
* Set the job
|
206 |
* @param string $table
|
207 |
*/
|
208 |
-
private function setJob(
|
209 |
-
|
|
|
210 |
return;
|
211 |
}
|
212 |
|
213 |
$this->options->job->current = $table;
|
214 |
-
$this->options->job->start
|
215 |
}
|
216 |
|
217 |
/**
|
@@ -220,57 +224,58 @@ class DatabaseExternal extends JobExecutable {
|
|
220 |
* @param string $old
|
221 |
* @return bool
|
222 |
*/
|
223 |
-
private function startJob(
|
224 |
-
|
225 |
-
if(
|
226 |
return false;
|
227 |
}
|
228 |
|
229 |
-
if(
|
230 |
return true;
|
231 |
}
|
232 |
|
233 |
// Table does not exist
|
234 |
-
$result = $this->db->query(
|
235 |
-
if(
|
236 |
-
$this->log(
|
237 |
return true;
|
238 |
}
|
239 |
|
240 |
-
$this->log(
|
241 |
-
$sql = $this->
|
242 |
|
243 |
$search = '';
|
244 |
// Get table 'wp_users' from main site
|
245 |
-
if(
|
246 |
$search = $this->db->prefix . 'users';
|
247 |
}
|
248 |
// Get table 'wp_usermeta' from main site
|
249 |
-
if(
|
250 |
$search = $this->db->prefix . 'usermeta';
|
251 |
}
|
252 |
|
253 |
// Replace table prefix to the new one
|
254 |
-
$sql = str_replace(
|
|
|
|
|
|
|
255 |
|
256 |
// Make constraint unique to prevent error:(errno: 121 "Duplicate key on write or update")
|
257 |
$sql = wpstg_unique_constraint($sql);
|
258 |
|
259 |
-
$this->stagingDb->query(
|
260 |
|
261 |
-
if(
|
262 |
-
$this->returnException(
|
263 |
}
|
264 |
|
265 |
-
|
266 |
// Count amount of rows to insert with next step
|
267 |
$this->options->job->total = 0;
|
268 |
-
$this->options->job->total = ( int )
|
269 |
|
270 |
-
$this->log(
|
271 |
|
272 |
-
|
273 |
-
if( 0 == $this->options->job->total ) {
|
274 |
$this->finishStep();
|
275 |
return false;
|
276 |
}
|
@@ -281,30 +286,32 @@ class DatabaseExternal extends JobExecutable {
|
|
281 |
/**
|
282 |
* Get MySQL query create table
|
283 |
*
|
284 |
-
* @param
|
285 |
* @return array
|
286 |
*/
|
287 |
-
private function
|
288 |
-
|
289 |
-
// Get the CREATE statement
|
290 |
-
$row = $this->db->get_results(
|
291 |
|
292 |
// Convert prefix and entire table name to lowercase to prevent capitalization issues:
|
293 |
// https://dev.mysql.com/doc/refman/5.7/en/identifier-case-sensitivity.html
|
294 |
// @todo Testing! Can lead to issues with CONSTRAINTS
|
295 |
-
|
|
|
|
|
296 |
|
297 |
// Query: Get wp_users from main site
|
298 |
-
if(
|
299 |
-
$row[0] = str_replace(
|
300 |
}
|
301 |
// Query: Get wp_usermeta from main site
|
302 |
-
if(
|
303 |
-
$row[0] = str_replace(
|
304 |
}
|
305 |
|
306 |
// Get create table
|
307 |
-
if(
|
308 |
return $row[0]['Create Table'];
|
309 |
}
|
310 |
return array();
|
@@ -315,39 +322,38 @@ class DatabaseExternal extends JobExecutable {
|
|
315 |
* @param string $new
|
316 |
* @param string $old
|
317 |
*/
|
318 |
-
private function copyData(
|
319 |
-
|
320 |
$rows = $this->options->job->start + $this->settings->queryLimit;
|
321 |
$this->log(
|
322 |
-
|
323 |
);
|
324 |
|
325 |
$limitation = '';
|
326 |
|
327 |
-
if(
|
328 |
$limitation = " LIMIT {$this->settings->queryLimit} OFFSET {$this->options->job->start}";
|
329 |
}
|
330 |
|
331 |
// Get data from production site
|
332 |
-
$rows = $this->db->get_results(
|
333 |
|
334 |
// Start transaction
|
335 |
-
$this->stagingDb->query(
|
336 |
-
$this->stagingDb->query(
|
337 |
-
$this->stagingDb->query(
|
338 |
|
339 |
// Copy into staging site
|
340 |
-
foreach (
|
341 |
-
$escaped_values = $this->mysqlEscapeMimic(
|
342 |
-
$values
|
343 |
-
if (false === $this->stagingDb->query(
|
344 |
$this->log("Can not insert data into table {$new}", \WPStaging\Utils\Logger::TYPE_INFO);
|
345 |
}
|
346 |
-
//$this->stagingDb->query( "INSERT INTO `{$new}` VALUES ('{$values}')" );
|
347 |
}
|
348 |
// Commit transaction
|
349 |
-
$this->stagingDb->query(
|
350 |
-
$this->stagingDb->query(
|
351 |
|
352 |
|
353 |
// Set new offset
|
@@ -358,15 +364,16 @@ class DatabaseExternal extends JobExecutable {
|
|
358 |
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
359 |
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
360 |
* @access public
|
361 |
-
* @param
|
362 |
* @return string
|
363 |
*/
|
364 |
-
private function mysqlEscapeMimic(
|
365 |
-
|
366 |
-
|
|
|
367 |
}
|
368 |
-
if(
|
369 |
-
return str_replace(
|
370 |
}
|
371 |
|
372 |
return $input;
|
@@ -377,19 +384,20 @@ class DatabaseExternal extends JobExecutable {
|
|
377 |
* @param string $table
|
378 |
* @return boolean
|
379 |
*/
|
380 |
-
private function isExcludedTable(
|
|
|
381 |
|
382 |
-
$customTables
|
383 |
$defaultTables = array('blogs', 'blog_versions');
|
384 |
|
385 |
-
$tables = array_merge(
|
386 |
|
387 |
$excludedTables = array();
|
388 |
-
foreach (
|
389 |
$excludedTables[] = $this->options->prefix . $value;
|
390 |
}
|
391 |
|
392 |
-
if(
|
393 |
return true;
|
394 |
}
|
395 |
return false;
|
@@ -398,14 +406,15 @@ class DatabaseExternal extends JobExecutable {
|
|
398 |
/**
|
399 |
* Finish the step
|
400 |
*/
|
401 |
-
private function finishStep()
|
|
|
402 |
// This job is not finished yet
|
403 |
-
if(
|
404 |
return false;
|
405 |
}
|
406 |
|
407 |
// Add it to cloned tables listing
|
408 |
-
$this->options->clonedTables[] = isset(
|
409 |
|
410 |
// Reset job
|
411 |
$this->options->job = new \stdClass();
|
@@ -417,18 +426,19 @@ class DatabaseExternal extends JobExecutable {
|
|
417 |
* Drop table if necessary
|
418 |
* @param string $new
|
419 |
*/
|
420 |
-
private function dropTable(
|
|
|
421 |
|
422 |
-
$old = $this->stagingDb->get_var(
|
423 |
|
424 |
-
if(
|
425 |
return;
|
426 |
}
|
427 |
|
428 |
-
$this->log(
|
429 |
-
$this->stagingDb->query(
|
430 |
-
$this->stagingDb->query(
|
431 |
-
$this->stagingDb->query(
|
432 |
}
|
433 |
|
434 |
/**
|
@@ -437,13 +447,14 @@ class DatabaseExternal extends JobExecutable {
|
|
437 |
* @param string $old
|
438 |
* @return bool
|
439 |
*/
|
440 |
-
private function shouldDropTable(
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
!isset(
|
|
|
445 |
0 == $this->options->job->start
|
446 |
-
|
447 |
return true;
|
448 |
}
|
449 |
return false;
|
3 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
4 |
|
5 |
// No Direct Access
|
6 |
+
if (!defined("WPINC")) {
|
7 |
die;
|
8 |
}
|
9 |
|
15 |
* Class Database
|
16 |
* @package WPStaging\Backend\Modules\Jobs
|
17 |
*/
|
18 |
+
class DatabaseExternal extends JobExecutable
|
19 |
+
{
|
20 |
|
21 |
/**
|
22 |
* @var int
|
43 |
/**
|
44 |
* Initialize
|
45 |
*/
|
46 |
+
public function initialize()
|
47 |
+
{
|
48 |
+
$this->db = WPStaging::getInstance()->get("wpdb");
|
49 |
$this->stagingDb = $this->getExternalDBConnection();
|
50 |
$this->getTables();
|
51 |
// Add 2 more tables to total count because we need to copy two more tables from the main multisite installation wp_users and wp_usermeta
|
52 |
+
$this->total = count($this->options->tables) + 2;
|
53 |
$this->isFatalError();
|
54 |
+
$this->strings = new Strings();
|
55 |
}
|
56 |
|
57 |
/**
|
58 |
* Get external db object
|
59 |
* @return mixed db | false
|
60 |
*/
|
61 |
+
private function getExternalDBConnection()
|
62 |
+
{
|
63 |
+
$db = new \wpdb( $this->options->databaseUser, $this->options->databasePassword, $this->options->databaseDatabase, $this->options->databaseServer );
|
64 |
|
65 |
// Can not connect to mysql
|
66 |
+
if (!empty($db->error->errors['db_connect_fail']['0'])) {
|
67 |
+
$this->returnException("Can not connect to external database {$this->options->databaseDatabase}");
|
68 |
return false;
|
69 |
}
|
70 |
|
71 |
// Can not connect to database
|
72 |
+
$db->select($this->options->databaseDatabase);
|
73 |
+
if (!$db->ready) {
|
74 |
+
$error = isset($db->error->errors['db_select_fail']) ? $db->error->errors['db_select_fail'] : "Error: Can't select {database} Either it does not exist or you don't have privileges to access it.";
|
75 |
+
$this->returnException($error);
|
76 |
exit;
|
77 |
}
|
78 |
return $db;
|
84 |
*
|
85 |
* return void
|
86 |
*/
|
87 |
+
private function getTables()
|
88 |
+
{
|
89 |
+
if (!in_array($this->db->prefix . 'users', $this->options->tables)) {
|
90 |
+
array_push($this->options->tables, $this->db->prefix . 'users');
|
91 |
$this->saveOptions();
|
92 |
}
|
93 |
+
if (!in_array($this->db->prefix . 'usermeta', $this->options->tables)) {
|
94 |
+
array_push($this->options->tables, $this->db->prefix . 'usermeta');
|
95 |
$this->saveOptions();
|
96 |
}
|
97 |
}
|
101 |
* and mainJob is not updating the clone
|
102 |
* @return boolean
|
103 |
*/
|
104 |
+
private function isFatalError()
|
105 |
+
{
|
106 |
+
$path = trailingslashit($this->options->cloneDir);
|
107 |
+
if (isset($this->options->mainJob) && $this->options->mainJob !== 'updating' && (is_dir($path) && !wpstg_is_empty_dir($path))) {
|
108 |
$this->returnException(" Can not continue for security purposes. Directory {$path} is not empty! Use FTP or a file manager plugin and make sure it does not contain any files. ");
|
109 |
}
|
110 |
return false;
|
114 |
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
115 |
* @return void
|
116 |
*/
|
117 |
+
protected function calculateTotalSteps()
|
118 |
+
{
|
119 |
$this->options->totalSteps = ($this->total === 0) ? 1 : $this->total;
|
120 |
}
|
121 |
|
124 |
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
125 |
* @return bool
|
126 |
*/
|
127 |
+
protected function execute()
|
128 |
+
{
|
|
|
129 |
// Over limits threshold
|
130 |
+
if ($this->isOverThreshold()) {
|
131 |
// Prepare response and save current progress
|
132 |
+
$this->prepareResponse(false, false);
|
133 |
$this->saveOptions();
|
134 |
return false;
|
135 |
}
|
136 |
|
137 |
// No more steps, finished
|
138 |
if (!$this->isRunning() || $this->options->currentStep > $this->total) {
|
139 |
+
$this->prepareResponse(true, false);
|
140 |
return false;
|
141 |
}
|
142 |
|
143 |
// Copy table
|
144 |
+
if (isset($this->options->tables[$this->options->currentStep]) && !$this->copyTable($this->options->tables[$this->options->currentStep])) {
|
145 |
// Prepare Response
|
146 |
+
$this->prepareResponse(false, false);
|
147 |
|
148 |
// Not finished
|
149 |
return true;
|
160 |
* Get new prefix for the staging site
|
161 |
* @return string
|
162 |
*/
|
163 |
+
private function getStagingPrefix()
|
164 |
+
{
|
165 |
+
$this->options->prefix = !empty($this->options->databasePrefix) ? $this->options->databasePrefix : $this->db->prefix;
|
|
|
166 |
return $this->options->prefix;
|
167 |
}
|
168 |
|
171 |
* @param string $tableName
|
172 |
* @return bool
|
173 |
*/
|
174 |
+
private function copyTable($tableName)
|
175 |
+
{
|
176 |
|
177 |
+
$tableName = is_object($tableName) ? $tableName->name : $tableName;
|
178 |
+
$newTableName = $this->getStagingPrefix() . $this->strings->str_replace_first($this->db->prefix, null, $tableName);
|
179 |
|
180 |
// Get wp_users from main site
|
181 |
+
if ('users' === $this->strings->str_replace_first($this->db->prefix, null, $tableName)) {
|
182 |
$tableName = $this->db->base_prefix . 'users';
|
183 |
}
|
184 |
// Get wp_usermeta from main site
|
185 |
+
if ('usermeta' === $this->strings->str_replace_first($this->db->prefix, null, $tableName)) {
|
186 |
$tableName = $this->db->base_prefix . 'usermeta';
|
187 |
}
|
188 |
|
189 |
// Drop table if necessary
|
190 |
+
$this->dropTable($newTableName);
|
191 |
|
192 |
// Save current job
|
193 |
+
$this->setJob($newTableName);
|
194 |
|
195 |
// Beginning of the job
|
196 |
+
if (!$this->startJob($newTableName, $tableName)) {
|
197 |
return true;
|
198 |
}
|
199 |
|
200 |
// Copy data
|
201 |
+
$this->copyData($newTableName, $tableName);
|
202 |
|
203 |
// Finish the step
|
204 |
return $this->finishStep();
|
208 |
* Set the job
|
209 |
* @param string $table
|
210 |
*/
|
211 |
+
private function setJob($table)
|
212 |
+
{
|
213 |
+
if (isset($this->options->job->current)) {
|
214 |
return;
|
215 |
}
|
216 |
|
217 |
$this->options->job->current = $table;
|
218 |
+
$this->options->job->start = 0;
|
219 |
}
|
220 |
|
221 |
/**
|
224 |
* @param string $old
|
225 |
* @return bool
|
226 |
*/
|
227 |
+
private function startJob($new, $old)
|
228 |
+
{
|
229 |
+
if ($this->isExcludedTable($new)) {
|
230 |
return false;
|
231 |
}
|
232 |
|
233 |
+
if (0 != $this->options->job->start) {
|
234 |
return true;
|
235 |
}
|
236 |
|
237 |
// Table does not exist
|
238 |
+
$result = $this->db->query("SHOW TABLES LIKE '{$old}'");
|
239 |
+
if (false === $result || 0 === $result) {
|
240 |
+
$this->log("DB External Copy: Table {$this->options->databaseDatabase}.{$old} does not exists. Skip!");
|
241 |
return true;
|
242 |
}
|
243 |
|
244 |
+
$this->log("DB External Copy: CREATE table {$this->options->databaseDatabase}.{$new}");
|
245 |
+
$sql = $this->getTableCreateStatement($old);
|
246 |
|
247 |
$search = '';
|
248 |
// Get table 'wp_users' from main site
|
249 |
+
if ('users' === $this->strings->str_replace_first($this->db->base_prefix, null, $old)) {
|
250 |
$search = $this->db->prefix . 'users';
|
251 |
}
|
252 |
// Get table 'wp_usermeta' from main site
|
253 |
+
if ('usermeta' === $this->strings->str_replace_first($this->db->base_prefix, null, $old)) {
|
254 |
$search = $this->db->prefix . 'usermeta';
|
255 |
}
|
256 |
|
257 |
// Replace table prefix to the new one
|
258 |
+
$sql = str_replace("CREATE TABLE `{$search}`", "CREATE TABLE `{$new}`", $sql);
|
259 |
+
|
260 |
+
// Fix missing underscore issue #251. Replace whole table name. Prevents bug where $old table prefix contains no underscore
|
261 |
+
$sql = str_replace("CREATE TABLE `{$old}`", "CREATE TABLE `{$new}`", $sql);
|
262 |
|
263 |
// Make constraint unique to prevent error:(errno: 121 "Duplicate key on write or update")
|
264 |
$sql = wpstg_unique_constraint($sql);
|
265 |
|
266 |
+
$this->stagingDb->query('SET FOREIGN_KEY_CHECKS=0;');
|
267 |
|
268 |
+
if (false === $this->stagingDb->query($sql)) {
|
269 |
+
$this->returnException("DB External Copy - Fatal Error: {$this->stagingDb->last_error} Query: {$sql}");
|
270 |
}
|
271 |
|
|
|
272 |
// Count amount of rows to insert with next step
|
273 |
$this->options->job->total = 0;
|
274 |
+
$this->options->job->total = ( int )$this->db->get_var("SELECT COUNT(1) FROM `{$this->db->dbname}`.`{$old}`");
|
275 |
|
276 |
+
$this->log("DB External Copy: Table {$old} contains {$this->options->job->total} rows ");
|
277 |
|
278 |
+
if (0 == $this->options->job->total) {
|
|
|
279 |
$this->finishStep();
|
280 |
return false;
|
281 |
}
|
286 |
/**
|
287 |
* Get MySQL query create table
|
288 |
*
|
289 |
+
* @param string $table_name Table name
|
290 |
* @return array
|
291 |
*/
|
292 |
+
private function getTableCreateStatement($tableName)
|
293 |
+
{
|
294 |
+
// Get the CREATE statement from production table
|
295 |
+
$row = $this->db->get_results("SHOW CREATE TABLE `{$tableName}`", ARRAY_A);
|
296 |
|
297 |
// Convert prefix and entire table name to lowercase to prevent capitalization issues:
|
298 |
// https://dev.mysql.com/doc/refman/5.7/en/identifier-case-sensitivity.html
|
299 |
// @todo Testing! Can lead to issues with CONSTRAINTS
|
300 |
+
// Deprecated, We do not change the capitalization any longer!
|
301 |
+
// This prevented sites from proper cloning where prefix contains capitalized letters
|
302 |
+
//$row[0] = str_replace($tableName, strtolower($tableName), $row[0]);
|
303 |
|
304 |
// Query: Get wp_users from main site
|
305 |
+
if ('users' === $this->strings->str_replace_first($this->db->base_prefix, null, $tableName)) {
|
306 |
+
$row[0] = str_replace($tableName, $this->db->prefix . 'users', $row[0]);
|
307 |
}
|
308 |
// Query: Get wp_usermeta from main site
|
309 |
+
if ('usermeta' === $this->strings->str_replace_first($this->db->base_prefix, null, $tableName)) {
|
310 |
+
$row[0] = str_replace($tableName, $this->db->prefix . 'usermeta', $row[0]);
|
311 |
}
|
312 |
|
313 |
// Get create table
|
314 |
+
if (isset($row[0]['Create Table'])) {
|
315 |
return $row[0]['Create Table'];
|
316 |
}
|
317 |
return array();
|
322 |
* @param string $new
|
323 |
* @param string $old
|
324 |
*/
|
325 |
+
private function copyData($new, $old)
|
326 |
+
{
|
327 |
$rows = $this->options->job->start + $this->settings->queryLimit;
|
328 |
$this->log(
|
329 |
+
"DB External Copy: INSERT {$this->db->dbname}.{$old} as {$this->options->databaseDatabase}.{$new} from {$this->options->job->start} to {$rows} records"
|
330 |
);
|
331 |
|
332 |
$limitation = '';
|
333 |
|
334 |
+
if (0 < ( int )$this->settings->queryLimit) {
|
335 |
$limitation = " LIMIT {$this->settings->queryLimit} OFFSET {$this->options->job->start}";
|
336 |
}
|
337 |
|
338 |
// Get data from production site
|
339 |
+
$rows = $this->db->get_results("SELECT * FROM `{$old}` {$limitation}", ARRAY_A);
|
340 |
|
341 |
// Start transaction
|
342 |
+
$this->stagingDb->query('SET autocommit=0;');
|
343 |
+
$this->stagingDb->query('SET FOREIGN_KEY_CHECKS=0;');
|
344 |
+
$this->stagingDb->query('START TRANSACTION;');
|
345 |
|
346 |
// Copy into staging site
|
347 |
+
foreach ($rows as $row) {
|
348 |
+
$escaped_values = $this->mysqlEscapeMimic(array_values($row));
|
349 |
+
$values = implode("', '", $escaped_values);
|
350 |
+
if (false === $this->stagingDb->query("INSERT INTO `{$new}` VALUES ('{$values}')")) {
|
351 |
$this->log("Can not insert data into table {$new}", \WPStaging\Utils\Logger::TYPE_INFO);
|
352 |
}
|
|
|
353 |
}
|
354 |
// Commit transaction
|
355 |
+
$this->stagingDb->query('COMMIT;');
|
356 |
+
$this->stagingDb->query('SET autocommit=1;');
|
357 |
|
358 |
|
359 |
// Set new offset
|
364 |
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
365 |
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
366 |
* @access public
|
367 |
+
* @param string $input The string to escape.
|
368 |
* @return string
|
369 |
*/
|
370 |
+
private function mysqlEscapeMimic($input)
|
371 |
+
{
|
372 |
+
if (is_array($input)) {
|
373 |
+
return array_map(__METHOD__, $input);
|
374 |
}
|
375 |
+
if (!empty($input) && is_string($input)) {
|
376 |
+
return str_replace(array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $input);
|
377 |
}
|
378 |
|
379 |
return $input;
|
384 |
* @param string $table
|
385 |
* @return boolean
|
386 |
*/
|
387 |
+
private function isExcludedTable($table)
|
388 |
+
{
|
389 |
|
390 |
+
$customTables = apply_filters('wpstg_clone_database_tables_exclude', array());
|
391 |
$defaultTables = array('blogs', 'blog_versions');
|
392 |
|
393 |
+
$tables = array_merge($customTables, $defaultTables);
|
394 |
|
395 |
$excludedTables = array();
|
396 |
+
foreach ($tables as $key => $value) {
|
397 |
$excludedTables[] = $this->options->prefix . $value;
|
398 |
}
|
399 |
|
400 |
+
if (in_array($table, $excludedTables)) {
|
401 |
return true;
|
402 |
}
|
403 |
return false;
|
406 |
/**
|
407 |
* Finish the step
|
408 |
*/
|
409 |
+
private function finishStep()
|
410 |
+
{
|
411 |
// This job is not finished yet
|
412 |
+
if ($this->options->job->total > $this->options->job->start) {
|
413 |
return false;
|
414 |
}
|
415 |
|
416 |
// Add it to cloned tables listing
|
417 |
+
$this->options->clonedTables[] = isset($this->options->tables[$this->options->currentStep]) ? $this->options->tables[$this->options->currentStep] : false;
|
418 |
|
419 |
// Reset job
|
420 |
$this->options->job = new \stdClass();
|
426 |
* Drop table if necessary
|
427 |
* @param string $new
|
428 |
*/
|
429 |
+
private function dropTable($new)
|
430 |
+
{
|
431 |
|
432 |
+
$old = $this->stagingDb->get_var($this->stagingDb->prepare("SHOW TABLES LIKE %s", $new));
|
433 |
|
434 |
+
if (!$this->shouldDropTable($new, $old)) {
|
435 |
return;
|
436 |
}
|
437 |
|
438 |
+
$this->log("DB External Copy: {$new} already exists, dropping it first");
|
439 |
+
$this->stagingDb->query("SET FOREIGN_KEY_CHECKS=0");
|
440 |
+
$this->stagingDb->query("DROP TABLE {$new}");
|
441 |
+
$this->stagingDb->query("SET FOREIGN_KEY_CHECKS=1");
|
442 |
}
|
443 |
|
444 |
/**
|
447 |
* @param string $old
|
448 |
* @return bool
|
449 |
*/
|
450 |
+
private function shouldDropTable($new, $old)
|
451 |
+
{
|
452 |
+
if ($old === $new &&
|
453 |
+
(
|
454 |
+
!isset($this->options->job->current) ||
|
455 |
+
!isset($this->options->job->start) ||
|
456 |
0 == $this->options->job->start
|
457 |
+
)) {
|
458 |
return true;
|
459 |
}
|
460 |
return false;
|
Backend/Modules/Jobs/Multisite/Files.php
CHANGED
@@ -311,6 +311,10 @@ class Files extends JobExecutable
|
|
311 |
$src = fopen($src, 'r');
|
312 |
$dest = fopen($dst, 'w');
|
313 |
|
|
|
|
|
|
|
|
|
314 |
// Try first method:
|
315 |
while (!feof($src)) {
|
316 |
if (false === fwrite($dest, fread($src, $buffersize))) {
|
311 |
$src = fopen($src, 'r');
|
312 |
$dest = fopen($dst, 'w');
|
313 |
|
314 |
+
if (!$src || !$dest) {
|
315 |
+
return false;
|
316 |
+
}
|
317 |
+
|
318 |
// Try first method:
|
319 |
while (!feof($src)) {
|
320 |
if (false === fwrite($dest, fread($src, $buffersize))) {
|
Backend/Modules/Jobs/PreserveDataFirstStep.php
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
+
|
5 |
+
use WPStaging\WPStaging;
|
6 |
+
use WPStaging\Service\Adapter\SourceDatabase;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Preserve staging sites in wpstg_existing_clones_beta in staging database while updating a site
|
10 |
+
* While cloning, copy an existing entry from staging site to wpstg_tmp_data and after cloning restore that data.
|
11 |
+
* Mainly used while an existing staging site is updated, not initially cloned
|
12 |
+
* @package WPStaging\Backend\Modules\Jobs
|
13 |
+
*/
|
14 |
+
|
15 |
+
class PreserveDataFirstStep extends JobExecutable
|
16 |
+
{
|
17 |
+
/** @var object */
|
18 |
+
private $stagingDb;
|
19 |
+
|
20 |
+
/** @var object */
|
21 |
+
private $productionDb;
|
22 |
+
|
23 |
+
/** @var string */
|
24 |
+
private $stagingPrefix;
|
25 |
+
|
26 |
+
protected function calculateTotalSteps()
|
27 |
+
{
|
28 |
+
$this->options->totalSteps = 1;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* @return object
|
33 |
+
*/
|
34 |
+
public function start()
|
35 |
+
{
|
36 |
+
$db = new SourceDatabase($this->options);
|
37 |
+
|
38 |
+
$this->stagingDb = $db->getDatabase();
|
39 |
+
|
40 |
+
$this->productionDb = WPStaging::getInstance()->get("wpdb");
|
41 |
+
|
42 |
+
$this->stagingPrefix = $this->options->prefix;
|
43 |
+
|
44 |
+
if($db->isExternalDatabase()){
|
45 |
+
$this->stagingPrefix = $this->options->databasePrefix;
|
46 |
+
}
|
47 |
+
|
48 |
+
$this->run();
|
49 |
+
|
50 |
+
$this->saveOptions();
|
51 |
+
|
52 |
+
return ( object )$this->response;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* @return bool
|
57 |
+
*/
|
58 |
+
protected function execute()
|
59 |
+
{
|
60 |
+
|
61 |
+
$this->copyToTmp();
|
62 |
+
|
63 |
+
$this->prepareResponse(true, true);
|
64 |
+
return false;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* @return bool
|
69 |
+
*/
|
70 |
+
|
71 |
+
public function copyToTmp()
|
72 |
+
{
|
73 |
+
// Delete wpstg_tmp_data and reset it
|
74 |
+
$delete = $this->productionDb->query(
|
75 |
+
$this->productionDb->prepare("DELETE FROM " . $this->productionDb->prefix . "options WHERE `option_name` = %s", "wpstg_tmp_data"
|
76 |
+
)
|
77 |
+
);
|
78 |
+
|
79 |
+
if(!$this->tableExists($this->stagingPrefix . "options")){
|
80 |
+
return true;
|
81 |
+
}
|
82 |
+
|
83 |
+
// Get wpstg_existing_clones_beta from staging database
|
84 |
+
$result = $this->stagingDb->get_var(
|
85 |
+
$this->stagingDb->prepare(
|
86 |
+
"SELECT `option_value` FROM " . $this->stagingPrefix . "options WHERE `option_name` = %s", "wpstg_existing_clones_beta"
|
87 |
+
)
|
88 |
+
);
|
89 |
+
|
90 |
+
// Nothing to do
|
91 |
+
if (!$result){
|
92 |
+
return true;
|
93 |
+
}
|
94 |
+
|
95 |
+
// Insert wpstg_existing_clones_beta into wpstg_tmp_data in production database
|
96 |
+
$insert = $this->productionDb->query(
|
97 |
+
$this->productionDb->prepare(
|
98 |
+
"INSERT INTO `" . $this->productionDb->prefix . "options` ( `option_id`, `option_name`, `option_value`, `autoload` ) VALUES ( NULL , %s, %s, %s )", "wpstg_tmp_data", $result, "no"
|
99 |
+
)
|
100 |
+
);
|
101 |
+
|
102 |
+
if (false === $delete) {
|
103 |
+
$this->log("Preserve Data: Failed to delete wpstg_tmp_data");
|
104 |
+
}
|
105 |
+
if (false === $result) {
|
106 |
+
$this->log("Preserve Data: Failed to get wpstg_existing_clones_beta");
|
107 |
+
}
|
108 |
+
if (false === $insert) {
|
109 |
+
$this->log("Preserve Data: Failed to insert wpstg_existing_clones_beta to wpstg_tmp_data");
|
110 |
+
}
|
111 |
+
return true;
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Check if table exists
|
116 |
+
* @param string $table
|
117 |
+
* @return boolean
|
118 |
+
*/
|
119 |
+
private function tableExists($table)
|
120 |
+
{
|
121 |
+
return !($this->stagingDb->get_var("SHOW TABLES LIKE '{$table}'") != $table);
|
122 |
+
}
|
123 |
+
|
124 |
+
|
125 |
+
}
|
Backend/Modules/Jobs/PreserveDataSecondStep.php
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
+
|
5 |
+
use WPStaging\WPStaging;
|
6 |
+
use WPStaging\Service\Adapter\SourceDatabase;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Copy wpstg_tmp_data back to wpstg_existing_clones_beta after cloning with class::PreserveDataSecondStep
|
10 |
+
* @package WPStaging\Backend\Modules\Jobs
|
11 |
+
*/
|
12 |
+
|
13 |
+
class PreserveDataSecondStep extends JobExecutable
|
14 |
+
{
|
15 |
+
/** @var object */
|
16 |
+
private $stagingDb;
|
17 |
+
|
18 |
+
/** @var object */
|
19 |
+
private $productionDb;
|
20 |
+
|
21 |
+
/** @var string */
|
22 |
+
private $stagingPrefix;
|
23 |
+
|
24 |
+
protected function calculateTotalSteps()
|
25 |
+
{
|
26 |
+
$this->options->totalSteps = 1;
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @return object
|
31 |
+
*/
|
32 |
+
public function start()
|
33 |
+
{
|
34 |
+
$this->run();
|
35 |
+
|
36 |
+
$this->saveOptions();
|
37 |
+
|
38 |
+
return ( object )$this->response;
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* @return bool
|
43 |
+
*/
|
44 |
+
protected function execute()
|
45 |
+
{
|
46 |
+
$db = new SourceDatabase($this->options);
|
47 |
+
|
48 |
+
$this->stagingDb = $db->getDatabase();
|
49 |
+
|
50 |
+
$this->productionDb = WPStaging::getInstance()->get("wpdb");
|
51 |
+
|
52 |
+
$this->stagingPrefix = $this->options->prefix;
|
53 |
+
|
54 |
+
if($db->isExternalDatabase()){
|
55 |
+
$this->stagingPrefix = $this->options->databasePrefix;
|
56 |
+
}
|
57 |
+
|
58 |
+
$this->copyToStaging();
|
59 |
+
|
60 |
+
$this->prepareResponse(true, true);
|
61 |
+
return false;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* @return bool
|
66 |
+
*/
|
67 |
+
|
68 |
+
public function copyToStaging()
|
69 |
+
{
|
70 |
+
// Get wpstg_tmp_data from production database
|
71 |
+
$result = $this->productionDb->get_var(
|
72 |
+
$this->productionDb->prepare(
|
73 |
+
"SELECT `option_value` FROM " . $this->productionDb->prefix . "options WHERE `option_name` = %s", "wpstg_tmp_data"
|
74 |
+
)
|
75 |
+
);
|
76 |
+
|
77 |
+
// Nothing to do
|
78 |
+
if (!$result){
|
79 |
+
return true;
|
80 |
+
}
|
81 |
+
|
82 |
+
// Delete wpstg_tmp_data
|
83 |
+
$delete = $this->stagingDb->query(
|
84 |
+
$this->stagingDb->prepare("DELETE FROM " . $this->stagingPrefix . "options WHERE `option_name` = %s", "wpstg_existing_clones_beta"
|
85 |
+
)
|
86 |
+
);
|
87 |
+
|
88 |
+
// Insert wpstg_existing_clones_beta in staging database
|
89 |
+
$insert = $this->stagingDb->query(
|
90 |
+
$this->stagingDb->prepare(
|
91 |
+
"INSERT INTO `" . $this->stagingPrefix . "options` ( `option_id`, `option_name`, `option_value`, `autoload` ) VALUES ( NULL , %s, %s, %s )", "wpstg_existing_clones_beta", $result, "no"
|
92 |
+
)
|
93 |
+
);
|
94 |
+
|
95 |
+
if (false === $delete) {
|
96 |
+
$this->log("Preserve Data Second Step: Failed to delete wpstg_tmp_data");
|
97 |
+
}
|
98 |
+
if (false === $result) {
|
99 |
+
$this->log("Preserve Data Second Step: Failed to get wpstg_existing_clones_beta");
|
100 |
+
}
|
101 |
+
if (false === $insert) {
|
102 |
+
$this->log("Preserve Data Second Step: Failed to insert wpstg_tmp_data to wpstg_existing_clones_beta");
|
103 |
+
}
|
104 |
+
return true;
|
105 |
+
}
|
106 |
+
|
107 |
+
|
108 |
+
}
|
Backend/Modules/Jobs/Scan.php
CHANGED
@@ -7,6 +7,7 @@ if( !defined( "WPINC" ) ) {
|
|
7 |
die;
|
8 |
}
|
9 |
|
|
|
10 |
use WPStaging\WPStaging;
|
11 |
use WPStaging\Utils\Directories;
|
12 |
use WPStaging\Backend\Optimizer\Optimizer;
|
@@ -50,11 +51,12 @@ class Scan extends Job {
|
|
50 |
|
51 |
/**
|
52 |
* Start Module
|
53 |
-
* @return $this
|
|
|
54 |
*/
|
55 |
public function start() {
|
56 |
// Basic Options
|
57 |
-
$this->options->root = str_replace( array("\\", '/'), DIRECTORY_SEPARATOR,
|
58 |
$this->options->existingClones = get_option( "wpstg_existing_clones_beta", array() );
|
59 |
$this->options->current = null;
|
60 |
|
@@ -81,8 +83,7 @@ class Scan extends Job {
|
|
81 |
$this->options->scannedDirectories = array();
|
82 |
|
83 |
// Job
|
84 |
-
$this->options->currentJob = "
|
85 |
-
//$this->options->currentJob = "directories";
|
86 |
$this->options->currentStep = 0;
|
87 |
$this->options->totalSteps = 0;
|
88 |
|
@@ -109,7 +110,7 @@ class Scan extends Job {
|
|
109 |
|
110 |
/**
|
111 |
* Format bytes into human readable form
|
112 |
-
* @param
|
113 |
* @param int $precision
|
114 |
* @return string
|
115 |
*/
|
@@ -128,7 +129,7 @@ class Scan extends Job {
|
|
128 |
}
|
129 |
|
130 |
/**
|
131 |
-
* @param null|
|
132 |
* @param bool $forceDisabled
|
133 |
* @return string
|
134 |
*/
|
@@ -142,7 +143,7 @@ class Scan extends Job {
|
|
142 |
|
143 |
$output = '';
|
144 |
foreach ( $directories as $name => $directory ) {
|
145 |
-
// Not a directory, possibly a symlink, therefore we will skip it
|
146 |
if( !is_array( $directory ) ) {
|
147 |
continue;
|
148 |
}
|
@@ -161,7 +162,7 @@ class Scan extends Job {
|
|
161 |
$dataSize = isset( $data["size"] ) ? $data["size"] : '';
|
162 |
|
163 |
|
164 |
-
// Select all wp core folders and their sub dirs.
|
165 |
// Unselect all other folders (default setting)
|
166 |
$isDisabled = ($name !== 'wp-admin' &&
|
167 |
$name !== 'wp-includes' &&
|
@@ -216,8 +217,7 @@ class Scan extends Job {
|
|
216 |
|
217 |
|
218 |
$data = array(
|
219 |
-
|
220 |
-
'usedspace' => $this->formatSize( $this->getDirectorySizeInclSubdirs( \WPStaging\WPStaging::getWPpath() ) )
|
221 |
);
|
222 |
|
223 |
echo json_encode( $data );
|
@@ -230,13 +230,6 @@ class Scan extends Job {
|
|
230 |
protected function getTables() {
|
231 |
$wpDB = WPStaging::getInstance()->get( "wpdb" );
|
232 |
|
233 |
-
// if( strlen( $wpDB->prefix ) > 0 ) {
|
234 |
-
// //$prefix = str_replace('_', '', $wpDB->prefix);
|
235 |
-
// $sql = "SHOW TABLE STATUS LIKE '{$wpDB->prefix}%'";
|
236 |
-
// } else {
|
237 |
-
// $sql = "SHOW TABLE STATUS";
|
238 |
-
// }
|
239 |
-
|
240 |
$sql = "SHOW TABLE STATUS";
|
241 |
|
242 |
$tables = $wpDB->get_results( $sql );
|
@@ -248,27 +241,33 @@ class Scan extends Job {
|
|
248 |
foreach ( $tables as $table ) {
|
249 |
|
250 |
// Create array of unchecked tables
|
251 |
-
|
|
|
|
|
|
|
252 |
$this->options->excludedTables[] = $table->Name;
|
253 |
}
|
254 |
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
|
|
|
|
|
|
260 |
}
|
261 |
|
262 |
$this->options->tables = json_decode( json_encode( $currentTables ) );
|
263 |
}
|
264 |
|
|
|
265 |
/**
|
266 |
* Get directories and main meta data about'em recursively
|
267 |
*/
|
268 |
protected function getDirectories() {
|
269 |
|
270 |
-
$directories = new Iterators\RecursiveDirectoryIterator(
|
271 |
-
|
272 |
|
273 |
foreach ( $directories as $directory ) {
|
274 |
// Not a valid directory
|
@@ -290,13 +289,11 @@ class Scan extends Job {
|
|
290 |
|
291 |
// Gather Custom Uploads Folder if there is one
|
292 |
$this->getSubDirectories( $this->getUploadDir() );
|
293 |
-
|
294 |
-
// Gather /sites/ or /blogs.dir/ folder if there is one (for multisites)
|
295 |
-
$this->getSubDirectories( $this->getMuUploadSitesDir() );
|
296 |
}
|
297 |
|
298 |
/**
|
299 |
* @param string $path
|
|
|
300 |
*/
|
301 |
protected function getSubDirectories( $path ) {
|
302 |
|
@@ -308,7 +305,7 @@ class Scan extends Job {
|
|
308 |
return false;
|
309 |
}
|
310 |
|
311 |
-
// IMPORTANT: If this is not used and a folder belongs to another user
|
312 |
// DirectoryIterator() will throw a fatal error which can not be catched with is_readable()
|
313 |
if( !opendir( $path ) ) {
|
314 |
return false;
|
@@ -324,12 +321,13 @@ class Scan extends Job {
|
|
324 |
|
325 |
$this->handleDirectory( $path );
|
326 |
}
|
|
|
327 |
}
|
328 |
|
329 |
/**
|
330 |
* Get Path from $directory
|
331 |
-
* @param
|
332 |
-
* @return string
|
333 |
*/
|
334 |
protected function getPath( $directory ) {
|
335 |
|
@@ -339,10 +337,10 @@ class Scan extends Job {
|
|
339 |
* Prevents open base dir restriction fatal errors
|
340 |
*/
|
341 |
|
342 |
-
if( strpos( $directory->getRealPath(),
|
343 |
return false;
|
344 |
}
|
345 |
-
$path = str_replace(
|
346 |
|
347 |
// Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
|
348 |
if( !$directory->isDir() || strlen( $path ) < 1 ) {
|
@@ -358,7 +356,7 @@ class Scan extends Job {
|
|
358 |
*/
|
359 |
protected function handleDirectory( $path ) {
|
360 |
$directoryArray = explode( DIRECTORY_SEPARATOR, $path );
|
361 |
-
$total = is_array( $directoryArray ) || $directoryArray instanceof Countable ? count( $directoryArray ) : 0;
|
362 |
|
363 |
if( $total < 1 ) {
|
364 |
return;
|
@@ -379,12 +377,12 @@ class Scan extends Job {
|
|
379 |
continue;
|
380 |
}
|
381 |
|
382 |
-
$fullPath =
|
383 |
$size = $this->getDirectorySize( $fullPath );
|
384 |
|
385 |
$currentArray["metaData"] = array(
|
386 |
"size" => $size,
|
387 |
-
"path" =>
|
388 |
);
|
389 |
}
|
390 |
}
|
@@ -407,7 +405,7 @@ class Scan extends Job {
|
|
407 |
* @param string $dir
|
408 |
* @return int
|
409 |
*/
|
410 |
-
function getDirectorySizeInclSubdirs( $dir ) {
|
411 |
$size = 0;
|
412 |
foreach ( glob( rtrim( $dir, '/' ) . '/*', GLOB_NOSORT ) as $each ) {
|
413 |
$size += is_file( $each ) ? filesize( $each ) : $this->getDirectorySizeInclSubdirs( $each );
|
@@ -415,45 +413,15 @@ class Scan extends Job {
|
|
415 |
return $size;
|
416 |
}
|
417 |
|
418 |
-
/**
|
419 |
-
* Get absolute WP uploads path e.g.
|
420 |
-
* Multisites: /var/www/htdocs/example.com/wp-content/uploads/sites/1 or /var/www/htdocs/example.com/wp-content/blogs.dir/1/files
|
421 |
-
* Single sites: /var/www/htdocs/example.com/wp-content/uploads
|
422 |
-
* @return string
|
423 |
-
*/
|
424 |
-
protected function getUploadDir() {
|
425 |
-
$uploads = wp_upload_dir( null, false );
|
426 |
-
|
427 |
-
$baseDir = wpstg_replace_windows_directory_separator( $uploads['basedir'] );
|
428 |
-
|
429 |
-
// If multisite (and if not the main site in a post-MU network)
|
430 |
-
if( is_multisite() && !( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
|
431 |
-
// blogs.dir is used on WP 3.5 and lower
|
432 |
-
if( false !== strpos( $baseDir, 'blogs.dir' ) ) {
|
433 |
-
// remove this piece from the basedir: /blogs.dir/2/files
|
434 |
-
$uploadDir = wpstg_replace_first_match( '/blogs.dir/' . get_current_blog_id() . '/files', null, $baseDir );
|
435 |
-
$dir = wpstg_replace_windows_directory_separator( $uploadDir . '/blogs.dir' );
|
436 |
-
} else {
|
437 |
-
// remove this piece from the basedir: /sites/2
|
438 |
-
$uploadDir = wpstg_replace_first_match( '/sites/' . get_current_blog_id(), null, $baseDir );
|
439 |
-
$dir = wpstg_replace_windows_directory_separator( $uploadDir . '/sites' );
|
440 |
-
}
|
441 |
-
|
442 |
-
|
443 |
-
return $dir;
|
444 |
-
}
|
445 |
-
return $baseDir;
|
446 |
-
}
|
447 |
|
448 |
/**
|
449 |
-
* Get absolute WP uploads path e.g.
|
450 |
* Multisites: /var/www/htdocs/example.com/wp-content/uploads/sites/1 or /var/www/htdocs/example.com/wp-content/blogs.dir/1/files
|
451 |
* Single sites: /var/www/htdocs/example.com/wp-content/uploads
|
452 |
* @return string
|
453 |
*/
|
454 |
-
protected function
|
455 |
$uploads = wp_upload_dir( null, false );
|
456 |
-
|
457 |
$baseDir = wpstg_replace_windows_directory_separator( $uploads['basedir'] );
|
458 |
|
459 |
// If multisite (and if not the main site in a post-MU network)
|
7 |
die;
|
8 |
}
|
9 |
|
10 |
+
use WPStaging\Command\Database\Snapshot\SnapshotHandler;
|
11 |
use WPStaging\WPStaging;
|
12 |
use WPStaging\Utils\Directories;
|
13 |
use WPStaging\Backend\Optimizer\Optimizer;
|
51 |
|
52 |
/**
|
53 |
* Start Module
|
54 |
+
* @return $this|object
|
55 |
+
* @throws \Exception
|
56 |
*/
|
57 |
public function start() {
|
58 |
// Basic Options
|
59 |
+
$this->options->root = str_replace( array("\\", '/'), DIRECTORY_SEPARATOR, WPStaging::getWPpath() );
|
60 |
$this->options->existingClones = get_option( "wpstg_existing_clones_beta", array() );
|
61 |
$this->options->current = null;
|
62 |
|
83 |
$this->options->scannedDirectories = array();
|
84 |
|
85 |
// Job
|
86 |
+
$this->options->currentJob = "PreserveDataFirstStep";
|
|
|
87 |
$this->options->currentStep = 0;
|
88 |
$this->options->totalSteps = 0;
|
89 |
|
110 |
|
111 |
/**
|
112 |
* Format bytes into human readable form
|
113 |
+
* @param float $bytes
|
114 |
* @param int $precision
|
115 |
* @return string
|
116 |
*/
|
129 |
}
|
130 |
|
131 |
/**
|
132 |
+
* @param null|array $directories
|
133 |
* @param bool $forceDisabled
|
134 |
* @return string
|
135 |
*/
|
143 |
|
144 |
$output = '';
|
145 |
foreach ( $directories as $name => $directory ) {
|
146 |
+
// Not a directory, possibly a symlink, therefore we will skip it
|
147 |
if( !is_array( $directory ) ) {
|
148 |
continue;
|
149 |
}
|
162 |
$dataSize = isset( $data["size"] ) ? $data["size"] : '';
|
163 |
|
164 |
|
165 |
+
// Select all wp core folders and their sub dirs.
|
166 |
// Unselect all other folders (default setting)
|
167 |
$isDisabled = ($name !== 'wp-admin' &&
|
168 |
$name !== 'wp-includes' &&
|
217 |
|
218 |
|
219 |
$data = array(
|
220 |
+
'usedspace' => $this->formatSize( $this->getDirectorySizeInclSubdirs( WPStaging::getWPpath() ) )
|
|
|
221 |
);
|
222 |
|
223 |
echo json_encode( $data );
|
230 |
protected function getTables() {
|
231 |
$wpDB = WPStaging::getInstance()->get( "wpdb" );
|
232 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
$sql = "SHOW TABLE STATUS";
|
234 |
|
235 |
$tables = $wpDB->get_results( $sql );
|
241 |
foreach ( $tables as $table ) {
|
242 |
|
243 |
// Create array of unchecked tables
|
244 |
+
// On the main website of a multisite installation, do not select network site tables beginning with wp_1_, wp_2_ etc.
|
245 |
+
// (On network sites, the correct tables are selected anyway)
|
246 |
+
if (( ! empty($wpDB->prefix) && 0 !== strpos($table->Name, $wpDB->prefix))
|
247 |
+
|| (is_multisite() && is_main_site() && preg_match('/^wp_\d+_/', $table->Name))) {
|
248 |
$this->options->excludedTables[] = $table->Name;
|
249 |
}
|
250 |
|
251 |
+
if ((0 !== strpos($table->Name, SnapshotHandler::PREFIX_MANUAL))
|
252 |
+
&& (0 !== strpos($table->Name, SnapshotHandler::PREFIX_AUTOMATIC))
|
253 |
+
&& ($table->Comment !== "VIEW")) {
|
254 |
+
$currentTables[] = array(
|
255 |
+
"name" => $table->Name,
|
256 |
+
"size" => ($table->Data_length + $table->Index_length)
|
257 |
+
);
|
258 |
+
}
|
259 |
}
|
260 |
|
261 |
$this->options->tables = json_decode( json_encode( $currentTables ) );
|
262 |
}
|
263 |
|
264 |
+
|
265 |
/**
|
266 |
* Get directories and main meta data about'em recursively
|
267 |
*/
|
268 |
protected function getDirectories() {
|
269 |
|
270 |
+
$directories = new Iterators\RecursiveDirectoryIterator( WPStaging::getWPpath() );
|
|
|
271 |
|
272 |
foreach ( $directories as $directory ) {
|
273 |
// Not a valid directory
|
289 |
|
290 |
// Gather Custom Uploads Folder if there is one
|
291 |
$this->getSubDirectories( $this->getUploadDir() );
|
|
|
|
|
|
|
292 |
}
|
293 |
|
294 |
/**
|
295 |
* @param string $path
|
296 |
+
* @return bool
|
297 |
*/
|
298 |
protected function getSubDirectories( $path ) {
|
299 |
|
305 |
return false;
|
306 |
}
|
307 |
|
308 |
+
// IMPORTANT: If this is not used and a folder belongs to another user
|
309 |
// DirectoryIterator() will throw a fatal error which can not be catched with is_readable()
|
310 |
if( !opendir( $path ) ) {
|
311 |
return false;
|
321 |
|
322 |
$this->handleDirectory( $path );
|
323 |
}
|
324 |
+
return false;
|
325 |
}
|
326 |
|
327 |
/**
|
328 |
* Get Path from $directory
|
329 |
+
* @param string
|
330 |
+
* @return bool|string
|
331 |
*/
|
332 |
protected function getPath( $directory ) {
|
333 |
|
337 |
* Prevents open base dir restriction fatal errors
|
338 |
*/
|
339 |
|
340 |
+
if( strpos( $directory->getRealPath(), WPStaging::getWPpath() ) !== 0 ) {
|
341 |
return false;
|
342 |
}
|
343 |
+
$path = str_replace( WPStaging::getWPpath(), null, $directory->getRealPath() );
|
344 |
|
345 |
// Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
|
346 |
if( !$directory->isDir() || strlen( $path ) < 1 ) {
|
356 |
*/
|
357 |
protected function handleDirectory( $path ) {
|
358 |
$directoryArray = explode( DIRECTORY_SEPARATOR, $path );
|
359 |
+
$total = is_array( $directoryArray ) || $directoryArray instanceof \Countable ? count( $directoryArray ) : 0;
|
360 |
|
361 |
if( $total < 1 ) {
|
362 |
return;
|
377 |
continue;
|
378 |
}
|
379 |
|
380 |
+
$fullPath = WPStaging::getWPpath() . $path;
|
381 |
$size = $this->getDirectorySize( $fullPath );
|
382 |
|
383 |
$currentArray["metaData"] = array(
|
384 |
"size" => $size,
|
385 |
+
"path" => WPStaging::getWPpath() . $path,
|
386 |
);
|
387 |
}
|
388 |
}
|
405 |
* @param string $dir
|
406 |
* @return int
|
407 |
*/
|
408 |
+
protected function getDirectorySizeInclSubdirs( $dir ) {
|
409 |
$size = 0;
|
410 |
foreach ( glob( rtrim( $dir, '/' ) . '/*', GLOB_NOSORT ) as $each ) {
|
411 |
$size += is_file( $each ) ? filesize( $each ) : $this->getDirectorySizeInclSubdirs( $each );
|
413 |
return $size;
|
414 |
}
|
415 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
416 |
|
417 |
/**
|
418 |
+
* Get absolute WP uploads path e.g.
|
419 |
* Multisites: /var/www/htdocs/example.com/wp-content/uploads/sites/1 or /var/www/htdocs/example.com/wp-content/blogs.dir/1/files
|
420 |
* Single sites: /var/www/htdocs/example.com/wp-content/uploads
|
421 |
* @return string
|
422 |
*/
|
423 |
+
protected function getUploadDir() {
|
424 |
$uploads = wp_upload_dir( null, false );
|
|
|
425 |
$baseDir = wpstg_replace_windows_directory_separator( $uploads['basedir'] );
|
426 |
|
427 |
// If multisite (and if not the main site in a post-MU network)
|
Backend/Modules/Jobs/SearchReplace.php
CHANGED
@@ -9,8 +9,6 @@ if (!defined("WPINC")) {
|
|
9 |
|
10 |
use WPStaging\WPStaging;
|
11 |
use WPStaging\Utils\Strings;
|
12 |
-
use WPStaging\Utils\Helper;
|
13 |
-
|
14 |
/**
|
15 |
* Class Database
|
16 |
* @package WPStaging\Backend\Modules\Jobs
|
@@ -44,7 +42,7 @@ class SearchReplace extends JobExecutable
|
|
44 |
|
45 |
/**
|
46 |
*
|
47 |
-
* @var
|
48 |
*/
|
49 |
private $strings;
|
50 |
|
@@ -367,6 +365,7 @@ class SearchReplace extends JobExecutable
|
|
367 |
'wpstg_existing_clones',
|
368 |
'wpstg_settings',
|
369 |
'wpstg_license_status',
|
|
|
370 |
'siteurl',
|
371 |
'home'
|
372 |
);
|
9 |
|
10 |
use WPStaging\WPStaging;
|
11 |
use WPStaging\Utils\Strings;
|
|
|
|
|
12 |
/**
|
13 |
* Class Database
|
14 |
* @package WPStaging\Backend\Modules\Jobs
|
42 |
|
43 |
/**
|
44 |
*
|
45 |
+
* @var object
|
46 |
*/
|
47 |
private $strings;
|
48 |
|
365 |
'wpstg_existing_clones',
|
366 |
'wpstg_settings',
|
367 |
'wpstg_license_status',
|
368 |
+
'wpstg_tmp_data',
|
369 |
'siteurl',
|
370 |
'home'
|
371 |
);
|
Backend/Modules/Jobs/SearchReplaceExternal.php
CHANGED
@@ -371,6 +371,7 @@ class SearchReplaceExternal extends JobExecutable
|
|
371 |
'wpstg_existing_clones',
|
372 |
'wpstg_settings',
|
373 |
'wpstg_license_status',
|
|
|
374 |
'siteurl',
|
375 |
'home'
|
376 |
);
|
371 |
'wpstg_existing_clones',
|
372 |
'wpstg_settings',
|
373 |
'wpstg_license_status',
|
374 |
+
'wpstg_tmp_data',
|
375 |
'siteurl',
|
376 |
'home'
|
377 |
);
|
Backend/Modules/SystemInfo.php
CHANGED
@@ -208,7 +208,8 @@ class SystemInfo extends InjectionAware
|
|
208 |
//$output .= PHP_EOL . PHP_EOL;
|
209 |
|
210 |
$output .= $this->info("Plugin Pro Version:", get_option('wpstgpro_version', 'undefined'));
|
211 |
-
|
|
|
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'));
|
208 |
//$output .= PHP_EOL . PHP_EOL;
|
209 |
|
210 |
$output .= $this->info("Plugin Pro Version:", get_option('wpstgpro_version', 'undefined'));
|
211 |
+
$output .= $this->info("Plugin Pro License Key:", get_option('wpstg_license_key'));
|
212 |
+
$output .= $this->info("Plugin Free Version:", get_option('wpstg_version', 'undefined'));
|
213 |
$output .= $this->info("Install Date:", get_option('wpstg_installDate', 'undefined'));
|
214 |
$output .= $this->info("Upgraded from Pro:", get_option('wpstgpro_version_upgraded_from', 'undefined'));
|
215 |
$output .= $this->info("Upgraded from Free:", get_option('wpstg_version_upgraded_from', 'undefined'));
|
Backend/public/css/wpstg-admin.css
CHANGED
@@ -960,7 +960,7 @@
|
|
960 |
margin-bottom:4px;
|
961 |
}
|
962 |
|
963 |
-
.wpstg-report-email {
|
964 |
width: 100%;
|
965 |
font-weight: 400;
|
966 |
font-size: .8rem;
|
960 |
margin-bottom:4px;
|
961 |
}
|
962 |
|
963 |
+
.wpstg-report-email, .wpstg-report-hosting-provider {
|
964 |
width: 100%;
|
965 |
font-weight: 400;
|
966 |
font-size: .8rem;
|
Backend/public/js/wpstg-admin.js
CHANGED
@@ -274,11 +274,35 @@ var WPStaging = (function ($) {
|
|
274 |
$('#wpstg_clone_dir').attr('placeholder', path);
|
275 |
$('#wpstg_clone_hostname').attr('placeholder', uri);
|
276 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
;
|
278 |
|
279 |
cloneActions();
|
280 |
};
|
281 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
282 |
/**
|
283 |
* Clone actions
|
284 |
*/
|
@@ -383,6 +407,12 @@ var WPStaging = (function ($) {
|
|
383 |
$existingClones.children("img").remove();
|
384 |
|
385 |
cache.get(".wpstg-loader").hide();
|
|
|
|
|
|
|
|
|
|
|
|
|
386 |
},
|
387 |
"HTML"
|
388 |
);
|
@@ -427,10 +457,7 @@ var WPStaging = (function ($) {
|
|
427 |
|
428 |
$workFlow.removeClass("loading").html(response);
|
429 |
|
430 |
-
|
431 |
-
.removeClass("wpstg-current-step")
|
432 |
-
.next("li")
|
433 |
-
.addClass("wpstg-current-step");
|
434 |
},
|
435 |
"HTML"
|
436 |
);
|
@@ -546,6 +573,11 @@ var WPStaging = (function ($) {
|
|
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.")) {
|
@@ -602,10 +634,11 @@ var WPStaging = (function ($) {
|
|
602 |
// Styling of elements
|
603 |
$workFlow.removeClass("loading").html(response);
|
604 |
|
605 |
-
|
606 |
-
.
|
607 |
-
|
608 |
-
.
|
|
|
609 |
|
610 |
// Start cloning
|
611 |
that.startCloning();
|
@@ -761,6 +794,8 @@ var WPStaging = (function ($) {
|
|
761 |
},
|
762 |
"HTML"
|
763 |
);
|
|
|
|
|
764 |
};
|
765 |
|
766 |
/**
|
@@ -1241,6 +1276,10 @@ var WPStaging = (function ($) {
|
|
1241 |
if (response.job === 'SearchReplace') {
|
1242 |
cache.get("#wpstg-progress-db").css('background-color', '#3bc36b');
|
1243 |
cache.get("#wpstg-progress-db").html('1. Database');
|
|
|
|
|
|
|
|
|
1244 |
cache.get("#wpstg-progress-sr").width(response.percentage * 0.1 + '%').html(response.percentage + '%');
|
1245 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Step 2 of 4 Preparing Database Data...');
|
1246 |
}
|
@@ -1248,25 +1287,36 @@ var WPStaging = (function ($) {
|
|
1248 |
if (response.job === 'directories') {
|
1249 |
cache.get("#wpstg-progress-sr").css('background-color', '#3bc36b');
|
1250 |
cache.get("#wpstg-progress-sr").html('2. Data');
|
|
|
|
|
1251 |
cache.get("#wpstg-progress-dirs").width(response.percentage * 0.1 + '%').html(response.percentage + '%');
|
1252 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Step 3 of 4 Getting files...');
|
1253 |
}
|
1254 |
if (response.job === 'files') {
|
1255 |
cache.get("#wpstg-progress-dirs").css('background-color', '#3bc36b');
|
1256 |
cache.get("#wpstg-progress-dirs").html('3. Files');
|
|
|
|
|
1257 |
cache.get("#wpstg-progress-files").width(response.percentage * 0.6 + '%').html(response.percentage + '%');
|
1258 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Step 4 of 4 Copy files...');
|
1259 |
}
|
1260 |
if (response.job === 'finish') {
|
1261 |
cache.get("#wpstg-progress-files").css('background-color', '#3bc36b');
|
1262 |
cache.get("#wpstg-progress-files").html('4. Copy Files');
|
|
|
|
|
1263 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Cloning Process Finished');
|
1264 |
}
|
1265 |
}
|
1266 |
-
|
1267 |
-
|
1268 |
});
|
1269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1270 |
/**
|
1271 |
* Initiation
|
1272 |
* @type {Function}
|
@@ -1689,6 +1739,7 @@ jQuery(document).ready(function ($) {
|
|
1689 |
|
1690 |
var spinner = self.next();
|
1691 |
var email = $('.wpstg-report-email').val();
|
|
|
1692 |
var message = $('.wpstg-report-description').val();
|
1693 |
var syslog = $('.wpstg-report-syslog').is(':checked');
|
1694 |
var terms = $('.wpstg-report-terms').is(':checked');
|
@@ -1705,6 +1756,7 @@ jQuery(document).ready(function ($) {
|
|
1705 |
'action': 'wpstg_send_report',
|
1706 |
'nonce': wpstg.nonce,
|
1707 |
'wpstg_email': email,
|
|
|
1708 |
'wpstg_message': message,
|
1709 |
'wpstg_syslog': +syslog,
|
1710 |
'wpstg_terms': +terms
|
274 |
$('#wpstg_clone_dir').attr('placeholder', path);
|
275 |
$('#wpstg_clone_hostname').attr('placeholder', uri);
|
276 |
})
|
277 |
+
.on('input', '#wpstg_clone_hostname', function () {
|
278 |
+
if ($(this).val() === "" || validateTargetHost()) {
|
279 |
+
$('#wpstg_clone_hostname_error').remove();
|
280 |
+
return;
|
281 |
+
}
|
282 |
+
if (!validateTargetHost() && !$('#wpstg_clone_hostname_error').length) {
|
283 |
+
$('#wpstg-clone-directory tr:last-of-type').after('<tr><td> </td><td><p id="wpstg_clone_hostname_error" style="color: red;"> Invalid host name. Please provide it in a format like http://example.com</p></td></tr>');
|
284 |
+
}
|
285 |
+
})
|
286 |
;
|
287 |
|
288 |
cloneActions();
|
289 |
};
|
290 |
|
291 |
+
/* @returns {boolean} */
|
292 |
+
var validateTargetHost = function () {
|
293 |
+
var the_domain = $('#wpstg_clone_hostname').val();
|
294 |
+
|
295 |
+
if (the_domain === "") {
|
296 |
+
return true;
|
297 |
+
}
|
298 |
+
|
299 |
+
var reg = /^http(s)?:\/\/.*$/;
|
300 |
+
if (reg.test(the_domain) === false) {
|
301 |
+
return false;
|
302 |
+
}
|
303 |
+
return true;
|
304 |
+
};
|
305 |
+
|
306 |
/**
|
307 |
* Clone actions
|
308 |
*/
|
407 |
$existingClones.children("img").remove();
|
408 |
|
409 |
cache.get(".wpstg-loader").hide();
|
410 |
+
|
411 |
+
$('html, body').animate({
|
412 |
+
//This logic is meant to be a "scrollBottom"
|
413 |
+
scrollTop: $("#wpstg-remove-clone").offset().top - $(window).height() +
|
414 |
+
$("#wpstg-remove-clone").height() + 10
|
415 |
+
}, 1000);
|
416 |
},
|
417 |
"HTML"
|
418 |
);
|
457 |
|
458 |
$workFlow.removeClass("loading").html(response);
|
459 |
|
460 |
+
that.switchStep(2);
|
|
|
|
|
|
|
461 |
},
|
462 |
"HTML"
|
463 |
);
|
573 |
var $this = $(this);
|
574 |
var isScan = false;
|
575 |
|
576 |
+
if($('#wpstg_clone_hostname').length && !validateTargetHost()) {
|
577 |
+
$('#wpstg_clone_hostname').focus();
|
578 |
+
return false;
|
579 |
+
}
|
580 |
+
|
581 |
if ($this.data("action") === "wpstg_update") {
|
582 |
// Update Clone - confirmed
|
583 |
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.")) {
|
634 |
// Styling of elements
|
635 |
$workFlow.removeClass("loading").html(response);
|
636 |
|
637 |
+
if ($this.data("action") === "wpstg_scanning") {
|
638 |
+
that.switchStep(2);
|
639 |
+
} else if ($this.data("action") === "wpstg_cloning" || $this.data("action") === "wpstg_update") {
|
640 |
+
that.switchStep(3);
|
641 |
+
}
|
642 |
|
643 |
// Start cloning
|
644 |
that.startCloning();
|
794 |
},
|
795 |
"HTML"
|
796 |
);
|
797 |
+
|
798 |
+
that.switchStep(1);
|
799 |
};
|
800 |
|
801 |
/**
|
1276 |
if (response.job === 'SearchReplace') {
|
1277 |
cache.get("#wpstg-progress-db").css('background-color', '#3bc36b');
|
1278 |
cache.get("#wpstg-progress-db").html('1. Database');
|
1279 |
+
//Assumption: All previous steps are done.
|
1280 |
+
//This avoids bugs where some steps are skipped and the progress bar is incomplete as a result
|
1281 |
+
cache.get("#wpstg-progress-db").width('20%');
|
1282 |
+
|
1283 |
cache.get("#wpstg-progress-sr").width(response.percentage * 0.1 + '%').html(response.percentage + '%');
|
1284 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Step 2 of 4 Preparing Database Data...');
|
1285 |
}
|
1287 |
if (response.job === 'directories') {
|
1288 |
cache.get("#wpstg-progress-sr").css('background-color', '#3bc36b');
|
1289 |
cache.get("#wpstg-progress-sr").html('2. Data');
|
1290 |
+
cache.get("#wpstg-progress-sr").width('10%');
|
1291 |
+
|
1292 |
cache.get("#wpstg-progress-dirs").width(response.percentage * 0.1 + '%').html(response.percentage + '%');
|
1293 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Step 3 of 4 Getting files...');
|
1294 |
}
|
1295 |
if (response.job === 'files') {
|
1296 |
cache.get("#wpstg-progress-dirs").css('background-color', '#3bc36b');
|
1297 |
cache.get("#wpstg-progress-dirs").html('3. Files');
|
1298 |
+
cache.get("#wpstg-progress-dirs").width('10%');
|
1299 |
+
|
1300 |
cache.get("#wpstg-progress-files").width(response.percentage * 0.6 + '%').html(response.percentage + '%');
|
1301 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Step 4 of 4 Copy files...');
|
1302 |
}
|
1303 |
if (response.job === 'finish') {
|
1304 |
cache.get("#wpstg-progress-files").css('background-color', '#3bc36b');
|
1305 |
cache.get("#wpstg-progress-files").html('4. Copy Files');
|
1306 |
+
cache.get("#wpstg-progress-files").width('60%');
|
1307 |
+
|
1308 |
cache.get("#wpstg-processing-status").html(response.percentage.toFixed(0) + '%' + ' - Cloning Process Finished');
|
1309 |
}
|
1310 |
}
|
|
|
|
|
1311 |
});
|
1312 |
|
1313 |
+
that.switchStep = function (step) {
|
1314 |
+
cache.get(".wpstg-current-step")
|
1315 |
+
.removeClass("wpstg-current-step");
|
1316 |
+
cache.get(".wpstg-step" + step)
|
1317 |
+
.addClass("wpstg-current-step");
|
1318 |
+
}
|
1319 |
+
|
1320 |
/**
|
1321 |
* Initiation
|
1322 |
* @type {Function}
|
1739 |
|
1740 |
var spinner = self.next();
|
1741 |
var email = $('.wpstg-report-email').val();
|
1742 |
+
var hosting_provider = $('.wpstg-report-hosting-provider').val();
|
1743 |
var message = $('.wpstg-report-description').val();
|
1744 |
var syslog = $('.wpstg-report-syslog').is(':checked');
|
1745 |
var terms = $('.wpstg-report-terms').is(':checked');
|
1756 |
'action': 'wpstg_send_report',
|
1757 |
'nonce': wpstg.nonce,
|
1758 |
'wpstg_email': email,
|
1759 |
+
'wpstg_provider': hosting_provider,
|
1760 |
'wpstg_message': message,
|
1761 |
'wpstg_syslog': +syslog,
|
1762 |
'wpstg_terms': +terms
|
Backend/views/_main/report-issue.php
CHANGED
@@ -1,15 +1,18 @@
|
|
1 |
<div class="wpstg-report-issue-form">
|
2 |
<div class="wpstg-field">
|
3 |
-
<input placeholder="
|
4 |
</div>
|
5 |
<div class="wpstg-field">
|
6 |
-
<
|
|
|
|
|
|
|
7 |
</div>
|
8 |
<div class="wpstg-field wpstg-report-privacy-policy">
|
9 |
<label for="wpstg-report-syslog">
|
10 |
<input type="checkbox" class="wpstg-report-syslog" id="wpstg-report-syslog">
|
11 |
<?php echo sprintf(
|
12 |
-
__('Optional: Submit the <a href="%s" target="_blank">System Log</a
|
13 |
admin_url().'admin.php?page=wpstg-tools&tab=system_info'
|
14 |
); ?>
|
15 |
</label>
|
@@ -21,7 +24,7 @@
|
|
21 |
</label>
|
22 |
</div>
|
23 |
<div class="wpstg-field">
|
24 |
-
<div class="wpstg-buttons">
|
25 |
<button type="submit" id="wpstg-report-submit" class="wpstg-form-submit button-primary wpstg-button">
|
26 |
<?php _e( 'Submit', 'wp-staging' ); ?>
|
27 |
</button>
|
@@ -30,4 +33,4 @@
|
|
30 |
<div class="wpstg-clear"></div>
|
31 |
</div>
|
32 |
</div>
|
33 |
-
</div>
|
1 |
<div class="wpstg-report-issue-form">
|
2 |
<div class="wpstg-field">
|
3 |
+
<input placeholder="Your email address..." type="email" id="wpstg-report-email" class="wpstg-report-email">
|
4 |
</div>
|
5 |
<div class="wpstg-field">
|
6 |
+
<input placeholder="Your hosting provider...(optional)" type="text" id="wpstg-report-hosting-provider" class="wpstg-report-hosting-provider">
|
7 |
+
</div>
|
8 |
+
<div class="wpstg-field">
|
9 |
+
<textarea rows="3" id="wpstg-report-description" class="wpstg-report-description" placeholder="Describe your issue here! Optionally, include the login credentials to your WordPress admin so we can help you faster."></textarea>
|
10 |
</div>
|
11 |
<div class="wpstg-field wpstg-report-privacy-policy">
|
12 |
<label for="wpstg-report-syslog">
|
13 |
<input type="checkbox" class="wpstg-report-syslog" id="wpstg-report-syslog">
|
14 |
<?php echo sprintf(
|
15 |
+
__('Optional: Submit the <a href="%s" target="_blank">System Log</a> and your WordPress debug log. This helps us to resolve your technical issues.','wp-staging'),
|
16 |
admin_url().'admin.php?page=wpstg-tools&tab=system_info'
|
17 |
); ?>
|
18 |
</label>
|
24 |
</label>
|
25 |
</div>
|
26 |
<div class="wpstg-field">
|
27 |
+
<div class="wpstg-buttons">
|
28 |
<button type="submit" id="wpstg-report-submit" class="wpstg-form-submit button-primary wpstg-button">
|
29 |
<?php _e( 'Submit', 'wp-staging' ); ?>
|
30 |
</button>
|
33 |
<div class="wpstg-clear"></div>
|
34 |
</div>
|
35 |
</div>
|
36 |
+
</div>
|
Backend/views/clone/ajax/scan.php
CHANGED
@@ -112,9 +112,8 @@
|
|
112 |
</div>
|
113 |
</div>
|
114 |
|
115 |
-
<
|
116 |
-
|
117 |
-
</div>
|
118 |
|
119 |
<button type="button" class="wpstg-prev-step-link wpstg-link-btn wpstg-blue-primary wpstg-button">
|
120 |
<?php _e( "Back", "wp-staging" ) ?>
|
112 |
</div>
|
113 |
</div>
|
114 |
|
115 |
+
<strong>Important:</strong><a href="#" id="wpstg-check-space"><?php _e( 'Check required disk space', 'wp-staging' ); ?></a>
|
116 |
+
<p></p>
|
|
|
117 |
|
118 |
<button type="button" class="wpstg-prev-step-link wpstg-link-btn wpstg-blue-primary wpstg-button">
|
119 |
<?php _e( "Back", "wp-staging" ) ?>
|
Backend/views/clone/ajax/single-overview.php
CHANGED
@@ -41,7 +41,13 @@
|
|
41 |
$cloneDir = !empty( $data['path'] ) ? __( "Directory: <span class='wpstg-bold'>" . $data['path'], "wp-staging" ) . '</span> ' : 'Directory: ';
|
42 |
$url = !empty( $data['url'] ) ? __(sprintf('URL: <a href="%s" target="_blank"><span class="wpstg-bold">%1$s</span></a>', $data['url']), "wp-staging") : 'URL: ';
|
43 |
$datetime = !empty( $data['datetime'] ) ? __( "Updated: <span>" . date( "D, d M Y H:i:s T", $data['datetime'] ), "wp-staging" ) . '</span> ' : ' ';
|
44 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
echo $dbname;
|
47 |
echo '</br>';
|
41 |
$cloneDir = !empty( $data['path'] ) ? __( "Directory: <span class='wpstg-bold'>" . $data['path'], "wp-staging" ) . '</span> ' : 'Directory: ';
|
42 |
$url = !empty( $data['url'] ) ? __(sprintf('URL: <a href="%s" target="_blank"><span class="wpstg-bold">%1$s</span></a>', $data['url']), "wp-staging") : 'URL: ';
|
43 |
$datetime = !empty( $data['datetime'] ) ? __( "Updated: <span>" . date( "D, d M Y H:i:s T", $data['datetime'] ), "wp-staging" ) . '</span> ' : ' ';
|
44 |
+
$statusTooltip = "This clone is incomplete and does not work. Clone or update it again! \n\n".
|
45 |
+
"Important: Keep the browser open until the cloning is finished. \n".
|
46 |
+
"It will not proceed if your browser is not open.\n\n".
|
47 |
+
"If you have an unstable internet connection and cloning breaks due to that, clone again only the folders wp-admin, wp-includes, and all database tables.\n\n".
|
48 |
+
"That will not take much time. Then, you can proceed with the wp-content folder that usually needs the most disk space. ".
|
49 |
+
"If it interrupts again, at least it will not break the existing staging site again, and you can repeat and resume the last operation.";
|
50 |
+
$status = !empty( $data['status'] ) && $data['status'] !== 'finished' ? "Status: <span class='wpstg-bold' style='color:#ffc2c2;' title='$statusTooltip'>" . $data['status'] . "</span>" : ' ';
|
51 |
|
52 |
echo $dbname;
|
53 |
echo '</br>';
|
Backend/views/clone/single-site/index.php
CHANGED
@@ -1,13 +1,13 @@
|
|
1 |
<ul id="wpstg-steps">
|
2 |
-
<li class="wpstg-current-step">
|
3 |
<span class="wpstg-step-num">1</span>
|
4 |
<?php echo __( "Overview", "wp-staging" ) ?>
|
5 |
</li>
|
6 |
-
<li>
|
7 |
<span class="wpstg-step-num">2</span>
|
8 |
<?php echo __( "Scanning", "wp-staging" ) ?>
|
9 |
</li>
|
10 |
-
<li>
|
11 |
<span class="wpstg-step-num">3</span>
|
12 |
<?php echo __( "Cloning", "wp-staging" ) ?>
|
13 |
</li>
|
@@ -31,4 +31,4 @@
|
|
31 |
<img src="<?php echo WPSTG_PLUGIN_URL . 'Backend/public/img/wpstaging-banner200x400-tryout.gif'; ?>">
|
32 |
</a>
|
33 |
</div>
|
34 |
-
<?php } ?>
|
1 |
<ul id="wpstg-steps">
|
2 |
+
<li class="wpstg-current-step wpstg-step1">
|
3 |
<span class="wpstg-step-num">1</span>
|
4 |
<?php echo __( "Overview", "wp-staging" ) ?>
|
5 |
</li>
|
6 |
+
<li class="wpstg-step2">
|
7 |
<span class="wpstg-step-num">2</span>
|
8 |
<?php echo __( "Scanning", "wp-staging" ) ?>
|
9 |
</li>
|
10 |
+
<li class="wpstg-step3">
|
11 |
<span class="wpstg-step-num">3</span>
|
12 |
<?php echo __( "Cloning", "wp-staging" ) ?>
|
13 |
</li>
|
31 |
<img src="<?php echo WPSTG_PLUGIN_URL . 'Backend/public/img/wpstaging-banner200x400-tryout.gif'; ?>">
|
32 |
</a>
|
33 |
</div>
|
34 |
+
<?php } ?>
|
Command/Database/Export/ExportCommand.php
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; return types & type-hints
|
5 |
+
|
6 |
+
namespace WPStaging\Command\Database\Export;
|
7 |
+
|
8 |
+
use Exception;
|
9 |
+
use WPStaging\Manager\Database\Mysqldump\Mysqldump;
|
10 |
+
use Psr\Log\LoggerInterface;
|
11 |
+
use WPStaging\Manager\Database\TableManager;
|
12 |
+
use WPStaging\Service\Command\CommandInterface;
|
13 |
+
|
14 |
+
class ExportCommand implements CommandInterface
|
15 |
+
{
|
16 |
+
const FORMAT_GZIP = Mysqldump::GZIP;
|
17 |
+
const FORMAT_BZIP2 = Mysqldump::BZIP2;
|
18 |
+
const FORMAT_SQL = Mysqldump::NONE;
|
19 |
+
|
20 |
+
/** @var ExportDto */
|
21 |
+
private $dto;
|
22 |
+
|
23 |
+
/** @var TableManager */
|
24 |
+
private $tableManager;
|
25 |
+
|
26 |
+
/** @var LoggerInterface */
|
27 |
+
private $logger;
|
28 |
+
|
29 |
+
public function __construct(ExportDto $dto, TableManager $tableManager = null, LoggerInterface $logger = null)
|
30 |
+
{
|
31 |
+
$this->dto = $dto;
|
32 |
+
$this->logger = $logger;
|
33 |
+
$this->tableManager = $tableManager;
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @inheritDoc
|
38 |
+
* @throws Exception
|
39 |
+
*/
|
40 |
+
public function execute()
|
41 |
+
{
|
42 |
+
$this->generateSqlFile();
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @throws Exception
|
47 |
+
*/
|
48 |
+
protected function generateSqlFile()
|
49 |
+
{
|
50 |
+
$dumper = new Mysqldump(
|
51 |
+
sprintf('mysql:host=%s;port=%d;dbname=%s', $this->dto->getHost(), $this->dto->getPort(), $this->dto->getName()),
|
52 |
+
$this->dto->getUsername(),
|
53 |
+
$this->dto->getPassword(),
|
54 |
+
[
|
55 |
+
'compress' => $this->dto->getFormat(),
|
56 |
+
'include-tables' => $this->getIncludeTables(),
|
57 |
+
'version' => $this->dto->getVersion(),
|
58 |
+
]
|
59 |
+
);
|
60 |
+
|
61 |
+
try {
|
62 |
+
$dumper->start($this->dto->getFullPath());
|
63 |
+
return $this->dto->getFullPath();
|
64 |
+
}
|
65 |
+
catch (Exception $e) {
|
66 |
+
$this->logger->alert($e->getMessage());
|
67 |
+
throw new ExportException(sprintf(
|
68 |
+
'Failed to export database. Database Name: %s | Prefix: %s | File Path: %s | %s',
|
69 |
+
$this->dto->getUsername() .':' . $this->dto->getPassword() . '@' . $this->dto->getHost() . ':' . $this->dto->getPort() . ' - ' . $this->dto->getName(),
|
70 |
+
$this->dto->getPrefix(),
|
71 |
+
$this->dto->getFullPath(),
|
72 |
+
$e->getMessage()
|
73 |
+
));
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
protected function getIncludeTables()
|
78 |
+
{
|
79 |
+
$tables = $this->tableManager->findStartsWith($this->dto->getPrefix());
|
80 |
+
$data = [];
|
81 |
+
foreach ($tables as $table) {
|
82 |
+
$data[] = $table->getName();
|
83 |
+
}
|
84 |
+
return $data;
|
85 |
+
}
|
86 |
+
}
|
Command/Database/Export/ExportDto.php
ADDED
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; return types & type-hints
|
5 |
+
|
6 |
+
namespace WPStaging\Command\Database\Export;
|
7 |
+
|
8 |
+
use DateTime;
|
9 |
+
use Exception;
|
10 |
+
use WPStaging\Service\Adapter\Database;
|
11 |
+
use WPStaging\Service\Traits\HydrateTrait;
|
12 |
+
|
13 |
+
class ExportDto
|
14 |
+
{
|
15 |
+
use HydrateTrait;
|
16 |
+
|
17 |
+
const DEFAULT_FORMAT = ExportCommand::FORMAT_GZIP;
|
18 |
+
const DEFAULT_PORT = 3306;
|
19 |
+
|
20 |
+
/** @var string */
|
21 |
+
private $host;
|
22 |
+
|
23 |
+
/** @var int */
|
24 |
+
private $port;
|
25 |
+
|
26 |
+
/** @var string */
|
27 |
+
private $name;
|
28 |
+
|
29 |
+
/** @var string */
|
30 |
+
private $username;
|
31 |
+
|
32 |
+
/** @var string */
|
33 |
+
private $password;
|
34 |
+
|
35 |
+
/** @var string */
|
36 |
+
private $prefix;
|
37 |
+
|
38 |
+
/** @var string */
|
39 |
+
private $format;
|
40 |
+
|
41 |
+
/** @var string|null */
|
42 |
+
private $directory;
|
43 |
+
|
44 |
+
/** @var string|null */
|
45 |
+
private $fullPath;
|
46 |
+
|
47 |
+
/** @var string */
|
48 |
+
private $version;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* @return string
|
52 |
+
*/
|
53 |
+
public function getHost()
|
54 |
+
{
|
55 |
+
if (!$this->host) {
|
56 |
+
return DB_HOST;
|
57 |
+
}
|
58 |
+
return $this->host;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* @param string $host
|
63 |
+
*/
|
64 |
+
public function setHost($host)
|
65 |
+
{
|
66 |
+
$this->host = $host;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* @return int
|
71 |
+
*/
|
72 |
+
public function getPort()
|
73 |
+
{
|
74 |
+
if ($this->port) {
|
75 |
+
return $this->port;
|
76 |
+
}
|
77 |
+
|
78 |
+
$parts = explode(':', DB_HOST);
|
79 |
+
if (isset($parts[1]) && 0 < (int) $parts[1]) {
|
80 |
+
return (int) $parts[1];
|
81 |
+
}
|
82 |
+
|
83 |
+
return self::DEFAULT_PORT;
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* @param int $port
|
88 |
+
*/
|
89 |
+
public function setPort($port)
|
90 |
+
{
|
91 |
+
$this->port = (int) $port;
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* @return string
|
96 |
+
*/
|
97 |
+
public function getName()
|
98 |
+
{
|
99 |
+
if (!$this->name) {
|
100 |
+
return DB_NAME;
|
101 |
+
}
|
102 |
+
return $this->name;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* @param string $name
|
107 |
+
*/
|
108 |
+
public function setName($name)
|
109 |
+
{
|
110 |
+
$this->name = $name;
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* @return string
|
115 |
+
*/
|
116 |
+
public function getUsername()
|
117 |
+
{
|
118 |
+
if (!$this->username) {
|
119 |
+
return DB_USER;
|
120 |
+
}
|
121 |
+
return $this->username;
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* @param string $username
|
126 |
+
*/
|
127 |
+
public function setUsername($username)
|
128 |
+
{
|
129 |
+
$this->username = $username;
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* @return string
|
134 |
+
*/
|
135 |
+
public function getPassword()
|
136 |
+
{
|
137 |
+
if (!$this->password) {
|
138 |
+
return DB_PASSWORD;
|
139 |
+
}
|
140 |
+
return $this->password;
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* @param string $password
|
145 |
+
*/
|
146 |
+
public function setPassword($password)
|
147 |
+
{
|
148 |
+
$this->password = $password;
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* @return string
|
153 |
+
*/
|
154 |
+
public function getPrefix()
|
155 |
+
{
|
156 |
+
if (!$this->prefix) {
|
157 |
+
return (new Database)->getPrefix();
|
158 |
+
}
|
159 |
+
return $this->prefix;
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* @param string $prefix
|
164 |
+
*/
|
165 |
+
public function setPrefix($prefix)
|
166 |
+
{
|
167 |
+
$this->prefix = $prefix;
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* @return string
|
172 |
+
*/
|
173 |
+
public function getFormat()
|
174 |
+
{
|
175 |
+
return $this->format ?: self::DEFAULT_FORMAT;
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* @param string $format
|
180 |
+
*/
|
181 |
+
public function setFormat($format)
|
182 |
+
{
|
183 |
+
$this->format = $format;
|
184 |
+
}
|
185 |
+
|
186 |
+
public function provideFileFormat()
|
187 |
+
{
|
188 |
+
switch($this->getFormat()) {
|
189 |
+
case ExportCommand::FORMAT_GZIP:
|
190 |
+
return 'gz';
|
191 |
+
case ExportCommand::FORMAT_SQL:
|
192 |
+
return 'sql';
|
193 |
+
case ExportCommand::FORMAT_BZIP2:
|
194 |
+
return 'bz2';
|
195 |
+
}
|
196 |
+
|
197 |
+
return $this->format;
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* @return string|null
|
202 |
+
*/
|
203 |
+
public function getDirectory()
|
204 |
+
{
|
205 |
+
return $this->directory;
|
206 |
+
}
|
207 |
+
|
208 |
+
/**
|
209 |
+
* @param string|null $directory
|
210 |
+
*/
|
211 |
+
public function setDirectory($directory)
|
212 |
+
{
|
213 |
+
$this->directory = $directory;
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* @return string
|
218 |
+
* @throws Exception
|
219 |
+
*/
|
220 |
+
public function getFullPath()
|
221 |
+
{
|
222 |
+
if ($this->fullPath) {
|
223 |
+
return $this->fullPath;
|
224 |
+
}
|
225 |
+
|
226 |
+
$fileName = sprintf(
|
227 |
+
'%s_%s_%s.%s',
|
228 |
+
rtrim($this->prefix, '_-'),
|
229 |
+
(new DateTime)->format('Y-m-d'),
|
230 |
+
md5(mt_rand()),
|
231 |
+
$this->provideFileFormat()
|
232 |
+
);
|
233 |
+
|
234 |
+
$this->setFullPath($this->getDirectory() . $fileName);
|
235 |
+
return $this->fullPath;
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* @param string|null $fullPath
|
240 |
+
*/
|
241 |
+
public function setFullPath($fullPath)
|
242 |
+
{
|
243 |
+
$this->fullPath = $fullPath;
|
244 |
+
}
|
245 |
+
|
246 |
+
/**
|
247 |
+
* @return string
|
248 |
+
*/
|
249 |
+
public function getVersion()
|
250 |
+
{
|
251 |
+
return $this->version;
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
* @param string $version
|
256 |
+
*/
|
257 |
+
public function setVersion($version)
|
258 |
+
{
|
259 |
+
$this->version = $version;
|
260 |
+
}
|
261 |
+
}
|
Command/Database/Export/ExportException.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; return types & type-hints
|
5 |
+
|
6 |
+
namespace WPStaging\Command\Database\Export;
|
7 |
+
|
8 |
+
use RuntimeException;
|
9 |
+
|
10 |
+
class ExportException extends RuntimeException
|
11 |
+
{
|
12 |
+
|
13 |
+
}
|
Command/Database/Export/ExportHandler.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; return types & type-hints
|
5 |
+
|
6 |
+
namespace WPStaging\Command\Database\Export;
|
7 |
+
|
8 |
+
use Exception;
|
9 |
+
use Psr\Log\LoggerInterface;
|
10 |
+
use WPStaging\Manager\Database\TableManager;
|
11 |
+
use WPStaging\Manager\FileSystem\DirectoryManager;
|
12 |
+
use WPStaging\Plugin;
|
13 |
+
|
14 |
+
// TODO Check PDO extension installation: \WPStaging\Component\Snapshot\AjaxExport:38
|
15 |
+
class ExportHandler
|
16 |
+
{
|
17 |
+
const EXPORT_DIRNAME = 'snapshots/export';
|
18 |
+
|
19 |
+
/** @var Plugin */
|
20 |
+
private $plugin;
|
21 |
+
|
22 |
+
/** @var DirectoryManager */
|
23 |
+
private $directoryManager;
|
24 |
+
|
25 |
+
/** @var LoggerInterface */
|
26 |
+
private $logger;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @param Plugin $plugin
|
30 |
+
* @param DirectoryManager $directoryManager
|
31 |
+
* @param LoggerInterface $logger
|
32 |
+
*/
|
33 |
+
public function __construct(Plugin $plugin, DirectoryManager $directoryManager, LoggerInterface $logger)
|
34 |
+
{
|
35 |
+
$this->plugin = $plugin;
|
36 |
+
$this->directoryManager = $directoryManager;
|
37 |
+
$this->logger = $logger;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* @param string $prefix
|
42 |
+
*
|
43 |
+
* @return string
|
44 |
+
* @throws Exception
|
45 |
+
*/
|
46 |
+
public function handle($prefix)
|
47 |
+
{
|
48 |
+
$dto = (new ExportDto)->hydrate([
|
49 |
+
'prefix' => $prefix,
|
50 |
+
'directory' => $this->generatePath(),
|
51 |
+
'format' => $this->provideFormat(),
|
52 |
+
'version' => $this->plugin->getVersion(),
|
53 |
+
]);
|
54 |
+
|
55 |
+
$command = new ExportCommand($dto, new TableManager, $this->logger);
|
56 |
+
$command->execute();
|
57 |
+
return $dto->getFullPath();
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @return string
|
62 |
+
*/
|
63 |
+
public function generatePath()
|
64 |
+
{
|
65 |
+
$dirname = sprintf(
|
66 |
+
'%s/%s/',
|
67 |
+
$this->plugin->getDomain(),
|
68 |
+
self::EXPORT_DIRNAME
|
69 |
+
);
|
70 |
+
return $this->directoryManager->provideCustomUploadsDirectory($dirname);
|
71 |
+
}
|
72 |
+
|
73 |
+
private function provideFormat()
|
74 |
+
{
|
75 |
+
if (!function_exists('gzwrite')) {
|
76 |
+
return ExportCommand::FORMAT_SQL;
|
77 |
+
}
|
78 |
+
return ExportCommand::FORMAT_GZIP;
|
79 |
+
}
|
80 |
+
}
|
Command/Database/Snapshot/AbstractSnapshotCommand.php
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; type-hints & return types
|
5 |
+
// TODO PHP7.1; constant visibility
|
6 |
+
|
7 |
+
namespace WPStaging\Command\Database\Snapshot;
|
8 |
+
|
9 |
+
use WPStaging\Entity\Snapshot;
|
10 |
+
use WPStaging\Manager\Database\TableDto;
|
11 |
+
use WPStaging\Manager\Database\TableManager;
|
12 |
+
use WPStaging\Repository\SnapshotRepository;
|
13 |
+
use WPStaging\Service\Adapter\Database;
|
14 |
+
use WPStaging\Service\Collection\Collection;
|
15 |
+
use WPStaging\Service\Collection\OptionCollection;
|
16 |
+
use WPStaging\Service\Command\CommandInterface;
|
17 |
+
|
18 |
+
abstract class AbstractSnapshotCommand implements CommandInterface
|
19 |
+
{
|
20 |
+
|
21 |
+
/** @var Database */
|
22 |
+
protected $database;
|
23 |
+
|
24 |
+
/** @var SnapshotRepository */
|
25 |
+
protected $repository;
|
26 |
+
|
27 |
+
/** @var SnapshotDto */
|
28 |
+
protected $dto;
|
29 |
+
|
30 |
+
/** @var Snapshot[]|OptionCollection */
|
31 |
+
protected $snapshots;
|
32 |
+
|
33 |
+
abstract protected function saveSnapshots();
|
34 |
+
|
35 |
+
public function __construct(Database $database, SnapshotRepository $repository, SnapshotDto $dto = null)
|
36 |
+
{
|
37 |
+
$this->database = $database;
|
38 |
+
$this->repository = $repository;
|
39 |
+
$this->setDto($dto);
|
40 |
+
|
41 |
+
$this->snapshots = $this->repository->findAll()? : new OptionCollection(Snapshot::class);
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* @param SnapshotDto $dto
|
46 |
+
*/
|
47 |
+
public function setDto(SnapshotDto $dto = null)
|
48 |
+
{
|
49 |
+
if (!$dto) {
|
50 |
+
return;
|
51 |
+
}
|
52 |
+
|
53 |
+
$this->dto = $dto;
|
54 |
+
|
55 |
+
if (!$this->dto->getSourcePrefix()) {
|
56 |
+
$this->dto->setSourcePrefix($this->database->getPrefix());
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @throws SnapshotCommandException
|
62 |
+
*/
|
63 |
+
protected function validateSnapshot()
|
64 |
+
{
|
65 |
+
if ($this->database->getPrefix() === $this->dto->getTargetPrefix()) {
|
66 |
+
throw new SnapshotCommandException('You are trying to process production tables!');
|
67 |
+
}
|
68 |
+
|
69 |
+
if ($this->dto->getSourcePrefix() === $this->dto->getTargetPrefix()) {
|
70 |
+
throw new SnapshotCommandException('You are trying to process same tables!');
|
71 |
+
}
|
72 |
+
}
|
73 |
+
}
|
Command/Database/Snapshot/CreateSnapshotCommand.php
ADDED
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Command\Database\Snapshot;
|
4 |
+
|
5 |
+
use DateTime;
|
6 |
+
use WPStaging\Entity\Snapshot;
|
7 |
+
use WPStaging\Manager\Database\TableDto;
|
8 |
+
use WPStaging\Manager\Database\TableManager;
|
9 |
+
|
10 |
+
class CreateSnapshotCommand extends AbstractSnapshotCommand
|
11 |
+
{
|
12 |
+
|
13 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
14 |
+
public function execute()
|
15 |
+
{
|
16 |
+
$this->validateSnapshot();
|
17 |
+
|
18 |
+
if (null === $this->dto->getStep()) {
|
19 |
+
$this->executeAll();
|
20 |
+
return;
|
21 |
+
}
|
22 |
+
|
23 |
+
$this->executeStep();
|
24 |
+
}
|
25 |
+
|
26 |
+
protected function executeAll()
|
27 |
+
{
|
28 |
+
foreach($this->findTables() as $table) {
|
29 |
+
$this->backupTable($table);
|
30 |
+
}
|
31 |
+
|
32 |
+
$this->saveSnapshots();
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @noinspection PhpUnhandledExceptionInspection
|
37 |
+
*/
|
38 |
+
protected function executeStep()
|
39 |
+
{
|
40 |
+
/** @var array $tables */
|
41 |
+
$tables = $this->findTables();
|
42 |
+
|
43 |
+
if (!isset($tables[$this->dto->getStep()])) {
|
44 |
+
throw new SnapshotCommandException('failed to get tables with prefix: ' . $this->dto->getSourcePrefix());
|
45 |
+
}
|
46 |
+
|
47 |
+
$this->backupTable($tables[$this->dto->getStep()]);
|
48 |
+
|
49 |
+
// This was the last step, save the snapshot
|
50 |
+
if (count($tables) === $this->dto->getStep() + 1) {
|
51 |
+
$this->saveSnapshots();
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* @return TableDto[]|null
|
57 |
+
*/
|
58 |
+
protected function findTables()
|
59 |
+
{
|
60 |
+
$tables = (new TableManager)->findStartsWith($this->dto->getSourcePrefix());
|
61 |
+
if (!$tables) {
|
62 |
+
return null;
|
63 |
+
}
|
64 |
+
return $tables->toArray();
|
65 |
+
}
|
66 |
+
|
67 |
+
protected function backupTable(TableDto $tableDto)
|
68 |
+
{
|
69 |
+
$newTableName = $this->dto->getTargetPrefix() . str_replace($this->dto->getSourcePrefix(), null, $tableDto->getName());
|
70 |
+
$this->database->exec('OPTIMIZE TABLE '. $tableDto->getName());
|
71 |
+
$this->database->exec('DROP TABLE IF EXISTS '. $newTableName);
|
72 |
+
$this->database->exec('CREATE TABLE ' . $newTableName . ' LIKE ' . $tableDto->getName());
|
73 |
+
$this->database->exec('INSERT INTO ' . $newTableName . ' SELECT * FROM ' . $tableDto->getName());
|
74 |
+
$this->database->exec('OPTIMIZE TABLE ' . $newTableName);
|
75 |
+
}
|
76 |
+
|
77 |
+
protected function saveSnapshots()
|
78 |
+
{
|
79 |
+
if (!$this->dto->isSaveRecords()) {
|
80 |
+
return;
|
81 |
+
}
|
82 |
+
|
83 |
+
/** @var Snapshot $snapshot */
|
84 |
+
$snapshot = $this->snapshots->findById($this->dto->getTargetPrefix());
|
85 |
+
|
86 |
+
if ($snapshot) {
|
87 |
+
$snapshot->setUpdatedAt(new DateTime);
|
88 |
+
$this->repository->save($this->snapshots);
|
89 |
+
return;
|
90 |
+
}
|
91 |
+
|
92 |
+
$snapshot = new Snapshot;
|
93 |
+
$snapshot->setId($this->dto->getTargetPrefix());
|
94 |
+
$snapshot->setName($this->dto->getName());
|
95 |
+
$snapshot->setNotes($this->dto->getNotes());
|
96 |
+
$snapshot->setCreatedAt(new DateTime);
|
97 |
+
|
98 |
+
$this->snapshots->attach($snapshot);
|
99 |
+
$this->repository->save($this->snapshots);
|
100 |
+
}
|
101 |
+
}
|
Command/Database/Snapshot/DeleteSnapshotCommand.php
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Command\Database\Snapshot;
|
4 |
+
|
5 |
+
use WPStaging\Manager\Database\TableManager;
|
6 |
+
use WPStaging\Manager\SnapshotManager;
|
7 |
+
|
8 |
+
class DeleteSnapshotCommand extends AbstractSnapshotCommand
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* @param bool force deletes snapshot from listing even if there are no tables in db
|
12 |
+
* @throws SnapshotCommandException
|
13 |
+
*/
|
14 |
+
public function execute()
|
15 |
+
{
|
16 |
+
$this->validateSnapshot();
|
17 |
+
|
18 |
+
$tables = (new TableManager)->findStartsWith($this->dto->getTargetPrefix());
|
19 |
+
|
20 |
+
if (!$tables && $tables->count() < 1) {
|
21 |
+
throw new SnapshotCommandException('DeleteSnapshot tables do not exist: ', $this->dto->getTargetPrefix());
|
22 |
+
}
|
23 |
+
|
24 |
+
$this->database->exec('SET FOREIGN_KEY_CHECKS = 0');
|
25 |
+
foreach($tables as $table) {
|
26 |
+
$this->database->exec('DROP TABLE IF EXISTS ' . $table->getName());
|
27 |
+
}
|
28 |
+
$this->database->exec('SET FOREIGN_KEY_CHECKS = 1');
|
29 |
+
|
30 |
+
$this->saveSnapshots();
|
31 |
+
}
|
32 |
+
|
33 |
+
protected function saveSnapshots()
|
34 |
+
{
|
35 |
+
(new SnapshotManager)->deleteByPrefix($this->dto->getTargetPrefix());
|
36 |
+
}
|
37 |
+
|
38 |
+
/** @noinspection PhpUnhandledExceptionInspection */
|
39 |
+
protected function validateSnapshot()
|
40 |
+
{
|
41 |
+
parent::validateSnapshot();
|
42 |
+
if (!$this->snapshots->doesIncludeId($this->dto->getTargetPrefix())) {
|
43 |
+
throw new SnapshotCommandException(
|
44 |
+
'DeleteSnapshot prefix does not exist: ' . $this->dto->getTargetPrefix()
|
45 |
+
);
|
46 |
+
}
|
47 |
+
}
|
48 |
+
}
|
Command/Database/Snapshot/SnapshotCommandException.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Command\Database\Snapshot;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
|
7 |
+
class SnapshotCommandException extends Exception
|
8 |
+
{}
|
Command/Database/Snapshot/SnapshotDto.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_type=1);
|
4 |
+
// TODO PHP7.x; type hints & return types
|
5 |
+
|
6 |
+
namespace WPStaging\Command\Database\Snapshot;
|
7 |
+
|
8 |
+
class SnapshotDto
|
9 |
+
{
|
10 |
+
const SNAPSHOT_DEFAULT_NAME = 'snapshot';
|
11 |
+
|
12 |
+
/** @var string */
|
13 |
+
private $name;
|
14 |
+
|
15 |
+
/** @var string|null */
|
16 |
+
private $notes;
|
17 |
+
|
18 |
+
/** @var string */
|
19 |
+
private $targetPrefix;
|
20 |
+
|
21 |
+
/** @var string|null */
|
22 |
+
private $sourcePrefix;
|
23 |
+
|
24 |
+
/** @var int|null */
|
25 |
+
private $step;
|
26 |
+
|
27 |
+
/** @var bool */
|
28 |
+
private $isSaveRecords = true;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @return string
|
32 |
+
*/
|
33 |
+
public function getName()
|
34 |
+
{
|
35 |
+
return $this->name ?: self::SNAPSHOT_DEFAULT_NAME;
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @param string|null $name
|
40 |
+
*/
|
41 |
+
public function setName($name)
|
42 |
+
{
|
43 |
+
$this->name = $name;
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* @return string|null
|
48 |
+
*/
|
49 |
+
public function getNotes()
|
50 |
+
{
|
51 |
+
return $this->notes ?: null;
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* @param string|null $notes
|
56 |
+
*/
|
57 |
+
public function setNotes($notes)
|
58 |
+
{
|
59 |
+
$this->notes = $notes;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @return string
|
64 |
+
*/
|
65 |
+
public function getTargetPrefix()
|
66 |
+
{
|
67 |
+
return $this->targetPrefix;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* @param string $targetPrefix
|
72 |
+
*/
|
73 |
+
public function setTargetPrefix($targetPrefix)
|
74 |
+
{
|
75 |
+
$this->targetPrefix = $targetPrefix;
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* @return string|null
|
80 |
+
*/
|
81 |
+
public function getSourcePrefix()
|
82 |
+
{
|
83 |
+
return $this->sourcePrefix;
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* @param string|null $sourcePrefix
|
88 |
+
*/
|
89 |
+
public function setSourcePrefix($sourcePrefix)
|
90 |
+
{
|
91 |
+
$this->sourcePrefix = $sourcePrefix;
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* @return int|null
|
96 |
+
*/
|
97 |
+
public function getStep()
|
98 |
+
{
|
99 |
+
return $this->step;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* @param int|null $step
|
104 |
+
*/
|
105 |
+
public function setStep($step)
|
106 |
+
{
|
107 |
+
$this->step = $step;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* @return bool
|
112 |
+
*/
|
113 |
+
public function isSaveRecords()
|
114 |
+
{
|
115 |
+
return $this->isSaveRecords;
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* @param bool $isSaveRecords
|
120 |
+
*/
|
121 |
+
public function setIsSaveRecords($isSaveRecords)
|
122 |
+
{
|
123 |
+
$this->isSaveRecords = (bool) $isSaveRecords;
|
124 |
+
}
|
125 |
+
}
|
126 |
+
|
Command/Database/Snapshot/SnapshotHandler.php
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Command\Database\Snapshot;
|
4 |
+
|
5 |
+
use WPStaging\Service\Command\CommandInterface;
|
6 |
+
use WPStaging\Service\Command\HandlerInterface;
|
7 |
+
use SplObjectStorage;
|
8 |
+
|
9 |
+
class SnapshotHandler implements HandlerInterface
|
10 |
+
{
|
11 |
+
const PREFIX_AUTOMATIC = 'wpsa';
|
12 |
+
const PREFIX_MANUAL = 'wpsm';
|
13 |
+
|
14 |
+
/** @var SplObjectStorage */
|
15 |
+
private $commands;
|
16 |
+
|
17 |
+
/** @var SnapshotDto */
|
18 |
+
private $dto;
|
19 |
+
|
20 |
+
public function __construct(SnapshotDto $dto)
|
21 |
+
{
|
22 |
+
$this->dto = $dto;
|
23 |
+
$this->commands = new SplObjectStorage;
|
24 |
+
}
|
25 |
+
|
26 |
+
public function addCommand(CommandInterface $command)
|
27 |
+
{
|
28 |
+
/** @var AbstractSnapshotCommand $command */
|
29 |
+
if ($this->commands->contains($command)) {
|
30 |
+
return;
|
31 |
+
}
|
32 |
+
|
33 |
+
$command->setDto($this->dto);
|
34 |
+
|
35 |
+
$this->commands->attach($command);
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @param string|null $action
|
40 |
+
*/
|
41 |
+
public function handle($action = null)
|
42 |
+
{
|
43 |
+
/** @var CommandInterface $command */
|
44 |
+
foreach($this->commands as $command) {
|
45 |
+
$command->execute();
|
46 |
+
}
|
47 |
+
}
|
48 |
+
}
|
Command/Database/Snapshot/UpdateSnapshotCommand.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Command\Database\Snapshot;
|
4 |
+
|
5 |
+
use DateTime;
|
6 |
+
use WPStaging\Entity\Snapshot;
|
7 |
+
use WPStaging\Manager\Database\TableManager;
|
8 |
+
|
9 |
+
class UpdateSnapshotCommand extends AbstractSnapshotCommand
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* @noinspection PhpUnhandledExceptionInspection
|
13 |
+
* @noinspection DuplicatedCode
|
14 |
+
*/
|
15 |
+
public function execute()
|
16 |
+
{
|
17 |
+
$this->validateSnapshot();
|
18 |
+
|
19 |
+
$tables = (new TableManager)->findStartsWith();
|
20 |
+
if (!$tables) {
|
21 |
+
throw new SnapshotCommandException('UpdateSnapshot failed to get tables');
|
22 |
+
}
|
23 |
+
|
24 |
+
$this->database->exec('SET FOREIGN_KEY_CHECKS = 0');
|
25 |
+
foreach($tables as $table) {
|
26 |
+
$newTableName = $this->dto->getTargetPrefix() . $table->getName();
|
27 |
+
// Why this way? Because of schema changes, do not go shortcut with UPDATE query!
|
28 |
+
$this->database->exec('DROP TABLE IF EXISTS ' . $newTableName);
|
29 |
+
$this->database->exec('OPTIMIZE TABLE '. $table->getName());
|
30 |
+
$this->database->exec('CREATE TABLE ' . $newTableName . ' LIKE ' . $table->getName());
|
31 |
+
$this->database->exec('INSERT INTO ' . $newTableName . ' SELECT * FROM ' . $table->getName());
|
32 |
+
}
|
33 |
+
$this->database->exec('SET FOREIGN_KEY_CHECKS = 1');
|
34 |
+
|
35 |
+
$this->saveSnapshots();
|
36 |
+
}
|
37 |
+
|
38 |
+
protected function saveSnapshots()
|
39 |
+
{
|
40 |
+
/** @var Snapshot $snapshot */
|
41 |
+
$snapshot = $this->snapshots->findById($this->dto->getTargetPrefix());
|
42 |
+
$snapshot->setUpdatedAt(new DateTime);
|
43 |
+
$this->repository->save($this->snapshots);
|
44 |
+
}
|
45 |
+
|
46 |
+
protected function validateSnapshot()
|
47 |
+
{
|
48 |
+
parent::validateSnapshot();
|
49 |
+
if (!$this->snapshots->doesIncludeId($this->dto->getTargetPrefix())) {
|
50 |
+
throw new SnapshotCommandException(
|
51 |
+
'UpdateSnapshot prefix does not exist: ' . $this->dto->getTargetPrefix()
|
52 |
+
);
|
53 |
+
}
|
54 |
+
}
|
55 |
+
}
|
Command/Database/SnapshotFactory.php
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Command\Database;
|
4 |
+
|
5 |
+
use WPStaging\Command\Database\Snapshot\CreateSnapshotCommand;
|
6 |
+
use WPStaging\Command\Database\Snapshot\DeleteSnapshotCommand;
|
7 |
+
use WPStaging\Command\Database\Snapshot\SnapshotDto;
|
8 |
+
use WPStaging\Command\Database\Snapshot\SnapshotHandler;
|
9 |
+
use WPStaging\Command\Database\Snapshot\UpdateSnapshotCommand;
|
10 |
+
use WPStaging\Service\Command\CommandInterface;
|
11 |
+
use WPStaging\Service\Command\HandlerInterface;
|
12 |
+
use WPStaging\WPStaging;
|
13 |
+
|
14 |
+
class SnapshotFactory
|
15 |
+
{
|
16 |
+
// TODO PHP7.1; visibility
|
17 |
+
const CREATE_SNAPSHOT = 'create';
|
18 |
+
const UPDATE_SNAPSHOT = 'update';
|
19 |
+
const DELETE_SNAPSHOT = 'delete';
|
20 |
+
|
21 |
+
private static $container;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @param SnapshotDto $dto
|
25 |
+
* @param string|null $action
|
26 |
+
*
|
27 |
+
* @return SnapshotHandler
|
28 |
+
*/
|
29 |
+
public static function make(SnapshotDto $dto, $action = null)
|
30 |
+
{
|
31 |
+
$handler = new SnapshotHandler($dto);
|
32 |
+
|
33 |
+
if ($action) {
|
34 |
+
self::makeAction($handler, $action);
|
35 |
+
return $handler;
|
36 |
+
}
|
37 |
+
|
38 |
+
foreach([self::CREATE_SNAPSHOT, self::UPDATE_SNAPSHOT, self::DELETE_SNAPSHOT] as $item) {
|
39 |
+
self::makeAction($handler, $item);
|
40 |
+
}
|
41 |
+
|
42 |
+
return $handler;
|
43 |
+
}
|
44 |
+
|
45 |
+
private static function makeAction(HandlerInterface $handler, $action)
|
46 |
+
{
|
47 |
+
switch($action) {
|
48 |
+
case self::CREATE_SNAPSHOT:
|
49 |
+
$handler->addCommand(self::getCommand(CreateSnapshotCommand::class));
|
50 |
+
return;
|
51 |
+
case self::UPDATE_SNAPSHOT:
|
52 |
+
$handler->addCommand(self::getCommand(UpdateSnapshotCommand::class));
|
53 |
+
return;
|
54 |
+
case self::DELETE_SNAPSHOT:
|
55 |
+
$handler->addCommand(self::getCommand(DeleteSnapshotCommand::class));
|
56 |
+
return;
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @param string $command
|
62 |
+
*
|
63 |
+
* @return CommandInterface|null
|
64 |
+
*/
|
65 |
+
private static function getCommand($command)
|
66 |
+
{
|
67 |
+
// TODO RPoC v3.0.0
|
68 |
+
if (!self::$container) {
|
69 |
+
self::$container = WPStaging::getContainer();
|
70 |
+
}
|
71 |
+
|
72 |
+
/** @var CommandInterface|null $command */
|
73 |
+
/** @noinspection CallableParameterUseCaseInTypeContextInspection */
|
74 |
+
$command = self::$container->get($command);
|
75 |
+
return $command;
|
76 |
+
}
|
77 |
+
}
|
Core/Utils/Report.php
CHANGED
@@ -5,81 +5,81 @@ namespace WPStaging\Utils;
|
|
5 |
use WPStaging\Backend\Modules\SystemInfo;
|
6 |
use WPStaging\DI\InjectionAware;
|
7 |
|
8 |
-
class Report extends InjectionAware
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
23 |
$message .= "\n\n'" . $this->getSyslog();
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
} else {
|
80 |
-
return false;
|
81 |
-
}
|
82 |
-
die();
|
83 |
-
}
|
84 |
|
85 |
}
|
5 |
use WPStaging\Backend\Modules\SystemInfo;
|
6 |
use WPStaging\DI\InjectionAware;
|
7 |
|
8 |
+
class Report extends InjectionAware
|
9 |
+
{
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Send customer issue report
|
13 |
+
*
|
14 |
+
* @param string $email User e-mail
|
15 |
+
* @param string $message User message
|
16 |
+
* @param integer $terms User accept terms
|
17 |
+
*
|
18 |
+
* @return array
|
19 |
+
*/
|
20 |
+
public function send($email, $message, $terms, $syslog, $provider = null)
|
21 |
+
{
|
22 |
+
$errors = array();
|
23 |
+
$attachments = array();
|
24 |
+
$maxFileSize = 512 * 1024;
|
25 |
+
$message .= "\n\n'Hosting provider: " . $provider;
|
26 |
+
|
27 |
+
if ( ! empty($syslog)) {
|
28 |
$message .= "\n\n'" . $this->getSyslog();
|
29 |
+
|
30 |
+
$debugLogFile = WP_CONTENT_DIR . '/debug.log';
|
31 |
+
if (filesize($debugLogFile) && filesize($debugLogFile) < $maxFileSize) {
|
32 |
+
$attachments[] = $debugLogFile;
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
if ( ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
37 |
+
$errors[] = __('Email address is not valid.', 'wp-staging');
|
38 |
+
} elseif (empty($message)) {
|
39 |
+
$errors[] = __('Please enter your issue.', 'wp-staging');
|
40 |
+
} elseif (empty($terms)) {
|
41 |
+
$errors[] = __('Please accept our privacy policy.', 'wp-staging');
|
42 |
+
} else {
|
43 |
+
|
44 |
+
if (false === $this->sendMail($email, $message, $attachments)) {
|
45 |
+
$errors[] = 'Can not send report. <br>Please send us a mail to<br>support@wp-staging.com';
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
return $errors;
|
50 |
+
}
|
51 |
+
|
52 |
+
private function getSyslog()
|
53 |
+
{
|
54 |
+
|
55 |
+
$syslog = new SystemInfo($this->di);
|
56 |
+
|
57 |
+
return $syslog->get();
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* send feedback via email
|
62 |
+
*
|
63 |
+
* @return boolean
|
64 |
+
*/
|
65 |
+
private function sendMail($from, $text, $attachments)
|
66 |
+
{
|
67 |
+
|
68 |
+
$headers = array();
|
69 |
+
|
70 |
+
$headers[] = "From: $from";
|
71 |
+
$headers[] = "Reply-To: $from";
|
72 |
+
|
73 |
+
$subject = 'Report Issue!';
|
74 |
+
|
75 |
+
$success = wp_mail('support@wp-staging.com', $subject, $text, $headers, $attachments);
|
76 |
+
|
77 |
+
if ($success) {
|
78 |
+
return true;
|
79 |
+
} else {
|
80 |
+
return false;
|
81 |
+
}
|
82 |
+
die();
|
83 |
+
}
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
}
|
Core/Utils/functions.php
CHANGED
@@ -110,9 +110,9 @@ function wpstg_mysql_escape_mimic($input)
|
|
110 |
|
111 |
/**
|
112 |
* Search & Replace first occurence of string in haystack
|
113 |
-
* @param
|
114 |
-
* @param
|
115 |
-
* @return
|
116 |
*/
|
117 |
function wpstg_replace_first_match($needle, $replace, $haystack)
|
118 |
{
|
110 |
|
111 |
/**
|
112 |
* Search & Replace first occurence of string in haystack
|
113 |
+
* @param string $haystack
|
114 |
+
* @param string $needle
|
115 |
+
* @return string
|
116 |
*/
|
117 |
function wpstg_replace_first_match($needle, $replace, $haystack)
|
118 |
{
|
Core/WPStaging.php
CHANGED
@@ -13,12 +13,14 @@ 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\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
|
@@ -41,7 +43,7 @@ final class WPStaging {
|
|
41 |
* Absolute plugin path
|
42 |
* @var string
|
43 |
*/
|
44 |
-
|
45 |
|
46 |
/**
|
47 |
* Services
|
@@ -55,6 +57,16 @@ final class WPStaging {
|
|
55 |
*/
|
56 |
private static $instance;
|
57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
/**
|
59 |
* WPStaging constructor.
|
60 |
*/
|
@@ -69,6 +81,7 @@ final class WPStaging {
|
|
69 |
$this->initLicensing();
|
70 |
$this->initVersion();
|
71 |
$this->initActions();
|
|
|
72 |
}
|
73 |
|
74 |
/**
|
@@ -76,14 +89,14 @@ final class WPStaging {
|
|
76 |
*/
|
77 |
private function initCron() {
|
78 |
// Register cron job and add new interval 'weekly'
|
79 |
-
|
80 |
}
|
81 |
|
82 |
/**
|
83 |
* Get root WP root path -
|
84 |
* Changed ABSPATH trailingslash for windows compatibility
|
85 |
|
86 |
-
* @return
|
87 |
*/
|
88 |
public static function getWPpath() {
|
89 |
return str_replace( '/', DIRECTORY_SEPARATOR, ABSPATH );
|
@@ -94,19 +107,19 @@ final class WPStaging {
|
|
94 |
*/
|
95 |
public function registerMain() {
|
96 |
// Slug of the plugin
|
97 |
-
$this->slug = plugin_basename( dirname(
|
98 |
|
99 |
// absolute path to the main plugin dir
|
100 |
-
$this->pluginPath = plugin_dir_path(
|
101 |
|
102 |
// URL to main plugin folder
|
103 |
-
$this->url = plugin_dir_url(
|
104 |
|
105 |
// URL to backend public folder folder
|
106 |
-
$this->backend_url = plugin_dir_url(
|
107 |
|
108 |
// URL to frontend public folder folder
|
109 |
-
$this->frontend_url = plugin_dir_url(
|
110 |
}
|
111 |
|
112 |
/**
|
@@ -121,8 +134,7 @@ final class WPStaging {
|
|
121 |
|
122 |
/**
|
123 |
* Remove heartbeat api and user login check
|
124 |
-
* @param
|
125 |
-
* @return type
|
126 |
*/
|
127 |
public function removeWPCoreJs( $hook ) {
|
128 |
|
@@ -155,16 +167,16 @@ final class WPStaging {
|
|
155 |
|
156 |
// Load this css file on frontend and backend on all pages if current site is a staging site
|
157 |
if( wpstg_is_stagingsite() ) {
|
158 |
-
wp_enqueue_style( "wpstg-admin-bar", $this->backend_url . "css/wpstg-admin-bar.css", array(),
|
159 |
}
|
160 |
|
161 |
// Load js file on page plugins.php in free version only
|
162 |
if( !defined('WPSTGPRO_VERSION') && $this->isPluginsPage() ) {
|
163 |
wp_enqueue_script(
|
164 |
-
"wpstg-admin-script", $this->backend_url . "js/wpstg-admin-plugins.js", array("jquery"),
|
165 |
);
|
166 |
wp_enqueue_style(
|
167 |
-
"wpstg-admin-feedback", $this->backend_url . "css/wpstg-admin-feedback.css", array(),
|
168 |
);
|
169 |
}
|
170 |
|
@@ -175,13 +187,13 @@ final class WPStaging {
|
|
175 |
|
176 |
// Load admin js files
|
177 |
wp_enqueue_script(
|
178 |
-
"wpstg-admin-script", $this->backend_url . "js/wpstg-admin.js", array("jquery"),
|
179 |
);
|
180 |
|
181 |
// Load admin js pro files
|
182 |
if(defined('WPSTGPRO_VERSION')) {
|
183 |
wp_enqueue_script(
|
184 |
-
"wpstg-admin-pro-script", $this->url . "Backend/Pro/public/js/wpstg-admin-pro.js", array("jquery"),
|
185 |
);
|
186 |
|
187 |
// Sweet Alert
|
@@ -189,7 +201,7 @@ final class WPStaging {
|
|
189 |
'wpstg-admin-pro-sweetalerts',
|
190 |
$this->url . 'Backend/Pro/public/vendor/sweetalert2/sweetalert2.all.min.js',
|
191 |
[],
|
192 |
-
|
193 |
true
|
194 |
);
|
195 |
|
@@ -197,13 +209,13 @@ final class WPStaging {
|
|
197 |
'wpstg-admin-pro-sweetalerts',
|
198 |
$this->url . 'Backend/Pro/public/vendor/sweetalert2/wordpress-admin.min.css',
|
199 |
[],
|
200 |
-
|
201 |
);
|
202 |
}
|
203 |
|
204 |
// Load admin css files
|
205 |
wp_enqueue_style(
|
206 |
-
"wpstg-admin", $this->backend_url . "css/wpstg-admin.css", array(),
|
207 |
);
|
208 |
|
209 |
wp_localize_script( "wpstg-admin-script", "wpstg", array(
|
@@ -239,10 +251,7 @@ final class WPStaging {
|
|
239 |
);
|
240 |
}
|
241 |
|
242 |
-
|
243 |
-
return true;
|
244 |
-
}
|
245 |
-
return false;
|
246 |
}
|
247 |
|
248 |
/**
|
@@ -250,8 +259,7 @@ final class WPStaging {
|
|
250 |
* @return string
|
251 |
*/
|
252 |
public static function getTablePrefix() {
|
253 |
-
|
254 |
-
return $wpDB->prefix;
|
255 |
}
|
256 |
|
257 |
/**
|
@@ -302,28 +310,12 @@ final class WPStaging {
|
|
302 |
return static::$instance;
|
303 |
}
|
304 |
|
305 |
-
/**
|
306 |
-
* Prevent cloning
|
307 |
-
* @return void
|
308 |
-
*/
|
309 |
-
private function __clone() {
|
310 |
-
|
311 |
-
}
|
312 |
-
|
313 |
-
/**
|
314 |
-
* Prevent unserialization
|
315 |
-
* @return void
|
316 |
-
*/
|
317 |
-
private function __wakeup() {
|
318 |
-
|
319 |
-
}
|
320 |
-
|
321 |
/**
|
322 |
* Load Dependencies
|
323 |
*/
|
324 |
private function loadDependencies() {
|
325 |
// Load globally available functions
|
326 |
-
require_once $this->pluginPath .
|
327 |
|
328 |
$this->set( "loader", new Loader() );
|
329 |
|
@@ -350,6 +342,7 @@ final class WPStaging {
|
|
350 |
* Execute Plugin
|
351 |
*/
|
352 |
public function run() {
|
|
|
353 |
$this->get( "loader" )->run();
|
354 |
}
|
355 |
|
@@ -397,10 +390,9 @@ final class WPStaging {
|
|
397 |
{
|
398 |
return WPSTGPRO_VERSION;
|
399 |
}
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
}
|
404 |
}
|
405 |
|
406 |
/**
|
@@ -415,7 +407,7 @@ final class WPStaging {
|
|
415 |
*/
|
416 |
public static function getSlug()
|
417 |
{
|
418 |
-
return plugin_basename(dirname(
|
419 |
}
|
420 |
|
421 |
/**
|
@@ -423,15 +415,15 @@ final class WPStaging {
|
|
423 |
* @return string
|
424 |
*/
|
425 |
public function getPath() {
|
426 |
-
return dirname(
|
427 |
}
|
428 |
|
429 |
/**
|
430 |
* Get main plugin url
|
431 |
-
* @return
|
432 |
*/
|
433 |
public function getUrl() {
|
434 |
-
return plugin_dir_url(
|
435 |
}
|
436 |
|
437 |
/**
|
@@ -476,7 +468,7 @@ final class WPStaging {
|
|
476 |
public function initLicensing() {
|
477 |
// Add licensing stuff if class exists
|
478 |
if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
|
479 |
-
|
480 |
}
|
481 |
return false;
|
482 |
}
|
@@ -488,7 +480,7 @@ final class WPStaging {
|
|
488 |
public function initVersion() {
|
489 |
// Add licensing stuff if class exists
|
490 |
if( class_exists( 'WPStaging\Backend\Pro\Licensing\Version' ) ) {
|
491 |
-
|
492 |
}
|
493 |
return false;
|
494 |
}
|
@@ -507,4 +499,13 @@ final class WPStaging {
|
|
507 |
}
|
508 |
}
|
509 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
510 |
}
|
13 |
use WPStaging\Backend\Administrator;
|
14 |
use WPStaging\DTO\Settings;
|
15 |
use WPStaging\Frontend\Frontend;
|
16 |
+
use WPStaging\Service\Permalinks\PermalinksPurge;
|
17 |
use WPStaging\Service\Container\Container;
|
18 |
use WPStaging\Utils\Autoloader;
|
19 |
use WPStaging\Utils\Cache;
|
20 |
use WPStaging\Utils\Loader;
|
21 |
use WPStaging\Utils\Logger;
|
22 |
use WPStaging\Service\PluginFactory;
|
23 |
+
use WPStaging\Cron\Cron;
|
24 |
|
25 |
/**
|
26 |
* Class WPStaging
|
43 |
* Absolute plugin path
|
44 |
* @var string
|
45 |
*/
|
46 |
+
private $pluginPath;
|
47 |
|
48 |
/**
|
49 |
* Services
|
57 |
*/
|
58 |
private static $instance;
|
59 |
|
60 |
+
/*
|
61 |
+
* @var string
|
62 |
+
*/
|
63 |
+
private $backend_url;
|
64 |
+
|
65 |
+
/**
|
66 |
+
* @var string
|
67 |
+
*/
|
68 |
+
private $url;
|
69 |
+
|
70 |
/**
|
71 |
* WPStaging constructor.
|
72 |
*/
|
81 |
$this->initLicensing();
|
82 |
$this->initVersion();
|
83 |
$this->initActions();
|
84 |
+
$this->handleCacheIssues();
|
85 |
}
|
86 |
|
87 |
/**
|
89 |
*/
|
90 |
private function initCron() {
|
91 |
// Register cron job and add new interval 'weekly'
|
92 |
+
new Cron;
|
93 |
}
|
94 |
|
95 |
/**
|
96 |
* Get root WP root path -
|
97 |
* Changed ABSPATH trailingslash for windows compatibility
|
98 |
|
99 |
+
* @return string
|
100 |
*/
|
101 |
public static function getWPpath() {
|
102 |
return str_replace( '/', DIRECTORY_SEPARATOR, ABSPATH );
|
107 |
*/
|
108 |
public function registerMain() {
|
109 |
// Slug of the plugin
|
110 |
+
$this->slug = plugin_basename( dirname(__DIR__) );
|
111 |
|
112 |
// absolute path to the main plugin dir
|
113 |
+
$this->pluginPath = plugin_dir_path(__DIR__);
|
114 |
|
115 |
// URL to main plugin folder
|
116 |
+
$this->url = plugin_dir_url(__DIR__);
|
117 |
|
118 |
// URL to backend public folder folder
|
119 |
+
$this->backend_url = plugin_dir_url(__DIR__) . "Backend/public/";
|
120 |
|
121 |
// URL to frontend public folder folder
|
122 |
+
$this->frontend_url = plugin_dir_url(__DIR__) . "Frontend/public/";
|
123 |
}
|
124 |
|
125 |
/**
|
134 |
|
135 |
/**
|
136 |
* Remove heartbeat api and user login check
|
137 |
+
* @param bool $hook
|
|
|
138 |
*/
|
139 |
public function removeWPCoreJs( $hook ) {
|
140 |
|
167 |
|
168 |
// Load this css file on frontend and backend on all pages if current site is a staging site
|
169 |
if( wpstg_is_stagingsite() ) {
|
170 |
+
wp_enqueue_style( "wpstg-admin-bar", $this->backend_url . "css/wpstg-admin-bar.css", array(), self::getVersion() );
|
171 |
}
|
172 |
|
173 |
// Load js file on page plugins.php in free version only
|
174 |
if( !defined('WPSTGPRO_VERSION') && $this->isPluginsPage() ) {
|
175 |
wp_enqueue_script(
|
176 |
+
"wpstg-admin-script", $this->backend_url . "js/wpstg-admin-plugins.js", array("jquery"), self::getVersion(), false
|
177 |
);
|
178 |
wp_enqueue_style(
|
179 |
+
"wpstg-admin-feedback", $this->backend_url . "css/wpstg-admin-feedback.css", array(), self::getVersion()
|
180 |
);
|
181 |
}
|
182 |
|
187 |
|
188 |
// Load admin js files
|
189 |
wp_enqueue_script(
|
190 |
+
"wpstg-admin-script", $this->backend_url . "js/wpstg-admin.js", array("jquery"), self::getVersion(), false
|
191 |
);
|
192 |
|
193 |
// Load admin js pro files
|
194 |
if(defined('WPSTGPRO_VERSION')) {
|
195 |
wp_enqueue_script(
|
196 |
+
"wpstg-admin-pro-script", $this->url . "Backend/Pro/public/js/wpstg-admin-pro.js", array("jquery"), self::getVersion(), false
|
197 |
);
|
198 |
|
199 |
// Sweet Alert
|
201 |
'wpstg-admin-pro-sweetalerts',
|
202 |
$this->url . 'Backend/Pro/public/vendor/sweetalert2/sweetalert2.all.min.js',
|
203 |
[],
|
204 |
+
self::getVersion(),
|
205 |
true
|
206 |
);
|
207 |
|
209 |
'wpstg-admin-pro-sweetalerts',
|
210 |
$this->url . 'Backend/Pro/public/vendor/sweetalert2/wordpress-admin.min.css',
|
211 |
[],
|
212 |
+
self::getVersion()
|
213 |
);
|
214 |
}
|
215 |
|
216 |
// Load admin css files
|
217 |
wp_enqueue_style(
|
218 |
+
"wpstg-admin", $this->backend_url . "css/wpstg-admin.css", array(), self::getVersion()
|
219 |
);
|
220 |
|
221 |
wp_localize_script( "wpstg-admin-script", "wpstg", array(
|
251 |
);
|
252 |
}
|
253 |
|
254 |
+
return !in_array($page, $availablePages) || !is_admin();
|
|
|
|
|
|
|
255 |
}
|
256 |
|
257 |
/**
|
259 |
* @return string
|
260 |
*/
|
261 |
public static function getTablePrefix() {
|
262 |
+
return WPStaging::getInstance()->get( "wpdb" )->prefix;
|
|
|
263 |
}
|
264 |
|
265 |
/**
|
310 |
return static::$instance;
|
311 |
}
|
312 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
/**
|
314 |
* Load Dependencies
|
315 |
*/
|
316 |
private function loadDependencies() {
|
317 |
// Load globally available functions
|
318 |
+
require_once ($this->pluginPath . "Core/Utils/functions.php");
|
319 |
|
320 |
$this->set( "loader", new Loader() );
|
321 |
|
342 |
* Execute Plugin
|
343 |
*/
|
344 |
public function run() {
|
345 |
+
/** @noinspection **/
|
346 |
$this->get( "loader" )->run();
|
347 |
}
|
348 |
|
390 |
{
|
391 |
return WPSTGPRO_VERSION;
|
392 |
}
|
393 |
+
|
394 |
+
return WPSTG_VERSION;
|
395 |
+
|
|
|
396 |
}
|
397 |
|
398 |
/**
|
407 |
*/
|
408 |
public static function getSlug()
|
409 |
{
|
410 |
+
return plugin_basename(dirname(__DIR__));
|
411 |
}
|
412 |
|
413 |
/**
|
415 |
* @return string
|
416 |
*/
|
417 |
public function getPath() {
|
418 |
+
return dirname(__DIR__);
|
419 |
}
|
420 |
|
421 |
/**
|
422 |
* Get main plugin url
|
423 |
+
* @return string
|
424 |
*/
|
425 |
public function getUrl() {
|
426 |
+
return plugin_dir_url(__DIR__);
|
427 |
}
|
428 |
|
429 |
/**
|
468 |
public function initLicensing() {
|
469 |
// Add licensing stuff if class exists
|
470 |
if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
|
471 |
+
new Backend\Pro\Licensing\Licensing();
|
472 |
}
|
473 |
return false;
|
474 |
}
|
480 |
public function initVersion() {
|
481 |
// Add licensing stuff if class exists
|
482 |
if( class_exists( 'WPStaging\Backend\Pro\Licensing\Version' ) ) {
|
483 |
+
new Backend\Pro\Licensing\Version();
|
484 |
}
|
485 |
return false;
|
486 |
}
|
499 |
}
|
500 |
}
|
501 |
|
502 |
+
/**
|
503 |
+
* Takes care of cache issues in certain situations
|
504 |
+
*/
|
505 |
+
private function handleCacheIssues() {
|
506 |
+
$permalinksPurge = new PermalinksPurge();
|
507 |
+
add_action( 'wpstg_pushing_complete', array( $permalinksPurge, 'executeAfterPushing' ));
|
508 |
+
add_action( 'wp_loaded', array( $permalinksPurge, 'purgePermalinks' ), $permalinksPurge::PLUGINS_LOADED_PRIORITY);
|
509 |
+
}
|
510 |
+
|
511 |
}
|
Service/Adapter/SourceDatabase.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace WPStaging\Service\Adapter;
|
5 |
+
|
6 |
+
use stdClass;
|
7 |
+
use WPStaging\WPStaging;
|
8 |
+
|
9 |
+
class SourceDatabase
|
10 |
+
{
|
11 |
+
/** @var object */
|
12 |
+
private $wpdb;
|
13 |
+
|
14 |
+
/** @var object */
|
15 |
+
private $options;
|
16 |
+
|
17 |
+
public function __construct($options = stdClass::class)
|
18 |
+
{
|
19 |
+
$this->wpdb = WPStaging::getInstance()->get('wpdb');
|
20 |
+
$this->options = $options;
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @return bool
|
25 |
+
*/
|
26 |
+
public function isExternalDatabase()
|
27 |
+
{
|
28 |
+
return !(empty($this->options->databaseUser) ||
|
29 |
+
empty($this->options->databasePassword) ||
|
30 |
+
empty($this->options->databaseDatabase) ||
|
31 |
+
empty($this->options->databaseServer));
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* @return object
|
36 |
+
*/
|
37 |
+
private function getExternalDb()
|
38 |
+
{
|
39 |
+
return new \wpdb($this->options->databaseUser, str_replace("\\\\", "\\", $this->options->databasePassword), $this->options->databaseDatabase, $this->options->databaseServer);
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Check if source database is a local or external one and get the corresponding database object
|
44 |
+
*
|
45 |
+
* @return object
|
46 |
+
*
|
47 |
+
*/
|
48 |
+
public function getDatabase()
|
49 |
+
{
|
50 |
+
if ($this->isExternalDatabase()) {
|
51 |
+
return $this->getExternalDb();
|
52 |
+
}
|
53 |
+
return $this->wpdb;
|
54 |
+
}
|
55 |
+
}
|
Service/Permalinks/PermalinksPurge.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Permalinks;
|
4 |
+
|
5 |
+
class PermalinksPurge
|
6 |
+
{
|
7 |
+
|
8 |
+
const PLUGINS_LOADED_PRIORITY = 99999;
|
9 |
+
const TRANSIENT = "wpstg_permalinks_do_purge";
|
10 |
+
|
11 |
+
public function executeAfterPushing()
|
12 |
+
{
|
13 |
+
set_transient(self::TRANSIENT, "true");
|
14 |
+
}
|
15 |
+
|
16 |
+
public function purgePermalinks()
|
17 |
+
{
|
18 |
+
if (get_transient(self::TRANSIENT)) {
|
19 |
+
delete_transient(self::TRANSIENT);
|
20 |
+
flush_rewrite_rules(false);
|
21 |
+
}
|
22 |
+
}
|
23 |
+
}
|
Service/Utils/FileSystem.php
CHANGED
@@ -4,6 +4,10 @@
|
|
4 |
|
5 |
namespace WPStaging\Service\Utils;
|
6 |
|
|
|
|
|
|
|
|
|
7 |
class FileSystem
|
8 |
{
|
9 |
/*
|
4 |
|
5 |
namespace WPStaging\Service\Utils;
|
6 |
|
7 |
+
use FilesystemIterator;
|
8 |
+
use RecursiveDirectoryIterator;
|
9 |
+
use RecursiveIteratorIterator;
|
10 |
+
|
11 |
class FileSystem
|
12 |
{
|
13 |
/*
|
Service/Utils/Strings.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Service\Utils;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class Strings
|
7 |
+
* @package WPStaging\Service\Strings
|
8 |
+
*/
|
9 |
+
class Strings
|
10 |
+
{
|
11 |
+
/**
|
12 |
+
* This function ensures backwards compatibility with Wordpress prior to the 4.7 release. sanitize_textarea_field
|
13 |
+
* was introduced with that version.
|
14 |
+
* @param $str
|
15 |
+
*
|
16 |
+
* @return string
|
17 |
+
*/
|
18 |
+
public function sanitizeTextareaField($str)
|
19 |
+
{
|
20 |
+
if (function_exists('sanitize_textarea_field')) {
|
21 |
+
return sanitize_textarea_field($str);
|
22 |
+
} else {
|
23 |
+
return sanitize_text_field($str);
|
24 |
+
}
|
25 |
+
}
|
26 |
+
}
|
languages/wp-staging-de_DE.po
CHANGED
@@ -188,7 +188,7 @@ msgstr "Anzahl der Datenbank Einträge, die zugleich kopiert werden. Je höher d
|
|
188 |
|
189 |
#: Backend/views/clone/single-site/index.php:16
|
190 |
msgid "Report Issue"
|
191 |
-
msgstr "
|
192 |
|
193 |
#: Backend/views/clone/single-site/index.php:12
|
194 |
msgid "Cloning"
|
@@ -348,8 +348,8 @@ msgid "By submitting, I accept the <a href=\"https://wp-staging.com/privacy-poli
|
|
348 |
msgstr "Mit Übertragen akzeptiere ich die <a href=\"https://wp-staging.com/privacy-policy/\" target=\"_blank\">Datenschutz Vereinbarung</a> und erlaube, dass meine E-Mail Adresse gespeichert und verarbeitet wird um meine Support Anfrage zu beantworten."
|
349 |
|
350 |
#: Backend/views/_main/report-issue.php:12
|
351 |
-
msgid "Optional: Submit the <a href=\"%s\" target=\"_blank\">System Log</a
|
352 |
-
msgstr "Optional: Übertrage das <a href=\"%s\" target=\"_blank\">System Log</a
|
353 |
|
354 |
#: Backend/views/_main/messages/staging-directory-permission-problem.php:4
|
355 |
msgid ""
|
188 |
|
189 |
#: Backend/views/clone/single-site/index.php:16
|
190 |
msgid "Report Issue"
|
191 |
+
msgstr "Fehler melden"
|
192 |
|
193 |
#: Backend/views/clone/single-site/index.php:12
|
194 |
msgid "Cloning"
|
348 |
msgstr "Mit Übertragen akzeptiere ich die <a href=\"https://wp-staging.com/privacy-policy/\" target=\"_blank\">Datenschutz Vereinbarung</a> und erlaube, dass meine E-Mail Adresse gespeichert und verarbeitet wird um meine Support Anfrage zu beantworten."
|
349 |
|
350 |
#: Backend/views/_main/report-issue.php:12
|
351 |
+
msgid "Optional: Submit the <a href=\"%s\" target=\"_blank\">System Log</a> and your WordPress debug log. This helps us to resolve your technical issues."
|
352 |
+
msgstr "Optional: Übertrage das <a href=\"%s\" target=\"_blank\">System Log</a> sowie dein WordPress-Debug-Log. Das hilft uns Dein technisches Anliegen zu lösen."
|
353 |
|
354 |
#: Backend/views/_main/messages/staging-directory-permission-problem.php:4
|
355 |
msgid ""
|
readme.txt
CHANGED
@@ -153,6 +153,16 @@ https://wp-staging.com
|
|
153 |
|
154 |
== Changelog ==
|
155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
= 2.7.3 =
|
157 |
* New: Compatible up to WordPress 5.4.1
|
158 |
* New: Allow filtering of staging site title
|
@@ -257,5 +267,11 @@ https://wp-staging.com
|
|
257 |
Complete changelog: [https://wp-staging.com/wp-staging-changelog](https://wp-staging.com/wp-staging-changelog)
|
258 |
|
259 |
== Upgrade Notice ==
|
260 |
-
*
|
261 |
-
* Fix:
|
|
|
|
|
|
|
|
|
|
|
|
153 |
|
154 |
== Changelog ==
|
155 |
|
156 |
+
= 2.7.4 =
|
157 |
+
* New: Compatible up to WordPress 5.4.2
|
158 |
+
* Fix: Remove beta notice
|
159 |
+
* Fix: Error if views are cloned
|
160 |
+
* Fix: Fatal error if WordPress is older than 4.5
|
161 |
+
* Fix: Merge pro/free version
|
162 |
+
* Fix: Step switching logic does not work properly
|
163 |
+
* Fix: Fix progress bar when certains steps are skipped
|
164 |
+
* Fix: Change german translation for REPORT ISSUE
|
165 |
+
|
166 |
= 2.7.3 =
|
167 |
* New: Compatible up to WordPress 5.4.1
|
168 |
* New: Allow filtering of staging site title
|
267 |
Complete changelog: [https://wp-staging.com/wp-staging-changelog](https://wp-staging.com/wp-staging-changelog)
|
268 |
|
269 |
== Upgrade Notice ==
|
270 |
+
* New: Compatible up to WordPress 5.4.2
|
271 |
+
* Fix: Remove beta notice
|
272 |
+
* Fix: Error if views are cloned
|
273 |
+
* Fix: Fatal error if WordPress is older than 4.5
|
274 |
+
* Fix: Merge pro/free version
|
275 |
+
* Fix: Step switching logic does not work properly
|
276 |
+
* Fix: Fix progress bar when certains steps are skipped
|
277 |
+
* Fix: Change german translation for REPORT ISSUE
|
vendor/autoload.php
CHANGED
@@ -4,4 +4,4 @@
|
|
4 |
|
5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
6 |
|
7 |
-
return
|
4 |
|
5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
6 |
|
7 |
+
return ComposerAutoloaderInitb9bb895dff0feeace986bca17666d0d0::getLoader();
|
vendor/composer/autoload_real.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
-
class
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
@@ -22,15 +22,15 @@ class ComposerAutoloaderInitd3ab211c510172b0edc8b09988ac2855
|
|
22 |
return self::$loader;
|
23 |
}
|
24 |
|
25 |
-
spl_autoload_register(array('
|
26 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
27 |
-
spl_autoload_unregister(array('
|
28 |
|
29 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
30 |
if ($useStaticLoader) {
|
31 |
require_once __DIR__ . '/autoload_static.php';
|
32 |
|
33 |
-
call_user_func(\Composer\Autoload\
|
34 |
} else {
|
35 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
36 |
foreach ($map as $namespace => $path) {
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
+
class ComposerAutoloaderInitb9bb895dff0feeace986bca17666d0d0
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
22 |
return self::$loader;
|
23 |
}
|
24 |
|
25 |
+
spl_autoload_register(array('ComposerAutoloaderInitb9bb895dff0feeace986bca17666d0d0', 'loadClassLoader'), true, true);
|
26 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
27 |
+
spl_autoload_unregister(array('ComposerAutoloaderInitb9bb895dff0feeace986bca17666d0d0', 'loadClassLoader'));
|
28 |
|
29 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
30 |
if ($useStaticLoader) {
|
31 |
require_once __DIR__ . '/autoload_static.php';
|
32 |
|
33 |
+
call_user_func(\Composer\Autoload\ComposerStaticInitb9bb895dff0feeace986bca17666d0d0::getInitializer($loader));
|
34 |
} else {
|
35 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
36 |
foreach ($map as $namespace => $path) {
|
vendor/composer/autoload_static.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
-
class
|
8 |
{
|
9 |
public static $prefixLengthsPsr4 = array (
|
10 |
'W' =>
|
@@ -36,8 +36,8 @@ class ComposerStaticInitd3ab211c510172b0edc8b09988ac2855
|
|
36 |
public static function getInitializer(ClassLoader $loader)
|
37 |
{
|
38 |
return \Closure::bind(function () use ($loader) {
|
39 |
-
$loader->prefixLengthsPsr4 =
|
40 |
-
$loader->prefixDirsPsr4 =
|
41 |
|
42 |
}, null, ClassLoader::class);
|
43 |
}
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
+
class ComposerStaticInitb9bb895dff0feeace986bca17666d0d0
|
8 |
{
|
9 |
public static $prefixLengthsPsr4 = array (
|
10 |
'W' =>
|
36 |
public static function getInitializer(ClassLoader $loader)
|
37 |
{
|
38 |
return \Closure::bind(function () use ($loader) {
|
39 |
+
$loader->prefixLengthsPsr4 = ComposerStaticInitb9bb895dff0feeace986bca17666d0d0::$prefixLengthsPsr4;
|
40 |
+
$loader->prefixDirsPsr4 = ComposerStaticInitb9bb895dff0feeace986bca17666d0d0::$prefixDirsPsr4;
|
41 |
|
42 |
}, null, ClassLoader::class);
|
43 |
}
|
wp-staging.php
CHANGED
@@ -44,7 +44,7 @@ if (!defined('WPSTG_VERSION')) {
|
|
44 |
|
45 |
// Compatible up to WordPress Version
|
46 |
if (!defined('WPSTG_COMPATIBLE')) {
|
47 |
-
define('WPSTG_COMPATIBLE', '5.4.
|
48 |
}
|
49 |
|
50 |
// Absolute path to plugin
|
44 |
|
45 |
// Compatible up to WordPress Version
|
46 |
if (!defined('WPSTG_COMPATIBLE')) {
|
47 |
+
define('WPSTG_COMPATIBLE', '5.4.2');
|
48 |
}
|
49 |
|
50 |
// Absolute path to plugin
|