Duplicator – WordPress Migration Plugin - Version 1.4.0

Version Description

Download this release

Release Info

Developer cory@lamle.org
Plugin Icon 128x128 Duplicator – WordPress Migration Plugin
Version 1.4.0
Comparing to
See all releases

Code changes from version 1.3.40.1 to 1.4.0

Files changed (73) hide show
  1. assets/img/logo_wasbi.png +0 -0
  2. classes/class.plugin.upgrade.php +1 -7
  3. classes/class.server.php +3 -1
  4. classes/host/class.custom.host.manager.php +176 -0
  5. classes/host/class.flywheel.host.php +32 -0
  6. classes/host/class.godaddy.host.php +19 -7
  7. classes/host/class.liquidweb.host.php +30 -0
  8. classes/host/class.pantheon.host.php +30 -0
  9. classes/host/class.wordpresscom.host.php +30 -0
  10. classes/host/class.wpengine.host.php +28 -13
  11. classes/host/interface.host.php +35 -0
  12. classes/package/class.pack.archive.filters.php +1 -0
  13. classes/package/class.pack.database.php +27 -1
  14. classes/package/class.pack.php +1 -1
  15. classes/ui/class.ui.notice.php +104 -30
  16. ctrls/class.web.services.php +235 -232
  17. define.php +9 -4
  18. duplicator-main.php +406 -0
  19. duplicator.php +15 -405
  20. installer/dup-installer/assets/inc.css.php +587 -547
  21. installer/dup-installer/assets/inc.js.php +39 -1
  22. installer/dup-installer/assets/inc.libs.js +0 -22
  23. installer/dup-installer/classes/class.s3.func.php +4 -2
  24. installer/dup-installer/classes/class.server.php +29 -8
  25. installer/dup-installer/classes/config/class.boot.php +17 -4
  26. installer/dup-installer/classes/config/class.conf.srv.php +267 -264
  27. installer/dup-installer/classes/host/class.custom.host.manager.php +199 -0
  28. installer/dup-installer/classes/host/class.flywheel.host.php +62 -0
  29. installer/dup-installer/classes/host/class.godaddy.host.php +62 -0
  30. installer/dup-installer/classes/host/class.liquidweb.host.php +57 -0
  31. installer/dup-installer/classes/host/class.pantheon.host.php +71 -0
  32. installer/dup-installer/classes/host/class.wordpresscom.host.php +62 -0
  33. installer/dup-installer/classes/host/class.wpengine.host.php +62 -0
  34. installer/dup-installer/classes/host/interface.host.php +46 -0
  35. installer/dup-installer/classes/utilities/class.u.notices.manager.php +1250 -1251
  36. installer/dup-installer/classes/utilities/class.u.php +31 -1
  37. installer/dup-installer/classes/utilities/class.u.search.reaplce.manager.php +4 -3
  38. installer/dup-installer/ctrls/classes/class.ctrl.extraction.php +606 -0
  39. installer/dup-installer/ctrls/ctrl.s1.php +3 -420
  40. installer/dup-installer/ctrls/ctrl.s2.dbinstall.php +668 -645
  41. installer/dup-installer/ctrls/ctrl.s2.dbtest.php +42 -23
  42. installer/dup-installer/main.installer.php +1 -1
  43. installer/dup-installer/views/view.help.php +7 -0
  44. installer/dup-installer/views/view.s1.base.php +1465 -1397
  45. installer/dup-installer/views/view.s2.base.php +1 -1
  46. installer/dup-installer/views/view.s2.basic.php +254 -236
  47. installer/dup-installer/views/view.s2.dbtest.php +27 -3
  48. installer/dup-installer/views/view.s3.php +1 -1
  49. installer/dup-installer/views/view.s4.php +1 -1
  50. installer/installer.tpl +67 -5
  51. lib/snaplib/class.snaplib.logger.php +33 -2
  52. lib/snaplib/class.snaplib.u.db.php +241 -0
  53. lib/snaplib/class.snaplib.u.io.php +394 -92
  54. lib/snaplib/class.snaplib.u.json.php +25 -9
  55. lib/snaplib/class.snaplib.u.orig.files.manager.php +348 -0
  56. lib/snaplib/class.snaplib.u.os.php +11 -2
  57. lib/snaplib/class.snaplib.u.string.php +11 -1
  58. lib/snaplib/class.snaplib.u.url.php +130 -13
  59. lib/snaplib/class.snaplib.u.util.php +198 -34
  60. lib/snaplib/class.snaplib.u.wp.php +118 -5
  61. lib/snaplib/snaplib.all.php +3 -1
  62. readme.txt +3 -3
  63. tools/DuplicatorPhpVersionCheck.php +59 -0
  64. tools/Lite/Requirements.php +229 -0
  65. uninstall.php +13 -0
  66. views/packages/main/packages.php +4 -6
  67. views/packages/main/s2.scan1.php +448 -448
  68. views/packages/main/s2.scan2.php +230 -213
  69. views/packages/main/s2.scan3.php +35 -0
  70. views/settings/controller.php +1 -1
  71. views/settings/general.php +6 -2
  72. views/settings/gopro.php +267 -259
  73. views/tools/import.php +1 -1
assets/img/logo_wasbi.png ADDED
Binary file
classes/class.plugin.upgrade.php CHANGED
@@ -27,8 +27,6 @@ class DUP_LITE_Plugin_Upgrade
27
  {
28
  self::updateDatabase();
29
 
30
- update_option(DUP_UI_Notice::OPTION_KEY_INSTALLER_HASH_NOTICE, true);
31
-
32
  //WordPress Options Hooks
33
  update_option(self::DUP_VERSION_OPT_KEY, DUPLICATOR_VERSION);
34
  }
@@ -37,12 +35,8 @@ class DUP_LITE_Plugin_Upgrade
37
  {
38
  self::updateDatabase();
39
 
40
- if (version_compare($oldVersion, '1.3.30', '<=')) {
41
- update_option(DUP_UI_Notice::OPTION_KEY_INSTALLER_HASH_NOTICE, true);
42
- }
43
-
44
  if (version_compare($oldVersion, '1.3.35', '<')) {
45
- update_option(DUP_UI_Notice::OPTION_KEY_NEW_STORAGE_POSITION, true);
46
  DUP_Settings::Set('storage_position', DUP_Settings::STORAGE_POSITION_LECAGY);
47
  DUP_Settings::Save();
48
  }
27
  {
28
  self::updateDatabase();
29
 
 
 
30
  //WordPress Options Hooks
31
  update_option(self::DUP_VERSION_OPT_KEY, DUPLICATOR_VERSION);
32
  }
35
  {
36
  self::updateDatabase();
37
 
38
+ //Do not update to new wp-content storage till after 1.3.35
 
 
 
39
  if (version_compare($oldVersion, '1.3.35', '<')) {
 
40
  DUP_Settings::Set('storage_position', DUP_Settings::STORAGE_POSITION_LECAGY);
41
  DUP_Settings::Save();
42
  }
classes/class.server.php CHANGED
@@ -210,7 +210,9 @@ class DUP_Server
210
  $checks['SRV']['PHP']['maxtime'] = $php_test2;
211
  $checks['SRV']['PHP']['mysqli'] = $php_test3;
212
  $checks['SRV']['PHP']['version'] = $php_test4;
213
- $checks['SRV']['PHP']['ALL'] = ($php_test0 && $php_test1 && $php_test2 && $php_test3 && $php_test4) ? 'Good' : 'Warn';
 
 
214
 
215
  //WORDPRESS SETTINGS
216
  global $wp_version;
210
  $checks['SRV']['PHP']['maxtime'] = $php_test2;
211
  $checks['SRV']['PHP']['mysqli'] = $php_test3;
212
  $checks['SRV']['PHP']['version'] = $php_test4;
213
+ //MANAGED HOST
214
+ $checks['SRV']['SYS']['managedHost'] = !DUP_Custom_Host_Manager::getInstance()->isManaged();
215
+ $checks['SRV']['SYS']['ALL'] = ($php_test0 && $php_test1 && $php_test2 && $php_test3 && $php_test4 && $checks['SRV']['SYS']['managedHost']) ? 'Good' : 'Warn';
216
 
217
  //WORDPRESS SETTINGS
218
  global $wp_version;
classes/host/class.custom.host.manager.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * custom hosting manager
5
+ * singleton class
6
+ *
7
+ * Standard: PSR-2
8
+ *
9
+ * @package SC\DUPX\HOST
10
+ * @link http://www.php-fig.org/psr/psr-2/
11
+ *
12
+ */
13
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
14
+
15
+ require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/interface.host.php');
16
+ require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.godaddy.host.php');
17
+ require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.wpengine.host.php');
18
+ require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.wordpresscom.host.php');
19
+ require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.liquidweb.host.php');
20
+ require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.pantheon.host.php');
21
+ require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.flywheel.host.php');
22
+
23
+ class DUP_Custom_Host_Manager
24
+ {
25
+ const HOST_GODADDY = 'godaddy';
26
+ const HOST_WPENGINE = 'wpengine';
27
+ const HOST_WORDPRESSCOM = 'wordpresscom';
28
+ const HOST_LIQUIDWEB = 'liquidweb';
29
+ const HOST_PANTHEON = 'pantheon';
30
+ const HOST_FLYWHEEL = 'flywheel';
31
+
32
+ /**
33
+ *
34
+ * @var DUP_Custom_Host_Manager
35
+ */
36
+ protected static $instance = null;
37
+
38
+ /**
39
+ *
40
+ * @var bool
41
+ */
42
+ private $initialized = false;
43
+
44
+ /**
45
+ *
46
+ * @var DUP_Host_interface[]
47
+ */
48
+ private $customHostings = array();
49
+
50
+ /**
51
+ *
52
+ * @var string[]
53
+ */
54
+ private $activeHostings = array();
55
+
56
+ /**
57
+ *
58
+ * @return self
59
+ */
60
+ public static function getInstance()
61
+ {
62
+ if (is_null(self::$instance)) {
63
+ self::$instance = new self;
64
+ }
65
+ return self::$instance;
66
+ }
67
+
68
+ private function __construct()
69
+ {
70
+ $this->customHostings[DUP_WPEngine_Host::getIdentifier()] = new DUP_WPEngine_Host();
71
+ $this->customHostings[DUP_GoDaddy_Host::getIdentifier()] = new DUP_GoDaddy_Host();
72
+ $this->customHostings[DUP_WordpressCom_Host::getIdentifier()] = new DUP_WordpressCom_Host();
73
+ $this->customHostings[DUP_Liquidweb_Host::getIdentifier()] = new DUP_Liquidweb_Host();
74
+ $this->customHostings[DUP_Pantheon_Host::getIdentifier()] = new DUP_Pantheon_Host();
75
+ $this->customHostings[DUP_Flywheel_Host::getIdentifier()] = new DUP_Flywheel_Host();
76
+ }
77
+
78
+ public function init()
79
+ {
80
+ if ($this->initialized) {
81
+ return true;
82
+ }
83
+ foreach ($this->customHostings as $cHost) {
84
+ if (!($cHost instanceof DUP_Host_interface)) {
85
+ throw new Exception('Host must implement DUP_Host_interface');
86
+ }
87
+ if ($cHost->isHosting()) {
88
+ $this->activeHostings[] = $cHost->getIdentifier();
89
+ $cHost->init();
90
+ }
91
+ }
92
+ $this->initialized = true;
93
+ return true;
94
+ }
95
+
96
+ public function getActiveHostings()
97
+ {
98
+ return $this->activeHostings;
99
+ }
100
+
101
+ public function isHosting($identifier)
102
+ {
103
+ return in_array($identifier, $this->activeHostings);
104
+ }
105
+
106
+ public function isManaged()
107
+ {
108
+ if ($this->isHosting(self::HOST_WORDPRESSCOM)) {
109
+ return true;
110
+ }
111
+
112
+ if ($this->isHosting(self::HOST_GODADDY)) {
113
+ return true;
114
+ }
115
+
116
+ if ($this->isHosting(self::HOST_WPENGINE)) {
117
+ return true;
118
+ }
119
+
120
+ if ($this->isHosting(self::HOST_LIQUIDWEB)) {
121
+ return true;
122
+ }
123
+
124
+ if ($this->isHosting(self::HOST_PANTHEON)) {
125
+ return true;
126
+ }
127
+
128
+ if ($this->isHosting(self::HOST_FLYWHEEL)) {
129
+ return true;
130
+ }
131
+
132
+ if ($this->WPConfigIsNotWriteable()) {
133
+ return true;
134
+ }
135
+
136
+ if ($this->notAccessibleCoreDirPresent()) {
137
+ return true;
138
+ }
139
+
140
+ return false;
141
+ }
142
+
143
+ public function WPConfigIsNotWriteable()
144
+ {
145
+ $wpConfigPath = duplicator_get_abs_path()."/wp-config.php";
146
+
147
+ return file_exists($wpConfigPath) && !is_writeable($wpConfigPath);
148
+ }
149
+
150
+ public function notAccessibleCoreDirPresent()
151
+ {
152
+ $absPath = duplicator_get_abs_path();
153
+ $coreDirs = array(
154
+ $absPath.'/wp-admin',
155
+ $absPath.'/wp-includes',
156
+ WP_CONTENT_DIR
157
+ );
158
+
159
+ foreach ($coreDirs as $coreDir) {
160
+ if (file_exists($coreDir) && !is_writeable($coreDir)) {
161
+ return true;
162
+ }
163
+ }
164
+
165
+ return false;
166
+ }
167
+
168
+ public function getHosting($identifier)
169
+ {
170
+ if ($this->isHosting($identifier)) {
171
+ return $this->activeHostings[$identifier];
172
+ } else {
173
+ return false;
174
+ }
175
+ }
176
+ }
classes/host/class.flywheel.host.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Flywheel custom hosting class
5
+ *
6
+ * Standard: PSR-2
7
+ *
8
+ * @package SC\DUPX\HOST
9
+ * @link http://www.php-fig.org/psr/psr-2/
10
+ *
11
+ */
12
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
13
+
14
+ class DUP_Flywheel_Host implements DUP_Host_interface
15
+ {
16
+
17
+ public static function getIdentifier()
18
+ {
19
+ return DUP_Custom_Host_Manager::HOST_FLYWHEEL;
20
+ }
21
+
22
+ public function isHosting()
23
+ {
24
+ $path = duplicator_get_home_path().'/.fw-config.php';
25
+ return apply_filters('duplicator_host_check', file_exists($path), self::getIdentifier());
26
+ }
27
+
28
+ public function init()
29
+ {
30
+
31
+ }
32
+ }
classes/host/class.godaddy.host.php CHANGED
@@ -1,15 +1,27 @@
1
  <?php
2
  defined("ABSPATH") or die("");
3
 
4
- class DUP_GoDaddy_Host {
5
- public static function init() {
6
- add_filter('duplicator_defaults_settings', array('DUP_GoDaddy_Host', 'defaultsSettings'));
 
 
 
 
 
 
 
 
7
  }
8
 
9
- public static function defaultsSettings($defaults) {
 
 
 
 
 
 
10
  $defaults['archive_build_mode'] = DUP_Archive_Build_Mode::DupArchive;
11
  return $defaults;
12
  }
13
- }
14
-
15
- DUP_GoDaddy_Host::init();
1
  <?php
2
  defined("ABSPATH") or die("");
3
 
4
+ class DUP_GoDaddy_Host implements DUP_Host_interface
5
+ {
6
+
7
+ public static function getIdentifier()
8
+ {
9
+ return DUP_Custom_Host_Manager::HOST_GODADDY;
10
+ }
11
+
12
+ public function isHosting()
13
+ {
14
+ return apply_filters('duplicator_godaddy_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/gd-system-plugin.php'));
15
  }
16
 
17
+ public function init()
18
+ {
19
+ add_filter('duplicator_defaults_settings', array(__CLASS__, 'defaultsSettings'));
20
+ }
21
+
22
+ public static function defaultsSettings($defaults)
23
+ {
24
  $defaults['archive_build_mode'] = DUP_Archive_Build_Mode::DupArchive;
25
  return $defaults;
26
  }
27
+ }
 
 
classes/host/class.liquidweb.host.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * wpengine custom hosting class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\HOST
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ class DUP_Liquidweb_Host implements DUP_Host_interface
14
+ {
15
+
16
+ public static function getIdentifier()
17
+ {
18
+ return DUP_Custom_Host_Manager::HOST_LIQUIDWEB;
19
+ }
20
+
21
+ public function isHosting()
22
+ {
23
+ return apply_filters('duplicator_liquidweb_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/liquid-web.php'));
24
+ }
25
+
26
+ public function init()
27
+ {
28
+
29
+ }
30
+ }
classes/host/class.pantheon.host.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * godaddy custom hosting class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\HOST
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ class DUP_Pantheon_Host implements DUP_Host_interface
14
+ {
15
+
16
+ public static function getIdentifier()
17
+ {
18
+ return DUP_Custom_Host_Manager::HOST_PANTHEON;
19
+ }
20
+
21
+ public function isHosting()
22
+ {
23
+ return apply_filters('duplicator_pantheon_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/pantheon.php'));
24
+ }
25
+
26
+ public function init()
27
+ {
28
+
29
+ }
30
+ }
classes/host/class.wordpresscom.host.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * godaddy custom hosting class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\HOST
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ class DUP_WordpressCom_Host implements DUP_Host_interface
14
+ {
15
+
16
+ public static function getIdentifier()
17
+ {
18
+ return DUP_Custom_Host_Manager::HOST_WORDPRESSCOM;
19
+ }
20
+
21
+ public function isHosting()
22
+ {
23
+ return apply_filters('duplicator_pro_wordpress_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/wpcomsh-loader.php'));
24
+ }
25
+
26
+ public function init()
27
+ {
28
+
29
+ }
30
+ }
classes/host/class.wpengine.host.php CHANGED
@@ -1,34 +1,49 @@
1
  <?php
2
  defined("ABSPATH") or die("");
 
3
  // New encryption class
4
 
5
- class DUP_WPEngine_Host {
6
- public static function init() {
7
- add_filter('duplicator_installer_file_path', array('DUP_WPEngine_Host', 'installerFilePath'), 10, 1);
 
 
8
  add_filter('duplicator_global_file_filters_on', '__return_true');
9
- add_filter('duplicator_global_file_filters', array('DUP_WPEngine_Host', 'globalFileFilters'), 10, 1);
10
- add_filter('duplicator_defaults_settings', array('DUP_WPEngine_Host', 'defaultsSettings'));
 
 
 
 
 
11
  }
12
 
13
- public static function installerFilePath($path) {
 
 
 
 
 
 
 
14
  $path_info = pathinfo($path);
15
- $newPath = $path;
16
  if ('php' == $path_info['extension']) {
17
- $newPath = substr_replace($path, '.txt', -4);
18
  }
19
  return $newPath;
20
  }
21
 
22
- public static function globalFileFilters($files) {
 
23
  $files[] = wp_normalize_path(WP_CONTENT_DIR).'/mysql.sql';
24
  return $files;
25
  }
26
 
27
- public static function defaultsSettings($defaults) {
 
28
  $defaults['package_zip_flush'] = '1';
29
  return $defaults;
30
  }
31
 
32
- }
33
-
34
- DUP_WPEngine_Host::init();
1
  <?php
2
  defined("ABSPATH") or die("");
3
+
4
  // New encryption class
5
 
6
+ class DUP_WPEngine_Host implements DUP_Host_interface
7
+ {
8
+ public function init()
9
+ {
10
+ add_filter('duplicator_installer_file_path', array(__CLASS__, 'installerFilePath'), 10, 1);
11
  add_filter('duplicator_global_file_filters_on', '__return_true');
12
+ add_filter('duplicator_global_file_filters', array(__CLASS__, 'globalFileFilters'), 10, 1);
13
+ add_filter('duplicator_defaults_settings', array(__CLASS__, 'defaultsSettings'));
14
+ }
15
+
16
+ public static function getIdentifier()
17
+ {
18
+ return DUP_Custom_Host_Manager::HOST_WPENGINE;
19
  }
20
 
21
+
22
+ public function isHosting()
23
+ {
24
+ return apply_filters('duplicator_wp_engine_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/wpengine-security-auditor.php'));
25
+ }
26
+
27
+ public static function installerFilePath($path)
28
+ {
29
  $path_info = pathinfo($path);
30
+ $newPath = $path;
31
  if ('php' == $path_info['extension']) {
32
+ $newPath = substr_replace($path, '.txt', -4);
33
  }
34
  return $newPath;
35
  }
36
 
37
+ public static function globalFileFilters($files)
38
+ {
39
  $files[] = wp_normalize_path(WP_CONTENT_DIR).'/mysql.sql';
40
  return $files;
41
  }
42
 
43
+ public static function defaultsSettings($defaults)
44
+ {
45
  $defaults['package_zip_flush'] = '1';
46
  return $defaults;
47
  }
48
 
49
+ }
 
 
classes/host/interface.host.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * interface for specific hostings class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\HOST
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ interface DUP_Host_interface
14
+ {
15
+
16
+ /**
17
+ * return the current host itentifier
18
+ *
19
+ * @return string
20
+ */
21
+ public static function getIdentifier();
22
+
23
+ /**
24
+ * @return bool true if is current host
25
+ */
26
+ public function isHosting();
27
+
28
+ /**
29
+ * the init function.
30
+ * is called only if isHosting is true
31
+ *
32
+ * @return void
33
+ */
34
+ public function init();
35
+ }
classes/package/class.pack.archive.filters.php CHANGED
@@ -34,6 +34,7 @@ class DUP_Archive_Filter_Scope_Directory extends DUP_Archive_Filter_Scope_Base
34
  public $Warning = array();
35
  //Items that are not readable
36
  public $Unreadable = array();
 
37
  }
38
 
39
  /**
34
  public $Warning = array();
35
  //Items that are not readable
36
  public $Unreadable = array();
37
+ public $AddonSites = array();
38
  }
39
 
40
  /**
classes/package/class.pack.database.php CHANGED
@@ -87,6 +87,11 @@ class DUP_DatabaseInfo
87
  */
88
  public $tableWiseRowCounts;
89
 
 
 
 
 
 
90
  /**
91
  * Integer field file structure of table, table name as key
92
  */
@@ -103,6 +108,23 @@ class DUP_DatabaseInfo
103
  $this->collationList = array();
104
  $this->tableWiseRowCounts = array();
105
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  }
107
 
108
  class DUP_Database
@@ -297,6 +319,9 @@ class DUP_Database
297
  }
298
  }
299
 
 
 
 
300
  $info['Status']['DB_Case'] = preg_match('/[A-Z]/', $wpdb->dbname) ? 'Warn' : 'Good';
301
  $info['Status']['DB_Rows'] = ($info['Rows'] > DUPLICATOR_SCAN_DB_ALL_ROWS) ? 'Warn' : 'Good';
302
  $info['Status']['DB_Size'] = ($info['Size'] > DUPLICATOR_SCAN_DB_ALL_SIZE) ? 'Warn' : 'Good';
@@ -304,6 +329,7 @@ class DUP_Database
304
  $info['Status']['TBL_Case'] = ($tblCaseFound) ? 'Warn' : 'Good';
305
  $info['Status']['TBL_Rows'] = ($tblRowsFound) ? 'Warn' : 'Good';
306
  $info['Status']['TBL_Size'] = ($tblSizeFound) ? 'Warn' : 'Good';
 
307
 
308
  $info['RawSize'] = $info['Size'];
309
  $info['Size'] = DUP_Util::byteSize($info['Size']) or "unknown";
@@ -311,7 +337,6 @@ class DUP_Database
311
  $info['TableList'] = $info['TableList'] or "unknown";
312
  $info['TableCount'] = $tblCount;
313
 
314
- $this->setInfoObj();
315
  $this->info->isTablesUpperCase = $tblCaseFound;
316
  $this->info->tablesBaseCount = $tblBaseCount;
317
  $this->info->tablesFinalCount = $tblCount;
@@ -377,6 +402,7 @@ class DUP_Database
377
  $cmd .= ' --quote-names';
378
  $cmd .= ' --skip-comments';
379
  $cmd .= ' --skip-set-charset';
 
380
  $cmd .= ' --allow-keywords';
381
  $cmd .= ' --no-tablespaces';
382
 
87
  */
88
  public $tableWiseRowCounts;
89
 
90
+ /**
91
+ * @var array List of triggers included in the database
92
+ */
93
+ public $triggerList = array();
94
+
95
  /**
96
  * Integer field file structure of table, table name as key
97
  */
108
  $this->collationList = array();
109
  $this->tableWiseRowCounts = array();
110
  }
111
+
112
+ public function addTriggers()
113
+ {
114
+ global $wpdb;
115
+
116
+ if (!is_array($triggers = $wpdb->get_results("SHOW TRIGGERS", ARRAY_A))) {
117
+ return;
118
+ }
119
+
120
+ foreach ($triggers as $trigger) {
121
+ $name = $trigger["Trigger"];
122
+ $create = $wpdb->get_row("SHOW CREATE TRIGGER `{$name}`", ARRAY_N);
123
+ $this->triggerList[$name] = array(
124
+ "create" => "DELIMITER ;;\n".$create[2].";;\nDELIMITER ;"
125
+ );
126
+ }
127
+ }
128
  }
129
 
130
  class DUP_Database
319
  }
320
  }
321
 
322
+ $this->setInfoObj();
323
+ $this->info->addTriggers();
324
+
325
  $info['Status']['DB_Case'] = preg_match('/[A-Z]/', $wpdb->dbname) ? 'Warn' : 'Good';
326
  $info['Status']['DB_Rows'] = ($info['Rows'] > DUPLICATOR_SCAN_DB_ALL_ROWS) ? 'Warn' : 'Good';
327
  $info['Status']['DB_Size'] = ($info['Size'] > DUPLICATOR_SCAN_DB_ALL_SIZE) ? 'Warn' : 'Good';
329
  $info['Status']['TBL_Case'] = ($tblCaseFound) ? 'Warn' : 'Good';
330
  $info['Status']['TBL_Rows'] = ($tblRowsFound) ? 'Warn' : 'Good';
331
  $info['Status']['TBL_Size'] = ($tblSizeFound) ? 'Warn' : 'Good';
332
+ $info['Status']['Triggers'] = count($this->info->triggerList) > 0 ? 'Warn' : 'Good';
333
 
334
  $info['RawSize'] = $info['Size'];
335
  $info['Size'] = DUP_Util::byteSize($info['Size']) or "unknown";
337
  $info['TableList'] = $info['TableList'] or "unknown";
338
  $info['TableCount'] = $tblCount;
339
 
 
340
  $this->info->isTablesUpperCase = $tblCaseFound;
341
  $this->info->tablesBaseCount = $tblBaseCount;
342
  $this->info->tablesFinalCount = $tblCount;
402
  $cmd .= ' --quote-names';
403
  $cmd .= ' --skip-comments';
404
  $cmd .= ' --skip-set-charset';
405
+ $cmd .= ' --skip-triggers';
406
  $cmd .= ' --allow-keywords';
407
  $cmd .= ' --no-tablespaces';
408
 
classes/package/class.pack.php CHANGED
@@ -286,7 +286,7 @@ class DUP_Package
286
  $report['LL']['Status']['TotalSize'] = ($rawTotalSize > DUPLICATOR_MAX_DUPARCHIVE_SIZE) ? 'Fail' : 'Good';
287
 
288
  $warnings = array(
289
- $report['SRV']['PHP']['ALL'],
290
  $report['SRV']['WP']['ALL'],
291
  $report['ARC']['Status']['Size'],
292
  $report['ARC']['Status']['Names'],
286
  $report['LL']['Status']['TotalSize'] = ($rawTotalSize > DUPLICATOR_MAX_DUPARCHIVE_SIZE) ? 'Fail' : 'Good';
287
 
288
  $warnings = array(
289
+ $report['SRV']['SYS']['ALL'],
290
  $report['SRV']['WP']['ALL'],
291
  $report['ARC']['Status']['Size'],
292
  $report['ARC']['Status']['Names'],
classes/ui/class.ui.notice.php CHANGED
@@ -12,16 +12,21 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
  * @copyright (c) 2017, Snapcreek LLC
13
  *
14
  */
15
- // Exit if accessed directly
16
- if (!defined('DUPLICATOR_VERSION'))
17
- exit;
18
 
19
  class DUP_UI_Notice
20
  {
21
 
22
- const OPTION_KEY_INSTALLER_HASH_NOTICE = 'duplicator_lite_inst_hash_notice';
23
  const OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL = 'duplicator_reactivate_plugins_after_installation';
24
- const OPTION_KEY_NEW_STORAGE_POSITION = 'duplicator_new_storage_position';
 
 
 
 
 
 
 
 
 
25
 
26
  /**
27
  * init notice actions
@@ -32,18 +37,22 @@ class DUP_UI_Notice
32
  'showReservedFilesNotice',
33
  'installAutoDeactivatePlugins',
34
  'showFeedBackNotice',
35
- //Enable in 1.3.40 maybe
36
- //'newStoragePositionOption'
 
37
  );
38
  foreach ($methods as $method) {
39
  add_action('admin_notices', array(__CLASS__, $method));
40
  }
41
  }
42
 
43
-
44
- public static function newStoragePositionOption()
 
 
 
45
  {
46
- if (get_option(self::OPTION_KEY_NEW_STORAGE_POSITION) != true) {
47
  return;
48
  }
49
 
@@ -52,31 +61,18 @@ class DUP_UI_Notice
52
  return;
53
  }
54
 
55
- if ($screen->id == 'duplicator_page_duplicator-settings') {
56
- $action = filter_input(INPUT_POST, 'action', FILTER_SANITIZE_STRING);
57
- $storagePostion = filter_input(INPUT_POST, 'storage_position', FILTER_SANITIZE_STRING);
58
- if ($action == 'save' && $storagePostion == DUP_Settings::STORAGE_POSITION_WP_CONTENT) {
59
- delete_option(self::OPTION_KEY_INSTALLER_HASH_NOTICE);
60
- return;
61
- }
62
- }
63
-
64
- if (DUP_Settings::get('storage_position') == DUP_Settings::STORAGE_POSITION_WP_CONTENT) {
65
- delete_option(self::OPTION_KEY_NEW_STORAGE_POSITION);
66
- return;
67
- }
68
  ?>
69
- <div class="notice notice-success duplicator-admin-notice is-dismissible" data-to-dismiss="<?php echo esc_attr(self::OPTION_KEY_NEW_STORAGE_POSITION); ?>" >
70
  <p>
71
- <?php esc_html_e('Duplicator can now have a new storage location inside the wp-content folder.', 'duplicator'); ?><br>
72
  <?php
73
- echo sprintf(__('If this option is enabled all packages will be moved from <i>%s</i> to <i>%s</i>', 'duplicator'),
74
- esc_html(DUP_Settings::getSsdirPathLegacy()),
75
- esc_html(DUP_Settings::getSsdirPathWpCont()));
76
  ?>
77
  </p>
78
  <p>
79
- <?php echo sprintf(__('To enable this option or to get more information, open the <a href="%s">General Settings</a>', 'duplicator'), 'admin.php?page=duplicator-settings'); ?>
80
  </p>
81
  </div>
82
  <?php
@@ -226,7 +222,9 @@ class DUP_UI_Notice
226
  return;
227
  }
228
 
229
- $packagesCount = $GLOBALS['wpdb']->get_var('SELECT count(id) FROM '.DUP_Util::getTablePrefix().'duplicator_packages WHERE status=100');
 
 
230
 
231
  if ($packagesCount < DUPLICATOR_FEEDBACK_NOTICE_SHOW_AFTER_NO_PACKAGE) {
232
  return;
@@ -259,4 +257,80 @@ class DUP_UI_Notice
259
  </div>
260
  <?php
261
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  }
12
  * @copyright (c) 2017, Snapcreek LLC
13
  *
14
  */
 
 
 
15
 
16
  class DUP_UI_Notice
17
  {
18
 
 
19
  const OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL = 'duplicator_reactivate_plugins_after_installation';
20
+
21
+ //TEMPLATE VALUE: This is a just a simple example for setting up quick notices
22
+ const OPTION_KEY_NEW_NOTICE_TEMPLATE = 'duplicator_new_template_notice';
23
+ const OPTION_KEY_IS_PRO_ENABLE_NOTICE_DISMISSED = 'duplicator_is_pro_enable_notice_dismissed';
24
+ const OPTION_KEY_IS_MU_NOTICE_DISMISSED = 'duplicator_is_mu_notice_dismissed';
25
+
26
+ const GEN_INFO_NOTICE = 0;
27
+ const GEN_SUCCESS_NOTICE = 1;
28
+ const GEN_WARNING_NOTICE = 2;
29
+ const GEN_ERROR_NOTICE = 3;
30
 
31
  /**
32
  * init notice actions
37
  'showReservedFilesNotice',
38
  'installAutoDeactivatePlugins',
39
  'showFeedBackNotice',
40
+ 'showNoExportCapabilityNotice',
41
+ //FUTURE NOTICE TEMPLATE
42
+ //'newNotice_TEMPLATE',
43
  );
44
  foreach ($methods as $method) {
45
  add_action('admin_notices', array(__CLASS__, $method));
46
  }
47
  }
48
 
49
+ /**
50
+ * NOTICE SAMPLE: This method serves as a quick example for how to quickly setup a new notice
51
+ * Please do not edit this method, but simply use to copy a new setup.
52
+ */
53
+ public static function newNotice_TEMPLATE()
54
  {
55
+ if (get_option(self::OPTION_KEY_NEW_NOTICE_TEMPLATE) != true) {
56
  return;
57
  }
58
 
61
  return;
62
  }
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  ?>
65
+ <div class="notice notice-success duplicator-admin-notice is-dismissible" data-to-dismiss="<?php echo esc_attr(self::OPTION_KEY_NEW_NOTICE_TEMPLATE); ?>" >
66
  <p>
67
+ <?php esc_html_e('NOTICE: This is a sample message notice demo.', 'duplicator'); ?><br>
68
  <?php
69
+ echo sprintf(__('Example for passing dynamic data to notice message <i>%s</i> to <i>%s</i>', 'duplicator'),
70
+ esc_html("test 1"),
71
+ esc_html(time()));
72
  ?>
73
  </p>
74
  <p>
75
+ <?php echo sprintf(__('More info here: Goto <a href="%s">General Settings</a>', 'duplicator'), 'admin.php?page=duplicator-settings'); ?>
76
  </p>
77
  </div>
78
  <?php
222
  return;
223
  }
224
 
225
+ // not using DUP_Util::getTablePrefix() in place of $tablePrefix because DUP_UI_Notice included initially (Duplicator\Lite\Requirement is depended on the DUP_UI_Notice)
226
+ $tablePrefix = (is_multisite() && is_plugin_active_for_network('duplicator/duplicator.php')) ? $GLOBALS['wpdb']->base_prefix : $GLOBALS['wpdb']->prefix;
227
+ $packagesCount = $GLOBALS['wpdb']->get_var('SELECT count(id) FROM '.$tablePrefix.'duplicator_packages WHERE status=100');
228
 
229
  if ($packagesCount < DUPLICATOR_FEEDBACK_NOTICE_SHOW_AFTER_NO_PACKAGE) {
230
  return;
257
  </div>
258
  <?php
259
  }
260
+
261
+ /**
262
+ * Shows a display message in the wp-admin if the logged in user role has not export capability
263
+ *
264
+ * @return void
265
+ */
266
+ public static function showNoExportCapabilityNotice()
267
+ {
268
+ if (is_admin() && in_array('administrator', $GLOBALS['current_user']->roles) && !current_user_can('export')) {
269
+ $errorMessage = __('<strong>Duplicator</strong><hr> Your logged-in user role does not have export capability so you don\'t have access to Duplicator functionality.', 'duplicator').
270
+ "<br>".
271
+ sprintf(__('<strong>RECOMMENDATION:</strong> Add export capability to your role. See FAQ: <a target="_blank" href="%s">%s</a>', 'duplicator'), 'https://snapcreek.com/duplicator/docs/faqs-tech/#faq-licensing-040-q', __('Why is the Duplicator/Packages menu missing from my admin menu?', 'duplicator'));
272
+ DUP_UI_Notice::displayGeneralAdminNotice($errorMessage, self::GEN_ERROR_NOTICE, true);
273
+ }
274
+ }
275
+
276
+ /**
277
+ * display genral admin notice by printing it
278
+ *
279
+ * @param string $htmlMsg html code to be printed
280
+ * @param integer $noticeType constant value of SELF::GEN_
281
+ * @param boolean $isDismissible whether the notice is dismissable or not. Default is true
282
+ * @param array|string $extraClasses add more classes to the notice div
283
+ * @return void
284
+ */
285
+ public static function displayGeneralAdminNotice($htmlMsg, $noticeType, $isDismissible = true, $extraClasses = array())
286
+ {
287
+ if (empty($extraClasses)) {
288
+ $classes = array();
289
+ } elseif (is_array($extraClasses)) {
290
+ $classes = $extraClasses;
291
+ } else {
292
+ $classes = array($extraClasses);
293
+ }
294
+
295
+ $classes[] = 'notice';
296
+
297
+ switch ($noticeType) {
298
+ case self::GEN_INFO_NOTICE:
299
+ $classes[] = 'notice-info';
300
+ break;
301
+ case self::GEN_SUCCESS_NOTICE:
302
+ $classes[] = 'notice-success';
303
+ break;
304
+ case self::GEN_WARNING_NOTICE:
305
+ $classes[] = 'notice-warning';
306
+ break;
307
+ case self::GEN_ERROR_NOTICE:
308
+ $classes[] = 'notice-error';
309
+ break;
310
+ default:
311
+ throw new Exception('Invalid Admin notice type!');
312
+ }
313
+
314
+ if ($isDismissible) {
315
+ $classes[] = 'is-dismissible';
316
+ }
317
+
318
+ $classesStr = implode(' ', $classes);
319
+ ?>
320
+ <div class="<?php echo esc_attr($classesStr); ?>">
321
+ <p>
322
+ <?php
323
+ if (self::GEN_ERROR_NOTICE == $noticeType) {
324
+ ?>
325
+ <i class='fa fa-exclamation-triangle'></i>
326
+ <?php
327
+ }
328
+ ?>
329
+ <?php
330
+ echo $htmlMsg;
331
+ ?>
332
+ </p>
333
+ </div>
334
+ <?php
335
+ }
336
  }
ctrls/class.web.services.php CHANGED
@@ -1,232 +1,235 @@
1
- <?php
2
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
-
4
- class DUP_Web_Services
5
- {
6
-
7
- /**
8
- * init ajax actions
9
- */
10
- public static function init()
11
- {
12
- add_action('wp_ajax_duplicator_reset_all_settings', array(__CLASS__, 'ajax_reset_all'));
13
- add_action('wp_ajax_duplicator_set_admin_notice_viewed', array(__CLASS__, 'set_admin_notice_viewed'));
14
- add_action('wp_ajax_duplicator_admin_notice_to_dismiss', array(__CLASS__, 'admin_notice_to_dismiss'));
15
- add_action('wp_ajax_duplicator_download_installer', array(__CLASS__, 'duplicator_download_installer'));
16
- }
17
-
18
- /**
19
- *
20
- * @param DUP_Package $package
21
- */
22
- public static function package_delete_callback($package)
23
- {
24
- $package->delete();
25
- }
26
-
27
- /**
28
- * reset all ajax action
29
- *
30
- * the output must be json
31
- */
32
- public static function ajax_reset_all()
33
- {
34
- ob_start();
35
- try {
36
- DUP_Handler::init_error_handler();
37
-
38
- if (!check_ajax_referer('duplicator_reset_all_settings', 'nonce', false)) {
39
- DUP_LOG::Trace('Security issue');
40
- throw new Exception('Security issue');
41
- }
42
- DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
43
-
44
- /** Execute function * */
45
- $error = false;
46
- $result = array(
47
- 'data' => array(),
48
- 'html' => '',
49
- 'message' => ''
50
- );
51
-
52
- DUP_Package::by_status_callback(array(__CLASS__, 'package_delete_callback'), array(
53
- array('op' => '<', 'status' => DUP_PackageStatus::COMPLETE)
54
- ));
55
-
56
- /** reset active package id * */
57
- DUP_Settings::Set('active_package_id', -1);
58
- DUP_Settings::Save();
59
-
60
- /** Clean tmp folder * */
61
- DUP_Package::not_active_files_tmp_cleanup();
62
-
63
- //throw new Exception('force error test');
64
- }
65
- catch (Exception $e) {
66
- $error = true;
67
- $result['message'] = $e->getMessage();
68
- }
69
-
70
- /** Intercept output * */
71
- $result['html'] = ob_get_clean();
72
-
73
- /** check error and return json * */
74
- if ($error) {
75
- wp_send_json_error($result);
76
- } else {
77
- wp_send_json_success($result);
78
- }
79
- }
80
-
81
- public static function duplicator_download_installer()
82
- {
83
- check_ajax_referer('duplicator_download_installer', 'nonce');
84
-
85
- $isValid = true;
86
- $inputData = filter_input_array(INPUT_GET, array(
87
- 'id' => array(
88
- 'filter' => FILTER_VALIDATE_INT,
89
- 'flags' => FILTER_REQUIRE_SCALAR,
90
- 'options' => array(
91
- 'default' => false
92
- )
93
- ),
94
- 'hash' => array(
95
- 'filter' => FILTER_SANITIZE_STRING,
96
- 'flags' => FILTER_REQUIRE_SCALAR,
97
- 'options' => array(
98
- 'default' => false
99
- )
100
- )
101
- ));
102
-
103
- $packageId = $inputData['id'];
104
- $hash = $inputData['hash'];
105
-
106
- if (!$packageId || !$hash) {
107
- $isValid = false;
108
- }
109
-
110
- try {
111
- DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
112
-
113
- if (!$isValid) {
114
- throw new Exception(__("Invalid request"));
115
- }
116
-
117
- if (($package = DUP_Package::getByID($packageId)) == null) {
118
- throw new Exception(__("Invalid request."));
119
- }
120
-
121
- if ($hash !== $package->Hash) {
122
- throw new Exception(__("Invalid request."));
123
- }
124
-
125
- $fileName = $package->getInstDownloadName();
126
- $filepath = DUP_Settings::getSsdirPath().'/'.$package->Installer->File;
127
-
128
- // Process download
129
- if (!file_exists($filepath)) {
130
- throw new Exception(__("Invalid request."));
131
- }
132
-
133
- // Clean output buffer
134
- if (ob_get_level() !== 0 && @ob_end_clean() === FALSE) {
135
- @ob_clean();
136
- }
137
-
138
- header('Content-Description: File Transfer');
139
- header('Content-Type: application/octet-stream');
140
- header('Content-Disposition: attachment; filename="'.$fileName.'"');
141
- header('Expires: 0');
142
- header('Cache-Control: must-revalidate');
143
- header('Pragma: public');
144
- header('Content-Length: '.filesize($filepath));
145
- flush(); // Flush system output buffer
146
-
147
- try {
148
- $fp = @fopen($filepath, 'r');
149
- if (false === $fp) {
150
- throw new Exception('Fail to open the file '.$filepath);
151
- }
152
- while (!feof($fp) && ($data = fread($fp, DUPLICATOR_BUFFER_READ_WRITE_SIZE)) !== FALSE) {
153
- echo $data;
154
- }
155
- @fclose($fp);
156
- }
157
- catch (Exception $e) {
158
- readfile($filepath);
159
- }
160
- exit;
161
- }
162
- catch (Exception $ex) {
163
- //Prevent brute force
164
- sleep(2);
165
- wp_die($ex->getMessage());
166
- }
167
- }
168
-
169
- public static function set_admin_notice_viewed()
170
- {
171
- DUP_Handler::init_error_handler();
172
-
173
- try{
174
- DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
175
-
176
- if (!wp_verify_nonce($_REQUEST['nonce'], 'duplicator_set_admin_notice_viewed')) {
177
- DUP_Log::trace(__('Security issue', 'duplicator'));
178
- throw new Exception('Security issue');
179
- }
180
-
181
- $notice_id = DupLiteSnapLibUtil::filterInputRequest('notice_id', FILTER_SANITIZE_STRING);
182
-
183
- if (empty($notice_id)) {
184
- throw new Exception(__('Invalid Request', 'duplicator'));
185
- }
186
-
187
- $notices = get_user_meta(get_current_user_id(), DUPLICATOR_ADMIN_NOTICES_USER_META_KEY, true);
188
- if (empty($notices)) {
189
- $notices = array();
190
- }
191
-
192
- if (!isset($notices[$notice_id])) {
193
- throw new Exception(__("Notice with that ID doesn't exist.", 'duplicator'));
194
- }
195
-
196
- $notices[$notice_id] = 'true';
197
- update_user_meta(get_current_user_id(), DUPLICATOR_ADMIN_NOTICES_USER_META_KEY, $notices);
198
- }
199
- catch (Exception $ex) {
200
- wp_die($ex->getMessage());
201
- }
202
- }
203
-
204
- public static function admin_notice_to_dismiss()
205
- {
206
- try {
207
- DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
208
-
209
- $nonce = filter_input(INPUT_POST, 'nonce', FILTER_SANITIZE_STRING);
210
- if (!wp_verify_nonce($nonce, 'duplicator_admin_notice_to_dismiss')) {
211
- DUP_Log::trace('Security issue');
212
- throw new Exception('Security issue');
213
- }
214
-
215
- $noticeToDismiss = filter_input(INPUT_POST, 'notice', FILTER_SANITIZE_STRING);
216
- switch ($noticeToDismiss) {
217
- case DUP_UI_Notice::OPTION_KEY_INSTALLER_HASH_NOTICE:
218
- case DUP_UI_Notice::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL:
219
- case DUP_UI_Notice::OPTION_KEY_NEW_STORAGE_POSITION:
220
- delete_option($noticeToDismiss);
221
- break;
222
- default:
223
- throw new Exception('Notice invalid');
224
- }
225
- }
226
- catch (Exception $e) {
227
- wp_send_json_error($e->getMessage());
228
- }
229
-
230
- wp_send_json_success();
231
- }
232
- }
 
 
 
1
+ <?php
2
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+
4
+ class DUP_Web_Services
5
+ {
6
+
7
+ /**
8
+ * init ajax actions
9
+ */
10
+ public static function init()
11
+ {
12
+ add_action('wp_ajax_duplicator_reset_all_settings', array(__CLASS__, 'ajax_reset_all'));
13
+ add_action('wp_ajax_duplicator_set_admin_notice_viewed', array(__CLASS__, 'set_admin_notice_viewed'));
14
+ add_action('wp_ajax_duplicator_admin_notice_to_dismiss', array(__CLASS__, 'admin_notice_to_dismiss'));
15
+ add_action('wp_ajax_duplicator_download_installer', array(__CLASS__, 'duplicator_download_installer'));
16
+ }
17
+
18
+ /**
19
+ *
20
+ * @param DUP_Package $package
21
+ */
22
+ public static function package_delete_callback($package)
23
+ {
24
+ $package->delete();
25
+ }
26
+
27
+ /**
28
+ * reset all ajax action
29
+ *
30
+ * the output must be json
31
+ */
32
+ public static function ajax_reset_all()
33
+ {
34
+ ob_start();
35
+ try {
36
+ DUP_Handler::init_error_handler();
37
+
38
+ if (!check_ajax_referer('duplicator_reset_all_settings', 'nonce', false)) {
39
+ DUP_LOG::Trace('Security issue');
40
+ throw new Exception('Security issue');
41
+ }
42
+ DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
43
+
44
+ /** Execute function * */
45
+ $error = false;
46
+ $result = array(
47
+ 'data' => array(),
48
+ 'html' => '',
49
+ 'message' => ''
50
+ );
51
+
52
+ DUP_Package::by_status_callback(array(__CLASS__, 'package_delete_callback'), array(
53
+ array('op' => '<', 'status' => DUP_PackageStatus::COMPLETE)
54
+ ));
55
+
56
+ /** reset active package id * */
57
+ DUP_Settings::Set('active_package_id', -1);
58
+ DUP_Settings::Save();
59
+
60
+ /** Clean tmp folder * */
61
+ DUP_Package::not_active_files_tmp_cleanup();
62
+
63
+ //throw new Exception('force error test');
64
+ }
65
+ catch (Exception $e) {
66
+ $error = true;
67
+ $result['message'] = $e->getMessage();
68
+ }
69
+
70
+ /** Intercept output * */
71
+ $result['html'] = ob_get_clean();
72
+
73
+ /** check error and return json * */
74
+ if ($error) {
75
+ wp_send_json_error($result);
76
+ } else {
77
+ wp_send_json_success($result);
78
+ }
79
+ }
80
+
81
+ public static function duplicator_download_installer()
82
+ {
83
+ check_ajax_referer('duplicator_download_installer', 'nonce');
84
+
85
+ $isValid = true;
86
+ $inputData = filter_input_array(INPUT_GET, array(
87
+ 'id' => array(
88
+ 'filter' => FILTER_VALIDATE_INT,
89
+ 'flags' => FILTER_REQUIRE_SCALAR,
90
+ 'options' => array(
91
+ 'default' => false
92
+ )
93
+ ),
94
+ 'hash' => array(
95
+ 'filter' => FILTER_SANITIZE_STRING,
96
+ 'flags' => FILTER_REQUIRE_SCALAR,
97
+ 'options' => array(
98
+ 'default' => false
99
+ )
100
+ )
101
+ ));
102
+
103
+ $packageId = $inputData['id'];
104
+ $hash = $inputData['hash'];
105
+
106
+ if (!$packageId || !$hash) {
107
+ $isValid = false;
108
+ }
109
+
110
+ try {
111
+ DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
112
+
113
+ if (!$isValid) {
114
+ throw new Exception(__("Invalid request"));
115
+ }
116
+
117
+ if (($package = DUP_Package::getByID($packageId)) == null) {
118
+ throw new Exception(__("Invalid request."));
119
+ }
120
+
121
+ if ($hash !== $package->Hash) {
122
+ throw new Exception(__("Invalid request."));
123
+ }
124
+
125
+ $fileName = $package->getInstDownloadName();
126
+ $filepath = DUP_Settings::getSsdirPath().'/'.$package->Installer->File;
127
+
128
+ // Process download
129
+ if (!file_exists($filepath)) {
130
+ throw new Exception(__("Invalid request."));
131
+ }
132
+
133
+ // Clean output buffer
134
+ if (ob_get_level() !== 0 && @ob_end_clean() === FALSE) {
135
+ @ob_clean();
136
+ }
137
+
138
+ header('Content-Description: File Transfer');
139
+ header('Content-Type: application/octet-stream');
140
+ header('Content-Disposition: attachment; filename="'.$fileName.'"');
141
+ header('Expires: 0');
142
+ header('Cache-Control: must-revalidate');
143
+ header('Pragma: public');
144
+ header('Content-Length: '.filesize($filepath));
145
+ flush(); // Flush system output buffer
146
+
147
+ try {
148
+ $fp = @fopen($filepath, 'r');
149
+ if (false === $fp) {
150
+ throw new Exception('Fail to open the file '.$filepath);
151
+ }
152
+ while (!feof($fp) && ($data = fread($fp, DUPLICATOR_BUFFER_READ_WRITE_SIZE)) !== FALSE) {
153
+ echo $data;
154
+ }
155
+ @fclose($fp);
156
+ }
157
+ catch (Exception $e) {
158
+ readfile($filepath);
159
+ }
160
+ exit;
161
+ }
162
+ catch (Exception $ex) {
163
+ //Prevent brute force
164
+ sleep(2);
165
+ wp_die($ex->getMessage());
166
+ }
167
+ }
168
+
169
+ public static function set_admin_notice_viewed()
170
+ {
171
+ DUP_Handler::init_error_handler();
172
+
173
+ try{
174
+ DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
175
+
176
+ if (!wp_verify_nonce($_REQUEST['nonce'], 'duplicator_set_admin_notice_viewed')) {
177
+ DUP_Log::trace(__('Security issue', 'duplicator'));
178
+ throw new Exception('Security issue');
179
+ }
180
+
181
+ $notice_id = DupLiteSnapLibUtil::filterInputRequest('notice_id', FILTER_SANITIZE_STRING);
182
+
183
+ if (empty($notice_id)) {
184
+ throw new Exception(__('Invalid Request', 'duplicator'));
185
+ }
186
+
187
+ $notices = get_user_meta(get_current_user_id(), DUPLICATOR_ADMIN_NOTICES_USER_META_KEY, true);
188
+ if (empty($notices)) {
189
+ $notices = array();
190
+ }
191
+
192
+ if (!isset($notices[$notice_id])) {
193
+ throw new Exception(__("Notice with that ID doesn't exist.", 'duplicator'));
194
+ }
195
+
196
+ $notices[$notice_id] = 'true';
197
+ update_user_meta(get_current_user_id(), DUPLICATOR_ADMIN_NOTICES_USER_META_KEY, $notices);
198
+ }
199
+ catch (Exception $ex) {
200
+ wp_die($ex->getMessage());
201
+ }
202
+ }
203
+
204
+ public static function admin_notice_to_dismiss()
205
+ {
206
+ try {
207
+ DUP_Util::hasCapability('export', DUP_Util::SECURE_ISSUE_THROW);
208
+
209
+ $nonce = filter_input(INPUT_POST, 'nonce', FILTER_SANITIZE_STRING);
210
+ if (!wp_verify_nonce($nonce, 'duplicator_admin_notice_to_dismiss')) {
211
+ DUP_Log::trace('Security issue');
212
+ throw new Exception('Security issue');
213
+ }
214
+
215
+ $noticeToDismiss = filter_input(INPUT_POST, 'notice', FILTER_SANITIZE_STRING);
216
+ switch ($noticeToDismiss) {
217
+ case DUP_UI_Notice::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL:
218
+ case DUP_UI_Notice::OPTION_KEY_NEW_NOTICE_TEMPLATE:
219
+ delete_option($noticeToDismiss);
220
+ break;
221
+ case DUP_UI_Notice::OPTION_KEY_IS_PRO_ENABLE_NOTICE_DISMISSED:
222
+ case DUP_UI_Notice::OPTION_KEY_IS_MU_NOTICE_DISMISSED:
223
+ update_option($noticeToDismiss, true);
224
+ break;
225
+ default:
226
+ throw new Exception('Notice invalid');
227
+ }
228
+ }
229
+ catch (Exception $e) {
230
+ wp_send_json_error($e->getMessage());
231
+ }
232
+
233
+ wp_send_json_success();
234
+ }
235
+ }
define.php CHANGED
@@ -5,8 +5,8 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
5
 
6
  if (function_exists('plugin_dir_url'))
7
  {
8
- define('DUPLICATOR_VERSION', '1.3.40.1');
9
- define('DUPLICATOR_VERSION_BUILD', '2020-12-14_09:00');
10
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
11
  define('DUPLICATOR_SITE_URL', get_site_url());
12
 
@@ -28,7 +28,7 @@ if (function_exists('plugin_dir_url'))
28
  define('DUPLICATOR_INSTALL_PHP', 'installer.php');
29
  define('DUPLICATOR_INSTALL_BAK', 'installer-backup.php');
30
  define('DUPLICATOR_INSTALLER_HASH_PATTERN', '[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]');
31
- define('DUPLICATOR_INSTALL_SITE_OVERWRITE_ON', false);
32
 
33
  //GENERAL CONSTRAINTS
34
  define('DUPLICATOR_PHP_MAX_MEMORY', 4294967296); // 4096MB
@@ -60,7 +60,12 @@ if (function_exists('plugin_dir_url'))
60
  define("DUPLICATOR_FEEDBACK_NOTICE_SHOW_AFTER_NO_PACKAGE", 5);
61
 
62
  $GLOBALS['DUPLICATOR_SERVER_LIST'] = array('Apache','LiteSpeed', 'Nginx', 'Lighttpd', 'IIS', 'WebServerX', 'uWSGI');
63
- $GLOBALS['DUPLICATOR_OPTS_DELETE'] = array('duplicator_ui_view_state', 'duplicator_package_active', 'duplicator_settings');
 
 
 
 
 
64
  $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON'] = true;
65
  $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS'] = array(
66
  'error_log',
5
 
6
  if (function_exists('plugin_dir_url'))
7
  {
8
+ define('DUPLICATOR_VERSION', '1.4.0');
9
+ define('DUPLICATOR_VERSION_BUILD', '2021-03-1_09:00');
10
  define('DUPLICATOR_PLUGIN_URL', plugin_dir_url(__FILE__));
11
  define('DUPLICATOR_SITE_URL', get_site_url());
12
 
28
  define('DUPLICATOR_INSTALL_PHP', 'installer.php');
29
  define('DUPLICATOR_INSTALL_BAK', 'installer-backup.php');
30
  define('DUPLICATOR_INSTALLER_HASH_PATTERN', '[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]');
31
+ define('DUPLICATOR_INSTALL_SITE_OVERWRITE_ON', true);
32
 
33
  //GENERAL CONSTRAINTS
34
  define('DUPLICATOR_PHP_MAX_MEMORY', 4294967296); // 4096MB
60
  define("DUPLICATOR_FEEDBACK_NOTICE_SHOW_AFTER_NO_PACKAGE", 5);
61
 
62
  $GLOBALS['DUPLICATOR_SERVER_LIST'] = array('Apache','LiteSpeed', 'Nginx', 'Lighttpd', 'IIS', 'WebServerX', 'uWSGI');
63
+ $GLOBALS['DUPLICATOR_OPTS_DELETE'] = array(
64
+ 'duplicator_ui_view_state',
65
+ 'duplicator_package_active',
66
+ 'duplicator_settings',
67
+ 'duplicator_is_pro_enable_notice_dismissed'
68
+ );
69
  $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON'] = true;
70
  $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS'] = array(
71
  'error_log',
duplicator-main.php ADDED
@@ -0,0 +1,406 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ *
5
+ * @package Duplicator
6
+ * @copyright (c) 2021, Snapcreek LLC
7
+ *
8
+ */
9
+ defined('ABSPATH') || exit;
10
+
11
+ use Duplicator\Lite as Duplicator;
12
+
13
+ /* @var $currentPluginBootFile string */
14
+
15
+ // CHECK IF PLUGIN CAN BE EXECTUED
16
+ require_once(__DIR__ . "/tools/Lite/Requirements.php");
17
+ if (Duplicator\Requirements::canRun($currentPluginBootFile) === false) {
18
+ return;
19
+ } else {
20
+ // NOTE: Plugin code must be inside a conditional block to prevent functions definition, simple return is not enough
21
+ define('DUPLICATOR_LITE_PATH', dirname($currentPluginBootFile));
22
+ define('DUPLICATOR_LITE_FILE', $currentPluginBootFile);
23
+ define('DUPLICATOR_LITE_PLUGIN_URL', plugins_url('', $currentPluginBootFile));
24
+
25
+ if (!defined('DUPXABSPATH')) {
26
+ define('DUPXABSPATH', dirname(DUPLICATOR_LITE_FILE));
27
+ }
28
+
29
+ require_once("helper.php");
30
+ require_once("define.php");
31
+ if (is_admin() == true) {
32
+ if (defined('DUPLICATOR_DEACTIVATION_FEEDBACK') && DUPLICATOR_DEACTIVATION_FEEDBACK) {
33
+ require_once 'deactivation.php';
34
+ }
35
+ require_once 'lib/snaplib/snaplib.all.php';
36
+ require_once 'classes/class.constants.php';
37
+ require_once 'classes/host/class.custom.host.manager.php';
38
+ require_once 'classes/class.settings.php';
39
+ require_once 'classes/class.logging.php';
40
+ require_once 'classes/class.plugin.upgrade.php';
41
+ require_once 'classes/utilities/class.u.php';
42
+ require_once 'classes/utilities/class.u.string.php';
43
+ require_once 'classes/utilities/class.u.validator.php';
44
+ require_once 'classes/class.db.php';
45
+ require_once 'classes/class.server.php';
46
+ require_once 'classes/ui/class.ui.viewstate.php';
47
+ require_once 'classes/ui/class.ui.notice.php';
48
+ require_once 'classes/package/class.pack.php';
49
+ require_once 'views/packages/screen.php';
50
+
51
+ //Controllers
52
+ require_once 'ctrls/ctrl.package.php';
53
+ require_once 'ctrls/ctrl.tools.php';
54
+ require_once 'ctrls/ctrl.ui.php';
55
+ require_once 'ctrls/class.web.services.php';
56
+
57
+ //Init Class
58
+ DUP_Custom_Host_Manager::getInstance()->init();
59
+ DUP_Settings::init();
60
+ DUP_Log::Init();
61
+ DUP_Util::init();
62
+ DUP_DB::init();
63
+
64
+ /** ========================================================
65
+ * ACTIVATE/DEACTIVE/UPDATE HOOKS
66
+ * ===================================================== */
67
+ register_activation_hook(DUPLICATOR_LITE_FILE, array('DUP_LITE_Plugin_Upgrade', 'onActivationAction'));
68
+ register_deactivation_hook(DUPLICATOR_LITE_FILE, 'duplicator_deactivate');
69
+
70
+ /**
71
+ * Hooked into `plugins_loaded`. Routines used to update the plugin
72
+ *
73
+ * @access global
74
+ * @return null
75
+ */
76
+ function duplicator_update()
77
+ {
78
+ if (DUPLICATOR_VERSION != get_option(DUP_LITE_Plugin_Upgrade::DUP_VERSION_OPT_KEY)) {
79
+ DUP_LITE_Plugin_Upgrade::onActivationAction();
80
+ // $snapShotDirPerm = substr(sprintf("%o", fileperms(DUP_Settings::getSsdirPath())),-4);
81
+ }
82
+ load_plugin_textdomain('duplicator');
83
+ }
84
+
85
+ /**
86
+ * Hooked into `register_deactivation_hook`. Routines used to deactivate the plugin
87
+ * For uninstall see uninstall.php WordPress by default will call the uninstall.php file
88
+ *
89
+ * @access global
90
+ * @return null
91
+ */
92
+ function duplicator_deactivate()
93
+ {
94
+ //Logic has been added to uninstall.php
95
+ }
96
+ /** ========================================================
97
+ * ACTION HOOKS
98
+ * ===================================================== */
99
+ add_action('plugins_loaded', 'duplicator_update');
100
+ add_action('plugins_loaded', 'duplicator_wpfront_integrate');
101
+
102
+ function duplicator_load_textdomain()
103
+ {
104
+ load_plugin_textdomain('duplicator', false, false);
105
+ }
106
+ add_action('plugins_loaded', 'duplicator_load_textdomain');
107
+
108
+ add_action('admin_init', 'duplicator_admin_init');
109
+ add_action('admin_menu', 'duplicator_menu');
110
+ add_action('admin_enqueue_scripts', 'duplicator_admin_enqueue_scripts');
111
+ DUP_UI_Notice::init();
112
+
113
+ //CTRL ACTIONS
114
+ DUP_Web_Services::init();
115
+ add_action('wp_ajax_duplicator_active_package_info', 'duplicator_active_package_info');
116
+ add_action('wp_ajax_duplicator_package_scan', 'duplicator_package_scan');
117
+ add_action('wp_ajax_duplicator_package_build', 'duplicator_package_build');
118
+ add_action('wp_ajax_duplicator_package_delete', 'duplicator_package_delete');
119
+ add_action('wp_ajax_duplicator_duparchive_package_build', 'duplicator_duparchive_package_build');
120
+
121
+ $GLOBALS['CTRLS_DUP_CTRL_UI'] = new DUP_CTRL_UI();
122
+ $GLOBALS['CTRLS_DUP_CTRL_Tools'] = new DUP_CTRL_Tools();
123
+ $GLOBALS['CTRLS_DUP_CTRL_Package'] = new DUP_CTRL_Package();
124
+
125
+ /**
126
+ * User role editor integration
127
+ *
128
+ * @access global
129
+ * @return null
130
+ */
131
+ function duplicator_wpfront_integrate()
132
+ {
133
+ if (DUP_Settings::Get('wpfront_integrate')) {
134
+ do_action('wpfront_user_role_editor_duplicator_init', array('export', 'manage_options', 'read'));
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Hooked into `admin_init`. Init routines for all admin pages
140
+ *
141
+ * @access global
142
+ * @return null
143
+ */
144
+ function duplicator_admin_init()
145
+ {
146
+ /* CSS */
147
+ wp_register_style('dup-jquery-ui', DUPLICATOR_PLUGIN_URL . 'assets/css/jquery-ui.css', null, "1.11.2");
148
+ wp_register_style('dup-font-awesome', DUPLICATOR_PLUGIN_URL . 'assets/css/fontawesome-all.min.css', null, '5.7.2');
149
+ wp_register_style('dup-plugin-global-style', DUPLICATOR_PLUGIN_URL . 'assets/css/global_admin_style.css', null, DUPLICATOR_VERSION);
150
+ wp_register_style('dup-plugin-style', DUPLICATOR_PLUGIN_URL . 'assets/css/style.css', array('dup-plugin-global-style'), DUPLICATOR_VERSION);
151
+
152
+ wp_register_style('dup-jquery-qtip', DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.css', null, '2.2.1');
153
+ wp_register_style('dup-parsley-style', DUPLICATOR_PLUGIN_URL . 'assets/css/parsley.css', null, '2.3.5');
154
+ /* JS */
155
+ wp_register_script('dup-handlebars', DUPLICATOR_PLUGIN_URL . 'assets/js/handlebars.min.js', array('jquery'), '4.0.10');
156
+ wp_register_script('dup-parsley', DUPLICATOR_PLUGIN_URL . 'assets/js/parsley.min.js', array('jquery'), '1.1.18');
157
+ wp_register_script('dup-jquery-qtip', DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.js', array('jquery'), '2.2.1');
158
+
159
+ add_action('admin_head', array('DUP_UI_Screen', 'getCustomCss'));
160
+ // Clean tmp folder
161
+ DUP_Package::not_active_files_tmp_cleanup();
162
+
163
+ $unhook_third_party_js = DUP_Settings::Get('unhook_third_party_js');
164
+ $unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css');
165
+ if ($unhook_third_party_js || $unhook_third_party_css) {
166
+ add_action('admin_enqueue_scripts', 'duplicator_unhook_third_party_assets', 99999, 1);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Hooked into `admin_enqueue_scripts`. Init routines for all admin pages
172
+ *
173
+ * @access global
174
+ * @return null
175
+ */
176
+ function duplicator_admin_enqueue_scripts()
177
+ {
178
+ wp_enqueue_script('dup-global-script', DUPLICATOR_PLUGIN_URL . 'assets/js/global-admin-script.js', array('jquery'), DUPLICATOR_VERSION, true);
179
+ wp_localize_script('dup-global-script',
180
+ 'dup_global_script_data',
181
+ array(
182
+ 'duplicator_admin_notice_to_dismiss' => wp_create_nonce('duplicator_admin_notice_to_dismiss')
183
+ )
184
+ );
185
+ wp_enqueue_style('dup-plugin-global-style');
186
+ }
187
+
188
+ /**
189
+ * Redirects the clicked menu item to the correct location
190
+ *
191
+ * @access global
192
+ * @return null
193
+ */
194
+ function duplicator_get_menu()
195
+ {
196
+ $current_page = isset($_REQUEST['page']) ? sanitize_text_field($_REQUEST['page']) : 'duplicator';
197
+ switch ($current_page) {
198
+ case 'duplicator': include('views/packages/controller.php'); break;
199
+ case 'duplicator-settings': include('views/settings/controller.php'); break;
200
+ case 'duplicator-tools': include('views/tools/controller.php'); break;
201
+ case 'duplicator-debug': include('debug/main.php'); break;
202
+ case 'duplicator-gopro': include('views/settings/gopro.php'); break;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Hooked into `admin_menu`. Loads all of the wp left nav admin menus for Duplicator
208
+ *
209
+ * @access global
210
+ * @return null
211
+ */
212
+ function duplicator_menu()
213
+ {
214
+ $wpfront_caps_translator = 'wpfront_user_role_editor_duplicator_translate_capability';
215
+ //SVG Icon: See https://websemantics.uk/tools/image-to-data-uri-converter/
216
+ //older version
217
+ //$icon_svg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQXJ0d29yayIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIyMy4yNXB4IiBoZWlnaHQ9IjIyLjM3NXB4IiB2aWV3Qm94PSIwIDAgMjMuMjUgMjIuMzc1IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyMy4yNSAyMi4zNzUiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGZpbGw9IiM5Q0ExQTYiIGQ9Ik0xOC4wMTEsMS4xODhjLTEuOTk1LDAtMy42MTUsMS42MTgtMy42MTUsMy42MTRjMCwwLjA4NSwwLjAwOCwwLjE2NywwLjAxNiwwLjI1TDcuNzMzLDguMTg0QzcuMDg0LDcuNTY1LDYuMjA4LDcuMTgyLDUuMjQsNy4xODJjLTEuOTk2LDAtMy42MTUsMS42MTktMy42MTUsMy42MTRjMCwxLjk5NiwxLjYxOSwzLjYxMywzLjYxNSwzLjYxM2MwLjYyOSwwLDEuMjIyLTAuMTYyLDEuNzM3LTAuNDQ1bDIuODksMi40MzhjLTAuMTI2LDAuMzY4LTAuMTk4LDAuNzYzLTAuMTk4LDEuMTczYzAsMS45OTUsMS42MTgsMy42MTMsMy42MTQsMy42MTNjMS45OTUsMCwzLjYxNS0xLjYxOCwzLjYxNS0zLjYxM2MwLTEuOTk3LTEuNjItMy42MTQtMy42MTUtMy42MTRjLTAuNjMsMC0xLjIyMiwwLjE2Mi0xLjczNywwLjQ0M2wtMi44OS0yLjQzNWMwLjEyNi0wLjM2OCwwLjE5OC0wLjc2MywwLjE5OC0xLjE3M2MwLTAuMDg0LTAuMDA4LTAuMTY2LTAuMDEzLTAuMjVsNi42NzYtMy4xMzNjMC42NDgsMC42MTksMS41MjUsMS4wMDIsMi40OTUsMS4wMDJjMS45OTQsMCwzLjYxMy0xLjYxNywzLjYxMy0zLjYxM0MyMS42MjUsMi44MDYsMjAuMDA2LDEuMTg4LDE4LjAxMSwxLjE4OHoiLz48L3N2Zz4=';
218
+ $icon_svg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iMjU2cHgiIGhlaWdodD0iMjU2cHgiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyNTYgMjU2IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnPg0KCTxnPg0KCQk8cGF0aCBmaWxsPSIjQTdBOUFDIiBkPSJNMTcyLjEwMywzNS4yMjNsLTEuMzk1LTI0LjA5N0wxNTMuMzYsNi40NzhsLTEzLjI1MywyMC4xNzFjLTYuNzQyLTAuNjc1LTEzLjUzNS0wLjY5Ni0yMC4yNzYtMC4wNDINCgkJCUwxMDYuNDY3LDYuMjdsLTE3LjM0OCw0LjY0N2wtMS40LDI0LjIwNGMtNi4wNzMsMi43MjQtMTEuOTMsNi4wNzQtMTcuNDg1LDEwLjAzOUw0OC40MDMsMzQuMTgzTDM1LjcwNCw0Ni44ODJsMTAuOTEsMjEuNzAxDQoJCQljLTQuMDExLDUuNTIyLTcuMzk2LDExLjM1Mi0xMC4xNywxNy4zOTdsLTI0LjM2NywxLjQxbC00LjY0OCwxNy4zNDhsMjAuMjQxLDEzLjNjLTAuNzA4LDYuNzM0LTAuNzg1LDEzLjUyMy0wLjE2NiwyMC4yNjUNCgkJCWwtMjAuMjg0LDEzLjMzbDQuNjQ4LDE3LjM0OGwyMy4zMjQsMS4zNDlsMC4yMjctMC44MjZsOS4xMDYtMzMuMTc2Yy0yLjEyNS0yNC4zMzMsNi4xMDQtNDkuMzk3LDI0LjcyOS02OC4wMjMNCgkJCWMyNy4zOTMtMjcuMzkzLDY4LjcxLTMyLjMxNSwxMDEuMTQ1LTE0LjgzM0w1NC40MjIsMTY5LjQ0N2wtMi41ODUtMzIuMzU1TDMwLjg5LDIxMy4zOThsMzEuNjE0LTMxLjYxNEwxODIuNzM1LDYxLjU1Mw0KCQkJbDQuMjA0LTQuMjA2bDcuOTc4LTcuOTc4QzE4Ny44MzYsNDMuNTU3LDE4MC4xNSwzOC44NTcsMTcyLjEwMywzNS4yMjN6Ii8+DQoJCTxwYXRoIGZpbGw9IiNBN0E5QUMiIGQ9Ik0xMDUuMjE0LDkuNTU4bDEyLjIzMSwxOC42MTRsMC45NDUsMS40NGwxLjcxNS0wLjE2NmMzLjE4Mi0wLjMwOCw2LjQyMy0wLjQ2NSw5LjYzNC0wLjQ2NQ0KCQkJYzMuMzQ3LDAsNi43MzYsMC4xNywxMC4wODIsMC41MDZsMS43MTksMC4xNzJsMC45NS0xLjQ0NGwxMi4xMjItMTguNDQ5bDEzLjM2NSwzLjU4MWwxLjI3NCwyMi4wNDFsMC4xMDEsMS43MjRsMS41NzMsMC43MTENCgkJCWM3LjAzNiwzLjE3NSwxMy42NTIsNy4xMzYsMTkuNzExLDExLjc5MWwtNS43MTcsNS43MThsLTQuMjAzLDQuMjAzTDYwLjQ4NSwxNzkuNzY2bC0yMy45OTEsMjMuOTkybDEzLjc5Mi01MC4yNDRsMS4yOTIsMTYuMTYyDQoJCQlsMC40OTMsNi4xNTlsNC4zNjktNC4zNjdMMTcyLjQxNiw1NS40OWwyLjcwOS0yLjcxMWwtMy4zNzItMS44MThjLTEyLjgyOS02LjkxNS0yNy4zNDktMTAuNTcxLTQxLjk5NC0xMC41NzENCgkJCWMtMjMuNjIsMC00NS44MjMsOS4xOTgtNjIuNTIyLDI1Ljg5N0M0OC44MzMsODQuNjksMzkuNTIsMTEwLjA5NSw0MS42MzksMTM2LjA2MWwtOC41ODcsMzEuMjg4bC0xOC45NjItMS4wOTlsLTMuNTgxLTEzLjM2Mw0KCQkJbDE4LjU2Mi0xMi4xOThsMS40MzEtMC45NDJsLTAuMTU2LTEuNzA0Yy0wLjU5Mi02LjQzNi0wLjUzOC0xMy4wNjUsMC4xNjEtMTkuNzA2bDAuMTgyLTEuNzI4bC0xLjQ1Mi0wLjk1NWwtMTguNTE4LTEyLjE2Nw0KCQkJbDMuNTgxLTEzLjM2NmwyMi4zMDktMS4yOTFsMS43MTItMC4wOThsMC43MTctMS41NTljMi43MjktNS45NDgsNi4wNTUtMTEuNjM5LDkuODg1LTE2LjkxM2wxLjAyMS0xLjQwNmwtMC43NzktMS41NTINCgkJCWwtOS45ODQtMTkuODU5bDkuNzg0LTkuNzg0bDE5Ljk4OCwxMC4wNDlsMS41MzgsMC43NzRsMS40MDEtMS4wMDFjNS4zNDMtMy44MTEsMTEuMDYxLTcuMDk0LDE2Ljk5Ny05Ljc1N2wxLjU4MS0wLjcxMmwwLjEtMS43MjgNCgkJCWwxLjI4MS0yMi4xNDVMMTA1LjIxNCw5LjU1OCBNMTA2LjQ2Nyw2LjI3bC0xNy4zNDgsNC42NDdsLTEuNCwyNC4yMDRjLTYuMDczLDIuNzI2LTExLjkzLDYuMDc0LTE3LjQ4NiwxMC4wMzlsLTIxLjgzLTEwLjk3Ng0KCQkJbC0xMi43LDEyLjcwMWwxMC45MSwyMS42OTljLTQuMDExLDUuNTIyLTcuMzk2LDExLjM1My0xMC4xNywxNy4zOTdsLTI0LjM2NywxLjQxbC00LjY0OCwxNy4zNDhsMjAuMjQsMTMuMw0KCQkJYy0wLjcwOCw2LjczNC0wLjc4NCwxMy41MjMtMC4xNjUsMjAuMjY1bC0yMC4yODQsMTMuMzNsNC42NDgsMTcuMzQ4bDIzLjMyNCwxLjM0OWwwLjIyNy0wLjgyNmw5LjEwNi0zMy4xNzYNCgkJCWMtMi4xMjUtMjQuMzMzLDYuMTA0LTQ5LjM5NywyNC43MjktNjguMDIzYzE2LjcxLTE2LjcxMSwzOC42MDctMjUuMDYsNjAuNTA1LTI1LjA2YzEzLjk5OCwwLDI3Ljk5MiwzLjQxMSw0MC42NCwxMC4yMjcNCgkJCUw1NC40MjIsMTY5LjQ0OWwtMi41ODUtMzIuMzU3TDMwLjg5LDIxMy4zOThsMzEuNjE0LTMxLjYxNEwxODIuNzM1LDYxLjU1M2w0LjIwMy00LjIwNGw3Ljk3OS03Ljk3OQ0KCQkJYy03LjA4My01LjgxNS0xNC43NjctMTAuNTEzLTIyLjgxNC0xNC4xNDdsLTEuMzk1LTI0LjA5N0wxNTMuMzYsNi40NzhsLTEzLjI1NCwyMC4xN2MtMy40NDctMC4zNDYtNi45MDctMC41Mi0xMC4zNjYtMC41Mg0KCQkJYy0zLjMwNywwLTYuNjE0LDAuMTYtOS45MSwwLjQ3OUwxMDYuNDY3LDYuMjdMMTA2LjQ2Nyw2LjI3eiIvPg0KCTwvZz4NCgk8Zz4NCgkJPHBhdGggZmlsbD0iI0E3QTlBQyIgZD0iTTg3LjgwMiwyMjIuMjFsMS4zOTQsMjQuMDk3bDE3LjM0OCw0LjY0OWwxMy4yNTUtMjAuMTdjNi43NDIsMC42NzUsMTMuNTMzLDAuNjkzLDIwLjI3NCwwLjA0MQ0KCQkJbDEzLjM2NSwyMC4zMzVsMTcuMzQ3LTQuNjQ2bDEuMzk5LTI0LjIwMmM2LjA3My0yLjcyNSwxMS45My02LjA3NCwxNy40ODYtMTAuMDM4bDIxLjgzMSwxMC45NzRsMTIuNjk5LTEyLjY5OGwtMTAuOTEtMjEuNzAxDQoJCQljNC4wMTItNS41MjEsNy4zOTYtMTEuMzUyLDEwLjE2OS0xNy4zOThsMjQuMzY5LTEuNDA4bDQuNjQ2LTE3LjM0OGwtMjAuMjM5LTEzLjNjMC43MDgtNi43MzYsMC43ODQtMTMuNTIzLDAuMTY0LTIwLjI2Ng0KCQkJbDIwLjI4NC0xMy4zMjhsLTQuNjQ3LTE3LjM0OGwtMjMuMzIzLTEuMzQ5bC0wLjIyOCwwLjgyNWwtOS4xMDcsMzMuMTc1YzIuMTI3LDI0LjMzMi02LjEwNCw0OS4zOTctMjQuNzI5LDY4LjAyNA0KCQkJYy0yNy4zOTIsMjcuMzkzLTY4LjcwOSwzMi4zMTUtMTAxLjE0NCwxNC44MzFMMjA1LjQ4LDg3Ljk4NGwyLjU4NiwzMi4zNTZsMjAuOTQ4LTc2LjMwNWwtMzEuNjE1LDMxLjYxM0w3Ny4xNjksMTk1Ljg4DQoJCQlsLTQuMjA2LDQuMjA1bC03Ljk3OCw3Ljk3OUM3Mi4wNjgsMjEzLjg3Niw3OS43NTIsMjE4LjU3NSw4Ny44MDIsMjIyLjIxeiIvPg0KCQk8cGF0aCBmaWxsPSIjQTdBOUFDIiBkPSJNMjIzLjQwOSw1My42NzZsLTEzLjc5Myw1MC4yNGwtMS4yOS0xNi4xNmwtMC40OTQtNi4xNTlsLTQuMzY4LDQuMzdMODcuNDg3LDIwMS45NDJsLTIuNzA5LDIuNzEyDQoJCQlsMy4zNzMsMS44MThjMTIuODI4LDYuOTE0LDI3LjM1MSwxMC41NjgsNDEuOTk3LDEwLjU2OGMyMy42MTgsMCw0NS44MjEtOS4xOTUsNjIuNTItMjUuODk2DQoJCQljMTguNDAzLTE4LjQwMiwyNy43MTctNDMuODA3LDI1LjU5OC02OS43NzVsOC41ODgtMzEuMjgzbDE4Ljk2MSwxLjA5N2wzLjU4MiwxMy4zNjRsLTE4LjU2MywxMi4xOTdsLTEuNDMsMC45NDFsMC4xNTUsMS43MDUNCgkJCWMwLjU5Miw2LjQzNiwwLjUzOSwxMy4wNjctMC4xNiwxOS43MDZsLTAuMTgzLDEuNzI3bDEuNDUxLDAuOTU0bDE4LjUyMSwxMi4xNzFsLTMuNTgyLDEzLjM2NWwtMjIuMzExLDEuMjkxbC0xLjcxMiwwLjA5OQ0KCQkJbC0wLjcxNiwxLjU2Yy0yLjcyNyw1Ljk0NC02LjA1MywxMS42MzMtOS44ODYsMTYuOTExbC0xLjAyLDEuNDA0bDAuNzgsMS41NTRsOS45ODMsMTkuODU5bC05Ljc4NSw5Ljc4M2wtMTkuOTktMTAuMDUNCgkJCWwtMS41MzYtMC43NzJsLTEuNDAyLDAuOTk5Yy01LjM0MSwzLjgxNC0xMS4wNTksNy4wOTYtMTYuOTk0LDkuNzU4bC0xLjU4MiwwLjcxbC0wLjA5OSwxLjcyOWwtMS4yODMsMjIuMTQ2bC0xMy4zNjMsMy41ODENCgkJCWwtMTIuMjMzLTE4LjYxNWwtMC45NDYtMS40MzhsLTEuNzEzLDAuMTYzYy0zLjE4LDAuMzEtNi40MTcsMC40NjUtOS42MjYsMC40NjVjLTMuMzQ4LDAtNi43NDMtMC4xNjktMTAuMDktMC41MDVsLTEuNzE5LTAuMTcxDQoJCQlsLTAuOTUsMS40NDNsLTEyLjEyMiwxOC40NDhsLTEzLjM2Ni0zLjU4MWwtMS4yNzUtMjIuMDM4bC0wLjEtMS43MjdsLTEuNTc0LTAuNzA5Yy03LjAzNS0zLjE4LTEzLjY1My03LjEzOS0xOS43MS0xMS43OTINCgkJCWw1LjcxNi01LjcxNWw0LjIwNS00LjIwN0wxOTkuNDE4LDc3LjY2NkwyMjMuNDA5LDUzLjY3NiBNMjI5LjAxNSw0NC4wMzZsLTMxLjYxNSwzMS42MTNMNzcuMTY5LDE5NS44OGwtNC4yMDYsNC4yMDVsLTcuOTc3LDcuOTc5DQoJCQljNy4wOCw1LjgxMiwxNC43NjUsMTAuNTExLDIyLjgxNCwxNC4xNDZsMS4zOTQsMjQuMDk3bDE3LjM0OCw0LjY0OWwxMy4yNTQtMjAuMTczYzMuNDQ4LDAuMzQ4LDYuOTEyLDAuNTIzLDEwLjM3NCwwLjUyMw0KCQkJYzMuMzA0LDAsNi42MDctMC4xNjIsOS45LTAuNDc5bDEzLjM2NSwyMC4zMzVsMTcuMzQ3LTQuNjQ2bDEuMzk5LTI0LjIwMmM2LjA3My0yLjcyNSwxMS45MzEtNi4wNzcsMTcuNDg2LTEwLjAzOGwyMS44MzEsMTAuOTc0DQoJCQlsMTIuNjk5LTEyLjY5OGwtMTAuOTEtMjEuNzAxYzQuMDEyLTUuNTIxLDcuMzk2LTExLjM1MiwxMC4xNjktMTcuMzk4bDI0LjM2OS0xLjQwOGw0LjY0OS0xNy4zNDhsLTIwLjI0Mi0xMy4zDQoJCQljMC43MDgtNi43MzYsMC43ODQtMTMuNTIzLDAuMTY0LTIwLjI2NmwyMC4yODUtMTMuMzI4bC00LjY0OC0xNy4zNDhsLTIzLjMyNC0xLjM0OWwtMC4yMjcsMC44MjVsLTkuMTA3LDMzLjE3NQ0KCQkJYzIuMTI3LDI0LjMzMi02LjEwNCw0OS40MDEtMjQuNzI5LDY4LjAyNGMtMTYuNzA5LDE2LjcxLTM4LjYwNCwyNS4wNjEtNjAuNTAxLDI1LjA2MWMtMTMuOTk4LDAtMjcuOTk1LTMuNDEtNDAuNjQzLTEwLjIyOQ0KCQkJTDIwNS40OCw4Ny45ODRsMi41ODYsMzIuMzU2TDIyOS4wMTUsNDQuMDM2TDIyOS4wMTUsNDQuMDM2eiIvPg0KCTwvZz4NCjwvZz4NCjwvc3ZnPg0K';
219
+
220
+ //Main Menu
221
+ $perms = 'export';
222
+ $perms = apply_filters($wpfront_caps_translator, $perms);
223
+ $main_menu = add_menu_page('Duplicator Plugin', 'Duplicator', $perms, 'duplicator', 'duplicator_get_menu', $icon_svg);
224
+ $perms = 'export';
225
+ $perms = apply_filters($wpfront_caps_translator, $perms);
226
+ $lang_txt = esc_html__('Packages', 'duplicator');
227
+ $page_packages = add_submenu_page('duplicator', $lang_txt, $lang_txt, $perms, 'duplicator', 'duplicator_get_menu');
228
+ $GLOBALS['DUP_Package_Screen'] = new DUP_Package_Screen($page_packages);
229
+
230
+ $perms = 'manage_options';
231
+ $perms = apply_filters($wpfront_caps_translator, $perms);
232
+ $lang_txt = esc_html__('Tools', 'duplicator');
233
+ $page_tools = add_submenu_page('duplicator', $lang_txt, $lang_txt, $perms, 'duplicator-tools', 'duplicator_get_menu');
234
+
235
+ $perms = 'manage_options';
236
+ $perms = apply_filters($wpfront_caps_translator, $perms);
237
+ $lang_txt = esc_html__('Settings', 'duplicator');
238
+ $page_settings = add_submenu_page('duplicator', $lang_txt, $lang_txt, $perms, 'duplicator-settings', 'duplicator_get_menu');
239
+
240
+ $perms = 'manage_options';
241
+ $admin_color = get_user_option('admin_color');
242
+ $orange_for_admin_colors = array(
243
+ 'fresh',
244
+ 'coffee',
245
+ 'ectoplasm',
246
+ 'midnight'
247
+ );
248
+ $style = in_array($admin_color, $orange_for_admin_colors) ? 'style="color:#f18500"' : '';
249
+ $lang_txt = esc_html__('Go Pro!', 'duplicator');
250
+ $go_pro_link = '<span ' . $style . '>' . $lang_txt . '</span>';
251
+ $perms = apply_filters($wpfront_caps_translator, $perms);
252
+ $page_gopro = add_submenu_page('duplicator', $go_pro_link, $go_pro_link, $perms, 'duplicator-gopro', 'duplicator_get_menu');
253
+
254
+ //Apply Scripts
255
+ add_action('admin_print_scripts-' . $page_packages, 'duplicator_scripts');
256
+ add_action('admin_print_scripts-' . $page_settings, 'duplicator_scripts');
257
+ add_action('admin_print_scripts-' . $page_tools, 'duplicator_scripts');
258
+ add_action('admin_print_scripts-' . $page_gopro, 'duplicator_scripts');
259
+
260
+ add_action('wp_enqueue_scripts', 'duplicator_global_scripts');
261
+
262
+ //Apply Styles
263
+ add_action('admin_print_styles-' . $page_packages, 'duplicator_styles');
264
+ add_action('admin_print_styles-' . $page_settings, 'duplicator_styles');
265
+ add_action('admin_print_styles-' . $page_tools, 'duplicator_styles');
266
+ add_action('admin_print_styles-' . $page_gopro, 'duplicator_styles');
267
+ }
268
+
269
+ /**
270
+ * Loads all required javascript libs/source for DupPro
271
+ *
272
+ * @access global
273
+ * @return null
274
+ */
275
+ function duplicator_scripts()
276
+ {
277
+ wp_enqueue_script('jquery');
278
+ wp_enqueue_script('jquery-ui-core');
279
+ wp_enqueue_script('jquery-ui-progressbar');
280
+ wp_enqueue_script('dup-parsley');
281
+ wp_enqueue_script('dup-jquery-qtip');
282
+ }
283
+
284
+ /**
285
+ * Loads all CSS style libs/source for DupPro
286
+ *
287
+ * @access global
288
+ * @return null
289
+ */
290
+ function duplicator_styles()
291
+ {
292
+ wp_enqueue_style('dup-jquery-ui');
293
+ wp_enqueue_style('dup-font-awesome');
294
+ wp_enqueue_style('dup-plugin-style');
295
+ wp_enqueue_style('dup-jquery-qtip');
296
+ }
297
+ /** ========================================================
298
+ * FILTERS
299
+ * ===================================================== */
300
+ add_filter('plugin_action_links', 'duplicator_manage_link', 10, 2);
301
+ add_filter('plugin_row_meta', 'duplicator_meta_links', 10, 2);
302
+
303
+ /**
304
+ * Adds the manage link in the plugins list
305
+ *
306
+ * @access global
307
+ * @return string The manage link in the plugins list
308
+ */
309
+ function duplicator_manage_link($links, $file)
310
+ {
311
+ static $this_plugin;
312
+ if (!$this_plugin)
313
+ $this_plugin = plugin_basename(DUPLICATOR_LITE_FILE);
314
+
315
+ if ($file == $this_plugin) {
316
+ /*
317
+ $settings_link = '<a href="admin.php?page=duplicator">' . esc_html__("Manage", 'duplicator') . '</a>';
318
+ array_unshift($links, $settings_link);
319
+ */
320
+ $upgrade_link = '<a href="https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=plugins_page&utm_campaign=duplicator_pro"><strong style="color: #11967A; display: inline;">' . esc_html__("Upgrade to Professional", 'duplicator') . '</strong></a>';
321
+ array_unshift($links, $upgrade_link);
322
+ }
323
+ return $links;
324
+ }
325
+
326
+ /**
327
+ * Adds links to the plugins manager page
328
+ *
329
+ * @access global
330
+ * @return string The meta help link data for the plugins manager
331
+ */
332
+ function duplicator_meta_links($links, $file)
333
+ {
334
+ $plugin = plugin_basename(DUPLICATOR_LITE_FILE);
335
+ // create link
336
+ if ($file == $plugin) {
337
+ $links[] = '<a href="admin.php?page=duplicator" title="' . esc_attr__('Manage Packages', 'duplicator') . '" style="">' . esc_html__('Manage', 'duplicator') . '</a>';
338
+ return $links;
339
+ }
340
+ return $links;
341
+ }
342
+ /** ========================================================
343
+ * GENERAL
344
+ * ===================================================== */
345
+
346
+ /**
347
+ * Used for installer files to redirect if accessed directly
348
+ *
349
+ * @access global
350
+ * @return null
351
+ */
352
+ function duplicator_secure_check()
353
+ {
354
+ $baseURL = "http://" . strlen($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'];
355
+ header("HTTP/1.1 301 Moved Permanently");
356
+ header("Location: $baseURL");
357
+ exit;
358
+ }
359
+ if (!function_exists('duplicator_unhook_third_party_assets')) {
360
+
361
+ /**
362
+ * Remove all external styles and scripts coming from other plugins
363
+ * which may cause compatibility issue, especially with React
364
+ *
365
+ * @return void
366
+ */
367
+ function duplicator_unhook_third_party_assets($hook)
368
+ {
369
+ /*
370
+ $hook values in duplicator admin pages:
371
+ toplevel_page_duplicator
372
+ duplicator_page_duplicator-tools
373
+ duplicator_page_duplicator-settings
374
+ duplicator_page_duplicator-gopro
375
+ */
376
+ if (strpos($hook, 'duplicator') !== false && strpos($hook, 'duplicator-pro') === false) {
377
+ $unhook_third_party_js = DUP_Settings::Get('unhook_third_party_js');
378
+ $unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css');
379
+ $assets = array();
380
+ if ($unhook_third_party_css)
381
+ $assets['styles'] = wp_styles();
382
+ if ($unhook_third_party_js)
383
+ $assets['scripts'] = wp_scripts();
384
+ foreach ($assets as $type => $asset) {
385
+ foreach ($asset->registered as $handle => $dep) {
386
+ $src = $dep->src;
387
+ // test if the src is coming from /wp-admin/ or /wp-includes/ or /wp-fsqm-pro/.
388
+ if (
389
+ is_string($src) && // For some built-ins, $src is true|false
390
+ strpos($src, 'wp-admin') === false &&
391
+ strpos($src, 'wp-include') === false &&
392
+ // things below are specific to your plugin, so change them
393
+ strpos($src, 'duplicator') === false &&
394
+ strpos($src, 'woocommerce') === false &&
395
+ strpos($src, 'jetpack') === false &&
396
+ strpos($src, 'debug-bar') === false
397
+ ) {
398
+ 'scripts' === $type ? wp_dequeue_script($handle) : wp_dequeue_style($handle);
399
+ }
400
+ }
401
+ }
402
+ }
403
+ }
404
+ }
405
+ }
406
+ }
duplicator.php CHANGED
@@ -3,9 +3,13 @@
3
  Plugin Name: Duplicator
4
  Plugin URI: https://snapcreek.com/duplicator/duplicator-free/
5
  Description: Migrate and backup a copy of your WordPress files and database. Duplicate and move a site from one location to another quickly.
6
- Version: 1.3.40.1
 
 
 
7
  Author: Snap Creek
8
  Author URI: http://www.snapcreek.com/duplicator/
 
9
  Text Domain: duplicator
10
  License: GPLv2 or later
11
 
@@ -25,410 +29,16 @@
25
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26
 
27
  ================================================================================ */
28
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
29
- if ( !defined('DUPXABSPATH') ) {
30
- define('DUPXABSPATH', dirname(__FILE__));
 
 
 
 
 
31
  }
32
 
33
- if (!defined('ABSPATH')) {
34
- exit; // Exit if accessed directly.
35
- }
36
- require_once("helper.php");
37
- require_once("define.php");
38
-
39
- if (is_admin() == true)
40
- {
41
- if (defined('DUPLICATOR_DEACTIVATION_FEEDBACK') && DUPLICATOR_DEACTIVATION_FEEDBACK) {
42
- require_once 'deactivation.php';
43
- }
44
- require_once 'lib/snaplib/snaplib.all.php';
45
- require_once 'classes/class.constants.php';
46
- $isWPEngineHost = apply_filters('duplicator_wp_engine_host_check', file_exists(WPMU_PLUGIN_DIR.'/wpengine-security-auditor.php'));
47
- if ($isWPEngineHost) {
48
- require_once 'classes/host/class.wpengine.host.php';
49
- }
50
-
51
- // gethostname() only present in PHP 5.3
52
- if(version_compare(PHP_VERSION, '5.3.0') >= 0) {
53
- $hostName = gethostname();
54
- $goDaddyHostNameSuffix = '.secureserver.net';
55
- $lenGoDaddyHostNameSuffix = strlen($goDaddyHostNameSuffix);
56
- $isGoDaddyHost = apply_filters('duplicator_godaddy_host_check', (false !== $hostName && substr($hostName, - $lenGoDaddyHostNameSuffix) === $goDaddyHostNameSuffix));
57
- if ($isGoDaddyHost) {
58
- require_once 'classes/host/class.godaddy.host.php';
59
- }
60
- }
61
-
62
- require_once 'classes/class.settings.php';
63
- require_once 'classes/class.logging.php';
64
- require_once 'classes/class.plugin.upgrade.php';
65
- require_once 'classes/utilities/class.u.php';
66
- require_once 'classes/utilities/class.u.string.php';
67
- require_once 'classes/utilities/class.u.validator.php';
68
- require_once 'classes/class.db.php';
69
- require_once 'classes/class.server.php';
70
- require_once 'classes/ui/class.ui.viewstate.php';
71
- require_once 'classes/ui/class.ui.notice.php';
72
- require_once 'classes/package/class.pack.php';
73
- require_once 'views/packages/screen.php';
74
-
75
- //Controllers
76
- require_once 'ctrls/ctrl.package.php';
77
- require_once 'ctrls/ctrl.tools.php';
78
- require_once 'ctrls/ctrl.ui.php';
79
- require_once 'ctrls/class.web.services.php';
80
-
81
- //Init Class
82
- DUP_Settings::init();
83
- DUP_Log::Init();
84
- DUP_Util::init();
85
- DUP_DB::init();
86
-
87
- /** ========================================================
88
- * ACTIVATE/DEACTIVE/UPDATE HOOKS
89
- * ===================================================== */
90
- register_activation_hook(__FILE__, array('DUP_LITE_Plugin_Upgrade','onActivationAction'));
91
- register_deactivation_hook(__FILE__, 'duplicator_deactivate');
92
-
93
- /**
94
- * Hooked into `plugins_loaded`. Routines used to update the plugin
95
- *
96
- * @access global
97
- * @return null
98
- */
99
- function duplicator_update()
100
- {
101
- if (DUPLICATOR_VERSION != get_option(DUP_LITE_Plugin_Upgrade::DUP_VERSION_OPT_KEY)) {
102
- DUP_LITE_Plugin_Upgrade::onActivationAction();
103
- // $snapShotDirPerm = substr(sprintf("%o", fileperms(DUP_Settings::getSsdirPath())),-4);
104
- }
105
- load_plugin_textdomain( 'duplicator' );
106
- }
107
-
108
- /**
109
- * Hooked into `register_deactivation_hook`. Routines used to deactivate the plugin
110
- * For uninstall see uninstall.php WordPress by default will call the uninstall.php file
111
- *
112
- * @access global
113
- * @return null
114
- */
115
- function duplicator_deactivate()
116
- {
117
- //Logic has been added to uninstall.php
118
- }
119
-
120
- /** ========================================================
121
- * ACTION HOOKS
122
- * ===================================================== */
123
- add_action('plugins_loaded', 'duplicator_update');
124
- add_action('plugins_loaded', 'duplicator_wpfront_integrate');
125
-
126
- function duplicator_load_textdomain()
127
- {
128
- load_plugin_textdomain('duplicator', false, false);
129
- }
130
- add_action('plugins_loaded', 'duplicator_load_textdomain');
131
-
132
- add_action('admin_init', 'duplicator_admin_init');
133
- add_action('admin_menu', 'duplicator_menu');
134
- add_action('admin_enqueue_scripts', 'duplicator_admin_enqueue_scripts' );
135
- DUP_UI_Notice::init();
136
-
137
- //CTRL ACTIONS
138
- DUP_Web_Services::init();
139
- add_action('wp_ajax_duplicator_active_package_info', 'duplicator_active_package_info');
140
- add_action('wp_ajax_duplicator_package_scan', 'duplicator_package_scan');
141
- add_action('wp_ajax_duplicator_package_build', 'duplicator_package_build');
142
- add_action('wp_ajax_duplicator_package_delete', 'duplicator_package_delete');
143
- add_action('wp_ajax_duplicator_duparchive_package_build', 'duplicator_duparchive_package_build');
144
-
145
- $GLOBALS['CTRLS_DUP_CTRL_UI'] = new DUP_CTRL_UI();
146
- $GLOBALS['CTRLS_DUP_CTRL_Tools'] = new DUP_CTRL_Tools();
147
- $GLOBALS['CTRLS_DUP_CTRL_Package'] = new DUP_CTRL_Package();
148
-
149
- /**
150
- * User role editor integration
151
- *
152
- * @access global
153
- * @return null
154
- */
155
- function duplicator_wpfront_integrate()
156
- {
157
- if (DUP_Settings::Get('wpfront_integrate')) {
158
- do_action('wpfront_user_role_editor_duplicator_init', array('export', 'manage_options', 'read'));
159
- }
160
- }
161
-
162
- /**
163
- * Hooked into `admin_init`. Init routines for all admin pages
164
- *
165
- * @access global
166
- * @return null
167
- */
168
- function duplicator_admin_init()
169
- {
170
- /* CSS */
171
- wp_register_style('dup-jquery-ui', DUPLICATOR_PLUGIN_URL . 'assets/css/jquery-ui.css', null, "1.11.2");
172
- wp_register_style('dup-font-awesome', DUPLICATOR_PLUGIN_URL . 'assets/css/fontawesome-all.min.css', null, '5.7.2');
173
- wp_register_style('dup-plugin-global-style', DUPLICATOR_PLUGIN_URL . 'assets/css/global_admin_style.css', null , DUPLICATOR_VERSION);
174
- wp_register_style('dup-plugin-style', DUPLICATOR_PLUGIN_URL . 'assets/css/style.css', array('dup-plugin-global-style') , DUPLICATOR_VERSION);
175
-
176
- wp_register_style('dup-jquery-qtip',DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.css', null, '2.2.1');
177
- wp_register_style('dup-parsley-style', DUPLICATOR_PLUGIN_URL . 'assets/css/parsley.css', null, '2.3.5');
178
- /* JS */
179
- wp_register_script('dup-handlebars', DUPLICATOR_PLUGIN_URL . 'assets/js/handlebars.min.js', array('jquery'), '4.0.10');
180
- wp_register_script('dup-parsley', DUPLICATOR_PLUGIN_URL . 'assets/js/parsley.min.js', array('jquery'), '1.1.18');
181
- wp_register_script('dup-jquery-qtip', DUPLICATOR_PLUGIN_URL . 'assets/js/jquery.qtip/jquery.qtip.min.js', array('jquery'), '2.2.1');
182
-
183
- add_action('admin_head', array('DUP_UI_Screen', 'getCustomCss'));
184
- // Clean tmp folder
185
- DUP_Package::not_active_files_tmp_cleanup();
186
-
187
- $unhook_third_party_js = DUP_Settings::Get('unhook_third_party_js');
188
- $unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css');
189
- if ($unhook_third_party_js || $unhook_third_party_css) {
190
- add_action('admin_enqueue_scripts', 'duplicator_unhook_third_party_assets', 99999, 1);
191
- }
192
- }
193
 
194
- /**
195
- * Hooked into `admin_enqueue_scripts`. Init routines for all admin pages
196
- *
197
- * @access global
198
- * @return null
199
- */
200
- function duplicator_admin_enqueue_scripts() {
201
- wp_enqueue_script('dup-global-script', DUPLICATOR_PLUGIN_URL . 'assets/js/global-admin-script.js', array('jquery'), DUPLICATOR_VERSION, true);
202
- wp_localize_script('dup-global-script',
203
- 'dup_global_script_data',
204
- array(
205
- 'duplicator_admin_notice_to_dismiss' => wp_create_nonce('duplicator_admin_notice_to_dismiss')
206
- )
207
- );
208
- wp_enqueue_style('dup-plugin-global-style');
209
- }
210
-
211
- /**
212
- * Redirects the clicked menu item to the correct location
213
- *
214
- * @access global
215
- * @return null
216
- */
217
- function duplicator_get_menu()
218
- {
219
- $current_page = isset($_REQUEST['page']) ? sanitize_text_field($_REQUEST['page']) : 'duplicator';
220
- switch ($current_page)
221
- {
222
- case 'duplicator': include('views/packages/controller.php'); break;
223
- case 'duplicator-settings': include('views/settings/controller.php'); break;
224
- case 'duplicator-tools': include('views/tools/controller.php'); break;
225
- case 'duplicator-debug': include('debug/main.php'); break;
226
- case 'duplicator-gopro': include('views/settings/gopro.php'); break;
227
- }
228
- }
229
-
230
- /**
231
- * Hooked into `admin_menu`. Loads all of the wp left nav admin menus for Duplicator
232
- *
233
- * @access global
234
- * @return null
235
- */
236
- function duplicator_menu()
237
- {
238
- $wpfront_caps_translator = 'wpfront_user_role_editor_duplicator_translate_capability';
239
- //SVG Icon: See https://websemantics.uk/tools/image-to-data-uri-converter/
240
- //older version
241
- //$icon_svg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQXJ0d29yayIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIyMy4yNXB4IiBoZWlnaHQ9IjIyLjM3NXB4IiB2aWV3Qm94PSIwIDAgMjMuMjUgMjIuMzc1IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyMy4yNSAyMi4zNzUiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIGZpbGw9IiM5Q0ExQTYiIGQ9Ik0xOC4wMTEsMS4xODhjLTEuOTk1LDAtMy42MTUsMS42MTgtMy42MTUsMy42MTRjMCwwLjA4NSwwLjAwOCwwLjE2NywwLjAxNiwwLjI1TDcuNzMzLDguMTg0QzcuMDg0LDcuNTY1LDYuMjA4LDcuMTgyLDUuMjQsNy4xODJjLTEuOTk2LDAtMy42MTUsMS42MTktMy42MTUsMy42MTRjMCwxLjk5NiwxLjYxOSwzLjYxMywzLjYxNSwzLjYxM2MwLjYyOSwwLDEuMjIyLTAuMTYyLDEuNzM3LTAuNDQ1bDIuODksMi40MzhjLTAuMTI2LDAuMzY4LTAuMTk4LDAuNzYzLTAuMTk4LDEuMTczYzAsMS45OTUsMS42MTgsMy42MTMsMy42MTQsMy42MTNjMS45OTUsMCwzLjYxNS0xLjYxOCwzLjYxNS0zLjYxM2MwLTEuOTk3LTEuNjItMy42MTQtMy42MTUtMy42MTRjLTAuNjMsMC0xLjIyMiwwLjE2Mi0xLjczNywwLjQ0M2wtMi44OS0yLjQzNWMwLjEyNi0wLjM2OCwwLjE5OC0wLjc2MywwLjE5OC0xLjE3M2MwLTAuMDg0LTAuMDA4LTAuMTY2LTAuMDEzLTAuMjVsNi42NzYtMy4xMzNjMC42NDgsMC42MTksMS41MjUsMS4wMDIsMi40OTUsMS4wMDJjMS45OTQsMCwzLjYxMy0xLjYxNywzLjYxMy0zLjYxM0MyMS42MjUsMi44MDYsMjAuMDA2LDEuMTg4LDE4LjAxMSwxLjE4OHoiLz48L3N2Zz4=';
242
- $icon_svg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB3aWR0aD0iMjU2cHgiIGhlaWdodD0iMjU2cHgiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyNTYgMjU2IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnPg0KCTxnPg0KCQk8cGF0aCBmaWxsPSIjQTdBOUFDIiBkPSJNMTcyLjEwMywzNS4yMjNsLTEuMzk1LTI0LjA5N0wxNTMuMzYsNi40NzhsLTEzLjI1MywyMC4xNzFjLTYuNzQyLTAuNjc1LTEzLjUzNS0wLjY5Ni0yMC4yNzYtMC4wNDINCgkJCUwxMDYuNDY3LDYuMjdsLTE3LjM0OCw0LjY0N2wtMS40LDI0LjIwNGMtNi4wNzMsMi43MjQtMTEuOTMsNi4wNzQtMTcuNDg1LDEwLjAzOUw0OC40MDMsMzQuMTgzTDM1LjcwNCw0Ni44ODJsMTAuOTEsMjEuNzAxDQoJCQljLTQuMDExLDUuNTIyLTcuMzk2LDExLjM1Mi0xMC4xNywxNy4zOTdsLTI0LjM2NywxLjQxbC00LjY0OCwxNy4zNDhsMjAuMjQxLDEzLjNjLTAuNzA4LDYuNzM0LTAuNzg1LDEzLjUyMy0wLjE2NiwyMC4yNjUNCgkJCWwtMjAuMjg0LDEzLjMzbDQuNjQ4LDE3LjM0OGwyMy4zMjQsMS4zNDlsMC4yMjctMC44MjZsOS4xMDYtMzMuMTc2Yy0yLjEyNS0yNC4zMzMsNi4xMDQtNDkuMzk3LDI0LjcyOS02OC4wMjMNCgkJCWMyNy4zOTMtMjcuMzkzLDY4LjcxLTMyLjMxNSwxMDEuMTQ1LTE0LjgzM0w1NC40MjIsMTY5LjQ0N2wtMi41ODUtMzIuMzU1TDMwLjg5LDIxMy4zOThsMzEuNjE0LTMxLjYxNEwxODIuNzM1LDYxLjU1Mw0KCQkJbDQuMjA0LTQuMjA2bDcuOTc4LTcuOTc4QzE4Ny44MzYsNDMuNTU3LDE4MC4xNSwzOC44NTcsMTcyLjEwMywzNS4yMjN6Ii8+DQoJCTxwYXRoIGZpbGw9IiNBN0E5QUMiIGQ9Ik0xMDUuMjE0LDkuNTU4bDEyLjIzMSwxOC42MTRsMC45NDUsMS40NGwxLjcxNS0wLjE2NmMzLjE4Mi0wLjMwOCw2LjQyMy0wLjQ2NSw5LjYzNC0wLjQ2NQ0KCQkJYzMuMzQ3LDAsNi43MzYsMC4xNywxMC4wODIsMC41MDZsMS43MTksMC4xNzJsMC45NS0xLjQ0NGwxMi4xMjItMTguNDQ5bDEzLjM2NSwzLjU4MWwxLjI3NCwyMi4wNDFsMC4xMDEsMS43MjRsMS41NzMsMC43MTENCgkJCWM3LjAzNiwzLjE3NSwxMy42NTIsNy4xMzYsMTkuNzExLDExLjc5MWwtNS43MTcsNS43MThsLTQuMjAzLDQuMjAzTDYwLjQ4NSwxNzkuNzY2bC0yMy45OTEsMjMuOTkybDEzLjc5Mi01MC4yNDRsMS4yOTIsMTYuMTYyDQoJCQlsMC40OTMsNi4xNTlsNC4zNjktNC4zNjdMMTcyLjQxNiw1NS40OWwyLjcwOS0yLjcxMWwtMy4zNzItMS44MThjLTEyLjgyOS02LjkxNS0yNy4zNDktMTAuNTcxLTQxLjk5NC0xMC41NzENCgkJCWMtMjMuNjIsMC00NS44MjMsOS4xOTgtNjIuNTIyLDI1Ljg5N0M0OC44MzMsODQuNjksMzkuNTIsMTEwLjA5NSw0MS42MzksMTM2LjA2MWwtOC41ODcsMzEuMjg4bC0xOC45NjItMS4wOTlsLTMuNTgxLTEzLjM2Mw0KCQkJbDE4LjU2Mi0xMi4xOThsMS40MzEtMC45NDJsLTAuMTU2LTEuNzA0Yy0wLjU5Mi02LjQzNi0wLjUzOC0xMy4wNjUsMC4xNjEtMTkuNzA2bDAuMTgyLTEuNzI4bC0xLjQ1Mi0wLjk1NWwtMTguNTE4LTEyLjE2Nw0KCQkJbDMuNTgxLTEzLjM2NmwyMi4zMDktMS4yOTFsMS43MTItMC4wOThsMC43MTctMS41NTljMi43MjktNS45NDgsNi4wNTUtMTEuNjM5LDkuODg1LTE2LjkxM2wxLjAyMS0xLjQwNmwtMC43NzktMS41NTINCgkJCWwtOS45ODQtMTkuODU5bDkuNzg0LTkuNzg0bDE5Ljk4OCwxMC4wNDlsMS41MzgsMC43NzRsMS40MDEtMS4wMDFjNS4zNDMtMy44MTEsMTEuMDYxLTcuMDk0LDE2Ljk5Ny05Ljc1N2wxLjU4MS0wLjcxMmwwLjEtMS43MjgNCgkJCWwxLjI4MS0yMi4xNDVMMTA1LjIxNCw5LjU1OCBNMTA2LjQ2Nyw2LjI3bC0xNy4zNDgsNC42NDdsLTEuNCwyNC4yMDRjLTYuMDczLDIuNzI2LTExLjkzLDYuMDc0LTE3LjQ4NiwxMC4wMzlsLTIxLjgzLTEwLjk3Ng0KCQkJbC0xMi43LDEyLjcwMWwxMC45MSwyMS42OTljLTQuMDExLDUuNTIyLTcuMzk2LDExLjM1My0xMC4xNywxNy4zOTdsLTI0LjM2NywxLjQxbC00LjY0OCwxNy4zNDhsMjAuMjQsMTMuMw0KCQkJYy0wLjcwOCw2LjczNC0wLjc4NCwxMy41MjMtMC4xNjUsMjAuMjY1bC0yMC4yODQsMTMuMzNsNC42NDgsMTcuMzQ4bDIzLjMyNCwxLjM0OWwwLjIyNy0wLjgyNmw5LjEwNi0zMy4xNzYNCgkJCWMtMi4xMjUtMjQuMzMzLDYuMTA0LTQ5LjM5NywyNC43MjktNjguMDIzYzE2LjcxLTE2LjcxMSwzOC42MDctMjUuMDYsNjAuNTA1LTI1LjA2YzEzLjk5OCwwLDI3Ljk5MiwzLjQxMSw0MC42NCwxMC4yMjcNCgkJCUw1NC40MjIsMTY5LjQ0OWwtMi41ODUtMzIuMzU3TDMwLjg5LDIxMy4zOThsMzEuNjE0LTMxLjYxNEwxODIuNzM1LDYxLjU1M2w0LjIwMy00LjIwNGw3Ljk3OS03Ljk3OQ0KCQkJYy03LjA4My01LjgxNS0xNC43NjctMTAuNTEzLTIyLjgxNC0xNC4xNDdsLTEuMzk1LTI0LjA5N0wxNTMuMzYsNi40NzhsLTEzLjI1NCwyMC4xN2MtMy40NDctMC4zNDYtNi45MDctMC41Mi0xMC4zNjYtMC41Mg0KCQkJYy0zLjMwNywwLTYuNjE0LDAuMTYtOS45MSwwLjQ3OUwxMDYuNDY3LDYuMjdMMTA2LjQ2Nyw2LjI3eiIvPg0KCTwvZz4NCgk8Zz4NCgkJPHBhdGggZmlsbD0iI0E3QTlBQyIgZD0iTTg3LjgwMiwyMjIuMjFsMS4zOTQsMjQuMDk3bDE3LjM0OCw0LjY0OWwxMy4yNTUtMjAuMTdjNi43NDIsMC42NzUsMTMuNTMzLDAuNjkzLDIwLjI3NCwwLjA0MQ0KCQkJbDEzLjM2NSwyMC4zMzVsMTcuMzQ3LTQuNjQ2bDEuMzk5LTI0LjIwMmM2LjA3My0yLjcyNSwxMS45My02LjA3NCwxNy40ODYtMTAuMDM4bDIxLjgzMSwxMC45NzRsMTIuNjk5LTEyLjY5OGwtMTAuOTEtMjEuNzAxDQoJCQljNC4wMTItNS41MjEsNy4zOTYtMTEuMzUyLDEwLjE2OS0xNy4zOThsMjQuMzY5LTEuNDA4bDQuNjQ2LTE3LjM0OGwtMjAuMjM5LTEzLjNjMC43MDgtNi43MzYsMC43ODQtMTMuNTIzLDAuMTY0LTIwLjI2Ng0KCQkJbDIwLjI4NC0xMy4zMjhsLTQuNjQ3LTE3LjM0OGwtMjMuMzIzLTEuMzQ5bC0wLjIyOCwwLjgyNWwtOS4xMDcsMzMuMTc1YzIuMTI3LDI0LjMzMi02LjEwNCw0OS4zOTctMjQuNzI5LDY4LjAyNA0KCQkJYy0yNy4zOTIsMjcuMzkzLTY4LjcwOSwzMi4zMTUtMTAxLjE0NCwxNC44MzFMMjA1LjQ4LDg3Ljk4NGwyLjU4NiwzMi4zNTZsMjAuOTQ4LTc2LjMwNWwtMzEuNjE1LDMxLjYxM0w3Ny4xNjksMTk1Ljg4DQoJCQlsLTQuMjA2LDQuMjA1bC03Ljk3OCw3Ljk3OUM3Mi4wNjgsMjEzLjg3Niw3OS43NTIsMjE4LjU3NSw4Ny44MDIsMjIyLjIxeiIvPg0KCQk8cGF0aCBmaWxsPSIjQTdBOUFDIiBkPSJNMjIzLjQwOSw1My42NzZsLTEzLjc5Myw1MC4yNGwtMS4yOS0xNi4xNmwtMC40OTQtNi4xNTlsLTQuMzY4LDQuMzdMODcuNDg3LDIwMS45NDJsLTIuNzA5LDIuNzEyDQoJCQlsMy4zNzMsMS44MThjMTIuODI4LDYuOTE0LDI3LjM1MSwxMC41NjgsNDEuOTk3LDEwLjU2OGMyMy42MTgsMCw0NS44MjEtOS4xOTUsNjIuNTItMjUuODk2DQoJCQljMTguNDAzLTE4LjQwMiwyNy43MTctNDMuODA3LDI1LjU5OC02OS43NzVsOC41ODgtMzEuMjgzbDE4Ljk2MSwxLjA5N2wzLjU4MiwxMy4zNjRsLTE4LjU2MywxMi4xOTdsLTEuNDMsMC45NDFsMC4xNTUsMS43MDUNCgkJCWMwLjU5Miw2LjQzNiwwLjUzOSwxMy4wNjctMC4xNiwxOS43MDZsLTAuMTgzLDEuNzI3bDEuNDUxLDAuOTU0bDE4LjUyMSwxMi4xNzFsLTMuNTgyLDEzLjM2NWwtMjIuMzExLDEuMjkxbC0xLjcxMiwwLjA5OQ0KCQkJbC0wLjcxNiwxLjU2Yy0yLjcyNyw1Ljk0NC02LjA1MywxMS42MzMtOS44ODYsMTYuOTExbC0xLjAyLDEuNDA0bDAuNzgsMS41NTRsOS45ODMsMTkuODU5bC05Ljc4NSw5Ljc4M2wtMTkuOTktMTAuMDUNCgkJCWwtMS41MzYtMC43NzJsLTEuNDAyLDAuOTk5Yy01LjM0MSwzLjgxNC0xMS4wNTksNy4wOTYtMTYuOTk0LDkuNzU4bC0xLjU4MiwwLjcxbC0wLjA5OSwxLjcyOWwtMS4yODMsMjIuMTQ2bC0xMy4zNjMsMy41ODENCgkJCWwtMTIuMjMzLTE4LjYxNWwtMC45NDYtMS40MzhsLTEuNzEzLDAuMTYzYy0zLjE4LDAuMzEtNi40MTcsMC40NjUtOS42MjYsMC40NjVjLTMuMzQ4LDAtNi43NDMtMC4xNjktMTAuMDktMC41MDVsLTEuNzE5LTAuMTcxDQoJCQlsLTAuOTUsMS40NDNsLTEyLjEyMiwxOC40NDhsLTEzLjM2Ni0zLjU4MWwtMS4yNzUtMjIuMDM4bC0wLjEtMS43MjdsLTEuNTc0LTAuNzA5Yy03LjAzNS0zLjE4LTEzLjY1My03LjEzOS0xOS43MS0xMS43OTINCgkJCWw1LjcxNi01LjcxNWw0LjIwNS00LjIwN0wxOTkuNDE4LDc3LjY2NkwyMjMuNDA5LDUzLjY3NiBNMjI5LjAxNSw0NC4wMzZsLTMxLjYxNSwzMS42MTNMNzcuMTY5LDE5NS44OGwtNC4yMDYsNC4yMDVsLTcuOTc3LDcuOTc5DQoJCQljNy4wOCw1LjgxMiwxNC43NjUsMTAuNTExLDIyLjgxNCwxNC4xNDZsMS4zOTQsMjQuMDk3bDE3LjM0OCw0LjY0OWwxMy4yNTQtMjAuMTczYzMuNDQ4LDAuMzQ4LDYuOTEyLDAuNTIzLDEwLjM3NCwwLjUyMw0KCQkJYzMuMzA0LDAsNi42MDctMC4xNjIsOS45LTAuNDc5bDEzLjM2NSwyMC4zMzVsMTcuMzQ3LTQuNjQ2bDEuMzk5LTI0LjIwMmM2LjA3My0yLjcyNSwxMS45MzEtNi4wNzcsMTcuNDg2LTEwLjAzOGwyMS44MzEsMTAuOTc0DQoJCQlsMTIuNjk5LTEyLjY5OGwtMTAuOTEtMjEuNzAxYzQuMDEyLTUuNTIxLDcuMzk2LTExLjM1MiwxMC4xNjktMTcuMzk4bDI0LjM2OS0xLjQwOGw0LjY0OS0xNy4zNDhsLTIwLjI0Mi0xMy4zDQoJCQljMC43MDgtNi43MzYsMC43ODQtMTMuNTIzLDAuMTY0LTIwLjI2NmwyMC4yODUtMTMuMzI4bC00LjY0OC0xNy4zNDhsLTIzLjMyNC0xLjM0OWwtMC4yMjcsMC44MjVsLTkuMTA3LDMzLjE3NQ0KCQkJYzIuMTI3LDI0LjMzMi02LjEwNCw0OS40MDEtMjQuNzI5LDY4LjAyNGMtMTYuNzA5LDE2LjcxLTM4LjYwNCwyNS4wNjEtNjAuNTAxLDI1LjA2MWMtMTMuOTk4LDAtMjcuOTk1LTMuNDEtNDAuNjQzLTEwLjIyOQ0KCQkJTDIwNS40OCw4Ny45ODRsMi41ODYsMzIuMzU2TDIyOS4wMTUsNDQuMDM2TDIyOS4wMTUsNDQuMDM2eiIvPg0KCTwvZz4NCjwvZz4NCjwvc3ZnPg0K';
243
-
244
- //Main Menu
245
- $perms = 'export';
246
- $perms = apply_filters($wpfront_caps_translator, $perms);
247
- $main_menu = add_menu_page('Duplicator Plugin', 'Duplicator', $perms, 'duplicator', 'duplicator_get_menu', $icon_svg);
248
- $perms = 'export';
249
- $perms = apply_filters($wpfront_caps_translator, $perms);
250
- $lang_txt = esc_html__('Packages', 'duplicator');
251
- $page_packages = add_submenu_page('duplicator', $lang_txt, $lang_txt, $perms, 'duplicator', 'duplicator_get_menu');
252
- $GLOBALS['DUP_PRO_Package_Screen'] = new DUP_Package_Screen($page_packages);
253
-
254
- $perms = 'manage_options';
255
- $perms = apply_filters($wpfront_caps_translator, $perms);
256
- $lang_txt = esc_html__('Tools', 'duplicator');
257
- $page_tools = add_submenu_page('duplicator', $lang_txt, $lang_txt, $perms, 'duplicator-tools', 'duplicator_get_menu');
258
-
259
- $perms = 'manage_options';
260
- $perms = apply_filters($wpfront_caps_translator, $perms);
261
- $lang_txt = esc_html__('Settings', 'duplicator');
262
- $page_settings = add_submenu_page('duplicator', $lang_txt, $lang_txt, $perms, 'duplicator-settings', 'duplicator_get_menu');
263
-
264
- $perms = 'manage_options';
265
- $admin_color = get_user_option('admin_color');
266
- $orange_for_admin_colors = array(
267
- 'fresh',
268
- 'coffee',
269
- 'ectoplasm',
270
- 'midnight'
271
- );
272
- $style = in_array($admin_color, $orange_for_admin_colors)
273
- ? 'style="color:#f18500"'
274
- : '';
275
- $lang_txt = esc_html__('Go Pro!', 'duplicator');
276
- $go_pro_link = '<span '.$style.'>' . $lang_txt . '</span>';
277
- $perms = apply_filters($wpfront_caps_translator, $perms);
278
- $page_gopro = add_submenu_page('duplicator', $go_pro_link, $go_pro_link, $perms, 'duplicator-gopro', 'duplicator_get_menu');
279
-
280
- //Apply Scripts
281
- add_action('admin_print_scripts-' . $page_packages, 'duplicator_scripts');
282
- add_action('admin_print_scripts-' . $page_settings, 'duplicator_scripts');
283
- add_action('admin_print_scripts-' . $page_tools, 'duplicator_scripts');
284
- add_action('admin_print_scripts-' . $page_gopro, 'duplicator_scripts');
285
-
286
- add_action('wp_enqueue_scripts', 'duplicator_global_scripts');
287
-
288
- //Apply Styles
289
- add_action('admin_print_styles-' . $page_packages, 'duplicator_styles');
290
- add_action('admin_print_styles-' . $page_settings, 'duplicator_styles');
291
- add_action('admin_print_styles-' . $page_tools, 'duplicator_styles');
292
- add_action('admin_print_styles-' . $page_gopro, 'duplicator_styles');
293
- }
294
-
295
- /**
296
- * Loads all required javascript libs/source for DupPro
297
- *
298
- * @access global
299
- * @return null
300
- */
301
- function duplicator_scripts()
302
- {
303
- wp_enqueue_script('jquery');
304
- wp_enqueue_script('jquery-ui-core');
305
- wp_enqueue_script('jquery-ui-progressbar');
306
- wp_enqueue_script('dup-parsley');
307
- wp_enqueue_script('dup-jquery-qtip');
308
-
309
- }
310
-
311
- /**
312
- * Loads all CSS style libs/source for DupPro
313
- *
314
- * @access global
315
- * @return null
316
- */
317
- function duplicator_styles()
318
- {
319
- wp_enqueue_style('dup-jquery-ui');
320
- wp_enqueue_style('dup-font-awesome');
321
- wp_enqueue_style('dup-plugin-style');
322
- wp_enqueue_style('dup-jquery-qtip');
323
- }
324
-
325
-
326
- /** ========================================================
327
- * FILTERS
328
- * ===================================================== */
329
- add_filter('plugin_action_links', 'duplicator_manage_link', 10, 2);
330
- add_filter('plugin_row_meta', 'duplicator_meta_links', 10, 2);
331
-
332
- /**
333
- * Adds the manage link in the plugins list
334
- *
335
- * @access global
336
- * @return string The manage link in the plugins list
337
- */
338
- function duplicator_manage_link($links, $file)
339
- {
340
- static $this_plugin;
341
- if (!$this_plugin)
342
- $this_plugin = plugin_basename(__FILE__);
343
-
344
- if ($file == $this_plugin) {
345
- /*
346
- $settings_link = '<a href="admin.php?page=duplicator">' . esc_html__("Manage", 'duplicator') . '</a>';
347
- array_unshift($links, $settings_link);
348
- */
349
- $upgrade_link = '<a href="https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=plugins_page&utm_campaign=duplicator_pro"><strong style="color: #11967A; display: inline;">' . esc_html__("Upgrade to Professional", 'duplicator') . '</strong></a>';
350
- array_unshift($links, $upgrade_link);
351
- }
352
- return $links;
353
- }
354
-
355
- /**
356
- * Adds links to the plugins manager page
357
- *
358
- * @access global
359
- * @return string The meta help link data for the plugins manager
360
- */
361
- function duplicator_meta_links($links, $file)
362
- {
363
- $plugin = plugin_basename(__FILE__);
364
- // create link
365
- if ($file == $plugin) {
366
- $links[] = '<a href="admin.php?page=duplicator" title="' . esc_attr__('Manage Packages', 'duplicator') . '" style="">' . esc_html__('Manage', 'duplicator') . '</a>';
367
- return $links;
368
- }
369
- return $links;
370
- }
371
-
372
- /** ========================================================
373
- * GENERAL
374
- * ===================================================== */
375
- /**
376
- * Used for installer files to redirect if accessed directly
377
- *
378
- * @access global
379
- * @return null
380
- */
381
- function duplicator_secure_check()
382
- {
383
- $baseURL = "http://" . strlen($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'];
384
- header("HTTP/1.1 301 Moved Permanently");
385
- header("Location: $baseURL");
386
- exit;
387
- }
388
-
389
- if (!function_exists('duplicator_unhook_third_party_assets')) {
390
- /**
391
- * Remove all external styles and scripts coming from other plugins
392
- * which may cause compatibility issue, especially with React
393
- *
394
- * @return void
395
- */
396
- function duplicator_unhook_third_party_assets($hook)
397
- {
398
- /*
399
- $hook values in duplicator admin pages:
400
- toplevel_page_duplicator
401
- duplicator_page_duplicator-tools
402
- duplicator_page_duplicator-settings
403
- duplicator_page_duplicator-gopro
404
- */
405
- if (strpos($hook, 'duplicator') !== false && strpos($hook, 'duplicator-pro') === false) {
406
- $unhook_third_party_js = DUP_Settings::Get('unhook_third_party_js');
407
- $unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css');
408
- $assets = array();
409
- if ($unhook_third_party_css) $assets['styles'] = wp_styles();
410
- if ($unhook_third_party_js) $assets['scripts'] = wp_scripts();
411
- foreach ($assets as $type => $asset) {
412
- foreach ($asset->registered as $handle => $dep) {
413
- $src = $dep->src;
414
- // test if the src is coming from /wp-admin/ or /wp-includes/ or /wp-fsqm-pro/.
415
- if (
416
- is_string($src) && // For some built-ins, $src is true|false
417
- strpos($src, 'wp-admin') === false &&
418
- strpos($src, 'wp-include') === false &&
419
- // things below are specific to your plugin, so change them
420
- strpos($src, 'duplicator') === false &&
421
- strpos($src, 'woocommerce') === false &&
422
- strpos($src, 'jetpack') === false &&
423
- strpos($src, 'debug-bar') === false
424
- ) {
425
- 'scripts' === $type
426
- ? wp_dequeue_script($handle)
427
- : wp_dequeue_style($handle);
428
- }
429
- }
430
- }
431
- }
432
- }
433
- }
434
- }
3
  Plugin Name: Duplicator
4
  Plugin URI: https://snapcreek.com/duplicator/duplicator-free/
5
  Description: Migrate and backup a copy of your WordPress files and database. Duplicate and move a site from one location to another quickly.
6
+ Version: 1.4.0
7
+ Requires at least: 4.0
8
+ Tested up to: 5.6
9
+ Requires PHP: 5.3.8
10
  Author: Snap Creek
11
  Author URI: http://www.snapcreek.com/duplicator/
12
+ Network: true
13
  Text Domain: duplicator
14
  License: GPLv2 or later
15
 
29
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30
 
31
  ================================================================================ */
32
+ defined('ABSPATH') || exit;
33
+
34
+ // CHECK PHP VERSION
35
+ define('DUPLICATOR_LITE_PHP_MINIMUM_VERSION', '5.3.8');
36
+ define('DUPLICATOR_LITE_PHP_SUGGESTED_VERSION', '5.6.20');
37
+ require_once(dirname(__FILE__)."/tools/DuplicatorPhpVersionCheck.php");
38
+ if (DuplicatorPhpVersionCheck::check(DUPLICATOR_LITE_PHP_MINIMUM_VERSION, DUPLICATOR_LITE_PHP_SUGGESTED_VERSION) === false) {
39
+ return;
40
  }
41
 
42
+ $currentPluginBootFile = __FILE__;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ require_once dirname(__FILE__).'/duplicator-main.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/dup-installer/assets/inc.css.php CHANGED
@@ -1,547 +1,587 @@
1
- <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; ?>
2
- <style>
3
- body {font-family:Verdana,Arial,sans-serif; font-size:13px}
4
- fieldset {border:1px solid silver; border-radius:5px; padding:10px}
5
- h3 {margin:1px; padding:1px; font-size:13px;}
6
- a {color:#222}
7
- a:hover{color:gray}
8
-
9
- input:not([type=checkbox]):not([type=radio]):not([type=button]) , select {
10
- width: 100%;
11
- border-radius: 2px;
12
- border: 1px solid silver;
13
- padding: 4px;
14
- padding-left: 4px;
15
- font-family: Verdana,Arial,sans-serif;
16
- line-height: 20px;
17
- height: 30px;
18
- box-sizing: border-box;
19
- background-color: white;
20
- color: black;
21
- border-radius: 4px;
22
- }
23
-
24
- input[readonly]:not([type="checkbox"]):not([type="radio"]):not([type="button"]),
25
- select[readonly],
26
- select[readonly] option{
27
- background-color: darkgray;
28
- color: lightgray;
29
- cursor: not-allowed;
30
- }
31
-
32
- select[size] {
33
- height: auto;
34
- line-height: 25px;
35
- }
36
-
37
- select , option {
38
- color: black;
39
- }
40
- select {
41
- padding-left:0;
42
- }
43
- select option {
44
- padding: 2px 5px;
45
- }
46
- select option:disabled {
47
- text-decoration: line-through;
48
- cursor: not-allowed;
49
- color: #A9A9A9;
50
- }
51
-
52
- select:disabled {background:#EBEBE4}
53
- input.readonly {background-color:#efefef;}
54
- .no-display { display: none; }
55
-
56
- /* ============================
57
- COMMON VIEWS
58
- ============================ */
59
- div#content {border:1px solid #CDCDCD; width:850px; min-height:550px; margin:auto; margin-top:18px; border-radius:5px; box-shadow:0 8px 6px -6px #333; font-size:13px}
60
- div#content-inner {padding:10px 25px; min-height:550px}
61
- form.content-form {min-height:550px; position:relative; line-height:17px}
62
- div.logfile-link {float:right; font-weight:normal; font-size:11px; font-style:italic}
63
- span.sub-notes {font-size:10px;}
64
-
65
- /* Header */
66
- table.header-wizard {border-top-left-radius:5px; border-top-right-radius:5px; width:100%; box-shadow:0 5px 3px -3px #999; background-color:#F1F1F1; font-weight:bold}
67
- div.dupx-logfile-link {float:right; font-weight:normal; font-style:italic; font-size:11px; cursor:pointer}
68
- .wiz-dupx-version {white-space:nowrap; color:#777; font-size:11px; font-style:italic; text-align:right; padding:3px 15px 5px 0; line-height:14px; font-weight:normal}
69
- .wiz-dupx-version a { color:#777; }
70
- div.dupx-debug-hdr {padding:5px 0 5px 0; font-size:16px; font-weight:bold}
71
- div.dupx-branding-header {font-size:26px; padding: 10px 0 7px 15px;}
72
-
73
- .dupx-overwrite {color:#AF0000;}
74
- .dupx-pass {display:inline-block; color:green;}
75
- .dupx-fail {display:inline-block; color:#AF0000;}
76
- .dupx-warn {display:inline-block; color:#555;}
77
- .dupx-notice {display:inline-block; color:#000;}
78
- i[data-tooltip].fa-question-circle {cursor: pointer; color:#C3C3C3}
79
- div.status-badge-pass {background-color:#418446;}
80
- div.status-badge-fail {background-color:maroon;}
81
- div.status-badge-warn {background-color:#555;}
82
- div.status-badge-pass, div.status-badge-fail, div.status-badge-warn {float:right; border-radius:4px; color:#fff; padding:0 3px 0 3px; font-size:11px !important; min-width:30px; text-align:center; font-weight:normal;}
83
- button.default-btn, .default-btn, .default-btn:hover {
84
- cursor:pointer; color:#fff; font-size:16px; border-radius:5px; padding:7px 25px 5px 25px;
85
- background-color:#13659C; border:1px solid gray; text-decoration: none;
86
- }
87
- button.disabled, input.disabled {background-color:#F4F4F4; color:silver; border:1px solid silver;}
88
-
89
- div.log-ui-error {padding-top:2px; font-size:13px}
90
- div#progress-area {padding:5px; margin:150px 0 0 0; text-align:center;}
91
- div#ajaxerr-data {padding:6px; height:425px; width:99%; border:1px solid silver; border-radius:5px; background-color:#F1F1F1; font-size:13px; overflow-y:scroll; line-height:20px}
92
- div.hdr-main {font-size:22px; padding:0 0 5px 0; border-bottom:1px solid #D3D3D3; font-weight:bold; margin:15px 0 20px 0;}
93
- div.hdr-main span.step {color:#DB4B38}
94
-
95
- div.sub-header {font-size:11px; font-style:italic; font-weight:normal; margin:5px 0 -1px 0}
96
- div.hdr-sub1 {font-size:18px; margin-bottom:5px;border:1px solid #D3D3D3;padding:7px; background-color:#f9f9f9; font-weight:bold; border-radius:4px}
97
- div.hdr-sub1 a {cursor:pointer; text-decoration: none !important}
98
- div.hdr-sub1 i.fa {font-size:15px; display:inline-block; margin:2px 5px 0 0; vertical-align:top}
99
- div.hdr-sub1-area {padding:5px}
100
- div.hdr-sub2 {font-size:15px; padding:2px 2px 2px 0; font-weight:bold; margin-bottom:5px; border:none}
101
- div.hdr-sub3 {font-size:15px; padding:2px 2px 2px 0; border-bottom:1px solid #D3D3D3; font-weight:bold; margin-bottom:5px;}
102
- div.hdr-sub4 {font-size:15px; padding:7px; border:1px solid #D3D3D3;; font-weight:bold; background-color:#e9e9e9;}
103
- div.hdr-sub4:hover {background-color:#dfdfdf; cursor:pointer}
104
- div.toggle-hdr:hover {cursor:pointer; background-color:#f1f1f1; border:1px solid #dcdcdc; }
105
- div.toggle-hdr:hover a{color:#000}
106
-
107
- [data-type="toggle"] > i.fa,
108
- i.fa.fa-toggle-empty { min-width: 8px; }
109
-
110
- /* ============================
111
- NOTICES
112
- ============================ */
113
- /* step messages */
114
- #step-messages { padding: 10px 25px 0; }
115
- .notice {
116
- background: #fff;
117
- border:1px solid #dfdfdf;
118
- border-left: 4px solid #fff;
119
- margin: 4px;
120
- padding: 5px;
121
- border-radius: 4px;
122
- font-size: 12px;
123
- }
124
-
125
- .notice-report {
126
- border-left: 4px solid #fff;
127
- padding-left: 0;
128
- padding-right: 0;
129
- margin-bottom: 4px;
130
- }
131
-
132
- .next-step .title-separator {
133
- margin-top: 5px;
134
- padding-top: 5px;
135
- border-top: 1px solid lightgray;
136
- }
137
-
138
- .notice .info pre {
139
- margin: 0;
140
- padding: 0;
141
- overflow: auto;
142
- }
143
-
144
- .notice-report .title {
145
- padding: 0 10px;
146
- }
147
-
148
- .notice-report .info {
149
- border-top: 1px solid #dedede;
150
- padding: 10px;
151
- font-size: 10px;
152
- background: #FAFAFA;
153
- word-wrap: break-word;
154
- }
155
-
156
- .notice.l-info,
157
- .notice.l-notice {border-left-color: #197b19;}
158
- .notice.l-swarning {border-left-color: #636363;}
159
- .notice.l-hwarning {border-left-color: #636363;}
160
- .notice.l-critical {border-left-color: maroon;}
161
- .notice.l-fatal {border-left-color: #000000;}
162
-
163
- .report-sections-list .section {
164
- border: 1px solid #DFDFDF;
165
- margin-bottom: 25px;
166
- box-shadow: 4px 8px 11px -8px rgba(0,0,0,0.41);
167
- }
168
-
169
- .report-sections-list .section > .section-title {
170
- background-color: #efefef;
171
- padding: 3px;
172
- font-weight: bold;
173
- text-align: center;
174
- font-size: 14px;
175
- }
176
-
177
- .report-sections-list .section > .section-content {
178
- padding: 5px;
179
- }
180
-
181
- .notice-level-status {
182
- border-radius: 4px;
183
- padding: 2px;
184
- margin: 1px;
185
- font-size: 10px;
186
- display: inline-block;
187
- color: #FFF;
188
- font-weight: bold;
189
- min-width:55px;
190
- }
191
-
192
- .notice-level-status.l-info,
193
- .notice-level-status.l-notice {background: #197b19;}
194
- .notice-level-status.l-swarning {background: #636363;}
195
- .notice-level-status.l-hwarning {background: #636363;}
196
- .notice-level-status.l-critical {background: maroon;}
197
- .notice-level-status.l-fatal {background: #000000;}
198
-
199
- /*Adv Opts */
200
- table.dupx-opts {width:100%; border:0px;}
201
- table.dupx-opts td{padding:3px;}
202
- table.dupx-opts td:first-child{width:125px; font-weight: bold}
203
- table.dupx-advopts td:first-child{width:125px;}
204
- table.dupx-advopts label.radio {width:50px; display:inline-block}
205
- table.dupx-advopts label {white-space:nowrap; cursor:pointer}
206
- table.dupx-advopts-space {line-height:24px}
207
-
208
- div.error-pane {border:1px solid #efefef; border-left:4px solid #D54E21; padding:0 0 0 10px; margin:2px 0 10px 0}
209
- div.dupx-ui-error {padding-top:2px; font-size:13px; line-height: 20px}
210
-
211
- div.footer-buttons {position:absolute; bottom:10px; padding:10px; right:0; width:100%; text-align:right}
212
- div.footer-buttons input:hover, button:hover {border:1px solid #000}
213
- div.footer-buttons input[disabled=disabled], button[disabled=disabled]{background-color:#F4F4F4; color:silver; border:1px solid silver;}
214
- form#form-debug {display:block; margin:10px auto; width:750px;}
215
- form#form-debug a {display:inline-block;}
216
- form#form-debug pre {margin-top:-2px; display:none}
217
-
218
- /*Dialog Info */
219
- div.dlg-serv-info {line-height:22px; font-size:12px}
220
- div.dlg-serv-info label {display:inline-block; width:200px; font-weight: bold}
221
- div.dlg-serv-info div.hdr {font-weight: bold; margin-top:5px; padding:2px 5px 2px 0; border-bottom: 1px solid #777; font-size:14px}
222
- div.dupx-modes {color:#999; font-weight:normal; font-style:italic; font-size:11px; padding:5px 10px 0 0; text-align:right}
223
-
224
- /* ============================
225
- INIT 1:SECURE PASSWORD
226
- ============================ */
227
- button.pass-toggle {height:26px; width:26px; position:absolute; top:0px; right:0px; border:1px solid silver; border-radius:0 4px 4px 0;padding:2px 0 0 3px;}
228
- button.pass-toggle i { padding:0; display:block; margin:-4px 0 0 -5px}
229
- div.i1-pass-area {
230
- width:100%;
231
- text-align:center;
232
- max-width: 300px;
233
- margin: auto;
234
- position: relative;
235
- }
236
- div.i1-pass-data table {width:100%; border-collapse:collapse; padding:0}
237
- div.i1-pass-data label {
238
- display: block;
239
- margin-bottom: 10px;
240
- font-weight:bold;
241
- }
242
- div.i1-pass-errmsg {color:maroon; font-weight:bold}
243
- div#i1-pass-input {position:relative; margin:2px 0 15px 0}
244
- input#secure-pass {border-radius:4px 0 0 4px; width:250px}
245
-
246
-
247
- /* ============================
248
- STEP 1 VIEW
249
- ============================ */
250
- div#s1-area-setup-type label {cursor:pointer}
251
- div.s1-setup-type-sub {padding:5px 0 0 25px; display:none}
252
- div#s1-area-archive-file .ui-widget.ui-widget-content {border: 0px solid #d3d3d3}
253
- table.s1-archive-local {width:100%}
254
- table.s1-archive-local td {padding:4px 4px 4px 4px}
255
- table.s1-archive-local td:first-child {font-weight:bold; width:55px}
256
- div.s1-archive-failed-msg {padding:15px; border:1px dashed maroon; font-size: 12px; border-radius:5px;}
257
- div.s1-err-msg {padding:0 0 80px 0; line-height:20px}
258
- div.s1-err-msg i {color:maroon}
259
-
260
- div#s1-area-sys-setup div.info-top {text-align:center; font-style:italic; font-size:11px; padding:0 5px 5px 5px}
261
- table.s1-checks-area {width:100%; margin:0; padding:0}
262
- table.s1-checks-area td.title {font-size:16px; width:100%}
263
- table.s1-checks-area td.title small {font-size:11px; font-weight:normal}
264
- table.s1-checks-area td.toggle {font-size:11px; margin-right:7px; font-weight:normal}
265
-
266
- div.s1-reqs {background-color:#efefef; border:1px solid silver; border-radius:4px; padding-bottom:4px}
267
- div.s1-reqs div.header {background-color:#E0E0E0; color:#000; border-bottom: 1px solid silver; padding:2px; font-weight:bold }
268
- div.s1-reqs div.status {float:right; border-radius:4px; color:#fff; padding:0 3px 0 3px; margin:4px 5px 0 0; font-size:11px; min-width:30px; text-align:center;}
269
- div.s1-reqs div.pass {background-color:green;}
270
- div.s1-reqs div.fail {background-color:maroon;}
271
- div.s1-reqs div.title {padding:3px 3px 3px 5px; font-size:13px;}
272
- div.s1-reqs div.title:hover {background-color:#dfdfdf; cursor:pointer}
273
- div.s1-reqs div.info {padding:8px 8px 20px 8px; background-color:#fff; display:none; line-height:18px; font-size: 12px}
274
- div.s1-reqs div.info a {color:#485AA3;}
275
- select#archive_engine {width:90%; cursor:pointer}
276
-
277
- /*Terms and Notices*/
278
- div#s1-warning-check label{cursor:pointer;}
279
- div#s1-warning-msg {padding:5px;font-size:12px; color:#333; line-height:14px;font-style:italic; overflow-y:scroll; height:460px; border:1px solid #dfdfdf; background:#fff; border-radius:3px}
280
- div#s1-warning-check {padding:3px; font-size:14px; font-weight:normal;}
281
- input#accept-warnings {height: 17px; width:17px}
282
-
283
- /* ============================
284
- STEP 2 VIEW
285
- ============================ */
286
- div.s2-opts label {cursor:pointer}
287
- textarea#debug-dbtest-json {width:98%; height:200px}
288
- div.php-chuncking-warning {font-style:italic; font-size:11px; color:maroon; white-space:normal; line-height:16px; padding-left:20px}
289
-
290
- /*Toggle Buttons */
291
- div.s2-btngrp {text-align:center; margin:0 auto 10px auto}
292
- div.s2-btngrp input[type=button] {font-size:14px; padding:6px; width:120px; border:1px solid silver; cursor:pointer}
293
- div.s2-btngrp input[type=button]:first-child {border-radius:5px 0 0 5px; margin-right:-2px}
294
- div.s2-btngrp input[type=button]:last-child {border-radius:0 5px 5px 0; margin-left:-4px}
295
- div.s2-btngrp input[type=button].active {background-color:#13659C; color:#fff;}
296
- div.s2-btngrp input[type=button].in-active {background-color:#E4E4E4; }
297
- div.s2-btngrp input[type=button]:hover {border:1px solid #999}
298
-
299
- /*Basic DB */
300
- select#dbname-select {width:100%; border-radius:3px; height:20px; font-size:12px; border:1px solid silver;}
301
- div#s2-dbrefresh-basic {float:right; font-size:12px; display:none; font-weight:bold; margin:5px 5px 1px 0}
302
- div#s2-db-basic-overwrite {border: 1px solid silver; margin:5px 0 5px 0; padding:10px; background:#f9f9f9; border-radius:5px}
303
- div#s2-db-basic-overwrite div.warn-text {font-size:12px; padding:5px 0 5px 0; color:maroon}
304
- div#s2-db-basic-overwrite div.btn-area {text-align: right; margin:5px 0}
305
- input.overwrite-btn {
306
- cursor:pointer; color:#fff; font-size:13px; border-radius:5px; padding:5px 20px 4px 20px;
307
- background-color:#989898; border:1px solid #777;
308
- }
309
-
310
- /*cPanel DB */
311
- div.s2-cpnl-pane {margin-top:5px}
312
- div.s2-gopro {color: black; margin-top:10px; padding:0 20px 10px 20px; border: 1px solid silver; background-color:#F6F6F6; border-radius: 4px}
313
- div.s2-gopro h2 {text-align: center; margin:10px}
314
- div.s2-gopro small {font-style: italic}
315
- div.s2-cpanel-login {padding:15px; color:#fff; text-align:center; margin:15px 5px 15px 5px; border:1px solid silver; border-radius:5px; background-color:#13659C; font-size:14px; line-height:22px}
316
- div.s2-cpanel-off {padding:15px; color:#fff; text-align:center; margin:15px 5px 15px 5px; border:1px solid silver; border-radius:5px; background-color:#b54949; font-size:14px; line-height:22px}
317
- div.s2-cpnl-panel-no-support {text-align:center; font-size:18px; font-weight:bold; line-height:30px; margin-top:40px}
318
-
319
- /*DATABASE CHECKS */
320
- div.s2-dbtest-area {margin:auto; margin:5px 0 15px 0; min-height:110px}
321
- div.s2-dbtest-area input[type=button] {font-size:11px; height:20px; border:1px solid gray; border-radius:3px; cursor:pointer}
322
- div.s2-dbtest-area small.db-check {color:#000; text-align:center; padding:3px; font-size:11px; font-weight:normal }
323
- div.s2-dbtest-area div.message {padding:10px 10px 10px 10px; margin:5px auto 5px auto; text-align:center; font-style:italic; font-size:15px; line-height:22px; width:100%;}
324
- div.s2-dbtest-area div.sub-message {padding:5px; text-align:center; font-style:italic; color:maroon}
325
- div.s2-dbtest-area div.error-msg {color:maroon}
326
- div.s2-dbtest-area div.success-msg {color:green}
327
- div.s2-dbtest-area pre {font-family:Verdana,Arial,sans-serif; font-size:13px; margin:0; white-space:normal;}
328
-
329
- div.s2-reqs-hdr {border-radius:0; border-top-right-radius:6px; border-top-left-radius:6px; border-bottom:none}
330
- div.s2-notices-hdr {border-radius:0; border-bottom:1px solid #D3D3D3; }
331
- div#s2-reqs-all {display:none}
332
- div#s2-notices-all {display:none}
333
-
334
- div.s2-reqs {background-color:#efefef; border:1px solid #D3D3D3; border-top:none}
335
- div.s2-reqs div.status {float:right; border-radius:4px; color:#fff; padding:0 4px 0 4px; margin:4px 7px 0 0; font-size:12px; min-width:30px; text-align:center;}
336
- div.s2-reqs div.title {padding:3px 8px 3px 20px; font-size:13px; background-color:#f1f1f1; border-top: 1px solid #D3D3D3;}
337
- div.s2-reqs div.title:hover {background-color:#dfdfdf; cursor:pointer}
338
- div.s2-reqs div.info {padding:4px 12px 15px 12px;; background-color:#fff; display:none; line-height:18px; font-size: 12px}
339
- div.s2-reqs div.info a {color:#485AA3;}
340
- div.s2-reqs div.info ul {padding-left:25px}
341
- div.s2-reqs div.info ul li {padding:2px}
342
- div.s2-reqs div.info ul.vids {list-style-type: none;}
343
- div.s2-reqs div.sub-title{border-bottom: 1px solid #d3d3d3; font-weight:bold; margin:7px 0 3px 0}
344
-
345
- div.s2-reqs10 table {margin-top:5px;}
346
- div.s2-reqs10 table td {padding:1px;}
347
- div.s2-reqs10 table td:first-child {font-weight:bold; padding-right:10px}
348
- div.s2-reqs40 div.db-list {height:70px; width:95%; overflow-y:scroll; padding:2px 5px 5px 5px; border:1px solid #d3d3d3;}
349
- div.s2-reqs60 div.tbl-list {padding:2px 5px 5px 5px; border:0 }
350
- div.s2-reqs60 div.tbl-list b {display:inline-block; width:55px; }
351
-
352
- div.s2-notice20 table.collation-list table {padding:2px;}
353
- div.s2-notice20 table.collation-list td:first-child {font-weight:bold; padding-right:5px }
354
-
355
- /*Warning Area and Message */
356
- div.s2-warning-emptydb {color:maroon; margin:2px 0 0 0; font-size:11px; display: none; white-space:normal; width: 550px}
357
- div.s2-warning-manualdb {color:#1B67FF; margin:2px 0 0 0; font-size:11px; display:none; white-space:normal; width: 550px}
358
- div.s2-warning-renamedb {color:#1B67FF; margin:2px 0 0 0; font-size:11px; display:none; white-space:normal; width: 550px}
359
- div#s2-tryagain {padding-top:50px; text-align:center; width:100%; font-size:16px; color:#444; font-weight:bold;}
360
-
361
- /* ============================
362
- STEP 3 VIEW
363
- ============================ */
364
- table.s3-opts{width:96%; border:0;}
365
- table.s3-opts i.fa{font-size:16px}
366
- table.s3-opts td{white-space:nowrap; padding:3px;}
367
- table.s3-opts td:first-child{width:90px; font-weight: bold}
368
- div#s3-adv-opts {margin-top:5px; }
369
- div.s3-allnonelinks {font-size:11px; float:right;}
370
- div.s3-manaual-msg {font-style: italic; margin:-2px 0 5px 0}
371
- small.s3-warn {color:maroon; font-style:italic}
372
-
373
- /* ============================
374
- STEP 4 VIEW
375
- ============================ */
376
- div.s4-final-msg {height:110px; border:1px solid #CDCDCD; padding:8px;font-size:12px; border-radius:5px;box-shadow:0 4px 2px -2px #777;}
377
- div.s4-final-title {color:#BE2323; font-size:18px}
378
- div.s4-connect {font-size:12px; text-align:center; font-style:italic; position:absolute; bottom:10px; padding:10px; width:100%; margin-top:20px}
379
- table.s4-report-results,
380
- table.s4-report-errs {border-collapse:collapse; box-shadow: 4px 8px 11px -8px rgba(0,0,0,0.41);}
381
- table.s4-report-errs td {text-align:center; width:33%}
382
- table.s4-report-results th, table.s4-report-errs th {background-color:#d0d0d0; padding:3px; font-size:14px;}
383
- table.s4-report-results td, table.s4-report-errs td {padding:3px; white-space:nowrap; border:1px solid #dfdfdf; text-align:center; font-size:11px}
384
- table.s4-report-results td:first-child {text-align:left; font-weight:bold; padding-left:3px}
385
- div.s4-err-title {background-color:#dfdfdf; font-weight: bold; margin:-3px 0 15px 0; padding:5px; border-radius:3px; font-size:13px}
386
-
387
- div.s4-err-msg {padding:8px; display:none; border:1px dashed #999; margin:10px 0 20px 0; border-radius:5px;}
388
- div.s4-err-msg div.content{padding:5px; font-size:11px; line-height:17px; max-height:125px; overflow-y:scroll; border:1px solid silver; margin:3px; }
389
- div.s4-err-msg div.info-error{padding:7px; background-color:#f9c9c9; border:1px solid silver; border-radius:2px; font-size:12px; line-height:16px }
390
- div.s4-err-msg div.info-notice{padding:7px; background-color:#FCFEC5; border:1px solid silver; border-radius:2px; font-size:12px; line-height:16px;}
391
- table.s4-final-step {width:100%;}
392
- table.s4-final-step td {padding:5px 15px 5px 5px;font-size:13px; }
393
- table.s4-final-step td:first-child {white-space:nowrap; width:165px}
394
- div.s4-go-back {border-top:1px dotted #dfdfdf; margin:auto;font-size:11px; color:#333; padding-top:4px}
395
- div.s4-go-back ul {line-height:18px}
396
- button.s4-final-btns {cursor:pointer; color:#fff; font-size:16px; border-radius:5px; padding:7px; background-color:#13659C; border:1px solid gray; width:145px;}
397
- button.s4-final-btns:hover {background-color: #dfdfdf;}
398
- div.s4-gopro-btn {text-align:center; font-size:14px; margin:auto; width:200px; font-style: italic; font-weight:bold}
399
- div.s4-gopro-btn a{color:green}
400
- div.s4-warn {color:maroon;}
401
- pre.s4-diff-viewer {line-height:11px}
402
- div#s4-notice-reports div.section-content div.title {cursor:pointer}
403
-
404
- /* ============================
405
- STEP 5 HELP
406
- ============================ */
407
- #body-help div#content {
408
- width: 100%;
409
- max-width: 1024px;
410
- }
411
- div.help-target {float:right;}
412
- div.help-target a {float:right; font-size:16px; color:#13659C}
413
- div#main-help sup {font-size:11px; font-weight:normal; font-style:italic; color:blue}
414
- div.help-online {text-align:center; font-size:18px; padding:10px 0 0 0; line-height:24px}
415
- div.help {color:#555; font-style:italic; font-size:11px; padding:4px; border-top:1px solid #dfdfdf}
416
- div.help-page fieldset {margin-bottom:25px}
417
- div#main-help {font-size:13px; line-height:17px}
418
- div#main-help h3 {border-bottom:1px solid silver; padding:8px; margin:4px 0 8px 0; font-size:20px}
419
- div#main-help span.step {color:#DB4B38}
420
- .help-opt {width: 100%; border: none; border-collapse: collapse; margin:5px 0 0 0;}
421
- .help-opt .col-opt {
422
- width: 250px;
423
- }
424
- .help-opt td.section {background-color:#dfdfdf;}
425
- .help-opt td, .help-opt th {padding:15px 10px; border:1px solid silver;}
426
- .help-opt td:first-child {font-weight:bold; padding-right:10px; white-space:nowrap}
427
- .help-opt th {background: #333; color: #fff;border:1px solid #333 }
428
-
429
- #main-help section {
430
- border: 1px solid silver;
431
- margin-top: 28px;
432
- border-radius: 4px;
433
- overflow: hidden;
434
- }
435
-
436
- #main-help section h2.header {
437
- background-color:#F1F1F1;
438
- padding:15px;
439
- margin:0;
440
- font-size:20px;
441
- }
442
-
443
- #main-help section .content {
444
- padding: 10px;
445
- }
446
-
447
- /* ============================
448
- Expandable section
449
- ============================ */
450
- .expandable.close .expand-header {
451
- cursor:pointer;
452
- }
453
-
454
- .expandable.open .expand-header {
455
- cursor:pointer;
456
- }
457
-
458
- .expandable .expand-header::before {
459
- font-family: 'Font Awesome 5 Free';
460
- margin-right: 10px;
461
- }
462
-
463
- .expandable.close .expand-header::before {
464
- content: "\f0fe";
465
- }
466
-
467
- .expandable.open .expand-header::before {
468
- content: "\f146";
469
- }
470
-
471
- .expandable.close .content {
472
- display: none;
473
- }
474
-
475
- .expandable.open .content {
476
- display: block;
477
- }
478
-
479
- /* ============================
480
- VIEW EXCEPTION
481
- ============================ */
482
- .exception-trace {
483
- overflow: auto;
484
- border: 1px solid lightgray;
485
- padding: 10px;
486
- margin: 0;
487
- }
488
-
489
-
490
- /*!
491
- * password indicator
492
- */
493
-
494
- .top_testresult{
495
- font-weight:bold; font-size:11px; color:#222; display: block;
496
- position: absolute;
497
- top: 0;
498
- right: 30px;
499
- text-align: right;
500
- padding-right: 20px;
501
- box-sizing: border-box;
502
- width: 40%;
503
- height: 30px;
504
- line-height: 30px;
505
- }
506
-
507
-
508
- .top_shortPass,
509
- .top_badPass {
510
- background:#edabab;
511
- background: transparent linear-gradient(90deg, transparent 20%, #edabab);
512
- display:block;
513
- }
514
- .top_goodPass{
515
- background:#ffffe0;
516
- background: transparent linear-gradient(90deg, transparent 20%, #ffffe0);
517
- display:block;
518
- }
519
- .top_strongPass{
520
- background:#d3edab;
521
- background: transparent linear-gradient(90deg, transparent 20%, #d3edab);
522
- display:block;
523
- }
524
-
525
- /*================================================
526
- LIB OVERIDES*/
527
- input.parsley-error, textarea.parsley-error, select.parsley-error {
528
- color:#B94A48 !important;
529
- background-color:#F2DEDE !important;
530
- border:1px solid #EED3D7 !important;
531
- }
532
- ul.parsley-errors-list {margin:1px 0 0 -40px; list-style-type:none; font-size:10px}
533
- .ui-widget {font-size:13px}
534
-
535
-
536
- <?php if (DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)): ?>
537
- .dupx-debug {display:block; margin:0 0 25px 0; font-size:11px; background-color:#f5dbda; padding:8px; border:1px solid silver; border-radius:4px}
538
- .dupx-debug label {font-weight:bold; display:block; margin:4px 0 1px 0}
539
- .dupx-debug textarea {width:95%; height:100px; font-size:11px}
540
- .dupx-debug input {font-size:11px; padding:3px}
541
- <?php else : ?>
542
- .dupx-debug {display:none}
543
- <?php endif; ?>
544
-
545
- </style>
546
- <?php
547
- DUPX_U_Html::css();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; ?>
2
+ <style>
3
+ body {font-family:Verdana,Arial,sans-serif; font-size:13px}
4
+ fieldset {border:1px solid silver; border-radius:5px; padding:10px}
5
+ h3 {margin:1px; padding:1px; font-size:13px;}
6
+ a {color:#222}
7
+ a:hover{color:gray}
8
+
9
+ input:not([type=checkbox]):not([type=radio]):not([type=button]) , select {
10
+ width: 100%;
11
+ border-radius: 2px;
12
+ border: 1px solid silver;
13
+ padding: 4px;
14
+ padding-left: 4px;
15
+ font-family: Verdana,Arial,sans-serif;
16
+ line-height: 20px;
17
+ height: 30px;
18
+ box-sizing: border-box;
19
+ background-color: white;
20
+ color: black;
21
+ border-radius: 4px;
22
+ }
23
+
24
+ input[readonly]:not([type="checkbox"]):not([type="radio"]):not([type="button"]),
25
+ select[readonly],
26
+ select[readonly] option{
27
+ background-color: darkgray;
28
+ color: white;
29
+ cursor: not-allowed;
30
+ }
31
+
32
+ select[size] {
33
+ height: auto;
34
+ line-height: 25px;
35
+ }
36
+
37
+ select , option {
38
+ color: black;
39
+ }
40
+ select {
41
+ padding-left:0;
42
+ }
43
+ select option {
44
+ padding: 2px 5px;
45
+ }
46
+ select option:disabled {
47
+ text-decoration: line-through;
48
+ cursor: not-allowed;
49
+ color: #A9A9A9;
50
+ }
51
+
52
+ select:disabled {background:#EBEBE4}
53
+ input.readonly {background-color:#efefef;}
54
+ .no-display { display: none; }
55
+
56
+ /* ============================
57
+ COMMON VIEWS
58
+ ============================ */
59
+ div#content {border:1px solid #CDCDCD; width:850px; min-height:550px; margin:auto; margin-top:18px; border-radius:5px; box-shadow:0 8px 6px -6px #333; font-size:13px}
60
+ div#content-inner {padding:10px 25px; min-height:550px}
61
+ form.content-form {min-height:550px; position:relative; line-height:17px}
62
+ div.logfile-link {float:right; font-weight:normal; font-size:11px; font-style:italic}
63
+ span.sub-notes {font-size:10px;}
64
+
65
+ /* Header */
66
+ table.header-wizard {border-top-left-radius:5px; border-top-right-radius:5px; width:100%; box-shadow:0 5px 3px -3px #999; background-color:#F1F1F1; font-weight:bold}
67
+ div.dupx-logfile-link {float:right; font-weight:normal; font-style:italic; font-size:11px; cursor:pointer}
68
+ .wiz-dupx-version {white-space:nowrap; color:#777; font-size:11px; font-style:italic; text-align:right; padding:3px 15px 5px 0; line-height:14px; font-weight:normal}
69
+ .wiz-dupx-version a { color:#777; }
70
+ div.dupx-debug-hdr {padding:5px 0 5px 0; font-size:16px; font-weight:bold}
71
+ div.dupx-branding-header {font-size:26px; padding: 10px 0 7px 15px;}
72
+
73
+ .dupx-overwrite {color:#AF0000;}
74
+ .dupx-pass {display:inline-block; color:green;}
75
+ .dupx-fail {display:inline-block; color:#AF0000;}
76
+ .dupx-warn {display:inline-block; color:#555;}
77
+ .dupx-notice {display:inline-block; color:#000;}
78
+ i[data-tooltip].fa-question-circle {cursor: pointer; color:#C3C3C3}
79
+ div.status-badge-pass {background-color:#418446;}
80
+ div.status-badge-fail {background-color:maroon;}
81
+ div.status-badge-warn {background-color:#555;}
82
+ div.status-badge-pass, div.status-badge-fail, div.status-badge-warn {float:right; border-radius:4px; color:#fff; padding:0 3px 0 3px; font-size:11px !important; min-width:30px; text-align:center; font-weight:normal;}
83
+ button.default-btn, .default-btn, .default-btn:hover {
84
+ cursor:pointer; color:#fff; font-size:16px; border-radius:5px; padding:7px 25px 5px 25px;
85
+ background-color:#13659C; border:1px solid gray; text-decoration: none;
86
+ }
87
+ button.disabled, input.disabled {background-color:#F4F4F4; color:silver; border:1px solid silver;}
88
+
89
+ div.log-ui-error {padding-top:2px; font-size:13px}
90
+ div#progress-area {padding:5px; margin:150px 0 0 0; text-align:center;}
91
+ div#ajaxerr-data {padding:6px; height:425px; width:99%; border:1px solid silver; border-radius:5px; background-color:#F1F1F1; font-size:13px; overflow-y:scroll; line-height:20px}
92
+ div.hdr-main {font-size:22px; padding:0 0 5px 0; border-bottom:1px solid #D3D3D3; font-weight:bold; margin:15px 0 20px 0;}
93
+ div.hdr-main span.step {color:#DB4B38}
94
+
95
+ div.sub-header {font-size:11px; font-style:italic; font-weight:normal; margin:5px 0 -1px 0}
96
+ div.hdr-sub1 {font-size:18px; margin-bottom:5px;border:1px solid #D3D3D3;padding:7px; background-color:#f9f9f9; font-weight:bold; border-radius:4px}
97
+ div.hdr-sub1 a {cursor:pointer; text-decoration: none !important}
98
+ div.hdr-sub1 i.fa {font-size:15px; display:inline-block; margin:2px 5px 0 0; vertical-align:top}
99
+ div.hdr-sub1-area {padding:5px}
100
+ div.hdr-sub2 {font-size:15px; padding:2px 2px 2px 0; font-weight:bold; margin-bottom:5px; border:none}
101
+ div.hdr-sub3 {font-size:15px; padding:2px 2px 2px 0; border-bottom:1px solid #D3D3D3; font-weight:bold; margin-bottom:5px;}
102
+ div.hdr-sub4 {font-size:15px; padding:7px; border:1px solid #D3D3D3;; font-weight:bold; background-color:#e9e9e9;}
103
+ div.hdr-sub4:hover {background-color:#dfdfdf; cursor:pointer}
104
+ div.toggle-hdr:hover {cursor:pointer; background-color:#f1f1f1; border:1px solid #dcdcdc; }
105
+ div.toggle-hdr:hover a{color:#000}
106
+
107
+ [data-type="toggle"] > i.fa,
108
+ i.fa.fa-toggle-empty { min-width: 8px; }
109
+
110
+ /* ============================
111
+ NOTICES
112
+ ============================ */
113
+ /* step messages */
114
+ #step-messages { padding: 10px 25px 0; }
115
+ .notice {
116
+ background: #fff;
117
+ border:1px solid #dfdfdf;
118
+ border-left: 4px solid #fff;
119
+ margin: 4px;
120
+ padding: 5px;
121
+ border-radius: 4px;
122
+ font-size: 12px;
123
+ }
124
+
125
+ .notice-report {
126
+ border-left: 4px solid #fff;
127
+ padding-left: 0;
128
+ padding-right: 0;
129
+ margin-bottom: 4px;
130
+ }
131
+
132
+ .next-step .title-separator {
133
+ margin-top: 5px;
134
+ padding-top: 5px;
135
+ border-top: 1px solid lightgray;
136
+ }
137
+
138
+ .notice .info pre {
139
+ margin: 0;
140
+ padding: 0;
141
+ overflow: auto;
142
+ }
143
+
144
+ .notice-report .title {
145
+ padding: 0 10px;
146
+ }
147
+
148
+ .notice-report .info {
149
+ border-top: 1px solid #dedede;
150
+ padding: 10px;
151
+ font-size: 10px;
152
+ background: #FAFAFA;
153
+ word-wrap: break-word;
154
+ }
155
+
156
+ .notice.l-info,
157
+ .notice.l-notice {border-left-color: #197b19;}
158
+ .notice.l-swarning {border-left-color: #636363;}
159
+ .notice.l-hwarning {border-left-color: #636363;}
160
+ .notice.l-critical {border-left-color: maroon;}
161
+ .notice.l-fatal {border-left-color: #000000;}
162
+
163
+ .report-sections-list .section {
164
+ border: 1px solid #DFDFDF;
165
+ margin-bottom: 25px;
166
+ box-shadow: 4px 8px 11px -8px rgba(0,0,0,0.41);
167
+ }
168
+
169
+ .report-sections-list .section > .section-title {
170
+ background-color: #efefef;
171
+ padding: 3px;
172
+ font-weight: bold;
173
+ text-align: center;
174
+ font-size: 14px;
175
+ }
176
+
177
+ .report-sections-list .section > .section-content {
178
+ padding: 5px;
179
+ }
180
+
181
+ .notice-level-status {
182
+ border-radius: 4px;
183
+ padding: 2px;
184
+ margin: 1px;
185
+ font-size: 10px;
186
+ display: inline-block;
187
+ color: #FFF;
188
+ font-weight: bold;
189
+ min-width:55px;
190
+ }
191
+
192
+ .notice-level-status.l-info,
193
+ .notice-level-status.l-notice {background: #197b19;}
194
+ .notice-level-status.l-swarning {background: #636363;}
195
+ .notice-level-status.l-hwarning {background: #636363;}
196
+ .notice-level-status.l-critical {background: maroon;}
197
+ .notice-level-status.l-fatal {background: #000000;}
198
+
199
+ .gray-panel {
200
+ border: 1px solid silver;
201
+ margin:5px 0;
202
+ padding:10px;
203
+ background:#f9f9f9;
204
+ border-radius:5px
205
+ }
206
+ .gray-panel.warn-text,
207
+ .gray-panel .warn-text {
208
+ font-size:12px;
209
+ color:maroon
210
+ }
211
+ .gray-panel-overwrite {
212
+ font-size:14px !important;
213
+ line-height:25px;
214
+ }
215
+
216
+ /*Adv Opts */
217
+ table.dupx-opts {width:100%; border:0px;}
218
+ table.dupx-opts td{padding:3px;}
219
+ table.dupx-opts td:first-child{width:125px; font-weight: bold}
220
+ table.dupx-advopts td:first-child{width:125px;}
221
+ table.dupx-advopts label.radio {width:50px; display:inline-block}
222
+ table.dupx-advopts label {white-space:nowrap; cursor:pointer}
223
+ table.dupx-advopts-space {line-height:24px}
224
+
225
+ div.error-pane {border:1px solid #efefef; border-left:4px solid #D54E21; padding:0 0 0 10px; margin:2px 0 10px 0}
226
+ div.dupx-ui-error {padding-top:2px; font-size:13px; line-height: 20px}
227
+
228
+ div.footer-buttons {position:absolute; bottom:10px; padding:10px; right:0; width:100%; text-align:right}
229
+ div.footer-buttons input:hover, button:hover {border:1px solid #000}
230
+ div.footer-buttons input[disabled=disabled], button[disabled=disabled]{background-color:#F4F4F4; color:silver; border:1px solid silver;}
231
+ form#form-debug {display:block; margin:10px auto; width:750px;}
232
+ form#form-debug a {display:inline-block;}
233
+ form#form-debug pre {margin-top:-2px; display:none}
234
+
235
+ /*Dialog Info */
236
+ div.dlg-serv-info {line-height:22px; font-size:12px}
237
+ div.dlg-serv-info label {display:inline-block; width:200px; font-weight: bold}
238
+ div.dlg-serv-info div.hdr {font-weight: bold; margin-top:5px; padding:2px 5px 2px 0; border-bottom: 1px solid #777; font-size:14px}
239
+ div.dupx-modes {color:#999; font-weight:normal; font-style:italic; font-size:11px; padding:5px 10px 0 0; text-align:right}
240
+
241
+ /* ============================
242
+ INIT 1:SECURE PASSWORD
243
+ ============================ */
244
+ button.pass-toggle {height:26px; width:26px; position:absolute; top:0px; right:0px; border:1px solid silver; border-radius:0 4px 4px 0;padding:2px 0 0 3px;}
245
+ button.pass-toggle i { padding:0; display:block; margin:-4px 0 0 -5px}
246
+ div.i1-pass-area {
247
+ width:100%;
248
+ text-align:center;
249
+ max-width: 300px;
250
+ margin: auto;
251
+ position: relative;
252
+ }
253
+ div.i1-pass-data table {width:100%; border-collapse:collapse; padding:0}
254
+ div.i1-pass-data label {
255
+ display: block;
256
+ margin-bottom: 10px;
257
+ font-weight:bold;
258
+ }
259
+ div.i1-pass-errmsg {color:maroon; font-weight:bold}
260
+ div#i1-pass-input {position:relative; margin:2px 0 15px 0}
261
+ input#secure-pass {border-radius:4px 0 0 4px; width:250px}
262
+
263
+
264
+ /* ============================
265
+ STEP 1 VIEW
266
+ ============================ */
267
+ div#s1-area-setup-type label {cursor:pointer}
268
+ div.s1-setup-type-sub {padding:5px 0 0 25px; display:none}
269
+ div#s1-area-archive-file .ui-widget.ui-widget-content {border: 0px solid #d3d3d3}
270
+ table.s1-archive-local {width:100%}
271
+ table.s1-archive-local td {padding:4px 4px 4px 4px}
272
+ table.s1-archive-local td:first-child {font-weight:bold; width:55px}
273
+ div.s1-archive-failed-msg {padding:15px; border:1px dashed maroon; font-size: 12px; border-radius:5px;}
274
+ div.s1-err-msg {padding:0 0 80px 0; line-height:20px}
275
+ div.s1-err-msg i {color:maroon}
276
+ .maroon {color:maroon}
277
+ .green {color:green}
278
+
279
+ div#s1-area-sys-setup div.info-top {text-align:center; font-style:italic; font-size:11px; padding:0 5px 5px 5px}
280
+ table.s1-checks-area {width:100%; margin:0; padding:0}
281
+ table.s1-checks-area td.title {font-size:16px; width:100%}
282
+ table.s1-checks-area td.title small {font-size:11px; font-weight:normal}
283
+ table.s1-checks-area td.toggle {font-size:11px; margin-right:7px; font-weight:normal}
284
+
285
+ div.s1-reqs {background-color:#efefef; border:1px solid silver; border-radius:4px; padding-bottom:4px}
286
+ div.s1-reqs div.header {background-color:#E0E0E0; color:#000; border-bottom: 1px solid silver; padding:2px; font-weight:bold }
287
+ div.s1-reqs div.status {float:right; border-radius:4px; color:#fff; padding:0 3px 0 3px; margin:4px 5px 0 0; font-size:11px; min-width:30px; text-align:center;}
288
+ div.s1-reqs div.pass {background-color:green;}
289
+ div.s1-reqs div.fail {background-color:maroon;}
290
+ div.s1-reqs div.title {padding:3px 3px 3px 5px; font-size:13px;}
291
+ div.s1-reqs div.title:hover {background-color:#dfdfdf; cursor:pointer}
292
+ div.s1-reqs div.info {padding:8px 8px 20px 8px; background-color:#fff; display:none; line-height:18px; font-size: 12px}
293
+ div.s1-reqs div.info a {color:#485AA3;}
294
+ #archive_engine, #archive_action_input {width:90%; cursor:pointer}
295
+
296
+ .info > *:first-child {
297
+ margin-top: 0;
298
+ }
299
+
300
+ .info > *:last-child {
301
+ margin-bottom: 0;
302
+ }
303
+
304
+ /*Terms and Notices*/
305
+ div#s1-warning-check label{cursor:pointer;}
306
+ div#s1-warning-msg {padding:5px;font-size:12px; color:#333; line-height:14px;font-style:italic; overflow-y:scroll; height:460px; border:1px solid #dfdfdf; background:#fff; border-radius:3px}
307
+ div#s1-warning-check {padding:3px; font-size:14px; font-weight:normal;}
308
+ .s1-warning-check [type=checkbox] {
309
+ height: 17px;
310
+ width: 17px;
311
+ }
312
+
313
+ /* ============================
314
+ STEP 2 VIEW
315
+ ============================ */
316
+ div.s2-opts label {cursor:pointer}
317
+ textarea#debug-dbtest-json {width:98%; height:200px}
318
+ div.php-chuncking-warning {font-style:italic; font-size:11px; color:maroon; white-space:normal; line-height:16px; padding-left:20px}
319
+
320
+ /*Toggle Buttons */
321
+ div.s2-btngrp {text-align:center; margin:0 auto 10px auto}
322
+ div.s2-btngrp input[type=button] {font-size:14px; padding:6px; width:120px; border:1px solid silver; cursor:pointer}
323
+ div.s2-btngrp input[type=button]:first-child {border-radius:5px 0 0 5px; margin-right:-2px}
324
+ div.s2-btngrp input[type=button]:last-child {border-radius:0 5px 5px 0; margin-left:-4px}
325
+ div.s2-btngrp input[type=button].active {background-color:#13659C; color:#fff;}
326
+ div.s2-btngrp input[type=button].in-active {background-color:#E4E4E4; }
327
+ div.s2-btngrp input[type=button]:hover {border:1px solid #999}
328
+
329
+ /*Basic DB */
330
+ select#dbname-select {width:100%; border-radius:3px; height:20px; font-size:12px; border:1px solid silver;}
331
+ div#s2-dbrefresh-basic {float:right; font-size:12px; display:none; font-weight:bold; margin:5px 5px 1px 0}
332
+ div#s2-db-basic-overwrite div.warn-text {
333
+ padding:5px 0 5px 0;
334
+ }
335
+ div#s2-db-basic-overwrite div.btn-area {
336
+ text-align: right;
337
+ margin:5px 0
338
+ }
339
+ input.overwrite-btn {
340
+ cursor:pointer; color:#fff; font-size:13px; border-radius:5px; padding:5px 20px 4px 20px;
341
+ background-color:#989898; border:1px solid #777;
342
+ }
343
+
344
+ /*cPanel DB */
345
+ div.s2-cpnl-pane {margin-top:5px}
346
+ div.s2-gopro {color: black; margin-top:10px; padding:0 20px 10px 20px; border: 1px solid silver; background-color:#F6F6F6; border-radius: 4px}
347
+ div.s2-gopro h2 {text-align: center; margin:10px}
348
+ div.s2-gopro small {font-style: italic}
349
+ div.s2-cpanel-login {padding:15px; color:#fff; text-align:center; margin:15px 5px 15px 5px; border:1px solid silver; border-radius:5px; background-color:#13659C; font-size:14px; line-height:22px}
350
+ div.s2-cpanel-off {padding:15px; color:#fff; text-align:center; margin:15px 5px 15px 5px; border:1px solid silver; border-radius:5px; background-color:#b54949; font-size:14px; line-height:22px}
351
+ div.s2-cpnl-panel-no-support {text-align:center; font-size:18px; font-weight:bold; line-height:30px; margin-top:40px}
352
+
353
+ /*DATABASE CHECKS */
354
+ div.s2-dbtest-area {margin:auto; margin:5px 0 15px 0; min-height:110px}
355
+ div.s2-dbtest-area input[type=button] {font-size:11px; height:20px; border:1px solid gray; border-radius:3px; cursor:pointer}
356
+ div.s2-dbtest-area small.db-check {color:#000; text-align:center; padding:3px; font-size:11px; font-weight:normal }
357
+ div.s2-dbtest-area div.message {padding:10px 10px 10px 10px; margin:5px auto 5px auto; text-align:center; font-style:italic; font-size:15px; line-height:22px; width:100%;}
358
+ div.s2-dbtest-area div.sub-message {padding:5px; text-align:center; font-style:italic; color:maroon}
359
+ div.s2-dbtest-area div.error-msg {color:maroon}
360
+ div.s2-dbtest-area div.success-msg {color:green}
361
+ div.s2-dbtest-area pre {font-family:Verdana,Arial,sans-serif; font-size:13px; margin:0; white-space:normal;}
362
+
363
+ div.s2-reqs-hdr {border-radius:0; border-top-right-radius:6px; border-top-left-radius:6px; border-bottom:none}
364
+ div.s2-notices-hdr {border-radius:0; border-bottom:1px solid #D3D3D3; }
365
+ div#s2-reqs-all {display:none}
366
+ div#s2-notices-all {display:none}
367
+
368
+ div.s2-reqs {background-color:#efefef; border:1px solid #D3D3D3; border-top:none}
369
+ div.s2-reqs div.status {float:right; border-radius:4px; color:#fff; padding:0 4px 0 4px; margin:4px 7px 0 0; font-size:12px; min-width:30px; text-align:center;}
370
+ div.s2-reqs div.title {padding:3px 8px 3px 20px; font-size:13px; background-color:#f1f1f1; border-top: 1px solid #D3D3D3;}
371
+ div.s2-reqs div.title:hover {background-color:#dfdfdf; cursor:pointer}
372
+ div.s2-reqs div.info {padding:4px 12px 15px 12px;; background-color:#fff; display:none; line-height:18px; font-size: 12px}
373
+ div.s2-reqs div.info a {color:#485AA3;}
374
+ div.s2-reqs div.info ul {padding-left:25px}
375
+ div.s2-reqs div.info ul li {padding:2px}
376
+ div.s2-reqs div.info ul.vids {list-style-type: none;}
377
+ div.s2-reqs div.sub-title{border-bottom: 1px solid #d3d3d3; font-weight:bold; margin:7px 0 3px 0}
378
+
379
+ div.s2-reqs10 table {margin-top:5px;}
380
+ div.s2-reqs10 table td {padding:1px;}
381
+ div.s2-reqs10 table td:first-child {font-weight:bold; padding-right:10px}
382
+ div.s2-reqs40 div.db-list {height:70px; width:95%; overflow-y:scroll; padding:2px 5px 5px 5px; border:1px solid #d3d3d3;}
383
+ div.s2-reqs60 div.tbl-list {padding:2px 5px 5px 5px; border:0 }
384
+ div.s2-reqs60 div.tbl-list b {display:inline-block; width:55px; }
385
+
386
+ div.s2-notice20 table.collation-list table {padding:2px;}
387
+ div.s2-notice20 table.collation-list td:first-child {font-weight:bold; padding-right:5px }
388
+
389
+ textarea[readonly] {background-color: #efefef;}
390
+ .copy-to-clipboard-block textarea {width: 100%; height: 100px;}
391
+
392
+ .copy-to-clipboard-block button,
393
+ .copy-to-clipboard-block button:hover {font-size: 14px; padding: 5px 8px; margin-bottom: 15px;}
394
+
395
+ /*Warning Area and Message */
396
+ div.s2-warning-emptydb {color:maroon; margin:2px 0 0 0; font-size:11px; display: none; white-space:normal; width: 550px}
397
+ div.s2-warning-manualdb {color:#1B67FF; margin:2px 0 0 0; font-size:11px; display:none; white-space:normal; width: 550px}
398
+ div.s2-warning-renamedb {color:#1B67FF; margin:2px 0 0 0; font-size:11px; display:none; white-space:normal; width: 550px}
399
+ div#s2-tryagain {padding-top:50px; text-align:center; width:100%; font-size:16px; color:#444; font-weight:bold;}
400
+
401
+ /* ============================
402
+ STEP 3 VIEW
403
+ ============================ */
404
+ table.s3-opts{width:96%; border:0;}
405
+ table.s3-opts i.fa{font-size:16px}
406
+ table.s3-opts td{white-space:nowrap; padding:3px;}
407
+ table.s3-opts td:first-child{width:90px; font-weight: bold}
408
+ div#s3-adv-opts {margin-top:5px; }
409
+ div.s3-allnonelinks {font-size:11px; float:right;}
410
+ div.s3-manaual-msg {font-style: italic; margin:-2px 0 5px 0}
411
+ small.s3-warn {color:maroon; font-style:italic}
412
+
413
+ /* ============================
414
+ STEP 4 VIEW
415
+ ============================ */
416
+ div.s4-final-msg {height:110px; border:1px solid #CDCDCD; padding:8px;font-size:12px; border-radius:5px;box-shadow:0 4px 2px -2px #777;}
417
+ div.s4-final-title {color:#BE2323; font-size:18px}
418
+ div.s4-connect {font-size:12px; text-align:center; font-style:italic; position:absolute; bottom:10px; padding:10px; width:100%; margin-top:20px}
419
+ table.s4-report-results,
420
+ table.s4-report-errs {border-collapse:collapse; box-shadow: 4px 8px 11px -8px rgba(0,0,0,0.41);}
421
+ table.s4-report-errs td {text-align:center; width:33%}
422
+ table.s4-report-results th, table.s4-report-errs th {background-color:#d0d0d0; padding:3px; font-size:14px;}
423
+ table.s4-report-results td, table.s4-report-errs td {padding:3px; white-space:nowrap; border:1px solid #dfdfdf; text-align:center; font-size:11px}
424
+ table.s4-report-results td:first-child {text-align:left; font-weight:bold; padding-left:3px}
425
+ div.s4-err-title {background-color:#dfdfdf; font-weight: bold; margin:-3px 0 15px 0; padding:5px; border-radius:3px; font-size:13px}
426
+
427
+ div.s4-err-msg {padding:8px; display:none; border:1px dashed #999; margin:10px 0 20px 0; border-radius:5px;}
428
+ div.s4-err-msg div.content{padding:5px; font-size:11px; line-height:17px; max-height:125px; overflow-y:scroll; border:1px solid silver; margin:3px; }
429
+ div.s4-err-msg div.info-error{padding:7px; background-color:#f9c9c9; border:1px solid silver; border-radius:2px; font-size:12px; line-height:16px }
430
+ div.s4-err-msg div.info-notice{padding:7px; background-color:#FCFEC5; border:1px solid silver; border-radius:2px; font-size:12px; line-height:16px;}
431
+ table.s4-final-step {width:100%;}
432
+ table.s4-final-step td {padding:5px 15px 5px 5px;font-size:13px; }
433
+ table.s4-final-step td:first-child {white-space:nowrap; width:165px}
434
+ div.s4-go-back {border-top:1px dotted #dfdfdf; margin:auto;font-size:11px; color:#333; padding-top:4px}
435
+ div.s4-go-back ul {line-height:18px}
436
+ button.s4-final-btns {cursor:pointer; color:#fff; font-size:16px; border-radius:5px; padding:7px; background-color:#13659C; border:1px solid gray; width:145px;}
437
+ button.s4-final-btns:hover {background-color: #dfdfdf;}
438
+ div.s4-gopro-btn {text-align:center; font-size:14px; margin:auto; width:200px; font-style: italic; font-weight:bold}
439
+ div.s4-gopro-btn a{color:green}
440
+ div.s4-warn {color:maroon;}
441
+ pre.s4-diff-viewer {line-height:11px}
442
+ div#s4-notice-reports div.section-content div.title {cursor:pointer}
443
+
444
+ /* ============================
445
+ STEP 5 HELP
446
+ ============================ */
447
+ #body-help div#content {
448
+ width: 100%;
449
+ max-width: 1024px;
450
+ }
451
+ div.help-target {float:right;}
452
+ div.help-target a {float:right; font-size:16px; color:#13659C}
453
+ div#main-help sup {font-size:11px; font-weight:normal; font-style:italic; color:blue}
454
+ div.help-online {text-align:center; font-size:18px; padding:10px 0 0 0; line-height:24px}
455
+ div.help {color:#555; font-style:italic; font-size:11px; padding:4px; border-top:1px solid #dfdfdf}
456
+ div.help-page fieldset {margin-bottom:25px}
457
+ div#main-help {font-size:13px; line-height:17px}
458
+ div#main-help h3 {border-bottom:1px solid silver; padding:8px; margin:4px 0 8px 0; font-size:20px}
459
+ div#main-help span.step {color:#DB4B38}
460
+ .help-opt {width: 100%; border: none; border-collapse: collapse; margin:5px 0 0 0;}
461
+ .help-opt .col-opt {
462
+ width: 250px;
463
+ }
464
+ .help-opt td.section {background-color:#dfdfdf;}
465
+ .help-opt td, .help-opt th {padding:15px 10px; border:1px solid silver;}
466
+ .help-opt td:first-child {font-weight:bold; padding-right:10px; white-space:nowrap}
467
+ .help-opt th {background: #333; color: #fff;border:1px solid #333 }
468
+
469
+ #main-help section {
470
+ border: 1px solid silver;
471
+ margin-top: 28px;
472
+ border-radius: 4px;
473
+ overflow: hidden;
474
+ }
475
+
476
+ #main-help section h2.header {
477
+ background-color:#F1F1F1;
478
+ padding:15px;
479
+ margin:0;
480
+ font-size:20px;
481
+ }
482
+
483
+ #main-help section .content {
484
+ padding: 10px;
485
+ }
486
+
487
+ /* ============================
488
+ Expandable section
489
+ ============================ */
490
+ .expandable.close .expand-header {
491
+ cursor:pointer;
492
+ }
493
+
494
+ .expandable.open .expand-header {
495
+ cursor:pointer;
496
+ }
497
+
498
+ .expandable .expand-header::before {
499
+ font-family: 'Font Awesome 5 Free';
500
+ margin-right: 10px;
501
+ }
502
+
503
+ .expandable.close .expand-header::before {
504
+ content: "\f0fe";
505
+ }
506
+
507
+ .expandable.open .expand-header::before {
508
+ content: "\f146";
509
+ }
510
+
511
+ .expandable.close .content {
512
+ display: none;
513
+ }
514
+
515
+ .expandable.open .content {
516
+ display: block;
517
+ }
518
+
519
+ /* ============================
520
+ VIEW EXCEPTION
521
+ ============================ */
522
+ .exception-trace {
523
+ overflow: auto;
524
+ border: 1px solid lightgray;
525
+ padding: 10px;
526
+ margin: 0;
527
+ }
528
+
529
+
530
+ /*!
531
+ * password indicator
532
+ */
533
+
534
+ .top_testresult{
535
+ font-weight:bold; font-size:11px; color:#222; display: block;
536
+ position: absolute;
537
+ top: 0;
538
+ right: 30px;
539
+ text-align: right;
540
+ padding-right: 20px;
541
+ box-sizing: border-box;
542
+ width: 40%;
543
+ height: 30px;
544
+ line-height: 30px;
545
+ }
546
+
547
+
548
+ .top_shortPass,
549
+ .top_badPass {
550
+ background:#edabab;
551
+ background: transparent linear-gradient(90deg, transparent 20%, #edabab);
552
+ display:block;
553
+ }
554
+ .top_goodPass{
555
+ background:#ffffe0;
556
+ background: transparent linear-gradient(90deg, transparent 20%, #ffffe0);
557
+ display:block;
558
+ }
559
+ .top_strongPass{
560
+ background:#d3edab;
561
+ background: transparent linear-gradient(90deg, transparent 20%, #d3edab);
562
+ display:block;
563
+ }
564
+
565
+ /*================================================
566
+ LIB OVERIDES*/
567
+ input.parsley-error, textarea.parsley-error, select.parsley-error {
568
+ color:#B94A48 !important;
569
+ background-color:#F2DEDE !important;
570
+ border:1px solid #EED3D7 !important;
571
+ }
572
+ ul.parsley-errors-list {margin:1px 0 0 -40px; list-style-type:none; font-size:10px}
573
+ .ui-widget {font-size:13px}
574
+
575
+
576
+ <?php if (DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)): ?>
577
+ .dupx-debug {display:block; margin:0 0 25px 0; font-size:11px; background-color:#f5dbda; padding:8px; border:1px solid silver; border-radius:4px}
578
+ .dupx-debug label {font-weight:bold; display:block; margin:4px 0 1px 0}
579
+ .dupx-debug textarea {width:95%; height:100px; font-size:11px}
580
+ .dupx-debug input {font-size:11px; padding:3px}
581
+ <?php else : ?>
582
+ .dupx-debug {display:none}
583
+ <?php endif; ?>
584
+
585
+ </style>
586
+ <?php
587
+ DUPX_U_Html::css();
installer/dup-installer/assets/inc.js.php CHANGED
@@ -76,6 +76,24 @@
76
  }
77
  }
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  DUPX.toggleAll = function(id) {
80
  $(id + " *[data-type='toggle']").each(function() {
81
  $(this).trigger('click');
@@ -125,7 +143,6 @@
125
  : $(this).html("+ " + text );
126
  target.hide();
127
  }
128
-
129
  }
130
 
131
  DUPX.Util.formatBytes = function (bytes,decimals)
@@ -140,6 +157,27 @@
140
 
141
  $(document).ready(function()
142
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  <?php if (DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)) : ?>
144
  $("div.dupx-debug input[type=hidden], div.dupx-debug textarea").each(function() {
145
  var label = '<label>' + $(this).attr('name') + ':</label>';
76
  }
77
  }
78
 
79
+ DUPX.initToggle = function() {
80
+ $("body").on('click', "*[data-type~='toggle']", DUPX.toggleClick);
81
+
82
+ var hasFailedReq = false;
83
+ $("*[data-type~='auto'][data-status='fail']").each(function(){
84
+ hasFailedReq = true;
85
+ $(this).trigger('click');
86
+ });
87
+
88
+ $("*[data-type~='auto'][data-status='warn']").each(function(){
89
+ if (hasFailedReq) {
90
+ return ;
91
+ }
92
+
93
+ $(this).trigger('click');
94
+ });
95
+ }
96
+
97
  DUPX.toggleAll = function(id) {
98
  $(id + " *[data-type='toggle']").each(function() {
99
  $(this).trigger('click');
143
  : $(this).html("+ " + text );
144
  target.hide();
145
  }
 
146
  }
147
 
148
  DUPX.Util.formatBytes = function (bytes,decimals)
157
 
158
  $(document).ready(function()
159
  {
160
+ $('body').on( "click", ".copy-to-clipboard-block button", function(e) {
161
+ e.preventDefault();
162
+ var button = $(this);
163
+ var buttonText = button.html();
164
+ var textarea = button.parent().find("textarea")[0];
165
+
166
+ textarea.select();
167
+
168
+ try {
169
+ message = document.execCommand('copy') ? "Copied to Clipboard" : 'Unable to copy';
170
+ } catch (err) {
171
+ console.log(err);
172
+ }
173
+
174
+ button.html(message);
175
+
176
+ setTimeout(function () {
177
+ button.text(buttonText);
178
+ }, 2000);
179
+ });
180
+
181
  <?php if (DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)) : ?>
182
  $("div.dupx-debug input[type=hidden], div.dupx-debug textarea").each(function() {
183
  var label = '<label>' + $(this).attr('name') + ':</label>';
installer/dup-installer/assets/inc.libs.js CHANGED
@@ -103,28 +103,6 @@ r};b.C.prototype=new b.v;b.C.prototype.renderTemplateSource=function(a){var d=!(
103
  var f=b.data("precompiled");f||(f=b.text()||"",f=F.template(p,"{{ko_with $item.koBindingContext}}"+f+"{{/ko_with}}"),b.data("precompiled",f));b=[c.$data];c=F.extend({koBindingContext:c},e.templateOptions);c=F.tmpl(f,b,c);c.appendTo(y.createElement("div"));F.fragments={};return c};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){y.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(F.tmpl.tag.ko_code=
104
  {open:"__.push($1 || '');"},F.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};b.qa.prototype=new b.v;w=new b.qa;0<w.Db&&b.wa(w);b.b("jqueryTmplTemplateEngine",b.qa)}"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?L(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],L):L(x.ko={});m;
105
  })();
106
-
107
- /* ======================================== */
108
- /* json2.js
109
- * See www.JSON.org/js.html*/
110
- if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}
111
- Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+
112
- f(this.getUTCMonth()+1)+'-'+
113
- f(this.getUTCDate())+'T'+
114
- f(this.getUTCHours())+':'+
115
- f(this.getUTCMinutes())+':'+
116
- f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;}
117
- c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+
118
- (c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
119
- if(typeof value.toJSON==='function'){return stringify(value.toJSON());}
120
- a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i<l;i+=1){a.push(stringify(value[i],whitelist)||'null');}
121
- return'['+a.join(',')+']';}
122
- if(whitelist){l=whitelist.length;for(i=0;i<l;i+=1){k=whitelist[i];if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}else{for(k in value){if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}
123
- return'{'+a.join(',')+'}';}}
124
- return{stringify:stringify,parse:function(text,filter){var j;function walk(k,v){var i,n;if(v&&typeof v==='object'){for(i in v){if(Object.prototype.hasOwnProperty.apply(v,[i])){n=walk(i,v[i]);if(n!==undefined){v[i]=n;}}}}
125
- return filter(k,v);}
126
- if(/^[\],:{}\s]*$/.test(text.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof filter==='function'?walk('',j):j;}
127
- throw new SyntaxError('parseJSON');}};}();}
128
 
129
  /* ======================================== */
130
  /**
103
  var f=b.data("precompiled");f||(f=b.text()||"",f=F.template(p,"{{ko_with $item.koBindingContext}}"+f+"{{/ko_with}}"),b.data("precompiled",f));b=[c.$data];c=F.extend({koBindingContext:c},e.templateOptions);c=F.tmpl(f,b,c);c.appendTo(y.createElement("div"));F.fragments={};return c};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){y.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(F.tmpl.tag.ko_code=
104
  {open:"__.push($1 || '');"},F.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};b.qa.prototype=new b.v;w=new b.qa;0<w.Db&&b.wa(w);b.b("jqueryTmplTemplateEngine",b.qa)}"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?L(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],L):L(x.ko={});m;
105
  })();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
  /* ======================================== */
108
  /**
installer/dup-installer/classes/class.s3.func.php CHANGED
@@ -736,10 +736,10 @@ final class DUPX_S3_Funcs
736
  $dbhost = DUPX_U::getEscapedGenericString($this->post['dbhost']);
737
 
738
  $confTransformer->update('constant', 'DB_NAME', $dbname, array('raw' => true));
739
- DUPX_Log::info('UPDATE DB_NAME '.DUPX_Log::varToString($dbname));
740
 
741
  $confTransformer->update('constant', 'DB_USER', $dbuser, array('raw' => true));
742
- DUPX_Log::info('UPDATE DB_USER '.DUPX_Log::varToString($dbuser));
743
 
744
  $confTransformer->update('constant', 'DB_PASSWORD', $dbpass, array('raw' => true));
745
  DUPX_Log::info('UPDATE DB_PASSWORD '.DUPX_Log::varToString('** OBSCURED **'));
@@ -994,6 +994,8 @@ LONGMSG;
994
  $update_guid = @mysqli_affected_rows($this->dbh) or 0;
995
  DUPX_Log::info("Reverted '{$update_guid}' post guid columns back to '{$this->post['url_old']}'");
996
  }
 
 
997
  }
998
 
999
  /**
736
  $dbhost = DUPX_U::getEscapedGenericString($this->post['dbhost']);
737
 
738
  $confTransformer->update('constant', 'DB_NAME', $dbname, array('raw' => true));
739
+ DUPX_Log::info('UPDATE DB_NAME '. DUPX_Log::varToString('** OBSCURED **'));
740
 
741
  $confTransformer->update('constant', 'DB_USER', $dbuser, array('raw' => true));
742
+ DUPX_Log::info('UPDATE DB_USER '. DUPX_Log::varToString('** OBSCURED **'));
743
 
744
  $confTransformer->update('constant', 'DB_PASSWORD', $dbpass, array('raw' => true));
745
  DUPX_Log::info('UPDATE DB_PASSWORD '.DUPX_Log::varToString('** OBSCURED **'));
994
  $update_guid = @mysqli_affected_rows($this->dbh) or 0;
995
  DUPX_Log::info("Reverted '{$update_guid}' post guid columns back to '{$this->post['url_old']}'");
996
  }
997
+
998
+ DUPX_U::maintenanceMode(false);
999
  }
1000
 
1001
  /**
installer/dup-installer/classes/class.server.php CHANGED
@@ -19,18 +19,13 @@ class DUPX_Server
19
  /**
20
  * The minimum PHP version the installer will support
21
  */
22
- public static $php_version_min = "5.2.7";
23
 
24
  /**
25
  * Is the current servers version of PHP safe to use with the installer
26
  */
27
  public static $php_version_safe = false;
28
 
29
- /**
30
- * Is PHP 5.3 or better running
31
- */
32
- public static $php_version_53_plus;
33
-
34
  /**
35
  * A list of the core WordPress directories
36
  */
@@ -41,7 +36,6 @@ class DUPX_Server
41
  self::$php_safe_mode_on = in_array(strtolower(@ini_get('safe_mode')), array('on', 'yes', 'true', 1, "1"));
42
  self::$php_version = phpversion();
43
  self::$php_version_safe = (version_compare(phpversion(), self::$php_version_min) >= 0);
44
- self::$php_version_53_plus = version_compare(PHP_VERSION, '5.3.0') >= 0;
45
  }
46
 
47
  /**
@@ -103,7 +97,34 @@ class DUPX_Server
103
  }
104
  return $filepath;
105
  }
106
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  /**
108
  * Does the site look to be a WordPress site
109
  *
19
  /**
20
  * The minimum PHP version the installer will support
21
  */
22
+ public static $php_version_min = "5.3.8";
23
 
24
  /**
25
  * Is the current servers version of PHP safe to use with the installer
26
  */
27
  public static $php_version_safe = false;
28
 
 
 
 
 
 
29
  /**
30
  * A list of the core WordPress directories
31
  */
36
  self::$php_safe_mode_on = in_array(strtolower(@ini_get('safe_mode')), array('on', 'yes', 'true', 1, "1"));
37
  self::$php_version = phpversion();
38
  self::$php_version_safe = (version_compare(phpversion(), self::$php_version_min) >= 0);
 
39
  }
40
 
41
  /**
97
  }
98
  return $filepath;
99
  }
100
+
101
+ /**
102
+ *
103
+ * @return string[]
104
+ */
105
+ public static function getWpAddonsSiteLists()
106
+ {
107
+ $addonsSites = array();
108
+ $pathsToCheck = $GLOBALS['DUPX_ROOT'];
109
+
110
+ if (is_scalar($pathsToCheck)) {
111
+ $pathsToCheck = array($pathsToCheck);
112
+ }
113
+
114
+ foreach ($pathsToCheck as $mainPath) {
115
+ DupLiteSnapLibIOU::regexGlobCallback($mainPath, function ($path) use (&$addonsSites) {
116
+ if (DupLiteSnapLibUtilWp::isWpHomeFolder($path)) {
117
+ $addonsSites[] = $path;
118
+ }
119
+ }, array(
120
+ 'regexFile' => false,
121
+ 'recursive' => true
122
+ ));
123
+ }
124
+
125
+ return $addonsSites;
126
+ }
127
+
128
  /**
129
  * Does the site look to be a WordPress site
130
  *
installer/dup-installer/classes/config/class.boot.php CHANGED
@@ -19,7 +19,7 @@ class DUPX_Boot
19
 
20
  const ARCHIVE_PREFIX = 'dup-archive__';
21
  const ARCHIVE_EXTENSION = '.txt';
22
- const MINIMUM_PHP_VERSION = '5.2.17';
23
 
24
  /**
25
  * this variable becomes false after the installer is initialized by skipping the shutdown function defined in the boot class
@@ -62,6 +62,9 @@ class DUPX_Boot
62
  // init global values
63
  DUPX_Constants::init();
64
 
 
 
 
65
  // init ERR defines
66
  DUPX_Constants::initErrDefines();
67
  // init error handler after constant
@@ -151,6 +154,7 @@ class DUPX_Boot
151
  require_once($GLOBALS['DUPX_INIT'].'/ctrls/ctrl.base.php');
152
  require_once($GLOBALS['DUPX_INIT'].'/classes/config/class.archive.config.php');
153
  require_once($GLOBALS['DUPX_INIT'].'/classes/class.logging.php');
 
154
  }
155
 
156
  /**
@@ -295,9 +299,18 @@ class DUPX_Boot
295
  } else {
296
  $phpVersion = PHP_VERSION;
297
  }
298
- // no html
299
- echo 'This server is running PHP: '.$phpVersion.'. A minimum of PHP '.self::MINIMUM_PHP_VERSION.' is required to run the installer.'
300
- .' Contact your hosting provider or server administrator and let them know you would like to upgrade your PHP version.';
 
 
 
 
 
 
 
 
 
301
  die();
302
  }
303
  }
19
 
20
  const ARCHIVE_PREFIX = 'dup-archive__';
21
  const ARCHIVE_EXTENSION = '.txt';
22
+ const MINIMUM_PHP_VERSION = '5.3.8';
23
 
24
  /**
25
  * this variable becomes false after the installer is initialized by skipping the shutdown function defined in the boot class
62
  // init global values
63
  DUPX_Constants::init();
64
 
65
+ //init managed host manager
66
+ DUPX_Custom_Host_Manager::getInstance()->init();
67
+
68
  // init ERR defines
69
  DUPX_Constants::initErrDefines();
70
  // init error handler after constant
154
  require_once($GLOBALS['DUPX_INIT'].'/ctrls/ctrl.base.php');
155
  require_once($GLOBALS['DUPX_INIT'].'/classes/config/class.archive.config.php');
156
  require_once($GLOBALS['DUPX_INIT'].'/classes/class.logging.php');
157
+ require_once($GLOBALS['DUPX_INIT'].'/classes/host/class.custom.host.manager.php');
158
  }
159
 
160
  /**
299
  } else {
300
  $phpVersion = PHP_VERSION;
301
  }
302
+ $minPHPVersion = self::MINIMUM_PHP_VERSION;
303
+
304
+ echo '<div style="line-height:25px">';
305
+
306
+ echo "NOTICE: This web server is running <b>PHP: {$phpVersion}</b>.&nbsp; A minimum of PHP {$minPHPVersion} is required to run the installer and PHP 7.0+ is recommended.<br/>";
307
+ echo "Please contact your host or server administrator and let them know you would like to upgrade your PHP version.<br/>";
308
+
309
+ echo '<i>For more information on this topic see the FAQ titled '
310
+ . '<a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-licensing-017-q" target="_blank">What version of PHP Does Duplicator Support?</a></i>';
311
+
312
+ echo '</div>';
313
+
314
  die();
315
  }
316
  }
installer/dup-installer/classes/config/class.conf.srv.php CHANGED
@@ -8,11 +8,12 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
8
  */
9
  abstract class DUPX_ServerConfigTypes
10
  {
11
- const Apache = 0;
12
- const IIS = 1;
13
- const WordFence = 2;
14
- }
15
 
 
 
 
 
 
16
 
17
  /**
18
  * Class used to update and edit web server configuration files
@@ -24,145 +25,149 @@ abstract class DUPX_ServerConfigTypes
24
  */
25
  class DUPX_ServerConfig
26
  {
27
- protected static $fileHash;
28
- protected static $timeStamp;
29
- protected static $confFileApache;
30
- protected static $confFileApacheOrig;
31
- protected static $confFileIIS;
32
- protected static $confFileIISOrig;
33
- protected static $confFileWordFence;
34
- protected static $configMode;
35
- protected static $newSiteURL;
36
- protected static $rootPath;
37
-
38
- /**
39
- * Setup this classes properties
40
- */
41
- public static function init()
42
- {
43
- self::$fileHash = date("ymdHis") . '-' . uniqid();
44
- self::$timeStamp = date("Y-m-d H:i:s");
45
- self::$rootPath = "{$GLOBALS['DUPX_ROOT']}";
46
- self::$confFileApache = "{$GLOBALS['DUPX_ROOT']}/.htaccess";
47
- self::$confFileApacheOrig = "{$GLOBALS['DUPX_ROOT']}/.htaccess__".$GLOBALS['DUPX_AC']->package_hash;
48
- self::$confFileIIS = "{$GLOBALS['DUPX_ROOT']}/web.config";
49
- self::$confFileIISOrig = "{$GLOBALS['DUPX_ROOT']}/web.config.orig";
50
- self::$confFileWordFence = "{$GLOBALS['DUPX_ROOT']}/.user.ini";
51
- self::$configMode = isset($_POST['config_mode']) ? DUPX_U::sanitize_text_field($_POST['config_mode']) : null;
52
- self::$newSiteURL = isset($_POST['url_new']) ? DUPX_U::sanitize_text_field($_POST['url_new']) : null;
53
- }
54
-
55
- /**
56
- * After the archive is extracted run setup checks
57
- *
58
- * @return null
59
- */
60
- public static function afterExtractionSetup()
61
- {
62
- if (self::$configMode != 'IGNORE') {
63
- //WORDFENCE: Only the WordFence file needs to be removed
64
- //completly from setup to avoid any issues
65
- self::removeFile(self::$confFileWordFence, DUPX_ServerConfigTypes::WordFence);
66
- } else {
67
- DUPX_Log::info("** CONFIG FILE SET TO IGNORE ALL CHANGES **");
68
- }
69
- }
70
-
71
- /**
72
- * Before the archive is extracted run a series of back and remove checks
73
- * This is for existing config files that may exist before the ones in the
74
- * archive are extracted.
75
- *
76
- * @return void
77
- */
78
- public static function beforeExtractionSetup()
79
- {
80
- if (self::$configMode != 'IGNORE') {
81
- //---------------------
82
- //APACHE
83
- if (self::createBackup(self::$confFileApache, DUPX_ServerConfigTypes::Apache))
84
- self::removeFile(self::$confFileApache, DUPX_ServerConfigTypes::Apache);
85
-
86
- //---------------------
87
- //MICROSOFT IIS
88
- if (self::createBackup(self::$confFileIIS, DUPX_ServerConfigTypes::IIS))
89
- self::removeFile(self::$confFileIIS, DUPX_ServerConfigTypes::IIS);
90
-
91
- //---------------------
92
- //WORDFENCE
93
- if (self::createBackup(self::$confFileWordFence, DUPX_ServerConfigTypes::WordFence))
94
- self::removeFile(self::$confFileWordFence, DUPX_ServerConfigTypes::WordFence);
95
- }
96
- }
 
 
 
 
97
 
98
  /**
99
  * Copies the code in .htaccess__[HASH] and web.config.orig
100
- * to .htaccess and web.config
101
  *
102
- * @return void
103
  */
104
- public static function renameOrigConfigs()
105
- {
106
- //APACHE
107
- if(rename(self::$confFileApacheOrig, self::$confFileApache)){
108
- DUPX_Log::info("\n- PASS: The orginal .htaccess__[HASH] was renamed");
109
- } else {
110
- DUPX_Log::info("\n- WARN: The orginal .htaccess__[HASH] was NOT renamed");
111
- }
112
-
113
- //IIS
114
- if(rename(self::$confFileIISOrig, self::$confFileIIS)){
115
- DUPX_Log::info("\n- PASS: The orginal .htaccess__[HASH] was renamed");
116
- } else {
117
- DUPX_Log::info("\n- WARN: The orginal .htaccess__[HASH] was NOT renamed");
118
- }
119
  }
120
 
121
- /**
122
  * Creates the new config file
123
  *
124
- * @return void
125
  */
126
- public static function createNewConfigs()
127
- {
128
- $config_made = false;
129
-
130
- //APACHE
131
- if(file_exists(self::$confFileApacheOrig)){
132
- self::createNewApacheConfig();
133
- self::removeFile(self::$confFileApacheOrig, DUPX_ServerConfigTypes::Apache);
134
- $config_made = true;
135
- }
136
-
137
- if(file_exists(self::$confFileIISOrig)){
138
- self::createNewIISConfig();
139
- self::removeFile(self::$confFileIISOrig, DUPX_ServerConfigTypes::IIS);
140
- $config_made = true;
141
- }
142
-
143
- //No config was made so try to guess which one
144
- //95% of the time it will be Apache
145
- if (! $config_made) {
146
- if (DUPX_Server::isIISRunning()) {
147
- self::createNewIISConfig();
148
- } else {
149
- self::createNewApacheConfig();
150
- }
151
- }
152
  }
153
 
154
- /**
155
- * Sets up the web config file based on the inputs from the installer forms.
156
- *
157
- * @return void
158
- */
159
- private static function createNewApacheConfig()
160
- {
161
- $timestamp = self::$timeStamp;
162
- $newdata = parse_url(self::$newSiteURL);
163
- $newpath = DUPX_U::addSlash(isset($newdata['path']) ? $newdata['path'] : "");
164
- $update_msg = "#This Apache config file was created by Duplicator Installer on {$timestamp}.\n";
165
- $update_msg .= "#The original can be found in archived file with the name .htaccess__[HASH]\n";
166
 
167
  $tmp_htaccess = <<<HTACCESS
168
  {$update_msg}
@@ -178,105 +183,103 @@ RewriteRule . {$newpath}index.php [L]
178
  # END WordPress
179
  HTACCESS;
180
 
181
- if (@file_put_contents(self::$confFileApache, $tmp_htaccess) === FALSE) {
182
- DUPX_Log::info("- WARN: Unable to create the .htaccess file! Please check the permission on the root directory and make sure the .htaccess exists.");
183
- } else {
184
- DUPX_Log::info("- PASS: Successfully created a new .htaccess file.");
185
- @chmod(self::$confFileApache, 0644);
186
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  }
188
 
189
- /**
190
- * Sets up the web config file based on the inputs from the installer forms.
191
- *
192
- * @return void
193
- */
194
- private static function createNewIISConfig()
195
- {
196
- $timestamp = self::$timeStamp;
197
- $xml_contents = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
198
- $xml_contents .= "<!-- This new IIS config file was created by Duplicator Installer on {$timestamp}.\n"
199
- . "The original can be found in archived file with the name web.config.orig -->\n";
200
- $xml_contents .= "<configuration></configuration>\n";
201
- @file_put_contents(self::$confFileIIS, $xml_contents);
 
 
 
 
 
 
 
 
 
 
 
202
  }
203
-
204
- /**
205
- * Creates a copy of any existing file and hashes it with a .bak extension
206
- *
207
- * @param string $file_path The full path of the config file
208
- * @param DUPX_ServerConfigTypes $type A valid DUPX_ServerConfigTypes
209
- *
210
- * @return bool Returns true if the file was backed-up.
211
- */
212
- private static function createBackup($file_path, $type)
213
- {
214
- $status = false;
215
- $file_name = DupLiteSnapLibIOU::getFileName($file_path);
216
- $hash = self::$fileHash;
217
- $source = self::getTypeName($type);
218
- if (is_file($file_path)) {
219
- if (! self::backupExists($type)) {
220
- $status = copy($file_path, "{$file_path}-{$hash}-duplicator.bak");
221
- $status ? DUPX_Log::info("- PASS: {$source} '{$file_name}' backed-up to {$file_name}-{$hash}-duplicator.bak")
222
- : DUPX_Log::info("- WARN: {$source} '{$file_name}' unable to create backup copy, a possible permission error?");
223
- }
224
- } else {
225
- DUPX_Log::info("- PASS: {$source} '{$file_name}' not found - no backup needed.");
226
- }
227
-
228
- return $status;
229
- }
230
-
231
- /**
232
- * Removes the specified file
233
- *
234
- * @param string $file_path The full path of the config file
235
- * @param DUPX_ServerConfigTypes $type A valid DUPX_ServerConfigTypes
236
- *
237
- * @return bool Returns true if the file was removed
238
- */
239
- private static function removeFile($file_path, $type)
240
- {
241
- $status = false;
242
- if (is_file($file_path)) {
243
- $source = self::getTypeName($type);
244
- $file_name = DupLiteSnapLibIOU::getFileName($file_path);
245
- $status = @unlink($file_path);
246
- if ($status === FALSE) {
247
- @chmod($file_path, 0777);
248
- $status = @unlink($file_path);
249
- }
250
- $status ? DUPX_Log::info("- PASS: Existing {$source} '{$file_name}' was removed")
251
- : DUPX_Log::info("- WARN: Existing {$source} '{$file_path}' not removed, a possible permission error?");
252
- }
253
- return $status;
254
- }
255
-
256
- /**
257
- * Check if a backup file already exists
258
- *
259
- * @param DUPX_ServerConfigTypes $type A valid DUPX_ServerConfigTypes
260
- *
261
- * @return bool Returns true if the file was removed
262
- */
263
- private static function backupExists($type)
264
- {
265
- $pattern = 'unknown-duplicator-type-set';
266
-
267
- switch ($type) {
268
- case DUPX_ServerConfigTypes::Apache:
269
- $pattern = '/.htaccess-.*-duplicator.bak/';
270
- break;
271
- case DUPX_ServerConfigTypes::IIS:
272
- $pattern = '/web.config-.*-duplicator.bak/';
273
- break;
274
- case DUPX_ServerConfigTypes::WordFence:
275
- $pattern = '/.user.ini-.*-duplicator.bak/';
276
- break;
277
- }
278
-
279
- if (is_dir(self::$rootPath)) {
280
  $dir = new DirectoryIterator(self::$rootPath);
281
  foreach ($dir as $file) {
282
  if ($file->isDot()) {
@@ -294,33 +297,33 @@ HTACCESS;
294
  }
295
 
296
  return false;
297
- }
298
-
299
- /**
300
- * Gets the friendly type name
301
- *
302
- * @param DUPX_ServerConfigTypes $type A valid DUPX_ServerConfigTypes
303
- *
304
- * @return string The friendly enum name
305
- */
306
- private static function getTypeName($type)
307
- {
308
- switch ($type) {
309
- case DUPX_ServerConfigTypes::Apache:
310
- return 'Apache';
311
- break;
312
- case DUPX_ServerConfigTypes::IIS:
313
- return 'Microsoft IIS';
314
- break;
315
- case DUPX_ServerConfigTypes::WordFence:
316
- return 'WordFence';
317
- break;
318
-
319
- default:
320
- throw new Exception('The param $type must be of type DUPX_ServerConfigTypes');
321
- break;
322
- }
323
- }
324
 
325
  /**
326
  * Get AddHadler line from existing WP .htaccess file
@@ -365,15 +368,15 @@ HTACCESS;
365
  }
366
 
367
  /**
368
- * Sets up the web config file based on the inputs from the installer forms.
369
- *
370
- * @param int $mu_mode Is this site a specific multi-site mode
371
- * @param object $dbh The database connection handle for this request
372
- * @param string $path The path to the config file
373
- *
374
- * @return null
375
- */
376
- public static function setup($mu_mode, $mu_generation, $dbh, $path)
377
  {
378
  DUPX_Log::info("\nWEB SERVER CONFIGURATION FILE UPDATED:");
379
 
@@ -425,4 +428,4 @@ HTACCESS;
425
  }
426
  @chmod("{$path}/.htaccess", 0644);
427
  }
428
- }
8
  */
9
  abstract class DUPX_ServerConfigTypes
10
  {
 
 
 
 
11
 
12
+ const Apache = 0;
13
+ const IIS = 1;
14
+ const WordFence = 2;
15
+
16
+ }
17
 
18
  /**
19
  * Class used to update and edit web server configuration files
25
  */
26
  class DUPX_ServerConfig
27
  {
28
+
29
+ protected static $fileHash;
30
+ protected static $timeStamp;
31
+ protected static $confFileApache;
32
+ protected static $confFileApacheOrig;
33
+ protected static $confFileIIS;
34
+ protected static $confFileIISOrig;
35
+ protected static $confFileWordFence;
36
+ protected static $configMode;
37
+ protected static $newSiteURL;
38
+ protected static $rootPath;
39
+
40
+ /**
41
+ * Setup this classes properties
42
+ */
43
+ public static function init()
44
+ {
45
+ self::$fileHash = date("ymdHis").'-'.uniqid();
46
+ self::$timeStamp = date("Y-m-d H:i:s");
47
+ self::$rootPath = "{$GLOBALS['DUPX_ROOT']}";
48
+ self::$confFileApache = "{$GLOBALS['DUPX_ROOT']}/.htaccess";
49
+ self::$confFileApacheOrig = "{$GLOBALS['DUPX_ROOT']}/.htaccess__".$GLOBALS['DUPX_AC']->package_hash;
50
+ self::$confFileIIS = "{$GLOBALS['DUPX_ROOT']}/web.config";
51
+ self::$confFileIISOrig = "{$GLOBALS['DUPX_ROOT']}/web.config.orig";
52
+ self::$confFileWordFence = "{$GLOBALS['DUPX_ROOT']}/.user.ini";
53
+ self::$configMode = isset($_POST['config_mode']) ? DUPX_U::sanitize_text_field($_POST['config_mode']) : null;
54
+ self::$newSiteURL = isset($_POST['url_new']) ? DUPX_U::sanitize_text_field($_POST['url_new']) : null;
55
+ }
56
+
57
+ /**
58
+ * After the archive is extracted run setup checks
59
+ *
60
+ * @return null
61
+ */
62
+ public static function afterExtractionSetup()
63
+ {
64
+ if (self::$configMode != 'IGNORE') {
65
+ //WORDFENCE: Only the WordFence file needs to be removed
66
+ //completly from setup to avoid any issues
67
+ self::removeFile(self::$confFileWordFence, DUPX_ServerConfigTypes::WordFence);
68
+ } else {
69
+ DUPX_Log::info("** CONFIG FILE SET TO IGNORE ALL CHANGES **");
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Before the archive is extracted run a series of back and remove checks
75
+ * This is for existing config files that may exist before the ones in the
76
+ * archive are extracted.
77
+ *
78
+ * @return void
79
+ */
80
+ public static function beforeExtractionSetup()
81
+ {
82
+ if (self::$configMode != 'IGNORE') {
83
+ //---------------------
84
+ //APACHE
85
+ if (self::createBackup(self::$confFileApache, DUPX_ServerConfigTypes::Apache)) {
86
+ self::removeFile(self::$confFileApache, DUPX_ServerConfigTypes::Apache);
87
+ }
88
+
89
+ //---------------------
90
+ //MICROSOFT IIS
91
+ if (self::createBackup(self::$confFileIIS, DUPX_ServerConfigTypes::IIS)) {
92
+ self::removeFile(self::$confFileIIS, DUPX_ServerConfigTypes::IIS);
93
+ }
94
+
95
+ //---------------------
96
+ //WORDFENCE
97
+ if (self::createBackup(self::$confFileWordFence, DUPX_ServerConfigTypes::WordFence)) {
98
+ self::removeFile(self::$confFileWordFence, DUPX_ServerConfigTypes::WordFence);
99
+ }
100
+ }
101
+ }
102
 
103
  /**
104
  * Copies the code in .htaccess__[HASH] and web.config.orig
105
+ * to .htaccess and web.config
106
  *
107
+ * @return void
108
  */
109
+ public static function renameOrigConfigs()
110
+ {
111
+ //APACHE
112
+ if (rename(self::$confFileApacheOrig, self::$confFileApache)) {
113
+ DUPX_Log::info("\n- PASS: The orginal .htaccess__[HASH] was renamed");
114
+ } else {
115
+ DUPX_Log::info("\n- WARN: The orginal .htaccess__[HASH] was NOT renamed");
116
+ }
117
+
118
+ //IIS
119
+ if (rename(self::$confFileIISOrig, self::$confFileIIS)) {
120
+ DUPX_Log::info("\n- PASS: The orginal .htaccess__[HASH] was renamed");
121
+ } else {
122
+ DUPX_Log::info("\n- WARN: The orginal .htaccess__[HASH] was NOT renamed");
123
+ }
124
  }
125
 
126
+ /**
127
  * Creates the new config file
128
  *
129
+ * @return void
130
  */
131
+ public static function createNewConfigs()
132
+ {
133
+ $config_made = false;
134
+
135
+ //APACHE
136
+ if (file_exists(self::$confFileApacheOrig)) {
137
+ self::createNewApacheConfig();
138
+ self::removeFile(self::$confFileApacheOrig, DUPX_ServerConfigTypes::Apache);
139
+ $config_made = true;
140
+ }
141
+
142
+ if (file_exists(self::$confFileIISOrig)) {
143
+ self::createNewIISConfig();
144
+ self::removeFile(self::$confFileIISOrig, DUPX_ServerConfigTypes::IIS);
145
+ $config_made = true;
146
+ }
147
+
148
+ //No config was made so try to guess which one
149
+ //95% of the time it will be Apache
150
+ if (!$config_made) {
151
+ if (DUPX_Server::isIISRunning()) {
152
+ self::createNewIISConfig();
153
+ } else {
154
+ self::createNewApacheConfig();
155
+ }
156
+ }
157
  }
158
 
159
+ /**
160
+ * Sets up the web config file based on the inputs from the installer forms.
161
+ *
162
+ * @return void
163
+ */
164
+ private static function createNewApacheConfig()
165
+ {
166
+ $timestamp = self::$timeStamp;
167
+ $newdata = parse_url(self::$newSiteURL);
168
+ $newpath = DUPX_U::addSlash(isset($newdata['path']) ? $newdata['path'] : "");
169
+ $update_msg = "#This Apache config file was created by Duplicator Installer on {$timestamp}.\n";
170
+ $update_msg .= "#The original can be found in archived file with the name .htaccess__[HASH]\n";
171
 
172
  $tmp_htaccess = <<<HTACCESS
173
  {$update_msg}
183
  # END WordPress
184
  HTACCESS;
185
 
186
+ if (@file_put_contents(self::$confFileApache, $tmp_htaccess) === FALSE) {
187
+ DUPX_Log::info("- WARN: Unable to create the .htaccess file! Please check the permission on the root directory and make sure the .htaccess exists.");
188
+ } else {
189
+ DUPX_Log::info("- PASS: Successfully created a new .htaccess file.");
190
+ @chmod(self::$confFileApache, 0644);
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Sets up the web config file based on the inputs from the installer forms.
196
+ *
197
+ * @return void
198
+ */
199
+ private static function createNewIISConfig()
200
+ {
201
+ $timestamp = self::$timeStamp;
202
+ $xml_contents = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
203
+ $xml_contents .= "<!-- This new IIS config file was created by Duplicator Installer on {$timestamp}.\n"
204
+ ."The original can be found in archived file with the name web.config.orig -->\n";
205
+ $xml_contents .= "<configuration></configuration>\n";
206
+ @file_put_contents(self::$confFileIIS, $xml_contents);
207
  }
208
 
209
+ /**
210
+ * Creates a copy of any existing file and hashes it with a .bak extension
211
+ *
212
+ * @param string $file_path The full path of the config file
213
+ * @param DUPX_ServerConfigTypes $type A valid DUPX_ServerConfigTypes
214
+ *
215
+ * @return bool Returns true if the file was backed-up.
216
+ */
217
+ private static function createBackup($file_path, $type)
218
+ {
219
+ $status = false;
220
+ $file_name = DupLiteSnapLibIOU::getFileName($file_path);
221
+ $hash = self::$fileHash;
222
+ $source = self::getTypeName($type);
223
+ if (is_file($file_path)) {
224
+ if (!self::backupExists($type)) {
225
+ $status = copy($file_path, "{$file_path}-{$hash}-duplicator.bak");
226
+ $status ? DUPX_Log::info("- PASS: {$source} '{$file_name}' backed-up to {$file_name}-{$hash}-duplicator.bak") : DUPX_Log::info("- WARN: {$source} '{$file_name}' unable to create backup copy, a possible permission error?");
227
+ }
228
+ } else {
229
+ DUPX_Log::info("- PASS: {$source} '{$file_name}' not found - no backup needed.");
230
+ }
231
+
232
+ return $status;
233
  }
234
+
235
+ /**
236
+ * Removes the specified file
237
+ *
238
+ * @param string $file_path The full path of the config file
239
+ * @param DUPX_ServerConfigTypes $type A valid DUPX_ServerConfigTypes
240
+ *
241
+ * @return bool Returns true if the file was removed
242
+ */
243
+ private static function removeFile($file_path, $type)
244
+ {
245
+ $status = false;
246
+ if (is_file($file_path)) {
247
+ $source = self::getTypeName($type);
248
+ $file_name = DupLiteSnapLibIOU::getFileName($file_path);
249
+ $status = @unlink($file_path);
250
+ if ($status === FALSE) {
251
+ @chmod($file_path, 0777);
252
+ $status = @unlink($file_path);
253
+ }
254
+ $status ? DUPX_Log::info("- PASS: Existing {$source} '{$file_name}' was removed") : DUPX_Log::info("- WARN: Existing {$source} '{$file_path}' not removed, a possible permission error?");
255
+ }
256
+ return $status;
257
+ }
258
+
259
+ /**
260
+ * Check if a backup file already exists
261
+ *
262
+ * @param DUPX_ServerConfigTypes $type A valid DUPX_ServerConfigTypes
263
+ *
264
+ * @return bool Returns true if the file was removed
265
+ */
266
+ private static function backupExists($type)
267
+ {
268
+ $pattern = 'unknown-duplicator-type-set';
269
+
270
+ switch ($type) {
271
+ case DUPX_ServerConfigTypes::Apache:
272
+ $pattern = '/.htaccess-.*-duplicator.bak/';
273
+ break;
274
+ case DUPX_ServerConfigTypes::IIS:
275
+ $pattern = '/web.config-.*-duplicator.bak/';
276
+ break;
277
+ case DUPX_ServerConfigTypes::WordFence:
278
+ $pattern = '/.user.ini-.*-duplicator.bak/';
279
+ break;
280
+ }
281
+
282
+ if (is_dir(self::$rootPath)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  $dir = new DirectoryIterator(self::$rootPath);
284
  foreach ($dir as $file) {
285
  if ($file->isDot()) {
297
  }
298
 
299
  return false;
300
+ }
301
+
302
+ /**
303
+ * Gets the friendly type name
304
+ *
305
+ * @param DUPX_ServerConfigTypes $type A valid DUPX_ServerConfigTypes
306
+ *
307
+ * @return string The friendly enum name
308
+ */
309
+ private static function getTypeName($type)
310
+ {
311
+ switch ($type) {
312
+ case DUPX_ServerConfigTypes::Apache:
313
+ return 'Apache';
314
+ break;
315
+ case DUPX_ServerConfigTypes::IIS:
316
+ return 'Microsoft IIS';
317
+ break;
318
+ case DUPX_ServerConfigTypes::WordFence:
319
+ return 'WordFence';
320
+ break;
321
+
322
+ default:
323
+ throw new Exception('The param $type must be of type DUPX_ServerConfigTypes');
324
+ break;
325
+ }
326
+ }
327
 
328
  /**
329
  * Get AddHadler line from existing WP .htaccess file
368
  }
369
 
370
  /**
371
+ * Sets up the web config file based on the inputs from the installer forms.
372
+ *
373
+ * @param int $mu_mode Is this site a specific multi-site mode
374
+ * @param object $dbh The database connection handle for this request
375
+ * @param string $path The path to the config file
376
+ *
377
+ * @return null
378
+ */
379
+ public static function setup($mu_mode, $mu_generation, $dbh, $path)
380
  {
381
  DUPX_Log::info("\nWEB SERVER CONFIGURATION FILE UPDATED:");
382
 
428
  }
429
  @chmod("{$path}/.htaccess", 0644);
430
  }
431
+ }
installer/dup-installer/classes/host/class.custom.host.manager.php ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * custom hosting manager
4
+ * singleton class
5
+ *
6
+ * Standard: PSR-2
7
+ *
8
+ * @package SC\DUPX\DB
9
+ * @link http://www.php-fig.org/psr/psr-2/
10
+ *
11
+ */
12
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
13
+
14
+ require_once ($GLOBALS['DUPX_INIT'].'/classes/host/interface.host.php');
15
+ require_once ($GLOBALS['DUPX_INIT'].'/classes/host/class.godaddy.host.php');
16
+ require_once ($GLOBALS['DUPX_INIT'].'/classes/host/class.wpengine.host.php');
17
+ require_once ($GLOBALS['DUPX_INIT'].'/classes/host/class.wordpresscom.host.php');
18
+ require_once ($GLOBALS['DUPX_INIT'].'/classes/host/class.liquidweb.host.php');
19
+ require_once ($GLOBALS['DUPX_INIT'].'/classes/host/class.pantheon.host.php');
20
+ require_once ($GLOBALS['DUPX_INIT'].'/classes/host/class.flywheel.host.php');
21
+
22
+ class DUPX_Custom_Host_Manager
23
+ {
24
+
25
+ const HOST_GODADDY = 'godaddy';
26
+ const HOST_WPENGINE = 'wpengine';
27
+ const HOST_WORDPRESSCOM = 'wordpresscom';
28
+ const HOST_LIQUIDWEB = 'liquidweb';
29
+ const HOST_PANTHEON = 'pantheon';
30
+ const HOST_FLYWHEEL = 'flywheel';
31
+
32
+ /**
33
+ *
34
+ * @var self
35
+ */
36
+ protected static $instance = null;
37
+
38
+ /**
39
+ * this var prevent multiple params inizialization.
40
+ * it's useful on development to prevent an infinite loop in class constructor
41
+ *
42
+ * @var bool
43
+ */
44
+ private $initialized = false;
45
+
46
+ /**
47
+ * custom hostings list
48
+ *
49
+ * @var DUPX_Host_interface[]
50
+ */
51
+ private $customHostings = array();
52
+
53
+ /**
54
+ * active custom hosting in current server
55
+ *
56
+ * @var string[]
57
+ */
58
+ private $activeHostings = array();
59
+
60
+ /**
61
+ *
62
+ * @return self
63
+ */
64
+ public static function getInstance()
65
+ {
66
+ if (is_null(self::$instance)) {
67
+ self::$instance = new self;
68
+ }
69
+ return self::$instance;
70
+ }
71
+
72
+ /**
73
+ * init custom histings
74
+ */
75
+ private function __construct()
76
+ {
77
+ $this->customHostings[DUPX_WPEngine_Host::getIdentifier()] = new DUPX_WPEngine_Host();
78
+ $this->customHostings[DUPX_GoDaddy_Host::getIdentifier()] = new DUPX_GoDaddy_Host();
79
+ $this->customHostings[DUPX_WordpressCom_Host::getIdentifier()] = new DUPX_WordpressCom_Host();
80
+ $this->customHostings[DUPX_Liquidweb_Host::getIdentifier()] = new DUPX_Liquidweb_Host();
81
+ $this->customHostings[DUPX_Pantheon_Host::getIdentifier()] = new DUPX_Pantheon_Host();
82
+ $this->customHostings[DUPX_FlyWheel_Host::getIdentifier()] = new DUPX_FlyWheel_Host();
83
+ }
84
+
85
+ /**
86
+ * execute the active custom hostings inizialization only one time.
87
+ *
88
+ * @return boolean
89
+ * @throws Exception
90
+ */
91
+ public function init()
92
+ {
93
+ if ($this->initialized) {
94
+ return true;
95
+ }
96
+ foreach ($this->customHostings as $cHost) {
97
+ if (!($cHost instanceof DUPX_Host_interface)) {
98
+ throw new Exception('Host must implemnete DUPX_Host_interface');
99
+ }
100
+ if ($cHost->isHosting()) {
101
+ $this->activeHostings[] = $cHost->getIdentifier();
102
+ $cHost->init();
103
+ }
104
+ }
105
+ $this->initialized = true;
106
+ return true;
107
+ }
108
+
109
+ /**
110
+ * return the lisst of current custom active hostings
111
+ *
112
+ * @return DUPX_Host_interface[]
113
+ */
114
+ public function getActiveHostings()
115
+ {
116
+ $result = array();
117
+ foreach ($this->customHostings as $cHost) {
118
+ if ($cHost->isHosting()) {
119
+ $result[] = $cHost->getIdentifier();
120
+ }
121
+ }
122
+ return $result;
123
+ }
124
+
125
+ /**
126
+ * return true if current identifier hostoing is active
127
+ *
128
+ * @param string $identifier
129
+ * @return bool
130
+ */
131
+ public function isHosting($identifier)
132
+ {
133
+ return isset($this->customHostings[$identifier]) && $this->customHostings[$identifier]->isHosting();
134
+ }
135
+
136
+ /**
137
+ *
138
+ * @return boolean|string return false if isn't managed manage hosting of manager hosting
139
+ */
140
+ public function isManaged()
141
+ {
142
+ if ($this->isHosting(self::HOST_WPENGINE)) {
143
+ return self::HOST_WPENGINE;
144
+ } else if ($this->isHosting(self::HOST_LIQUIDWEB)) {
145
+ return self::HOST_LIQUIDWEB;
146
+ } else if ($this->isHosting(self::HOST_GODADDY)) {
147
+ return self::HOST_GODADDY;
148
+ } else if ($this->isHosting(self::HOST_WORDPRESSCOM)) {
149
+ return self::HOST_WORDPRESSCOM;
150
+ } else if ($this->isHosting(self::HOST_PANTHEON)) {
151
+ return self::HOST_PANTHEON;
152
+ } else if ($this->isHosting(self::HOST_FLYWHEEL)) {
153
+ return self::HOST_FLYWHEEL;
154
+ } else if ($this->wpConfigIsNotWriteable() || $this->notAccessibleCoreDirPresent()) {
155
+ return true;
156
+ } else {
157
+ return false;
158
+ }
159
+ }
160
+
161
+
162
+ public function wpConfigIsNotWriteable()
163
+ {
164
+ $path = $GLOBALS['DUPX_ROOT'].'/wp-config.php';
165
+
166
+ return file_exists($path) && !is_writeable($path);
167
+ }
168
+
169
+ public function notAccessibleCoreDirPresent()
170
+ {
171
+ $coreDirs = array(
172
+ $GLOBALS['DUPX_ROOT'].'/wp-admin',
173
+ $GLOBALS['DUPX_ROOT'].'/wp-includes',
174
+ $GLOBALS['DUPX_ROOT'].'/wp-content'
175
+ );
176
+
177
+ foreach ($coreDirs as $coreDir) {
178
+ if (file_exists($coreDir) && !is_writeable($coreDir)) {
179
+ return true;
180
+ }
181
+ }
182
+
183
+ return false;
184
+ }
185
+
186
+ /**
187
+ *
188
+ * @param type $identifier
189
+ * @return boolean|DUPX_Host_interface
190
+ */
191
+ public function getHosting($identifier)
192
+ {
193
+ if ($this->isHosting($identifier)) {
194
+ return $this->customHostings[$identifier];
195
+ } else {
196
+ return false;
197
+ }
198
+ }
199
+ }
installer/dup-installer/classes/host/class.flywheel.host.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * godaddy custom hosting class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\DB
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ /**
14
+ * class for GoDaddy managed hosting
15
+ *
16
+ * @todo not yet implemneted
17
+ *
18
+ */
19
+ class DUPX_FlyWheel_Host implements DUPX_Host_interface
20
+ {
21
+
22
+ /**
23
+ * return the current host identifier
24
+ *
25
+ * @return string
26
+ */
27
+ public static function getIdentifier()
28
+ {
29
+ return DUPX_Custom_Host_Manager::HOST_FLYWHEEL;
30
+ }
31
+
32
+ /**
33
+ * @return bool true if is current host
34
+ */
35
+ public function isHosting()
36
+ {
37
+ // check only mu plugin file exists
38
+
39
+ $file = $GLOBALS['DUPX_ROOT'].'/.fw-config.php';
40
+ return file_exists($file);
41
+ }
42
+
43
+ /**
44
+ * the init function.
45
+ * is called only if isHosting is true
46
+ *
47
+ * @return void
48
+ */
49
+ public function init()
50
+ {
51
+
52
+ }
53
+
54
+ /**
55
+ *
56
+ * @return string
57
+ */
58
+ public function getLabel()
59
+ {
60
+ return 'FlyWheel';
61
+ }
62
+ }
installer/dup-installer/classes/host/class.godaddy.host.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * godaddy custom hosting class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\DB
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ /**
14
+ * class for GoDaddy managed hosting
15
+ *
16
+ * @todo not yet implemneted
17
+ *
18
+ */
19
+ class DUPX_GoDaddy_Host implements DUPX_Host_interface
20
+ {
21
+
22
+ /**
23
+ * return the current host itentifier
24
+ *
25
+ * @return string
26
+ */
27
+ public static function getIdentifier()
28
+ {
29
+ return DUPX_Custom_Host_Manager::HOST_GODADDY;
30
+ }
31
+
32
+ /**
33
+ * @return bool true if is current host
34
+ */
35
+ public function isHosting()
36
+ {
37
+ // check only mu plugin file exists
38
+
39
+ $file = $GLOBALS['DUPX_ROOT'].'/wp-content/mu-plugins/gd-system-plugin.php';
40
+ return file_exists($file);
41
+ }
42
+
43
+ /**
44
+ * the init function.
45
+ * is called only if isHosting is true
46
+ *
47
+ * @return void
48
+ */
49
+ public function init()
50
+ {
51
+
52
+ }
53
+
54
+ /**
55
+ *
56
+ * @return string
57
+ */
58
+ public function getLabel()
59
+ {
60
+ return 'GoDaddy';
61
+ }
62
+ }
installer/dup-installer/classes/host/class.liquidweb.host.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * liquidweb custom hosting class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\DB
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ class DUPX_Liquidweb_Host implements DUPX_Host_interface
14
+ {
15
+
16
+ /**
17
+ * return the current host itentifier
18
+ *
19
+ * @return string
20
+ */
21
+ public static function getIdentifier()
22
+ {
23
+ return DUPX_Custom_Host_Manager::HOST_LIQUIDWEB;
24
+ }
25
+
26
+ /**
27
+ * @return bool true if is current host
28
+ */
29
+ public function isHosting()
30
+ {
31
+ // check only mu plugin file exists
32
+
33
+ $testFile = $GLOBALS['DUPX_ROOT'].'/wp-content/mu-plugins/liquid-web.php';
34
+ return file_exists($testFile);
35
+ }
36
+
37
+ /**
38
+ * the init function.
39
+ * is called only if isHosting is true
40
+ *
41
+ * @return void
42
+ */
43
+ public function init()
44
+ {
45
+
46
+ }
47
+
48
+ /**
49
+ * return the label of current hosting
50
+ *
51
+ * @return string
52
+ */
53
+ public function getLabel()
54
+ {
55
+ return 'Liquid Web';
56
+ }
57
+ }
installer/dup-installer/classes/host/class.pantheon.host.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * godaddy custom hosting class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\DB
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ /**
14
+ * class for GoDaddy managed hosting
15
+ *
16
+ * @todo not yet implemneted
17
+ *
18
+ */
19
+ class DUPX_Pantheon_Host implements DUPX_Host_interface
20
+ {
21
+
22
+ /**
23
+ * return the current host itentifier
24
+ *
25
+ * @return string
26
+ */
27
+ public static function getIdentifier()
28
+ {
29
+ return DUPX_Custom_Host_Manager::HOST_PANTHEON;
30
+ }
31
+
32
+ /**
33
+ * @return bool true if is current host
34
+ * @throws Exception
35
+ */
36
+ public function isHosting()
37
+ {
38
+ // check only mu plugin file exists
39
+
40
+ $testFile = $GLOBALS['DUPX_ROOT'].'/wp-content/mu-plugins/pantheon.php';
41
+ return file_exists($testFile);
42
+ }
43
+
44
+ /**
45
+ * the init function.
46
+ * is called only if isHosting is true
47
+ *
48
+ * @return void
49
+ */
50
+ public function init()
51
+ {
52
+
53
+ }
54
+
55
+ /**
56
+ *
57
+ * @return string
58
+ */
59
+ public function getLabel()
60
+ {
61
+ return 'Pantheon';
62
+ }
63
+
64
+ /**
65
+ * this function is called if current hosting is this
66
+ */
67
+ public function setCustomParams()
68
+ {
69
+
70
+ }
71
+ }
installer/dup-installer/classes/host/class.wordpresscom.host.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * godaddy custom hosting class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\DB
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ /**
14
+ * class for wordpress.com managed hosting
15
+ *
16
+ * @todo not yet implemneted
17
+ *
18
+ */
19
+ class DUPX_WordpressCom_Host implements DUPX_Host_interface
20
+ {
21
+
22
+ /**
23
+ * return the current host itentifier
24
+ *
25
+ * @return string
26
+ */
27
+ public static function getIdentifier()
28
+ {
29
+ return DUPX_Custom_Host_Manager::HOST_WORDPRESSCOM;
30
+ }
31
+
32
+ /**
33
+ * @return bool true if is current host
34
+ */
35
+ public function isHosting()
36
+ {
37
+ // check only mu plugin file exists
38
+
39
+ $testFile = $GLOBALS['DUPX_ROOT'].'/wp-content/mu-plugins/wpcomsh-loader.php';
40
+ return file_exists($testFile);
41
+ }
42
+
43
+ /**
44
+ * the init function.
45
+ * is called only if isHosting is true
46
+ *
47
+ * @return void
48
+ */
49
+ public function init()
50
+ {
51
+
52
+ }
53
+
54
+ /**
55
+ *
56
+ * @return string
57
+ */
58
+ public function getLabel()
59
+ {
60
+ return 'Wordpress.com';
61
+ }
62
+ }
installer/dup-installer/classes/host/class.wpengine.host.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * wpengine custom hosting class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\DB
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ /**
14
+ * class for wpengine managed hosting
15
+ *
16
+ * @todo not yet implemneted
17
+ *
18
+ */
19
+ class DUPX_WPEngine_Host implements DUPX_Host_interface
20
+ {
21
+
22
+ /**
23
+ * return the current host itentifier
24
+ *
25
+ * @return string
26
+ */
27
+ public static function getIdentifier()
28
+ {
29
+ return DUPX_Custom_Host_Manager::HOST_WPENGINE;
30
+ }
31
+
32
+ /**
33
+ * @return bool true if is current host
34
+ */
35
+ public function isHosting()
36
+ {
37
+ // check only mu plugin file exists
38
+
39
+ $file = $GLOBALS['DUPX_ROOT'].'/wp-content/mu-plugins/wpengine-security-auditor.php';
40
+ return file_exists($file);
41
+ }
42
+
43
+ /**
44
+ * the init function.
45
+ * is called only if isHosting is true
46
+ *
47
+ * @return void
48
+ */
49
+ public function init()
50
+ {
51
+
52
+ }
53
+
54
+ /**
55
+ *
56
+ * @return string
57
+ */
58
+ public function getLabel()
59
+ {
60
+ return 'WP Engine';
61
+ }
62
+ }
installer/dup-installer/classes/host/interface.host.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * interface for specific hostings class
4
+ *
5
+ * Standard: PSR-2
6
+ *
7
+ * @package SC\DUPX\DB
8
+ * @link http://www.php-fig.org/psr/psr-2/
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ /**
14
+ * instaler custom host interface for cusotm hosting classes
15
+ *
16
+ */
17
+ interface DUPX_Host_interface
18
+ {
19
+
20
+ /**
21
+ * return the current host itentifier
22
+ *
23
+ * @return string
24
+ */
25
+ public static function getIdentifier();
26
+
27
+ /**
28
+ * @return bool true if is current host
29
+ */
30
+ public function isHosting();
31
+
32
+ /**
33
+ * the init function.
34
+ * is called only if isHosting is true
35
+ *
36
+ * @return void
37
+ */
38
+ public function init();
39
+
40
+ /**
41
+ * return the label of current hosting
42
+ *
43
+ * @return string
44
+ */
45
+ public function getLabel();
46
+ }
installer/dup-installer/classes/utilities/class.u.notices.manager.php CHANGED
@@ -1,1252 +1,1251 @@
1
- <?php
2
- /**
3
- * Notice manager
4
- *
5
- * Standard: PSR-2
6
- * @link http://www.php-fig.org/psr/psr-2 Full Documentation
7
- *
8
- * @package SC\DUPX\U
9
- *
10
- */
11
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
-
13
- /**
14
- * Notice manager
15
- * singleton class
16
- */
17
- final class DUPX_NOTICE_MANAGER
18
- {
19
- const ADD_NORMAL = 0; // add notice in list
20
- const ADD_UNIQUE = 1; // add if unique id don't exists
21
- const ADD_UNIQUE_UPDATE = 2; // add or update notice unique id
22
- const ADD_UNIQUE_APPEND = 3; // append long msg
23
- const ADD_UNIQUE_APPEND_IF_EXISTS = 4; // append long msg if already exists item
24
- const ADD_UNIQUE_PREPEND = 5; // append long msg
25
- const ADD_UNIQUE_PREPEND_IF_EXISTS = 6; // prepend long msg if already exists item
26
- const DEFAULT_UNIQUE_ID_PREFIX = '__auto_unique_id__';
27
-
28
- private static $uniqueCountId = 0;
29
-
30
- /**
31
- *
32
- * @var DUPX_NOTICE_ITEM[]
33
- */
34
- private $nextStepNotices = array();
35
-
36
- /**
37
- *
38
- * @var DUPX_NOTICE_ITEM[]
39
- */
40
- private $finalReporNotices = array();
41
-
42
- /**
43
- *
44
- * @var DUPX_NOTICE_MANAGER
45
- */
46
- private static $instance = null;
47
-
48
- /**
49
- *
50
- * @var string
51
- */
52
- private $persistanceFile = null;
53
-
54
- /**
55
- *
56
- * @return DUPX_S_R_MANAGER
57
- */
58
- public static function getInstance()
59
- {
60
- if (is_null(self::$instance)) {
61
- self::$instance = new self();
62
- }
63
-
64
- return self::$instance;
65
- }
66
-
67
- private function __construct()
68
- {
69
- $this->persistanceFile = $GLOBALS["NOTICES_FILE_PATH"];
70
- $this->loadNotices();
71
- }
72
-
73
- /**
74
- * save notices from json file
75
- */
76
- public function saveNotices()
77
- {
78
- $notices = array(
79
- 'globalData' => array(
80
- 'uniqueCountId' => self::$uniqueCountId
81
- ),
82
- 'nextStep' => array(),
83
- 'finalReport' => array()
84
- );
85
-
86
- foreach ($this->nextStepNotices as $uniqueId => $notice) {
87
- $notices['nextStep'][$uniqueId] = $notice->toArray();
88
- }
89
-
90
- foreach ($this->finalReporNotices as $uniqueId => $notice) {
91
- $notices['finalReport'][$uniqueId] = $notice->toArray();
92
- }
93
-
94
- file_put_contents($this->persistanceFile, DupLiteSnapJsonU::wp_json_encode_pprint($notices));
95
- }
96
-
97
- /**
98
- * load notice from json file
99
- */
100
- private function loadNotices()
101
- {
102
- if (file_exists($this->persistanceFile)) {
103
- $json = file_get_contents($this->persistanceFile);
104
- $notices = json_decode($json, true);
105
-
106
- $this->nextStepNotices = array();
107
- $this->finalReporNotices = array();
108
-
109
- if (!empty($notices['nextStep'])) {
110
- foreach ($notices['nextStep'] as $uniqueId => $notice) {
111
- $this->nextStepNotices[$uniqueId] = DUPX_NOTICE_ITEM::getItemFromArray($notice);
112
- }
113
- }
114
-
115
- if (!empty($notices['finalReport'])) {
116
- foreach ($notices['finalReport'] as $uniqueId => $notice) {
117
- $this->finalReporNotices[$uniqueId] = DUPX_NOTICE_ITEM::getItemFromArray($notice);
118
- }
119
- }
120
-
121
- self::$uniqueCountId = $notices['globalData']['uniqueCountId'];
122
- } else {
123
- $this->resetNotices();
124
- }
125
- }
126
-
127
- /**
128
- * remove all notices and save reset file
129
- */
130
- public function resetNotices()
131
- {
132
- $this->nextStepNotices = array();
133
- $this->finalReporNotices = array();
134
- self::$uniqueCountId = 0;
135
- $this->saveNotices();
136
- }
137
-
138
- /**
139
- * return next step notice by id
140
- *
141
- * @param string $id
142
- * @return DUPX_NOTICE_ITEM
143
- */
144
- public function getNextStepNoticeById($id)
145
- {
146
- if (isset($this->nextStepNotices[$id])) {
147
- return $this->nextStepNotices[$id];
148
- } else {
149
- return null;
150
- }
151
- }
152
-
153
- /**
154
- * return last report notice by id
155
- *
156
- * @param string $id
157
- * @return DUPX_NOTICE_ITEM
158
- */
159
- public function getFinalReporNoticeById($id)
160
- {
161
- if (isset($this->finalReporNotices[$id])) {
162
- return $this->finalReporNotices[$id];
163
- } else {
164
- return null;
165
- }
166
- }
167
-
168
- /**
169
- *
170
- * @param array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
171
- * // if array must be [
172
- * 'shortMsg' => text,
173
- * 'level' => level,
174
- * 'longMsg' => html text,
175
- * 'sections' => sections list,
176
- * 'faqLink' => [
177
- * 'url' => external link
178
- * 'label' => link text if empty get external url link
179
- * ]
180
- * ]
181
- * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
182
- * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
183
- *
184
- * @return string // notice insert id
185
- *
186
- * @throws Exception
187
- */
188
- public function addBothNextAndFinalReportNotice($item, $mode = self::ADD_NORMAL, $uniqueId = null)
189
- {
190
- $this->addNextStepNotice($item, $mode, $uniqueId);
191
- $this->addFinalReportNotice($item, $mode, $uniqueId);
192
- }
193
-
194
- /**
195
- *
196
- * @param array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
197
- * // if array must be [
198
- * 'shortMsg' => text,
199
- * 'level' => level,
200
- * 'longMsg' => html text,
201
- * 'sections' => sections list,
202
- * 'faqLink' => [
203
- * 'url' => external link
204
- * 'label' => link text if empty get external url link
205
- * ]
206
- * ]
207
- * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
208
- * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
209
- *
210
- * @return string // notice insert id
211
- *
212
- * @throws Exception
213
- */
214
- public function addNextStepNotice($item, $mode = self::ADD_NORMAL, $uniqueId = null)
215
- {
216
- if (!is_array($item) && !($item instanceof DUPX_NOTICE_ITEM)) {
217
- throw new Exception('Invalid item param');
218
- }
219
- return self::addReportNoticeToList($this->nextStepNotices, $item, $mode, $uniqueId);
220
- }
221
-
222
- /**
223
- * addNextStepNotice wrapper to add simple message with error level
224
- *
225
- * @param string $message
226
- * @param int $level // warning level
227
- * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
228
- * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
229
- *
230
- * @return string // notice insert id
231
- *
232
- * @throws Exception
233
- */
234
- public function addNextStepNoticeMessage($message, $level = DUPX_NOTICE_ITEM::INFO, $mode = self::ADD_NORMAL, $uniqueId = null)
235
- {
236
- return $this->addNextStepNotice(array(
237
- 'shortMsg' => $message,
238
- 'level' => $level,
239
- ), $mode, $uniqueId);
240
- }
241
-
242
- /**
243
- *
244
- * @param array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
245
- * // if array must be [
246
- * 'shortMsg' => text,
247
- * 'level' => level,
248
- * 'longMsg' => html text,
249
- * 'sections' => sections list,
250
- * 'faqLink' => [
251
- * 'url' => external link
252
- * 'label' => link text if empty get external url link
253
- * ]
254
- * ]
255
- * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
256
- * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
257
- *
258
- * @return string // notice insert id
259
- *
260
- * @throws Exception
261
- */
262
- public function addFinalReportNotice($item, $mode = self::ADD_NORMAL, $uniqueId = null)
263
- {
264
- if (!is_array($item) && !($item instanceof DUPX_NOTICE_ITEM)) {
265
- throw new Exception('Invalid item param');
266
- }
267
- return self::addReportNoticeToList($this->finalReporNotices, $item, $mode, $uniqueId);
268
- }
269
-
270
- /**
271
- * addFinalReportNotice wrapper to add simple message with error level
272
- *
273
- * @param string $message
274
- * @param string|string[] $sections // message sections on final report
275
- * @param int $level // warning level
276
- * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
277
- * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
278
- *
279
- * @return string // notice insert id
280
- *
281
- * @throws Exception
282
- */
283
- public function addFinalReportNoticeMessage($message, $sections, $level = DUPX_NOTICE_ITEM::INFO, $mode = self::ADD_NORMAL, $uniqueId = null)
284
- {
285
- return $this->addFinalReportNotice(array(
286
- 'shortMsg' => $message,
287
- 'level' => $level,
288
- 'sections' => $sections,
289
- ), $mode, $uniqueId);
290
- }
291
-
292
- /**
293
- *
294
- * @param array $list
295
- * @param array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
296
- * // if array must be [
297
- * 'shortMsg' => text,
298
- * 'level' => level,
299
- * 'longMsg' => html text,
300
- * 'sections' => sections list,
301
- * 'faqLink' => [
302
- * 'url' => external link
303
- * 'label' => link text if empty get external url link
304
- * ]
305
- * ]
306
- * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
307
- * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
308
- *
309
- * @return string // notice insert id
310
- *
311
- * @throws Exception
312
- */
313
- private static function addReportNoticeToList(&$list, $item, $mode = self::ADD_NORMAL, $uniqueId = null)
314
- {
315
- switch ($mode) {
316
- case self::ADD_UNIQUE:
317
- if (empty($uniqueId)) {
318
- throw new Exception('uniqueId can\'t be empty');
319
- }
320
- if (isset($list[$uniqueId])) {
321
- return $uniqueId;
322
- }
323
- // no break -> continue on unique update
324
- case self::ADD_UNIQUE_UPDATE:
325
- if (empty($uniqueId)) {
326
- throw new Exception('uniqueId can\'t be empty');
327
- }
328
- $insertId = $uniqueId;
329
- break;
330
- case self::ADD_UNIQUE_APPEND_IF_EXISTS:
331
- if (empty($uniqueId)) {
332
- throw new Exception('uniqueId can\'t be empty');
333
- }
334
- if (!isset($list[$uniqueId])) {
335
- return false;
336
- }
337
- // no break
338
- case self::ADD_UNIQUE_APPEND:
339
- if (empty($uniqueId)) {
340
- throw new Exception('uniqueId can\'t be empty');
341
- }
342
- $insertId = $uniqueId;
343
- // if item id exist append long msg
344
- if (isset($list[$uniqueId])) {
345
- $tempObj = self::getObjFromParams($item);
346
- $list[$uniqueId]->longMsg .= $tempObj->longMsg;
347
- $item = $list[$uniqueId];
348
- }
349
- break;
350
- case self::ADD_UNIQUE_PREPEND_IF_EXISTS:
351
- if (empty($uniqueId)) {
352
- throw new Exception('uniqueId can\'t be empty');
353
- }
354
- if (!isset($list[$uniqueId])) {
355
- return false;
356
- }
357
- // no break
358
- case self::ADD_UNIQUE_PREPEND:
359
- if (empty($uniqueId)) {
360
- throw new Exception('uniqueId can\'t be empty');
361
- }
362
- $insertId = $uniqueId;
363
- // if item id exist append long msg
364
- if (isset($list[$uniqueId])) {
365
- $tempObj = self::getObjFromParams($item);
366
- $list[$uniqueId]->longMsg = $tempObj->longMsg.$list[$uniqueId]->longMsg;
367
- $item = $list[$uniqueId];
368
- }
369
- break;
370
- case self::ADD_NORMAL:
371
- default:
372
- if (empty($uniqueId)) {
373
- $insertId = self::getNewAutoUniqueId();
374
- } else {
375
- $insertId = $uniqueId;
376
- }
377
- }
378
-
379
- $list[$insertId] = self::getObjFromParams($item);
380
- return $insertId;
381
- }
382
-
383
- /**
384
- *
385
- * @param string|array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
386
- * // if array must be [
387
- * 'shortMsg' => text,
388
- * 'level' => level,
389
- * 'longMsg' => html text,
390
- * 'sections' => sections list,
391
- * 'faqLink' => [
392
- * 'url' => external link
393
- * 'label' => link text if empty get external url link
394
- * ]
395
- * ]
396
- * @param int $level message level considered only in the case where $item is a string.
397
- * @return \DUPX_NOTICE_ITEM
398
- *
399
- * @throws Exception
400
- */
401
- private static function getObjFromParams($item, $level = DUPX_NOTICE_ITEM::INFO)
402
- {
403
- if ($item instanceof DUPX_NOTICE_ITEM) {
404
- $newObj = $item;
405
- } else if (is_array($item)) {
406
- $newObj = DUPX_NOTICE_ITEM::getItemFromArray($item);
407
- } else if (is_string($item)) {
408
- $newObj = new DUPX_NOTICE_ITEM($item, $level);
409
- } else {
410
- throw new Exception('Notice input not valid');
411
- }
412
-
413
- return $newObj;
414
- }
415
-
416
- /**
417
- *
418
- * @param null|string $section if null is count global
419
- * @param int $level error level
420
- * @param string $operator > < >= <= = !=
421
- *
422
- * @return int
423
- */
424
- public function countFinalReportNotices($section = null, $level = DUPX_NOTICE_ITEM::INFO, $operator = '>=')
425
- {
426
- $result = 0;
427
- foreach ($this->finalReporNotices as $notice) {
428
- if (is_null($section) || in_array($section, $notice->sections)) {
429
- switch ($operator) {
430
- case '>=':
431
- $result += (int) ($notice->level >= $level);
432
- break;
433
- case '>':
434
- $result += (int) ($notice->level > $level);
435
- break;
436
- case '=':
437
- $result += (int) ($notice->level = $level);
438
- break;
439
- case '<=':
440
- $result += (int) ($notice->level <= $level);
441
- break;
442
- case '<':
443
- $result += (int) ($notice->level < $level);
444
- break;
445
- case '!=':
446
- $result += (int) ($notice->level != $level);
447
- break;
448
- }
449
- }
450
- }
451
- return $result;
452
- }
453
-
454
- /**
455
- * sort final report notice from priority and notice level
456
- */
457
- public function sortFinalReport()
458
- {
459
- uasort($this->finalReporNotices, 'DUPX_NOTICE_ITEM::sortNoticeForPriorityAndLevel');
460
- }
461
-
462
- /**
463
- * display final final report notice section
464
- *
465
- * @param string $section
466
- */
467
- public function displayFinalReport($section)
468
- {
469
- foreach ($this->finalReporNotices as $id => $notice) {
470
- if (in_array($section, $notice->sections)) {
471
- self::finalReportNotice($id, $notice);
472
- }
473
- }
474
- }
475
-
476
- /**
477
- *
478
- * @param string $section
479
- * @param string $title
480
- */
481
- public function displayFinalRepostSectionHtml($section, $title)
482
- {
483
- if ($this->haveSection($section)) {
484
- ?>
485
- <div id="report-section-<?php echo $section; ?>" class="section" >
486
- <div class="section-title" ><?php echo $title; ?></div>
487
- <div class="section-content">
488
- <?php
489
- $this->displayFinalReport($section);
490
- ?>
491
- </div>
492
- </div>
493
- <?php
494
- }
495
- }
496
-
497
- /**
498
- *
499
- * @param string $section
500
- * @return boolean
501
- */
502
- public function haveSection($section)
503
- {
504
- foreach ($this->finalReporNotices as $notice) {
505
- if (in_array($section, $notice->sections)) {
506
- return true;
507
- }
508
- }
509
- return false;
510
- }
511
-
512
- /**
513
- *
514
- * @param null|string $section if null is a global result
515
- *
516
- * @return int // returns the worst level found
517
- *
518
- */
519
- public function getSectionErrLevel($section = null)
520
- {
521
- $result = DUPX_NOTICE_ITEM::INFO;
522
-
523
- foreach ($this->finalReporNotices as $notice) {
524
- if (is_null($section) || in_array($section, $notice->sections)) {
525
- $result = max($result, $notice->level);
526
- }
527
- }
528
- return $result;
529
- }
530
-
531
- /**
532
- *
533
- * @param string $section
534
- * @param bool $echo
535
- * @return void|string
536
- */
537
- public function getSectionErrLevelHtml($section = null, $echo = true)
538
- {
539
- return self::getErrorLevelHtml($this->getSectionErrLevel($section), $echo);
540
- }
541
-
542
- /**
543
- * Displa next step notice message
544
- *
545
- * @param bool $deleteListAfterDisaply
546
- * @return void
547
- */
548
- public function displayStepMessages($deleteListAfterDisaply = true)
549
- {
550
- if (empty($this->nextStepNotices)) {
551
- return;
552
- }
553
- ?>
554
- <div id="step-messages">
555
- <?php
556
- foreach ($this->nextStepNotices as $notice) {
557
- self::stepMsg($notice);
558
- }
559
- ?>
560
- </div>
561
- <?php
562
- if ($deleteListAfterDisaply) {
563
- $this->nextStepNotices = array();
564
- $this->saveNotices();
565
- }
566
- }
567
-
568
- /**
569
- *
570
- * @param DUPX_NOTICE_ITEM $notice
571
- */
572
- private static function stepMsg($notice)
573
- {
574
- $classes = array(
575
- 'notice',
576
- 'next-step',
577
- self::getClassFromLevel($notice->level)
578
- );
579
- $haveContent = !empty($notice->faqLink) || !empty($notice->longMsg);
580
- ?>
581
- <div class="<?php echo implode(' ', $classes); ?>">
582
- <div class="title">
583
- <?php echo self::getNextStepLevelPrefixMessage($notice->level).': <b>'.htmlentities($notice->shortMsg).'</b>'; ?>
584
- </div>
585
- <?php if ($haveContent) { ?>
586
- <div class="title-separator" ></div>
587
- <?php
588
- ob_start();
589
- if (!empty($notice->faqLink)) {
590
- ?>
591
- See FAQ: <a href="<?php echo $notice->faqLink['url']; ?>" >
592
- <b><?php echo htmlentities(empty($notice->faqLink['label']) ? $notice->faqLink['url'] : $notice->faqLink['label']); ?></b>
593
- </a>
594
- <?php
595
- }
596
- if (!empty($notice->faqLink) && !empty($notice->longMsg)) {
597
- echo '<br><br>';
598
- }
599
- if (!empty($notice->longMsg)) {
600
- switch ($notice->longMsgMode) {
601
- case DUPX_NOTICE_ITEM::MSG_MODE_PRE:
602
- echo '<pre>'.htmlentities($notice->longMsg).'</pre>';
603
- break;
604
- case DUPX_NOTICE_ITEM::MSG_MODE_HTML:
605
- echo $notice->longMsg;
606
- break;
607
- case DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT:
608
- default:
609
- echo htmlentities($notice->longMsg);
610
- }
611
- }
612
- $longContent = ob_get_clean();
613
- DUPX_U_Html::getMoreContent($longContent, 'info', 200);
614
- }
615
- ?>
616
- </div>
617
- <?php
618
- }
619
-
620
- /**
621
- *
622
- * @param string $id
623
- * @param DUPX_NOTICE_ITEM $notice
624
- */
625
- private static function finalReportNotice($id, $notice)
626
- {
627
- $classes = array(
628
- 'notice-report',
629
- 'notice',
630
- self::getClassFromLevel($notice->level)
631
- );
632
- $haveContent = !empty($notice->faqLink) || !empty($notice->longMsg);
633
- $contentId = 'notice-content-'.$id;
634
- $iconClasses = $haveContent ? 'fa fa-caret-right' : 'fa fa-toggle-empty';
635
- $toggleLinkData = $haveContent ? 'data-type="toggle" data-target="#'.$contentId.'"' : '';
636
- ?>
637
- <div class="<?php echo implode(' ', $classes); ?>">
638
- <div class="title" <?php echo $toggleLinkData; ?>>
639
- <i class="<?php echo $iconClasses; ?>"></i> <?php echo htmlentities($notice->shortMsg); ?>
640
- </div>
641
- <?php
642
- if ($haveContent) {
643
- $infoClasses = array('info');
644
- if (!$notice->open) {
645
- $infoClasses[] = 'no-display';
646
- }
647
- ?>
648
- <div id="<?php echo $contentId; ?>" class="<?php echo implode(' ', $infoClasses); ?>" >
649
- <?php
650
- if (!empty($notice->faqLink)) {
651
- ?>
652
- <b>See FAQ</b>: <a href="<?php echo $notice->faqLink['url']; ?>" >
653
- <?php echo htmlentities(empty($notice->faqLink['label']) ? $notice->faqLink['url'] : $notice->faqLink['label']); ?>
654
- </a>
655
- <?php
656
- }
657
- if (!empty($notice->faqLink) && !empty($notice->longMsg)) {
658
- echo '<br><br>';
659
- }
660
- if (!empty($notice->longMsg)) {
661
- switch ($notice->longMsgMode) {
662
- case DUPX_NOTICE_ITEM::MSG_MODE_PRE:
663
- echo '<pre>'.htmlentities($notice->longMsg).'</pre>';
664
- break;
665
- case DUPX_NOTICE_ITEM::MSG_MODE_HTML:
666
- echo $notice->longMsg;
667
- break;
668
- case DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT:
669
- default:
670
- echo htmlentities($notice->longMsg);
671
- }
672
- }
673
- ?>
674
- </div>
675
- <?php
676
- }
677
- ?>
678
- </div>
679
- <?php
680
- }
681
-
682
- /**
683
- *
684
- * @param DUPX_NOTICE_ITEM $notice
685
- */
686
- private static function noticeToText($notice)
687
- {
688
- $result = '-----------------------'."\n".
689
- '['.self::getNextStepLevelPrefixMessage($notice->level, false).'] '.$notice->shortMsg;
690
-
691
- if (!empty($notice->sections)) {
692
- $result .= "\n\t".'SECTIONS: '.implode(',', $notice->sections);
693
- }
694
- if (!empty($notice->longMsg)) {
695
- $result .= "\n\t".'LONG MSG: '.$notice->longMsg;
696
- }
697
- return $result."\n";
698
- }
699
-
700
- public function nextStepLog()
701
- {
702
- if (!empty($this->nextStepNotices)) {
703
- DUPX_Log::info(
704
- '===================================='."\n".
705
- 'NEXT STEP NOTICES'."\n".
706
- '====================================');
707
- foreach ($this->nextStepNotices as $notice) {
708
- DUPX_Log::info(self::noticeToText($notice));
709
- }
710
- DUPX_Log::info(
711
- '====================================');
712
- }
713
- }
714
-
715
- public function finalReportLog($sections = array())
716
- {
717
- if (!empty($this->finalReporNotices)) {
718
- DUPX_Log::info(
719
- '===================================='."\n".
720
- 'FINAL REPORT NOTICES LIST'."\n".
721
- '====================================');
722
- foreach ($this->finalReporNotices as $notice) {
723
- if (count(array_intersect($notice->sections, $sections)) > 0) {
724
- DUPX_Log::info(self::noticeToText($notice));
725
- }
726
- }
727
- DUPX_Log::info(
728
- '====================================');
729
- }
730
- }
731
-
732
- /**
733
- * get html class from level
734
- *
735
- * @param int $level
736
- * @return string
737
- */
738
- private static function getClassFromLevel($level)
739
- {
740
- switch ($level) {
741
- case DUPX_NOTICE_ITEM::INFO:
742
- return 'l-info';
743
- case DUPX_NOTICE_ITEM::NOTICE:
744
- return 'l-notice';
745
- case DUPX_NOTICE_ITEM::SOFT_WARNING:
746
- return 'l-swarning';
747
- case DUPX_NOTICE_ITEM::HARD_WARNING:
748
- return 'l-hwarning';
749
- case DUPX_NOTICE_ITEM::CRITICAL:
750
- return 'l-critical';
751
- case DUPX_NOTICE_ITEM::FATAL:
752
- return 'l-fatal';
753
- }
754
- }
755
-
756
- /**
757
- * get level label from level
758
- *
759
- * @param int $level
760
- * @param bool $echo
761
- * @return type
762
- */
763
- public static function getErrorLevelHtml($level, $echo = true)
764
- {
765
- switch ($level) {
766
- case DUPX_NOTICE_ITEM::INFO:
767
- $label = 'good';
768
- break;
769
- case DUPX_NOTICE_ITEM::NOTICE:
770
- $label = 'good';
771
- break;
772
- case DUPX_NOTICE_ITEM::SOFT_WARNING:
773
- $label = 'warning';
774
- break;
775
- case DUPX_NOTICE_ITEM::HARD_WARNING:
776
- $label = 'warning';
777
- break;
778
- case DUPX_NOTICE_ITEM::CRITICAL:
779
- $label = 'critical error';
780
- break;
781
- case DUPX_NOTICE_ITEM::FATAL:
782
- $label = 'fatal error';
783
- break;
784
- default:
785
- return;
786
- }
787
- $classes = self::getClassFromLevel($level);
788
- ob_start();
789
- ?>
790
- <span class="notice-level-status <?php echo $classes; ?>"><?php echo $label; ?></span>
791
- <?php
792
- if ($echo) {
793
- ob_end_flush();
794
- } else {
795
- return ob_get_clean();
796
- }
797
- }
798
-
799
- /**
800
- * get next step message prefix
801
- *
802
- * @param int $level
803
- * @param bool $echo
804
- * @return string
805
- */
806
- public static function getNextStepLevelPrefixMessage($level, $echo = true)
807
- {
808
- switch ($level) {
809
- case DUPX_NOTICE_ITEM::INFO:
810
- $label = 'INFO';
811
- break;
812
- case DUPX_NOTICE_ITEM::NOTICE:
813
- $label = 'NOTICE';
814
- break;
815
- case DUPX_NOTICE_ITEM::SOFT_WARNING:
816
- $label = 'WARNING';
817
- break;
818
- case DUPX_NOTICE_ITEM::HARD_WARNING:
819
- $label = 'WARNING';
820
- break;
821
- case DUPX_NOTICE_ITEM::CRITICAL:
822
- $label = 'CRITICAL ERROR';
823
- break;
824
- case DUPX_NOTICE_ITEM::FATAL:
825
- $label = 'FATAL ERROR';
826
- break;
827
- default:
828
- return;
829
- }
830
-
831
- if ($echo) {
832
- echo $label;
833
- } else {
834
- return $label;
835
- }
836
- }
837
-
838
- /**
839
- * get unique id
840
- *
841
- * @return string
842
- */
843
- private static function getNewAutoUniqueId()
844
- {
845
- self::$uniqueCountId ++;
846
- return self::DEFAULT_UNIQUE_ID_PREFIX.self::$uniqueCountId;
847
- }
848
-
849
- /**
850
- * function for internal test
851
- *
852
- * display all messages levels
853
- */
854
- public static function testNextStepMessaesLevels()
855
- {
856
- $manager = self::getInstance();
857
- $manager->addNextStepNoticeMessage('Level info ('.DUPX_NOTICE_ITEM::INFO.')', DUPX_NOTICE_ITEM::INFO);
858
- $manager->addNextStepNoticeMessage('Level notice ('.DUPX_NOTICE_ITEM::NOTICE.')', DUPX_NOTICE_ITEM::NOTICE);
859
- $manager->addNextStepNoticeMessage('Level soft warning ('.DUPX_NOTICE_ITEM::SOFT_WARNING.')', DUPX_NOTICE_ITEM::SOFT_WARNING);
860
- $manager->addNextStepNoticeMessage('Level hard warning ('.DUPX_NOTICE_ITEM::HARD_WARNING.')', DUPX_NOTICE_ITEM::HARD_WARNING);
861
- $manager->addNextStepNoticeMessage('Level critical error ('.DUPX_NOTICE_ITEM::CRITICAL.')', DUPX_NOTICE_ITEM::CRITICAL);
862
- $manager->addNextStepNoticeMessage('Level fatal error ('.DUPX_NOTICE_ITEM::FATAL.')', DUPX_NOTICE_ITEM::FATAL);
863
- $manager->saveNotices();
864
- }
865
-
866
- /**
867
- * test function
868
- */
869
- public static function testNextStepFullMessageData()
870
- {
871
- $manager = self::getInstance();
872
- $longMsg = <<<LONGMSG
873
- <b>Formattend long text</b><br>
874
- <ul>
875
- <li>Proin dapibus mi eu erat pulvinar, id congue nisl egestas.</li>
876
- <li>Nunc venenatis eros et sapien ornare consequat.</li>
877
- <li>Mauris tincidunt est sit amet turpis placerat, a tristique dui porttitor.</li>
878
- <li>Etiam volutpat lectus quis risus molestie faucibus.</li>
879
- <li>Integer gravida eros sit amet sem viverra, a volutpat neque rutrum.</li>
880
- <li>Aenean varius ipsum vitae lorem tempus rhoncus.</li>
881
- </ul>
882
- LONGMSG;
883
- $manager->addNextStepNotice(array(
884
- 'shortMsg' => 'Full elements next step message MODE HTML',
885
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
886
- 'longMsg' => $longMsg,
887
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
888
- 'faqLink' => array(
889
- 'url' => 'http://www.google.it',
890
- 'label' => 'google link'
891
- )
892
- ));
893
-
894
- $longMsg = <<<LONGMSG
895
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc a auctor erat, et lobortis libero.
896
- Suspendisse aliquet neque in massa posuere mollis. Donec venenatis finibus sapien in bibendum. Donec et ex massa.
897
-
898
- Aliquam venenatis dapibus tellus nec ullamcorper. Mauris ante velit, tincidunt sit amet egestas et, mattis non lorem. In semper ex ut velit suscipit,
899
- at luctus nunc dapibus. Etiam blandit maximus dapibus. Nullam eu porttitor augue. Suspendisse pulvinar, massa eget condimentum aliquet, dolor massa tempus dui, vel rhoncus tellus ligula non odio.
900
- Ut ac faucibus tellus, in lobortis odio.
901
- LONGMSG;
902
- $manager->addNextStepNotice(array(
903
- 'shortMsg' => 'Full elements next step message MODE PRE',
904
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
905
- 'longMsg' => $longMsg,
906
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE,
907
- 'faqLink' => array(
908
- 'url' => 'http://www.google.it',
909
- 'label' => 'google link'
910
- )
911
- ));
912
-
913
- $longMsg = <<<LONGMSG
914
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc a auctor erat, et lobortis libero.
915
- Suspendisse aliquet neque in massa posuere mollis. Donec venenatis finibus sapien in bibendum. Donec et ex massa.
916
-
917
- Aliquam venenatis dapibus tellus nec ullamcorper. Mauris ante velit, tincidunt sit amet egestas et, mattis non lorem. In semper ex ut velit suscipit,
918
- at luctus nunc dapibus. Etiam blandit maximus dapibus. Nullam eu porttitor augue. Suspendisse pulvinar, massa eget condimentum aliquet, dolor massa tempus dui, vel rhoncus tellus ligula non odio.
919
- Ut ac faucibus tellus, in lobortis odio.
920
- LONGMSG;
921
- $manager->addNextStepNotice(array(
922
- 'shortMsg' => 'Full elements next step message MODE DEFAULT',
923
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
924
- 'longMsg' => $longMsg,
925
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
926
- 'faqLink' => array(
927
- 'url' => 'http://www.google.it',
928
- 'label' => 'google link'
929
- )
930
- ));
931
-
932
-
933
- $longMsg = <<<LONGMSG
934
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam cursus porttitor consectetur. Nunc faucibus elementum nisl nec ornare. Phasellus sit amet urna in diam ultricies ornare nec sit amet nibh. Nulla a aliquet leo. Quisque aliquet posuere lectus sit amet commodo. Nullam tempus enim eget urna rutrum egestas. Aliquam eget lorem nisl. Nulla tincidunt massa erat. Phasellus lectus tellus, mollis sit amet aliquam in, dapibus quis metus. Nunc venenatis nulla vitae convallis accumsan.
935
-
936
- Mauris eu ullamcorper metus. Aenean ultricies et turpis eget mollis. Aliquam auctor, elit scelerisque placerat pellentesque, quam augue fermentum lectus, vel pretium nisi justo sit amet ante. Donec blandit porttitor tempus. Duis vulputate nulla ut orci rutrum, et consectetur urna mollis. Sed at iaculis velit. Pellentesque id quam turpis. Curabitur eu ligula velit. Cras gravida, ipsum sed iaculis eleifend, mauris nunc posuere quam, vel blandit nisi justo congue ligula. Phasellus aliquam eu odio ac porttitor. Fusce dictum mollis turpis sit amet fringilla.
937
-
938
- Nulla eu ligula mauris. Fusce lobortis ligula elit, a interdum nibh pulvinar eu. Pellentesque rhoncus nec turpis id blandit. Morbi fringilla, justo non varius consequat, arcu ante efficitur ante, sit amet cursus lorem elit vel odio. Phasellus neque ligula, vehicula vel ipsum sed, volutpat dignissim eros. Curabitur at lacus id felis elementum auctor. Nullam ac tempus nisi. Phasellus nibh purus, aliquam nec purus ut, sodales lobortis nulla. Cras viverra dictum magna, ac malesuada nibh dictum ac. Mauris euismod, magna sit amet pretium posuere, ligula nibh ultrices tellus, sit amet pretium odio urna egestas justo. Suspendisse purus erat, eleifend sed magna in, efficitur interdum nibh.
939
-
940
- Vivamus nibh nunc, fermentum non tortor volutpat, consectetur vulputate velit. Phasellus lobortis, purus et faucibus mollis, metus eros viverra ante, sit amet euismod nibh est eu orci. Duis sodales cursus lacinia. Praesent laoreet ut ipsum ut interdum. Praesent venenatis massa vitae ligula consequat aliquet. Fusce in purus in odio molestie laoreet at ac augue. Fusce consectetur elit a magna mollis aliquet.
941
-
942
- Nulla eros nisi, dapibus eget diam vitae, tincidunt blandit odio. Fusce interdum tellus nec varius condimentum. Fusce non magna a purus sodales imperdiet sit amet vitae ligula. Quisque viverra leo sit amet mi egestas, et posuere nunc tincidunt. Suspendisse feugiat malesuada urna sed tincidunt. Morbi a urna sed magna volutpat pellentesque sit amet ac mauris. Nulla sed ultrices dui. Etiam massa arcu, tempor ut erat at, cursus malesuada ipsum. Duis sit amet felis dolor.
943
-
944
- Morbi gravida nisl nunc, vulputate iaculis risus vehicula non. Proin cursus, velit et laoreet consectetur, lacus libero sagittis lacus, quis accumsan odio lectus non erat. Aenean dolor lectus, euismod sit amet justo eget, dictum gravida nisl. Phasellus sed nunc non odio ullamcorper rhoncus non ut ipsum. Duis ante ligula, pellentesque sit amet imperdiet eget, congue vel dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla facilisi. Suspendisse luctus leo eget justo mollis, convallis convallis ex suscipit. Integer et justo eget odio lobortis sollicitudin. Pellentesque accumsan rhoncus augue, luctus suscipit ex accumsan nec. Maecenas lacinia consectetur risus at bibendum. Etiam venenatis purus lorem, sit amet elementum turpis tristique eu. Proin vulputate faucibus feugiat. Nunc vehicula congue odio consequat vulputate. Quisque bibendum augue id iaculis faucibus. Donec blandit cursus sem, eget accumsan orci commodo sed.
945
-
946
- Suspendisse iaculis est quam, sed scelerisque purus tincidunt non. Cras hendrerit ante turpis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse purus ipsum, rutrum id sem in, venenatis laoreet metus. Aliquam ac bibendum mauris. Cras egestas rhoncus est, sed lacinia nibh vestibulum id. Proin diam quam, sagittis congue molestie ac, rhoncus et mauris. Phasellus massa neque, ornare vel erat a, rutrum pharetra arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi et nulla eget massa auctor fermentum. Quisque maximus tellus sed cursus cursus. Ut vehicula erat at purus aliquet, quis imperdiet dui sagittis. Nullam eget quam leo.
947
-
948
- Nulla magna ipsum, congue nec dui ut, lacinia malesuada felis. Cras mattis metus non maximus venenatis. Aliquam euismod est vitae erat sollicitudin, at pellentesque augue sollicitudin. Curabitur euismod maximus cursus. In tortor dui, convallis sed sapien ac, varius congue metus. Nunc ullamcorper ac orci sit amet finibus. Vivamus molestie nibh vitae quam rhoncus, eu ultrices est molestie. Maecenas consectetur eu quam sit amet placerat.
949
-
950
- Curabitur ut fermentum mauris. Donec et congue nibh. Sed cursus elit sit amet convallis varius. Donec malesuada porta odio condimentum varius. Pellentesque ornare tempor ante, ut volutpat nulla lobortis sed. Nunc congue aliquet erat ac elementum. Quisque a ex sit amet turpis placerat sagittis eget ac ligula. Etiam in augue malesuada, aliquam est non, lacinia justo. Vivamus tincidunt dolor orci, id dignissim lorem maximus at. Vivamus ligula mauris, venenatis vel nibh id, lacinia ultrices ipsum. Mauris cursus, urna ac rutrum aliquet, risus ipsum tincidunt purus, sit amet blandit nunc sem sit amet nibh.
951
-
952
- Nam eleifend risus lacus, eu pharetra risus egestas eu. Maecenas hendrerit nisl in semper placerat. Vestibulum massa tellus, laoreet non euismod quis, sollicitudin id sapien. Morbi vel cursus metus. Aenean tincidunt nisi est, ut elementum est auctor id. Duis auctor elit leo, ac scelerisque risus suscipit et. Pellentesque lectus nisi, ultricies in elit sed, pulvinar iaculis massa. Morbi viverra eros mi, pretium facilisis neque egestas id. Curabitur non massa accumsan, porttitor sem vitae, ultricies lacus. Curabitur blandit nisl velit. Mauris sollicitudin ultricies purus sit amet placerat. Fusce ac neque sed leo venenatis laoreet ut non ex. Integer elementum rhoncus orci, eu maximus neque tempus eu. Curabitur euismod dignissim tellus, vitae lacinia metus. Mauris imperdiet metus vitae vulputate accumsan. Duis eget luctus nibh, sit amet finibus libero.
953
-
954
- LONGMSG;
955
- $manager->addNextStepNotice(array(
956
- 'shortMsg' => 'Full elements LONG LONG',
957
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
958
- 'longMsg' => $longMsg,
959
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
960
- 'faqLink' => array(
961
- 'url' => 'http://www.google.it',
962
- 'label' => 'google link'
963
- )
964
- ));
965
-
966
-
967
-
968
-
969
- $manager->saveNotices();
970
- }
971
-
972
- /**
973
- * test function
974
- */
975
- public static function testFinalReporMessaesLevels()
976
- {
977
- $section = 'general';
978
-
979
- $manager = self::getInstance();
980
- $manager->addFinalReportNoticeMessage('Level info ('.DUPX_NOTICE_ITEM::INFO.')', $section, DUPX_NOTICE_ITEM::INFO, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_0');
981
- $manager->addFinalReportNoticeMessage('Level notice ('.DUPX_NOTICE_ITEM::NOTICE.')', $section, DUPX_NOTICE_ITEM::NOTICE, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_1');
982
- $manager->addFinalReportNoticeMessage('Level soft warning ('.DUPX_NOTICE_ITEM::SOFT_WARNING.')', $section, DUPX_NOTICE_ITEM::SOFT_WARNING, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_2');
983
- $manager->addFinalReportNoticeMessage('Level hard warning ('.DUPX_NOTICE_ITEM::HARD_WARNING.')', $section, DUPX_NOTICE_ITEM::HARD_WARNING, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_3');
984
- $manager->addFinalReportNoticeMessage('Level critical error ('.DUPX_NOTICE_ITEM::CRITICAL.')', $section, DUPX_NOTICE_ITEM::CRITICAL, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_4');
985
- $manager->addFinalReportNoticeMessage('Level fatal error ('.DUPX_NOTICE_ITEM::FATAL.')', $section, DUPX_NOTICE_ITEM::FATAL, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_5');
986
- $manager->saveNotices();
987
- }
988
-
989
- /**
990
- * test function
991
- */
992
- public static function testFinalReportFullMessages()
993
- {
994
- $section = 'general';
995
- $manager = self::getInstance();
996
-
997
- $longMsg = <<<LONGMSG
998
- <b>Formattend long text</b><br>
999
- <ul>
1000
- <li>Proin dapibus mi eu erat pulvinar, id congue nisl egestas.</li>
1001
- <li>Nunc venenatis eros et sapien ornare consequat.</li>
1002
- <li>Mauris tincidunt est sit amet turpis placerat, a tristique dui porttitor.</li>
1003
- <li>Etiam volutpat lectus quis risus molestie faucibus.</li>
1004
- <li>Integer gravida eros sit amet sem viverra, a volutpat neque rutrum.</li>
1005
- <li>Aenean varius ipsum vitae lorem tempus rhoncus.</li>
1006
- </ul>
1007
- LONGMSG;
1008
-
1009
- $manager->addFinalReportNotice(array(
1010
- 'shortMsg' => 'Full elements final report message',
1011
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
1012
- 'longMsg' => $longMsg,
1013
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
1014
- 'sections' => $section,
1015
- 'faqLink' => array(
1016
- 'url' => 'http://www.google.it',
1017
- 'label' => 'google link'
1018
- )
1019
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_full_1');
1020
-
1021
- $manager->addFinalReportNotice(array(
1022
- 'shortMsg' => 'Full elements final report message info high priority',
1023
- 'level' => DUPX_NOTICE_ITEM::INFO,
1024
- 'longMsg' => $longMsg,
1025
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
1026
- 'sections' => $section,
1027
- 'faqLink' => array(
1028
- 'url' => 'http://www.google.it',
1029
- 'label' => 'google link'
1030
- ),
1031
- 'priority' => 5
1032
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_full_2');
1033
- $manager->saveNotices();
1034
- }
1035
-
1036
- //PHP 8 Requires method to be public
1037
- public function __wakeup()
1038
- {
1039
- }
1040
-
1041
- private function __clone()
1042
- {
1043
-
1044
- }
1045
-
1046
- }
1047
-
1048
- class DUPX_NOTICE_ITEM
1049
- {
1050
- const INFO = 0;
1051
- const NOTICE = 1;
1052
- const SOFT_WARNING = 2;
1053
- const HARD_WARNING = 3;
1054
- const CRITICAL = 4;
1055
- const FATAL = 5;
1056
- const MSG_MODE_DEFAULT = 'def';
1057
- const MSG_MODE_HTML = 'html';
1058
- const MSG_MODE_PRE = 'pre';
1059
-
1060
- /**
1061
- *
1062
- * @var string text
1063
- */
1064
- public $shortMsg = '';
1065
-
1066
- /**
1067
- *
1068
- * @var string html text
1069
- */
1070
- public $longMsg = '';
1071
-
1072
- /**
1073
- *
1074
- * @var bool if true long msg can be html
1075
- */
1076
- public $longMsgMode = self::MSG_MODE_DEFAULT;
1077
-
1078
- /**
1079
- *
1080
- * @var null|array // null = no faq link
1081
- * array( 'label' => link text , 'url' => faq url)
1082
- */
1083
- public $faqLink = array(
1084
- 'label' => '',
1085
- 'url' => ''
1086
- );
1087
-
1088
- /**
1089
- *
1090
- * @var string[] notice sections for final report only
1091
- */
1092
- public $sections = array();
1093
-
1094
- /**
1095
- *
1096
- * @var int
1097
- */
1098
- public $level = self::NOTICE;
1099
-
1100
- /**
1101
- *
1102
- * @var int
1103
- */
1104
- public $priority = 10;
1105
-
1106
- /**
1107
- *
1108
- * @var bool if true notice start open. For final report only
1109
- */
1110
- public $open = false;
1111
-
1112
- /**
1113
- *
1114
- * @param string $shortMsg text
1115
- * @param int $level
1116
- * @param string $longMsg html text
1117
- * @param string|string[] $sections
1118
- * @param null|array $faqLink [
1119
- * 'url' => external link
1120
- * 'label' => link text if empty get external url link
1121
- * ]
1122
- * @param int priority
1123
- * @param bool open
1124
- * @param string longMsgMode MSG_MODE_DEFAULT | MSG_MODE_HTML | MSG_MODE_PRE
1125
- */
1126
- public function __construct($shortMsg, $level = self::INFO, $longMsg = '', $sections = array(), $faqLink = null, $priority = 10, $open = false, $longMsgMode = self::MSG_MODE_DEFAULT)
1127
- {
1128
- $this->shortMsg = (string) $shortMsg;
1129
- $this->level = (int) $level;
1130
- $this->longMsg = (string) $longMsg;
1131
- $this->sections = is_array($sections) ? $sections : array($sections);
1132
- $this->faqLink = $faqLink;
1133
- $this->priority = $priority;
1134
- $this->open = $open;
1135
- $this->longMsgMode = $longMsgMode;
1136
- }
1137
-
1138
- /**
1139
- *
1140
- * @return array [
1141
- * 'shortMsg' => text,
1142
- * 'level' => level,
1143
- * 'longMsg' => html text,
1144
- * 'sections' => string|string[],
1145
- * 'faqLink' => [
1146
- * 'url' => external link
1147
- * 'label' => link text if empty get external url link
1148
- * ]
1149
- * 'priority' => int low first
1150
- * 'open' => if true the tab is opene on final report
1151
- * 'longMsgMode'=> MSG_MODE_DEFAULT | MSG_MODE_HTML | MSG_MODE_PRE
1152
- * ]
1153
- */
1154
- public function toArray()
1155
- {
1156
- return array(
1157
- 'shortMsg' => $this->shortMsg,
1158
- 'level' => $this->level,
1159
- 'longMsg' => $this->longMsg,
1160
- 'sections' => $this->sections,
1161
- 'faqLink' => $this->faqLink,
1162
- 'priority' => $this->priority,
1163
- 'open' => $this->open,
1164
- 'longMsgMode' => $this->longMsgMode
1165
- );
1166
- }
1167
-
1168
- /**
1169
- *
1170
- * @return array [
1171
- * 'shortMsg' => text,
1172
- * 'level' => level,
1173
- * 'longMsg' => html text,
1174
- * 'sections' => string|string[],
1175
- * 'faqLink' => [
1176
- * 'url' => external link
1177
- * 'label' => link text if empty get external url link
1178
- * ],
1179
- * priority
1180
- * open
1181
- * longMsgMode
1182
- * ]
1183
- * @return DUPX_NOTICE_ITEM
1184
- */
1185
- public static function getItemFromArray($array)
1186
- {
1187
- if (isset($array['sections']) && !is_array($array['sections'])) {
1188
- if (empty($array['sections'])) {
1189
- $array['sections'] = array();
1190
- } else {
1191
- $array['sections'] = array($array['sections']);
1192
- }
1193
- }
1194
- $params = array_merge(self::getDefaultArrayParams(), $array);
1195
- $result = new self($params['shortMsg'], $params['level'], $params['longMsg'], $params['sections'], $params['faqLink'], $params['priority'], $params['open'], $params['longMsgMode']);
1196
- return $result;
1197
- }
1198
-
1199
- /**
1200
- *
1201
- * @return array [
1202
- * 'shortMsg' => text,
1203
- * 'level' => level,
1204
- * 'longMsg' => html text,
1205
- * 'sections' => string|string[],
1206
- * 'faqLink' => [
1207
- * 'url' => external link
1208
- * 'label' => link text if empty get external url link
1209
- * ],
1210
- * priority
1211
- * open
1212
- * longMsgMode
1213
- * ]
1214
- */
1215
- public static function getDefaultArrayParams()
1216
- {
1217
- return array(
1218
- 'shortMsg' => '',
1219
- 'level' => self::INFO,
1220
- 'longMsg' => '',
1221
- 'sections' => array(),
1222
- 'faqLink' => null,
1223
- 'priority' => 10,
1224
- 'open' => false,
1225
- 'longMsgMode' => self::MSG_MODE_DEFAULT
1226
- );
1227
- }
1228
-
1229
- /**
1230
- * before lower priority
1231
- * before highest level
1232
- *
1233
- * @param DUPX_NOTICE_ITEM $a
1234
- * @param DUPX_NOTICE_ITEM $b
1235
- */
1236
- public static function sortNoticeForPriorityAndLevel($a, $b)
1237
- {
1238
- if ($a->priority == $b->priority) {
1239
- if ($a->level == $b->level) {
1240
- return 0;
1241
- } else if ($a->level < $b->level) {
1242
- return 1;
1243
- } else {
1244
- return -1;
1245
- }
1246
- } else if ($a->priority < $b->priority) {
1247
- return -1;
1248
- } else {
1249
- return 1;
1250
- }
1251
- }
1252
  }
1
+ <?php
2
+ /**
3
+ * Notice manager
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2 Full Documentation
7
+ *
8
+ * @package SC\DUPX\U
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ /**
14
+ * Notice manager
15
+ * singleton class
16
+ */
17
+ final class DUPX_NOTICE_MANAGER
18
+ {
19
+ const ADD_NORMAL = 0; // add notice in list
20
+ const ADD_UNIQUE = 1; // add if unique id don't exists
21
+ const ADD_UNIQUE_UPDATE = 2; // add or update notice unique id
22
+ const ADD_UNIQUE_APPEND = 3; // append long msg
23
+ const ADD_UNIQUE_APPEND_IF_EXISTS = 4; // append long msg if already exists item
24
+ const ADD_UNIQUE_PREPEND = 5; // append long msg
25
+ const ADD_UNIQUE_PREPEND_IF_EXISTS = 6; // prepend long msg if already exists item
26
+ const DEFAULT_UNIQUE_ID_PREFIX = '__auto_unique_id__';
27
+
28
+ private static $uniqueCountId = 0;
29
+
30
+ /**
31
+ *
32
+ * @var DUPX_NOTICE_ITEM[]
33
+ */
34
+ private $nextStepNotices = array();
35
+
36
+ /**
37
+ *
38
+ * @var DUPX_NOTICE_ITEM[]
39
+ */
40
+ private $finalReporNotices = array();
41
+
42
+ /**
43
+ *
44
+ * @var DUPX_NOTICE_MANAGER
45
+ */
46
+ private static $instance = null;
47
+
48
+ /**
49
+ *
50
+ * @var string
51
+ */
52
+ private $persistanceFile = null;
53
+
54
+ /**
55
+ *
56
+ * @return DUPX_S_R_MANAGER
57
+ */
58
+ public static function getInstance()
59
+ {
60
+ if (is_null(self::$instance)) {
61
+ self::$instance = new self();
62
+ }
63
+
64
+ return self::$instance;
65
+ }
66
+
67
+ private function __construct()
68
+ {
69
+ $this->persistanceFile = $GLOBALS["NOTICES_FILE_PATH"];
70
+ $this->loadNotices();
71
+ }
72
+
73
+ /**
74
+ * save notices from json file
75
+ */
76
+ public function saveNotices()
77
+ {
78
+ $notices = array(
79
+ 'globalData' => array(
80
+ 'uniqueCountId' => self::$uniqueCountId
81
+ ),
82
+ 'nextStep' => array(),
83
+ 'finalReport' => array()
84
+ );
85
+
86
+ foreach ($this->nextStepNotices as $uniqueId => $notice) {
87
+ $notices['nextStep'][$uniqueId] = $notice->toArray();
88
+ }
89
+
90
+ foreach ($this->finalReporNotices as $uniqueId => $notice) {
91
+ $notices['finalReport'][$uniqueId] = $notice->toArray();
92
+ }
93
+
94
+ file_put_contents($this->persistanceFile, DupLiteSnapJsonU::wp_json_encode_pprint($notices));
95
+ }
96
+
97
+ /**
98
+ * load notice from json file
99
+ */
100
+ private function loadNotices()
101
+ {
102
+ if (file_exists($this->persistanceFile)) {
103
+ $json = file_get_contents($this->persistanceFile);
104
+ $notices = json_decode($json, true);
105
+
106
+ $this->nextStepNotices = array();
107
+ $this->finalReporNotices = array();
108
+
109
+ if (!empty($notices['nextStep'])) {
110
+ foreach ($notices['nextStep'] as $uniqueId => $notice) {
111
+ $this->nextStepNotices[$uniqueId] = DUPX_NOTICE_ITEM::getItemFromArray($notice);
112
+ }
113
+ }
114
+
115
+ if (!empty($notices['finalReport'])) {
116
+ foreach ($notices['finalReport'] as $uniqueId => $notice) {
117
+ $this->finalReporNotices[$uniqueId] = DUPX_NOTICE_ITEM::getItemFromArray($notice);
118
+ }
119
+ }
120
+
121
+ self::$uniqueCountId = $notices['globalData']['uniqueCountId'];
122
+ } else {
123
+ $this->resetNotices();
124
+ }
125
+ }
126
+
127
+ /**
128
+ * remove all notices and save reset file
129
+ */
130
+ public function resetNotices()
131
+ {
132
+ $this->nextStepNotices = array();
133
+ $this->finalReporNotices = array();
134
+ self::$uniqueCountId = 0;
135
+ $this->saveNotices();
136
+ }
137
+
138
+ /**
139
+ * return next step notice by id
140
+ *
141
+ * @param string $id
142
+ * @return DUPX_NOTICE_ITEM
143
+ */
144
+ public function getNextStepNoticeById($id)
145
+ {
146
+ if (isset($this->nextStepNotices[$id])) {
147
+ return $this->nextStepNotices[$id];
148
+ } else {
149
+ return null;
150
+ }
151
+ }
152
+
153
+ /**
154
+ * return last report notice by id
155
+ *
156
+ * @param string $id
157
+ * @return DUPX_NOTICE_ITEM
158
+ */
159
+ public function getFinalReporNoticeById($id)
160
+ {
161
+ if (isset($this->finalReporNotices[$id])) {
162
+ return $this->finalReporNotices[$id];
163
+ } else {
164
+ return null;
165
+ }
166
+ }
167
+
168
+ /**
169
+ *
170
+ * @param array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
171
+ * // if array must be [
172
+ * 'shortMsg' => text,
173
+ * 'level' => level,
174
+ * 'longMsg' => html text,
175
+ * 'sections' => sections list,
176
+ * 'faqLink' => [
177
+ * 'url' => external link
178
+ * 'label' => link text if empty get external url link
179
+ * ]
180
+ * ]
181
+ * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
182
+ * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
183
+ *
184
+ * @return string // notice insert id
185
+ *
186
+ * @throws Exception
187
+ */
188
+ public function addBothNextAndFinalReportNotice($item, $mode = self::ADD_NORMAL, $uniqueId = null)
189
+ {
190
+ $this->addNextStepNotice($item, $mode, $uniqueId);
191
+ $this->addFinalReportNotice($item, $mode, $uniqueId);
192
+ }
193
+
194
+ /**
195
+ *
196
+ * @param array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
197
+ * // if array must be [
198
+ * 'shortMsg' => text,
199
+ * 'level' => level,
200
+ * 'longMsg' => html text,
201
+ * 'sections' => sections list,
202
+ * 'faqLink' => [
203
+ * 'url' => external link
204
+ * 'label' => link text if empty get external url link
205
+ * ]
206
+ * ]
207
+ * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
208
+ * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
209
+ *
210
+ * @return string // notice insert id
211
+ *
212
+ * @throws Exception
213
+ */
214
+ public function addNextStepNotice($item, $mode = self::ADD_NORMAL, $uniqueId = null)
215
+ {
216
+ if (!is_array($item) && !($item instanceof DUPX_NOTICE_ITEM)) {
217
+ throw new Exception('Invalid item param');
218
+ }
219
+ return self::addReportNoticeToList($this->nextStepNotices, $item, $mode, $uniqueId);
220
+ }
221
+
222
+ /**
223
+ * addNextStepNotice wrapper to add simple message with error level
224
+ *
225
+ * @param string $message
226
+ * @param int $level // warning level
227
+ * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
228
+ * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
229
+ *
230
+ * @return string // notice insert id
231
+ *
232
+ * @throws Exception
233
+ */
234
+ public function addNextStepNoticeMessage($message, $level = DUPX_NOTICE_ITEM::INFO, $mode = self::ADD_NORMAL, $uniqueId = null)
235
+ {
236
+ return $this->addNextStepNotice(array(
237
+ 'shortMsg' => $message,
238
+ 'level' => $level,
239
+ ), $mode, $uniqueId);
240
+ }
241
+
242
+ /**
243
+ *
244
+ * @param array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
245
+ * // if array must be [
246
+ * 'shortMsg' => text,
247
+ * 'level' => level,
248
+ * 'longMsg' => html text,
249
+ * 'sections' => sections list,
250
+ * 'faqLink' => [
251
+ * 'url' => external link
252
+ * 'label' => link text if empty get external url link
253
+ * ]
254
+ * ]
255
+ * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
256
+ * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
257
+ *
258
+ * @return string // notice insert id
259
+ *
260
+ * @throws Exception
261
+ */
262
+ public function addFinalReportNotice($item, $mode = self::ADD_NORMAL, $uniqueId = null)
263
+ {
264
+ if (!is_array($item) && !($item instanceof DUPX_NOTICE_ITEM)) {
265
+ throw new Exception('Invalid item param');
266
+ }
267
+ return self::addReportNoticeToList($this->finalReporNotices, $item, $mode, $uniqueId);
268
+ }
269
+
270
+ /**
271
+ * addFinalReportNotice wrapper to add simple message with error level
272
+ *
273
+ * @param string $message
274
+ * @param string|string[] $sections // message sections on final report
275
+ * @param int $level // warning level
276
+ * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
277
+ * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
278
+ *
279
+ * @return string // notice insert id
280
+ *
281
+ * @throws Exception
282
+ */
283
+ public function addFinalReportNoticeMessage($message, $sections, $level = DUPX_NOTICE_ITEM::INFO, $mode = self::ADD_NORMAL, $uniqueId = null)
284
+ {
285
+ return $this->addFinalReportNotice(array(
286
+ 'shortMsg' => $message,
287
+ 'level' => $level,
288
+ 'sections' => $sections,
289
+ ), $mode, $uniqueId);
290
+ }
291
+
292
+ /**
293
+ *
294
+ * @param array $list
295
+ * @param array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
296
+ * // if array must be [
297
+ * 'shortMsg' => text,
298
+ * 'level' => level,
299
+ * 'longMsg' => html text,
300
+ * 'sections' => sections list,
301
+ * 'faqLink' => [
302
+ * 'url' => external link
303
+ * 'label' => link text if empty get external url link
304
+ * ]
305
+ * ]
306
+ * @param int $mode // ADD_NORMAL | ADD_UNIQUE | ADD_UNIQUE_UPDATE | ADD_UNIQUE_APPEND
307
+ * @param string $uniqueId // used for ADD_UNIQUE or ADD_UNIQUE_UPDATE or ADD_UNIQUE_APPEND
308
+ *
309
+ * @return string // notice insert id
310
+ *
311
+ * @throws Exception
312
+ */
313
+ private static function addReportNoticeToList(&$list, $item, $mode = self::ADD_NORMAL, $uniqueId = null)
314
+ {
315
+ switch ($mode) {
316
+ case self::ADD_UNIQUE:
317
+ if (empty($uniqueId)) {
318
+ throw new Exception('uniqueId can\'t be empty');
319
+ }
320
+ if (isset($list[$uniqueId])) {
321
+ return $uniqueId;
322
+ }
323
+ // no break -> continue on unique update
324
+ case self::ADD_UNIQUE_UPDATE:
325
+ if (empty($uniqueId)) {
326
+ throw new Exception('uniqueId can\'t be empty');
327
+ }
328
+ $insertId = $uniqueId;
329
+ break;
330
+ case self::ADD_UNIQUE_APPEND_IF_EXISTS:
331
+ if (empty($uniqueId)) {
332
+ throw new Exception('uniqueId can\'t be empty');
333
+ }
334
+ if (!isset($list[$uniqueId])) {
335
+ return false;
336
+ }
337
+ // no break
338
+ case self::ADD_UNIQUE_APPEND:
339
+ if (empty($uniqueId)) {
340
+ throw new Exception('uniqueId can\'t be empty');
341
+ }
342
+ $insertId = $uniqueId;
343
+ // if item id exist append long msg
344
+ if (isset($list[$uniqueId])) {
345
+ $tempObj = self::getObjFromParams($item);
346
+ $list[$uniqueId]->longMsg .= $tempObj->longMsg;
347
+ $item = $list[$uniqueId];
348
+ }
349
+ break;
350
+ case self::ADD_UNIQUE_PREPEND_IF_EXISTS:
351
+ if (empty($uniqueId)) {
352
+ throw new Exception('uniqueId can\'t be empty');
353
+ }
354
+ if (!isset($list[$uniqueId])) {
355
+ return false;
356
+ }
357
+ // no break
358
+ case self::ADD_UNIQUE_PREPEND:
359
+ if (empty($uniqueId)) {
360
+ throw new Exception('uniqueId can\'t be empty');
361
+ }
362
+ $insertId = $uniqueId;
363
+ // if item id exist append long msg
364
+ if (isset($list[$uniqueId])) {
365
+ $tempObj = self::getObjFromParams($item);
366
+ $list[$uniqueId]->longMsg = $tempObj->longMsg.$list[$uniqueId]->longMsg;
367
+ $item = $list[$uniqueId];
368
+ }
369
+ break;
370
+ case self::ADD_NORMAL:
371
+ default:
372
+ if (empty($uniqueId)) {
373
+ $insertId = self::getNewAutoUniqueId();
374
+ } else {
375
+ $insertId = $uniqueId;
376
+ }
377
+ }
378
+
379
+ $list[$insertId] = self::getObjFromParams($item);
380
+ return $insertId;
381
+ }
382
+
383
+ /**
384
+ *
385
+ * @param string|array|DUPX_NOTICE_ITEM $item // if string add new notice obj with item message and level param
386
+ * // if array must be [
387
+ * 'shortMsg' => text,
388
+ * 'level' => level,
389
+ * 'longMsg' => html text,
390
+ * 'sections' => sections list,
391
+ * 'faqLink' => [
392
+ * 'url' => external link
393
+ * 'label' => link text if empty get external url link
394
+ * ]
395
+ * ]
396
+ * @param int $level message level considered only in the case where $item is a string.
397
+ * @return \DUPX_NOTICE_ITEM
398
+ *
399
+ * @throws Exception
400
+ */
401
+ private static function getObjFromParams($item, $level = DUPX_NOTICE_ITEM::INFO)
402
+ {
403
+ if ($item instanceof DUPX_NOTICE_ITEM) {
404
+ $newObj = $item;
405
+ } else if (is_array($item)) {
406
+ $newObj = DUPX_NOTICE_ITEM::getItemFromArray($item);
407
+ } else if (is_string($item)) {
408
+ $newObj = new DUPX_NOTICE_ITEM($item, $level);
409
+ } else {
410
+ throw new Exception('Notice input not valid');
411
+ }
412
+
413
+ return $newObj;
414
+ }
415
+
416
+ /**
417
+ *
418
+ * @param null|string $section if null is count global
419
+ * @param int $level error level
420
+ * @param string $operator > < >= <= = !=
421
+ *
422
+ * @return int
423
+ */
424
+ public function countFinalReportNotices($section = null, $level = DUPX_NOTICE_ITEM::INFO, $operator = '>=')
425
+ {
426
+ $result = 0;
427
+ foreach ($this->finalReporNotices as $notice) {
428
+ if (is_null($section) || in_array($section, $notice->sections)) {
429
+ switch ($operator) {
430
+ case '>=':
431
+ $result += (int) ($notice->level >= $level);
432
+ break;
433
+ case '>':
434
+ $result += (int) ($notice->level > $level);
435
+ break;
436
+ case '=':
437
+ $result += (int) ($notice->level = $level);
438
+ break;
439
+ case '<=':
440
+ $result += (int) ($notice->level <= $level);
441
+ break;
442
+ case '<':
443
+ $result += (int) ($notice->level < $level);
444
+ break;
445
+ case '!=':
446
+ $result += (int) ($notice->level != $level);
447
+ break;
448
+ }
449
+ }
450
+ }
451
+ return $result;
452
+ }
453
+
454
+ /**
455
+ * sort final report notice from priority and notice level
456
+ */
457
+ public function sortFinalReport()
458
+ {
459
+ uasort($this->finalReporNotices, 'DUPX_NOTICE_ITEM::sortNoticeForPriorityAndLevel');
460
+ }
461
+
462
+ /**
463
+ * display final final report notice section
464
+ *
465
+ * @param string $section
466
+ */
467
+ public function displayFinalReport($section)
468
+ {
469
+ foreach ($this->finalReporNotices as $id => $notice) {
470
+ if (in_array($section, $notice->sections)) {
471
+ self::finalReportNotice($id, $notice);
472
+ }
473
+ }
474
+ }
475
+
476
+ /**
477
+ *
478
+ * @param string $section
479
+ * @param string $title
480
+ */
481
+ public function displayFinalRepostSectionHtml($section, $title)
482
+ {
483
+ if ($this->haveSection($section)) {
484
+ ?>
485
+ <div id="report-section-<?php echo $section; ?>" class="section" >
486
+ <div class="section-title" ><?php echo $title; ?></div>
487
+ <div class="section-content">
488
+ <?php
489
+ $this->displayFinalReport($section);
490
+ ?>
491
+ </div>
492
+ </div>
493
+ <?php
494
+ }
495
+ }
496
+
497
+ /**
498
+ *
499
+ * @param string $section
500
+ * @return boolean
501
+ */
502
+ public function haveSection($section)
503
+ {
504
+ foreach ($this->finalReporNotices as $notice) {
505
+ if (in_array($section, $notice->sections)) {
506
+ return true;
507
+ }
508
+ }
509
+ return false;
510
+ }
511
+
512
+ /**
513
+ *
514
+ * @param null|string $section if null is a global result
515
+ *
516
+ * @return int // returns the worst level found
517
+ *
518
+ */
519
+ public function getSectionErrLevel($section = null)
520
+ {
521
+ $result = DUPX_NOTICE_ITEM::INFO;
522
+
523
+ foreach ($this->finalReporNotices as $notice) {
524
+ if (is_null($section) || in_array($section, $notice->sections)) {
525
+ $result = max($result, $notice->level);
526
+ }
527
+ }
528
+ return $result;
529
+ }
530
+
531
+ /**
532
+ *
533
+ * @param string $section
534
+ * @param bool $echo
535
+ * @return void|string
536
+ */
537
+ public function getSectionErrLevelHtml($section = null, $echo = true)
538
+ {
539
+ return self::getErrorLevelHtml($this->getSectionErrLevel($section), $echo);
540
+ }
541
+
542
+ /**
543
+ * Displa next step notice message
544
+ *
545
+ * @param bool $deleteListAfterDisaply
546
+ * @return void
547
+ */
548
+ public function displayStepMessages($deleteListAfterDisaply = true)
549
+ {
550
+ if (empty($this->nextStepNotices)) {
551
+ return;
552
+ }
553
+ ?>
554
+ <div id="step-messages">
555
+ <?php
556
+ foreach ($this->nextStepNotices as $notice) {
557
+ self::stepMsg($notice);
558
+ }
559
+ ?>
560
+ </div>
561
+ <?php
562
+ if ($deleteListAfterDisaply) {
563
+ $this->nextStepNotices = array();
564
+ $this->saveNotices();
565
+ }
566
+ }
567
+
568
+ /**
569
+ *
570
+ * @param DUPX_NOTICE_ITEM $notice
571
+ */
572
+ private static function stepMsg($notice)
573
+ {
574
+ $classes = array(
575
+ 'notice',
576
+ 'next-step',
577
+ self::getClassFromLevel($notice->level)
578
+ );
579
+ $haveContent = !empty($notice->faqLink) || !empty($notice->longMsg);
580
+ ?>
581
+ <div class="<?php echo implode(' ', $classes); ?>">
582
+ <div class="title">
583
+ <?php echo self::getNextStepLevelPrefixMessage($notice->level).': <b>'.htmlentities($notice->shortMsg).'</b>'; ?>
584
+ </div>
585
+ <?php if ($haveContent) { ?>
586
+ <div class="title-separator" ></div>
587
+ <?php
588
+ ob_start();
589
+ if (!empty($notice->faqLink)) {
590
+ ?>
591
+ See FAQ: <a href="<?php echo $notice->faqLink['url']; ?>" >
592
+ <b><?php echo htmlentities(empty($notice->faqLink['label']) ? $notice->faqLink['url'] : $notice->faqLink['label']); ?></b>
593
+ </a>
594
+ <?php
595
+ }
596
+ if (!empty($notice->faqLink) && !empty($notice->longMsg)) {
597
+ echo '<br><br>';
598
+ }
599
+ if (!empty($notice->longMsg)) {
600
+ switch ($notice->longMsgMode) {
601
+ case DUPX_NOTICE_ITEM::MSG_MODE_PRE:
602
+ echo '<pre>'.htmlentities($notice->longMsg).'</pre>';
603
+ break;
604
+ case DUPX_NOTICE_ITEM::MSG_MODE_HTML:
605
+ echo $notice->longMsg;
606
+ break;
607
+ case DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT:
608
+ default:
609
+ echo htmlentities($notice->longMsg);
610
+ }
611
+ }
612
+ $longContent = ob_get_clean();
613
+ DUPX_U_Html::getMoreContent($longContent, 'info', 200);
614
+ }
615
+ ?>
616
+ </div>
617
+ <?php
618
+ }
619
+
620
+ /**
621
+ *
622
+ * @param string $id
623
+ * @param DUPX_NOTICE_ITEM $notice
624
+ */
625
+ private static function finalReportNotice($id, $notice)
626
+ {
627
+ $classes = array(
628
+ 'notice-report',
629
+ 'notice',
630
+ self::getClassFromLevel($notice->level)
631
+ );
632
+ $haveContent = !empty($notice->faqLink) || !empty($notice->longMsg);
633
+ $contentId = 'notice-content-'.$id;
634
+ $iconClasses = $haveContent ? 'fa fa-caret-right' : 'fa fa-toggle-empty';
635
+ $toggleLinkData = $haveContent ? 'data-type="toggle" data-target="#'.$contentId.'"' : '';
636
+ ?>
637
+ <div class="<?php echo implode(' ', $classes); ?>">
638
+ <div class="title" <?php echo $toggleLinkData; ?>>
639
+ <i class="<?php echo $iconClasses; ?>"></i> <?php echo htmlentities($notice->shortMsg); ?>
640
+ </div>
641
+ <?php
642
+ if ($haveContent) {
643
+ $infoClasses = array('info');
644
+ if (!$notice->open) {
645
+ $infoClasses[] = 'no-display';
646
+ }
647
+ ?>
648
+ <div id="<?php echo $contentId; ?>" class="<?php echo implode(' ', $infoClasses); ?>" >
649
+ <?php
650
+ if (!empty($notice->faqLink)) {
651
+ ?>
652
+ <b>See FAQ</b>: <a href="<?php echo $notice->faqLink['url']; ?>" >
653
+ <?php echo htmlentities(empty($notice->faqLink['label']) ? $notice->faqLink['url'] : $notice->faqLink['label']); ?>
654
+ </a>
655
+ <?php
656
+ }
657
+ if (!empty($notice->faqLink) && !empty($notice->longMsg)) {
658
+ echo '<br><br>';
659
+ }
660
+ if (!empty($notice->longMsg)) {
661
+ switch ($notice->longMsgMode) {
662
+ case DUPX_NOTICE_ITEM::MSG_MODE_PRE:
663
+ echo '<pre>'.htmlentities($notice->longMsg).'</pre>';
664
+ break;
665
+ case DUPX_NOTICE_ITEM::MSG_MODE_HTML:
666
+ echo $notice->longMsg;
667
+ break;
668
+ case DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT:
669
+ default:
670
+ echo htmlentities($notice->longMsg);
671
+ }
672
+ }
673
+ ?>
674
+ </div>
675
+ <?php
676
+ }
677
+ ?>
678
+ </div>
679
+ <?php
680
+ }
681
+
682
+ /**
683
+ *
684
+ * @param DUPX_NOTICE_ITEM $notice
685
+ */
686
+ private static function noticeToText($notice)
687
+ {
688
+ $result = '-----------------------'."\n".
689
+ '['.self::getNextStepLevelPrefixMessage($notice->level, false).'] '.$notice->shortMsg;
690
+
691
+ if (!empty($notice->sections)) {
692
+ $result .= "\n\t".'SECTIONS: '.implode(',', $notice->sections);
693
+ }
694
+ if (!empty($notice->longMsg)) {
695
+ $result .= "\n\t".'LONG MSG: '.$notice->longMsg;
696
+ }
697
+ return $result."\n";
698
+ }
699
+
700
+ public function nextStepLog()
701
+ {
702
+ if (!empty($this->nextStepNotices)) {
703
+ DUPX_Log::info(
704
+ '===================================='."\n".
705
+ 'NEXT STEP NOTICES'."\n".
706
+ '====================================');
707
+ foreach ($this->nextStepNotices as $notice) {
708
+ DUPX_Log::info(self::noticeToText($notice));
709
+ }
710
+ DUPX_Log::info(
711
+ '====================================');
712
+ }
713
+ }
714
+
715
+ public function finalReportLog($sections = array())
716
+ {
717
+ if (!empty($this->finalReporNotices)) {
718
+ DUPX_Log::info(
719
+ '===================================='."\n".
720
+ 'FINAL REPORT NOTICES LIST'."\n".
721
+ '====================================');
722
+ foreach ($this->finalReporNotices as $notice) {
723
+ if (count(array_intersect($notice->sections, $sections)) > 0) {
724
+ DUPX_Log::info(self::noticeToText($notice));
725
+ }
726
+ }
727
+ DUPX_Log::info(
728
+ '====================================');
729
+ }
730
+ }
731
+
732
+ /**
733
+ * get html class from level
734
+ *
735
+ * @param int $level
736
+ * @return string
737
+ */
738
+ private static function getClassFromLevel($level)
739
+ {
740
+ switch ($level) {
741
+ case DUPX_NOTICE_ITEM::INFO:
742
+ return 'l-info';
743
+ case DUPX_NOTICE_ITEM::NOTICE:
744
+ return 'l-notice';
745
+ case DUPX_NOTICE_ITEM::SOFT_WARNING:
746
+ return 'l-swarning';
747
+ case DUPX_NOTICE_ITEM::HARD_WARNING:
748
+ return 'l-hwarning';
749
+ case DUPX_NOTICE_ITEM::CRITICAL:
750
+ return 'l-critical';
751
+ case DUPX_NOTICE_ITEM::FATAL:
752
+ return 'l-fatal';
753
+ }
754
+ }
755
+
756
+ /**
757
+ * get level label from level
758
+ *
759
+ * @param int $level
760
+ * @param bool $echo
761
+ * @return type
762
+ */
763
+ public static function getErrorLevelHtml($level, $echo = true)
764
+ {
765
+ switch ($level) {
766
+ case DUPX_NOTICE_ITEM::INFO:
767
+ $label = 'good';
768
+ break;
769
+ case DUPX_NOTICE_ITEM::NOTICE:
770
+ $label = 'good';
771
+ break;
772
+ case DUPX_NOTICE_ITEM::SOFT_WARNING:
773
+ $label = 'warning';
774
+ break;
775
+ case DUPX_NOTICE_ITEM::HARD_WARNING:
776
+ $label = 'warning';
777
+ break;
778
+ case DUPX_NOTICE_ITEM::CRITICAL:
779
+ $label = 'critical error';
780
+ break;
781
+ case DUPX_NOTICE_ITEM::FATAL:
782
+ $label = 'fatal error';
783
+ break;
784
+ default:
785
+ return;
786
+ }
787
+ $classes = self::getClassFromLevel($level);
788
+ ob_start();
789
+ ?>
790
+ <span class="notice-level-status <?php echo $classes; ?>"><?php echo $label; ?></span>
791
+ <?php
792
+ if ($echo) {
793
+ ob_end_flush();
794
+ } else {
795
+ return ob_get_clean();
796
+ }
797
+ }
798
+
799
+ /**
800
+ * get next step message prefix
801
+ *
802
+ * @param int $level
803
+ * @param bool $echo
804
+ * @return string
805
+ */
806
+ public static function getNextStepLevelPrefixMessage($level, $echo = true)
807
+ {
808
+ switch ($level) {
809
+ case DUPX_NOTICE_ITEM::INFO:
810
+ $label = 'INFO';
811
+ break;
812
+ case DUPX_NOTICE_ITEM::NOTICE:
813
+ $label = 'NOTICE';
814
+ break;
815
+ case DUPX_NOTICE_ITEM::SOFT_WARNING:
816
+ $label = 'WARNING';
817
+ break;
818
+ case DUPX_NOTICE_ITEM::HARD_WARNING:
819
+ $label = 'WARNING';
820
+ break;
821
+ case DUPX_NOTICE_ITEM::CRITICAL:
822
+ $label = 'CRITICAL ERROR';
823
+ break;
824
+ case DUPX_NOTICE_ITEM::FATAL:
825
+ $label = 'FATAL ERROR';
826
+ break;
827
+ default:
828
+ return;
829
+ }
830
+
831
+ if ($echo) {
832
+ echo $label;
833
+ } else {
834
+ return $label;
835
+ }
836
+ }
837
+
838
+ /**
839
+ * get unique id
840
+ *
841
+ * @return string
842
+ */
843
+ private static function getNewAutoUniqueId()
844
+ {
845
+ self::$uniqueCountId ++;
846
+ return self::DEFAULT_UNIQUE_ID_PREFIX.self::$uniqueCountId;
847
+ }
848
+
849
+ /**
850
+ * function for internal test
851
+ *
852
+ * display all messages levels
853
+ */
854
+ public static function testNextStepMessaesLevels()
855
+ {
856
+ $manager = self::getInstance();
857
+ $manager->addNextStepNoticeMessage('Level info ('.DUPX_NOTICE_ITEM::INFO.')', DUPX_NOTICE_ITEM::INFO);
858
+ $manager->addNextStepNoticeMessage('Level notice ('.DUPX_NOTICE_ITEM::NOTICE.')', DUPX_NOTICE_ITEM::NOTICE);
859
+ $manager->addNextStepNoticeMessage('Level soft warning ('.DUPX_NOTICE_ITEM::SOFT_WARNING.')', DUPX_NOTICE_ITEM::SOFT_WARNING);
860
+ $manager->addNextStepNoticeMessage('Level hard warning ('.DUPX_NOTICE_ITEM::HARD_WARNING.')', DUPX_NOTICE_ITEM::HARD_WARNING);
861
+ $manager->addNextStepNoticeMessage('Level critical error ('.DUPX_NOTICE_ITEM::CRITICAL.')', DUPX_NOTICE_ITEM::CRITICAL);
862
+ $manager->addNextStepNoticeMessage('Level fatal error ('.DUPX_NOTICE_ITEM::FATAL.')', DUPX_NOTICE_ITEM::FATAL);
863
+ $manager->saveNotices();
864
+ }
865
+
866
+ /**
867
+ * test function
868
+ */
869
+ public static function testNextStepFullMessageData()
870
+ {
871
+ $manager = self::getInstance();
872
+ $longMsg = <<<LONGMSG
873
+ <b>Formattend long text</b><br>
874
+ <ul>
875
+ <li>Proin dapibus mi eu erat pulvinar, id congue nisl egestas.</li>
876
+ <li>Nunc venenatis eros et sapien ornare consequat.</li>
877
+ <li>Mauris tincidunt est sit amet turpis placerat, a tristique dui porttitor.</li>
878
+ <li>Etiam volutpat lectus quis risus molestie faucibus.</li>
879
+ <li>Integer gravida eros sit amet sem viverra, a volutpat neque rutrum.</li>
880
+ <li>Aenean varius ipsum vitae lorem tempus rhoncus.</li>
881
+ </ul>
882
+ LONGMSG;
883
+ $manager->addNextStepNotice(array(
884
+ 'shortMsg' => 'Full elements next step message MODE HTML',
885
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
886
+ 'longMsg' => $longMsg,
887
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
888
+ 'faqLink' => array(
889
+ 'url' => 'http://www.google.it',
890
+ 'label' => 'google link'
891
+ )
892
+ ));
893
+
894
+ $longMsg = <<<LONGMSG
895
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc a auctor erat, et lobortis libero.
896
+ Suspendisse aliquet neque in massa posuere mollis. Donec venenatis finibus sapien in bibendum. Donec et ex massa.
897
+
898
+ Aliquam venenatis dapibus tellus nec ullamcorper. Mauris ante velit, tincidunt sit amet egestas et, mattis non lorem. In semper ex ut velit suscipit,
899
+ at luctus nunc dapibus. Etiam blandit maximus dapibus. Nullam eu porttitor augue. Suspendisse pulvinar, massa eget condimentum aliquet, dolor massa tempus dui, vel rhoncus tellus ligula non odio.
900
+ Ut ac faucibus tellus, in lobortis odio.
901
+ LONGMSG;
902
+ $manager->addNextStepNotice(array(
903
+ 'shortMsg' => 'Full elements next step message MODE PRE',
904
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
905
+ 'longMsg' => $longMsg,
906
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_PRE,
907
+ 'faqLink' => array(
908
+ 'url' => 'http://www.google.it',
909
+ 'label' => 'google link'
910
+ )
911
+ ));
912
+
913
+ $longMsg = <<<LONGMSG
914
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc a auctor erat, et lobortis libero.
915
+ Suspendisse aliquet neque in massa posuere mollis. Donec venenatis finibus sapien in bibendum. Donec et ex massa.
916
+
917
+ Aliquam venenatis dapibus tellus nec ullamcorper. Mauris ante velit, tincidunt sit amet egestas et, mattis non lorem. In semper ex ut velit suscipit,
918
+ at luctus nunc dapibus. Etiam blandit maximus dapibus. Nullam eu porttitor augue. Suspendisse pulvinar, massa eget condimentum aliquet, dolor massa tempus dui, vel rhoncus tellus ligula non odio.
919
+ Ut ac faucibus tellus, in lobortis odio.
920
+ LONGMSG;
921
+ $manager->addNextStepNotice(array(
922
+ 'shortMsg' => 'Full elements next step message MODE DEFAULT',
923
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
924
+ 'longMsg' => $longMsg,
925
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
926
+ 'faqLink' => array(
927
+ 'url' => 'http://www.google.it',
928
+ 'label' => 'google link'
929
+ )
930
+ ));
931
+
932
+
933
+ $longMsg = <<<LONGMSG
934
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam cursus porttitor consectetur. Nunc faucibus elementum nisl nec ornare. Phasellus sit amet urna in diam ultricies ornare nec sit amet nibh. Nulla a aliquet leo. Quisque aliquet posuere lectus sit amet commodo. Nullam tempus enim eget urna rutrum egestas. Aliquam eget lorem nisl. Nulla tincidunt massa erat. Phasellus lectus tellus, mollis sit amet aliquam in, dapibus quis metus. Nunc venenatis nulla vitae convallis accumsan.
935
+
936
+ Mauris eu ullamcorper metus. Aenean ultricies et turpis eget mollis. Aliquam auctor, elit scelerisque placerat pellentesque, quam augue fermentum lectus, vel pretium nisi justo sit amet ante. Donec blandit porttitor tempus. Duis vulputate nulla ut orci rutrum, et consectetur urna mollis. Sed at iaculis velit. Pellentesque id quam turpis. Curabitur eu ligula velit. Cras gravida, ipsum sed iaculis eleifend, mauris nunc posuere quam, vel blandit nisi justo congue ligula. Phasellus aliquam eu odio ac porttitor. Fusce dictum mollis turpis sit amet fringilla.
937
+
938
+ Nulla eu ligula mauris. Fusce lobortis ligula elit, a interdum nibh pulvinar eu. Pellentesque rhoncus nec turpis id blandit. Morbi fringilla, justo non varius consequat, arcu ante efficitur ante, sit amet cursus lorem elit vel odio. Phasellus neque ligula, vehicula vel ipsum sed, volutpat dignissim eros. Curabitur at lacus id felis elementum auctor. Nullam ac tempus nisi. Phasellus nibh purus, aliquam nec purus ut, sodales lobortis nulla. Cras viverra dictum magna, ac malesuada nibh dictum ac. Mauris euismod, magna sit amet pretium posuere, ligula nibh ultrices tellus, sit amet pretium odio urna egestas justo. Suspendisse purus erat, eleifend sed magna in, efficitur interdum nibh.
939
+
940
+ Vivamus nibh nunc, fermentum non tortor volutpat, consectetur vulputate velit. Phasellus lobortis, purus et faucibus mollis, metus eros viverra ante, sit amet euismod nibh est eu orci. Duis sodales cursus lacinia. Praesent laoreet ut ipsum ut interdum. Praesent venenatis massa vitae ligula consequat aliquet. Fusce in purus in odio molestie laoreet at ac augue. Fusce consectetur elit a magna mollis aliquet.
941
+
942
+ Nulla eros nisi, dapibus eget diam vitae, tincidunt blandit odio. Fusce interdum tellus nec varius condimentum. Fusce non magna a purus sodales imperdiet sit amet vitae ligula. Quisque viverra leo sit amet mi egestas, et posuere nunc tincidunt. Suspendisse feugiat malesuada urna sed tincidunt. Morbi a urna sed magna volutpat pellentesque sit amet ac mauris. Nulla sed ultrices dui. Etiam massa arcu, tempor ut erat at, cursus malesuada ipsum. Duis sit amet felis dolor.
943
+
944
+ Morbi gravida nisl nunc, vulputate iaculis risus vehicula non. Proin cursus, velit et laoreet consectetur, lacus libero sagittis lacus, quis accumsan odio lectus non erat. Aenean dolor lectus, euismod sit amet justo eget, dictum gravida nisl. Phasellus sed nunc non odio ullamcorper rhoncus non ut ipsum. Duis ante ligula, pellentesque sit amet imperdiet eget, congue vel dui. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla facilisi. Suspendisse luctus leo eget justo mollis, convallis convallis ex suscipit. Integer et justo eget odio lobortis sollicitudin. Pellentesque accumsan rhoncus augue, luctus suscipit ex accumsan nec. Maecenas lacinia consectetur risus at bibendum. Etiam venenatis purus lorem, sit amet elementum turpis tristique eu. Proin vulputate faucibus feugiat. Nunc vehicula congue odio consequat vulputate. Quisque bibendum augue id iaculis faucibus. Donec blandit cursus sem, eget accumsan orci commodo sed.
945
+
946
+ Suspendisse iaculis est quam, sed scelerisque purus tincidunt non. Cras hendrerit ante turpis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse purus ipsum, rutrum id sem in, venenatis laoreet metus. Aliquam ac bibendum mauris. Cras egestas rhoncus est, sed lacinia nibh vestibulum id. Proin diam quam, sagittis congue molestie ac, rhoncus et mauris. Phasellus massa neque, ornare vel erat a, rutrum pharetra arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi et nulla eget massa auctor fermentum. Quisque maximus tellus sed cursus cursus. Ut vehicula erat at purus aliquet, quis imperdiet dui sagittis. Nullam eget quam leo.
947
+
948
+ Nulla magna ipsum, congue nec dui ut, lacinia malesuada felis. Cras mattis metus non maximus venenatis. Aliquam euismod est vitae erat sollicitudin, at pellentesque augue sollicitudin. Curabitur euismod maximus cursus. In tortor dui, convallis sed sapien ac, varius congue metus. Nunc ullamcorper ac orci sit amet finibus. Vivamus molestie nibh vitae quam rhoncus, eu ultrices est molestie. Maecenas consectetur eu quam sit amet placerat.
949
+
950
+ Curabitur ut fermentum mauris. Donec et congue nibh. Sed cursus elit sit amet convallis varius. Donec malesuada porta odio condimentum varius. Pellentesque ornare tempor ante, ut volutpat nulla lobortis sed. Nunc congue aliquet erat ac elementum. Quisque a ex sit amet turpis placerat sagittis eget ac ligula. Etiam in augue malesuada, aliquam est non, lacinia justo. Vivamus tincidunt dolor orci, id dignissim lorem maximus at. Vivamus ligula mauris, venenatis vel nibh id, lacinia ultrices ipsum. Mauris cursus, urna ac rutrum aliquet, risus ipsum tincidunt purus, sit amet blandit nunc sem sit amet nibh.
951
+
952
+ Nam eleifend risus lacus, eu pharetra risus egestas eu. Maecenas hendrerit nisl in semper placerat. Vestibulum massa tellus, laoreet non euismod quis, sollicitudin id sapien. Morbi vel cursus metus. Aenean tincidunt nisi est, ut elementum est auctor id. Duis auctor elit leo, ac scelerisque risus suscipit et. Pellentesque lectus nisi, ultricies in elit sed, pulvinar iaculis massa. Morbi viverra eros mi, pretium facilisis neque egestas id. Curabitur non massa accumsan, porttitor sem vitae, ultricies lacus. Curabitur blandit nisl velit. Mauris sollicitudin ultricies purus sit amet placerat. Fusce ac neque sed leo venenatis laoreet ut non ex. Integer elementum rhoncus orci, eu maximus neque tempus eu. Curabitur euismod dignissim tellus, vitae lacinia metus. Mauris imperdiet metus vitae vulputate accumsan. Duis eget luctus nibh, sit amet finibus libero.
953
+
954
+ LONGMSG;
955
+ $manager->addNextStepNotice(array(
956
+ 'shortMsg' => 'Full elements LONG LONG',
957
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
958
+ 'longMsg' => $longMsg,
959
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_DEFAULT,
960
+ 'faqLink' => array(
961
+ 'url' => 'http://www.google.it',
962
+ 'label' => 'google link'
963
+ )
964
+ ));
965
+
966
+
967
+
968
+
969
+ $manager->saveNotices();
970
+ }
971
+
972
+ /**
973
+ * test function
974
+ */
975
+ public static function testFinalReporMessaesLevels()
976
+ {
977
+ $section = 'general';
978
+
979
+ $manager = self::getInstance();
980
+ $manager->addFinalReportNoticeMessage('Level info ('.DUPX_NOTICE_ITEM::INFO.')', $section, DUPX_NOTICE_ITEM::INFO, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_0');
981
+ $manager->addFinalReportNoticeMessage('Level notice ('.DUPX_NOTICE_ITEM::NOTICE.')', $section, DUPX_NOTICE_ITEM::NOTICE, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_1');
982
+ $manager->addFinalReportNoticeMessage('Level soft warning ('.DUPX_NOTICE_ITEM::SOFT_WARNING.')', $section, DUPX_NOTICE_ITEM::SOFT_WARNING, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_2');
983
+ $manager->addFinalReportNoticeMessage('Level hard warning ('.DUPX_NOTICE_ITEM::HARD_WARNING.')', $section, DUPX_NOTICE_ITEM::HARD_WARNING, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_3');
984
+ $manager->addFinalReportNoticeMessage('Level critical error ('.DUPX_NOTICE_ITEM::CRITICAL.')', $section, DUPX_NOTICE_ITEM::CRITICAL, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_4');
985
+ $manager->addFinalReportNoticeMessage('Level fatal error ('.DUPX_NOTICE_ITEM::FATAL.')', $section, DUPX_NOTICE_ITEM::FATAL, DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_5');
986
+ $manager->saveNotices();
987
+ }
988
+
989
+ /**
990
+ * test function
991
+ */
992
+ public static function testFinalReportFullMessages()
993
+ {
994
+ $section = 'general';
995
+ $manager = self::getInstance();
996
+
997
+ $longMsg = <<<LONGMSG
998
+ <b>Formattend long text</b><br>
999
+ <ul>
1000
+ <li>Proin dapibus mi eu erat pulvinar, id congue nisl egestas.</li>
1001
+ <li>Nunc venenatis eros et sapien ornare consequat.</li>
1002
+ <li>Mauris tincidunt est sit amet turpis placerat, a tristique dui porttitor.</li>
1003
+ <li>Etiam volutpat lectus quis risus molestie faucibus.</li>
1004
+ <li>Integer gravida eros sit amet sem viverra, a volutpat neque rutrum.</li>
1005
+ <li>Aenean varius ipsum vitae lorem tempus rhoncus.</li>
1006
+ </ul>
1007
+ LONGMSG;
1008
+
1009
+ $manager->addFinalReportNotice(array(
1010
+ 'shortMsg' => 'Full elements final report message',
1011
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
1012
+ 'longMsg' => $longMsg,
1013
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
1014
+ 'sections' => $section,
1015
+ 'faqLink' => array(
1016
+ 'url' => 'http://www.google.it',
1017
+ 'label' => 'google link'
1018
+ )
1019
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_full_1');
1020
+
1021
+ $manager->addFinalReportNotice(array(
1022
+ 'shortMsg' => 'Full elements final report message info high priority',
1023
+ 'level' => DUPX_NOTICE_ITEM::INFO,
1024
+ 'longMsg' => $longMsg,
1025
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
1026
+ 'sections' => $section,
1027
+ 'faqLink' => array(
1028
+ 'url' => 'http://www.google.it',
1029
+ 'label' => 'google link'
1030
+ ),
1031
+ 'priority' => 5
1032
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE, 'test_fr_full_2');
1033
+ $manager->saveNotices();
1034
+ }
1035
+
1036
+ //PHP 8 Requires method to be public
1037
+ public function __wakeup()
1038
+ {
1039
+ }
1040
+
1041
+ private function __clone()
1042
+ {
1043
+
1044
+ }
1045
+ }
1046
+
1047
+ class DUPX_NOTICE_ITEM
1048
+ {
1049
+ const INFO = 0;
1050
+ const NOTICE = 1;
1051
+ const SOFT_WARNING = 2;
1052
+ const HARD_WARNING = 3;
1053
+ const CRITICAL = 4;
1054
+ const FATAL = 5;
1055
+ const MSG_MODE_DEFAULT = 'def';
1056
+ const MSG_MODE_HTML = 'html';
1057
+ const MSG_MODE_PRE = 'pre';
1058
+
1059
+ /**
1060
+ *
1061
+ * @var string text
1062
+ */
1063
+ public $shortMsg = '';
1064
+
1065
+ /**
1066
+ *
1067
+ * @var string html text
1068
+ */
1069
+ public $longMsg = '';
1070
+
1071
+ /**
1072
+ *
1073
+ * @var bool if true long msg can be html
1074
+ */
1075
+ public $longMsgMode = self::MSG_MODE_DEFAULT;
1076
+
1077
+ /**
1078
+ *
1079
+ * @var null|array // null = no faq link
1080
+ * array( 'label' => link text , 'url' => faq url)
1081
+ */
1082
+ public $faqLink = array(
1083
+ 'label' => '',
1084
+ 'url' => ''
1085
+ );
1086
+
1087
+ /**
1088
+ *
1089
+ * @var string[] notice sections for final report only
1090
+ */
1091
+ public $sections = array();
1092
+
1093
+ /**
1094
+ *
1095
+ * @var int
1096
+ */
1097
+ public $level = self::NOTICE;
1098
+
1099
+ /**
1100
+ *
1101
+ * @var int
1102
+ */
1103
+ public $priority = 10;
1104
+
1105
+ /**
1106
+ *
1107
+ * @var bool if true notice start open. For final report only
1108
+ */
1109
+ public $open = false;
1110
+
1111
+ /**
1112
+ *
1113
+ * @param string $shortMsg text
1114
+ * @param int $level
1115
+ * @param string $longMsg html text
1116
+ * @param string|string[] $sections
1117
+ * @param null|array $faqLink [
1118
+ * 'url' => external link
1119
+ * 'label' => link text if empty get external url link
1120
+ * ]
1121
+ * @param int priority
1122
+ * @param bool open
1123
+ * @param string longMsgMode MSG_MODE_DEFAULT | MSG_MODE_HTML | MSG_MODE_PRE
1124
+ */
1125
+ public function __construct($shortMsg, $level = self::INFO, $longMsg = '', $sections = array(), $faqLink = null, $priority = 10, $open = false, $longMsgMode = self::MSG_MODE_DEFAULT)
1126
+ {
1127
+ $this->shortMsg = (string) $shortMsg;
1128
+ $this->level = (int) $level;
1129
+ $this->longMsg = (string) $longMsg;
1130
+ $this->sections = is_array($sections) ? $sections : array($sections);
1131
+ $this->faqLink = $faqLink;
1132
+ $this->priority = $priority;
1133
+ $this->open = $open;
1134
+ $this->longMsgMode = $longMsgMode;
1135
+ }
1136
+
1137
+ /**
1138
+ *
1139
+ * @return array [
1140
+ * 'shortMsg' => text,
1141
+ * 'level' => level,
1142
+ * 'longMsg' => html text,
1143
+ * 'sections' => string|string[],
1144
+ * 'faqLink' => [
1145
+ * 'url' => external link
1146
+ * 'label' => link text if empty get external url link
1147
+ * ]
1148
+ * 'priority' => int low first
1149
+ * 'open' => if true the tab is opene on final report
1150
+ * 'longMsgMode'=> MSG_MODE_DEFAULT | MSG_MODE_HTML | MSG_MODE_PRE
1151
+ * ]
1152
+ */
1153
+ public function toArray()
1154
+ {
1155
+ return array(
1156
+ 'shortMsg' => $this->shortMsg,
1157
+ 'level' => $this->level,
1158
+ 'longMsg' => $this->longMsg,
1159
+ 'sections' => $this->sections,
1160
+ 'faqLink' => $this->faqLink,
1161
+ 'priority' => $this->priority,
1162
+ 'open' => $this->open,
1163
+ 'longMsgMode' => $this->longMsgMode
1164
+ );
1165
+ }
1166
+
1167
+ /**
1168
+ *
1169
+ * @return array [
1170
+ * 'shortMsg' => text,
1171
+ * 'level' => level,
1172
+ * 'longMsg' => html text,
1173
+ * 'sections' => string|string[],
1174
+ * 'faqLink' => [
1175
+ * 'url' => external link
1176
+ * 'label' => link text if empty get external url link
1177
+ * ],
1178
+ * priority
1179
+ * open
1180
+ * longMsgMode
1181
+ * ]
1182
+ * @return DUPX_NOTICE_ITEM
1183
+ */
1184
+ public static function getItemFromArray($array)
1185
+ {
1186
+ if (isset($array['sections']) && !is_array($array['sections'])) {
1187
+ if (empty($array['sections'])) {
1188
+ $array['sections'] = array();
1189
+ } else {
1190
+ $array['sections'] = array($array['sections']);
1191
+ }
1192
+ }
1193
+ $params = array_merge(self::getDefaultArrayParams(), $array);
1194
+ $result = new self($params['shortMsg'], $params['level'], $params['longMsg'], $params['sections'], $params['faqLink'], $params['priority'], $params['open'], $params['longMsgMode']);
1195
+ return $result;
1196
+ }
1197
+
1198
+ /**
1199
+ *
1200
+ * @return array [
1201
+ * 'shortMsg' => text,
1202
+ * 'level' => level,
1203
+ * 'longMsg' => html text,
1204
+ * 'sections' => string|string[],
1205
+ * 'faqLink' => [
1206
+ * 'url' => external link
1207
+ * 'label' => link text if empty get external url link
1208
+ * ],
1209
+ * priority
1210
+ * open
1211
+ * longMsgMode
1212
+ * ]
1213
+ */
1214
+ public static function getDefaultArrayParams()
1215
+ {
1216
+ return array(
1217
+ 'shortMsg' => '',
1218
+ 'level' => self::INFO,
1219
+ 'longMsg' => '',
1220
+ 'sections' => array(),
1221
+ 'faqLink' => null,
1222
+ 'priority' => 10,
1223
+ 'open' => false,
1224
+ 'longMsgMode' => self::MSG_MODE_DEFAULT
1225
+ );
1226
+ }
1227
+
1228
+ /**
1229
+ * before lower priority
1230
+ * before highest level
1231
+ *
1232
+ * @param DUPX_NOTICE_ITEM $a
1233
+ * @param DUPX_NOTICE_ITEM $b
1234
+ */
1235
+ public static function sortNoticeForPriorityAndLevel($a, $b)
1236
+ {
1237
+ if ($a->priority == $b->priority) {
1238
+ if ($a->level == $b->level) {
1239
+ return 0;
1240
+ } else if ($a->level < $b->level) {
1241
+ return 1;
1242
+ } else {
1243
+ return -1;
1244
+ }
1245
+ } else if ($a->priority < $b->priority) {
1246
+ return -1;
1247
+ } else {
1248
+ return 1;
1249
+ }
1250
+ }
 
1251
  }
installer/dup-installer/classes/utilities/class.u.php CHANGED
@@ -1671,7 +1671,7 @@ class DUPX_U
1671
  /**
1672
  * Test if a given path is a stream URL
1673
  *
1674
- * from wordpress function wp_is_stream
1675
  *
1676
  * @param string $path The resource path or URL.
1677
  * @return bool True if the path is a stream URL.
@@ -1689,6 +1689,36 @@ class DUPX_U
1689
 
1690
  return in_array($stream, stream_get_wrappers(), true);
1691
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1692
 
1693
  /**
1694
  * Check if string is base64 encoded
1671
  /**
1672
  * Test if a given path is a stream URL
1673
  *
1674
+ * from WordPress function wp_is_stream
1675
  *
1676
  * @param string $path The resource path or URL.
1677
  * @return bool True if the path is a stream URL.
1689
 
1690
  return in_array($stream, stream_get_wrappers(), true);
1691
  }
1692
+
1693
+ /**
1694
+ * Toggle maintenance mode for the site.
1695
+ *
1696
+ * Creates/deletes the maintenance file to enable/disable maintenance mode.
1697
+ *
1698
+ * @param bool $enable True to enable maintenance mode, false to disable.
1699
+ */
1700
+ public static function maintenanceMode($enable = false)
1701
+ {
1702
+ $pathNew = DupLiteSnapLibIOU::safePathUntrailingslashit($GLOBALS['DUPX_ROOT']);
1703
+ if (!is_writable($pathNew)) {
1704
+ DUPX_Log::info('CAN\'T SET/REMOVE MAINTENANCE MODE, ROOT FOLDER NOT WRITABLE');
1705
+ return;
1706
+ }
1707
+
1708
+ $file = $pathNew.'/.maintenance';
1709
+ if ($enable) {
1710
+ DUPX_Log::info('MAINTENANCE MODE ENABLE');
1711
+ // Create maintenance file to signal that we are upgrading
1712
+ $maintenanceString = '<?php $upgrading = '.time().'; ?>';
1713
+ if (file_exists($file)) {
1714
+ @unlink($file);
1715
+ }
1716
+ file_put_contents($file, $maintenanceString);
1717
+ } else if (!$enable && file_exists($file)) {
1718
+ DUPX_Log::info('MAINTENANCE MODE DISABLE');
1719
+ unlink($file);
1720
+ }
1721
+ }
1722
 
1723
  /**
1724
  * Check if string is base64 encoded
installer/dup-installer/classes/utilities/class.u.search.reaplce.manager.php CHANGED
@@ -252,15 +252,16 @@ final class DUPX_S_R_MANAGER
252
  return $result;
253
  }
254
 
255
- private function __clone()
 
256
  {
257
-
258
  }
259
 
260
- private function __wakeup()
261
  {
262
 
263
  }
 
264
  }
265
 
266
  /**
252
  return $result;
253
  }
254
 
255
+ //PHP 8 Requires method to be public
256
+ public function __wakeup()
257
  {
 
258
  }
259
 
260
+ private function __clone()
261
  {
262
 
263
  }
264
+
265
  }
266
 
267
  /**
installer/dup-installer/ctrls/classes/class.ctrl.extraction.php ADDED
@@ -0,0 +1,606 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined("DUPXABSPATH") or die("");
3
+
4
+ class DUP_LITE_Extraction
5
+ {
6
+
7
+ const ACTION_DO_NOTHING = 'donothing';
8
+ const ACTION_REMOVE_ALL_FILES = 'removeall';
9
+ const ACTION_REMOVE_WP_FILES = 'removewpfiles';
10
+ const INPUT_NAME_ARCHIVE_ACTION = 'archive_action';
11
+
12
+ public $archive_action = self::ACTION_DO_NOTHING;
13
+
14
+ /**
15
+ *
16
+ * @var self
17
+ */
18
+ protected static $instance = null;
19
+
20
+ /**
21
+ *
22
+ * @return self
23
+ */
24
+ public static function getInstance()
25
+ {
26
+ if (is_null(self::$instance)) {
27
+ self::$instance = new self;
28
+ }
29
+ return self::$instance;
30
+ }
31
+
32
+ private function __construct()
33
+ {
34
+ $this->initData();
35
+ }
36
+
37
+ /**
38
+ * inizialize extraction data
39
+ */
40
+ public function initData()
41
+ {
42
+ if ($_POST['archive_engine'] == 'manual') {
43
+ $GLOBALS['DUPX_STATE']->isManualExtraction = true;
44
+ $GLOBALS['DUPX_STATE']->save();
45
+ }
46
+ }
47
+
48
+ /**
49
+ *
50
+ * @param string[] $folders
51
+ */
52
+ protected function removeFiles($folders = array())
53
+ {
54
+ $archive_path = $GLOBALS['FW_PACKAGE_PATH'];
55
+
56
+ $excludeFiles = array(
57
+ '/^'.preg_quote($archive_path, '/').'$/',
58
+ '/^'.preg_quote(DUPX_CSRF::getVal('bootLogFile'), '/').'$/',
59
+ '/^'.preg_quote(DUPX_CSRF::getVal('installerOrigPath'), '/').'$/',
60
+ '/^'.preg_quote($GLOBALS['DUPX_ROOT'].'/wp-config.php', '/').'$/'
61
+ );
62
+
63
+ $excludeFolders = array(
64
+ '/.+\/backups-dup-(lite|pro)$/',
65
+ '/^'.preg_quote($GLOBALS['DUPX_INIT'], '/').'$/'
66
+ );
67
+
68
+ foreach (DUPX_Server::getWpAddonsSiteLists() as $addonPath) {
69
+ $excludeFolders[] = '/^'.preg_quote($addonPath, '/').'$/';
70
+ }
71
+
72
+ foreach ($folders as $folder) {
73
+ DUPX_Log::info('REMOVE FOLDER '.DUPX_Log::varToString($folder));
74
+ DupLiteSnapLibIOU::regexGlobCallback($folder, function ($path) {
75
+
76
+ if (is_dir($path)) {
77
+ rmdir($path);
78
+ } else {
79
+ unlink($path);
80
+ }
81
+ }, array(
82
+ 'regexFile' => $excludeFiles,
83
+ 'regexFolder' => $excludeFolders,
84
+ 'checkFullPath' => true,
85
+ 'recursive' => true,
86
+ 'invert' => true,
87
+ 'childFirst' => true
88
+ ));
89
+ }
90
+ }
91
+
92
+ protected function removeWpFiles()
93
+ {
94
+ try {
95
+ DUPX_Log::info('REMOVE WP FILES');
96
+ DUPX_Log::resetTime(DUPX_Log::LV_DEFAULT, false);
97
+
98
+ $absDir = DupLiteSnapLibIOU::trailingslashit($GLOBALS['DUPX_ROOT']);
99
+ if (!is_dir($absDir) || !is_readable($absDir)) {
100
+ return false;
101
+ }
102
+
103
+ $removeFolders = array();
104
+
105
+ if (($dh = opendir($absDir))) {
106
+ while (($elem = readdir($dh)) !== false) {
107
+ if ($elem === '.' || $elem === '..') {
108
+ continue;
109
+ }
110
+
111
+ if (DupLiteSnapLibUtilWp::isWpCore($elem, DupLiteSnapLibUtilWp::PATH_RELATIVE)) {
112
+ $fullPath = $absDir.$elem;
113
+ if (is_dir($fullPath)) {
114
+ $removeFolders[] = $fullPath;
115
+ } else {
116
+ if (is_writable($fullPath)) {
117
+ unlink($fullPath);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ closedir($dh);
123
+ }
124
+
125
+ $this->removeFiles(array_unique($removeFolders));
126
+ DUPX_Log::logTime('FOLDERS REMOVED', DUPX_Log::LV_DEFAULT, false);
127
+ }
128
+ catch (Exception $e) {
129
+ DUPX_Log::logException($e);
130
+ }
131
+ catch (Error $e) {
132
+ DUPX_Log::logException($e);
133
+ }
134
+ }
135
+
136
+ /**
137
+ *
138
+ */
139
+ protected function removeAllFiles()
140
+ {
141
+ try {
142
+ DUPX_Log::info('REMOVE ALL FILES');
143
+ DUPX_Log::resetTime(DUPX_Log::LV_DEFAULT, false);
144
+ $this->removeFiles(array($GLOBALS['DUPX_ROOT']));
145
+ DUPX_Log::logTime('FOLDERS REMOVED', DUPX_Log::LV_DEFAULT, false);
146
+ }
147
+ catch (Exception $e) {
148
+ DUPX_Log::logException($e);
149
+ }
150
+ catch (Error $e) {
151
+ DUPX_Log::logException($e);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * preliminary actions before the extraction.
157
+ *
158
+ * @return void
159
+ */
160
+ protected function beforeExtraction()
161
+ {
162
+ DUPX_Log::info('BEFORE EXTRACION ACTIONS');
163
+
164
+ if (!$GLOBALS['DUPX_AC']->exportOnlyDB) {
165
+ switch ($_POST[self::INPUT_NAME_ARCHIVE_ACTION]) {
166
+ case self::ACTION_REMOVE_ALL_FILES:
167
+ $this->removeAllFiles();
168
+ break;
169
+ case self::ACTION_REMOVE_WP_FILES:
170
+ $this->removeWpFiles();
171
+ break;
172
+ case self::ACTION_DO_NOTHING:
173
+ break;
174
+ default:
175
+ throw new Exception('Invalid engine action '.$_POST[self::INPUT_NAME_ARCHIVE_ACTION]);
176
+ }
177
+ }
178
+ }
179
+
180
+ /**
181
+ *
182
+ * @throws Exception
183
+ */
184
+ public function runExtraction()
185
+ {
186
+ //OPTIONS
187
+ $_POST['set_file_perms'] = (isset($_POST['set_file_perms'])) ? 1 : 0;
188
+ $_POST['set_dir_perms'] = (isset($_POST['set_dir_perms'])) ? 1 : 0;
189
+ $_POST['file_perms_value'] = (isset($_POST['file_perms_value'])) ? DUPX_U::sanitize_text_field($_POST['file_perms_value']) : 0755;
190
+ $_POST['dir_perms_value'] = (isset($_POST['dir_perms_value'])) ? DUPX_U::sanitize_text_field($_POST['dir_perms_value']) : 0644;
191
+ $_POST['zip_filetime'] = (isset($_POST['zip_filetime'])) ? $_POST['zip_filetime'] : 'current';
192
+ $_POST['config_mode'] = (isset($_POST['config_mode'])) ? $_POST['config_mode'] : 'NEW';
193
+ $_POST[self::INPUT_NAME_ARCHIVE_ACTION] = (isset($_POST[self::INPUT_NAME_ARCHIVE_ACTION])) ? $_POST[self::INPUT_NAME_ARCHIVE_ACTION] : self::ACTION_DO_NOTHING;
194
+ $_POST['archive_engine'] = (isset($_POST['archive_engine'])) ? $_POST['archive_engine'] : 'manual';
195
+ $_POST['exe_safe_mode'] = (isset($_POST['exe_safe_mode'])) ? $_POST['exe_safe_mode'] : 0;
196
+
197
+ //LOGGING
198
+ $POST_LOG = $_POST;
199
+ unset($POST_LOG['dbpass']);
200
+ ksort($POST_LOG);
201
+
202
+
203
+
204
+ //ACTION VARS
205
+ $ajax1_start = DUPX_U::getMicrotime();
206
+ $root_path = $GLOBALS['DUPX_ROOT'];
207
+ $wpconfig_ark_path = ($GLOBALS['DUPX_AC']->installSiteOverwriteOn) ?
208
+ "{$root_path}/dup-wp-config-arc__{$GLOBALS['DUPX_AC']->package_hash}.txt" : "{$root_path}/wp-config.php";
209
+
210
+ $archive_path = $GLOBALS['FW_PACKAGE_PATH'];
211
+ $dataResult = array();
212
+ $dataResult['pass'] = 0;
213
+
214
+ /** JSON RESPONSE: Most sites have warnings turned off by default, but if they're turned on the warnings
215
+ cause errors in the JSON data Here we hide the status so warning level is reset at it at the end */
216
+ $ajax1_error_level = error_reporting();
217
+ error_reporting(E_ERROR);
218
+
219
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
220
+
221
+ //===============================
222
+ //ARCHIVE ERROR MESSAGES
223
+ //===============================
224
+ ($GLOBALS['LOG_FILE_HANDLE'] != false) or DUPX_Log::error(ERR_MAKELOG);
225
+
226
+ if (!$GLOBALS['DUPX_AC']->exportOnlyDB) {
227
+
228
+ $post_archive_engine = DUPX_U::sanitize_text_field($_POST['archive_engine']);
229
+
230
+ if ($post_archive_engine == 'manual') {
231
+ if (!file_exists($wpconfig_ark_path) && !file_exists("database.sql")) {
232
+ DUPX_Log::error(ERR_ZIPMANUAL);
233
+ }
234
+ } else {
235
+ if (!is_readable("{$archive_path}")) {
236
+ DUPX_Log::error("archive path:{$archive_path}<br/>".ERR_ZIPNOTFOUND);
237
+ }
238
+ }
239
+
240
+ //ERR_ZIPMANUAL
241
+ if (('ziparchive' == $post_archive_engine || 'shellexec_unzip' == $post_archive_engine) && !$GLOBALS['DUPX_AC']->installSiteOverwriteOn) {
242
+ //ERR_CONFIG_FOUND
243
+ $outer_root_path = dirname($root_path);
244
+
245
+ if ((file_exists($wpconfig_ark_path) || (@file_exists("{$outer_root_path}/wp-config.php") && !@file_exists("{$outer_root_path}/wp-settings.php"))) && @file_exists("{$root_path}/wp-admin") && @file_exists("{$root_path}/wp-includes")) {
246
+ DUPX_Log::error(ERR_CONFIG_FOUND);
247
+ }
248
+ }
249
+ }
250
+
251
+ DUPX_Log::info("********************************************************************************");
252
+ DUPX_Log::info('* DUPLICATOR-PRO: Install-Log');
253
+ DUPX_Log::info('* STEP-1 START @ '.@date('h:i:s'));
254
+ DUPX_Log::info("* VERSION: {$GLOBALS['DUPX_AC']->version_dup}");
255
+ DUPX_Log::info('* NOTICE: Do NOT post to public sites or forums!!');
256
+ DUPX_Log::info("********************************************************************************");
257
+
258
+ $colSize = 60;
259
+ $labelPadSize = 20;
260
+ $os = defined('PHP_OS') ? PHP_OS : 'unknown';
261
+ $log = str_pad(str_pad('PACKAGE INFO', $labelPadSize, '_', STR_PAD_RIGHT).' '.'CURRENT SERVER', $colSize, ' ', STR_PAD_RIGHT).'|'.'ORIGINAL SERVER'."\n".
262
+ str_pad(str_pad('PHP VERSION', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_php, $colSize, ' ', STR_PAD_RIGHT).'|'.phpversion()."\n".
263
+ str_pad(str_pad('OS', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_os, $colSize, ' ', STR_PAD_RIGHT).'|'.$os."\n".
264
+ str_pad('CREATED', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->created."\n".
265
+ str_pad('WP VERSION', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_wp."\n".
266
+ str_pad('DUP VERSION', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_dup."\n".
267
+ str_pad('DB', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_db."\n".
268
+ str_pad('DB TABLES', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->dbInfo->tablesFinalCount."\n".
269
+ str_pad('DB ROWS', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->dbInfo->tablesRowCount."\n".
270
+ str_pad('DB FILE SIZE', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->dbInfo->tablesSizeOnDisk."\n".
271
+ "********************************************************************************";
272
+ DUPX_Log::info($log);
273
+ DUPX_Log::info("SERVER INFO");
274
+ DUPX_Log::info(str_pad('PHP', $labelPadSize, '_', STR_PAD_RIGHT).': '.phpversion().' | SAPI: '.php_sapi_name());
275
+ DUPX_Log::info(str_pad('PHP MEMORY', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['PHP_MEMORY_LIMIT'].' | SUHOSIN: '.$GLOBALS['PHP_SUHOSIN_ON']);
276
+ DUPX_Log::info(str_pad('SERVER', $labelPadSize, '_', STR_PAD_RIGHT).': '.$_SERVER['SERVER_SOFTWARE']);
277
+ DUPX_Log::info(str_pad('DOC ROOT', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($root_path));
278
+ DUPX_Log::info(str_pad('DOC ROOT 755', $labelPadSize, '_', STR_PAD_RIGHT).': '.var_export($GLOBALS['CHOWN_ROOT_PATH'], true));
279
+ DUPX_Log::info(str_pad('LOG FILE 644', $labelPadSize, '_', STR_PAD_RIGHT).': '.var_export($GLOBALS['CHOWN_LOG_PATH'], true));
280
+ DUPX_Log::info(str_pad('REQUEST URL', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($GLOBALS['URL_PATH']));
281
+
282
+ DUPX_Log::info("********************************************************************************");
283
+ DUPX_Log::info("USER INPUTS");
284
+ DUPX_Log::info(str_pad('ARCHIVE ACTION', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST[self::INPUT_NAME_ARCHIVE_ACTION]));
285
+ DUPX_Log::info(str_pad('ARCHIVE ENGINE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['archive_engine']));
286
+ DUPX_Log::info(str_pad('SET DIR PERMS', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['set_dir_perms']));
287
+ DUPX_Log::info(str_pad('DIR PERMS VALUE', $labelPadSize, '_', STR_PAD_RIGHT).': '.decoct($_POST['dir_perms_value']));
288
+ DUPX_Log::info(str_pad('SET FILE PERMS', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['set_file_perms']));
289
+ DUPX_Log::info(str_pad('FILE PERMS VALUE', $labelPadSize, '_', STR_PAD_RIGHT).': '.decoct($_POST['file_perms_value']));
290
+ DUPX_Log::info(str_pad('SAFE MODE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['exe_safe_mode']));
291
+ DUPX_Log::info(str_pad('LOGGING', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['logging']));
292
+ DUPX_Log::info(str_pad('CONFIG MODE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['config_mode']));
293
+ DUPX_Log::info(str_pad('FILE TIME', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['zip_filetime']));
294
+ DUPX_Log::info("********************************************************************************\n");
295
+
296
+ $log = "--------------------------------------\n";
297
+ $log .= "POST DATA\n";
298
+ $log .= "--------------------------------------\n";
299
+ $log .= print_r($POST_LOG, true);
300
+ DUPX_Log::info($log, DUPX_Log::LV_DEBUG);
301
+
302
+ $log = "\n--------------------------------------\n";
303
+ $log .= "ARCHIVE SETUP\n";
304
+ $log .= "--------------------------------------\n";
305
+ $log .= str_pad('NAME', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($GLOBALS['FW_PACKAGE_PATH'])."\n";
306
+ if (file_exists($GLOBALS['FW_PACKAGE_PATH'])) {
307
+ $log .= str_pad('SIZE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_U::readableByteSize(@filesize($GLOBALS['FW_PACKAGE_PATH']));
308
+ }
309
+ DUPX_Log::info($log."\n", DUPX_Log::LV_DEFAULT, true);
310
+
311
+ DUPX_Log::info('PRE-EXTRACT-CHECKS');
312
+ DUPX_ServerConfig::beforeExtractionSetup();
313
+
314
+ $this->beforeExtraction();
315
+
316
+ $target = $root_path;
317
+ DUPX_U::maintenanceMode(true);
318
+
319
+ $post_archive_engine = DUPX_U::sanitize_text_field($_POST['archive_engine']);
320
+ switch ($post_archive_engine) {
321
+
322
+ //-----------------------
323
+ //MANUAL EXTRACTION
324
+ case 'manual':
325
+ DUPX_Log::info("\n** PACKAGE EXTRACTION IS IN MANUAL MODE ** \n");
326
+ break;
327
+
328
+ //-----------------------
329
+ //SHELL EXEC
330
+ case 'shellexec_unzip':
331
+ DUPX_Log::info("\n\nSTART ZIP FILE EXTRACTION SHELLEXEC >>> ");
332
+ $shell_exec_path = DUPX_Server::get_unzip_filepath();
333
+
334
+
335
+ $command = escapeshellcmd($shell_exec_path)." -o -qq ".escapeshellarg($archive_path)." -d ".escapeshellarg($target)." 2>&1";
336
+ if ($_POST['zip_filetime'] == 'original') {
337
+ DUPX_Log::info("\nShell Exec Current does not support orginal file timestamp please use ZipArchive");
338
+ }
339
+
340
+ DUPX_Log::info(">>> Starting Shell-Exec Unzip:\nCommand: {$command}", DUPX_Log::LV_DEBUG);
341
+ $stderr = shell_exec($command);
342
+ if ($stderr != '') {
343
+ $zip_err_msg = ERR_SHELLEXEC_ZIPOPEN.": $stderr";
344
+ $zip_err_msg .= "<br/><br/><b>To resolve error see <a href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-130-q' target='_blank'>https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-130-q</a></b>";
345
+ DUPX_Log::error($zip_err_msg);
346
+ }
347
+ DUPX_Log::info("<<< Shell-Exec Unzip Complete.");
348
+
349
+ break;
350
+
351
+ //-----------------------
352
+ //ZIP-ARCHIVE
353
+ case 'ziparchive':
354
+ DUPX_Log::info("\n\nSTART ZIP FILE EXTRACTION STANDARD >>> ");
355
+
356
+ if (!class_exists('ZipArchive')) {
357
+ DUPX_Log::info("ERROR: Stopping install process. Trying to extract without ZipArchive module installed. Please use the 'Manual Archive Extraction' mode to extract zip file.");
358
+ DUPX_Log::error(ERR_ZIPARCHIVE);
359
+ }
360
+
361
+ if (($dupInstallerFolder = DUPX_U::findDupInstallerFolder($archive_path)) === false) {
362
+ DUPX_Log::info("findDupInstallerFolder error; set no subfolder");
363
+ // if not found set not subfolder
364
+ $dupInstallerFolder = '';
365
+ }
366
+ if (!empty($dupInstallerFolder)) {
367
+ DUPX_Log::info("ARCHIVE dup-installer SUBFOLDER:\"".$dupInstallerFolder."\"");
368
+ } else {
369
+ DUPX_Log::info("ARCHIVE dup-installer SUBFOLDER:\"".$dupInstallerFolder."\"", 2);
370
+ }
371
+
372
+ $dupInstallerZipPath = $dupInstallerFolder.'/dup-installer';
373
+
374
+ $zip = new ZipArchive();
375
+
376
+ if ($zip->open($archive_path) === TRUE) {
377
+ $extract_filenames = array();
378
+ DUPX_Handler::setMode(DUPX_Handler::MODE_VAR, false, false);
379
+
380
+ for ($i = 0; $i < $zip->numFiles; $i++) {
381
+ $extract_filename = $zip->getNameIndex($i);
382
+
383
+ // skip dup-installer folder. Alrady extracted in bootstrap
384
+ if (
385
+ (strpos($extract_filename, $dupInstallerZipPath) === 0) ||
386
+ (!empty($dupInstallerFolder) && strpos($extract_filename, $dupInstallerFolder) !== 0)
387
+ ) {
388
+ DUPX_Log::info("SKIPPING NOT IN ZIPATH:\"".DUPX_Log::varToString($extract_filename)."\"", DUPX_Log::LV_DETAILED);
389
+ continue;
390
+ }
391
+
392
+ try {
393
+ if (!$zip->extractTo($target, $extract_filename)) {
394
+ if (DupLiteSnapLibUtilWp::isWpCore($extract_filename, DupLiteSnapLibUtilWp::PATH_RELATIVE)) {
395
+ DUPX_Log::info("FILE CORE EXTRACION ERROR: ".$extract_filename);
396
+ $shortMsg = 'Can\'t extract wp core files';
397
+ $finalShortMsg = 'Wp core files not extracted';
398
+ $errLevel = DUPX_NOTICE_ITEM::CRITICAL;
399
+ $idManager = 'wp-extract-error-file-core';
400
+ } else {
401
+ DUPX_Log::info("FILE EXTRACION ERROR: ".$extract_filename);
402
+ $shortMsg = 'Can\'t extract files';
403
+ $finalShortMsg = 'Files not extracted';
404
+ $errLevel = DUPX_NOTICE_ITEM::SOFT_WARNING;
405
+ $idManager = 'wp-extract-error-file-no-core';
406
+ }
407
+ $longMsg = 'FILE: <b>'.htmlspecialchars($extract_filename).'</b><br>Message: '.htmlspecialchars(DUPX_Handler::getVarLogClean()).'<br><br>';
408
+
409
+ $nManager->addNextStepNotice(array(
410
+ 'shortMsg' => $shortMsg,
411
+ 'longMsg' => $longMsg,
412
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
413
+ 'level' => $errLevel
414
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
415
+ $nManager->addFinalReportNotice(array(
416
+ 'shortMsg' => $finalShortMsg,
417
+ 'longMsg' => $longMsg,
418
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
419
+ 'level' => $errLevel,
420
+ 'sections' => array('files'),
421
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
422
+ } else {
423
+ DUPX_Log::info("FILE EXTRACTION DONE: ".DUPX_Log::varToString($extract_filename), DUPX_Log::LV_HARD_DEBUG);
424
+ }
425
+ }
426
+ catch (Exception $ex) {
427
+ if (DupLiteSnapLibUtilWp::isWpCore($extract_filename, DupLiteSnapLibUtilWp::PATH_RELATIVE)) {
428
+ DUPX_Log::info("FILE CORE EXTRACION ERROR: {$extract_filename} | MSG:".$ex->getMessage());
429
+ $shortMsg = 'Can\'t extract wp core files';
430
+ $finalShortMsg = 'Wp core files not extracted';
431
+ $errLevel = DUPX_NOTICE_ITEM::CRITICAL;
432
+ $idManager = 'wp-extract-error-file-core';
433
+ } else {
434
+ DUPX_Log::info("FILE EXTRACION ERROR: {$extract_filename} | MSG:".$ex->getMessage());
435
+ $shortMsg = 'Can\'t extract files';
436
+ $finalShortMsg = 'Files not extracted';
437
+ $errLevel = DUPX_NOTICE_ITEM::SOFT_WARNING;
438
+ $idManager = 'wp-extract-error-file-no-core';
439
+ }
440
+ $longMsg = 'FILE: <b>'.htmlspecialchars($extract_filename).'</b><br>Message: '.htmlspecialchars($ex->getMessage()).'<br><br>';
441
+
442
+ $nManager->addNextStepNotice(array(
443
+ 'shortMsg' => $shortMsg,
444
+ 'longMsg' => $longMsg,
445
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
446
+ 'level' => $errLevel
447
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
448
+ $nManager->addFinalReportNotice(array(
449
+ 'shortMsg' => $finalShortMsg,
450
+ 'longMsg' => $longMsg,
451
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
452
+ 'level' => $errLevel,
453
+ 'sections' => array('files'),
454
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
455
+ }
456
+ }
457
+
458
+ if (!empty($dupInstallerFolder)) {
459
+ DUPX_U::moveUpfromSubFolder($target.'/'.$dupInstallerFolder, true);
460
+ }
461
+
462
+ //Uncomment if needed
463
+ //if (DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)) {
464
+ // $log = print_r($zip, true);
465
+ //}
466
+ //FILE-TIMESTAMP
467
+ if ($_POST['zip_filetime'] == 'original') {
468
+ $log .= "File timestamp set to Original\n";
469
+ for ($idx = 0; $s = $zip->statIndex($idx); $idx++) {
470
+ touch($target.DIRECTORY_SEPARATOR.$s['name'], $s['mtime']);
471
+ }
472
+ } else {
473
+ $now = @date("Y-m-d H:i:s");
474
+ $log .= "File timestamp set to Current: {$now}\n";
475
+ }
476
+
477
+ // set handler as default
478
+ DUPX_Handler::setMode();
479
+
480
+ $close_response = $zip->close();
481
+ $log .= "<<< ZipArchive Unzip Complete: ".var_export($close_response, true);
482
+ DUPX_Log::info($log);
483
+ } else {
484
+ $zip_err_msg = ERR_ZIPOPEN;
485
+ $zip_err_msg .= "<br/><br/><b>To resolve error see <a href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-130-q' target='_blank'>https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-130-q</a></b>";
486
+ DUPX_Log::error($zip_err_msg);
487
+ }
488
+
489
+ break;
490
+
491
+ //-----------------------
492
+ //DUP-ARCHIVE
493
+ case 'duparchive':
494
+ DUPX_Log::info(">>> DupArchive Extraction Complete");
495
+
496
+ if (isset($_POST['extra_data'])) {
497
+ $extraData = $_POST['extra_data'];
498
+
499
+ $log = "\n--------------------------------------\n";
500
+ $log .= "DUPARCHIVE EXTRACTION STATUS\n";
501
+ $log .= "--------------------------------------\n";
502
+
503
+ $dawsStatus = json_decode($extraData);
504
+
505
+ if ($dawsStatus === null) {
506
+ $log .= "Can't decode the dawsStatus!\n";
507
+ $log .= print_r(extraData, true);
508
+ } else {
509
+ $criticalPresent = false;
510
+
511
+ if (count($dawsStatus->failures) > 0) {
512
+ $log .= "Archive extracted with errors.\n";
513
+
514
+ foreach ($dawsStatus->failures as $failure) {
515
+ if ($failure->isCritical) {
516
+ $log .= '(C) ';
517
+ $criticalPresent = true;
518
+ }
519
+ $log .= "{$failure->description}\n";
520
+ }
521
+ } else {
522
+ $log .= "Archive extracted with no errors.\n";
523
+ }
524
+
525
+ if ($criticalPresent) {
526
+ $log .= "\n\nCritical Errors present so stopping install.\n";
527
+ exit();
528
+ }
529
+ }
530
+
531
+ DUPX_Log::info($log);
532
+ } else {
533
+ DUPX_LOG::info("DAWS STATUS: UNKNOWN since extra_data wasn't in post!");
534
+ }
535
+
536
+ break;
537
+ }
538
+
539
+ $log = "--------------------------------------\n";
540
+ $log .= "POST-EXTACT-CHECKS\n";
541
+ $log .= "--------------------------------------";
542
+ DUPX_Log::info($log);
543
+
544
+ //===============================
545
+ //FILE PERMISSIONS
546
+ if ($_POST['set_file_perms'] || $_POST['set_dir_perms']) {
547
+ $set_file_perms = $_POST['set_file_perms'];
548
+ $set_dir_perms = $_POST['set_dir_perms'];
549
+ $set_file_mtime = ($_POST['zip_filetime'] == 'current');
550
+ $file_perms_value = $_POST['file_perms_value'] ? $_POST['file_perms_value'] : 0755;
551
+ $dir_perms_value = $_POST['dir_perms_value'] ? $_POST['dir_perms_value'] : 0644;
552
+
553
+ DUPX_Log::info("PERMISSION UPDATES:");
554
+ DUPX_Log::info(" -DIRS: '{$dir_perms_value}'");
555
+ DUPX_Log::info(" -FILES: '{$file_perms_value}'");
556
+
557
+ $objects = new RecursiveIteratorIterator(new IgnorantRecursiveDirectoryIterator($root_path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
558
+
559
+ foreach ($objects as $name => $object) {
560
+ if ($set_file_perms && is_file($name)) {
561
+ DUPX_Log::info("SET PERMISSION: ".DUPX_Log::varToString($name).'[MODE:'.$file_perms_value.']', DUPX_Log::LV_HARD_DEBUG);
562
+ if (!DupLiteSnapLibIOU::chmod($name, $file_perms_value)) {
563
+ DUPX_Log::info("Permissions setting on file '{$name}' failed");
564
+ }
565
+ } else if ($set_dir_perms && is_dir($name)) {
566
+ DUPX_Log::info("SET PERMISSION: ".DUPX_Log::varToString($name).'[MODE:'.$dir_perms_value.']', DUPX_Log::LV_HARD_DEBUG);
567
+ if (!DupLiteSnapLibIOU::chmod($name, $dir_perms_value)) {
568
+ DUPX_Log::info("Permissions setting on directory '{$name}' failed");
569
+ }
570
+ }
571
+ if ($set_file_mtime) {
572
+ @touch($name);
573
+ }
574
+ }
575
+ } else {
576
+ DUPX_Log::info("\nPERMISSION UPDATES: None Applied");
577
+ }
578
+
579
+ DUPX_ServerConfig::afterExtractionSetup();
580
+ $nManager->saveNotices();
581
+
582
+ //FINAL RESULTS
583
+ $ajax1_sum = DUPX_U::elapsedTime(DUPX_U::getMicrotime(), $ajax1_start);
584
+ DUPX_Log::info("\nSTEP-1 COMPLETE @ ".@date('h:i:s')." - RUNTIME: {$ajax1_sum}");
585
+
586
+ $dataResult['pass'] = 1;
587
+ error_reporting($ajax1_error_level);
588
+ fclose($GLOBALS["LOG_FILE_HANDLE"]);
589
+ return $dataResult;
590
+ }
591
+ }
592
+
593
+ // Skips past paths it can't read
594
+ class IgnorantRecursiveDirectoryIterator extends RecursiveDirectoryIterator
595
+ {
596
+
597
+ function getChildren()
598
+ {
599
+ try {
600
+ return new IgnorantRecursiveDirectoryIterator($this->getPathname(), RecursiveDirectoryIterator::SKIP_DOTS);
601
+ }
602
+ catch (UnexpectedValueException $e) {
603
+ return new RecursiveArrayIterator(array());
604
+ }
605
+ }
606
+ }
installer/dup-installer/ctrls/ctrl.s1.php CHANGED
@@ -1,424 +1,7 @@
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
 
4
- /** IDE HELPERS */
5
- /* @var $GLOBALS['DUPX_AC'] DUPX_ArchiveConfig */
6
 
7
- //OPTIONS
8
- $_POST['set_file_perms'] = (isset($_POST['set_file_perms'])) ? 1 : 0;
9
- $_POST['set_dir_perms'] = (isset($_POST['set_dir_perms'])) ? 1 : 0;
10
- $_POST['file_perms_value'] = (isset($_POST['file_perms_value'])) ? DUPX_U::sanitize_text_field($_POST['file_perms_value']) : 0755;
11
- $_POST['dir_perms_value'] = (isset($_POST['dir_perms_value'])) ? DUPX_U::sanitize_text_field($_POST['dir_perms_value']) : 0644;
12
- $_POST['zip_filetime'] = (isset($_POST['zip_filetime'])) ? $_POST['zip_filetime'] : 'current';
13
- $_POST['config_mode'] = (isset($_POST['config_mode'])) ? $_POST['config_mode'] : 'NEW';
14
- $_POST['archive_engine'] = (isset($_POST['archive_engine'])) ? $_POST['archive_engine'] : 'manual';
15
- $_POST['exe_safe_mode'] = (isset($_POST['exe_safe_mode'])) ? $_POST['exe_safe_mode'] : 0;
16
-
17
- //LOGGING
18
- $POST_LOG = $_POST;
19
- unset($POST_LOG['dbpass']);
20
- ksort($POST_LOG);
21
-
22
- if($_POST['archive_engine'] == 'manual') {
23
- $GLOBALS['DUPX_STATE']->isManualExtraction = true;
24
- $GLOBALS['DUPX_STATE']->save();
25
- }
26
-
27
- //ACTION VARS
28
- $ajax1_start = DUPX_U::getMicrotime();
29
- $root_path = $GLOBALS['DUPX_ROOT'];
30
- $wpconfig_ark_path = ($GLOBALS['DUPX_AC']->installSiteOverwriteOn) ?
31
- "{$root_path}/dup-wp-config-arc__{$GLOBALS['DUPX_AC']->package_hash}.txt"
32
- : "{$root_path}/wp-config.php";
33
-
34
- $archive_path = $GLOBALS['FW_PACKAGE_PATH'];
35
- $JSON = array();
36
- $JSON['pass'] = 0;
37
-
38
- /** JSON RESPONSE: Most sites have warnings turned off by default, but if they're turned on the warnings
39
- cause errors in the JSON data Here we hide the status so warning level is reset at it at the end */
40
- $ajax1_error_level = error_reporting();
41
- error_reporting(E_ERROR);
42
-
43
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
44
-
45
- //===============================
46
- //ARCHIVE ERROR MESSAGES
47
- //===============================
48
- ($GLOBALS['LOG_FILE_HANDLE'] != false) or DUPX_Log::error(ERR_MAKELOG);
49
-
50
- if (! $GLOBALS['DUPX_AC']->exportOnlyDB) {
51
-
52
- $post_archive_engine = DUPX_U::sanitize_text_field($_POST['archive_engine']);
53
-
54
- if ($post_archive_engine == 'manual'){
55
- if (!file_exists($wpconfig_ark_path) && !file_exists("database.sql")) {
56
- DUPX_Log::error(ERR_ZIPMANUAL);
57
- }
58
- } else {
59
- if (!is_readable("{$archive_path}")) {
60
- DUPX_Log::error("archive path:{$archive_path}<br/>" . ERR_ZIPNOTFOUND);
61
- }
62
- }
63
-
64
- //ERR_ZIPMANUAL
65
- if (('ziparchive' == $post_archive_engine || 'shellexec_unzip' == $post_archive_engine) && !$GLOBALS['DUPX_AC']->installSiteOverwriteOn) {
66
- //ERR_CONFIG_FOUND
67
- $outer_root_path = dirname($root_path);
68
-
69
- if ((file_exists($wpconfig_ark_path) || (@file_exists("{$outer_root_path}/wp-config.php") && !@file_exists("{$outer_root_path}/wp-settings.php"))) && @file_exists("{$root_path}/wp-admin") && @file_exists("{$root_path}/wp-includes")) {
70
- DUPX_Log::error(ERR_CONFIG_FOUND);
71
- }
72
- }
73
- }
74
-
75
- DUPX_Log::info("********************************************************************************");
76
- DUPX_Log::info('* DUPLICATOR-PRO: Install-Log');
77
- DUPX_Log::info('* STEP-1 START @ '.@date('h:i:s'));
78
- DUPX_Log::info("* VERSION: {$GLOBALS['DUPX_AC']->version_dup}");
79
- DUPX_Log::info('* NOTICE: Do NOT post to public sites or forums!!');
80
- DUPX_Log::info("********************************************************************************");
81
-
82
- $colSize = 60;
83
- $labelPadSize = 20;
84
- $os = defined('PHP_OS') ? PHP_OS : 'unknown';
85
- $log = str_pad(str_pad('PACKAGE INFO', $labelPadSize, '_', STR_PAD_RIGHT).' '.'CURRENT SERVER', $colSize, ' ', STR_PAD_RIGHT).'|'.'ORIGINAL SERVER'."\n".
86
- str_pad(str_pad('PHP VERSION', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_php, $colSize, ' ', STR_PAD_RIGHT).'|'.phpversion()."\n".
87
- str_pad(str_pad('OS', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_os, $colSize, ' ', STR_PAD_RIGHT).'|'.$os."\n".
88
- str_pad('CREATED', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->created."\n".
89
- str_pad('WP VERSION', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_wp."\n".
90
- str_pad('DUP VERSION', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_dup."\n".
91
- str_pad('DB', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->version_db."\n".
92
- str_pad('DB TABLES', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->dbInfo->tablesFinalCount."\n".
93
- str_pad('DB ROWS', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->dbInfo->tablesRowCount."\n".
94
- str_pad('DB FILE SIZE', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['DUPX_AC']->dbInfo->tablesSizeOnDisk."\n".
95
- "********************************************************************************";
96
- DUPX_Log::info($log);
97
- DUPX_Log::info("SERVER INFO");
98
- DUPX_Log::info(str_pad('PHP', $labelPadSize, '_', STR_PAD_RIGHT).': '.phpversion().' | SAPI: '.php_sapi_name());
99
- DUPX_Log::info(str_pad('PHP MEMORY', $labelPadSize, '_', STR_PAD_RIGHT).': '.$GLOBALS['PHP_MEMORY_LIMIT'].' | SUHOSIN: '.$GLOBALS['PHP_SUHOSIN_ON']);
100
- DUPX_Log::info(str_pad('SERVER', $labelPadSize, '_', STR_PAD_RIGHT).': '.$_SERVER['SERVER_SOFTWARE']);
101
- DUPX_Log::info(str_pad('DOC ROOT', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($root_path));
102
- DUPX_Log::info(str_pad('DOC ROOT 755', $labelPadSize, '_', STR_PAD_RIGHT).': '.var_export($GLOBALS['CHOWN_ROOT_PATH'], true));
103
- DUPX_Log::info(str_pad('LOG FILE 644', $labelPadSize, '_', STR_PAD_RIGHT).': '.var_export($GLOBALS['CHOWN_LOG_PATH'], true));
104
- DUPX_Log::info(str_pad('REQUEST URL', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($GLOBALS['URL_PATH']));
105
-
106
- DUPX_Log::info("********************************************************************************");
107
- DUPX_Log::info("USER INPUTS");
108
- DUPX_Log::info(str_pad('ARCHIVE ENGINE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['archive_engine']));
109
- DUPX_Log::info(str_pad('SET DIR PERMS', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['set_dir_perms']));
110
- DUPX_Log::info(str_pad('DIR PERMS VALUE', $labelPadSize, '_', STR_PAD_RIGHT).': '.decoct($_POST['dir_perms_value']));
111
- DUPX_Log::info(str_pad('SET FILE PERMS', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['set_file_perms'] ));
112
- DUPX_Log::info(str_pad('FILE PERMS VALUE', $labelPadSize, '_', STR_PAD_RIGHT).': '.decoct($_POST['file_perms_value']));
113
- DUPX_Log::info(str_pad('SAFE MODE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['exe_safe_mode']));
114
- DUPX_Log::info(str_pad('LOGGING', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['logging']));
115
- DUPX_Log::info(str_pad('CONFIG MODE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['config_mode']));
116
- DUPX_Log::info(str_pad('FILE TIME', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($_POST['zip_filetime']));
117
- DUPX_Log::info("********************************************************************************\n");
118
-
119
- $log = "--------------------------------------\n";
120
- $log .= "POST DATA\n";
121
- $log .= "--------------------------------------\n";
122
- $log .= print_r($POST_LOG, true);
123
- DUPX_Log::info($log, DUPX_Log::LV_DEBUG);
124
-
125
- $log = "\n--------------------------------------\n";
126
- $log .= "ARCHIVE SETUP\n";
127
- $log .= "--------------------------------------\n";
128
- $log .= str_pad('NAME', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_Log::varToString($GLOBALS['FW_PACKAGE_PATH'])."\n";
129
- if (file_exists($GLOBALS['FW_PACKAGE_PATH'])) {
130
- $log .= str_pad('SIZE', $labelPadSize, '_', STR_PAD_RIGHT).': '.DUPX_U::readableByteSize(@filesize($GLOBALS['FW_PACKAGE_PATH']));
131
- }
132
- DUPX_Log::info($log."\n", DUPX_Log::LV_DEFAULT, true);
133
-
134
- DUPX_Log::info('PRE-EXTRACT-CHECKS');
135
- DUPX_ServerConfig::beforeExtractionSetup();
136
-
137
- $target = $root_path;
138
-
139
- $post_archive_engine = DUPX_U::sanitize_text_field($_POST['archive_engine']);
140
- switch ($post_archive_engine) {
141
-
142
- //-----------------------
143
- //MANUAL EXTRACTION
144
- case 'manual':
145
- DUPX_Log::info("\n** PACKAGE EXTRACTION IS IN MANUAL MODE ** \n");
146
- break;
147
-
148
- //-----------------------
149
- //SHELL EXEC
150
- case 'shellexec_unzip':
151
- DUPX_Log::info("\n\nSTART ZIP FILE EXTRACTION SHELLEXEC >>> ");
152
- $shell_exec_path = DUPX_Server::get_unzip_filepath();
153
-
154
-
155
- $command = escapeshellcmd($shell_exec_path)." -o -qq ".escapeshellarg($archive_path)." -d ".escapeshellarg($target)." 2>&1";
156
- if ($_POST['zip_filetime'] == 'original') {
157
- DUPX_Log::info("\nShell Exec Current does not support orginal file timestamp please use ZipArchive");
158
- }
159
-
160
- DUPX_Log::info(">>> Starting Shell-Exec Unzip:\nCommand: {$command}", DUPX_Log::LV_DEBUG);
161
- $stderr = shell_exec($command);
162
- if ($stderr != '') {
163
- $zip_err_msg = ERR_SHELLEXEC_ZIPOPEN.": $stderr";
164
- $zip_err_msg .= "<br/><br/><b>To resolve error see <a href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-130-q' target='_blank'>https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-130-q</a></b>";
165
- DUPX_Log::error($zip_err_msg);
166
- }
167
- DUPX_Log::info("<<< Shell-Exec Unzip Complete.");
168
-
169
- break;
170
-
171
- //-----------------------
172
- //ZIP-ARCHIVE
173
- case 'ziparchive':
174
- DUPX_Log::info("\n\nSTART ZIP FILE EXTRACTION STANDARD >>> ");
175
-
176
- if (!class_exists('ZipArchive')) {
177
- DUPX_Log::info("ERROR: Stopping install process. Trying to extract without ZipArchive module installed. Please use the 'Manual Archive Extraction' mode to extract zip file.");
178
- DUPX_Log::error(ERR_ZIPARCHIVE);
179
- }
180
-
181
- if (($dupInstallerFolder = DUPX_U::findDupInstallerFolder($archive_path)) === false) {
182
- DUPX_Log::info("findDupInstallerFolder error; set no subfolder");
183
- // if not found set not subfolder
184
- $dupInstallerFolder = '';
185
- }
186
- if (!empty($dupInstallerFolder)) {
187
- DUPX_Log::info("ARCHIVE dup-installer SUBFOLDER:\"".$dupInstallerFolder."\"");
188
- } else {
189
- DUPX_Log::info("ARCHIVE dup-installer SUBFOLDER:\"".$dupInstallerFolder."\"", 2);
190
- }
191
-
192
- $dupInstallerZipPath = $dupInstallerFolder.'/dup-installer';
193
-
194
- $zip = new ZipArchive();
195
-
196
- if ($zip->open($archive_path) === TRUE) {
197
- $extract_filenames = array();
198
- DUPX_Handler::setMode(DUPX_Handler::MODE_VAR , false , false);
199
-
200
- for($i = 0; $i < $zip->numFiles; $i++) {
201
- $extract_filename = $zip->getNameIndex($i);
202
-
203
- // skip dup-installer folder. Alrady extracted in bootstrap
204
- if (
205
- (strpos($extract_filename, $dupInstallerZipPath) === 0) ||
206
- (!empty($dupInstallerFolder) && strpos($extract_filename , $dupInstallerFolder) !== 0)
207
- ) {
208
- DUPX_Log::info("SKIPPING NOT IN ZIPATH:\"".DUPX_Log::varToString($extract_filename)."\"" , DUPX_Log::LV_DETAILED);
209
- continue;
210
- }
211
-
212
- try {
213
- if (!$zip->extractTo($target , $extract_filename)) {
214
- if (DupLiteSnapLibUtilWp::isWpCore($extract_filename, DupLiteSnapLibUtilWp::PATH_RELATIVE)) {
215
- DUPX_Log::info("FILE CORE EXTRACION ERROR: ".$extract_filename);
216
- $shortMsg = 'Can\'t extract wp core files';
217
- $finalShortMsg = 'Wp core files not extracted';
218
- $errLevel = DUPX_NOTICE_ITEM::CRITICAL;
219
- $idManager = 'wp-extract-error-file-core';
220
- } else {
221
- DUPX_Log::info("FILE EXTRACION ERROR: ".$extract_filename);
222
- $shortMsg = 'Can\'t extract files';
223
- $finalShortMsg = 'Files not extracted';
224
- $errLevel = DUPX_NOTICE_ITEM::SOFT_WARNING;
225
- $idManager = 'wp-extract-error-file-no-core';
226
- }
227
- $longMsg = 'FILE: <b>'.htmlspecialchars($extract_filename).'</b><br>Message: '.htmlspecialchars(DUPX_Handler::getVarLogClean()).'<br><br>';
228
-
229
- $nManager->addNextStepNotice(array(
230
- 'shortMsg' => $shortMsg,
231
- 'longMsg' => $longMsg,
232
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
233
- 'level' => $errLevel
234
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
235
- $nManager->addFinalReportNotice(array(
236
- 'shortMsg' => $finalShortMsg,
237
- 'longMsg' => $longMsg,
238
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
239
- 'level' => $errLevel,
240
- 'sections' => array('files'),
241
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
242
- } else {
243
- DUPX_Log::info("FILE EXTRACTION DONE: ".DUPX_Log::varToString($extract_filename), DUPX_Log::LV_HARD_DEBUG);
244
- }
245
- } catch (Exception $ex) {
246
- if (DupLiteSnapLibUtilWp::isWpCore($extract_filename, DupLiteSnapLibUtilWp::PATH_RELATIVE)) {
247
- DUPX_Log::info("FILE CORE EXTRACION ERROR: {$extract_filename} | MSG:".$ex->getMessage());
248
- $shortMsg = 'Can\'t extract wp core files';
249
- $finalShortMsg = 'Wp core files not extracted';
250
- $errLevel = DUPX_NOTICE_ITEM::CRITICAL;
251
- $idManager = 'wp-extract-error-file-core';
252
- } else {
253
- DUPX_Log::info("FILE EXTRACION ERROR: {$extract_filename} | MSG:".$ex->getMessage());
254
- $shortMsg = 'Can\'t extract files';
255
- $finalShortMsg = 'Files not extracted';
256
- $errLevel = DUPX_NOTICE_ITEM::SOFT_WARNING;
257
- $idManager = 'wp-extract-error-file-no-core';
258
- }
259
- $longMsg = 'FILE: <b>'.htmlspecialchars($extract_filename).'</b><br>Message: '.htmlspecialchars($ex->getMessage()).'<br><br>';
260
-
261
- $nManager->addNextStepNotice(array(
262
- 'shortMsg' => $shortMsg,
263
- 'longMsg' => $longMsg,
264
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
265
- 'level' => $errLevel
266
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
267
- $nManager->addFinalReportNotice(array(
268
- 'shortMsg' => $finalShortMsg,
269
- 'longMsg' => $longMsg,
270
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
271
- 'level' => $errLevel,
272
- 'sections' => array('files'),
273
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, $idManager);
274
- }
275
- }
276
-
277
- if (!empty($dupInstallerFolder)) {
278
- DUPX_U::moveUpfromSubFolder($target.'/'.$dupInstallerFolder , true);
279
- }
280
-
281
- //Uncomment if needed
282
- //if (DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)) {
283
- // $log = print_r($zip, true);
284
- //}
285
-
286
- //FILE-TIMESTAMP
287
- if ($_POST['zip_filetime'] == 'original') {
288
- $log .= "File timestamp set to Original\n";
289
- for ($idx = 0; $s = $zip->statIndex($idx); $idx++) {
290
- touch($target.DIRECTORY_SEPARATOR.$s['name'], $s['mtime']);
291
- }
292
- } else {
293
- $now = @date("Y-m-d H:i:s");
294
- $log .= "File timestamp set to Current: {$now}\n";
295
- }
296
-
297
- // set handler as default
298
- DUPX_Handler::setMode();
299
-
300
- $close_response = $zip->close();
301
- $log .= "<<< ZipArchive Unzip Complete: " . var_export($close_response, true);
302
- DUPX_Log::info($log);
303
- } else {
304
- $zip_err_msg = ERR_ZIPOPEN;
305
- $zip_err_msg .= "<br/><br/><b>To resolve error see <a href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-130-q' target='_blank'>https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-130-q</a></b>";
306
- DUPX_Log::error($zip_err_msg);
307
- }
308
-
309
- break;
310
-
311
- //-----------------------
312
- //DUP-ARCHIVE
313
- case 'duparchive':
314
- DUPX_Log::info(">>> DupArchive Extraction Complete");
315
-
316
- if (isset($_POST['extra_data'])) {
317
- $extraData = $_POST['extra_data'];
318
-
319
- $log = "\n--------------------------------------\n";
320
- $log .= "DUPARCHIVE EXTRACTION STATUS\n";
321
- $log .= "--------------------------------------\n";
322
-
323
- $dawsStatus = json_decode($extraData);
324
-
325
- if ($dawsStatus === null) {
326
- $log .= "Can't decode the dawsStatus!\n";
327
- $log .= print_r(extraData, true);
328
- } else {
329
- $criticalPresent = false;
330
-
331
- if (count($dawsStatus->failures) > 0) {
332
- $log .= "Archive extracted with errors.\n";
333
-
334
- foreach ($dawsStatus->failures as $failure) {
335
- if ($failure->isCritical) {
336
- $log .= '(C) ';
337
- $criticalPresent = true;
338
- }
339
- $log .= "{$failure->description}\n";
340
- }
341
- } else {
342
- $log .= "Archive extracted with no errors.\n";
343
- }
344
-
345
- if ($criticalPresent) {
346
- $log .= "\n\nCritical Errors present so stopping install.\n";
347
- exit();
348
- }
349
- }
350
-
351
- DUPX_Log::info($log);
352
- } else {
353
- DUPX_LOG::info("DAWS STATUS: UNKNOWN since extra_data wasn't in post!");
354
- }
355
-
356
- break;
357
- }
358
-
359
-
360
- $log = "--------------------------------------\n";
361
- $log .= "POST-EXTACT-CHECKS\n";
362
- $log .= "--------------------------------------";
363
- DUPX_Log::info($log);
364
-
365
- //===============================
366
- //FILE PERMISSIONS
367
- if ($_POST['set_file_perms'] || $_POST['set_dir_perms']) {
368
-
369
- // Skips past paths it can't read
370
- class IgnorantRecursiveDirectoryIterator extends RecursiveDirectoryIterator
371
- {
372
- function getChildren()
373
- {
374
- try {
375
- return new IgnorantRecursiveDirectoryIterator($this->getPathname(), RecursiveDirectoryIterator::SKIP_DOTS);
376
- } catch (UnexpectedValueException $e) {
377
- return new RecursiveArrayIterator(array());
378
- }
379
- }
380
- }
381
-
382
- $set_file_perms = $_POST['set_file_perms'];
383
- $set_dir_perms = $_POST['set_dir_perms'];
384
- $set_file_mtime = ($_POST['zip_filetime'] == 'current');
385
- $file_perms_value = $_POST['file_perms_value'] ? $_POST['file_perms_value'] : 0755;
386
- $dir_perms_value = $_POST['dir_perms_value'] ? $_POST['dir_perms_value'] : 0644;
387
-
388
- DUPX_Log::info("PERMISSION UPDATES:");
389
- DUPX_Log::info(" -DIRS: '{$dir_perms_value}'");
390
- DUPX_Log::info(" -FILES: '{$file_perms_value}'");
391
-
392
- $objects = new RecursiveIteratorIterator(new IgnorantRecursiveDirectoryIterator($root_path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
393
-
394
- foreach ($objects as $name => $object) {
395
- if ($set_file_perms && is_file($name)) {
396
- DUPX_Log::info("SET PERMISSION: ".DUPX_Log::varToString($name).'[MODE:'.$file_perms_value.']', DUPX_Log::LV_HARD_DEBUG);
397
- if (!DupLiteSnapLibIOU::chmod($name, $file_perms_value)) {
398
- DUPX_Log::info("Permissions setting on file '{$name}' failed");
399
- }
400
- } else if ($set_dir_perms && is_dir($name)) {
401
- DUPX_Log::info("SET PERMISSION: ".DUPX_Log::varToString($name).'[MODE:'.$dir_perms_value.']', DUPX_Log::LV_HARD_DEBUG);
402
- if (!DupLiteSnapLibIOU::chmod($name, $dir_perms_value)) {
403
- DUPX_Log::info("Permissions setting on directory '{$name}' failed");
404
- }
405
- }
406
- if ($set_file_mtime) {
407
- @touch($name);
408
- }
409
- }
410
- } else {
411
- DUPX_Log::info("\nPERMISSION UPDATES: None Applied");
412
- }
413
-
414
- DUPX_ServerConfig::afterExtractionSetup();
415
- $nManager->saveNotices();
416
-
417
- //FINAL RESULTS
418
- $ajax1_sum = DUPX_U::elapsedTime(DUPX_U::getMicrotime(), $ajax1_start);
419
- DUPX_Log::info("\nSTEP-1 COMPLETE @ " . @date('h:i:s') . " - RUNTIME: {$ajax1_sum}");
420
-
421
- $JSON['pass'] = 1;
422
- error_reporting($ajax1_error_level);
423
- fclose($GLOBALS["LOG_FILE_HANDLE"]);
424
- die(DupLiteSnapJsonU::wp_json_encode($JSON));
1
  <?php
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
 
4
+ require_once($GLOBALS['DUPX_INIT'].'/ctrls/classes/class.ctrl.extraction.php');
 
5
 
6
+ $data = DUP_LITE_Extraction::getInstance()->runExtraction();
7
+ die(DupLiteSnapJsonU::wp_json_encode($data));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
installer/dup-installer/ctrls/ctrl.s2.dbinstall.php CHANGED
@@ -1,646 +1,669 @@
1
- <?php
2
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
-
4
- class DUPX_DBInstall
5
- {
6
- const USER_DEFINER_PATTERN = "/^(\s*(?:\/\*!\d+\s)?\s*(?:CREATE.+)?DEFINER\s*=)(\S+)(.*)$/m";
7
- const SQL_SECURITY_INVOKER_PATTERN = "/^([\s\t]*CREATE.+PROCEDURE[\s\S]*)(BEGIN)([\s\S]*)$/";
8
- const SQL_SECURITY_INVOKER_REPLACE = "$1SQL SECURITY INVOKER\n$2$3";
9
- const QUERY_ERROR_LOG_LEN = 200;
10
-
11
- private $dbh;
12
- private $post;
13
- public $sql_result_data;
14
- public $sql_result_data_length;
15
- public $dbvar_maxtime;
16
- public $dbvar_maxpacks;
17
- public $dbvar_sqlmode;
18
- public $dbvar_version;
19
- public $pos_in_sql;
20
- public $sql_file_path;
21
- public $sql_result_file_path;
22
- public $php_mem;
23
- public $php_mem_range;
24
- public $php_used_mem;
25
- public $table_count;
26
- public $table_rows;
27
- public $query_errs;
28
- public $root_path;
29
- public $drop_tbl_log;
30
- public $rename_tbl_log;
31
- public $dbquery_errs;
32
- public $dbquery_rows;
33
- public $dbtable_count;
34
- public $dbtable_rows;
35
- public $dbdelete_count;
36
- public $profile_start;
37
- public $profile_end;
38
- public $start_microtime;
39
- public $dbcollatefb;
40
- public $dbobj_views;
41
- public $dbobj_procs;
42
- public $dbFileSize = 0;
43
- public $dbDefinerReplace;
44
-
45
- public function __construct($post, $start_microtime)
46
- {
47
- $this->post = $post;
48
- $this->php_mem = $GLOBALS['PHP_MEMORY_LIMIT'];
49
- $this->php_used_mem = memory_get_usage();
50
- $this->php_mem_range = 1024 * 1024;
51
- $this->root_path = $GLOBALS['DUPX_ROOT'];
52
- $this->sql_file_path = "{$GLOBALS['DUPX_INIT']}/dup-database__{$GLOBALS['DUPX_AC']->package_hash}.sql";
53
- $this->sql_result_file_path = "{$GLOBALS['DUPX_INIT']}/{$GLOBALS['SQL_FILE_NAME']}";
54
- $this->dbFileSize = @filesize($this->sql_file_path);
55
-
56
- //ESTABLISH CONNECTION
57
- $this->dbh = DUPX_DB::connect($post['dbhost'], $post['dbuser'], $post['dbpass']);
58
- ($this->dbh) or DUPX_Log::error(ERR_DBCONNECT.mysqli_connect_error());
59
- if ($_POST['dbaction'] == 'empty' || $post['dbaction'] == 'rename') {
60
- mysqli_select_db($this->dbh, $post['dbname'])
61
- or DUPX_Log::error(sprintf(ERR_DBCREATE, $post['dbname']));
62
- }
63
-
64
- @mysqli_query($this->dbh, "SET wait_timeout = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_TIME']));
65
- @mysqli_query($this->dbh, "SET GLOBAL max_allowed_packet = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_PACKETS']));
66
- @mysqli_query($this->dbh, "SET max_allowed_packet = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_PACKETS']));
67
-
68
- $this->profile_start = isset($post['profile_start']) ? DUPX_U::sanitize_text_field($post['profile_start']) : DUPX_U::getMicrotime();
69
- $this->start_microtime = isset($post['start_microtime']) ? DUPX_U::sanitize_text_field($post['start_microtime']) : $start_microtime;
70
- $this->dbvar_maxtime = DUPX_DB::getVariable($this->dbh, 'wait_timeout');
71
- $this->dbvar_maxpacks = DUPX_DB::getVariable($this->dbh, 'max_allowed_packet');
72
- $this->dbvar_sqlmode = DUPX_DB::getVariable($this->dbh, 'sql_mode');
73
- $this->dbvar_version = DUPX_DB::getVersion($this->dbh);
74
- $this->dbvar_maxtime = is_null($this->dbvar_maxtime) ? 300 : $this->dbvar_maxtime;
75
- $this->dbvar_maxpacks = is_null($this->dbvar_maxpacks) ? 1048576 : $this->dbvar_maxpacks;
76
- $this->dbvar_sqlmode = empty($this->dbvar_sqlmode) ? 'NOT_SET' : $this->dbvar_sqlmode;
77
- $this->dbDefinerReplace = '$1' . addcslashes("`" . $this->post["dbuser"] . "`@`" . $this->post["dbhost"] . "`", '\\$') . '$3';
78
- $this->dbquery_errs = isset($post['dbquery_errs']) ? DUPX_U::sanitize_text_field($post['dbquery_errs']) : 0;
79
- $this->drop_tbl_log = isset($post['drop_tbl_log']) ? DUPX_U::sanitize_text_field($post['drop_tbl_log']) : 0;
80
- $this->rename_tbl_log = isset($post['rename_tbl_log']) ? DUPX_U::sanitize_text_field($post['rename_tbl_log']) : 0;
81
- $this->dbquery_rows = isset($post['dbquery_rows']) ? DUPX_U::sanitize_text_field($post['dbquery_rows']) : 0;
82
- $this->dbdelete_count = isset($post['dbdelete_count']) ? DUPX_U::sanitize_text_field($post['dbdelete_count']) : 0;
83
- $this->dbcollatefb = isset($post['dbcollatefb']) ? DUPX_U::sanitize_text_field($post['dbcollatefb']) : 0;
84
- $this->dbobj_views = isset($post['dbobj_views']) ? DUPX_U::sanitize_text_field($post['dbobj_views']) : 0;
85
- $this->dbobj_procs = isset($post['dbobj_procs']) ? DUPX_U::sanitize_text_field($post['dbobj_procs']) : 0;
86
- }
87
-
88
- public function prepareDB()
89
- {
90
- //RUN DATABASE SCRIPT
91
- @mysqli_query($this->dbh, "SET wait_timeout = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_TIME']));
92
- @mysqli_query($this->dbh, "SET max_allowed_packet = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_PACKETS']));
93
- DUPX_DB::setCharset($this->dbh, $this->post['dbcharset'], $this->post['dbcollate']);
94
-
95
- //Will set mode to null only for this db handle session
96
- //sql_mode can cause db create issues on some systems
97
- switch ($this->post['dbmysqlmode']) {
98
- case 'DISABLE':
99
- @mysqli_query($this->dbh, "SET SESSION sql_mode = ''");
100
- break;
101
- case 'CUSTOM':
102
- $dbmysqlmode_opts = $this->post['dbmysqlmode_opts'];
103
-
104
- $qry_session_custom = @mysqli_query($this->dbh, "SET SESSION sql_mode = '".mysqli_real_escape_string($this->dbh, $dbmysqlmode_opts)."'");
105
- if ($qry_session_custom == false) {
106
- $sql_error = mysqli_error($this->dbh);
107
- $log = "WARNING: A custom sql_mode setting issue has been detected:\n{$sql_error}.\n";
108
- $log .= "For more details visit: http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html\n";
109
- }
110
- break;
111
- }
112
-
113
-
114
- //Set defaults incase the variable could not be read
115
- $this->drop_tbl_log = 0;
116
- $this->rename_tbl_log = 0;
117
- $sql_file_size = DUPX_U::readableByteSize(@filesize("{$GLOBALS['DUPX_INIT']}/dup-database__{$GLOBALS['DUPX_AC']->package_hash}.sql"));
118
- $collate_fb = $this->dbcollatefb ? 'On' : 'Off';
119
-
120
- DUPX_Log::info("--------------------------------------");
121
- DUPX_Log::info('DATABASE-ENVIRONMENT');
122
- DUPX_Log::info("--------------------------------------");
123
- DUPX_Log::info("MYSQL VERSION:\tThis Server: {$this->dbvar_version} -- Build Server: {$GLOBALS['DUPX_AC']->version_db}");
124
- DUPX_Log::info("FILE SIZE:\tdup-database__{$GLOBALS['DUPX_AC']->package_hash}.sql ({$sql_file_size})");
125
- DUPX_Log::info("TIMEOUT:\t{$this->dbvar_maxtime}");
126
- DUPX_Log::info("MAXPACK:\t{$this->dbvar_maxpacks}");
127
- DUPX_Log::info("SQLMODE:\t{$this->dbvar_sqlmode}");
128
- DUPX_Log::info("NEW SQL FILE:\t[{$this->sql_result_file_path}]");
129
- DUPX_Log::info("COLLATE FB:\t{$collate_fb}");
130
-
131
- if (version_compare($this->dbvar_version, $GLOBALS['DUPX_AC']->version_db) < 0) {
132
- DUPX_Log::info("\nNOTICE: This servers version [{$this->dbvar_version}] is less than the build version [{$GLOBALS['DUPX_AC']->version_db}]. \n"
133
- ."If you find issues after testing your site please referr to this FAQ item.\n"
134
- ."https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-260-q");
135
- }
136
-
137
- //CREATE DB
138
- switch ($this->post['dbaction']) {
139
- case "create":
140
- if ($this->post['view_mode'] == 'basic') {
141
- mysqli_query($this->dbh, "CREATE DATABASE IF NOT EXISTS `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`");
142
- }
143
- mysqli_select_db($this->dbh, mysqli_real_escape_string($this->dbh, $this->post['dbname']))
144
- or DUPX_Log::error(sprintf(ERR_DBCONNECT_CREATE, $this->post['dbname']));
145
- break;
146
-
147
- //DROP DB TABLES: DROP TABLE statement does not support views
148
- case "empty":
149
- //Drop all tables, views and procs
150
- $this->dropTables();
151
- $this->dropViews();
152
- $this->dropProcs();
153
- break;
154
-
155
- //RENAME DB TABLES
156
- case "rename" :
157
- $sql = "SHOW TABLES FROM `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."` WHERE `Tables_in_".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."` NOT LIKE '".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_RENAME_PREFIX'])."%'";
158
- $found_tables = null;
159
- if ($result = mysqli_query($this->dbh, $sql)) {
160
- while ($row = mysqli_fetch_row($result)) {
161
- $found_tables[] = $row[0];
162
- }
163
- if (count($found_tables) > 0) {
164
- foreach ($found_tables as $table_name) {
165
- $sql = "RENAME TABLE `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $table_name)."` TO `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_RENAME_PREFIX']).mysqli_real_escape_string($this->dbh, $table_name)."`";
166
- if (!$result = mysqli_query($this->dbh, $sql)) {
167
- DUPX_Log::error(sprintf(ERR_DBTRYRENAME, "{$this->post['dbname']}.{$table_name}"));
168
- }
169
- }
170
- $this->rename_tbl_log = count($found_tables);
171
- }
172
- }
173
- break;
174
- }
175
- }
176
-
177
- public function getRowCountMisMatchTables()
178
- {
179
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
180
-
181
- $tableWiseRowCounts = $GLOBALS['DUPX_AC']->dbInfo->tableWiseRowCounts;
182
- $skipTables = array(
183
- $GLOBALS['DUPX_AC']->wp_tableprefix."duplicator_packages",
184
- $GLOBALS['DUPX_AC']->wp_tableprefix."options",
185
- $GLOBALS['DUPX_AC']->wp_tableprefix."duplicator_pro_packages",
186
- $GLOBALS['DUPX_AC']->wp_tableprefix."duplicator_pro_entities",
187
- );
188
- $misMatchTables = array();
189
- foreach ($tableWiseRowCounts as $table => $rowCount) {
190
- if (in_array($table, $skipTables)) {
191
- continue;
192
- }
193
- $sql = "SELECT count(*) as cnt FROM `".mysqli_real_escape_string($this->dbh, $table)."`";
194
- $result = mysqli_query($this->dbh, $sql);
195
- if (false !== $result) {
196
- $row = mysqli_fetch_assoc($result);
197
- if ($rowCount != ($row['cnt'])) {
198
- $errMsg = 'DATABASE: table '.DUPX_Log::varToString($table).' row count mismatch; expected '.DUPX_Log::varToString($rowCount).' in database'.DUPX_Log::varToString($row['cnt']);
199
- DUPX_Log::info($errMsg);
200
- $nManager->addBothNextAndFinalReportNotice(array(
201
- 'shortMsg' => 'Database Table row count validation was failed',
202
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
203
- 'longMsg' => $errMsg."\n",
204
- 'sections' => 'database'
205
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'row-count-mismatch');
206
-
207
- $misMatchTables[] = $table;
208
- }
209
- }
210
- }
211
- return $misMatchTables;
212
- }
213
-
214
- public function writeInDB()
215
- {
216
- //WRITE DATA
217
- $fcgi_buffer_pool = 5000;
218
- $fcgi_buffer_count = 0;
219
- $counter = 0;
220
- if (!empty($sql_data)) {
221
- $this->sql_result_data = $sql_data;
222
- }
223
-
224
- $handle = fopen($this->sql_file_path, 'rb');
225
- if ($handle === false) {
226
- return false;
227
- }
228
-
229
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
230
-
231
- @mysqli_autocommit($this->dbh, false);
232
-
233
- $query = null;
234
- $delimiter = ';';
235
- while (($line = fgets($handle)) !== false) {
236
- if ('DELIMITER ;' == trim($query)) {
237
- $delimiter = ';';
238
- $query = null;
239
- continue;
240
- }
241
- $query .= $line;
242
- if (preg_match('/'.$delimiter.'\s*$/S', $query)) {
243
- $query_strlen = strlen(trim($query));
244
- if ($this->dbvar_maxpacks < $query_strlen) {
245
- $errorMsg = "**ERROR** Query size limit [length={$this->dbvar_maxpacks}] [sql=".substr($this->sql_result_data[$counter], 0, 75)."...]";
246
- $this->dbquery_errs++;
247
- $nManager->addNextStepNoticeMessage('QUERY ERROR: size limit' , DUPX_NOTICE_ITEM::SOFT_WARNING , DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'query-size-limit-msg');
248
- $nManager->addFinalReportNotice(array(
249
- 'shortMsg' => 'QUERY ERROR: size limit',
250
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
251
- 'longMsg' => $errorMsg,
252
- 'sections' => 'database'
253
- ));
254
- DUPX_Log::info($errorMsg);
255
- } elseif ($query_strlen > 0) {
256
- $query = $this->nbspFix($query);
257
- $query = $this->applyQueryCollationFallback($query);
258
- $query = $this->applyQueryProcAndViewFix($query);
259
-
260
- // $query = $this->queryDelimiterFix($query);
261
- $query = trim($query);
262
- if (0 === strpos($query, "DELIMITER")) {
263
- // Ending delimiter
264
- // control never comes in this if condition, but written
265
- if ('DELIMITER ;' == $query) {
266
- $delimiter = ';';
267
- } else { // starting delimiter
268
- $delimiter = substr($query, 10);
269
- $delimiter = trim($delimiter);
270
- }
271
-
272
- DUPX_Log::info("Skipping delimiter query");
273
- $query = null;
274
- continue;
275
- }
276
-
277
- $result = @mysqli_query($this->dbh, $query);
278
- if ($result instanceof mysqli_result){
279
- @mysqli_free_result($result);
280
- }
281
-
282
- $err = mysqli_error($this->dbh);
283
- //Check to make sure the connection is alive
284
- if (!empty($err)) {
285
- if (!mysqli_ping($this->dbh)) {
286
- mysqli_close($this->dbh);
287
- $this->dbh = DUPX_DB::connect($this->post['dbhost'], $this->post['dbuser'], $this->post['dbpass'], $this->post['dbname']);
288
- // Reset session setup
289
- @mysqli_query($this->dbh, "SET wait_timeout = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_TIME']));
290
- DUPX_DB::setCharset($this->dbh, $this->post['dbcharset'], $this->post['dbcollate']);
291
- }
292
- $errMsg = "**ERROR** database error write '{$err}' - [sql=".substr($query, 0, 75)."...]";
293
- DUPX_Log::info($errMsg);
294
-
295
- if (DUPX_U::contains($err, 'Unknown collation')) {
296
- $nManager->addNextStepNotice(array(
297
- 'shortMsg' => 'DATABASE ERROR: database error write',
298
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
299
- 'longMsg' => 'Unknown collation<br>RECOMMENDATION: Try resolutions found at https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q',
300
- 'faqLink' => array(
301
- 'url' => 'https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q',
302
- 'label' => 'FAQ Link'
303
- )
304
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'query-collation-write-msg');
305
- $nManager->addFinalReportNotice(array(
306
- 'shortMsg' => 'DATABASE ERROR: database error write',
307
- 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
308
- 'longMsg' => 'Unknown collation<br>RECOMMENDATION: Try resolutions found at https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q'.'<br>'.$errMsg,
309
- 'sections' => 'database',
310
- 'faqLink' => array(
311
- 'url' => 'https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q',
312
- 'label' => 'FAQ Link'
313
- )
314
- ));
315
- DUPX_Log::info('RECOMMENDATION: Try resolutions found at https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q');
316
- } else {
317
- $nManager->addNextStepNoticeMessage('DATABASE ERROR: database error write' , DUPX_NOTICE_ITEM::SOFT_WARNING , DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'query-write-msg');
318
- $nManager->addFinalReportNotice(array(
319
- 'shortMsg' => 'DATABASE ERROR: database error write',
320
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
321
- 'longMsg' => $errMsg,
322
- 'sections' => 'database'
323
- ));
324
- }
325
-
326
- $this->dbquery_errs++;
327
-
328
- //Buffer data to browser to keep connection open
329
- } else {
330
- if ($fcgi_buffer_count++ > $fcgi_buffer_pool) {
331
- $fcgi_buffer_count = 0;
332
- }
333
- $this->dbquery_rows++;
334
- }
335
- }
336
- $query = null;
337
- $counter++;
338
- }
339
- }
340
- @mysqli_commit($this->dbh);
341
- @mysqli_autocommit($this->dbh, true);
342
-
343
- $nManager ->saveNotices();
344
-
345
- //DATA CLEANUP: Perform Transient Cache Cleanup
346
- //Remove all duplicator entries and record this one since this is a new install.
347
- $dbdelete_count1 = 0;
348
- $dbdelete_count2 = 0;
349
-
350
- @mysqli_query($this->dbh, "DELETE FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."duplicator_packages`");
351
- $dbdelete_count1 = @mysqli_affected_rows($this->dbh);
352
-
353
- @mysqli_query($this->dbh,
354
- "DELETE FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` WHERE `option_name` LIKE ('_transient%') OR `option_name` LIKE ('_site_transient%')");
355
- $dbdelete_count2 = @mysqli_affected_rows($this->dbh);
356
-
357
- mysqli_query($this->dbh, "DELETE FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` WHERE `option_name` = 'duplicator_usage_id'");
358
- $dbdelete_count3 = @mysqli_affected_rows($this->dbh);
359
- $this->dbdelete_count += (abs($dbdelete_count1) + abs($dbdelete_count2) + abs($dbdelete_count3));
360
-
361
- //Reset Duplicator Options
362
- if (DUPX_U::isTraversable($GLOBALS['DUPX_AC']->opts_delete)) {
363
- foreach ($GLOBALS['DUPX_AC']->opts_delete as $value) {
364
- mysqli_query($this->dbh, "DELETE FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` WHERE `option_name` = '".mysqli_real_escape_string($this->dbh, $value)."'");
365
- }
366
- }
367
-
368
- //Remove views from DB
369
- if (!$this->dbobj_views) {
370
- $this->dropViews();
371
- DUPX_Log::info("DB VIEWS:\tdisabled");
372
- } else {
373
- DUPX_Log::info("DB VIEWS:\tenabled");
374
- }
375
-
376
- //Remove procedures from DB
377
- if (!$this->dbobj_procs) {
378
- $this->dropProcs();
379
- DUPX_Log::info("DB PROCEDURES:\tdisabled");
380
- } else {
381
- DUPX_Log::info("DB PROCEDURES:\tenabled");
382
- }
383
- }
384
-
385
- private function dropTables()
386
- {
387
- $sql = "SHOW FULL TABLES WHERE Table_Type != 'VIEW'";
388
- $found_tables = null;
389
- if ($result = mysqli_query($this->dbh, $sql)) {
390
- while ($row = mysqli_fetch_row($result)) {
391
- $found_tables[] = $row[0];
392
- }
393
- if ($found_tables != null && count($found_tables) > 0) {
394
- mysqli_query($this->dbh, "SET FOREIGN_KEY_CHECKS = 0;");
395
- foreach ($found_tables as $table_name) {
396
- $sql = "DROP TABLE `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $table_name)."`";
397
- if (!$result = mysqli_query($this->dbh, $sql)) {
398
- DUPX_Log::error(sprintf(ERR_DROP_TABLE_TRYCLEAN, $table_name, $this->post['dbname'], mysqli_error($this->dbh)));
399
- }
400
- }
401
- $this->drop_tbl_log = count($found_tables);
402
- mysqli_query($this->dbh, "SET FOREIGN_KEY_CHECKS = 1;");
403
- }
404
- }
405
- }
406
-
407
- private function dropProcs()
408
- {
409
- $sql = "SHOW PROCEDURE STATUS WHERE db='{$this->post['dbname']}'";
410
- $found = array();
411
- if ($result = mysqli_query($this->dbh, $sql)) {
412
- while ($row = mysqli_fetch_row($result)) {
413
- $found[] = $row[1];
414
- }
415
- if (count($found) > 0) {
416
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
417
-
418
- foreach ($found as $proc_name) {
419
- $sql = "DROP PROCEDURE IF EXISTS `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $proc_name)."`";
420
- if (!$result = mysqli_query($this->dbh, $sql)) {
421
- $err = mysqli_error($this->dbh);
422
-
423
- $nManager->addNextStepNotice(array(
424
- 'shortMsg' => 'PROCEDURE CLEAN ERROR',
425
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
426
- 'longMsg' => sprintf('Unable to remove PROCEDURE "%s" from database "%s".<br/>', $proc_name, $this->post['dbname']),
427
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
428
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'drop-proc-fail-msg');
429
-
430
- $nManager->addFinalReportNotice(array(
431
- 'shortMsg' => 'PROCEDURE CLEAN ERROR: '.$err,
432
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
433
- 'longMsg' => sprintf('Unable to remove PROCEDURE "%s" from database "%s".', $proc_name, $this->post['dbname']),
434
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
435
- 'sections' => 'database',
436
- ));
437
-
438
- DUPX_Log::info("PROCEDURE CLEAN ERROR: '{$err}'\n\t[SQL=".substr($sql, 0, self::QUERY_ERROR_LOG_LEN)."...]\n\n");
439
- }
440
- }
441
-
442
- $nManager->addNextStepNotice(array(
443
- 'shortMsg' => 'PROCEDURE CLEAN ERROR',
444
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
445
- 'longMsg' => sprintf(ERR_DROP_PROCEDURE_TRYCLEAN, mysqli_error($this->dbh)),
446
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
447
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_PREPEND_IF_EXISTS, 'drop-proc-fail-msg');
448
- }
449
- }
450
- }
451
-
452
- private function dropViews()
453
- {
454
- $sql = "SHOW FULL TABLES WHERE Table_Type = 'VIEW'";
455
- $found_views = null;
456
- if ($result = mysqli_query($this->dbh, $sql)) {
457
- while ($row = mysqli_fetch_row($result)) {
458
- $found_views[] = $row[0];
459
- }
460
- if (!is_null($found_views) && count($found_views) > 0) {
461
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
462
-
463
- foreach ($found_views as $view_name) {
464
- $sql = "DROP VIEW `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $view_name)."`";
465
- if (!$result = mysqli_query($this->dbh, $sql)) {
466
- $err = mysqli_error($this->dbh);
467
-
468
- $nManager->addNextStepNotice(array(
469
- 'shortMsg' => 'VIEW CLEAN ERROR',
470
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
471
- 'longMsg' => sprintf('Unable to remove VIEW "%s" from database "%s".<br/>', $view_name, $this->post['dbname']),
472
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
473
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'drop-view-fail-msg');
474
-
475
- $nManager->addFinalReportNotice(array(
476
- 'shortMsg' => 'VIEW CLEAN ERROR: '.$err,
477
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
478
- 'longMsg' => sprintf('Unable to remove VIEW "%s" from database "%s"', $view_name, $this->post['dbname']),
479
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
480
- 'sections' => 'database',
481
- ));
482
-
483
- DUPX_Log::info("VIEW CLEAN ERROR: '{$err}'\n\t[SQL=".substr($sql, 0, self::QUERY_ERROR_LOG_LEN)."...]\n\n");
484
- }
485
- }
486
-
487
- $nManager->addNextStepNotice(array(
488
- 'shortMsg' => 'VIEW CLEAN ERROR',
489
- 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
490
- 'longMsg' => sprintf(ERR_DROP_VIEW_TRYCLEAN, mysqli_error($this->dbh)),
491
- 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
492
- ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_PREPEND_IF_EXISTS, 'drop-view-fail-msg');
493
-
494
- }
495
- }
496
- }
497
-
498
- public function writeLog()
499
- {
500
- $nManager = DUPX_NOTICE_MANAGER::getInstance();
501
- $nManager->saveNotices();
502
-
503
- DUPX_Log::info("ERRORS FOUND:\t{$this->dbquery_errs}");
504
- DUPX_Log::info("DROPPED TABLES:\t{$this->drop_tbl_log}");
505
- DUPX_Log::info("RENAMED TABLES:\t{$this->rename_tbl_log}");
506
- DUPX_Log::info("QUERIES RAN:\t{$this->dbquery_rows}\n");
507
-
508
- $this->dbtable_rows = 1;
509
- $this->dbtable_count = 0;
510
-
511
- if ($result = mysqli_query($this->dbh, "SHOW TABLES")) {
512
- while ($row = mysqli_fetch_array($result, MYSQLI_NUM)) {
513
- $table_rows = DUPX_DB::countTableRows($this->dbh, $row[0]);
514
- $this->dbtable_rows += $table_rows;
515
- DUPX_Log::info("{$row[0]}: ({$table_rows})");
516
- $this->dbtable_count++;
517
- }
518
- @mysqli_free_result($result);
519
- }
520
-
521
- DUPX_Log::info("Removed '{$this->dbdelete_count}' cache/transient rows");
522
-
523
- if ($this->dbtable_count == 0) {
524
- DUPX_Log::info("NOTICE: You may have to manually run the installer-data.sql to validate data input.
525
- Also check to make sure your installer file is correct and the table prefix
526
- '{$GLOBALS['DUPX_AC']->wp_tableprefix}' is correct for this particular version of WordPress. \n");
527
- }
528
- }
529
-
530
- public function getJSON($json)
531
- {
532
- $json['table_count'] = $this->dbtable_count;
533
- $json['table_rows'] = $this->dbtable_rows;
534
- $json['query_errs'] = $this->dbquery_errs;
535
-
536
- return $json;
537
- }
538
-
539
- private function applyQueryCollationFallback($query) {
540
- if (!empty($this->post['dbcolsearchreplace']) && $this->post['dbcollatefb']) {
541
- $collation_replace_list = json_decode(stripslashes($this->post['dbcolsearchreplace']), true);
542
-
543
- if ($collation_replace_list === null) {
544
- DUPX_Log::info("WARNING: Cannot decode collation replace list JSON.\n", 1);
545
- return;
546
- }
547
-
548
- if (!empty($collation_replace_list)) {
549
-
550
- if ($this->firstOrNotChunking()) {
551
- DUPX_Log::info("LEGACY COLLATION FALLBACK:\n\tRunning the following replacements:\n\t".stripslashes($this->post['dbcolsearchreplace']));
552
- }
553
-
554
- foreach ($collation_replace_list as $val) {
555
- $replace_charset = false;
556
- if (strpos($val['search'], 'utf8mb4') !== false && strpos($val['replace'], 'utf8mb4') === false) {
557
- $replace_charset = true;
558
- }
559
- /*
560
- foreach ($this->sql_result_data as $key => $query) {
561
- */
562
- if (strpos($query, $val['search'])) {
563
- $query = str_replace($val['search'], $val['replace'], $query);
564
- $sub_query = str_replace("\n", '', substr($query, 0, 80));
565
- DUPX_Log::info("\tNOTICE: {$val['search']} replaced by {$val['replace']} in query [{$sub_query}...]");
566
- }
567
- if ($replace_charset && strpos($query, 'utf8mb4')) {
568
- $query = str_replace('utf8mb4', 'utf8', $query);
569
- $sub_query = str_replace("\n", '', substr($query, 0, 80));
570
- DUPX_Log::info("\tNOTICE: utf8mb4 replaced by utf8 in query [{$sub_query}...]");
571
- }
572
- /*
573
- }
574
- */
575
- }
576
- }
577
- }
578
-
579
- return $query;
580
- }
581
-
582
- private function applyProcUserFix()
583
- {
584
- foreach ($this->sql_result_data as $key => $query) {
585
- if (preg_match("/DEFINER.*PROCEDURE/", $query) === 1) {
586
- $query = preg_replace("/DEFINER.*PROCEDURE/", "PROCEDURE", $query);
587
- $query = str_replace("BEGIN", "SQL SECURITY INVOKER\nBEGIN", $query);
588
- $this->sql_result_data[$key] = $query;
589
- }
590
- }
591
- }
592
-
593
- private function applyQueryProcAndViewFix($query)
594
- {
595
- return preg_replace(array(
596
- self::USER_DEFINER_PATTERN,
597
- self::SQL_SECURITY_INVOKER_PATTERN
598
- ), array(
599
- $this->dbDefinerReplace,
600
- self::SQL_SECURITY_INVOKER_REPLACE
601
- ), $query);
602
- }
603
-
604
- private function delimiterFix($counter)
605
- {
606
- $firstQuery = trim(preg_replace('/\s\s+/', ' ', $this->sql_result_data[$counter]));
607
- $start = $counter;
608
- $end = 0;
609
- if (strpos($firstQuery, "DELIMITER") === 0) {
610
- $this->sql_result_data[$start] = "";
611
- $continueSearch = true;
612
- while ($continueSearch) {
613
- $counter++;
614
- if (strpos($this->sql_result_data[$counter], 'DELIMITER') === 0) {
615
- $continueSearch = false;
616
- unset($this->sql_result_data[$counter]);
617
- $this->sql_result_data = array_values($this->sql_result_data);
618
- } else {
619
- $this->sql_result_data[$start] .= $this->sql_result_data[$counter].";\n";
620
- unset($this->sql_result_data[$counter]);
621
- }
622
- }
623
- }
624
- }
625
-
626
- public function nbspFix($sql)
627
- {
628
- if ($this->post['dbnbsp']) {
629
- if ($this->firstOrNotChunking()) {
630
- DUPX_Log::info("ran fix non-breaking space characters\n");
631
- }
632
- $sql = preg_replace('/\xC2\xA0/', ' ', $sql);
633
- }
634
- return $sql;
635
- }
636
-
637
- public function firstOrNotChunking()
638
- {
639
- return (!isset($this->post['continue_chunking']) || $this->post['first_chunk']);
640
- }
641
-
642
- public function __destruct()
643
- {
644
- @mysqli_close($this->dbh);
645
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
646
  }
1
+ <?php
2
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+
4
+ class DUPX_DBInstall
5
+ {
6
+ const USER_DEFINER_REPLACE_PATTERN = "/^(\s*(?:\/\*!\d+\s)?\s*(?:CREATE.+)?DEFINER\s*=)(\S+)(.*)$/m";
7
+ const USER_DEFINER_REMOVE_PATTERN = "/^(\s*(?:\/\*!\d+\s)?\s*(?:CREATE.+)?)(DEFINER\s*=\s*\S+)(.*)$/m";
8
+ const SQL_SECURITY_INVOKER_PATTERN = "/^([\s\t]*CREATE.+PROCEDURE[\s\S]*)(BEGIN)([\s\S]*)$/";
9
+ const SQL_SECURITY_INVOKER_REPLACE = "$1SQL SECURITY INVOKER\n$2$3";
10
+ const QUERY_ERROR_LOG_LEN = 200;
11
+
12
+ private $dbh;
13
+ private $post;
14
+ public $sql_result_data;
15
+ public $sql_result_data_length;
16
+ public $dbvar_maxtime;
17
+ public $dbvar_maxpacks;
18
+ public $dbvar_sqlmode;
19
+ public $dbvar_version;
20
+ public $pos_in_sql;
21
+ public $sql_file_path;
22
+ public $sql_result_file_path;
23
+ public $php_mem;
24
+ public $php_mem_range;
25
+ public $php_used_mem;
26
+ public $table_count;
27
+ public $table_rows;
28
+ public $query_errs;
29
+ public $root_path;
30
+ public $drop_tbl_log;
31
+ public $rename_tbl_log;
32
+ public $dbquery_errs;
33
+ public $dbquery_rows;
34
+ public $dbtable_count;
35
+ public $dbtable_rows;
36
+ public $dbdelete_count;
37
+ public $profile_start;
38
+ public $profile_end;
39
+ public $start_microtime;
40
+ public $dbcollatefb;
41
+ public $dbobj_views;
42
+ public $dbobj_procs;
43
+ public $dbRemoveDefiner;
44
+ public $dbFileSize = 0;
45
+ public $dbDefinerReplace;
46
+
47
+ public function __construct($post, $start_microtime)
48
+ {
49
+ $this->post = $post;
50
+ $this->php_mem = $GLOBALS['PHP_MEMORY_LIMIT'];
51
+ $this->php_used_mem = memory_get_usage();
52
+ $this->php_mem_range = 1024 * 1024;
53
+ $this->root_path = $GLOBALS['DUPX_ROOT'];
54
+ $this->sql_file_path = "{$GLOBALS['DUPX_INIT']}/dup-database__{$GLOBALS['DUPX_AC']->package_hash}.sql";
55
+ $this->sql_result_file_path = "{$GLOBALS['DUPX_INIT']}/{$GLOBALS['SQL_FILE_NAME']}";
56
+ $this->dbFileSize = @filesize($this->sql_file_path);
57
+
58
+ //ESTABLISH CONNECTION
59
+ $this->dbh = DUPX_DB::connect($post['dbhost'], $post['dbuser'], $post['dbpass']);
60
+ ($this->dbh) or DUPX_Log::error(ERR_DBCONNECT.mysqli_connect_error());
61
+ if ($_POST['dbaction'] == 'empty' || $post['dbaction'] == 'rename') {
62
+ mysqli_select_db($this->dbh, $post['dbname'])
63
+ or DUPX_Log::error(sprintf(ERR_DBCREATE, $post['dbname']));
64
+ }
65
+
66
+ @mysqli_query($this->dbh, "SET wait_timeout = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_TIME']));
67
+ @mysqli_query($this->dbh, "SET GLOBAL max_allowed_packet = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_PACKETS']));
68
+ @mysqli_query($this->dbh, "SET max_allowed_packet = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_PACKETS']));
69
+
70
+ $this->profile_start = isset($post['profile_start']) ? DUPX_U::sanitize_text_field($post['profile_start']) : DUPX_U::getMicrotime();
71
+ $this->start_microtime = isset($post['start_microtime']) ? DUPX_U::sanitize_text_field($post['start_microtime']) : $start_microtime;
72
+ $this->dbvar_maxtime = DUPX_DB::getVariable($this->dbh, 'wait_timeout');
73
+ $this->dbvar_maxpacks = DUPX_DB::getVariable($this->dbh, 'max_allowed_packet');
74
+ $this->dbvar_sqlmode = DUPX_DB::getVariable($this->dbh, 'sql_mode');
75
+ $this->dbvar_version = DUPX_DB::getVersion($this->dbh);
76
+ $this->dbvar_maxtime = is_null($this->dbvar_maxtime) ? 300 : $this->dbvar_maxtime;
77
+ $this->dbvar_maxpacks = is_null($this->dbvar_maxpacks) ? 1048576 : $this->dbvar_maxpacks;
78
+ $this->dbvar_sqlmode = empty($this->dbvar_sqlmode) ? 'NOT_SET' : $this->dbvar_sqlmode;
79
+ $definerHost = $this->post["dbhost"] == "localhost" || $this->post["dbhost"] == "127.0.0.1" ? $this->post["dbhost"] : '%';
80
+ $this->dbDefinerReplace = '$1' . addcslashes("`" . $this->post["dbuser"] . "`@`" . $definerHost . "`", '\\$') . '$3';
81
+ $this->dbquery_errs = isset($post['dbquery_errs']) ? DUPX_U::sanitize_text_field($post['dbquery_errs']) : 0;
82
+ $this->drop_tbl_log = isset($post['drop_tbl_log']) ? DUPX_U::sanitize_text_field($post['drop_tbl_log']) : 0;
83
+ $this->rename_tbl_log = isset($post['rename_tbl_log']) ? DUPX_U::sanitize_text_field($post['rename_tbl_log']) : 0;
84
+ $this->dbquery_rows = isset($post['dbquery_rows']) ? DUPX_U::sanitize_text_field($post['dbquery_rows']) : 0;
85
+ $this->dbdelete_count = isset($post['dbdelete_count']) ? DUPX_U::sanitize_text_field($post['dbdelete_count']) : 0;
86
+ $this->dbcollatefb = isset($post['dbcollatefb']) ? DUPX_U::sanitize_text_field($post['dbcollatefb']) : 0;
87
+ $this->dbobj_views = isset($post['dbobj_views']) ? DUPX_U::sanitize_text_field($post['dbobj_views']) : 0;
88
+ $this->dbobj_procs = isset($post['dbobj_procs']) ? DUPX_U::sanitize_text_field($post['dbobj_procs']) : 0;
89
+ $this->dbRemoveDefiner = isset($post['db_remove_definer']) ? DUPX_U::sanitize_text_field($post['db_remove_definer']) : 0;
90
+ }
91
+
92
+ public function prepareDB()
93
+ {
94
+ //RUN DATABASE SCRIPT
95
+ @mysqli_query($this->dbh, "SET wait_timeout = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_TIME']));
96
+ @mysqli_query($this->dbh, "SET max_allowed_packet = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_PACKETS']));
97
+ DUPX_DB::setCharset($this->dbh, $this->post['dbcharset'], $this->post['dbcollate']);
98
+
99
+ //Will set mode to null only for this db handle session
100
+ //sql_mode can cause db create issues on some systems
101
+ switch ($this->post['dbmysqlmode']) {
102
+ case 'DISABLE':
103
+ @mysqli_query($this->dbh, "SET SESSION sql_mode = ''");
104
+ break;
105
+ case 'CUSTOM':
106
+ $dbmysqlmode_opts = $this->post['dbmysqlmode_opts'];
107
+
108
+ $qry_session_custom = @mysqli_query($this->dbh, "SET SESSION sql_mode = '".mysqli_real_escape_string($this->dbh, $dbmysqlmode_opts)."'");
109
+ if ($qry_session_custom == false) {
110
+ $sql_error = mysqli_error($this->dbh);
111
+ $log = "WARNING: A custom sql_mode setting issue has been detected:\n{$sql_error}.\n";
112
+ $log .= "For more details visit: http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html\n";
113
+ }
114
+ break;
115
+ }
116
+
117
+
118
+ //Set defaults incase the variable could not be read
119
+ $this->drop_tbl_log = 0;
120
+ $this->rename_tbl_log = 0;
121
+ $sql_file_size = DUPX_U::readableByteSize(@filesize("{$GLOBALS['DUPX_INIT']}/dup-database__{$GLOBALS['DUPX_AC']->package_hash}.sql"));
122
+ $collate_fb = $this->dbcollatefb ? 'On' : 'Off';
123
+
124
+ DUPX_Log::info("--------------------------------------");
125
+ DUPX_Log::info('DATABASE-ENVIRONMENT');
126
+ DUPX_Log::info("--------------------------------------");
127
+ DUPX_Log::info("MYSQL VERSION:\tThis Server: {$this->dbvar_version} -- Build Server: {$GLOBALS['DUPX_AC']->version_db}");
128
+ DUPX_Log::info("FILE SIZE:\tdup-database__{$GLOBALS['DUPX_AC']->package_hash}.sql ({$sql_file_size})");
129
+ DUPX_Log::info("TIMEOUT:\t{$this->dbvar_maxtime}");
130
+ DUPX_Log::info("MAXPACK:\t{$this->dbvar_maxpacks}");
131
+ DUPX_Log::info("SQLMODE:\t{$this->dbvar_sqlmode}");
132
+ DUPX_Log::info("NEW SQL FILE:\t[{$this->sql_result_file_path}]");
133
+ DUPX_Log::info("COLLATE FB:\t{$collate_fb}");
134
+
135
+ if (version_compare($this->dbvar_version, $GLOBALS['DUPX_AC']->version_db) < 0) {
136
+ DUPX_Log::info("\nNOTICE: This servers version [{$this->dbvar_version}] is less than the build version [{$GLOBALS['DUPX_AC']->version_db}]. \n"
137
+ ."If you find issues after testing your site please referr to this FAQ item.\n"
138
+ ."https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-260-q");
139
+ }
140
+
141
+ //CREATE DB
142
+ switch ($this->post['dbaction']) {
143
+ case "create":
144
+ if ($this->post['view_mode'] == 'basic') {
145
+ mysqli_query($this->dbh, "CREATE DATABASE IF NOT EXISTS `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`");
146
+ }
147
+ mysqli_select_db($this->dbh, mysqli_real_escape_string($this->dbh, $this->post['dbname']))
148
+ or DUPX_Log::error(sprintf(ERR_DBCONNECT_CREATE, $this->post['dbname']));
149
+ break;
150
+
151
+ //DROP DB TABLES: DROP TABLE statement does not support views
152
+ case "empty":
153
+ //Drop all tables, views and procs
154
+ $this->dropTables();
155
+ $this->dropViews();
156
+ $this->dropProcs();
157
+ break;
158
+
159
+ //RENAME DB TABLES
160
+ case "rename" :
161
+ $sql = "SHOW TABLES FROM `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."` WHERE `Tables_in_".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."` NOT LIKE '".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_RENAME_PREFIX'])."%'";
162
+ $found_tables = null;
163
+ if ($result = mysqli_query($this->dbh, $sql)) {
164
+ while ($row = mysqli_fetch_row($result)) {
165
+ $found_tables[] = $row[0];
166
+ }
167
+ if (count($found_tables) > 0) {
168
+ foreach ($found_tables as $table_name) {
169
+ $sql = "RENAME TABLE `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $table_name)."` TO `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_RENAME_PREFIX']).mysqli_real_escape_string($this->dbh, $table_name)."`";
170
+ if (!$result = mysqli_query($this->dbh, $sql)) {
171
+ DUPX_Log::error(sprintf(ERR_DBTRYRENAME, "{$this->post['dbname']}.{$table_name}"));
172
+ }
173
+ }
174
+ $this->rename_tbl_log = count($found_tables);
175
+ }
176
+ }
177
+ break;
178
+ }
179
+ }
180
+
181
+ public function getRowCountMisMatchTables()
182
+ {
183
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
184
+
185
+ $tableWiseRowCounts = $GLOBALS['DUPX_AC']->dbInfo->tableWiseRowCounts;
186
+ $skipTables = array(
187
+ $GLOBALS['DUPX_AC']->wp_tableprefix."duplicator_packages",
188
+ $GLOBALS['DUPX_AC']->wp_tableprefix."options",
189
+ $GLOBALS['DUPX_AC']->wp_tableprefix."duplicator_pro_packages",
190
+ $GLOBALS['DUPX_AC']->wp_tableprefix."duplicator_pro_entities",
191
+ );
192
+ $misMatchTables = array();
193
+ foreach ($tableWiseRowCounts as $table => $rowCount) {
194
+ if (in_array($table, $skipTables)) {
195
+ continue;
196
+ }
197
+ $sql = "SELECT count(*) as cnt FROM `".mysqli_real_escape_string($this->dbh, $table)."`";
198
+ $result = mysqli_query($this->dbh, $sql);
199
+ if (false !== $result) {
200
+ $row = mysqli_fetch_assoc($result);
201
+ if ($rowCount != ($row['cnt'])) {
202
+ $errMsg = 'DATABASE: table '.DUPX_Log::varToString($table).' row count mismatch; expected '.DUPX_Log::varToString($rowCount).' in database'.DUPX_Log::varToString($row['cnt']);
203
+ DUPX_Log::info($errMsg);
204
+ $nManager->addBothNextAndFinalReportNotice(array(
205
+ 'shortMsg' => 'Database Table row count validation was failed',
206
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
207
+ 'longMsg' => $errMsg."\n",
208
+ 'sections' => 'database'
209
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'row-count-mismatch');
210
+
211
+ $misMatchTables[] = $table;
212
+ }
213
+ }
214
+ }
215
+ return $misMatchTables;
216
+ }
217
+
218
+ public function writeInDB()
219
+ {
220
+ //WRITE DATA
221
+ $fcgi_buffer_pool = 5000;
222
+ $fcgi_buffer_count = 0;
223
+ $counter = 0;
224
+ if (!empty($sql_data)) {
225
+ $this->sql_result_data = $sql_data;
226
+ }
227
+
228
+ $handle = fopen($this->sql_file_path, 'rb');
229
+ if ($handle === false) {
230
+ return false;
231
+ }
232
+
233
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
234
+
235
+ @mysqli_autocommit($this->dbh, false);
236
+
237
+ $query = null;
238
+ $delimiter = ';';
239
+ while (($line = fgets($handle)) !== false) {
240
+ if ('DELIMITER ;' == trim($query)) {
241
+ $delimiter = ';';
242
+ $query = null;
243
+ continue;
244
+ }
245
+ $query .= $line;
246
+ if (preg_match('/'.$delimiter.'\s*$/S', $query)) {
247
+ $query_strlen = strlen(trim($query));
248
+ if ($this->dbvar_maxpacks < $query_strlen) {
249
+ $errorMsg = "**ERROR** Query size limit [length={$this->dbvar_maxpacks}] [sql=".substr($this->sql_result_data[$counter], 0, 75)."...]";
250
+ $this->dbquery_errs++;
251
+ $nManager->addNextStepNoticeMessage('QUERY ERROR: size limit' , DUPX_NOTICE_ITEM::SOFT_WARNING , DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'query-size-limit-msg');
252
+ $nManager->addFinalReportNotice(array(
253
+ 'shortMsg' => 'QUERY ERROR: size limit',
254
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
255
+ 'longMsg' => $errorMsg,
256
+ 'sections' => 'database'
257
+ ));
258
+ DUPX_Log::info($errorMsg);
259
+ } elseif ($query_strlen > 0) {
260
+ $query = $this->nbspFix($query);
261
+ $query = $this->applyQueryCollationFallback($query);
262
+ $query = $this->applyQueryProcAndViewFix($query);
263
+
264
+ // $query = $this->queryDelimiterFix($query);
265
+ $query = trim($query);
266
+ if (0 === strpos($query, "DELIMITER")) {
267
+ // Ending delimiter
268
+ // control never comes in this if condition, but written
269
+ if ('DELIMITER ;' == $query) {
270
+ $delimiter = ';';
271
+ } else { // starting delimiter
272
+ $delimiter = substr($query, 10);
273
+ $delimiter = trim($delimiter);
274
+ }
275
+
276
+ DUPX_Log::info("Skipping delimiter query");
277
+ $query = null;
278
+ continue;
279
+ }
280
+
281
+ $result = @mysqli_query($this->dbh, $query);
282
+ if ($result instanceof mysqli_result){
283
+ @mysqli_free_result($result);
284
+ }
285
+
286
+ $err = mysqli_error($this->dbh);
287
+ //Check to make sure the connection is alive
288
+ if (!empty($err)) {
289
+ if (!mysqli_ping($this->dbh)) {
290
+ mysqli_close($this->dbh);
291
+ $this->dbh = DUPX_DB::connect($this->post['dbhost'], $this->post['dbuser'], $this->post['dbpass'], $this->post['dbname']);
292
+ // Reset session setup
293
+ @mysqli_query($this->dbh, "SET wait_timeout = ".mysqli_real_escape_string($this->dbh, $GLOBALS['DB_MAX_TIME']));
294
+ DUPX_DB::setCharset($this->dbh, $this->post['dbcharset'], $this->post['dbcollate']);
295
+ }
296
+ $errMsg = "**ERROR** database error write '{$err}' - [sql=".substr($query, 0, 75)."...]";
297
+ DUPX_Log::info($errMsg);
298
+
299
+ if (DUPX_U::contains($err, 'Unknown collation')) {
300
+ $nManager->addNextStepNotice(array(
301
+ 'shortMsg' => 'DATABASE ERROR: database error write',
302
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
303
+ 'longMsg' => 'Unknown collation<br>RECOMMENDATION: Try resolutions found at https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q',
304
+ 'faqLink' => array(
305
+ 'url' => 'https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q',
306
+ 'label' => 'FAQ Link'
307
+ )
308
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'query-collation-write-msg');
309
+ $nManager->addFinalReportNotice(array(
310
+ 'shortMsg' => 'DATABASE ERROR: database error write',
311
+ 'level' => DUPX_NOTICE_ITEM::HARD_WARNING,
312
+ 'longMsg' => 'Unknown collation<br>RECOMMENDATION: Try resolutions found at https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q'.'<br>'.$errMsg,
313
+ 'sections' => 'database',
314
+ 'faqLink' => array(
315
+ 'url' => 'https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q',
316
+ 'label' => 'FAQ Link'
317
+ )
318
+ ));
319
+ DUPX_Log::info('RECOMMENDATION: Try resolutions found at https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-110-q');
320
+ } else {
321
+ $nManager->addNextStepNoticeMessage('DATABASE ERROR: database error write' , DUPX_NOTICE_ITEM::SOFT_WARNING , DUPX_NOTICE_MANAGER::ADD_UNIQUE , 'query-write-msg');
322
+ $nManager->addFinalReportNotice(array(
323
+ 'shortMsg' => 'DATABASE ERROR: database error write',
324
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
325
+ 'longMsg' => $errMsg,
326
+ 'sections' => 'database'
327
+ ));
328
+ }
329
+
330
+ $this->dbquery_errs++;
331
+
332
+ //Buffer data to browser to keep connection open
333
+ } else {
334
+ if ($fcgi_buffer_count++ > $fcgi_buffer_pool) {
335
+ $fcgi_buffer_count = 0;
336
+ }
337
+ $this->dbquery_rows++;
338
+ }
339
+ }
340
+ $query = null;
341
+ $counter++;
342
+ }
343
+ }
344
+ @mysqli_commit($this->dbh);
345
+ @mysqli_autocommit($this->dbh, true);
346
+
347
+ $nManager ->saveNotices();
348
+
349
+ //DATA CLEANUP: Perform Transient Cache Cleanup
350
+ //Remove all duplicator entries and record this one since this is a new install.
351
+ $dbdelete_count1 = 0;
352
+ $dbdelete_count2 = 0;
353
+
354
+ @mysqli_query($this->dbh, "DELETE FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."duplicator_packages`");
355
+ $dbdelete_count1 = @mysqli_affected_rows($this->dbh);
356
+
357
+ @mysqli_query($this->dbh,
358
+ "DELETE FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` WHERE `option_name` LIKE ('_transient%') OR `option_name` LIKE ('_site_transient%')");
359
+ $dbdelete_count2 = @mysqli_affected_rows($this->dbh);
360
+
361
+ mysqli_query($this->dbh, "DELETE FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` WHERE `option_name` = 'duplicator_usage_id'");
362
+ $dbdelete_count3 = @mysqli_affected_rows($this->dbh);
363
+ $this->dbdelete_count += (abs($dbdelete_count1) + abs($dbdelete_count2) + abs($dbdelete_count3));
364
+
365
+ //Reset Duplicator Options
366
+ if (DUPX_U::isTraversable($GLOBALS['DUPX_AC']->opts_delete)) {
367
+ foreach ($GLOBALS['DUPX_AC']->opts_delete as $value) {
368
+ mysqli_query($this->dbh, "DELETE FROM `".mysqli_real_escape_string($this->dbh, $GLOBALS['DUPX_AC']->wp_tableprefix)."options` WHERE `option_name` = '".mysqli_real_escape_string($this->dbh, $value)."'");
369
+ }
370
+ }
371
+
372
+ //Remove views from DB
373
+ if (!$this->dbobj_views) {
374
+ $this->dropViews();
375
+ DUPX_Log::info("DB VIEWS:\tdisabled");
376
+ } else {
377
+ DUPX_Log::info("DB VIEWS:\tenabled");
378
+ }
379
+
380
+ //Remove procedures from DB
381
+ if (!$this->dbobj_procs) {
382
+ $this->dropProcs();
383
+ DUPX_Log::info("DB PROCEDURES:\tdisabled");
384
+ } else {
385
+ DUPX_Log::info("DB PROCEDURES:\tenabled");
386
+ }
387
+ }
388
+
389
+ private function dropTables()
390
+ {
391
+ $sql = "SHOW FULL TABLES WHERE Table_Type != 'VIEW'";
392
+ $found_tables = null;
393
+ if ($result = mysqli_query($this->dbh, $sql)) {
394
+ while ($row = mysqli_fetch_row($result)) {
395
+ $found_tables[] = $row[0];
396
+ }
397
+ if ($found_tables != null && count($found_tables) > 0) {
398
+ mysqli_query($this->dbh, "SET FOREIGN_KEY_CHECKS = 0;");
399
+ foreach ($found_tables as $table_name) {
400
+ $sql = "DROP TABLE `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $table_name)."`";
401
+ if (!$result = mysqli_query($this->dbh, $sql)) {
402
+ DUPX_Log::error(sprintf(ERR_DROP_TABLE_TRYCLEAN, $table_name, $this->post['dbname'], mysqli_error($this->dbh)));
403
+ }
404
+ }
405
+ $this->drop_tbl_log = count($found_tables);
406
+ mysqli_query($this->dbh, "SET FOREIGN_KEY_CHECKS = 1;");
407
+ }
408
+ }
409
+ }
410
+
411
+ private function dropProcs()
412
+ {
413
+ $sql = "SHOW PROCEDURE STATUS WHERE db='{$this->post['dbname']}'";
414
+ $found = array();
415
+ if ($result = mysqli_query($this->dbh, $sql)) {
416
+ while ($row = mysqli_fetch_row($result)) {
417
+ $found[] = $row[1];
418
+ }
419
+ if (count($found) > 0) {
420
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
421
+
422
+ foreach ($found as $proc_name) {
423
+ $sql = "DROP PROCEDURE IF EXISTS `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $proc_name)."`";
424
+ if (!$result = mysqli_query($this->dbh, $sql)) {
425
+ $err = mysqli_error($this->dbh);
426
+
427
+ $nManager->addNextStepNotice(array(
428
+ 'shortMsg' => 'PROCEDURE CLEAN ERROR',
429
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
430
+ 'longMsg' => sprintf('Unable to remove PROCEDURE "%s" from database "%s".<br/>', $proc_name, $this->post['dbname']),
431
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
432
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'drop-proc-fail-msg');
433
+
434
+ $nManager->addFinalReportNotice(array(
435
+ 'shortMsg' => 'PROCEDURE CLEAN ERROR: '.$err,
436
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
437
+ 'longMsg' => sprintf('Unable to remove PROCEDURE "%s" from database "%s".', $proc_name, $this->post['dbname']),
438
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
439
+ 'sections' => 'database',
440
+ ));
441
+
442
+ DUPX_Log::info("PROCEDURE CLEAN ERROR: '{$err}'\n\t[SQL=".substr($sql, 0, self::QUERY_ERROR_LOG_LEN)."...]\n\n");
443
+ }
444
+ }
445
+
446
+ $nManager->addNextStepNotice(array(
447
+ 'shortMsg' => 'PROCEDURE CLEAN ERROR',
448
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
449
+ 'longMsg' => sprintf(ERR_DROP_PROCEDURE_TRYCLEAN, mysqli_error($this->dbh)),
450
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
451
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_PREPEND_IF_EXISTS, 'drop-proc-fail-msg');
452
+ }
453
+ }
454
+ }
455
+
456
+ private function dropViews()
457
+ {
458
+ $sql = "SHOW FULL TABLES WHERE Table_Type = 'VIEW'";
459
+ $found_views = null;
460
+ if ($result = mysqli_query($this->dbh, $sql)) {
461
+ while ($row = mysqli_fetch_row($result)) {
462
+ $found_views[] = $row[0];
463
+ }
464
+ if (!is_null($found_views) && count($found_views) > 0) {
465
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
466
+
467
+ foreach ($found_views as $view_name) {
468
+ $sql = "DROP VIEW `".mysqli_real_escape_string($this->dbh, $this->post['dbname'])."`.`".mysqli_real_escape_string($this->dbh, $view_name)."`";
469
+ if (!$result = mysqli_query($this->dbh, $sql)) {
470
+ $err = mysqli_error($this->dbh);
471
+
472
+ $nManager->addNextStepNotice(array(
473
+ 'shortMsg' => 'VIEW CLEAN ERROR',
474
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
475
+ 'longMsg' => sprintf('Unable to remove VIEW "%s" from database "%s".<br/>', $view_name, $this->post['dbname']),
476
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
477
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_APPEND, 'drop-view-fail-msg');
478
+
479
+ $nManager->addFinalReportNotice(array(
480
+ 'shortMsg' => 'VIEW CLEAN ERROR: '.$err,
481
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
482
+ 'longMsg' => sprintf('Unable to remove VIEW "%s" from database "%s"', $view_name, $this->post['dbname']),
483
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
484
+ 'sections' => 'database',
485
+ ));
486
+
487
+ DUPX_Log::info("VIEW CLEAN ERROR: '{$err}'\n\t[SQL=".substr($sql, 0, self::QUERY_ERROR_LOG_LEN)."...]\n\n");
488
+ }
489
+ }
490
+
491
+ $nManager->addNextStepNotice(array(
492
+ 'shortMsg' => 'VIEW CLEAN ERROR',
493
+ 'level' => DUPX_NOTICE_ITEM::SOFT_WARNING,
494
+ 'longMsg' => sprintf(ERR_DROP_VIEW_TRYCLEAN, mysqli_error($this->dbh)),
495
+ 'longMsgMode' => DUPX_NOTICE_ITEM::MSG_MODE_HTML,
496
+ ), DUPX_NOTICE_MANAGER::ADD_UNIQUE_PREPEND_IF_EXISTS, 'drop-view-fail-msg');
497
+
498
+ }
499
+ }
500
+ }
501
+
502
+ public function writeLog()
503
+ {
504
+ $nManager = DUPX_NOTICE_MANAGER::getInstance();
505
+ $nManager->saveNotices();
506
+
507
+ DUPX_Log::info("ERRORS FOUND:\t{$this->dbquery_errs}");
508
+ DUPX_Log::info("DROPPED TABLES:\t{$this->drop_tbl_log}");
509
+ DUPX_Log::info("RENAMED TABLES:\t{$this->rename_tbl_log}");
510
+ DUPX_Log::info("QUERIES RAN:\t{$this->dbquery_rows}\n");
511
+
512
+ $this->dbtable_rows = 1;
513
+ $this->dbtable_count = 0;
514
+
515
+ if ($result = mysqli_query($this->dbh, "SHOW TABLES")) {
516
+ while ($row = mysqli_fetch_array($result, MYSQLI_NUM)) {
517
+ $table_rows = DUPX_DB::countTableRows($this->dbh, $row[0]);
518
+ $this->dbtable_rows += $table_rows;
519
+ DUPX_Log::info("{$row[0]}: ({$table_rows})");
520
+ $this->dbtable_count++;
521
+ }
522
+ @mysqli_free_result($result);
523
+ }
524
+
525
+ DUPX_Log::info("Removed '{$this->dbdelete_count}' cache/transient rows");
526
+
527
+ if ($this->dbtable_count == 0) {
528
+ DUPX_Log::info("NOTICE: You may have to manually run the installer-data.sql to validate data input.
529
+ Also check to make sure your installer file is correct and the table prefix
530
+ '{$GLOBALS['DUPX_AC']->wp_tableprefix}' is correct for this particular version of WordPress. \n");
531
+ }
532
+ }
533
+
534
+ public function getJSON($json)
535
+ {
536
+ $json['table_count'] = $this->dbtable_count;
537
+ $json['table_rows'] = $this->dbtable_rows;
538
+ $json['query_errs'] = $this->dbquery_errs;
539
+
540
+ return $json;
541
+ }
542
+
543
+ private function applyQueryCollationFallback($query) {
544
+ if (!empty($this->post['dbcolsearchreplace']) && $this->post['dbcollatefb']) {
545
+ $collation_replace_list = json_decode(stripslashes($this->post['dbcolsearchreplace']), true);
546
+
547
+ if ($collation_replace_list === null) {
548
+ DUPX_Log::info("WARNING: Cannot decode collation replace list JSON.\n", 1);
549
+ return;
550
+ }
551
+
552
+ if (!empty($collation_replace_list)) {
553
+
554
+ if ($this->firstOrNotChunking()) {
555
+ DUPX_Log::info("LEGACY COLLATION FALLBACK:\n\tRunning the following replacements:\n\t".stripslashes($this->post['dbcolsearchreplace']));
556
+ }
557
+
558
+ foreach ($collation_replace_list as $val) {
559
+ $replace_charset = false;
560
+ if (strpos($val['search'], 'utf8mb4') !== false && strpos($val['replace'], 'utf8mb4') === false) {
561
+ $replace_charset = true;
562
+ }
563
+ /*
564
+ foreach ($this->sql_result_data as $key => $query) {
565
+ */
566
+ if (strpos($query, $val['search'])) {
567
+ $query = str_replace($val['search'], $val['replace'], $query);
568
+ $sub_query = str_replace("\n", '', substr($query, 0, 80));
569
+ DUPX_Log::info("\tNOTICE: {$val['search']} replaced by {$val['replace']} in query [{$sub_query}...]");
570
+ }
571
+ if ($replace_charset && strpos($query, 'utf8mb4')) {
572
+ $query = str_replace('utf8mb4', 'utf8', $query);
573
+ $sub_query = str_replace("\n", '', substr($query, 0, 80));
574
+ DUPX_Log::info("\tNOTICE: utf8mb4 replaced by utf8 in query [{$sub_query}...]");
575
+ }
576
+ /*
577
+ }
578
+ */
579
+ }
580
+ }
581
+ }
582
+
583
+ return $query;
584
+ }
585
+
586
+ private function applyProcUserFix()
587
+ {
588
+ foreach ($this->sql_result_data as $key => $query) {
589
+ if (preg_match("/DEFINER.*PROCEDURE/", $query) === 1) {
590
+ $query = preg_replace("/DEFINER.*PROCEDURE/", "PROCEDURE", $query);
591
+ $query = str_replace("BEGIN", "SQL SECURITY INVOKER\nBEGIN", $query);
592
+ $this->sql_result_data[$key] = $query;
593
+ }
594
+ }
595
+ }
596
+
597
+ private function applyQueryProcAndViewFix($query)
598
+ {
599
+ static $replaceRules = null;
600
+ if (is_null($replaceRules)) {
601
+ $replaceRules['patterns'] = array(
602
+ self::USER_DEFINER_REPLACE_PATTERN,
603
+ self::SQL_SECURITY_INVOKER_PATTERN
604
+ );
605
+
606
+ $replaceRules['replaces'] = array(
607
+ $this->dbDefinerReplace,
608
+ self::SQL_SECURITY_INVOKER_REPLACE
609
+ );
610
+
611
+ if ($this->dbRemoveDefiner) {
612
+ //No need to run the definer replace if we are removing them
613
+ $replaceRules['patterns'][0] = self::USER_DEFINER_REMOVE_PATTERN;
614
+ $replaceRules['replaces'][0] = "$1 $3";
615
+ }
616
+ }
617
+
618
+ $fixedQuery = preg_replace($replaceRules['patterns'], $replaceRules['replaces'], $query);
619
+
620
+ if ($fixedQuery !== $query) {
621
+ DUPX_Log::info("REPLACED DEFINER/INVOKER IN QUERY: [sql=".$fixedQuery."]", DUPX_Log::LV_DEBUG);
622
+ }
623
+
624
+ return $fixedQuery;
625
+ }
626
+
627
+ private function delimiterFix($counter)
628
+ {
629
+ $firstQuery = trim(preg_replace('/\s\s+/', ' ', $this->sql_result_data[$counter]));
630
+ $start = $counter;
631
+ $end = 0;
632
+ if (strpos($firstQuery, "DELIMITER") === 0) {
633
+ $this->sql_result_data[$start] = "";
634
+ $continueSearch = true;
635
+ while ($continueSearch) {
636
+ $counter++;
637
+ if (strpos($this->sql_result_data[$counter], 'DELIMITER') === 0) {
638
+ $continueSearch = false;
639
+ unset($this->sql_result_data[$counter]);
640
+ $this->sql_result_data = array_values($this->sql_result_data);
641
+ } else {
642
+ $this->sql_result_data[$start] .= $this->sql_result_data[$counter].";\n";
643
+ unset($this->sql_result_data[$counter]);
644
+ }
645
+ }
646
+ }
647
+ }
648
+
649
+ public function nbspFix($sql)
650
+ {
651
+ if ($this->post['dbnbsp']) {
652
+ if ($this->firstOrNotChunking()) {
653
+ DUPX_Log::info("ran fix non-breaking space characters\n");
654
+ }
655
+ $sql = preg_replace('/\xC2\xA0/', ' ', $sql);
656
+ }
657
+ return $sql;
658
+ }
659
+
660
+ public function firstOrNotChunking()
661
+ {
662
+ return (!isset($this->post['continue_chunking']) || $this->post['first_chunk']);
663
+ }
664
+
665
+ public function __destruct()
666
+ {
667
+ @mysqli_close($this->dbh);
668
+ }
669
  }
installer/dup-installer/ctrls/ctrl.s2.dbtest.php CHANGED
@@ -80,6 +80,7 @@ class DUPX_DBTest
80
  $this->reqs[80] = array('title' => "Check GTID mode", 'info' => "{$default_msg}", 'pass' => -1);
81
  //NOTICES
82
  $this->notices[10] = array('title' => "Table Case Sensitivity", 'info' => "{$default_msg}", 'pass' => -1);
 
83
  }
84
 
85
  public function run()
@@ -143,6 +144,7 @@ class DUPX_DBTest
143
 
144
  //NOTICES
145
  $this->n10All($this->notices[10]);
 
146
  $this->r70All($this->reqs[70]);
147
  $this->r80All($this->reqs[80]);
148
  $this->basicCleanup();
@@ -400,32 +402,23 @@ class DUPX_DBTest
400
  $invalid_match = 0;
401
 
402
  foreach($this->collationStatus as $key => $val) {
403
-
404
  if ($this->collationStatus[$key]['found'] == 0) {
405
  if($this->in->dbcollatefb){
406
  $not_supported_col = $this->collationStatus[$key]['name'];
407
- //returns false or key
408
- $i = array_search($not_supported_col,$collation_arr);
409
-
410
- if($i !== false){
411
- ++$i;
412
- for($i; $i < $collation_arr_max; $i++) {
413
-
414
- $col_status = DUPX_DB::getCollationStatus($this->dbh, array($collation_arr[$i]));
415
- $cur_col_is_supported = $col_status[0]['found'];
416
- if($cur_col_is_supported){
417
- $this->collationReplaceList[] = array(
418
- 'search' => $not_supported_col,
419
- 'replace' => $collation_arr[$i]
420
- );
421
- ++$invalid_match;
422
- break;
423
- }
424
- }
425
- } else {
426
- $invalid = 1;
427
- break;
428
- }
429
  } else {
430
  $invalid = 1;
431
  break;
@@ -544,6 +537,32 @@ class DUPX_DBTest
544
  }
545
  }
546
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  /**
548
  * Input has UTF8 data
549
  *
80
  $this->reqs[80] = array('title' => "Check GTID mode", 'info' => "{$default_msg}", 'pass' => -1);
81
  //NOTICES
82
  $this->notices[10] = array('title' => "Table Case Sensitivity", 'info' => "{$default_msg}", 'pass' => -1);
83
+ $this->notices[20] = array('title' => "Source Site Triggers", 'info' => "{$default_msg}", 'pass' => -1);
84
  }
85
 
86
  public function run()
144
 
145
  //NOTICES
146
  $this->n10All($this->notices[10]);
147
+ $this->n20All($this->notices[20]);
148
  $this->r70All($this->reqs[70]);
149
  $this->r80All($this->reqs[80]);
150
  $this->basicCleanup();
402
  $invalid_match = 0;
403
 
404
  foreach($this->collationStatus as $key => $val) {
 
405
  if ($this->collationStatus[$key]['found'] == 0) {
406
  if($this->in->dbcollatefb){
407
  $not_supported_col = $this->collationStatus[$key]['name'];
408
+ for($i = 0; $i < $collation_arr_max; $i++) {
409
+ $col_status = DUPX_DB::getCollationStatus($this->dbh, array($collation_arr[$i]));
410
+ $cur_col_is_supported = $col_status[0]['found'];
411
+ if($cur_col_is_supported){
412
+ $this->collationReplaceList[] = array(
413
+ 'search' => $not_supported_col,
414
+ 'replace' => $collation_arr[$i]
415
+ );
416
+ ++$invalid_match;
417
+ break;
418
+ }
419
+ }
420
+ $invalid = 1;
421
+ break;
 
 
 
 
 
 
 
 
422
  } else {
423
  $invalid = 1;
424
  break;
537
  }
538
  }
539
 
540
+ /**
541
+ * Show source site trigger creates
542
+ *
543
+ * @return null
544
+ */
545
+ private function n20All(&$test)
546
+ {
547
+ if ($this->isFailedState($test)) {
548
+ return;
549
+ }
550
+
551
+ $triggers = (array)$this->ac->dbInfo->triggerList;
552
+ if (count($triggers) > 0) {
553
+ $test['pass'] = 0;
554
+ $test['info'] = "";
555
+
556
+ foreach ($triggers as $trigger) {
557
+ $test['info'] .= $trigger->create."\n\n";;
558
+ }
559
+
560
+ } else {
561
+ $test['pass'] = 1;
562
+ $test['info'] = "Source site did not contain triggers.";
563
+ }
564
+ }
565
+
566
  /**
567
  * Input has UTF8 data
568
  *
installer/dup-installer/main.installer.php CHANGED
@@ -333,7 +333,7 @@ if (!empty($unespectOutput)) {
333
 
334
  if ($GLOBALS['DUPX_AC']->installSiteOverwriteOn) {
335
  echo ($GLOBALS['DUPX_STATE']->mode === DUPX_InstallerMode::OverwriteInstall)
336
- ? "<span class='dupx-overwrite'>Mode: Overwrite Install {$db_only_txt}</span>"
337
  : "Mode: Standard Install {$db_only_txt}";
338
  } else {
339
  echo "Mode: Standard Install {$db_only_txt}";
333
 
334
  if ($GLOBALS['DUPX_AC']->installSiteOverwriteOn) {
335
  echo ($GLOBALS['DUPX_STATE']->mode === DUPX_InstallerMode::OverwriteInstall)
336
+ ? "<span class='dupx-overwrite'>Mode: Overwrite Install (Beta) {$db_only_txt}</span>"
337
  : "Mode: Standard Install {$db_only_txt}";
338
  } else {
339
  echo "Mode: Standard Install {$db_only_txt}";
installer/dup-installer/views/view.help.php CHANGED
@@ -409,6 +409,13 @@ $expandClass = $sectionId == $open_section ? 'open' : 'close';
409
  <td>The MySQL mode option will allow you to set the mode for this session. It is very useful when running into conversion issues. For a full overview please
410
  see the <a href="https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html" target="_blank">MySQL mode documentation</a> specific to your version.</td>
411
  </tr>
 
 
 
 
 
 
 
412
  <tr>
413
  <td class="col-opt">Charset</td>
414
  <td>When the database is populated from the SQL script it will use this value as part of its connection. Only change this value if you know what your
409
  <td>The MySQL mode option will allow you to set the mode for this session. It is very useful when running into conversion issues. For a full overview please
410
  see the <a href="https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html" target="_blank">MySQL mode documentation</a> specific to your version.</td>
411
  </tr>
412
+ <tr>
413
+ <td class="col-opt">Objects</td>
414
+ <td>Allow or Ignore objects for 'Views', 'Stored Procedures", and 'DEFINER' statements. Typically the defaults for these settings should be used.
415
+ In the event you see an error such as "'Access denied; you need (at least one of) the SUPER privilege(s) for this operation" then changing the value
416
+ for each operation should be considered.
417
+ </td>
418
+ </tr>
419
  <tr>
420
  <td class="col-opt">Charset</td>
421
  <td>When the database is populated from the SQL script it will use this value as part of its connection. Only change this value if you know what your
installer/dup-installer/views/view.s1.base.php CHANGED
@@ -1,1397 +1,1465 @@
1
- <?php
2
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
- /** IDE HELPERS */
4
- /* @var $GLOBALS['DUPX_AC'] DUPX_ArchiveConfig */
5
- /* @var $archive_config DUPX_ArchiveConfig */
6
- /* @var $installer_state DUPX_InstallerState */
7
-
8
- require_once($GLOBALS['DUPX_INIT'] . '/classes/config/class.archive.config.php');
9
-
10
- $root_path = $GLOBALS['DUPX_ROOT'];
11
- $is_wpconfarc_present = file_exists(DUPX_Package::getWpconfigArkPath());
12
- //ARCHIVE FILE
13
- if (file_exists($GLOBALS['FW_PACKAGE_PATH'])) {
14
- $arcCheck = 'Pass';
15
- } else {
16
- if ($is_wpconfarc_present) {
17
- $arcCheck = 'Warn';
18
- } else {
19
- $arcCheck = 'Fail';
20
- }
21
- }
22
- $arcSize = file_exists($GLOBALS['FW_PACKAGE_PATH']) ? @filesize($GLOBALS['FW_PACKAGE_PATH']) : 0;
23
- $arcSize = is_numeric($arcSize) ? $arcSize : 0;
24
-
25
- $installer_state = DUPX_InstallerState::getInstance();
26
- $is_overwrite_mode = ($installer_state->mode === DUPX_InstallerMode::OverwriteInstall);
27
- $is_wordpress = DUPX_Server::isWordPress();
28
- $is_dbonly = $GLOBALS['DUPX_AC']->exportOnlyDB;
29
-
30
- //REQUIRMENTS
31
- $req = array();
32
- $req['10'] = DUPX_Server::is_dir_writable($GLOBALS['DUPX_ROOT']) ? 'Pass' : 'Fail';
33
- $req['20'] = function_exists('mysqli_connect') ? 'Pass' : 'Fail';
34
- $req['30'] = DUPX_Server::$php_version_safe ? 'Pass' : 'Fail';
35
- $all_req = in_array('Fail', $req) ? 'Fail' : 'Pass';
36
-
37
- //NOTICES
38
- $openbase = ini_get("open_basedir");
39
- $datetime1 = $GLOBALS['DUPX_AC']->created;
40
- $datetime2 = date("Y-m-d H:i:s");
41
- $fulldays = round(abs(strtotime($datetime1) - strtotime($datetime2))/86400);
42
- $root_path = DupLiteSnapLibIOU::safePath($GLOBALS['DUPX_ROOT'], true);
43
- $wpconf_path = "{$root_path}/wp-config.php";
44
- $max_time_zero = ($GLOBALS['DUPX_ENFORCE_PHP_INI']) ? false : @set_time_limit(0);
45
- $max_time_size = 314572800; //300MB
46
- $max_time_ini = ini_get('max_execution_time');
47
- $max_time_warn = (is_numeric($max_time_ini) && $max_time_ini < 31 && $max_time_ini > 0) && $arcSize > $max_time_size;
48
- $parentWordFencePath = DUPX_Server::parentWordfencePath();
49
-
50
- $notice = array();
51
- $notice['10'] = ! $is_overwrite_mode ? 'Good' : 'Warn';
52
- $notice['20'] = ! $is_wpconfarc_present ? 'Good' : 'Warn';
53
- if ($is_dbonly) {
54
- $notice['25'] = $is_wordpress ? 'Good' : 'Warn';
55
- }
56
- $notice['30'] = $fulldays <= 180 ? 'Good' : 'Warn';
57
- $notice['40'] = DUPX_Server::$php_version_53_plus ? 'Good' : 'Warn';
58
-
59
- $packagePHP = $GLOBALS['DUPX_AC']->version_php;
60
- $currentPHP = DUPX_Server::$php_version;
61
- $packagePHPMajor = intval($packagePHP);
62
- $currentPHPMajor = intval($currentPHP);
63
- $notice['45'] = ($packagePHPMajor === $currentPHPMajor || $GLOBALS['DUPX_AC']->exportOnlyDB) ? 'Good' : 'Warn';
64
-
65
- $notice['50'] = empty($openbase) ? 'Good' : 'Warn';
66
- $notice['60'] = !$max_time_warn ? 'Good' : 'Warn';
67
- $notice['70'] = $GLOBALS['DUPX_AC']->mu_mode == 0 ? 'Good' : 'Warn';
68
- $notice['80'] = !$GLOBALS['DUPX_AC']->is_outer_root_wp_config_file ? 'Good' : 'Warn';
69
- if ($GLOBALS['DUPX_AC']->exportOnlyDB) {
70
- $notice['90'] = 'Good';
71
- } else {
72
- $notice['90'] = (!$GLOBALS['DUPX_AC']->is_outer_root_wp_content_dir)
73
- ? 'Good'
74
- : 'Warn';
75
- }
76
-
77
- $space_free = @disk_free_space($GLOBALS['DUPX_ROOT']);
78
- $archive_size = file_exists($GLOBALS['FW_PACKAGE_PATH']) ? filesize($GLOBALS['FW_PACKAGE_PATH']) : 0;
79
- $notice['100'] = ($space_free && $archive_size > $space_free)
80
- ? 'Warn'
81
- : 'Good';
82
- $notice['110'] = $parentWordFencePath === false ? 'Good' : 'Warn';
83
-
84
- $all_notice = in_array('Warn', $notice) ? 'Warn' : 'Good';
85
-
86
- //SUMMATION
87
- $req_success = ($all_req == 'Pass');
88
- $req_notice = ($all_notice == 'Good');
89
- $all_success = ($req_success && $req_notice);
90
- $agree_msg = "To enable this button the checkbox above under the 'Terms & Notices' must be checked.";
91
-
92
- $shell_exec_unzip_path = DUPX_Server::get_unzip_filepath();
93
- $shell_exec_zip_enabled = ($shell_exec_unzip_path != null);
94
- $zip_archive_enabled = class_exists('ZipArchive') ? 'Enabled' : 'Not Enabled';
95
- $archive_config = DUPX_ArchiveConfig::getInstance();
96
- ?>
97
-
98
- <form id="s1-input-form" method="post" class="content-form" autocomplete="off">
99
- <input type="hidden" name="view" value="step1" />
100
- <input type="hidden" name="csrf_token" value="<?php echo DUPX_CSRF::generate('step1'); ?>">
101
- <input type="hidden" name="ctrl_action" value="ctrl-step1" />
102
- <input type="hidden" name="ctrl_csrf_token" value="<?php echo DUPX_U::esc_attr(DUPX_CSRF::generate('ctrl-step1')); ?>">
103
- <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_html($_POST['secure-pass']); ?>" />
104
- <input type="hidden" id="s1-input-form-extra-data" name="extra_data" />
105
-
106
- <div class="hdr-main">
107
- Step <span class="step">1</span> of 4: Deployment
108
- <div class="sub-header">This step will extract the archive file contents.</div>
109
- </div><br/>
110
-
111
- <!-- ====================================
112
- SETUP TYPE: @todo implement
113
- ==================================== -->
114
- <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s1-area-setup-type" style="display:none">
115
- <a id="s1-area-setup-type-link"><i class="fa fa-plus-square"></i>Setup</a>
116
- </div>
117
- <div id="s1-area-setup-type" style="display:none">
118
-
119
- <!-- STANDARD INSTALL -->
120
- <input type="radio" id="setup-type-fresh" name="setup_type" value="1" checked="true" onclick="DUPX.toggleSetupType()" />
121
- <label for="setup-type-fresh"><b>Standard Install</b></label>
122
- <i class="fas fa-question-circle fa-sm"
123
- data-tooltip-title="Standard Install"
124
- data-tooltip="A standard install is the default way Duplicator has always worked. Setup your package in an empty directory and run the installer."></i>
125
- <br/>
126
- <div class="s1-setup-type-sub" id="s1-setup-type-sub-1">
127
- <input type="checkbox" name="setup-backup-files" id="setup-backup-files-fresh" />
128
- <label for="setup-backup-files-fresh">Backup Existing Files</label><br/>
129
- <input type="checkbox" name="setup-remove-files" id="setup-remove-files-fresh" />
130
- <label for="setup-remove-files-fresh">Remove Existing Files</label><br/>
131
- </div><br/>
132
-
133
- <!-- OVERWRITE INSTALL -->
134
- <input type="radio" id="setup-type-overwrite" name="setup_type" value="2" onclick="DUPX.toggleSetupType()" />
135
- <label for="setup-type-overwrite"><b>Overwrite Install</b></label>
136
- <i class="fas fa-question-circle fa-sm"
137
- data-tooltip-title="Overwrite Install"
138
- data-tooltip="An Overwrite Install allows Duplicator to overwrite an existing WordPress Site."></i><br/>
139
- <div class="s1-setup-type-sub" id="s1-setup-type-sub-2">
140
- <input type="checkbox" name="setup-backup-files" id="setup-backup-files-overwrite" />
141
- <label for="setup-backup-files-overwrite">Backup Existing Files</label><br/>
142
- <input type="checkbox" name="setup-remove-files" id="setup-remove-files-overwrite" />
143
- <label for="setup-remove-files-overwrite">Remove Existing Files</label><br/>
144
- <input type="checkbox" name="setup-backup-database" id="setup-backup-database-overwrite" />
145
- <label for="setup-backup-database-overwrite">Backup Existing Database</label> <br/>
146
- </div><br/>
147
-
148
- <!-- DB-ONLY INSTALL -->
149
- <input type="radio" id="setup-type-db" name="setup_type" value="3" onclick="DUPX.toggleSetupType()" />
150
- <label for="setup-type-db"><b>Database Only Install</b></label>
151
- <i class="fas fa-question-circle fa-sm"
152
- data-tooltip-title="Database Only"
153
- data-tooltip="A database only install allows Duplicator to connect to a database and install only the database."></i><br/>
154
- <div class="s1-setup-type-sub" id="s1-setup-type-sub-3">
155
- <input type="checkbox" name="setup-backup-database" id="setup-backup-database-db" />
156
- <label for="setup-backup-database-db">Backup Existing Database</label> <br/>
157
- </div><br/>
158
-
159
- </div>
160
-
161
-
162
- <!-- ====================================
163
- ARCHIVE
164
- ==================================== -->
165
- <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s1-area-archive-file">
166
- <a id="s1-area-archive-file-link"><i class="fa fa-plus-square"></i>Setup</a>
167
- <?php
168
- $badge = DUPX_View_Funcs::getBadgeClassFromCheckStatus($arcCheck);
169
- ?>
170
- <div class="<?php echo $badge;?>">
171
- <?php echo $arcCheck;?>
172
- </div>
173
- </div>
174
- <div id="s1-area-archive-file" style="display:none" class="hdr-sub1-area">
175
- <div id="tabs">
176
- <ul>
177
- <li><a href="#tabs-1">Archive</a></li>
178
- </ul>
179
- <div id="tabs-1">
180
-
181
- <table class="s1-archive-local">
182
- <tr>
183
- <td colspan="2"><div class="hdr-sub3">Site Details</div></td>
184
- </tr>
185
- <tr>
186
- <td>Site:</td>
187
- <td><?php echo DUPX_U::esc_html($GLOBALS['DUPX_AC']->blogname);?> </td>
188
- </tr>
189
- <tr>
190
- <td>Notes:</td>
191
- <td><?php echo strlen($GLOBALS['DUPX_AC']->package_notes) ? DUPX_U::esc_html($GLOBALS['DUPX_AC']->package_notes) : " - no notes - "; ?></td>
192
- </tr>
193
- <?php if ($GLOBALS['DUPX_AC']->exportOnlyDB) :?>
194
- <tr>
195
- <td>Mode:</td>
196
- <td>Archive only database was enabled during package package creation.</td>
197
- </tr>
198
- <?php endif; ?>
199
- </table>
200
-
201
- <table class="s1-archive-local">
202
- <tr>
203
- <td colspan="2"><div class="hdr-sub3">File Details</div></td>
204
- </tr>
205
- <tr>
206
- <td style="vertical-align:top">Status:</td>
207
- <td>
208
- <?php if ($arcCheck == 'Fail' || $arcCheck == 'Warn') : ?>
209
- <span class="dupx-fail" style="font-style:italic">
210
- <?php
211
- if ($arcCheck == 'Warn') {
212
- ?>
213
- The archive file named above must be the <u>exact</u> name of the archive file placed in the root path (character for character). But you can proceed with choosing Manual Archive Extraction.
214
- <?php
215
- } else {
216
- ?>
217
- The archive file named above must be the <u>exact</u> name of the archive file placed in the root path (character for character).
218
- When downloading the package files make sure both files are from the same package line. <br/><br/>
219
-
220
- If the contents of the archive were manually transferred to this location without the archive file then simply create a temp file named with
221
- the exact name shown above and place the file in the same directory as the installer.php file. The temp file will not need to contain any data.
222
- Afterward, refresh this page and continue with the install process.
223
- <?php
224
- }
225
- ?>
226
- </span>
227
- <?php else : ?>
228
- <span class="dupx-pass">Archive file successfully detected.</span>
229
- <?php endif; ?>
230
- </td>
231
- </tr>
232
- <tr>
233
- <td>Path:</td>
234
- <td><?php echo DUPX_U::esc_html($root_path); ?> </td>
235
- </tr>
236
- <tr>
237
- <td>Size:</td>
238
- <td><?php echo DUPX_U::readableByteSize($arcSize);?> </td>
239
- </tr>
240
- </table>
241
-
242
- </div>
243
- <!--div id="tabs-2"><p>Content Here</p></div-->
244
- </div>
245
- </div><br/><br/>
246
-
247
- <!-- ====================================
248
- VALIDATION
249
- ==================================== -->
250
- <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s1-area-sys-setup">
251
- <a id="s1-area-sys-setup-link"><i class="fa fa-plus-square"></i>Validation</a>
252
- <div class="<?php echo ( $req_success) ? 'status-badge-pass' : 'status-badge-fail'; ?> ">
253
- <?php echo ( $req_success) ? 'Pass' : 'Fail'; ?>
254
- </div>
255
- </div>
256
- <div id="s1-area-sys-setup" style="display:none" class="hdr-sub1-area">
257
- <div class='info-top'>The system validation checks help to make sure the system is ready for install.</div>
258
-
259
- <!-- REQUIREMENTS -->
260
- <div class="s1-reqs" id="s1-reqs-all">
261
- <div class="header">
262
- <table class="s1-checks-area">
263
- <tr>
264
- <td class="title">Requirements <small>(must pass)</small></td>
265
- <td class="toggle"><a href="javascript:void(0)" onclick="DUPX.toggleAll('#s1-reqs-all')">[toggle]</a></td>
266
- </tr>
267
- </table>
268
- </div>
269
-
270
- <!-- REQ 10 -->
271
- <?php
272
- $status = strtolower($req['10']);
273
- ?>
274
- <div class="status <?php echo DUPX_U::esc_attr($status); ?>"><?php echo DUPX_U::esc_html($req['10']); ?></div>
275
- <div class="title" data-type="toggle" data-target="#s1-reqs10"><i class="fa fa-caret-right"></i> Permissions</div>
276
- <div class="info" id="s1-reqs10">
277
- <table>
278
- <tr>
279
- <td><b>Deployment Path:</b> </td>
280
- <td><i><?php echo "{$GLOBALS['DUPX_ROOT']}"; ?></i> </td>
281
- </tr>
282
- <tr>
283
- <td><b>Suhosin Extension:</b> </td>
284
- <td><?php echo extension_loaded('suhosin') ? "<i class='dupx-fail'>Enabled</i>" : "<i class='dupx-pass'>Disabled</i>"; ?> </td>
285
- </tr>
286
- <tr>
287
- <td><b>PHP Safe Mode:</b> </td>
288
- <td><?php echo (DUPX_Server::$php_safe_mode_on) ? "<i class='dupx-fail'>Enabled</i>" : "<i class='dupx-pass'>Disabled</i>"; ?> </td>
289
- </tr>
290
- </table><br/>
291
-
292
- The deployment path must be writable by PHP in order to extract the archive file. Incorrect permissions and extension such as
293
- <a href="https://suhosin.org/stories/index.html" target="_blank">suhosin</a> can sometimes interfere with PHP being able to write/extract files.
294
- Please see the <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-055-q" target="_blank">FAQ permission</a> help link for complete details.
295
- PHP with <a href='http://php.net/manual/en/features.safe-mode.php' target='_blank'>safe mode</a> should be disabled. If Safe Mode is enabled then
296
- please contact your hosting provider or server administrator to disable PHP safe mode.
297
- </div>
298
-
299
- <!-- REQ 20 -->
300
- <div class="status <?php echo strtolower($req['20']); ?>"><?php echo DUPX_U::esc_html($req['20']); ?></div>
301
- <div class="title" data-type="toggle" data-target="#s1-reqs20"><i class="fa fa-caret-right"></i> PHP Mysqli</div>
302
- <div class="info" id="s1-reqs20">
303
- Support for the PHP <a href='http://us2.php.net/manual/en/mysqli.installation.php' target='_blank'>mysqli extension</a> is required.
304
- Please contact your hosting provider or server administrator to enable the mysqli extension. <i>The detection for this call uses
305
- the function_exists('mysqli_connect') call.</i>
306
- </div>
307
-
308
- <!-- REQ 30 -->
309
- <div class="status <?php echo strtolower($req['30']); ?>"><?php echo DUPX_U::esc_html($req['30']); ?></div>
310
- <div class="title" data-type="toggle" data-target="#s1-reqs30"><i class="fa fa-caret-right"></i> PHP Version</div>
311
- <div class="info" id="s1-reqs30">
312
- This server is running PHP: <b><?php echo DUPX_Server::$php_version ?></b>. <i>A minimum of PHP 5.2.17 is required</i>.
313
- Contact your hosting provider or server administrator and let them know you would like to upgrade your PHP version.
314
- </div>
315
- </div><br/>
316
-
317
-
318
- <!-- ====================================
319
- NOTICES -->
320
- <div class="s1-reqs" id="s1-notice-all">
321
- <div class="header">
322
- <table class="s1-checks-area">
323
- <tr>
324
- <td class="title">Notices <small>(optional)</small></td>
325
- <td class="toggle"><a href="javascript:void(0)" onclick="DUPX.toggleAll('#s1-notice-all')">[toggle]</a></td>
326
- </tr>
327
- </table>
328
- </div>
329
-
330
- <!-- NOTICE 10: OVERWRITE INSTALL -->
331
- <?php if ($is_overwrite_mode && $is_wordpress) :?>
332
- <div class="status fail">Warn</div>
333
- <div class="title" data-type="toggle" data-target="#s1-notice10"><i class="fa fa-caret-right"></i> Overwrite Install</div>
334
- <div class="info" id="s1-notice10">
335
- <b>Deployment Path:</b> <i><?php echo "{$GLOBALS['DUPX_ROOT']}"; ?></i>
336
- <br/><br/>
337
- <?php
338
- if ($GLOBALS['DUPX_AC']->installSiteOverwriteOn || $is_dbonly) {
339
- ?>
340
- Duplicator is in "Overwrite Install" mode because it has detected an existing WordPress site at the deployment path above. This mode allows for the installer
341
- to be dropped directly into an existing WordPress site and overwrite its contents. Any content inside of the archive file
342
- will <u>overwrite</u> the contents from the deployment path. To continue choose one of these options:
343
-
344
- <ol>
345
- <li>Ignore this notice and continue with the install if you want to overwrite this sites files.</li>
346
- <li>Move this installer and archive to another empty directory path to keep this sites files.</li>
347
- </ol>
348
-
349
- <small style="color:maroon">
350
- <b>Notice:</b> Existing content such as plugin/themes/images will still show-up after the install is complete if they did not already exist in
351
- the archive file. For example if you have an SEO plugin in the current site but that same SEO plugin <u>does not exist</u> in the archive file
352
- then that plugin will display as a disabled plugin after the install is completed. The same concept with themes and images applies. This will
353
- not impact the sites operation, and the behavior is expected.
354
- </small>
355
- <br/><br/>
356
-
357
- <small style="color:#025d02">
358
- <b>Recommendation:</b> It is recommended you only overwrite WordPress sites that have a minimal setup (plugins/themes). Typically a fresh install or a
359
- cPanel 'one click' install is the best baseline to work from when using this mode but is not required.
360
- </small>
361
- <?php
362
- } else {
363
- ?>
364
- Duplicator works best by placing the installer and archive files into an empty directory. If a wp-config.php file is found in the extraction
365
- directory it might indicate that a pre-existing WordPress site exists which can lead to a bad install.
366
- <br/><br/>
367
- <b>Options:</b>
368
- <ul style="margin-bottom: 0">
369
- <li>If the archive was already manually extracted then <a href="javascript:void(0)" onclick="DUPX.getManaualArchiveOpt()">[Enable Manual Archive Extraction]</a></li>
370
- <li>Empty the directory of all files, except for the installer.php and archive.zip/daf files.</li>
371
- <li>Advanced Users: Can attempt to manually remove the wp-config file only if the archive was manually extracted.</li>
372
- </ul>
373
- <?php
374
- }
375
- ?>
376
- </div>
377
-
378
- <!-- NOTICE 20: ARCHIVE EXTRACTED -->
379
- <?php elseif ($is_wpconfarc_present && file_exists('{$root_path}/dup-installer')) :?>
380
- <div class="status fail">Warn</div>
381
- <div class="title" data-type="toggle" data-target="#s1-notice20"><i class="fa fa-caret-right"></i> Archive Extracted</div>
382
- <div class="info" id="s1-notice20">
383
- <b>Deployment Path:</b> <i><?php echo "{$GLOBALS['DUPX_ROOT']}"; ?></i>
384
- <br/><br/>
385
-
386
- The installer has detected that the archive file has been extracted to the deployment path above. To continue choose one of these options:
387
-
388
- <ol>
389
- <li>Skip the extraction process by <a href="javascript:void(0)" onclick="DUPX.getManaualArchiveOpt()">[enabling manual archive extraction]</a> </li>
390
- <li>Ignore this message and continue with the install process to re-extract the archive file.</li>
391
- </ol>
392
-
393
- <small>Note: This test looks for a file named <i>dup-wp-config-arc__[HASH].txt</i> in the dup-installer directory. If the file exists then this notice is shown.
394
- The <i>dup-wp-config-arc__[HASH].txt</i> file is created with every archive and removed once the install is complete. For more details on this process see the
395
- <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q" target="_blank">manual extraction FAQ</a>.</small>
396
- </div>
397
- <?php endif; ?>
398
-
399
- <!-- NOTICE 25: DATABASE ONLY -->
400
- <?php if ($is_dbonly && ! $is_wordpress) :?>
401
- <div class="status fail">Warn</div>
402
- <div class="title" data-type="toggle" data-target="#s1-notice25"><i class="fa fa-caret-right"></i> Database Only</div>
403
- <div class="info" id="s1-notice25">
404
- <b>Deployment Path:</b> <i><?php echo "{$GLOBALS['DUPX_ROOT']}"; ?></i>
405
- <br/><br/>
406
-
407
- The installer has detected that a WordPress site does not exist at the deployment path above. This installer is currently in 'Database Only' mode because that is
408
- how the archive was created. If core WordPress site files do not exist at the path above then they will need to be placed there in order for a WordPress site
409
- to properly work. To continue choose one of these options:
410
-
411
- <ol>
412
- <li>Place this installer and archive at a path where core WordPress files already exist to hide this message. </li>
413
- <li>Create a new package that includes both the database and the core WordPress files.</li>
414
- <li>Ignore this message and install only the database (for advanced users only).</li>
415
- </ol>
416
-
417
- <small>Note: This test simply looks for the directories <?php echo DUPX_Server::$wpCoreDirsList; ?> and a wp-config.php file. If they are not found in the
418
- deployment path above then this notice is shown.</small>
419
-
420
- </div>
421
- <?php endif; ?>
422
-
423
- <!-- NOTICE 30 -->
424
- <div class="status <?php echo ($notice['30'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['30']); ?></div>
425
- <div class="title" data-type="toggle" data-target="#s1-notice30"><i class="fa fa-caret-right"></i> Package Age</div>
426
- <div class="info" id="s1-notice30">
427
- This package is <?php echo "{$fulldays}"; ?> day(s) old. Packages older than 180 days might be considered stale. It is recommended to build a new
428
- package unless your aware of the content and its data. This is message is simply a recommendation.
429
- </div>
430
-
431
-
432
- <!-- NOTICE 40 -->
433
- <div class="status <?php echo ($notice['40'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['40']); ?></div>
434
- <div class="title" data-type="toggle" data-target="#s1-notice40"><i class="fa fa-caret-right"></i> PHP Version 5.2</div>
435
- <div class="info" id="s1-notice40">
436
- <?php
437
- $cssStyle = DUPX_Server::$php_version_53_plus ? 'color:green' : 'color:red';
438
- echo "<b style='{$cssStyle}'>This server is currently running PHP version [{$currentPHP}]</b>.<br/>"
439
- . "Duplicator allows PHP 5.2 to be used during install but does not officially support it. If you're using PHP 5.2 we strongly recommend NOT using it and having your "
440
- . "host upgrade to a newer more stable, secure and widely supported version. The <a href='http://php.net/eol.php' target='_blank'>end of life for PHP 5.2</a> "
441
- . "was in January of 2011 and is not recommended for use.<br/><br/>";
442
-
443
- echo "Many plugin and theme authors are no longer supporting PHP 5.2 and trying to use it can result in site wide problems and compatibility warnings and errors. "
444
- . "Please note if you continue with the install using PHP 5.2 the Duplicator support team will not be able to help with issues or troubleshoot your site. "
445
- . "If your server is running <b>PHP 5.3+</b> please feel free to reach out for help if you run into issues with your migration/install.";
446
- ?>
447
- </div>
448
-
449
- <!-- NOTICE 45 -->
450
- <div class="status <?php echo ($notice['45'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo $notice['45']; ?></div>
451
- <div class="title" data-type="toggle" data-target="#s1-notice45"><i class="fa fa-caret-right"></i> PHP Version Mismatch</div>
452
- <div class="info" id="s1-notice45">
453
- <?php
454
- $cssStyle = $notice['45'] == 'Good' ? 'color:green' : 'color:red';
455
- echo "<b style='{$cssStyle}'>You are migrating site from the PHP {$packagePHP} to the PHP {$currentPHP}</b>.<br/>"
456
- ."If this servers PHP version is different to the PHP version of your package was created it might cause problems with proper functioning of your website
457
- and/or plugins and themes. It is highly recommended to try and use the same version of PHP if you are able to do so. <br/>";
458
- ?>
459
- </div>
460
-
461
- <!-- NOTICE 50 -->
462
- <div class="status <?php echo ($notice['50'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['50']); ?></div>
463
- <div class="title" data-type="toggle" data-target="#s1-notice50"><i class="fa fa-caret-right"></i> PHP Open Base</div>
464
- <div class="info" id="s1-notice50">
465
- <b>Open BaseDir:</b> <i><?php echo $notice['50'] == 'Good' ? "<i class='dupx-pass'>Disabled</i>" : "<i class='dupx-fail'>Enabled</i>"; ?></i>
466
- <br/><br/>
467
-
468
- If <a href="http://php.net/manual/en/ini.core.php#ini.open-basedir" target="_blank">open_basedir</a> is enabled and your
469
- having issues getting your site to install properly; please work with your host and follow these steps to prevent issues:
470
- <ol style="margin:7px; line-height:19px">
471
- <li>Disable the open_basedir setting in the php.ini file</li>
472
- <li>If the host will not disable, then add the path below to the open_basedir setting in the php.ini<br/>
473
- <i style="color:maroon">"<?php echo str_replace('\\', '/', dirname( __FILE__ )); ?>"</i>
474
- </li>
475
- <li>Save the settings and restart the web server</li>
476
- </ol>
477
- Note: This warning will still show if you choose option #2 and open_basedir is enabled, but should allow the installer to run properly. Please work with your
478
- hosting provider or server administrator to set this up correctly.
479
- </div>
480
-
481
- <!-- NOTICE 60 -->
482
- <div class="status <?php echo ($notice['60'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['60']); ?></div>
483
- <div class="title" data-type="toggle" data-target="#s1-notice60"><i class="fa fa-caret-right"></i> PHP Timeout</div>
484
- <div class="info" id="s1-notice60">
485
- <b>Archive Size:</b> <?php echo DUPX_U::readableByteSize($arcSize) ?> <small>(detection limit is set at <?php echo DUPX_U::readableByteSize($max_time_size) ?>) </small><br/>
486
- <b>PHP max_execution_time:</b> <?php echo "{$max_time_ini}"; ?> <small>(zero means not limit)</small> <br/>
487
- <b>PHP set_time_limit:</b> <?php echo ($max_time_zero) ? '<i style="color:green">Success</i>' : '<i style="color:maroon">Failed</i>' ?>
488
- <br/><br/>
489
-
490
- The PHP <a href="http://php.net/manual/en/info.configuration.php#ini.max-execution-time" target="_blank">max_execution_time</a> setting is used to
491
- determine how long a PHP process is allowed to run. If the setting is too small and the archive file size is too large then PHP may not have enough
492
- time to finish running before the process is killed causing a timeout.
493
- <br/><br/>
494
-
495
- Duplicator attempts to turn off the timeout by using the
496
- <a href="http://php.net/manual/en/function.set-time-limit.php" target="_blank">set_time_limit</a> setting. If this notice shows as a warning then it is
497
- still safe to continue with the install. However, if a timeout occurs then you will need to consider working with the max_execution_time setting or extracting the
498
- archive file using the 'Manual Archive Extraction' method.
499
- Please see the <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-100-q" target="_blank">FAQ timeout</a> help link for more details.
500
- </div>
501
-
502
-
503
- <!-- NOTICE 8 -->
504
- <div class="status <?php echo ($notice['70'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['70']); ?></div>
505
- <div class="title" data-type="toggle" data-target="#s1-notice70"><i class="fa fa-caret-right"></i> WordPress Multisite</div>
506
- <div class="info" id="s1-notice70">
507
- <b>Status:</b> <?php echo $notice['70'] <= 0 ? 'This archive is not a multisite' : 'This is an unsupported multisite archive'; ?>
508
- <br/><br/>
509
-
510
- Duplicator does not support WordPress multisite migrations. We recommend using Duplicator Pro which currently supports full multisite migrations and subsite to
511
- standalone site migrations.
512
- <br/><br/>
513
- While it is not recommended you can still continue with the build of this package. Please note that after the install the site may not be working correctly.
514
- Additional manual custom configurations will need to be made to finalize this multisite migration.
515
-
516
- <i><a href='https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_is_mu_warn_exe&utm_campaign=duplicator_pro' target='_blank'>[upgrade to pro]</a></i>
517
- </div>
518
-
519
- <!-- NOTICE 80 -->
520
- <div class="status <?php echo ($notice['80'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['80']); ?></div>
521
- <div class="title" data-type="toggle" data-target="#s1-notice80"><i class="fa fa-caret-right"></i> WordPress wp-config Location</div>
522
- <div class="info" id="s1-notice80">
523
- If the wp-config.php file was moved up one level and out of the WordPress root folder in the package creation site then this test will show a warning.
524
- <br/><br/>
525
- This Duplicator installer will place this wp-config.php file in the WordPress setup root folder of this installation site to help stabilize the install process.
526
- This process will not break anything in your installation site, but the details are here for your information.
527
- </div>
528
-
529
- <!-- NOTICE 90 -->
530
- <div class="status <?php echo ($notice['90'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['90']); ?></div>
531
- <div class="title" data-type="toggle" data-target="#s1-notice90"><i class="fa fa-caret-right"></i> WordPress wp-content Location</div>
532
- <div class="info" id="s1-notice90">
533
- If the wp-content directory was moved and not located at the WordPress root folder in the package creation site then this test will show a warning.
534
- <br/><br/>
535
- Duplicator Installer will place this wp-content directory in the WordPress setup root folder of this installation site. It will not break anything in your installation
536
- site. It is just for your information.
537
- </div>
538
-
539
- <!-- NOTICE 100 -->
540
- <div class="status <?php echo ($notice['100'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['100']); ?></div>
541
- <div class="title" data-type="toggle" data-target="#s1-notice100"><i class="fa fa-caret-right"></i> Sufficient disk space</div>
542
- <div class="info" id="s1-notice100">
543
- <?php
544
- echo ($notice['100'] == 'Good')
545
- ? 'You have sufficient disk space in your machine to extract the archive.'
546
- : 'You don’t have sufficient disk space in your machine to extract the archive. Ask your host to increase disk space.'
547
- ?>
548
- </div>
549
-
550
- <!-- NOTICE 110 -->
551
- <div class="status <?php echo ($notice['110'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['110']); ?></div>
552
- <div class="title" data-type="toggle" data-target="#s1-notice110"><i class="fa fa-caret-right"></i> Wordfence</div>
553
- <div class="info" id="s1-notice110">
554
- <b>Wordfence Firewall:</b> <?php echo ($notice['110'] == 'Warn') ? "<span style='color:red;'>detected at {$parentWordFencePath}</span>" : "<span style='color:green;'>not detected</span>"; ?>
555
- <p>
556
- The Wordfence Web Application Firewall is a PHP based, application level firewall that filters out malicious
557
- requests to your site. Sometimes Wordfence returns false positives on requests done during the installation process,
558
- because of which it might fail. We recommend turning off the Wordfence firewall of the WordPress instance located at the mentioned path.
559
- </p>
560
- </div>
561
-
562
- </div>
563
-
564
- </div>
565
- <br/><br/>
566
-
567
-
568
- <!-- ====================================
569
- OPTIONS
570
- ==================================== -->
571
- <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s1-area-adv-opts">
572
- <a href="javascript:void(0)"><i class="fa fa-plus-square"></i>Options</a>
573
- </div>
574
- <div id="s1-area-adv-opts" class="hdr-sub1-area" style="display:none">
575
- <div class="help-target">
576
- <?php DUPX_View_Funcs::helpIconLink('step1'); ?>
577
- </div>
578
- <div class="hdr-sub3">General</div>
579
- <table class="dupx-opts dupx-advopts">
580
- <tr>
581
- <td>Extraction:</td>
582
- <td>
583
- <?php
584
- $options = array();
585
- $extra_attr = ($arcCheck == 'Warn' && $is_wpconfarc_present) ? ' selected="selected"' : '';
586
- $options[] = '<option '.($is_wpconfarc_present ? '' : 'disabled').$extra_attr.' value="manual">Manual Archive Extraction '.($is_wpconfarc_present ? '' : '*').'</option>';
587
- if($archive_config->isZipArchive()){
588
- //ZIP-ARCHIVE
589
- $extra_attr = ('Pass' == $arcCheck && $zip_archive_enabled && !$shell_exec_zip_enabled)
590
- ? ' selected="selected"'
591
- : '';
592
- $extra_attr .= ('Pass' != $arcCheck || !$zip_archive_enabled)
593
- ? ' disabled="disabled"'
594
- : '';
595
- $options[] = '<option value="ziparchive"'.$extra_attr.'>PHP ZipArchive</option>';
596
-
597
- //SHELL-EXEC UNZIP
598
- $extra_attr = ('Pass' != $arcCheck || !$shell_exec_zip_enabled) ? ' disabled="disabled"' : '';
599
- $extra_attr .= ('Pass' == $arcCheck && $shell_exec_zip_enabled) ? ' selected="selected"' : '';
600
- $options[] = '<option value="shellexec_unzip"'.$extra_attr.'>Shell Exec Unzip</option>';
601
- } else { // DUPARCHIVE
602
- $extra_attr = ('Pass' == $arcCheck) ? ' selected="selected"' : 'disabled="disabled"';
603
- $options[] = '<option value="duparchive"'.$extra_attr.'>DupArchive</option>';
604
- }
605
- $num_selections = count($options);
606
- ?>
607
- <select id="archive_engine" name="archive_engine" size="<?php echo DUPX_U::esc_attr($num_selections); ?>">
608
- <?php echo implode('', $options); ?>
609
- </select><br/>
610
- <?php if (!$is_wpconfarc_present):?>
611
- <span class="sub-notes">
612
- *Option enabled when archive has been pre-extracted
613
- <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q" target="_blank">[more info]</a>
614
- </span>
615
- <?php endif; ?>
616
- </td>
617
- </tr>
618
- <tr>
619
- <td>Permissions:</td>
620
- <td>
621
- <input type="checkbox" name="set_file_perms" id="set_file_perms" value="1" onclick="jQuery('#file_perms_value').prop('disabled', !jQuery(this).is(':checked'));"/>
622
- <label for="set_file_perms">All Files</label><input name="file_perms_value" id="file_perms_value" style="width:45px; margin-left:7px;" value="644" disabled> &nbsp;
623
- <input type="checkbox" name="set_dir_perms" id="set_dir_perms" value="1" onclick="jQuery('#dir_perms_value').prop('disabled', !jQuery(this).is(':checked'));"/>
624
- <label for="set_dir_perms">All Directories</label><input name="dir_perms_value" id="dir_perms_value" style="width:45px; margin-left:7px;" value="755" disabled>
625
- </td>
626
- </tr>
627
- </table><br/><br/>
628
-
629
- <div class="hdr-sub3">Advanced</div>
630
- <table class="dupx-opts dupx-advopts">
631
- <tr>
632
- <td>Safe Mode:</td>
633
- <td>
634
- <select name="exe_safe_mode" id="exe_safe_mode" onchange="DUPX.onSafeModeSwitch();" style="width:250px;">
635
- <option value="0">Off</option>
636
- <option value="1">Basic</option>
637
- <option value="2">Advanced</option>
638
- </select>
639
- </td>
640
- </tr>
641
- <tr>
642
- <td>Config Files:</td>
643
- <td>
644
- <select name="config_mode" id="config_mode" style="width:250px;">
645
- <option value="NEW">Create New (recommended)</option>
646
- <optgroup label="Advanced">
647
- <option value="RESTORE">Restore Original</option>
648
- <option value="IGNORE">Ignore All</option>
649
- </optgroup>
650
- </select> <br/>
651
- <span class="sub-notes" style="font-weight: normal">
652
- Controls how .htaccess, .user.ini and web.config are used.<br/>
653
- These options are not applied until step 3 is ran.
654
- <?php DUPX_View_Funcs::helpLink('step1', '[more info]'); ?>
655
- </span>
656
- </td>
657
- </tr>
658
- <tr>
659
- <td>File Times:</td>
660
- <td>
661
- <input type="radio" name="zip_filetime" id="zip_filetime_now" value="current" checked="checked" />
662
- <label class="radio" for="zip_filetime_now" title='Set the files current date time to now'>Current</label> &nbsp;
663
- <input type="radio" name="zip_filetime" id="zip_filetime_orginal" value="original" />
664
- <label class="radio" for="zip_filetime_orginal" title="Keep the files date time the same">Original</label>
665
- </td>
666
- </tr>
667
- <tr>
668
- <td>Logging:</td>
669
- <td>
670
- <input type="radio" name="logging" id="logging-light" value="<?php echo DUPX_Log::LV_DEFAULT; ?>" checked="true"> <label for="logging-light" class="radio">Light</label> &nbsp;
671
- <input type="radio" name="logging" id="logging-detailed" value="<?php echo DUPX_Log::LV_DETAILED; ?>"> <label for="logging-detailed" class="radio">Detailed</label> &nbsp;
672
- <input type="radio" name="logging" id="logging-debug" value="<?php echo DUPX_Log::LV_DEBUG; ?>"> <label for="logging-debug" class="radio">Debug</label> &nbsp;
673
- <input type="radio" name="logging" id="logging-h-debug" value="<?php echo DUPX_Log::LV_HARD_DEBUG; ?>"> <label for="logging-h-debug" class="radio">Hard debug</label>
674
- </td>
675
- </tr>
676
- <?php if(!$archive_config->isZipArchive()): ?>
677
- <tr>
678
- <td>Client-Kickoff:</td>
679
- <td>
680
- <input type="checkbox" name="clientside_kickoff" id="clientside_kickoff" value="1" checked/>
681
- <label for="clientside_kickoff" style="font-weight: normal">Browser drives the archive engine.</label>
682
- </td>
683
- </tr>
684
- <?php endif;?>
685
- <tr>
686
- <td>Testing:</td>
687
- <td>
688
- <a href="javascript:void(0)" target="db-test" onclick="DUPX.openDBValidationWindow(); return false;">[Quick Database Connection Test]</a>
689
- </td>
690
- </tr>
691
- </table>
692
- </div><br/>
693
-
694
- <?php include ('view.s1.terms.php') ;?>
695
-
696
- <div id="s1-warning-check">
697
- <input id="accept-warnings" name="accpet-warnings" type="checkbox" onclick="DUPX.acceptWarning()" />
698
- <label for="accept-warnings">I have read and accept all <a href="javascript:void(0)" onclick="DUPX.viewTerms()">terms &amp; notices</a> <small style="font-style:italic">(required to continue)</small></label><br/>
699
- </div>
700
- <br/><br/>
701
- <br/><br/>
702
-
703
-
704
- <?php if (!$req_success || $arcCheck == 'Fail') : ?>
705
- <div class="s1-err-msg">
706
- <i>
707
- This installation will not be able to proceed until the archive and validation sections both pass. Please adjust your servers settings or contact your
708
- server administrator, hosting provider or visit the resources below for additional help.
709
- </i>
710
- <div style="padding:10px">
711
- &raquo; <a href="https://snapcreek.com/duplicator/docs/faqs-tech/" target="_blank">Technical FAQs</a> <br/>
712
- &raquo; <a href="https://snapcreek.com/support/docs/" target="_blank">Online Documentation</a> <br/>
713
- </div>
714
- </div>
715
- <?php else : ?>
716
- <div class="footer-buttons" >
717
- <button id="s1-deploy-btn" type="button" title="<?php echo DUPX_U::esc_attr($agree_msg); ?>" onclick="DUPX.processNext()" class="default-btn"> Next <i class="fa fa-caret-right"></i> </button>
718
- </div>
719
- <?php endif; ?>
720
-
721
- </form>
722
-
723
- <!-- =========================================
724
- VIEW: STEP 1 - DB QUICK TEST
725
- ========================================= -->
726
- <form id="s1-dbtest-form" method="post" target="_blank" autocomplete="off">
727
- <input type="hidden" name="dbonlytest" value="1" />
728
- <input type="hidden" name="view" value="step2" />
729
- <input type="hidden" name="csrf_token" value="<?php echo DUPX_CSRF::generate('step2'); ?>">
730
- <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
731
- </form>
732
-
733
-
734
- <!-- =========================================
735
- VIEW: STEP 1 - AJAX RESULT
736
- Auto Posts to view.step2.php
737
- ========================================= -->
738
- <form id='s1-result-form' method="post" class="content-form" style="display:none" autocomplete="off">
739
-
740
- <div class="dupx-logfile-link"><?php DUPX_View_Funcs::installerLogLink(); ?></div>
741
- <div class="hdr-main">
742
- Step <span class="step">1</span> of 4: Deployment
743
- <div class="sub-header">This step will extract the archive file contents.</div>
744
- </div>
745
-
746
- <!-- POST PARAMS -->
747
- <div class="dupx-debug">
748
- <i>Step 1 - AJAX Response</i>
749
- <input type="hidden" name="view" value="step2" />
750
- <input type="hidden" name="csrf_token" value="<?php echo DUPX_CSRF::generate('step2'); ?>">
751
- <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
752
- <input type="hidden" name="logging" id="ajax-logging" />
753
- <input type="hidden" name="config_mode" id="ajax-config-mode" />
754
- <input type="hidden" name="exe_safe_mode" id="exe-safe-mode" value="0" />
755
- <input type="hidden" name="json" id="ajax-json" />
756
- <textarea id='ajax-json-debug' name='json_debug_view'></textarea>
757
- <input type='submit' value='manual submit'>
758
- </div>
759
-
760
- <!-- PROGRESS BAR -->
761
- <div id="progress-area">
762
- <div style="width:500px; margin:auto">
763
- <div style="font-size:1.7em; margin-bottom:20px"><i class="fas fa-circle-notch fa-spin"></i> Extracting Archive Files<span id="progress-pct"></span></div>
764
- <div id="progress-bar"></div>
765
- <h3> Please Wait...</h3><br/><br/>
766
- <i>Keep this window open during the extraction process.</i><br/>
767
- <i>This can take several minutes.</i>
768
- </div>
769
- </div>
770
-
771
- <!-- AJAX SYSTEM ERROR -->
772
- <div id="ajaxerr-area" style="display:none">
773
- <p>Please try again an issue has occurred.</p>
774
- <div style="padding: 0px 10px 10px 0px;">
775
- <div id="ajaxerr-data">An unknown issue has occurred with the file and database setup process. Please see the <?php DUPX_View_Funcs::installerLogLink(); ?> file for more details.</div>
776
- <div style="text-align:center; margin:10px auto 0px auto">
777
- <br/>
778
- <input type="button" class="default-btn" onclick="DUPX.hideErrorResult()" value="&laquo; Try Again" />
779
- <br/><br/>
780
- <i style='font-size:11px'>See online help for more details at <a href='https://snapcreek.com/ticket' target='_blank'>snapcreek.com</a></i>
781
- </div>
782
- </div>
783
- </div>
784
- </form>
785
-
786
- <script>
787
- DUPX.openDBValidationWindow = function()
788
- {
789
- console.log('test');
790
- $('#s1-dbtest-form').submit();
791
- }
792
-
793
- DUPX.toggleSetupType = function ()
794
- {
795
- var val = $("input:radio[name='setup_type']:checked").val();
796
- $('div.s1-setup-type-sub').hide();
797
- $('#s1-setup-type-sub-' + val).show(200);
798
- };
799
-
800
- DUPX.getManaualArchiveOpt = function ()
801
- {
802
- $("html, body").animate({scrollTop: $(document).height()}, 1500);
803
- $("div[data-target='#s1-area-adv-opts']").find('i.fa').removeClass('fa-plus-square').addClass('fa-minus-square');
804
- $('#s1-area-adv-opts').show(1000);
805
- $('select#archive_engine').val('manual').focus();
806
- };
807
-
808
- DUPX.startExtraction = function()
809
- {
810
- var isManualExtraction = ($("#archive_engine").val() == "manual");
811
- var zipEnabled = <?php echo DupLiteSnapLibStringU::boolToString($archive_config->isZipArchive()); ?>;
812
-
813
- $("#operation-text").text("Extracting Archive Files");
814
-
815
- if (zipEnabled || isManualExtraction) {
816
- DUPX.runStandardExtraction();
817
- } else {
818
- DUPX.kickOffDupArchiveExtract();
819
- }
820
- }
821
-
822
- DUPX.processNext = function ()
823
- {
824
- DUPX.startExtraction();
825
- };
826
-
827
- DUPX.updateProgressPercent = function (percent)
828
- {
829
- var percentString = '';
830
- if (percent > 0) {
831
- percentString = ' ' + percent + '%';
832
- }
833
- $("#progress-pct").text(percentString);
834
- };
835
-
836
- DUPX.clearDupArchiveStatusTimer = function ()
837
- {
838
- if (DUPX.dupArchiveStatusIntervalID != -1) {
839
- clearInterval(DUPX.dupArchiveStatusIntervalID);
840
- DUPX.dupArchiveStatusIntervalID = -1;
841
- }
842
- };
843
-
844
- DUPX.getCriticalFailureText = function(failures)
845
- {
846
- var retVal = null;
847
-
848
- if((failures !== null) && (typeof failures !== 'undefined')) {
849
- var len = failures.length;
850
-
851
- for(var j = 0; j < len; j++) {
852
- failure = failures[j];
853
-
854
- if(failure.isCritical) {
855
- retVal = failure.description;
856
- break;
857
- }
858
- }
859
- }
860
-
861
- return retVal;
862
- };
863
-
864
- DUPX.DAWSProcessingFailed = function(errorText)
865
- {
866
- DUPX.clearDupArchiveStatusTimer();
867
- $('#ajaxerr-data').html(errorText);
868
- DUPX.hideProgressBar();
869
- }
870
-
871
- DUPX.handleDAWSProcessingProblem = function(errorText, pingDAWS) {
872
-
873
- DUPX.DAWS.FailureCount++;
874
-
875
- if(DUPX.DAWS.FailureCount <= DUPX.DAWS.MaxRetries) {
876
- var callback = DUPX.pingDAWS;
877
-
878
- if(pingDAWS) {
879
- console.log('!!!PING FAILURE #' + DUPX.DAWS.FailureCount);
880
- } else {
881
- console.log('!!!KICKOFF FAILURE #' + DUPX.DAWS.FailureCount);
882
- callback = DUPX.kickOffDupArchiveExtract;
883
- }
884
-
885
- DUPX.throttleDelay = 9; // Equivalent of 'low' server throttling
886
- console.log('Relaunching in ' + DUPX.DAWS.RetryDelayInMs);
887
- setTimeout(callback, DUPX.DAWS.RetryDelayInMs);
888
- }
889
- else {
890
- console.log('Too many failures.');
891
- DUPX.DAWSProcessingFailed(errorText);
892
- }
893
- };
894
-
895
-
896
- DUPX.handleDAWSCommunicationProblem = function(xHr, pingDAWS, textStatus, page)
897
- {
898
- DUPX.DAWS.FailureCount++;
899
-
900
- if(DUPX.DAWS.FailureCount <= DUPX.DAWS.MaxRetries) {
901
-
902
- var callback = DUPX.pingDAWS;
903
-
904
- if(pingDAWS) {
905
- console.log('!!!PING FAILURE #' + DUPX.DAWS.FailureCount);
906
- } else {
907
- console.log('!!!KICKOFF FAILURE #' + DUPX.DAWS.FailureCount);
908
- callback = DUPX.kickOffDupArchiveExtract;
909
- }
910
- console.log(xHr);
911
- DUPX.throttleDelay = 9; // Equivalent of 'low' server throttling
912
- console.log('Relaunching in ' + DUPX.DAWS.RetryDelayInMs);
913
- setTimeout(callback, DUPX.DAWS.RetryDelayInMs);
914
- }
915
- else {
916
- console.log('Too many failures.');
917
- DUPX.ajaxCommunicationFailed(xHr, textStatus, page);
918
- }
919
- };
920
-
921
- // Will either query for status or push it to continue the extraction
922
- DUPX.pingDAWS = function ()
923
- {
924
- console.log('pingDAWS:start');
925
- var request = new Object();
926
- var isClientSideKickoff = DUPX.isClientSideKickoff();
927
-
928
- if (isClientSideKickoff) {
929
- console.log('pingDAWS:client side kickoff');
930
- request.action = "expand";
931
- request.client_driven = 1;
932
- request.throttle_delay = DUPX.throttleDelay;
933
- request.worker_time = DUPX.DAWS.PingWorkerTimeInSec;
934
- } else {
935
- console.log('pingDAWS:not client side kickoff');
936
- request.action = "get_status";
937
- }
938
-
939
- console.log("pingDAWS:action=" + request.action);
940
-
941
- $.ajax({
942
- type: "POST",
943
- timeout: DUPX.DAWS.PingWorkerTimeInSec * 2000, // Double worker time and convert to ms
944
- url: DUPX.DAWS.Url,
945
- data: JSON.stringify(request),
946
- success: function (respData, textStatus, xHr) {
947
- try {
948
- var data = DUPX.parseJSON(respData);
949
- } catch(err) {
950
- console.error(err);
951
- console.error('JSON parse failed for response data: ' + respData);
952
- console.log('AJAX error. textStatus=');
953
- console.log(textStatus);
954
- DUPX.handleDAWSCommunicationProblem(xHr, true, textStatus, 'ping');
955
- return false;
956
- }
957
-
958
- DUPX.DAWS.FailureCount = 0;
959
- console.log("pingDAWS:AJAX success. Resetting failure count");
960
-
961
- // DATA FIELDS
962
- // archive_offset, archive_size, failures, file_index, is_done, timestamp
963
-
964
- if (typeof (data) != 'undefined' && data.pass == 1) {
965
-
966
- console.log("pingDAWS:Passed");
967
-
968
- var status = data.status;
969
- var percent = Math.round((status.archive_offset * 100.0) / status.archive_size);
970
-
971
- console.log("pingDAWS:updating progress percent");
972
- DUPX.updateProgressPercent(percent);
973
-
974
- var criticalFailureText = DUPX.getCriticalFailureText(status.failures);
975
-
976
- if(status.failures.length > 0) {
977
- console.log("pingDAWS:There are failures present. (" + status.failures.length) + ")";
978
- }
979
-
980
- if (criticalFailureText === null) {
981
- console.log("pingDAWS:No critical failures");
982
- if (status.is_done) {
983
-
984
- console.log("pingDAWS:archive has completed");
985
- if(status.failures.length > 0) {
986
-
987
- console.log(status.failures);
988
- var errorMessage = "pingDAWS:Problems during extract. These may be non-critical so continue with install.\n------\n";
989
- var len = status.failures.length;
990
-
991
- for(var j = 0; j < len; j++) {
992
- failure = status.failures[j];
993
- errorMessage += failure.subject + ":" + failure.description + "\n";
994
- }
995
-
996
- alert(errorMessage);
997
- }
998
-
999
- DUPX.clearDupArchiveStatusTimer();
1000
- console.log("pingDAWS:calling finalizeDupArchiveExtraction");
1001
- DUPX.finalizeDupArchiveExtraction(status);
1002
- console.log("pingDAWS:after finalizeDupArchiveExtraction");
1003
-
1004
- var dataJSON = JSON.stringify(data);
1005
-
1006
- // Don't stop for non-critical failures - just display those at the end
1007
-
1008
- $("#ajax-logging").val($("input:radio[name=logging]:checked").val());
1009
- $("#ajax-config-mode").val($("#config_mode").val());
1010
- $("#ajax-json").val(escape(dataJSON));
1011
-
1012
- <?php if (!DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)) : ?>
1013
- setTimeout(function () {
1014
- $('#s1-result-form').submit();
1015
- }, 500);
1016
- <?php endif; ?>
1017
- $('#progress-area').fadeOut(1000);
1018
- //Failures aren't necessarily fatal - just record them for later display
1019
-
1020
- $("#ajax-json-debug").val(dataJSON);
1021
- } else if (isClientSideKickoff) {
1022
- console.log('pingDAWS:Archive not completed so continue ping DAWS in 500');
1023
- setTimeout(DUPX.pingDAWS, 500);
1024
- }
1025
- }
1026
- else {
1027
- console.log("pingDAWS:critical failures present");
1028
- // If we get a critical failure it means it's something we can't recover from so no purpose in retrying, just fail immediately.
1029
- var errorString = 'Error Processing Step 1<br/>';
1030
-
1031
- errorString += criticalFailureText;
1032
-
1033
- DUPX.DAWSProcessingFailed(errorString);
1034
- }
1035
- } else {
1036
- var errorString = 'Error Processing Step 1<br/>';
1037
- errorString += data.error;
1038
-
1039
- DUPX.handleDAWSProcessingProblem(errorString, true);
1040
- }
1041
- },
1042
- error: function (xHr, textStatus) {
1043
- console.log('AJAX error. textStatus=');
1044
- console.log(textStatus);
1045
- DUPX.handleDAWSCommunicationProblem(xHr, true, textStatus, 'ping');
1046
- }
1047
- });
1048
- };
1049
-
1050
-
1051
- DUPX.isClientSideKickoff = function()
1052
- {
1053
- return $('#clientside_kickoff').is(':checked');
1054
- }
1055
-
1056
- DUPX.areConfigFilesPreserved = function()
1057
- {
1058
- return $('#config_mode').is(':checked');
1059
- }
1060
-
1061
- DUPX.kickOffDupArchiveExtract = function ()
1062
- {
1063
- console.log('kickOffDupArchiveExtract:start');
1064
- var $form = $('#s1-input-form');
1065
- var request = new Object();
1066
- var isClientSideKickoff = DUPX.isClientSideKickoff();
1067
-
1068
- request.action = "start_expand";
1069
- request.restore_directory = '<?php echo DUPX_U::esc_js($root_path); ?>';
1070
- request.worker_time = DUPX.DAWS.KickoffWorkerTimeInSec;
1071
- request.client_driven = isClientSideKickoff ? 1 : 0;
1072
- request.throttle_delay = DUPX.throttleDelay;
1073
- request.filtered_directories = ['dup-installer'];
1074
-
1075
- var requestString = JSON.stringify(request);
1076
-
1077
- if (!isClientSideKickoff) {
1078
- console.log('kickOffDupArchiveExtract:Setting timer');
1079
- // If server is driving things we need to poll the status
1080
- DUPX.dupArchiveStatusIntervalID = setInterval(DUPX.pingDAWS, DUPX.DAWS.StatusPeriodInMS);
1081
- }
1082
- else {
1083
- console.log('kickOffDupArchiveExtract:client side kickoff');
1084
- }
1085
-
1086
- console.log("daws url=" + DUPX.DAWS.Url);
1087
- console.log("requeststring=" + requestString);
1088
-
1089
- $.ajax({
1090
- type: "POST",
1091
- timeout: DUPX.DAWS.KickoffWorkerTimeInSec * 2000, // Double worker time and convert to ms
1092
- url: DUPX.DAWS.Url + '&daws_action=start_expand',
1093
- data: requestString,
1094
- beforeSend: function () {
1095
- DUPX.showProgressBar();
1096
- $form.hide();
1097
- $('#s1-result-form').show();
1098
- DUPX.updateProgressPercent(0);
1099
- },
1100
- success: function (respData, textStatus, xHr) {
1101
- try {
1102
- var data = DUPX.parseJSON(respData);
1103
- } catch(err) {
1104
- console.error(err);
1105
- console.error('JSON parse failed for response data: ' + respData);
1106
- console.log('kickOffDupArchiveExtract:AJAX error. textStatus=', textStatus);
1107
- DUPX.handleDAWSCommunicationProblem(xHr, false, textStatus);
1108
- return false;
1109
- }
1110
- console.log('kickOffDupArchiveExtract:success');
1111
- if (typeof (data) != 'undefined' && data.pass == 1) {
1112
-
1113
- var criticalFailureText = DUPX.getCriticalFailureText(status.failures);
1114
-
1115
- if (criticalFailureText === null) {
1116
-
1117
- var dataJSON = JSON.stringify(data);
1118
-
1119
- //RSR TODO:Need to check only for FATAL errors right now - have similar failure check as in pingdaws
1120
- DUPX.DAWS.FailureCount = 0;
1121
- console.log("kickOffDupArchiveExtract:Resetting failure count");
1122
-
1123
- $("#ajax-json-debug").val(dataJSON);
1124
- if (typeof (data) != 'undefined' && data.pass == 1) {
1125
-
1126
- if (isClientSideKickoff) {
1127
- console.log('kickOffDupArchiveExtract:Initial ping DAWS in 500');
1128
- setTimeout(DUPX.pingDAWS, 500);
1129
- }
1130
-
1131
- } else {
1132
- $('#ajaxerr-data').html('Error Processing Step 1');
1133
- DUPX.hideProgressBar();
1134
- }
1135
- } else {
1136
- // If we get a critical failure it means it's something we can't recover from so no purpose in retrying, just fail immediately.
1137
- var errorString = 'kickOffDupArchiveExtract:Error Processing Step 1<br/>';
1138
- errorString += criticalFailureText;
1139
- DUPX.DAWSProcessingFailed(errorString);
1140
- }
1141
- } else {
1142
- if ('undefined' !== typeof data.isWPAlreadyExistsError
1143
- && data.isWPAlreadyExistsError) {
1144
- DUPX.DAWSProcessingFailed(data.error);
1145
- } else {
1146
- var errorString = 'kickOffDupArchiveExtract:Error Processing Step 1<br/>';
1147
- errorString += data.error;
1148
- DUPX.handleDAWSProcessingProblem(errorString, false);
1149
- }
1150
- }
1151
- },
1152
- error: function (xHr, textStatus) {
1153
-
1154
- console.log('kickOffDupArchiveExtract:AJAX error. textStatus=', textStatus);
1155
- DUPX.handleDAWSCommunicationProblem(xHr, false, textStatus);
1156
- }
1157
- });
1158
- };
1159
-
1160
- DUPX.finalizeDupArchiveExtraction = function(dawsStatus)
1161
- {
1162
- console.log("finalizeDupArchiveExtraction:start");
1163
- var $form = $('#s1-input-form');
1164
- $("#s1-input-form-extra-data").val(JSON.stringify(dawsStatus));
1165
- console.log("finalizeDupArchiveExtraction:after stringify dawsstatus");
1166
- var formData = $form.serialize();
1167
-
1168
- $.ajax({
1169
- type: "POST",
1170
- timeout: 30000,
1171
- url: window.location.href,
1172
- data: formData,
1173
- success: function (respData, textStatus, xHr) {
1174
- try {
1175
- var data = DUPX.parseJSON(respData);
1176
- } catch(err) {
1177
- console.error(err);
1178
- console.error('JSON parse failed for response data: ' + respData);
1179
- console.log("finalizeDupArchiveExtraction:error");
1180
- console.log(xHr.statusText);
1181
- console.log(xHr.getAllResponseHeaders());
1182
- console.log(xHr.responseText);
1183
- return false;
1184
- }
1185
- console.log("finalizeDupArchiveExtraction:success");
1186
- },
1187
- error: function (xHr) {
1188
- console.log("finalizeDupArchiveExtraction:error");
1189
- console.log(xHr.statusText);
1190
- console.log(xHr.getAllResponseHeaders());
1191
- console.log(xHr.responseText);
1192
- }
1193
- });
1194
- };
1195
-
1196
- /**
1197
- * Performs Ajax post to either do a zip or manual extract and then create db
1198
- */
1199
- DUPX.runStandardExtraction = function ()
1200
- {
1201
- var $form = $('#s1-input-form');
1202
-
1203
- //3600000 = 60 minutes
1204
- //If the extraction takes longer than 30 minutes then user
1205
- //will probably want to do a manual extraction or even FTP
1206
- $.ajax({
1207
- type: "POST",
1208
- timeout: 3600000,
1209
- cache: false,
1210
- url: window.location.href,
1211
- data: $form.serialize(),
1212
- beforeSend: function () {
1213
- DUPX.showProgressBar();
1214
- $form.hide();
1215
- $('#s1-result-form').show();
1216
- },
1217
- success: function (data, textStatus, xHr) {
1218
- $("#ajax-json-debug").val(data);
1219
- var dataJSON = data;
1220
- data = DUPX.parseJSON(data, xHr, textStatus);
1221
- if (false === data) {
1222
- return;
1223
- }
1224
- $("#ajax-json-debug").val(dataJSON);
1225
- if (typeof (data) != 'undefined' && data.pass == 1) {
1226
- $("#ajax-logging").val($("input:radio[name=logging]:checked").val());
1227
- $("#ajax-config-mode").val($("#config_mode").val());
1228
- $("#ajax-json").val(escape(dataJSON));
1229
-
1230
- <?php if (!DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)) : ?>
1231
- setTimeout(function () {$('#s1-result-form').submit();}, 500);
1232
- <?php endif; ?>
1233
- $('#progress-area').fadeOut(1000);
1234
- } else {
1235
- $('#ajaxerr-data').html('Error Processing Step 1');
1236
- DUPX.hideProgressBar();
1237
- }
1238
- },
1239
- error: function (xHr) {
1240
- DUPX.ajaxCommunicationFailed(xHr, '', 'extract');
1241
- }
1242
- });
1243
- };
1244
-
1245
- DUPX.ajaxCommunicationFailed = function (xhr, textStatus, page)
1246
- {
1247
- var status = "<b>Server Code:</b> " + xhr.status + "<br/>";
1248
- status += "<b>Status:</b> " + xhr.statusText + "<br/>";
1249
- status += "<b>Response:</b> " + xhr.responseText + "<hr/>";
1250
-
1251
- if(textStatus && textStatus.toLowerCase() == "timeout" || textStatus.toLowerCase() == "service unavailable") {
1252
-
1253
- var default_timeout_message = "<b>Recommendation:</b><br/>";
1254
- default_timeout_message += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116102141#faq-trouble-100-q'>this FAQ item</a> for possible resolutions.";
1255
- default_timeout_message += "<hr>";
1256
- default_timeout_message += "<b>Additional Resources...</b><br/>";
1257
- default_timeout_message += "With thousands of different permutations it's difficult to try and debug/diagnose a server. If you're running into timeout issues and need help we suggest you follow these steps:<br/><br/>";
1258
- default_timeout_message += "<ol>";
1259
- default_timeout_message += "<li><strong>Contact Host:</strong> Tell your host that you're running into PHP/Web Server timeout issues and ask them if they have any recommendations</li>";
1260
- default_timeout_message += "<li><strong>Dedicated Help:</strong> If you're in a time-crunch we suggest that you contact <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116150030#faq-resource-030-q'>professional server administrator</a>. A dedicated resource like this will be able to work with you around the clock to the solve the issue much faster than we can in most cases.</li>";
1261
- default_timeout_message += "<li><strong>Consider Upgrading:</strong> If you're on a budget host then you may run into constraints. If you're running a larger or more complex site it might be worth upgrading to a <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116150030#faq-resource-040-q'>managed VPS server</a>. These systems will pretty much give you full control to use the software without constraints and come with excellent support from the hosting company.</li>";
1262
- default_timeout_message += "<li><strong>Contact SnapCreek:</strong> We will try our best to help configure and point users in the right direction, however these types of issues can be time-consuming and can take time from our support staff.</li>";
1263
- default_timeout_message += "</ol>";
1264
-
1265
- if(page) {
1266
- switch(page) {
1267
- default:
1268
- status += default_timeout_message;
1269
- break;
1270
- case 'extract':
1271
- status += "<b>Recommendation:</b><br/>";
1272
- status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q'>this FAQ item</a> for possible resolutions.<br/><br/>";
1273
- break;
1274
- case 'ping':
1275
- status += "<b>Recommendation:</b><br/>";
1276
- status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116152758#faq-trouble-030-q'>this FAQ item</a> for possible resolutions.<br/><br/>";
1277
- break;
1278
- case 'delete-site':
1279
- status += "<b>Recommendation:</b><br/>";
1280
- status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116153643#faq-installer-120-q'>this FAQ item</a> for possible resolutions.<br/><br/>";
1281
- break;
1282
- }
1283
- } else {
1284
- status += default_timeout_message;
1285
- }
1286
-
1287
- }
1288
- else if ((xhr.status == 403) || (xhr.status == 500)) {
1289
- status += "<b>Recommendation:</b><br/>";
1290
- status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-120-q'>this FAQ item</a> for possible resolutions.<br/><br/>"
1291
- } else if ((xhr.status == 0) || (xhr.status == 200)) {
1292
- status += "<b>Recommendation:</b><br/>";
1293
- status += "Possible server timeout! Performing a 'Manual Extraction' can avoid timeouts.";
1294
- status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q'>this FAQ item</a> for a complete overview.<br/><br/>"
1295
- } else {
1296
- status += "<b>Additional Resources:</b><br/> ";
1297
- status += "&raquo; <a target='_blank' href='https://snapcreek.com/duplicator/docs/'>Help Resources</a><br/>";
1298
- status += "&raquo; <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/'>Technical FAQ</a>";
1299
- }
1300
-
1301
- $('#ajaxerr-data').html(status);
1302
- DUPX.hideProgressBar();
1303
- };
1304
-
1305
- DUPX.parseJSON = function(mixData, xHr, textStatus) {
1306
- try {
1307
- var parsed = JSON.parse(mixData);
1308
- return parsed;
1309
- } catch (e) {
1310
- console.log("JSON parse failed - 1");
1311
- }
1312
-
1313
- var jsonStartPos = mixData.indexOf('{');
1314
- var jsonLastPos = mixData.lastIndexOf('}');
1315
- if (jsonStartPos > -1 && jsonLastPos > -1) {
1316
- var expectedJsonStr = mixData.slice(jsonStartPos, jsonLastPos + 1);
1317
- try {
1318
- var parsed = JSON.parse(expectedJsonStr);
1319
- return parsed;
1320
- } catch (e) {
1321
- console.log("JSON parse failed - 2");
1322
- DUPX.ajaxCommunicationFailed(xHr, textStatus, 'extract');
1323
- return false;
1324
- }
1325
- }
1326
- DUPX.ajaxCommunicationFailed(xHr, textStatus, 'extract');
1327
- return false;
1328
- }
1329
-
1330
- /** Go back on AJAX result view */
1331
- DUPX.hideErrorResult = function ()
1332
- {
1333
- $('#s1-result-form').hide();
1334
- $('#s1-input-form').show(200);
1335
- }
1336
-
1337
- /**
1338
- * Accetps Usage Warning */
1339
- DUPX.acceptWarning = function ()
1340
- {
1341
- if ($("#accept-warnings").is(':checked')) {
1342
- $("#s1-deploy-btn").removeAttr("disabled");
1343
- $("#s1-deploy-btn").removeAttr("title");
1344
- } else {
1345
- $("#s1-deploy-btn").attr("disabled", "true");
1346
- $("#s1-deploy-btn").attr("title", "<?php echo DUPX_U::esc_js($agree_msg); ?>");
1347
- }
1348
- };
1349
-
1350
- DUPX.onSafeModeSwitch = function ()
1351
- {
1352
- var mode = $('#exe_safe_mode').val();
1353
- if (mode == 0) {
1354
- $("#config_mode").removeAttr("disabled");
1355
- } else if(mode == 1 || mode ==2) {
1356
- $("#config_mode").val("NEW");
1357
- $("#config_mode").attr("disabled", true);
1358
- $('#config_mode option:eq(0)').prop('selected', true)
1359
- }
1360
-
1361
- $('#exe-safe-mode').val(mode);
1362
- };
1363
-
1364
- //DOCUMENT LOAD
1365
- $(document).ready(function() {
1366
- DUPX.DAWS = new Object();
1367
- DUPX.DAWS.Url = window.location.href + '?is_daws=1&daws_csrf_token=<?php echo urlencode(DUPX_CSRF::generate('daws'));?>';
1368
- DUPX.DAWS.StatusPeriodInMS = 5000;
1369
- DUPX.DAWS.PingWorkerTimeInSec = 9;
1370
- DUPX.DAWS.KickoffWorkerTimeInSec = 6; // Want the initial progress % to come back quicker
1371
-
1372
- DUPX.DAWS.MaxRetries = 10;
1373
- DUPX.DAWS.RetryDelayInMs = 8000;
1374
-
1375
- DUPX.dupArchiveStatusIntervalID = -1;
1376
- DUPX.DAWS.FailureCount = 0;
1377
- DUPX.throttleDelay = 0;
1378
-
1379
- //INIT Routines
1380
- $("*[data-type='toggle']").click(DUPX.toggleClick);
1381
- $("#tabs").tabs();
1382
- DUPX.acceptWarning();
1383
- <?php
1384
- $isWindows = DUPX_U::isWindows();
1385
- if (!$isWindows) {
1386
- ?>
1387
- $('#set_file_perms').trigger("click");
1388
- $('#set_dir_perms').trigger("click");
1389
- <?php
1390
- }
1391
- ?>
1392
- DUPX.toggleSetupType();
1393
-
1394
- <?php echo ($arcCheck == 'Fail') ? "$('#s1-area-archive-file-link').trigger('click');" : ""; ?>
1395
- <?php echo (!$all_success) ? "$('#s1-area-sys-setup-link').trigger('click');" : ""; ?>
1396
- });
1397
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+ /** IDE HELPERS */
4
+ /* @var $GLOBALS['DUPX_AC'] DUPX_ArchiveConfig */
5
+ /* @var $archive_config DUPX_ArchiveConfig */
6
+ /* @var $installer_state DUPX_InstallerState */
7
+
8
+ require_once($GLOBALS['DUPX_INIT'].'/classes/config/class.archive.config.php');
9
+ require_once($GLOBALS['DUPX_INIT'].'/ctrls/classes/class.ctrl.extraction.php');
10
+
11
+ $is_wpconfarc_present = file_exists(DUPX_Package::getWpconfigArkPath());
12
+ //ARCHIVE FILE
13
+ if (file_exists($GLOBALS['FW_PACKAGE_PATH'])) {
14
+ $arcCheck = 'Pass';
15
+ } else {
16
+ if ($is_wpconfarc_present) {
17
+ $arcCheck = 'Warn';
18
+ } else {
19
+ $arcCheck = 'Fail';
20
+ }
21
+ }
22
+ $arcSize = file_exists($GLOBALS['FW_PACKAGE_PATH']) ? @filesize($GLOBALS['FW_PACKAGE_PATH']) : 0;
23
+ $arcSize = is_numeric($arcSize) ? $arcSize : 0;
24
+
25
+ $installer_state = DUPX_InstallerState::getInstance();
26
+ $mh_manager = DUPX_Custom_Host_Manager::getInstance();
27
+ $is_overwrite_mode = ($installer_state->mode === DUPX_InstallerMode::OverwriteInstall);
28
+ $is_wordpress = DUPX_Server::isWordPress();
29
+ $is_dbonly = $GLOBALS['DUPX_AC']->exportOnlyDB;
30
+ $managed_host = $mh_manager->isManaged();
31
+
32
+ //REQUIRMENTS
33
+ $req = array();
34
+ $req['10'] = DUPX_Server::is_dir_writable($GLOBALS['DUPX_ROOT']) ? 'Pass' : 'Fail';
35
+ $req['20'] = function_exists('mysqli_connect') ? 'Pass' : 'Fail';
36
+ $req['30'] = DUPX_Server::$php_version_safe ? 'Pass' : 'Fail';
37
+ $req['40'] = $managed_host === false ? 'Pass' : 'Fail';
38
+ $all_req = in_array('Fail', $req) ? 'Fail' : 'Pass';
39
+
40
+ //NOTICES
41
+ $openbase = ini_get("open_basedir");
42
+ $datetime1 = $GLOBALS['DUPX_AC']->created;
43
+ $datetime2 = date("Y-m-d H:i:s");
44
+ $fulldays = round(abs(strtotime($datetime1) - strtotime($datetime2)) / 86400);
45
+ $root_path = DupLiteSnapLibIOU::safePath($GLOBALS['DUPX_ROOT'], true);
46
+ $wpconf_path = "{$root_path}/wp-config.php";
47
+ $max_time_zero = ($GLOBALS['DUPX_ENFORCE_PHP_INI']) ? false : @set_time_limit(0);
48
+ $max_time_size = 314572800; //300MB
49
+ $max_time_ini = ini_get('max_execution_time');
50
+ $max_time_warn = (is_numeric($max_time_ini) && $max_time_ini < 31 && $max_time_ini > 0) && $arcSize > $max_time_size;
51
+ $parentWordFencePath = DUPX_Server::parentWordfencePath();
52
+
53
+ $notice = array();
54
+ $notice['10'] = !$is_overwrite_mode ? 'Good' : 'Warn';
55
+ $notice['20'] = !$is_wpconfarc_present ? 'Good' : 'Warn';
56
+ if ($is_dbonly) {
57
+ $notice['25'] = $is_wordpress ? 'Good' : 'Warn';
58
+ }
59
+ $notice['30'] = $fulldays <= 180 ? 'Good' : 'Warn';
60
+
61
+ $packagePHP = $GLOBALS['DUPX_AC']->version_php;
62
+ $currentPHP = DUPX_Server::$php_version;
63
+ $packagePHPMajor = intval($packagePHP);
64
+ $currentPHPMajor = intval($currentPHP);
65
+ $notice['45'] = ($packagePHPMajor === $currentPHPMajor || $GLOBALS['DUPX_AC']->exportOnlyDB) ? 'Good' : 'Warn';
66
+
67
+ $notice['50'] = empty($openbase) ? 'Good' : 'Warn';
68
+ $notice['60'] = !$max_time_warn ? 'Good' : 'Warn';
69
+ $notice['70'] = $GLOBALS['DUPX_AC']->mu_mode == 0 ? 'Good' : 'Warn';
70
+ $notice['80'] = !$GLOBALS['DUPX_AC']->is_outer_root_wp_config_file ? 'Good' : 'Warn';
71
+ if ($GLOBALS['DUPX_AC']->exportOnlyDB) {
72
+ $notice['90'] = 'Good';
73
+ } else {
74
+ $notice['90'] = (!$GLOBALS['DUPX_AC']->is_outer_root_wp_content_dir) ? 'Good' : 'Warn';
75
+ }
76
+
77
+ $space_free = @disk_free_space($GLOBALS['DUPX_ROOT']);
78
+ $archive_size = file_exists($GLOBALS['FW_PACKAGE_PATH']) ? filesize($GLOBALS['FW_PACKAGE_PATH']) : 0;
79
+ $notice['100'] = ($space_free && $archive_size > $space_free) ? 'Warn' : 'Good';
80
+ $notice['110'] = $parentWordFencePath === false ? 'Good' : 'Warn';
81
+
82
+ $all_notice = in_array('Warn', $notice) ? 'Warn' : 'Good';
83
+
84
+ //SUMMATION
85
+ $req_success = ($all_req == 'Pass');
86
+ $req_notice = ($all_notice == 'Good');
87
+ $all_success = ($req_success && $req_notice);
88
+ $agree_msg = "To enable this button the checkbox above under the 'Terms & Notices' must be checked.";
89
+
90
+ $shell_exec_unzip_path = DUPX_Server::get_unzip_filepath();
91
+ $shell_exec_zip_enabled = ($shell_exec_unzip_path != null);
92
+ $zip_archive_enabled = class_exists('ZipArchive') ? 'Enabled' : 'Not Enabled';
93
+ $archive_config = DUPX_ArchiveConfig::getInstance();
94
+ ?>
95
+
96
+ <form id="s1-input-form" method="post" class="content-form" autocomplete="off">
97
+ <input type="hidden" name="view" value="step1" />
98
+ <input type="hidden" name="csrf_token" value="<?php echo DUPX_CSRF::generate('step1'); ?>">
99
+ <input type="hidden" name="ctrl_action" value="ctrl-step1" />
100
+ <input type="hidden" name="ctrl_csrf_token" value="<?php echo DUPX_U::esc_attr(DUPX_CSRF::generate('ctrl-step1')); ?>">
101
+ <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_html($_POST['secure-pass']); ?>" />
102
+ <input type="hidden" id="s1-input-form-extra-data" name="extra_data" />
103
+
104
+ <div class="hdr-main">
105
+ Step <span class="step">1</span> of 4: Deployment
106
+ <div class="sub-header">This step will extract the archive file contents.</div>
107
+ </div><br/>
108
+
109
+ <!-- ====================================
110
+ SETUP TYPE: @todo implement
111
+ ==================================== -->
112
+ <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s1-area-setup-type" style="display:none">
113
+ <a id="s1-area-setup-type-link"><i class="fa fa-plus-square"></i>Setup</a>
114
+ </div>
115
+ <div id="s1-area-setup-type" style="display:none">
116
+
117
+ <!-- STANDARD INSTALL -->
118
+ <input type="radio" id="setup-type-fresh" name="setup_type" value="1" checked="true" onclick="DUPX.toggleSetupType()" />
119
+ <label for="setup-type-fresh"><b>Standard Install</b></label>
120
+ <i class="fas fa-question-circle fa-sm"
121
+ data-tooltip-title="Standard Install"
122
+ data-tooltip="A standard install is the default way Duplicator has always worked. Setup your package in an empty directory and run the installer."></i>
123
+ <br/>
124
+ <div class="s1-setup-type-sub" id="s1-setup-type-sub-1">
125
+ <input type="checkbox" name="setup-backup-files" id="setup-backup-files-fresh" />
126
+ <label for="setup-backup-files-fresh">Backup Existing Files</label><br/>
127
+ <input type="checkbox" name="setup-remove-files" id="setup-remove-files-fresh" />
128
+ <label for="setup-remove-files-fresh">Remove Existing Files</label><br/>
129
+ </div><br/>
130
+
131
+ <!-- OVERWRITE INSTALL -->
132
+ <input type="radio" id="setup-type-overwrite" name="setup_type" value="2" onclick="DUPX.toggleSetupType()" />
133
+ <label for="setup-type-overwrite"><b>Overwrite Install (Beta)</b></label>
134
+ <i class="fas fa-question-circle fa-sm"
135
+ data-tooltip-title="Overwrite Install"
136
+ data-tooltip="An Overwrite Install allows Duplicator to overwrite an existing WordPress Site."></i><br/>
137
+ <div class="s1-setup-type-sub" id="s1-setup-type-sub-2">
138
+ <input type="checkbox" name="setup-backup-files" id="setup-backup-files-overwrite" />
139
+ <label for="setup-backup-files-overwrite">Backup Existing Files</label><br/>
140
+ <input type="checkbox" name="setup-remove-files" id="setup-remove-files-overwrite" />
141
+ <label for="setup-remove-files-overwrite">Remove Existing Files</label><br/>
142
+ <input type="checkbox" name="setup-backup-database" id="setup-backup-database-overwrite" />
143
+ <label for="setup-backup-database-overwrite">Backup Existing Database</label> <br/>
144
+ </div><br/>
145
+
146
+ <!-- DB-ONLY INSTALL -->
147
+ <input type="radio" id="setup-type-db" name="setup_type" value="3" onclick="DUPX.toggleSetupType()" />
148
+ <label for="setup-type-db"><b>Database Only Install</b></label>
149
+ <i class="fas fa-question-circle fa-sm"
150
+ data-tooltip-title="Database Only"
151
+ data-tooltip="A database only install allows Duplicator to connect to a database and install only the database."></i><br/>
152
+ <div class="s1-setup-type-sub" id="s1-setup-type-sub-3">
153
+ <input type="checkbox" name="setup-backup-database" id="setup-backup-database-db" />
154
+ <label for="setup-backup-database-db">Backup Existing Database</label> <br/>
155
+ </div><br/>
156
+
157
+ </div>
158
+
159
+
160
+ <!-- ====================================
161
+ ARCHIVE
162
+ ==================================== -->
163
+ <div class="hdr-sub1 toggle-hdr" data-status="<?php echo strtolower($arcCheck); ?>" data-type="toggle auto" data-target="#s1-area-archive-file">
164
+ <a id="s1-area-archive-file-link"><i class="fa fa-plus-square"></i>Setup</a>
165
+ <?php
166
+ $badge = DUPX_View_Funcs::getBadgeClassFromCheckStatus($arcCheck);
167
+ ?>
168
+ <div class="<?php echo $badge; ?>">
169
+ <?php echo $arcCheck; ?>
170
+ </div>
171
+ </div>
172
+ <div id="s1-area-archive-file" style="display:none" class="hdr-sub1-area">
173
+ <div id="tabs">
174
+ <ul>
175
+ <li><a href="#tabs-1">Archive</a></li>
176
+ </ul>
177
+ <div id="tabs-1">
178
+
179
+ <table class="s1-archive-local">
180
+ <tr>
181
+ <td colspan="2"><div class="hdr-sub3">Site Details</div></td>
182
+ </tr>
183
+ <tr>
184
+ <td>Site:</td>
185
+ <td><?php echo DUPX_U::esc_html($GLOBALS['DUPX_AC']->blogname); ?> </td>
186
+ </tr>
187
+ <tr>
188
+ <td>Notes:</td>
189
+ <td><?php echo strlen($GLOBALS['DUPX_AC']->package_notes) ? DUPX_U::esc_html($GLOBALS['DUPX_AC']->package_notes) : " - no notes - "; ?></td>
190
+ </tr>
191
+ <?php if ($GLOBALS['DUPX_AC']->exportOnlyDB) : ?>
192
+ <tr>
193
+ <td>Mode:</td>
194
+ <td>Archive only database was enabled during package package creation.</td>
195
+ </tr>
196
+ <?php endif; ?>
197
+ </table>
198
+
199
+ <table class="s1-archive-local">
200
+ <tr>
201
+ <td colspan="2"><div class="hdr-sub3">File Details</div></td>
202
+ </tr>
203
+ <tr>
204
+ <td style="vertical-align:top">Status:</td>
205
+ <td>
206
+ <?php if ($arcCheck == 'Fail' || $arcCheck == 'Warn') : ?>
207
+ <span class="dupx-fail" style="font-style:italic">
208
+ <?php
209
+ if ($arcCheck == 'Warn') {
210
+ ?>
211
+ The archive file named above must be the <u>exact</u> name of the archive file placed in the root path (character for character). But you can proceed with choosing Manual Archive Extraction.
212
+ <?php
213
+ } else {
214
+ ?>
215
+ The archive file named above must be the <u>exact</u> name of the archive file placed in the root path (character for character).
216
+ When downloading the package files make sure both files are from the same package line. <br/><br/>
217
+
218
+ If the contents of the archive were manually transferred to this location without the archive file then simply create a temp file named with
219
+ the exact name shown above and place the file in the same directory as the installer.php file. The temp file will not need to contain any data.
220
+ Afterward, refresh this page and continue with the install process.
221
+ <?php
222
+ }
223
+ ?>
224
+ </span>
225
+ <?php else : ?>
226
+ <span class="dupx-pass">Archive file successfully detected.</span>
227
+ <?php endif; ?>
228
+ </td>
229
+ </tr>
230
+ <tr>
231
+ <td>Path:</td>
232
+ <td><?php echo DUPX_U::esc_html($root_path); ?> </td>
233
+ </tr>
234
+ <tr>
235
+ <td>Size:</td>
236
+ <td><?php echo DUPX_U::readableByteSize($arcSize); ?> </td>
237
+ </tr>
238
+ </table>
239
+
240
+ </div>
241
+ <!--div id="tabs-2"><p>Content Here</p></div-->
242
+ </div>
243
+ </div><br/><br/>
244
+
245
+ <!-- ====================================
246
+ VALIDATION
247
+ ==================================== -->
248
+ <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s1-area-sys-setup">
249
+ <a id="s1-area-sys-setup-link"><i class="fa fa-plus-square"></i>Validation</a>
250
+ <div class="<?php echo ( $req_success) ? 'status-badge-pass' : 'status-badge-fail'; ?> ">
251
+ <?php echo ( $req_success) ? 'Pass' : 'Fail'; ?>
252
+ </div>
253
+ </div>
254
+ <div id="s1-area-sys-setup" style="display:none" class="hdr-sub1-area">
255
+ <div class='info-top'>The system validation checks help to make sure the system is ready for install.</div>
256
+
257
+ <!-- REQUIREMENTS -->
258
+ <div class="s1-reqs" id="s1-reqs-all">
259
+ <div class="header">
260
+ <table class="s1-checks-area">
261
+ <tr>
262
+ <td class="title">Requirements <small>(must pass)</small></td>
263
+ <td class="toggle"><a href="javascript:void(0)" onclick="DUPX.toggleAll('#s1-reqs-all')">[toggle]</a></td>
264
+ </tr>
265
+ </table>
266
+ </div>
267
+
268
+ <!-- REQ 10 -->
269
+ <?php
270
+ $status = strtolower($req['10']);
271
+ ?>
272
+ <div class="status <?php echo DUPX_U::esc_attr($status); ?>"><?php echo DUPX_U::esc_html($req['10']); ?></div>
273
+ <div class="title" data-status="<?php echo DUPX_U::esc_attr($status); ?>" data-type="toggle auto" data-target="#s1-reqs10"><i class="fa fa-caret-right"></i> Permissions</div>
274
+ <div class="info" id="s1-reqs10">
275
+ <table>
276
+ <tr>
277
+ <td><b>Deployment Path:</b> </td>
278
+ <td><i><?php echo "{$GLOBALS['DUPX_ROOT']}"; ?></i> </td>
279
+ </tr>
280
+ <tr>
281
+ <td><b>Suhosin Extension:</b> </td>
282
+ <td><?php echo extension_loaded('suhosin') ? "<i class='dupx-fail'>Enabled</i>" : "<i class='dupx-pass'>Disabled</i>"; ?> </td>
283
+ </tr>
284
+ <tr>
285
+ <td><b>PHP Safe Mode:</b> </td>
286
+ <td><?php echo (DUPX_Server::$php_safe_mode_on) ? "<i class='dupx-fail'>Enabled</i>" : "<i class='dupx-pass'>Disabled</i>"; ?> </td>
287
+ </tr>
288
+ </table><br/>
289
+
290
+ The deployment path must be writable by PHP in order to extract the archive file. Incorrect permissions and extension such as
291
+ <a href="https://suhosin.org/stories/index.html" target="_blank">suhosin</a> can sometimes interfere with PHP being able to write/extract files.
292
+ Please see the <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-055-q" target="_blank">FAQ permission</a> help link for complete details.
293
+ PHP with <a href='http://php.net/manual/en/features.safe-mode.php' target='_blank'>safe mode</a> should be disabled. If Safe Mode is enabled then
294
+ please contact your hosting provider or server administrator to disable PHP safe mode.
295
+ </div>
296
+
297
+ <!-- REQ 20 -->
298
+ <div class="status <?php echo strtolower($req['20']); ?>"><?php echo DUPX_U::esc_html($req['20']); ?></div>
299
+ <div class="title" data-status="<?php echo strtolower($req['20']); ?>" data-type="toggle auto" data-target="#s1-reqs20"><i class="fa fa-caret-right"></i> PHP Mysqli</div>
300
+ <div class="info" id="s1-reqs20">
301
+ Support for the PHP <a href='http://us2.php.net/manual/en/mysqli.installation.php' target='_blank'>mysqli extension</a> is required.
302
+ Please contact your hosting provider or server administrator to enable the mysqli extension. <i>The detection for this call uses
303
+ the function_exists('mysqli_connect') call.</i>
304
+ </div>
305
+
306
+ <!-- REQ 30 -->
307
+ <div class="status <?php echo strtolower($req['30']); ?>"><?php echo DUPX_U::esc_html($req['30']); ?></div>
308
+ <div class="title" data-status="<?php echo strtolower($req['30']); ?>" data-type="toggle auto" data-target="#s1-reqs30"><i class="fa fa-caret-right"></i> PHP Version</div>
309
+ <div class="info" id="s1-reqs30">
310
+ This server is running: <b>PHP <?php echo DUPX_Server::$php_version ?></b>. <i>A minimum of PHP 5.3.8+ is required. PHP 7.0+ is recommended.</i>
311
+ <br/><br/>
312
+
313
+ If this requirement fails contact your host or server administrator and let them know you would like to upgrade your PHP version.
314
+ For more information on this topic see the FAQ titled <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-licensing-017-q" target="_blank">What version of PHP Does Duplicator Support?</a>
315
+ </div>
316
+
317
+ <!-- REQ 40 -->
318
+ <div class="status <?php echo strtolower($req['40']); ?>"><?php echo DUPX_U::esc_html($req['40']); ?></div>
319
+ <div class="title" data-status="<?php echo strtolower($req['40']); ?>" data-type="toggle auto" data-target="#s1-reqs40"><i class="fa fa-caret-right"></i> Managed Environment</div>
320
+ <div class="info" id="s1-reqs40">
321
+ <p>
322
+ <?php if ($managed_host !== false): ?>
323
+ The installer has detected that this server is possibly in a managed hosting setup. The followings checks
324
+ have been made which will not allow the installer to continue.
325
+ <?php else: ?>
326
+ Current host is not managed.
327
+ <?php endif; ?>
328
+ </p>
329
+ <ul>
330
+ <li>
331
+ <b>Managed system: </b> <?php echo is_string($managed_host)
332
+ ? '<span class="maroon">It appears the installer is being executed on "' . $mh_manager->getHosting($managed_host)->getLabel() . '". Managed hosting is not presently supported in Duplicator Lite.</span>'
333
+ : "<span class='green'>No restrictions have been found for this host.</span>" ?>
334
+ </li>
335
+ <li>
336
+ <b>Configuration file: </b><?php echo $mh_manager->wpConfigIsNotWriteable()
337
+ ? "<span class='maroon'>The WordPress configuration file (wp-config.php) must be accessible and writeable to the installer</span>"
338
+ : "<span class='green'>The wp-config.php is accessible to the installer.</span>" ?>
339
+ </li>
340
+ <li>
341
+ <b>Core Directories: </b><?php echo $mh_manager->notAccessibleCoreDirPresent() > 0
342
+ ? "<span class='maroon'>The WordPress core directories wp-admin, wp-content and wp-includes must be accessible and writeable to the installer</span>"
343
+ : "<span class='green'>The WordPress core directories are accessible to the installer</span>"; ?>
344
+ </li>
345
+ </ul>
346
+ </div>
347
+ </div><br/>
348
+
349
+ <!-- ====================================
350
+ NOTICES -->
351
+ <div class="s1-reqs" id="s1-notice-all">
352
+ <div class="header">
353
+ <table class="s1-checks-area">
354
+ <tr>
355
+ <td class="title">Notices <small>(optional)</small></td>
356
+ <td class="toggle"><a href="javascript:void(0)" onclick="DUPX.toggleAll('#s1-notice-all')">[toggle]</a></td>
357
+ </tr>
358
+ </table>
359
+ </div>
360
+
361
+ <!-- NOTICE 10: OVERWRITE INSTALL -->
362
+ <?php if ($is_overwrite_mode && $is_wordpress) : ?>
363
+ <div class="status fail">Warn</div>
364
+ <div class="title" data-status="warn" data-type="toggle auto" data-target="#s1-notice10"><i class="fa fa-caret-right"></i> Overwrite Install (Beta)</div>
365
+ <div class="info" id="s1-notice10">
366
+ <?php if ($GLOBALS['DUPX_AC']->installSiteOverwriteOn || $is_dbonly) { ?>
367
+ <div class="gray-panel warn-text gray-panel-overwrite" >
368
+ <i class="fas fa-exclamation-triangle fa-lg"></i> WARNING: The Duplicator installer file is currently placed in a location that has an existing WordPress site!
369
+ Continuing with this install process will <u>overwrite</u> all existing files and the database associated with this WordPress site. Only continue
370
+ with this process if this site is no longer needed.<br/>
371
+ </div>
372
+ <?php } ?>
373
+ <p style="font-size:14px">
374
+ <b><i class="fas fa-folder-open"></i> Deployment Path:</b> <i><?php echo "{$GLOBALS['DUPX_ROOT']}"; ?></i>
375
+ </p>
376
+ <?php if ($GLOBALS['DUPX_AC']->installSiteOverwriteOn || $is_dbonly) { ?>
377
+ <p>
378
+ Duplicator is in "Overwrite Install (Beta)" mode because it has detected an existing WordPress site at the deployment path above. This mode allows for the installer
379
+ to be dropped directly into an existing WordPress site and overwrite its contents. Any content inside of the archive file
380
+ will <u>overwrite</u> the existing contents in the deployment path above. To continue choose one of these options:
381
+ </p>
382
+
383
+ <ol>
384
+ <li>Ignore this notice and continue with the install to overwrite this WordPress site.</li>
385
+ <li>Move the installer and archive to an <u>empty directory</u>. Then install from there to keep this site intact.</li>
386
+ </ol>
387
+
388
+ <p style="color:maroon">
389
+ <b>Notice:</b> Existing content such as plugin/themes/images will still show-up after the install is complete if they did not already exist in
390
+ the archive file. For example, if plugin X is in the current site but that same plugin X <u>does not exist</u> in the archive file
391
+ then that plugin will display as a disabled plugin after the install is completed. The same concept with themes, images and files apply.
392
+ This will not impact the site's operation, and the behavior is expected since the install process only extracts the archive files to the deployment
393
+ path.
394
+ </p>
395
+
396
+ <p>
397
+ <b>Recommendation:</b> It is recommended you only overwrite WordPress sites that have no value, such as a temporary staging site. On step 2
398
+ of this installer you will be given the option to change the database if needed. However, by default the current sites database will be
399
+ replaced with the one in this Duplicator package.
400
+ </p>
401
+ <?php
402
+ } else {
403
+ ?>
404
+ <p>
405
+ Duplicator works best by placing the installer and archive files into an empty directory. If a wp-config.php file is found in the extraction
406
+ directory it might indicate that a pre-existing WordPress site exists which can lead to a bad install.
407
+ </p>
408
+ <b>Options:</b>
409
+ <ul style="margin-bottom: 0">
410
+ <li>If the archive was already manually extracted then <a href="javascript:void(0)" onclick="DUPX.getManaualArchiveOpt()">[Enable Manual Archive Extraction]</a></li>
411
+ <li>Empty the directory of all files, except for the installer.php and archive.zip/daf files.</li>
412
+ <li>Advanced Users: Can attempt to manually remove the wp-config file only if the archive was manually extracted.</li>
413
+ </ul>
414
+ <?php
415
+ }
416
+ ?>
417
+ </div>
418
+
419
+ <!-- NOTICE 20: ARCHIVE EXTRACTED -->
420
+ <?php elseif ($is_wpconfarc_present && file_exists("{$root_path}/dup-installer")) : ?>
421
+ <div class="status fail">Warn</div>
422
+ <div class="title" data-type="toggle" data-target="#s1-notice20"><i class="fa fa-caret-right"></i> Archive Extracted</div>
423
+ <div class="info" id="s1-notice20">
424
+ <b>Deployment Path:</b> <i><?php echo "{$GLOBALS['DUPX_ROOT']}"; ?></i>
425
+ <br/><br/>
426
+
427
+ The installer has detected that the archive file has been extracted to the deployment path above. To continue choose one of these options:
428
+
429
+ <ol>
430
+ <li>Skip the extraction process by <a href="javascript:void(0)" onclick="DUPX.getManaualArchiveOpt()">[enabling manual archive extraction]</a> </li>
431
+ <li>Ignore this message and continue with the install process to re-extract the archive file.</li>
432
+ </ol>
433
+
434
+ <small>Note: This test looks for a file named <i>dup-wp-config-arc__[HASH].txt</i> in the dup-installer directory. If the file exists then this notice is shown.
435
+ The <i>dup-wp-config-arc__[HASH].txt</i> file is created with every archive and removed once the install is complete. For more details on this process see the
436
+ <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q" target="_blank">manual extraction FAQ</a>.</small>
437
+ </div>
438
+ <?php endif; ?>
439
+
440
+ <!-- NOTICE 25: DATABASE ONLY -->
441
+ <?php if ($is_dbonly && !$is_wordpress) : ?>
442
+ <div class="status fail">Warn</div>
443
+ <div class="title" data-type="toggle" data-target="#s1-notice25"><i class="fa fa-caret-right"></i> Database Only</div>
444
+ <div class="info" id="s1-notice25">
445
+ <b>Deployment Path:</b> <i><?php echo "{$GLOBALS['DUPX_ROOT']}"; ?></i>
446
+ <br/><br/>
447
+
448
+ The installer has detected that a WordPress site does not exist at the deployment path above. This installer is currently in 'Database Only' mode because that is
449
+ how the archive was created. If core WordPress site files do not exist at the path above then they will need to be placed there in order for a WordPress site
450
+ to properly work. To continue choose one of these options:
451
+
452
+ <ol>
453
+ <li>Place this installer and archive at a path where core WordPress files already exist to hide this message. </li>
454
+ <li>Create a new package that includes both the database and the core WordPress files.</li>
455
+ <li>Ignore this message and install only the database (for advanced users only).</li>
456
+ </ol>
457
+
458
+ <small>Note: This test simply looks for the directories <?php echo DUPX_Server::$wpCoreDirsList; ?> and a wp-config.php file. If they are not found in the
459
+ deployment path above then this notice is shown.</small>
460
+
461
+ </div>
462
+ <?php endif; ?>
463
+
464
+ <!-- NOTICE 30 -->
465
+ <div class="status <?php echo ($notice['30'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['30']); ?></div>
466
+ <div class="title" data-type="toggle" data-target="#s1-notice30"><i class="fa fa-caret-right"></i> Package Age</div>
467
+ <div class="info" id="s1-notice30">
468
+ This package is <?php echo "{$fulldays}"; ?> day(s) old. Packages older than 180 days might be considered stale. It is recommended to build a new
469
+ package unless your aware of the content and its data. This is message is simply a recommendation.
470
+ </div>
471
+
472
+
473
+ <!-- NOTICE 40:
474
+ Legacy PHP 5.2 Version check (Removed) -->
475
+
476
+
477
+ <!-- NOTICE 45 -->
478
+ <div class="status <?php echo ($notice['45'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo $notice['45']; ?></div>
479
+ <div class="title" data-type="toggle" data-target="#s1-notice45"><i class="fa fa-caret-right"></i> PHP Version Mismatch</div>
480
+ <div class="info" id="s1-notice45">
481
+ <?php
482
+ $cssStyle = $notice['45'] == 'Good' ? 'color:green' : 'color:red';
483
+ echo "<b style='{$cssStyle}'>You are migrating site from the PHP {$packagePHP} to the PHP {$currentPHP}</b>.<br/>"
484
+ ."If this servers PHP version is different to the PHP version of your package was created it might cause problems with proper functioning of your website
485
+ and/or plugins and themes. It is highly recommended to try and use the same version of PHP if you are able to do so. <br/>";
486
+ ?>
487
+ </div>
488
+
489
+ <!-- NOTICE 50 -->
490
+ <div class="status <?php echo ($notice['50'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['50']); ?></div>
491
+ <div class="title" data-type="toggle" data-target="#s1-notice50"><i class="fa fa-caret-right"></i> PHP Open Base</div>
492
+ <div class="info" id="s1-notice50">
493
+ <b>Open BaseDir:</b> <i><?php echo $notice['50'] == 'Good' ? "<i class='dupx-pass'>Disabled</i>" : "<i class='dupx-fail'>Enabled</i>"; ?></i>
494
+ <br/><br/>
495
+
496
+ If <a href="http://php.net/manual/en/ini.core.php#ini.open-basedir" target="_blank">open_basedir</a> is enabled and your
497
+ having issues getting your site to install properly; please work with your host and follow these steps to prevent issues:
498
+ <ol style="margin:7px; line-height:19px">
499
+ <li>Disable the open_basedir setting in the php.ini file</li>
500
+ <li>If the host will not disable, then add the path below to the open_basedir setting in the php.ini<br/>
501
+ <i style="color:maroon">"<?php echo str_replace('\\', '/', dirname(__FILE__)); ?>"</i>
502
+ </li>
503
+ <li>Save the settings and restart the web server</li>
504
+ </ol>
505
+ Note: This warning will still show if you choose option #2 and open_basedir is enabled, but should allow the installer to run properly. Please work with your
506
+ hosting provider or server administrator to set this up correctly.
507
+ </div>
508
+
509
+ <!-- NOTICE 60 -->
510
+ <div class="status <?php echo ($notice['60'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['60']); ?></div>
511
+ <div class="title" data-type="toggle" data-target="#s1-notice60"><i class="fa fa-caret-right"></i> PHP Timeout</div>
512
+ <div class="info" id="s1-notice60">
513
+ <b>Archive Size:</b> <?php echo DUPX_U::readableByteSize($arcSize) ?> <small>(detection limit is set at <?php echo DUPX_U::readableByteSize($max_time_size) ?>) </small><br/>
514
+ <b>PHP max_execution_time:</b> <?php echo "{$max_time_ini}"; ?> <small>(zero means not limit)</small> <br/>
515
+ <b>PHP set_time_limit:</b> <?php echo ($max_time_zero) ? '<i style="color:green">Success</i>' : '<i style="color:maroon">Failed</i>' ?>
516
+ <br/><br/>
517
+
518
+ The PHP <a href="http://php.net/manual/en/info.configuration.php#ini.max-execution-time" target="_blank">max_execution_time</a> setting is used to
519
+ determine how long a PHP process is allowed to run. If the setting is too small and the archive file size is too large then PHP may not have enough
520
+ time to finish running before the process is killed causing a timeout.
521
+ <br/><br/>
522
+
523
+ Duplicator attempts to turn off the timeout by using the
524
+ <a href="http://php.net/manual/en/function.set-time-limit.php" target="_blank">set_time_limit</a> setting. If this notice shows as a warning then it is
525
+ still safe to continue with the install. However, if a timeout occurs then you will need to consider working with the max_execution_time setting or extracting the
526
+ archive file using the 'Manual Archive Extraction' method.
527
+ Please see the <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-trouble-100-q" target="_blank">FAQ timeout</a> help link for more details.
528
+ </div>
529
+
530
+
531
+ <!-- NOTICE 8 -->
532
+ <div class="status <?php echo ($notice['70'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['70']); ?></div>
533
+ <div class="title" data-type="toggle" data-target="#s1-notice70"><i class="fa fa-caret-right"></i> WordPress Multisite</div>
534
+ <div class="info" id="s1-notice70">
535
+ <b>Status:</b> <?php echo $notice['70'] == 'Good' ? 'This archive is not a Multisite' : 'This is an unsupported Multisite archive'; ?>
536
+ <br/><br/>
537
+
538
+ Duplicator does not support WordPress Multisite (MU) migrations. We recommend using Duplicator Pro which currently supports full Multisite migrations and
539
+ subsite to standalone site migrations.
540
+ <br/><br/>
541
+ While it is not recommended you can still continue with the build of this package. Please note that after the install the site may not be working correctly.
542
+ Additional manual custom configurations will need to be made to finalize this Multisite migration.
543
+
544
+ <i><a href='https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_is_mu_warn_exe&utm_campaign=duplicator_pro' target='_blank'>[upgrade to pro]</a></i>
545
+ </div>
546
+
547
+ <!-- NOTICE 80 -->
548
+ <div class="status <?php echo ($notice['80'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['80']); ?></div>
549
+ <div class="title" data-type="toggle" data-target="#s1-notice80"><i class="fa fa-caret-right"></i> WordPress wp-config Location</div>
550
+ <div class="info" id="s1-notice80">
551
+ If the wp-config.php file was moved up one level and out of the WordPress root folder in the package creation site then this test will show a warning.
552
+ <br/><br/>
553
+ This Duplicator installer will place this wp-config.php file in the WordPress setup root folder of this installation site to help stabilize the install process.
554
+ This process will not break anything in your installation site, but the details are here for your information.
555
+ </div>
556
+
557
+ <!-- NOTICE 90 -->
558
+ <div class="status <?php echo ($notice['90'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['90']); ?></div>
559
+ <div class="title" data-type="toggle" data-target="#s1-notice90"><i class="fa fa-caret-right"></i> WordPress wp-content Location</div>
560
+ <div class="info" id="s1-notice90">
561
+ If the wp-content directory was moved and not located at the WordPress root folder in the package creation site then this test will show a warning.
562
+ <br/><br/>
563
+ Duplicator Installer will place this wp-content directory in the WordPress setup root folder of this installation site. It will not break anything in your installation
564
+ site. It is just for your information.
565
+ </div>
566
+
567
+ <!-- NOTICE 100 -->
568
+ <div class="status <?php echo ($notice['100'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['100']); ?></div>
569
+ <div class="title" data-type="toggle" data-target="#s1-notice100"><i class="fa fa-caret-right"></i> Sufficient Disk Space</div>
570
+ <div class="info" id="s1-notice100">
571
+ <?php
572
+ echo ($notice['100'] == 'Good') ? 'You have sufficient disk space in your machine to extract the archive.' : 'You don’t have sufficient disk space in your machine to extract the archive. Ask your host to increase disk space.'
573
+ ?>
574
+ </div>
575
+
576
+ <!-- NOTICE 110 -->
577
+ <div class="status <?php echo ($notice['110'] == 'Good') ? 'pass' : 'fail' ?>"><?php echo DUPX_U::esc_html($notice['110']); ?></div>
578
+ <div class="title" data-type="toggle" data-target="#s1-notice110"><i class="fa fa-caret-right"></i> Wordfence</div>
579
+ <div class="info" id="s1-notice110">
580
+ <b>Wordfence Firewall:</b> <?php echo ($notice['110'] == 'Warn') ? "<span style='color:red;'>detected at {$parentWordFencePath}</span>" : "<span style='color:green;'>not detected</span>"; ?>
581
+ <p>
582
+ The Wordfence Web Application Firewall is a PHP based, application level firewall that filters out malicious
583
+ requests to your site. Sometimes Wordfence returns false positives on requests done during the installation process,
584
+ because of which it might fail. We recommend turning off the Wordfence firewall of the WordPress instance located at the mentioned path.
585
+ </p>
586
+ </div>
587
+
588
+ </div>
589
+
590
+ </div>
591
+ <br/><br/>
592
+
593
+
594
+ <!-- ====================================
595
+ OPTIONS
596
+ ==================================== -->
597
+ <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s1-area-adv-opts">
598
+ <a href="javascript:void(0)"><i class="fa fa-plus-square"></i>Options</a>
599
+ </div>
600
+ <div id="s1-area-adv-opts" class="hdr-sub1-area" style="display:none">
601
+ <div class="help-target">
602
+ <?php DUPX_View_Funcs::helpIconLink('step1'); ?>
603
+ </div>
604
+ <div class="hdr-sub3">General</div>
605
+ <table class="dupx-opts dupx-advopts">
606
+ <tr>
607
+ <td>Extraction:</td>
608
+ <td>
609
+ <?php
610
+ $options = array();
611
+ $extra_attr = ($arcCheck == 'Warn' && $is_wpconfarc_present) ? ' selected="selected"' : '';
612
+ $options[] = '<option '.($is_wpconfarc_present ? '' : 'disabled').$extra_attr.' value="manual">Manual Archive Extraction '.($is_wpconfarc_present ? '' : '*').'</option>';
613
+ if ($archive_config->isZipArchive()) {
614
+ //ZIP-ARCHIVE
615
+ $extra_attr = ('Pass' == $arcCheck && $zip_archive_enabled && !$shell_exec_zip_enabled) ? ' selected="selected"' : '';
616
+ $extra_attr .= ('Pass' != $arcCheck || !$zip_archive_enabled) ? ' disabled="disabled"' : '';
617
+ $options[] = '<option value="ziparchive"'.$extra_attr.'>PHP ZipArchive</option>';
618
+
619
+ //SHELL-EXEC UNZIP
620
+ $extra_attr = ('Pass' != $arcCheck || !$shell_exec_zip_enabled) ? ' disabled="disabled"' : '';
621
+ $extra_attr .= ('Pass' == $arcCheck && $shell_exec_zip_enabled) ? ' selected="selected"' : '';
622
+ $options[] = '<option value="shellexec_unzip"'.$extra_attr.'>Shell Exec Unzip</option>';
623
+ } else { // DUPARCHIVE
624
+ $extra_attr = ('Pass' == $arcCheck) ? ' selected="selected"' : 'disabled="disabled"';
625
+ $options[] = '<option value="duparchive"'.$extra_attr.'>DupArchive</option>';
626
+ }
627
+ $num_selections = count($options);
628
+ ?>
629
+ <select id="archive_engine" name="archive_engine" size="<?php echo DUPX_U::esc_attr($num_selections); ?>">
630
+ <?php echo implode('', $options); ?>
631
+ </select><br/>
632
+ <?php if (!$is_wpconfarc_present): ?>
633
+ <span class="sub-notes">
634
+ *Option enabled when archive has been pre-extracted
635
+ <a href="https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q" target="_blank">[more info]</a>
636
+ </span>
637
+ <?php endif; ?>
638
+ </td>
639
+ </tr>
640
+ <tr>
641
+ <td style="vertical-align: top;padding-top: 10px;" >Archive Action:</td>
642
+ <td id="archive_action_wrapper">
643
+ <select id="archive_action_input" name="<?php echo DUP_LITE_Extraction::INPUT_NAME_ARCHIVE_ACTION; ?>" class="input-item" >
644
+ <option value="<?php echo DUP_LITE_Extraction::ACTION_DO_NOTHING; ?>" selected="selected">
645
+ Extract files over current files
646
+ </option>
647
+ <option value="<?php echo DUP_LITE_Extraction::ACTION_REMOVE_WP_FILES; ?>">
648
+ Remove WP core and content and extract
649
+ </option>
650
+ <option value="<?php echo DUP_LITE_Extraction::ACTION_REMOVE_ALL_FILES; ?>">
651
+ Remove all files and extract
652
+ </option>
653
+ </select>
654
+ <div class="sub-note" style="margin-top: 5px;max-width: 90%;" >
655
+ <div class="archive-action-note archive-action-<?php echo DUP_LITE_Extraction::ACTION_DO_NOTHING; ?>">
656
+ Note: <b>Files are extracted over existing files.</b> After install, the destination folder will contain a combination of the old site files and the files extracted from the archive.<br>
657
+ This option is the most conservative option for those who want to make sure they do not want to lose data.
658
+ </div>
659
+ <div class="archive-action-note archive-action-<?php echo DUP_LITE_Extraction::ACTION_REMOVE_ALL_FILES; ?> no-display">
660
+ Note: Before extracting the package files, <b>all files and folders in the installation folder will be removed</b> except for folders that contain WordPress installations or Duplicator backup folders<br>
661
+ This option is recommended for those who want to delete all files related to old installations or external applications.
662
+ </div>
663
+ <div class="archive-action-note archive-action-<?php echo DUP_LITE_Extraction::ACTION_REMOVE_WP_FILES; ?> no-display">
664
+ Note: Before extracting the package files, <b>all current WordPress core and content files and folders will be removed</b> (wp-include, wp-content ... )<br>
665
+ This option is for those who want to avoid having old site media mixed with new but have other files/folders in the home path that they don't want to delete.
666
+ </div>
667
+ </div>
668
+ </div>
669
+ </td>
670
+ </tr>
671
+ </table><br/><br/>
672
+
673
+ <div class="hdr-sub3">Advanced</div>
674
+ <table class="dupx-opts dupx-advopts">
675
+ <tr>
676
+ <td>Permissions:</td>
677
+ <td>
678
+ <input type="checkbox" name="set_file_perms" id="set_file_perms" value="1" onclick="jQuery('#file_perms_value').prop('disabled', !jQuery(this).is(':checked'));"/>
679
+ <label for="set_file_perms">All Files</label><input name="file_perms_value" id="file_perms_value" style="width:45px; margin-left:7px;" value="644" disabled> &nbsp;
680
+ <input type="checkbox" name="set_dir_perms" id="set_dir_perms" value="1" onclick="jQuery('#dir_perms_value').prop('disabled', !jQuery(this).is(':checked'));"/>
681
+ <label for="set_dir_perms">All Directories</label><input name="dir_perms_value" id="dir_perms_value" style="width:45px; margin-left:7px;" value="755" disabled>
682
+ </td>
683
+ </tr>
684
+ <tr>
685
+ <td>Safe Mode:</td>
686
+ <td>
687
+ <select name="exe_safe_mode" id="exe_safe_mode" onchange="DUPX.onSafeModeSwitch();" style="width:250px;">
688
+ <option value="0">Off</option>
689
+ <option value="1">Basic</option>
690
+ <option value="2">Advanced</option>
691
+ </select>
692
+ </td>
693
+ </tr>
694
+ <tr>
695
+ <td>Config Files:</td>
696
+ <td>
697
+ <select name="config_mode" id="config_mode" style="width:250px;">
698
+ <option value="NEW">Create New (recommended)</option>
699
+ <optgroup label="Advanced">
700
+ <option value="RESTORE">Restore Original</option>
701
+ <option value="IGNORE">Ignore All</option>
702
+ </optgroup>
703
+ </select> <br/>
704
+ <span class="sub-notes" style="font-weight: normal">
705
+ Controls how .htaccess, .user.ini and web.config are used.<br/>
706
+ These options are not applied until step 3 is ran.
707
+ <?php DUPX_View_Funcs::helpLink('step1', '[more info]'); ?>
708
+ </span>
709
+ </td>
710
+ </tr>
711
+ <tr>
712
+ <td>File Times:</td>
713
+ <td>
714
+ <input type="radio" name="zip_filetime" id="zip_filetime_now" value="current" checked="checked" />
715
+ <label class="radio" for="zip_filetime_now" title='Set the files current date time to now'>Current</label> &nbsp;
716
+ <input type="radio" name="zip_filetime" id="zip_filetime_orginal" value="original" />
717
+ <label class="radio" for="zip_filetime_orginal" title="Keep the files date time the same">Original</label>
718
+ </td>
719
+ </tr>
720
+ <tr>
721
+ <td>Logging:</td>
722
+ <td>
723
+ <input type="radio" name="logging" id="logging-light" value="<?php echo DUPX_Log::LV_DEFAULT; ?>" checked="true"> <label for="logging-light" class="radio">Light</label> &nbsp;
724
+ <input type="radio" name="logging" id="logging-detailed" value="<?php echo DUPX_Log::LV_DETAILED; ?>"> <label for="logging-detailed" class="radio">Detailed</label> &nbsp;
725
+ <input type="radio" name="logging" id="logging-debug" value="<?php echo DUPX_Log::LV_DEBUG; ?>"> <label for="logging-debug" class="radio">Debug</label> &nbsp;
726
+ <input type="radio" name="logging" id="logging-h-debug" value="<?php echo DUPX_Log::LV_HARD_DEBUG; ?>"> <label for="logging-h-debug" class="radio">Hard debug</label>
727
+ </td>
728
+ </tr>
729
+ <?php if (!$archive_config->isZipArchive()): ?>
730
+ <tr>
731
+ <td>Client-Kickoff:</td>
732
+ <td>
733
+ <input type="checkbox" name="clientside_kickoff" id="clientside_kickoff" value="1" checked/>
734
+ <label for="clientside_kickoff" style="font-weight: normal">Browser drives the archive engine.</label>
735
+ </td>
736
+ </tr>
737
+ <?php endif; ?>
738
+ <tr>
739
+ <td>Testing:</td>
740
+ <td>
741
+ <a href="javascript:void(0)" target="db-test" onclick="DUPX.openDBValidationWindow(); return false;">[Quick Database Connection Test]</a>
742
+ </td>
743
+ </tr>
744
+ </table>
745
+ </div><br/>
746
+
747
+
748
+ <?php if ($req_success && $arcCheck != 'Fail') : ?>
749
+ <div id="s1-warning-check">
750
+ <?php if ($is_overwrite_mode && $is_wordpress) { ?>
751
+ <input id="accept-overwrite" name="accept-overwrite" type="checkbox" onclick="DUPX.acceptWarning()" />
752
+ <label for="accept-overwrite">Continue with site overwrite mode <small style="font-style:italic">(required to continue)</small></label><br/>
753
+ <?php } ?>
754
+ <input id="accept-warnings" name="accpet-warnings" type="checkbox" onclick="DUPX.acceptWarning()" />
755
+ <label for="accept-warnings">I have read and accept all <a href="javascript:void(0)" onclick="DUPX.viewTerms()">terms &amp; notices</a> <small style="font-style:italic">(required to continue)</small></label><br/>
756
+ </div>
757
+ <?php include ('view.s1.terms.php'); ?>
758
+ <br/><br/>
759
+ <br/><br/>
760
+ <?php endif; ?>
761
+
762
+
763
+ <?php if (!$req_success || $arcCheck == 'Fail') : ?>
764
+ <div class="s1-err-msg">
765
+ <i>
766
+ This installation will not be able to proceed until the setup and validation sections above both pass. Please adjust your servers settings or contact your
767
+ server administrator, hosting provider or visit the resources below for additional help.
768
+ </i>
769
+ <div style="padding:10px">
770
+ &raquo; <a href="https://snapcreek.com/duplicator/docs/faqs-tech/" target="_blank">Technical FAQs</a> <br/>
771
+ &raquo; <a href="https://snapcreek.com/support/docs/" target="_blank">Online Documentation</a> <br/>
772
+ </div>
773
+ </div>
774
+ <?php else : ?>
775
+ <div class="footer-buttons" >
776
+ <button id="s1-deploy-btn" type="button" title="<?php echo DUPX_U::esc_attr($agree_msg); ?>" onclick="DUPX.processNext()" class="default-btn"> Next <i class="fa fa-caret-right"></i> </button>
777
+ </div>
778
+ <?php endif; ?>
779
+
780
+ </form>
781
+
782
+ <!-- =========================================
783
+ VIEW: STEP 1 - DB QUICK TEST
784
+ ========================================= -->
785
+ <form id="s1-dbtest-form" method="post" target="_blank" autocomplete="off">
786
+ <input type="hidden" name="dbonlytest" value="1" />
787
+ <input type="hidden" name="view" value="step2" />
788
+ <input type="hidden" name="csrf_token" value="<?php echo DUPX_CSRF::generate('step2'); ?>">
789
+ <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
790
+ </form>
791
+
792
+
793
+ <!-- =========================================
794
+ VIEW: STEP 1 - AJAX RESULT
795
+ Auto Posts to view.step2.php
796
+ ========================================= -->
797
+ <form id='s1-result-form' method="post" class="content-form" style="display:none" autocomplete="off">
798
+
799
+ <div class="dupx-logfile-link"><?php DUPX_View_Funcs::installerLogLink(); ?></div>
800
+ <div class="hdr-main">
801
+ Step <span class="step">1</span> of 4: Deployment
802
+ <div class="sub-header">This step will extract the archive file contents.</div>
803
+ </div>
804
+
805
+ <!-- POST PARAMS -->
806
+ <div class="dupx-debug">
807
+ <i>Step 1 - AJAX Response</i>
808
+ <input type="hidden" name="view" value="step2" />
809
+ <input type="hidden" name="csrf_token" value="<?php echo DUPX_CSRF::generate('step2'); ?>">
810
+ <input type="hidden" name="secure-pass" value="<?php echo DUPX_U::esc_attr($_POST['secure-pass']); ?>" />
811
+ <input type="hidden" name="logging" id="ajax-logging" />
812
+ <input type="hidden" name="config_mode" id="ajax-config-mode" />
813
+ <input type="hidden" name="exe_safe_mode" id="exe-safe-mode" value="0" />
814
+ <input type="hidden" name="json" id="ajax-json" />
815
+ <textarea id='ajax-json-debug' name='json_debug_view'></textarea>
816
+ <input type='submit' value='manual submit'>
817
+ </div>
818
+
819
+ <!-- PROGRESS BAR -->
820
+ <div id="progress-area">
821
+ <div style="width:500px; margin:auto">
822
+ <div style="font-size:1.7em; margin-bottom:20px"><i class="fas fa-circle-notch fa-spin"></i> Extracting Archive Files<span id="progress-pct"></span></div>
823
+ <div id="progress-bar"></div>
824
+ <h3> Please Wait...</h3><br/><br/>
825
+ <i>Keep this window open during the extraction process.</i><br/>
826
+ <i>This can take several minutes.</i>
827
+ </div>
828
+ </div>
829
+
830
+ <!-- AJAX SYSTEM ERROR -->
831
+ <div id="ajaxerr-area" style="display:none">
832
+ <p>Please try again an issue has occurred.</p>
833
+ <div style="padding: 0px 10px 10px 0px;">
834
+ <div id="ajaxerr-data">An unknown issue has occurred with the file and database setup process. Please see the <?php DUPX_View_Funcs::installerLogLink(); ?> file for more details.</div>
835
+ <div style="text-align:center; margin:10px auto 0px auto">
836
+ <br/>
837
+ <input type="button" class="default-btn" onclick="DUPX.hideErrorResult()" value="&laquo; Try Again" />
838
+ <br/><br/>
839
+ <i style='font-size:11px'>See online help for more details at <a href='https://snapcreek.com/ticket' target='_blank'>snapcreek.com</a></i>
840
+ </div>
841
+ </div>
842
+ </div>
843
+ </form>
844
+
845
+ <script>
846
+ DUPX.openDBValidationWindow = function ()
847
+ {
848
+ console.log('test');
849
+ $('#s1-dbtest-form').submit();
850
+ }
851
+
852
+ DUPX.toggleSetupType = function ()
853
+ {
854
+ var val = $("input:radio[name='setup_type']:checked").val();
855
+ $('div.s1-setup-type-sub').hide();
856
+ $('#s1-setup-type-sub-' + val).show(200);
857
+ };
858
+
859
+ DUPX.getManaualArchiveOpt = function ()
860
+ {
861
+ $("html, body").animate({scrollTop: $(document).height()}, 1500);
862
+ $("div[data-target='#s1-area-adv-opts']").find('i.fa').removeClass('fa-plus-square').addClass('fa-minus-square');
863
+ $('#s1-area-adv-opts').show(1000);
864
+ $('select#archive_engine').val('manual').focus();
865
+ };
866
+
867
+ DUPX.startExtraction = function ()
868
+ {
869
+ var isManualExtraction = ($("#archive_engine").val() == "manual");
870
+ var zipEnabled = <?php echo DupLiteSnapLibStringU::boolToString($archive_config->isZipArchive()); ?>;
871
+
872
+ $("#operation-text").text("Extracting Archive Files");
873
+
874
+ if (zipEnabled || isManualExtraction) {
875
+ DUPX.runStandardExtraction();
876
+ } else {
877
+ DUPX.kickOffDupArchiveExtract();
878
+ }
879
+ }
880
+
881
+ DUPX.processNext = function ()
882
+ {
883
+ DUPX.startExtraction();
884
+ };
885
+
886
+ DUPX.updateProgressPercent = function (percent)
887
+ {
888
+ var percentString = '';
889
+ if (percent > 0) {
890
+ percentString = ' ' + percent + '%';
891
+ }
892
+ $("#progress-pct").text(percentString);
893
+ };
894
+
895
+ DUPX.clearDupArchiveStatusTimer = function ()
896
+ {
897
+ if (DUPX.dupArchiveStatusIntervalID != -1) {
898
+ clearInterval(DUPX.dupArchiveStatusIntervalID);
899
+ DUPX.dupArchiveStatusIntervalID = -1;
900
+ }
901
+ };
902
+
903
+ DUPX.getCriticalFailureText = function (failures)
904
+ {
905
+ var retVal = null;
906
+
907
+ if ((failures !== null) && (typeof failures !== 'undefined')) {
908
+ var len = failures.length;
909
+
910
+ for (var j = 0; j < len; j++) {
911
+ failure = failures[j];
912
+
913
+ if (failure.isCritical) {
914
+ retVal = failure.description;
915
+ break;
916
+ }
917
+ }
918
+ }
919
+
920
+ return retVal;
921
+ };
922
+
923
+ DUPX.DAWSProcessingFailed = function (errorText)
924
+ {
925
+ DUPX.clearDupArchiveStatusTimer();
926
+ $('#ajaxerr-data').html(errorText);
927
+ DUPX.hideProgressBar();
928
+ }
929
+
930
+ DUPX.handleDAWSProcessingProblem = function (errorText, pingDAWS) {
931
+
932
+ DUPX.DAWS.FailureCount++;
933
+
934
+ if (DUPX.DAWS.FailureCount <= DUPX.DAWS.MaxRetries) {
935
+ var callback = DUPX.pingDAWS;
936
+
937
+ if (pingDAWS) {
938
+ console.log('!!!PING FAILURE #' + DUPX.DAWS.FailureCount);
939
+ } else {
940
+ console.log('!!!KICKOFF FAILURE #' + DUPX.DAWS.FailureCount);
941
+ callback = DUPX.kickOffDupArchiveExtract;
942
+ }
943
+
944
+ DUPX.throttleDelay = 9; // Equivalent of 'low' server throttling
945
+ console.log('Relaunching in ' + DUPX.DAWS.RetryDelayInMs);
946
+ setTimeout(callback, DUPX.DAWS.RetryDelayInMs);
947
+ } else {
948
+ console.log('Too many failures.');
949
+ DUPX.DAWSProcessingFailed(errorText);
950
+ }
951
+ };
952
+
953
+
954
+ DUPX.handleDAWSCommunicationProblem = function (xHr, pingDAWS, textStatus, page)
955
+ {
956
+ DUPX.DAWS.FailureCount++;
957
+
958
+ if (DUPX.DAWS.FailureCount <= DUPX.DAWS.MaxRetries) {
959
+
960
+ var callback = DUPX.pingDAWS;
961
+
962
+ if (pingDAWS) {
963
+ console.log('!!!PING FAILURE #' + DUPX.DAWS.FailureCount);
964
+ } else {
965
+ console.log('!!!KICKOFF FAILURE #' + DUPX.DAWS.FailureCount);
966
+ callback = DUPX.kickOffDupArchiveExtract;
967
+ }
968
+ console.log(xHr);
969
+ DUPX.throttleDelay = 9; // Equivalent of 'low' server throttling
970
+ console.log('Relaunching in ' + DUPX.DAWS.RetryDelayInMs);
971
+ setTimeout(callback, DUPX.DAWS.RetryDelayInMs);
972
+ } else {
973
+ console.log('Too many failures.');
974
+ DUPX.ajaxCommunicationFailed(xHr, textStatus, page);
975
+ }
976
+ };
977
+
978
+ // Will either query for status or push it to continue the extraction
979
+ DUPX.pingDAWS = function ()
980
+ {
981
+ console.log('pingDAWS:start');
982
+ var request = new Object();
983
+ var isClientSideKickoff = DUPX.isClientSideKickoff();
984
+
985
+ if (isClientSideKickoff) {
986
+ console.log('pingDAWS:client side kickoff');
987
+ request.action = "expand";
988
+ request.client_driven = 1;
989
+ request.throttle_delay = DUPX.throttleDelay;
990
+ request.worker_time = DUPX.DAWS.PingWorkerTimeInSec;
991
+ } else {
992
+ console.log('pingDAWS:not client side kickoff');
993
+ request.action = "get_status";
994
+ }
995
+
996
+ console.log("pingDAWS:action=" + request.action);
997
+
998
+ $.ajax({
999
+ type: "POST",
1000
+ timeout: DUPX.DAWS.PingWorkerTimeInSec * 2000, // Double worker time and convert to ms
1001
+ url: DUPX.DAWS.Url,
1002
+ data: JSON.stringify(request),
1003
+ success: function (respData, textStatus, xHr) {
1004
+ try {
1005
+ var data = DUPX.parseJSON(respData);
1006
+ } catch (err) {
1007
+ console.error(err);
1008
+ console.error('JSON parse failed for response data: ' + respData);
1009
+ console.log('AJAX error. textStatus=');
1010
+ console.log(textStatus);
1011
+ DUPX.handleDAWSCommunicationProblem(xHr, true, textStatus, 'ping');
1012
+ return false;
1013
+ }
1014
+
1015
+ DUPX.DAWS.FailureCount = 0;
1016
+ console.log("pingDAWS:AJAX success. Resetting failure count");
1017
+
1018
+ // DATA FIELDS
1019
+ // archive_offset, archive_size, failures, file_index, is_done, timestamp
1020
+
1021
+ if (typeof (data) != 'undefined' && data.pass == 1) {
1022
+
1023
+ console.log("pingDAWS:Passed");
1024
+
1025
+ var status = data.status;
1026
+ var percent = Math.round((status.archive_offset * 100.0) / status.archive_size);
1027
+
1028
+ console.log("pingDAWS:updating progress percent");
1029
+ DUPX.updateProgressPercent(percent);
1030
+
1031
+ var criticalFailureText = DUPX.getCriticalFailureText(status.failures);
1032
+
1033
+ if (status.failures.length > 0) {
1034
+ console.log("pingDAWS:There are failures present. (" + status.failures.length) + ")";
1035
+ }
1036
+
1037
+ if (criticalFailureText === null) {
1038
+ console.log("pingDAWS:No critical failures");
1039
+ if (status.is_done) {
1040
+
1041
+ console.log("pingDAWS:archive has completed");
1042
+ if (status.failures.length > 0) {
1043
+
1044
+ console.log(status.failures);
1045
+ var errorMessage = "pingDAWS:Problems during extract. These may be non-critical so continue with install.\n------\n";
1046
+ var len = status.failures.length;
1047
+
1048
+ for (var j = 0; j < len; j++) {
1049
+ failure = status.failures[j];
1050
+ errorMessage += failure.subject + ":" + failure.description + "\n";
1051
+ }
1052
+
1053
+ alert(errorMessage);
1054
+ }
1055
+
1056
+ DUPX.clearDupArchiveStatusTimer();
1057
+ console.log("pingDAWS:calling finalizeDupArchiveExtraction");
1058
+ DUPX.finalizeDupArchiveExtraction(status);
1059
+ console.log("pingDAWS:after finalizeDupArchiveExtraction");
1060
+
1061
+ var dataJSON = JSON.stringify(data);
1062
+
1063
+ // Don't stop for non-critical failures - just display those at the end
1064
+
1065
+ $("#ajax-logging").val($("input:radio[name=logging]:checked").val());
1066
+ $("#ajax-config-mode").val($("#config_mode").val());
1067
+ $("#ajax-json").val(escape(dataJSON));
1068
+
1069
+ <?php if (!DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)) : ?>
1070
+ setTimeout(function () {
1071
+ $('#s1-result-form').submit();
1072
+ }, 500);
1073
+ <?php endif; ?>
1074
+ $('#progress-area').fadeOut(1000);
1075
+ //Failures aren't necessarily fatal - just record them for later display
1076
+
1077
+ $("#ajax-json-debug").val(dataJSON);
1078
+ } else if (isClientSideKickoff) {
1079
+ console.log('pingDAWS:Archive not completed so continue ping DAWS in 500');
1080
+ setTimeout(DUPX.pingDAWS, 500);
1081
+ }
1082
+ } else {
1083
+ console.log("pingDAWS:critical failures present");
1084
+ // If we get a critical failure it means it's something we can't recover from so no purpose in retrying, just fail immediately.
1085
+ var errorString = 'Error Processing Step 1<br/>';
1086
+
1087
+ errorString += criticalFailureText;
1088
+
1089
+ DUPX.DAWSProcessingFailed(errorString);
1090
+ }
1091
+ } else {
1092
+ var errorString = 'Error Processing Step 1<br/>';
1093
+ errorString += data.error;
1094
+
1095
+ DUPX.handleDAWSProcessingProblem(errorString, true);
1096
+ }
1097
+ },
1098
+ error: function (xHr, textStatus) {
1099
+ console.log('AJAX error. textStatus=');
1100
+ console.log(textStatus);
1101
+ DUPX.handleDAWSCommunicationProblem(xHr, true, textStatus, 'ping');
1102
+ }
1103
+ });
1104
+ };
1105
+
1106
+
1107
+ DUPX.isClientSideKickoff = function ()
1108
+ {
1109
+ return $('#clientside_kickoff').is(':checked');
1110
+ }
1111
+
1112
+ DUPX.areConfigFilesPreserved = function ()
1113
+ {
1114
+ return $('#config_mode').is(':checked');
1115
+ }
1116
+
1117
+ DUPX.kickOffDupArchiveExtract = function ()
1118
+ {
1119
+ console.log('kickOffDupArchiveExtract:start');
1120
+ var $form = $('#s1-input-form');
1121
+ var request = new Object();
1122
+ var isClientSideKickoff = DUPX.isClientSideKickoff();
1123
+
1124
+ request.action = "start_expand";
1125
+ request.restore_directory = '<?php echo DUPX_U::esc_js($root_path); ?>';
1126
+ request.worker_time = DUPX.DAWS.KickoffWorkerTimeInSec;
1127
+ request.client_driven = isClientSideKickoff ? 1 : 0;
1128
+ request.throttle_delay = DUPX.throttleDelay;
1129
+ request.filtered_directories = ['dup-installer'];
1130
+
1131
+ var requestString = JSON.stringify(request);
1132
+
1133
+ if (!isClientSideKickoff) {
1134
+ console.log('kickOffDupArchiveExtract:Setting timer');
1135
+ // If server is driving things we need to poll the status
1136
+ DUPX.dupArchiveStatusIntervalID = setInterval(DUPX.pingDAWS, DUPX.DAWS.StatusPeriodInMS);
1137
+ } else {
1138
+ console.log('kickOffDupArchiveExtract:client side kickoff');
1139
+ }
1140
+
1141
+ console.log("daws url=" + DUPX.DAWS.Url);
1142
+ console.log("requeststring=" + requestString);
1143
+
1144
+ $.ajax({
1145
+ type: "POST",
1146
+ timeout: DUPX.DAWS.KickoffWorkerTimeInSec * 2000, // Double worker time and convert to ms
1147
+ url: DUPX.DAWS.Url + '&daws_action=start_expand',
1148
+ data: requestString,
1149
+ beforeSend: function () {
1150
+ DUPX.showProgressBar();
1151
+ $form.hide();
1152
+ $('#s1-result-form').show();
1153
+ DUPX.updateProgressPercent(0);
1154
+ },
1155
+ success: function (respData, textStatus, xHr) {
1156
+ try {
1157
+ var data = DUPX.parseJSON(respData);
1158
+ } catch (err) {
1159
+ console.error(err);
1160
+ console.error('JSON parse failed for response data: ' + respData);
1161
+ console.log('kickOffDupArchiveExtract:AJAX error. textStatus=', textStatus);
1162
+ DUPX.handleDAWSCommunicationProblem(xHr, false, textStatus);
1163
+ return false;
1164
+ }
1165
+ console.log('kickOffDupArchiveExtract:success');
1166
+ if (typeof (data) != 'undefined' && data.pass == 1) {
1167
+
1168
+ var criticalFailureText = DUPX.getCriticalFailureText(status.failures);
1169
+
1170
+ if (criticalFailureText === null) {
1171
+
1172
+ var dataJSON = JSON.stringify(data);
1173
+
1174
+ //RSR TODO:Need to check only for FATAL errors right now - have similar failure check as in pingdaws
1175
+ DUPX.DAWS.FailureCount = 0;
1176
+ console.log("kickOffDupArchiveExtract:Resetting failure count");
1177
+
1178
+ $("#ajax-json-debug").val(dataJSON);
1179
+ if (typeof (data) != 'undefined' && data.pass == 1) {
1180
+
1181
+ if (isClientSideKickoff) {
1182
+ console.log('kickOffDupArchiveExtract:Initial ping DAWS in 500');
1183
+ setTimeout(DUPX.pingDAWS, 500);
1184
+ }
1185
+
1186
+ } else {
1187
+ $('#ajaxerr-data').html('Error Processing Step 1');
1188
+ DUPX.hideProgressBar();
1189
+ }
1190
+ } else {
1191
+ // If we get a critical failure it means it's something we can't recover from so no purpose in retrying, just fail immediately.
1192
+ var errorString = 'kickOffDupArchiveExtract:Error Processing Step 1<br/>';
1193
+ errorString += criticalFailureText;
1194
+ DUPX.DAWSProcessingFailed(errorString);
1195
+ }
1196
+ } else {
1197
+ if ('undefined' !== typeof data.isWPAlreadyExistsError
1198
+ && data.isWPAlreadyExistsError) {
1199
+ DUPX.DAWSProcessingFailed(data.error);
1200
+ } else {
1201
+ var errorString = 'kickOffDupArchiveExtract:Error Processing Step 1<br/>';
1202
+ errorString += data.error;
1203
+ DUPX.handleDAWSProcessingProblem(errorString, false);
1204
+ }
1205
+ }
1206
+ },
1207
+ error: function (xHr, textStatus) {
1208
+
1209
+ console.log('kickOffDupArchiveExtract:AJAX error. textStatus=', textStatus);
1210
+ DUPX.handleDAWSCommunicationProblem(xHr, false, textStatus);
1211
+ }
1212
+ });
1213
+ };
1214
+
1215
+ DUPX.finalizeDupArchiveExtraction = function (dawsStatus)
1216
+ {
1217
+ console.log("finalizeDupArchiveExtraction:start");
1218
+ var $form = $('#s1-input-form');
1219
+ $("#s1-input-form-extra-data").val(JSON.stringify(dawsStatus));
1220
+ console.log("finalizeDupArchiveExtraction:after stringify dawsstatus");
1221
+ var formData = $form.serialize();
1222
+
1223
+ $.ajax({
1224
+ type: "POST",
1225
+ timeout: 30000,
1226
+ url: window.location.href,
1227
+ data: formData,
1228
+ success: function (respData, textStatus, xHr) {
1229
+ try {
1230
+ var data = DUPX.parseJSON(respData);
1231
+ } catch (err) {
1232
+ console.error(err);
1233
+ console.error('JSON parse failed for response data: ' + respData);
1234
+ console.log("finalizeDupArchiveExtraction:error");
1235
+ console.log(xHr.statusText);
1236
+ console.log(xHr.getAllResponseHeaders());
1237
+ console.log(xHr.responseText);
1238
+ return false;
1239
+ }
1240
+ console.log("finalizeDupArchiveExtraction:success");
1241
+ },
1242
+ error: function (xHr) {
1243
+ console.log("finalizeDupArchiveExtraction:error");
1244
+ console.log(xHr.statusText);
1245
+ console.log(xHr.getAllResponseHeaders());
1246
+ console.log(xHr.responseText);
1247
+ }
1248
+ });
1249
+ };
1250
+
1251
+ /**
1252
+ * Performs Ajax post to either do a zip or manual extract and then create db
1253
+ */
1254
+ DUPX.runStandardExtraction = function ()
1255
+ {
1256
+ var $form = $('#s1-input-form');
1257
+
1258
+ //3600000 = 60 minutes
1259
+ //If the extraction takes longer than 30 minutes then user
1260
+ //will probably want to do a manual extraction or even FTP
1261
+ $.ajax({
1262
+ type: "POST",
1263
+ timeout: 3600000,
1264
+ cache: false,
1265
+ url: window.location.href,
1266
+ data: $form.serialize(),
1267
+ beforeSend: function () {
1268
+ DUPX.showProgressBar();
1269
+ $form.hide();
1270
+ $('#s1-result-form').show();
1271
+ },
1272
+ success: function (data, textStatus, xHr) {
1273
+ $("#ajax-json-debug").val(data);
1274
+ var dataJSON = data;
1275
+ data = DUPX.parseJSON(data, xHr, textStatus);
1276
+ if (false === data) {
1277
+ return;
1278
+ }
1279
+ $("#ajax-json-debug").val(dataJSON);
1280
+ if (typeof (data) != 'undefined' && data.pass == 1) {
1281
+ $("#ajax-logging").val($("input:radio[name=logging]:checked").val());
1282
+ $("#ajax-config-mode").val($("#config_mode").val());
1283
+ $("#ajax-json").val(escape(dataJSON));
1284
+
1285
+ <?php if (!DUPX_Log::isLevel(DUPX_Log::LV_DEBUG)) : ?>
1286
+ setTimeout(function () {
1287
+ $('#s1-result-form').submit();
1288
+ }, 500);
1289
+ <?php endif; ?>
1290
+ $('#progress-area').fadeOut(1000);
1291
+ } else {
1292
+ $('#ajaxerr-data').html('Error Processing Step 1');
1293
+ DUPX.hideProgressBar();
1294
+ }
1295
+ },
1296
+ error: function (xHr) {
1297
+ DUPX.ajaxCommunicationFailed(xHr, '', 'extract');
1298
+ }
1299
+ });
1300
+ };
1301
+
1302
+ DUPX.ajaxCommunicationFailed = function (xhr, textStatus, page)
1303
+ {
1304
+ var status = "<b>Server Code:</b> " + xhr.status + "<br/>";
1305
+ status += "<b>Status:</b> " + xhr.statusText + "<br/>";
1306
+ status += "<b>Response:</b> " + xhr.responseText + "<hr/>";
1307
+
1308
+ if (textStatus && textStatus.toLowerCase() == "timeout" || textStatus.toLowerCase() == "service unavailable") {
1309
+
1310
+ var default_timeout_message = "<b>Recommendation:</b><br/>";
1311
+ default_timeout_message += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116102141#faq-trouble-100-q'>this FAQ item</a> for possible resolutions.";
1312
+ default_timeout_message += "<hr>";
1313
+ default_timeout_message += "<b>Additional Resources...</b><br/>";
1314
+ default_timeout_message += "With thousands of different permutations it's difficult to try and debug/diagnose a server. If you're running into timeout issues and need help we suggest you follow these steps:<br/><br/>";
1315
+ default_timeout_message += "<ol>";
1316
+ default_timeout_message += "<li><strong>Contact Host:</strong> Tell your host that you're running into PHP/Web Server timeout issues and ask them if they have any recommendations</li>";
1317
+ default_timeout_message += "<li><strong>Dedicated Help:</strong> If you're in a time-crunch we suggest that you contact <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116150030#faq-resource-030-q'>professional server administrator</a>. A dedicated resource like this will be able to work with you around the clock to the solve the issue much faster than we can in most cases.</li>";
1318
+ default_timeout_message += "<li><strong>Consider Upgrading:</strong> If you're on a budget host then you may run into constraints. If you're running a larger or more complex site it might be worth upgrading to a <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116150030#faq-resource-040-q'>managed VPS server</a>. These systems will pretty much give you full control to use the software without constraints and come with excellent support from the hosting company.</li>";
1319
+ default_timeout_message += "<li><strong>Contact SnapCreek:</strong> We will try our best to help configure and point users in the right direction, however these types of issues can be time-consuming and can take time from our support staff.</li>";
1320
+ default_timeout_message += "</ol>";
1321
+
1322
+ if (page) {
1323
+ switch (page) {
1324
+ default:
1325
+ status += default_timeout_message;
1326
+ break;
1327
+ case 'extract':
1328
+ status += "<b>Recommendation:</b><br/>";
1329
+ status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q'>this FAQ item</a> for possible resolutions.<br/><br/>";
1330
+ break;
1331
+ case 'ping':
1332
+ status += "<b>Recommendation:</b><br/>";
1333
+ status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116152758#faq-trouble-030-q'>this FAQ item</a> for possible resolutions.<br/><br/>";
1334
+ break;
1335
+ case 'delete-site':
1336
+ status += "<b>Recommendation:</b><br/>";
1337
+ status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/?180116153643#faq-installer-120-q'>this FAQ item</a> for possible resolutions.<br/><br/>";
1338
+ break;
1339
+ }
1340
+ } else {
1341
+ status += default_timeout_message;
1342
+ }
1343
+
1344
+ } else if ((xhr.status == 403) || (xhr.status == 500)) {
1345
+ status += "<b>Recommendation:</b><br/>";
1346
+ status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-120-q'>this FAQ item</a> for possible resolutions.<br/><br/>"
1347
+ } else if ((xhr.status == 0) || (xhr.status == 200)) {
1348
+ status += "<b>Recommendation:</b><br/>";
1349
+ status += "Possible server timeout! Performing a 'Manual Extraction' can avoid timeouts.";
1350
+ status += "See <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/#faq-installer-015-q'>this FAQ item</a> for a complete overview.<br/><br/>"
1351
+ } else {
1352
+ status += "<b>Additional Resources:</b><br/> ";
1353
+ status += "&raquo; <a target='_blank' href='https://snapcreek.com/duplicator/docs/'>Help Resources</a><br/>";
1354
+ status += "&raquo; <a target='_blank' href='https://snapcreek.com/duplicator/docs/faqs-tech/'>Technical FAQ</a>";
1355
+ }
1356
+
1357
+ $('#ajaxerr-data').html(status);
1358
+ DUPX.hideProgressBar();
1359
+ };
1360
+
1361
+ DUPX.parseJSON = function (mixData, xHr, textStatus) {
1362
+ try {
1363
+ var parsed = JSON.parse(mixData);
1364
+ return parsed;
1365
+ } catch (e) {
1366
+ console.log("JSON parse failed - 1");
1367
+ }
1368
+
1369
+ var jsonStartPos = mixData.indexOf('{');
1370
+ var jsonLastPos = mixData.lastIndexOf('}');
1371
+ if (jsonStartPos > -1 && jsonLastPos > -1) {
1372
+ var expectedJsonStr = mixData.slice(jsonStartPos, jsonLastPos + 1);
1373
+ try {
1374
+ var parsed = JSON.parse(expectedJsonStr);
1375
+ return parsed;
1376
+ } catch (e) {
1377
+ console.log("JSON parse failed - 2");
1378
+ DUPX.ajaxCommunicationFailed(xHr, textStatus, 'extract');
1379
+ return false;
1380
+ }
1381
+ }
1382
+ DUPX.ajaxCommunicationFailed(xHr, textStatus, 'extract');
1383
+ return false;
1384
+ }
1385
+
1386
+ /** Go back on AJAX result view */
1387
+ DUPX.hideErrorResult = function ()
1388
+ {
1389
+ $('#s1-result-form').hide();
1390
+ $('#s1-input-form').show(200);
1391
+ }
1392
+
1393
+ /**
1394
+ * Accetps Usage Warning */
1395
+ DUPX.acceptWarning = function ()
1396
+ {
1397
+ if ($('#s1-warning-check :checkbox').not(':checked').length === 0) {
1398
+ $("#s1-deploy-btn").removeAttr("disabled");
1399
+ $("#s1-deploy-btn").removeAttr("title");
1400
+ } else {
1401
+ $("#s1-deploy-btn").attr("disabled", "true");
1402
+ $("#s1-deploy-btn").attr("title", "<?php echo DUPX_U::esc_js($agree_msg); ?>");
1403
+ }
1404
+ };
1405
+
1406
+ DUPX.onSafeModeSwitch = function ()
1407
+ {
1408
+ var mode = $('#exe_safe_mode').val();
1409
+ if (mode == 0) {
1410
+ $("#config_mode").removeAttr("disabled");
1411
+ } else if (mode == 1 || mode == 2) {
1412
+ $("#config_mode").val("NEW");
1413
+ $("#config_mode").attr("disabled", true);
1414
+ $('#config_mode option:eq(0)').prop('selected', true)
1415
+ }
1416
+
1417
+ $('#exe-safe-mode').val(mode);
1418
+ };
1419
+
1420
+ //DOCUMENT LOAD
1421
+ $(document).ready(function () {
1422
+ DUPX.DAWS = new Object();
1423
+ DUPX.DAWS.Url = window.location.href + '?is_daws=1&daws_csrf_token=<?php echo urlencode(DUPX_CSRF::generate('daws')); ?>';
1424
+ DUPX.DAWS.StatusPeriodInMS = 5000;
1425
+ DUPX.DAWS.PingWorkerTimeInSec = 9;
1426
+ DUPX.DAWS.KickoffWorkerTimeInSec = 6; // Want the initial progress % to come back quicker
1427
+
1428
+ DUPX.DAWS.MaxRetries = 10;
1429
+ DUPX.DAWS.RetryDelayInMs = 8000;
1430
+
1431
+ DUPX.dupArchiveStatusIntervalID = -1;
1432
+ DUPX.DAWS.FailureCount = 0;
1433
+ DUPX.throttleDelay = 0;
1434
+
1435
+ //INIT Routines
1436
+ DUPX.initToggle();
1437
+ $("#tabs").tabs();
1438
+ DUPX.acceptWarning();
1439
+
1440
+ // <td id="archive_action_wrapper" >
1441
+ // <select id="archive_action_input"
1442
+
1443
+ $('#archive_action_wrapper').each(function () {
1444
+ let paramWrapper = $(this);
1445
+ let noteWrapper = paramWrapper.find('.sub-note');
1446
+
1447
+ paramWrapper.find('.input-item').change(function () {
1448
+ noteWrapper.find('.archive-action-note').addClass('no-display');
1449
+ noteWrapper.find('.archive-action-' + $(this).val()).removeClass('no-display');
1450
+ });
1451
+ });
1452
+ <?php
1453
+ $isWindows = DUPX_U::isWindows();
1454
+ if (!$isWindows) {
1455
+ ?>
1456
+ $('#set_file_perms').trigger("click");
1457
+ $('#set_dir_perms').trigger("click");
1458
+ <?php
1459
+ }
1460
+ ?>
1461
+ DUPX.toggleSetupType();
1462
+
1463
+ <?php echo (!$all_success) ? "$('#s1-area-sys-setup-link').trigger('click');" : ""; ?>
1464
+ });
1465
+ </script>
installer/dup-installer/views/view.s2.base.php CHANGED
@@ -358,7 +358,7 @@ Auto Posts to view.step3.php -->
358
  $(document).ready(function () {
359
  //Init
360
  DUPX.togglePanels("basic");
361
- $("*[data-type='toggle']").click(DUPX.toggleClick);
362
 
363
  });
364
  </script>
358
  $(document).ready(function () {
359
  //Init
360
  DUPX.togglePanels("basic");
361
+ DUPX.initToggle();
362
 
363
  });
364
  </script>
installer/dup-installer/views/view.s2.basic.php CHANGED
@@ -4,11 +4,11 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
4
  /* @var $GLOBALS['DUPX_AC'] DUPX_ArchiveConfig */
5
  /* @var $state DUPX_InstallerState */
6
 
7
- $state = $GLOBALS['DUPX_STATE'];
8
- $is_standard_mode = $state->mode == DUPX_InstallerMode::StandardInstall;
9
- $is_overwrite_mode = ($state->mode == DUPX_InstallerMode::OverwriteInstall && $GLOBALS['DUPX_AC']->installSiteOverwriteOn);
10
 
11
- if($is_standard_mode) {
12
 
13
  $ovr_dbhost = NULL;
14
  $ovr_dbname = NULL;
@@ -22,29 +22,27 @@ if($is_standard_mode) {
22
 
23
  $dbFormDisabledString = '';
24
  } else {
25
- $wpConfigPath = "{$GLOBALS['DUPX_ROOT']}/wp-config.php";
26
- $outerWPConfigPath = dirname($GLOBALS['DUPX_ROOT'])."/wp-config.php";
27
- require_once($GLOBALS['DUPX_INIT'].'/lib/config/class.wp.config.tranformer.php');
28
- $config_transformer = file_exists($wpConfigPath)
29
- ? new DupLiteWPConfigTransformer($wpConfigPath)
30
- : new DupLiteWPConfigTransformer($outerWPConfigPath);
31
 
32
- function dupxGetDbConstVal($constName) {
33
- if ($GLOBALS['config_transformer']->exists('constant', $constName)) {
34
- $configVal = $GLOBALS['config_transformer']->get_value('constant', $constName);
35
- $constVal = htmlspecialchars($configVal);
36
- } else {
37
- $constVal = '';
38
- }
39
- return $constVal;
40
- }
 
 
 
 
 
41
 
42
- $ovr_dbhost = dupxGetDbConstVal('DB_HOST');
43
- $ovr_dbname = dupxGetDbConstVal('DB_NAME');
44
- $ovr_dbuser = dupxGetDbConstVal('DB_USER');
45
- $ovr_dbpass = dupxGetDbConstVal('DB_PASSWORD');
46
-
47
- $dbhost = '';
48
  $dbname = '';
49
  $dbuser = '';
50
  $dbpass = '';
@@ -54,156 +52,160 @@ if($is_standard_mode) {
54
  <!-- =========================================
55
  BASIC PANEL -->
56
  <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s2-db-basic">
57
- <a href="javascript:void(0)"><i class="fa fa-minus-square"></i>Setup</a>
58
  </div>
59
  <div id="s2-db-basic">
60
- <?php if($is_overwrite_mode) : ?>
61
- <div id="s2-db-basic-overwrite">
62
- <b style='color:maroon'>Ready to connect to existing sites database? </b><br/>
63
- <div class="warn-text">
64
- The existing sites database settings are ready to be applied below. If you want to connect to this database and replace all its data then
65
- click the 'Apply button' to set the placeholder values. To use different database settings click the 'Reset button' to clear and set new values.
66
- <br/><br/>
67
-
68
- <i><i class="fas fa-exclamation-triangle fa-sm"></i> Warning: Please note that reusing an existing site's database will <u>overwrite</u> all of its data. If you're not 100% sure about
69
- using these database settings, then create a new database and use the new credentials instead.</i>
70
- </div>
71
 
72
- <div class="btn-area">
73
- <input type="button" value="Apply" class="overwrite-btn" onclick="DUPX.checkOverwriteParameters()">
74
- <input type="button" value="Reset" class="overwrite-btn" onclick="DUPX.resetParameters()">
75
- </div>
76
- </div>
77
- <?php endif; ?>
78
- <table class="dupx-opts">
79
- <tr>
80
- <td>Action:</td>
81
- <td>
82
- <select name="dbaction" id="dbaction">
83
- <?php if($is_standard_mode) : ?>
84
- <option value="create">Create New Database</option>
85
  <?php endif; ?>
86
- <option value="empty" selected>Connect and Remove All Data</option>
87
- </select>
88
- </td>
89
- </tr>
90
- <tr>
91
- <td>Host:</td>
92
- <td><input type="text" name="dbhost" id="dbhost" required="true" value="<?php echo htmlspecialchars($dbhost); ?>" placeholder="localhost" /></td>
93
- </tr>
94
- <tr>
95
- <td>Database:</td>
96
- <td>
97
- <input type="text" name="dbname" id="dbname" required="true" value="<?php echo htmlspecialchars($dbname); ?>" placeholder="new or existing database name" />
98
- <div class="s2-warning-emptydb">
99
- Warning: The selected 'Action' above will remove <u>all data</u> from this database!
100
- </div>
101
- <div class="s2-warning-renamedb">
102
- Notice: The selected 'Action' will rename <u>all existing tables</u> from the database name above with a prefix '<?php echo DUPX_U::esc_html($GLOBALS['DB_RENAME_PREFIX']); ?>'.
103
- The prefix is only applied to existing tables and not the new tables that will be installed.
104
- </div>
105
- <div class="s2-warning-manualdb">
106
- Notice: The 'Manual SQL execution' action will prevent the SQL script in the archive from running. The database above should already be
107
- pre-populated with data which will be updated in the next step. No data in the database will be modified until after Step 3 runs.
108
- </div>
109
- </td>
110
- </tr>
111
- <tr><td>User:</td><td><input type="text" name="dbuser" id="dbuser" required="true" value="<?php echo DUPX_U::esc_attr($dbuser); ?>" placeholder="valid database username" /></td></tr>
112
  <tr>
113
  <td>Password:</td>
114
  <td>
115
  <?php
116
- DUPX_U_Html::inputPasswordToggle('dbpass' , 'dbpass' , array() , array(
117
- 'placeholder' => 'valid database user password' ,
118
- 'value' => $dbpass
119
  ));
120
  ?>
121
  </td>
122
  </tr>
123
- </table>
124
  </div>
125
  <br/><br/>
126
 
127
  <!-- =========================================
128
  BASIC: DB VALIDATION -->
129
  <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s2-dbtest-area-basic">
130
- <a href="javascript:void(0)"><i class="fa fa-minus-square"></i>Validation</a>
131
  </div>
132
 
133
  <div id="s2-dbtest-area-basic" class="s2-dbtest-area hdr-sub1-area">
134
- <div id="s2-dbrefresh-basic">
135
- <a href="javascript:void(0)" onclick="DUPX.testDBConnect()"><i class="fa fa-sync"></i> Retry Test</a>
136
- </div>
137
- <div style="clear:both"></div>
138
- <div id="s2-dbtest-hb-basic" class="s2-dbtest-hb">
139
- <div class="message">
140
- To continue click the 'Test Database' button <br/>
141
- to perform a database integrity check.
142
- </div>
143
- </div>
144
  </div>
145
 
146
- <?php if (! $is_dbtest_mode) : ?>
147
- <!-- =========================================
148
- OPTIONS -->
149
- <div class="hdr-sub1 toggle-hdr" id="s2-opts-hdr-basic" data-type="toggle" data-target="#s2-opts-basic">
150
- <a href="javascript:void(0)"><i class="fa fa-plus-square"></i>Options</a>
151
- </div>
152
- <div id="s2-opts-basic" class="s2-opts hdr-sub1-area" style="display:none;padding-top:0">
153
- <div class="help-target">
154
- <?php DUPX_View_Funcs::helpIconLink('step2'); ?>
155
- </div>
156
 
157
- <table class="dupx-opts dupx-advopts dupx-advopts-space">
158
- <tr>
159
- <td>Legacy:</td>
160
- <td><input type="checkbox" name="dbcollatefb" id="dbcollatefb" value="1" /> <label for="dbcollatefb">Apply legacy collation fallback support for unknown collations types</label></td>
161
- </tr>
162
- <tr>
163
- <td>Spacing:</td>
164
- <td><input type="checkbox" name="dbnbsp" id="dbnbsp" value="1" /> <label for="dbnbsp">Fix non-breaking space characters</label></td>
165
- </tr>
166
- <tr>
167
- <td style="vertical-align:top">Mode:</td>
168
- <td>
169
- <input type="radio" name="dbmysqlmode" id="dbmysqlmode_1" checked="true" value="DEFAULT"/> <label for="dbmysqlmode_1">Default</label> &nbsp;
170
- <input type="radio" name="dbmysqlmode" id="dbmysqlmode_2" value="DISABLE"/> <label for="dbmysqlmode_2">Disable</label> &nbsp;
171
- <input type="radio" name="dbmysqlmode" id="dbmysqlmode_3" value="CUSTOM"/> <label for="dbmysqlmode_3">Custom</label> &nbsp;
172
- <div id="dbmysqlmode_3_view" style="display:none; padding:5px">
173
- <input type="text" name="dbmysqlmode_opts" value="" /><br/>
174
- <small>Separate additional <?php
175
  DUPX_View_Funcs::helpLink('step2', 'sql modes');
176
  ?> with commas &amp; no spaces.<br/>
177
- Example: <i>NO_ENGINE_SUBSTITUTION,NO_ZERO_IN_DATE,...</i>.</small>
178
- </div>
179
- </td>
180
- </tr>
181
- </table>
182
 
183
- <table class="dupx-opts dupx-advopts">
184
- <tr>
185
- <td style="width:130px">Objects:</td>
186
- <td><input type="checkbox" name="dbobj_views" id="dbobj_views" checked="true" /><label for="dbobj_views">Enable View Creation</label></td>
187
- </tr>
188
- <tr>
189
- <td></td>
190
- <td><input type="checkbox" name="dbobj_procs" id="dbobj_procs" checked="true" /><label for="dbobj_procs">Enable Stored Procedure Creation</label></td>
191
- </tr>
192
- <tr>
193
- <td>Charset:</td>
194
- <td>
195
- <input type="text" name="dbcharset" id="dbcharset" value="<?php echo DUPX_U::esc_attr($_POST['dbcharset']); ?>" />
196
- </td>
197
- </tr>
198
- <tr>
199
- <td>Collation: </td>
200
- <td>
201
- <input type="text" name="dbcollate" id="dbcollate" value="<?php echo DUPX_U::esc_attr($_POST['dbcollate']); ?>" />
202
- </td>
203
- </tr>
204
- </table>
205
- </div>
206
- <br/><br/>
 
 
 
 
207
  <?php endif; ?>
208
 
209
 
@@ -212,105 +214,121 @@ BASIC: DB VALIDATION -->
212
  <br/><br/><br/>
213
 
214
  <div class="footer-buttons">
215
- <?php if ($is_dbtest_mode) : ?>
216
- <div style="text-align: center; font-size:11px; margin-top: -20px">
217
- <button id="s2-dbtest-btn-basic" type="button" onclick="DUPX.testDBConnect()" class="default-btn" /><i class="fas fa-database fa-sm"></i> Test Database</button>
218
- <br/><br/>
219
- Notice: This a database only connection view.<br/>
220
- To continue with the install, close this browser window/tab.
221
- </div>
222
- <?php else : ?>
223
- <button id="s2-dbtest-btn-basic" type="button" onclick="DUPX.testDBConnect()" class="default-btn" /><i class="fas fa-database fa-sm"></i> Test Database</button>
224
- <button id="s2-next-btn-basic" type="button" onclick="DUPX.confirmDeployment()" class="default-btn disabled" disabled="true"
225
- title="The 'Test Database' connectivity requirements must pass to continue with install!">
226
- Next <i class="fa fa-caret-right"></i>
227
- </button>
228
- <?php endif; ?>
229
  </div>
230
 
231
  <script>
232
- /**
233
- * Bacic Action Change */
234
- DUPX.basicDBActionChange = function ()
235
- {
236
- var action = $('#dbaction').val();
237
- $('#s2-basic-pane .s2-warning-manualdb').hide();
238
- $('#s2-basic-pane .s2-warning-emptydb').hide();
239
- $('#s2-basic-pane .s2-warning-renamedb').hide();
240
- switch (action) {
241
- case 'create' : break;
242
- case 'empty' : $('#s2-basic-pane .s2-warning-emptydb').show(300); break;
243
- case 'rename' : $('#s2-basic-pane .s2-warning-renamedb').show(300); break;
244
- case 'manual' : $('#s2-basic-pane .s2-warning-manualdb').show(300); break;
245
- }
246
- };
 
 
 
 
 
 
 
247
 
248
  //DOCUMENT INIT
249
- $(document).ready(function ()
250
- {
251
- $("#dbaction").on("change", DUPX.basicDBActionChange);
252
- DUPX.basicDBActionChange();
253
 
254
- $("input[name=dbmysqlmode]").click(function() {
255
- ($(this).val() == 'CUSTOM')
256
- ? $('#dbmysqlmode_3_view').show()
257
- : $('#dbmysqlmode_3_view').hide();
258
- });
259
 
260
- //state = 'enabled', 'disable', 'toggle'
261
- DUPX.basicDBToggleImportMode = function(state)
262
- {
263
- state = typeof state !== 'undefined' ? state : 'enabled';
264
- var $inputs = $("#s2-db-basic").find("input[type=text]");
265
 
266
- switch (state) {
267
- case 'readonly' :
268
- $inputs.each(function(){$(this).attr('readonly', true).css('border', 'none');});
269
- break;
270
- case 'enable' :
271
- $inputs.each(function(){$(this).removeAttr('readonly').css('border', '1px solid silver');});
272
- break;
273
- case 'toggle' :
274
- var readonly = $('input#dbhost').is('[readonly]');
275
- if (readonly) {
276
- $inputs.each(function(){$(this).removeAttr('readonly').css('border', '1px solid silver');});
277
- } else {
278
- $inputs.each(function(){$(this).attr('readonly', true).css('border', 'none');});
279
- }
280
- break;
281
- }
282
- }
 
 
 
 
 
 
 
 
283
 
284
- DUPX.checkOverwriteParameters = function(dbhost, dbname, dbuser, dbpass)
285
- {
286
- $("#dbhost").val(<?php echo "'{$ovr_dbhost}'" ?>);
287
- $("#dbname").val(<?php echo "'{$ovr_dbname}'" ?>);
288
- $("#dbuser").val(<?php echo "'{$ovr_dbuser}'" ?>);
289
- $("#dbpass").val(<?php echo "'{$ovr_dbpass}'" ?>);
290
- DUPX.basicDBToggleImportMode('readonly');
291
- $("#s2-db-basic-setup").show();
292
- }
293
 
294
- DUPX.fillInPlaceHolders = function()
295
- {
296
- $("#dbhost").attr('placeholder', <?php echo "'{$ovr_dbhost}'" ?>);
297
- $("#dbname").attr('placeholder', <?php echo "'{$ovr_dbname}'" ?>);
298
- $("#dbuser").attr('placeholder', <?php echo "'{$ovr_dbuser}'" ?>);
299
- $("#dbpass").attr('placeholder', <?php echo "'{$ovr_dbpass}'" ?>);
300
- }
301
 
302
- DUPX.resetParameters = function()
303
- {
304
- $("#dbhost").val('').attr('placeholder', 'localhost');
305
- $("#dbname").val('').attr('placeholder', 'new or existing database name');
306
- $("#dbuser").val('').attr('placeholder', 'valid database user name');
307
- $("#dbpass").val('').attr('placeholder', 'valid database user password');
308
- DUPX.basicDBToggleImportMode('enable');
309
- }
310
 
311
- <?php if($is_overwrite_mode) : ?>
312
- DUPX.fillInPlaceHolders();
313
- <?php endif; ?>
 
314
 
315
- });
316
  </script>
4
  /* @var $GLOBALS['DUPX_AC'] DUPX_ArchiveConfig */
5
  /* @var $state DUPX_InstallerState */
6
 
7
+ $state = $GLOBALS['DUPX_STATE'];
8
+ $is_standard_mode = $state->mode == DUPX_InstallerMode::StandardInstall;
9
+ $is_overwrite_mode = ($state->mode == DUPX_InstallerMode::OverwriteInstall && $GLOBALS['DUPX_AC']->installSiteOverwriteOn);
10
 
11
+ if ($is_standard_mode) {
12
 
13
  $ovr_dbhost = NULL;
14
  $ovr_dbname = NULL;
22
 
23
  $dbFormDisabledString = '';
24
  } else {
25
+ $wpConfigPath = "{$GLOBALS['DUPX_ROOT']}/wp-config.php";
26
+ $outerWPConfigPath = dirname($GLOBALS['DUPX_ROOT'])."/wp-config.php";
27
+ require_once($GLOBALS['DUPX_INIT'].'/lib/config/class.wp.config.tranformer.php');
28
+ $config_transformer = file_exists($wpConfigPath) ? new DupLiteWPConfigTransformer($wpConfigPath) : new DupLiteWPConfigTransformer($outerWPConfigPath);
 
 
29
 
30
+ function dupxGetDbConstVal($constName)
31
+ {
32
+ if ($GLOBALS['config_transformer']->exists('constant', $constName)) {
33
+ $configVal = $GLOBALS['config_transformer']->get_value('constant', $constName);
34
+ $constVal = htmlspecialchars($configVal);
35
+ } else {
36
+ $constVal = '';
37
+ }
38
+ return $constVal;
39
+ }
40
+ $ovr_dbhost = dupxGetDbConstVal('DB_HOST');
41
+ $ovr_dbname = dupxGetDbConstVal('DB_NAME');
42
+ $ovr_dbuser = dupxGetDbConstVal('DB_USER');
43
+ $ovr_dbpass = dupxGetDbConstVal('DB_PASSWORD');
44
 
45
+ $dbhost = '';
 
 
 
 
 
46
  $dbname = '';
47
  $dbuser = '';
48
  $dbpass = '';
52
  <!-- =========================================
53
  BASIC PANEL -->
54
  <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s2-db-basic">
55
+ <a href="javascript:void(0)"><i class="fa fa-minus-square"></i>Setup</a>
56
  </div>
57
  <div id="s2-db-basic">
58
+ <?php if ($is_overwrite_mode) : ?>
59
+ <div id="s2-db-basic-overwrite" class="gray-panel" >
60
+ <b style='color:maroon'>Ready to connect to existing sites database? </b><br/>
61
+ <div class="warn-text">
62
+ The existing sites database settings should have been applied below. If you want to connect to this database and replace all its data then keep these values.
63
+ To use different database settings click the 'Reset button' to clear the values. To apply the current sites database use the 'Apply Button'.
64
+ <br/><br/>
65
+
66
+ <i><i class="fas fa-exclamation-triangle fa-sm"></i> Warning: Please note that reusing an existing site's database will <u>overwrite</u> all of its data. If you're not 100% sure about
67
+ using these database settings, then create a new database and use the new credentials instead.</i>
68
+ </div>
69
 
70
+ <div class="btn-area">
71
+ <input id="overwrite-btn-apply" type="button" value="Apply" class="overwrite-btn" onclick="DUPX.checkOverwriteParameters()">
72
+ <input id="overwrite-btn-reset" type="button" value="Reset" class="overwrite-btn" onclick="DUPX.resetParameters()">
73
+ </div>
74
+ </div>
75
+ <?php endif; ?>
76
+ <table class="dupx-opts">
77
+ <tr>
78
+ <td>Action:</td>
79
+ <td>
80
+ <select name="dbaction" id="dbaction">
81
+ <?php if ($is_standard_mode) : ?>
82
+ <option value="create">Create New Database</option>
83
  <?php endif; ?>
84
+ <option value="empty" selected>Connect and Remove All Data</option>
85
+ </select>
86
+ </td>
87
+ </tr>
88
+ <tr>
89
+ <td>Host:</td>
90
+ <td><input type="text" name="dbhost" id="dbhost" required="true" value="<?php echo htmlspecialchars($dbhost); ?>" placeholder="localhost" /></td>
91
+ </tr>
92
+ <tr>
93
+ <td>Database:</td>
94
+ <td>
95
+ <input type="text" name="dbname" id="dbname" required="true" value="<?php echo htmlspecialchars($dbname); ?>" placeholder="new or existing database name" />
96
+ <div class="s2-warning-emptydb">
97
+ Warning: The selected 'Action' above will remove <u>all data</u> from this database!
98
+ </div>
99
+ <div class="s2-warning-renamedb">
100
+ Notice: The selected 'Action' will rename <u>all existing tables</u> from the database name above with a prefix '<?php echo DUPX_U::esc_html($GLOBALS['DB_RENAME_PREFIX']); ?>'.
101
+ The prefix is only applied to existing tables and not the new tables that will be installed.
102
+ </div>
103
+ <div class="s2-warning-manualdb">
104
+ Notice: The 'Manual SQL execution' action will prevent the SQL script in the archive from running. The database above should already be
105
+ pre-populated with data which will be updated in the next step. No data in the database will be modified until after Step 3 runs.
106
+ </div>
107
+ </td>
108
+ </tr>
109
+ <tr><td>User:</td><td><input type="text" name="dbuser" id="dbuser" required="true" value="<?php echo DUPX_U::esc_attr($dbuser); ?>" placeholder="valid database username" /></td></tr>
110
  <tr>
111
  <td>Password:</td>
112
  <td>
113
  <?php
114
+ DUPX_U_Html::inputPasswordToggle('dbpass', 'dbpass', array(), array(
115
+ 'placeholder' => 'valid database user password',
116
+ 'value' => $dbpass
117
  ));
118
  ?>
119
  </td>
120
  </tr>
121
+ </table>
122
  </div>
123
  <br/><br/>
124
 
125
  <!-- =========================================
126
  BASIC: DB VALIDATION -->
127
  <div class="hdr-sub1 toggle-hdr" data-type="toggle" data-target="#s2-dbtest-area-basic">
128
+ <a href="javascript:void(0)"><i class="fa fa-minus-square"></i>Validation</a>
129
  </div>
130
 
131
  <div id="s2-dbtest-area-basic" class="s2-dbtest-area hdr-sub1-area">
132
+ <div id="s2-dbrefresh-basic">
133
+ <a href="javascript:void(0)" onclick="DUPX.testDBConnect()"><i class="fa fa-sync"></i> Retry Test</a>
134
+ </div>
135
+ <div style="clear:both"></div>
136
+ <div id="s2-dbtest-hb-basic" class="s2-dbtest-hb">
137
+ <div class="message">
138
+ To continue click the 'Test Database' button <br/>
139
+ to perform a database integrity check.
140
+ </div>
141
+ </div>
142
  </div>
143
 
144
+ <?php if (!$is_dbtest_mode) : ?>
145
+ <!-- =========================================
146
+ OPTIONS -->
147
+ <div class="hdr-sub1 toggle-hdr" id="s2-opts-hdr-basic" data-type="toggle" data-target="#s2-opts-basic">
148
+ <a href="javascript:void(0)"><i class="fa fa-plus-square"></i>Options</a>
149
+ </div>
150
+ <div id="s2-opts-basic" class="s2-opts hdr-sub1-area" style="display:none;padding-top:0">
151
+ <div class="help-target">
152
+ <?php DUPX_View_Funcs::helpIconLink('step2'); ?>
153
+ </div>
154
 
155
+ <table class="dupx-opts dupx-advopts dupx-advopts-space">
156
+ <tr>
157
+ <td>Legacy:</td>
158
+ <td><input type="checkbox" name="dbcollatefb" id="dbcollatefb" value="1" /> <label for="dbcollatefb">Apply legacy collation fallback support for unknown collations types</label></td>
159
+ </tr>
160
+ <tr>
161
+ <td>Spacing:</td>
162
+ <td><input type="checkbox" name="dbnbsp" id="dbnbsp" value="1" /> <label for="dbnbsp">Fix non-breaking space characters</label></td>
163
+ </tr>
164
+ <tr>
165
+ <td style="vertical-align:top">Mode:</td>
166
+ <td>
167
+ <input type="radio" name="dbmysqlmode" id="dbmysqlmode_1" checked="true" value="DEFAULT"/> <label for="dbmysqlmode_1">Default</label> &nbsp;
168
+ <input type="radio" name="dbmysqlmode" id="dbmysqlmode_2" value="DISABLE"/> <label for="dbmysqlmode_2">Disable</label> &nbsp;
169
+ <input type="radio" name="dbmysqlmode" id="dbmysqlmode_3" value="CUSTOM"/> <label for="dbmysqlmode_3">Custom</label> &nbsp;
170
+ <div id="dbmysqlmode_3_view" style="display:none; padding:5px">
171
+ <input type="text" name="dbmysqlmode_opts" value="" /><br/>
172
+ <small>Separate additional <?php
173
  DUPX_View_Funcs::helpLink('step2', 'sql modes');
174
  ?> with commas &amp; no spaces.<br/>
175
+ Example: <i>NO_ENGINE_SUBSTITUTION,NO_ZERO_IN_DATE,...</i>.</small>
176
+ </div>
177
+ </td>
178
+ </tr>
179
+ </table>
180
 
181
+ <table class="dupx-opts dupx-advopts">
182
+ <tr>
183
+ <td style="width:130px">Objects:</td>
184
+ <td><input type="checkbox" name="dbobj_views" id="dbobj_views" checked="true" /><label for="dbobj_views">Enable View Creation</label></td>
185
+ </tr>
186
+ <tr>
187
+ <td></td>
188
+ <td><input type="checkbox" name="dbobj_procs" id="dbobj_procs" checked="true" /><label for="dbobj_procs">Enable Stored Procedure Creation</label></td>
189
+ </tr>
190
+ <tr>
191
+ <td></td>
192
+ <td><input type="checkbox" name="db_remove_definer" id="db_remove_definer"/><label for="db_remove_definer">Remove DEFINER from CREATE queries</label></td>
193
+ </tr>
194
+ <tr>
195
+ <td>Charset:</td>
196
+ <td>
197
+ <input type="text" name="dbcharset" id="dbcharset" value="<?php echo DUPX_U::esc_attr($_POST['dbcharset']); ?>" />
198
+ </td>
199
+ </tr>
200
+ <tr>
201
+ <td>Collation: </td>
202
+ <td>
203
+ <input type="text" name="dbcollate" id="dbcollate" value="<?php echo DUPX_U::esc_attr($_POST['dbcollate']); ?>" />
204
+ </td>
205
+ </tr>
206
+ </table>
207
+ </div>
208
+ <br/><br/>
209
  <?php endif; ?>
210
 
211
 
214
  <br/><br/><br/>
215
 
216
  <div class="footer-buttons">
217
+ <?php if ($is_dbtest_mode) : ?>
218
+ <div style="text-align: center; font-size:11px; margin-top: -20px">
219
+ <button id="s2-dbtest-btn-basic" type="button" onclick="DUPX.testDBConnect()" class="default-btn" /><i class="fas fa-database fa-sm"></i> Test Database</button>
220
+ <br/><br/>
221
+ Notice: This a database only connection view.<br/>
222
+ To continue with the install, close this browser window/tab.
223
+ </div>
224
+ <?php else : ?>
225
+ <button id="s2-dbtest-btn-basic" type="button" onclick="DUPX.testDBConnect()" class="default-btn" /><i class="fas fa-database fa-sm"></i> Test Database</button>
226
+ <button id="s2-next-btn-basic" type="button" onclick="DUPX.confirmDeployment()" class="default-btn disabled" disabled="true"
227
+ title="The 'Test Database' connectivity requirements must pass to continue with install!">
228
+ Next <i class="fa fa-caret-right"></i>
229
+ </button>
230
+ <?php endif; ?>
231
  </div>
232
 
233
  <script>
234
+ /**
235
+ * Bacic Action Change */
236
+ DUPX.basicDBActionChange = function ()
237
+ {
238
+ var action = $('#dbaction').val();
239
+ $('#s2-basic-pane .s2-warning-manualdb').hide();
240
+ $('#s2-basic-pane .s2-warning-emptydb').hide();
241
+ $('#s2-basic-pane .s2-warning-renamedb').hide();
242
+ switch (action) {
243
+ case 'create':
244
+ break;
245
+ case 'empty':
246
+ $('#s2-basic-pane .s2-warning-emptydb').show(300);
247
+ break;
248
+ case 'rename':
249
+ $('#s2-basic-pane .s2-warning-renamedb').show(300);
250
+ break;
251
+ case 'manual':
252
+ $('#s2-basic-pane .s2-warning-manualdb').show(300);
253
+ break;
254
+ }
255
+ };
256
 
257
  //DOCUMENT INIT
258
+ $(document).ready(function ()
259
+ {
260
+ $("#dbaction").on("change", DUPX.basicDBActionChange);
261
+ DUPX.basicDBActionChange();
262
 
263
+ $("input[name=dbmysqlmode]").click(function () {
264
+ ($(this).val() == 'CUSTOM')
265
+ ? $('#dbmysqlmode_3_view').show()
266
+ : $('#dbmysqlmode_3_view').hide();
267
+ });
268
 
269
+ //state = 'enabled', 'disable', 'toggle'
270
+ DUPX.basicDBToggleImportMode = function (state)
271
+ {
272
+ state = typeof state !== 'undefined' ? state : 'enabled';
273
+ var $inputs = $("#s2-db-basic").find("input[type=text]");
274
 
275
+ switch (state) {
276
+ case 'readonly':
277
+ $inputs.each(function () {
278
+ $(this).attr('readonly', true).css('border', 'none');
279
+ });
280
+ break;
281
+ case 'enable':
282
+ $inputs.each(function () {
283
+ $(this).removeAttr('readonly').css('border', '1px solid silver');
284
+ });
285
+ break;
286
+ case 'toggle':
287
+ var readonly = $('input#dbhost').is('[readonly]');
288
+ if (readonly) {
289
+ $inputs.each(function () {
290
+ $(this).removeAttr('readonly').css('border', '1px solid silver');
291
+ });
292
+ } else {
293
+ $inputs.each(function () {
294
+ $(this).attr('readonly', true).css('border', 'none');
295
+ });
296
+ }
297
+ break;
298
+ }
299
+ }
300
 
301
+ DUPX.checkOverwriteParameters = function (dbhost, dbname, dbuser, dbpass)
302
+ {
303
+ $("#dbhost").val(<?php echo "'{$ovr_dbhost}'" ?>);
304
+ $("#dbname").val(<?php echo "'{$ovr_dbname}'" ?>);
305
+ $("#dbuser").val(<?php echo "'{$ovr_dbuser}'" ?>);
306
+ $("#dbpass").val(<?php echo "'{$ovr_dbpass}'" ?>);
307
+ DUPX.basicDBToggleImportMode('readonly');
308
+ $("#s2-db-basic-setup").show();
309
+ }
310
 
311
+ DUPX.fillInPlaceHolders = function ()
312
+ {
313
+ $("#dbhost").attr('placeholder', <?php echo "'{$ovr_dbhost}'" ?>);
314
+ $("#dbname").attr('placeholder', <?php echo "'{$ovr_dbname}'" ?>);
315
+ $("#dbuser").attr('placeholder', <?php echo "'{$ovr_dbuser}'" ?>);
316
+ $("#dbpass").attr('placeholder', <?php echo "'{$ovr_dbpass}'" ?>);
317
+ }
318
 
319
+ DUPX.resetParameters = function ()
320
+ {
321
+ $("#dbhost").val('').attr('placeholder', 'localhost');
322
+ $("#dbname").val('').attr('placeholder', 'new or existing database name');
323
+ $("#dbuser").val('').attr('placeholder', 'valid database user name');
324
+ $("#dbpass").val('').attr('placeholder', 'valid database user password');
325
+ DUPX.basicDBToggleImportMode('enable');
326
+ }
327
 
328
+ <?php if ($is_overwrite_mode) : ?>
329
+ DUPX.fillInPlaceHolders();
330
+ $('#overwrite-btn-apply').click();
331
+ <?php endif; ?>
332
 
333
+ });
334
  </script>
installer/dup-installer/views/view.s2.dbtest.php CHANGED
@@ -299,6 +299,33 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
299
  </ul>
300
  </div>
301
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  </div>
303
  </script>
304
 
@@ -490,9 +517,6 @@ DUPX.intTestDBResults = function(data, result)
490
  $(this).attr('data-target', attr + mode);
491
  });
492
 
493
- $("div#" + resultID + " *[data-type='toggle']").on('click', DUPX.toggleClick);
494
-
495
-
496
  var $divReqsAll = $('div#s2-reqs-all' + mode);
497
  var $divNoticeAll = $('div#s2-notices-all' + mode);
498
  var $btnNext = $('#s2-next-btn' + mode);
299
  </ul>
300
  </div>
301
 
302
+ <!-- ==================================
303
+ NOTICE 20: SOURCE SITE CONTAINED TRIGGERS-->
304
+ <div class="status {{optionalNoticeStyle payload.notices.20.pass}}">{{noticeText payload.notices.20.pass}}</div>
305
+ <div class="title" data-type="toggle" data-target="#s2-notice20" style="border-top:none"><i class="fa fa-caret-right"></i> {{payload.notices.20.title}}</div>
306
+ <div class="info" id="s2-notice20">
307
+ <div class="sub-title">STATUS</div>
308
+ {{#if payload.notices.20.pass}}
309
+ <p>{{payload.notices.20.info}}</p>
310
+ {{else}}
311
+ <p>The source site contains Triggers which can optionally be imported after the install process is complete. </p>
312
+ <div class="sub-title">DETAILS</div>
313
+ <p>
314
+ Triggers are not being imported alongside the rest of the database, because they may cause unintended behavior during the install process.
315
+ It is recommeded that you copy the queries to a seperate document and save them for later. After the install process is
316
+ completed and you have logged into your WordPress Admin you can then add the triggers if needed.
317
+ <br/><br/>
318
+ For a quick overview on how to add these triggers back to your site checkout this
319
+ <a href="https://www.siteground.com/tutorials/phpmyadmin/" target="_blank">phpMyAdmin Tutorial</a>. See the section
320
+ titled "How to Run MySQL Queries" to run the queries below.
321
+ </p>
322
+ <div class="copy-to-clipboard-block">
323
+ <button type="button" class="default-btn">Copy Queries To Clipboard</button>
324
+ <textarea readonly="readonly">{{payload.notices.20.info}}</textarea>
325
+ </div>
326
+ {{/if}}
327
+ </div>
328
+
329
  </div>
330
  </script>
331
 
517
  $(this).attr('data-target', attr + mode);
518
  });
519
 
 
 
 
520
  var $divReqsAll = $('div#s2-reqs-all' + mode);
521
  var $divNoticeAll = $('div#s2-notices-all' + mode);
522
  var $btnNext = $('#s2-next-btn' + mode);
installer/dup-installer/views/view.s3.php CHANGED
@@ -599,7 +599,7 @@ $(document).ready(function()
599
  $("#tabs").tabs();
600
  DUPX.getNewURL('url_new');
601
  DUPX.getNewURL('siteurl');
602
- $("*[data-type='toggle']").click(DUPX.toggleClick);
603
  $("#wp_password").passStrength({
604
  shortPass: "top_shortPass",
605
  badPass: "top_badPass",
599
  $("#tabs").tabs();
600
  DUPX.getNewURL('url_new');
601
  DUPX.getNewURL('siteurl');
602
+ DUPX.initToggle();
603
  $("#wp_password").passStrength({
604
  shortPass: "top_shortPass",
605
  badPass: "top_badPass",
installer/dup-installer/views/view.s4.php CHANGED
@@ -413,7 +413,7 @@ LONGMSG;
413
  $(document).ready(function () {
414
 
415
  //INIT Routines
416
- $("*[data-type='toggle']").click(DUPX.toggleClick);
417
  $("#tabs").tabs();
418
 
419
  });
413
  $(document).ready(function () {
414
 
415
  //INIT Routines
416
+ DUPX.initToggle();
417
  $("#tabs").tabs();
418
 
419
  });
installer/installer.tpl CHANGED
@@ -550,6 +550,54 @@ class DUPX_Bootstrap
550
 
551
  return $retVal;
552
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553
 
554
  /**
555
  * Attempts to set the 'dup-installer' directory permissions
@@ -593,7 +641,7 @@ class DUPX_Bootstrap
593
  }
594
  }
595
 
596
- /**
597
  * Set the permissions of a single directory or file
598
  *
599
  * @param string $path The full path to the directory or file where perms will be set
@@ -601,15 +649,15 @@ class DUPX_Bootstrap
601
  *
602
  * @return bool Returns true if the permission was properly set
603
  */
604
- private function setPermsOnItem($path, $perms)
605
- {
606
  if (($result = self::chmod($path, $perms)) === false) {
607
  self::log("ERROR: Couldn't set permissions of $path<br/>");
608
  } else {
609
  self::log("Set permissions of $path<br/>");
610
  }
611
  return $result;
612
- }
613
 
614
  /**
615
  * Compare two strings and return html text which represts diff
@@ -655,7 +703,7 @@ class DUPX_Bootstrap
655
  {
656
  static $logfile = null;
657
  if (is_null($logfile)) {
658
- $logfile = dirname(__FILE__).'/dup-installer-bootlog__'.self::SECONDARY_PACKAGE_HASH.'.txt';
659
  }
660
  if ($deleteOld && file_exists($logfile)) {
661
  @unlink($logfile);
@@ -664,6 +712,15 @@ class DUPX_Bootstrap
664
  return @file_put_contents($logfile, '['.$timestamp.'] '.self::postprocessLog($s)."\n", FILE_APPEND);
665
  }
666
 
 
 
 
 
 
 
 
 
 
667
  protected static function postprocessLog($str) {
668
  return str_replace(array(
669
  self::getArchiveFileHash(),
@@ -1614,6 +1671,11 @@ if ($boot_error == null) {
1614
  DUPX_CSRF::setKeyVal('archive', $boot->archive);
1615
  DUPX_CSRF::setKeyVal('bootloader', $boot->bootloader);
1616
  DUPX_CSRF::setKeyVal('secondaryHash', DUPX_Bootstrap::SECONDARY_PACKAGE_HASH);
 
 
 
 
 
1617
  }
1618
  ?>
1619
 
550
 
551
  return $retVal;
552
  }
553
+
554
+ /**
555
+ * Fetches current URL via php
556
+ *
557
+ * @param bool $queryString If true the query string will also be returned.
558
+ * @param int $getParentDirLevel if 0 get current script name or parent folder, if 1 parent folder if 2 parent of parent folder ...
559
+ *
560
+ * @returns The current page url
561
+ */
562
+ public static function getCurrentUrl($queryString = true, $requestUri = false, $getParentDirLevel = 0)
563
+ {
564
+ // *** HOST
565
+ if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) {
566
+ $host = $_SERVER['HTTP_X_ORIGINAL_HOST'];
567
+ } else {
568
+ $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']; //WAS SERVER_NAME and caused problems on some boxes
569
+ }
570
+
571
+ // *** PROTOCOL
572
+ if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
573
+ $_SERVER ['HTTPS'] = 'on';
574
+ }
575
+ if (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'https') {
576
+ $_SERVER ['HTTPS'] = 'on';
577
+ }
578
+ if (isset($_SERVER['HTTP_CF_VISITOR'])) {
579
+ $visitor = json_decode($_SERVER['HTTP_CF_VISITOR']);
580
+ if ($visitor->scheme == 'https') {
581
+ $_SERVER ['HTTPS'] = 'on';
582
+ }
583
+ }
584
+ $protocol = 'http'.((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on') ? 's' : '');
585
+
586
+ if ($requestUri) {
587
+ $serverUrlSelf = preg_replace('/\?.*$/', '', $_SERVER['REQUEST_URI']);
588
+ } else {
589
+ // *** SCRIPT NAME
590
+ $serverUrlSelf = $_SERVER['SCRIPT_NAME'];
591
+ for ($i = 0; $i < $getParentDirLevel; $i++) {
592
+ $serverUrlSelf = preg_match('/^[\\\\\/]?$/', dirname($serverUrlSelf)) ? '' : dirname($serverUrlSelf);
593
+ }
594
+ }
595
+
596
+ // *** QUERY STRING
597
+ $query = ($queryString && isset($_SERVER['QUERY_STRING']) && strlen($_SERVER['QUERY_STRING']) > 0 ) ? '?'.$_SERVER['QUERY_STRING'] : '';
598
+
599
+ return $protocol.'://'.$host.$serverUrlSelf.$query;
600
+ }
601
 
602
  /**
603
  * Attempts to set the 'dup-installer' directory permissions
641
  }
642
  }
643
 
644
+ /**
645
  * Set the permissions of a single directory or file
646
  *
647
  * @param string $path The full path to the directory or file where perms will be set
649
  *
650
  * @return bool Returns true if the permission was properly set
651
  */
652
+ private function setPermsOnItem($path, $perms)
653
+ {
654
  if (($result = self::chmod($path, $perms)) === false) {
655
  self::log("ERROR: Couldn't set permissions of $path<br/>");
656
  } else {
657
  self::log("Set permissions of $path<br/>");
658
  }
659
  return $result;
660
+ }
661
 
662
  /**
663
  * Compare two strings and return html text which represts diff
703
  {
704
  static $logfile = null;
705
  if (is_null($logfile)) {
706
+ $logfile = self::getBootLogFilePath();
707
  }
708
  if ($deleteOld && file_exists($logfile)) {
709
  @unlink($logfile);
712
  return @file_put_contents($logfile, '['.$timestamp.'] '.self::postprocessLog($s)."\n", FILE_APPEND);
713
  }
714
 
715
+ /**
716
+ * get boot log file name the dup-installer-bootlog__[HASH].txt file
717
+ *
718
+ * @return string
719
+ */
720
+ public static function getBootLogFilePath() {
721
+ return dirname(__FILE__).'/dup-installer-bootlog__'.self::SECONDARY_PACKAGE_HASH.'.txt';
722
+ }
723
+
724
  protected static function postprocessLog($str) {
725
  return str_replace(array(
726
  self::getArchiveFileHash(),
1671
  DUPX_CSRF::setKeyVal('archive', $boot->archive);
1672
  DUPX_CSRF::setKeyVal('bootloader', $boot->bootloader);
1673
  DUPX_CSRF::setKeyVal('secondaryHash', DUPX_Bootstrap::SECONDARY_PACKAGE_HASH);
1674
+ DUPX_CSRF::setKeyVal('installerOrigCall', DUPX_Bootstrap::getCurrentUrl());
1675
+ DUPX_CSRF::setKeyVal('installerOrigPath', __FILE__);
1676
+ DUPX_CSRF::setKeyVal('booturl', '//'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
1677
+ DUPX_CSRF::setKeyVal('bootLogFile', DUPX_Bootstrap::getBootLogFilePath());
1678
+ DUPX_CSRF::setKeyVal('package_hash', DUPX_Bootstrap::PACKAGE_HASH);
1679
  }
1680
  ?>
1681
 
lib/snaplib/class.snaplib.logger.php CHANGED
@@ -18,7 +18,7 @@ if (!class_exists('DupLiteSnapLibLogger', false)) {
18
  {
19
 
20
  public static $logFilepath = null;
21
- static $logHandle = null;
22
 
23
  public static function init($logFilepath)
24
  {
@@ -109,5 +109,36 @@ if (!class_exists('DupLiteSnapLibLogger', false)) {
109
 
110
  self::log(" {$dPrev} : {$dSame} : {$currentTime} : {$s}");
111
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  }
113
- }
18
  {
19
 
20
  public static $logFilepath = null;
21
+ public static $logHandle = null;
22
 
23
  public static function init($logFilepath)
24
  {
109
 
110
  self::log(" {$dPrev} : {$dSame} : {$currentTime} : {$s}");
111
  }
112
+
113
+ /**
114
+ *
115
+ * @param mixed $var
116
+ * @param bool $checkCallable // if true check if var is callable and display it
117
+ * @return string
118
+ */
119
+ public static function varToString($var, $checkCallable = false)
120
+ {
121
+ if ($checkCallable && is_callable($var)) {
122
+ return '(callable) '.print_r($var, true);
123
+ }
124
+ switch (gettype($var)) {
125
+ case "boolean":
126
+ return $var ? 'true' : 'false';
127
+ case "integer":
128
+ case "double":
129
+ return (string) $var;
130
+ case "string":
131
+ return '"'.$var.'"';
132
+ case "array":
133
+ case "object":
134
+ return print_r($var, true);
135
+ case "resource":
136
+ case "resource (closed)":
137
+ case "NULL":
138
+ case "unknown type":
139
+ default:
140
+ return gettype($var);
141
+ }
142
+ }
143
  }
144
+ }
lib/snaplib/class.snaplib.u.db.php ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Snap Database utils
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2
7
+ *
8
+ * @package SnapLib
9
+ * @copyright (c) 2017, Snapcreek LLC
10
+ * @license https://opensource.org/licenses/GPL-3.0 GNU Public License
11
+ *
12
+ */
13
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
14
+
15
+ class DupLiteSnapLibDB
16
+ {
17
+
18
+ const CACHE_PREFIX_PRIMARY_KEY_COLUMN = 'pkcol_';
19
+ const DB_ENGINE_MYSQL = 'MySQL';
20
+ const DB_ENGINE_MARIA = 'MariaDB';
21
+ const DB_ENGINE_PERCONA = 'Percona';
22
+
23
+ private static $cache = array();
24
+
25
+ /**
26
+ *
27
+ * @param mysqli $dbh // Database connection handle
28
+ * @param string $tableName
29
+ * @return string|string[] // return array if primary key is composite key
30
+ * @throws Exception
31
+ */
32
+ public static function getUniqueIndexColumn(\mysqli $dbh, $tableName, $logCallback = null)
33
+ {
34
+ $cacheKey = self::CACHE_PREFIX_PRIMARY_KEY_COLUMN.$tableName;
35
+
36
+ if (!isset(self::$cache[$cacheKey])) {
37
+ $query = 'SHOW COLUMNS FROM `'.mysqli_real_escape_string($dbh, $tableName).'` WHERE `Key` IN ("PRI","UNI")';
38
+ if (($result = mysqli_query($dbh, $query)) === false) {
39
+ if (is_callable($logCallback)) {
40
+ call_user_func($logCallback, $dbh, $result, $query);
41
+ }
42
+ throw new Exception('SHOW KEYS QUERY ERROR: '.mysqli_error($dbh));
43
+ }
44
+
45
+ if (is_callable($logCallback)) {
46
+ call_user_func($logCallback, $dbh, $result, $query);
47
+ }
48
+
49
+ if ($result->num_rows == 0) {
50
+ self::$cache[$cacheKey] = false;
51
+ } else {
52
+ $primary = false;
53
+ $unique = false;
54
+
55
+ while ($row = $result->fetch_assoc()) {
56
+ switch ($row['Key']) {
57
+ case 'PRI':
58
+ if ($primary === false) {
59
+ $primary = $row['Field'];
60
+ } else {
61
+ if (is_scalar($primary)) {
62
+ $primary = array($primary);
63
+ }
64
+ $primary[] = $row['Field'];
65
+ }
66
+ break;
67
+ case 'UNI':
68
+ $unique = $row['Field'];
69
+ break;
70
+ default:
71
+ break;
72
+ }
73
+ }
74
+ if ($primary !== false) {
75
+ self::$cache[$cacheKey] = $primary;
76
+ } else if ($unique !== false) {
77
+ self::$cache[$cacheKey] = $unique;
78
+ } else {
79
+ self::$cache[$cacheKey] = false;
80
+ }
81
+ }
82
+
83
+ $result->free();
84
+ }
85
+
86
+ return self::$cache[$cacheKey];
87
+ }
88
+
89
+ /**
90
+ *
91
+ * @param array $row
92
+ * @param string|string[] $indexColumns
93
+ * @return string|string[]
94
+ */
95
+ public static function getOffsetFromRowAssoc($row, $indexColumns, $lastOffset)
96
+ {
97
+ if (is_array($indexColumns)) {
98
+ $result = array();
99
+ foreach ($indexColumns as $col) {
100
+ $result[$col] = isset($row[$col]) ? $row[$col] : 0;
101
+ }
102
+ return $result;
103
+ } else if (strlen($indexColumns) > 0) {
104
+ return isset($row[$indexColumns]) ? $row[$indexColumns] : 0;
105
+ } else {
106
+ return $lastOffset + 1;
107
+ }
108
+ }
109
+
110
+ /**
111
+ * This function performs a select by structuring the primary key as offset if the table has a primary key.
112
+ * For optimization issues, no checks are performed on the input query and it is assumed that the select has at least a where value.
113
+ * If there are no conditions, you still have to perform an always true condition, for example
114
+ * SELECT * FROM `copy1_postmeta` WHERE 1
115
+ *
116
+ * @param mysqli $dbh // Database connection handle
117
+ * @param string $query
118
+ * @param string $table
119
+ * @param int $offset
120
+ * @param int $limit // 0 no limit
121
+ * @param mixed $lastRowOffset // last offset to use on next function call
122
+ * @return mysqli_result
123
+ * @throws Exception // exception on query fail
124
+ */
125
+ public static function selectUsingPrimaryKeyAsOffset(\mysqli $dbh, $query, $table, $offset, $limit, &$lastRowOffset = null, $logCallback = null)
126
+ {
127
+ $where = '';
128
+ $orderby = '';
129
+ $offsetStr = '';
130
+ $limitStr = $limit > 0 ? ' LIMIT '.$limit : '';
131
+
132
+ if (($primaryColumn = self::getUniqueIndexColumn($dbh, $table, $logCallback)) == false) {
133
+ $offsetStr = ' OFFSET '.(is_scalar($offset) ? $offset : 0);
134
+ } else {
135
+ if (is_array($primaryColumn)) {
136
+ // COMPOSITE KEY
137
+ $orderByCols = array();
138
+ foreach ($primaryColumn as $colIndex => $col) {
139
+ $orderByCols[] = '`'.$col.'` ASC';
140
+ }
141
+ $orderby = ' ORDER BY '.implode(',', $orderByCols);
142
+ } else {
143
+ $orderby = ' ORDER BY `'.$primaryColumn.'` ASC';
144
+ }
145
+ $where = self::getOffsetKeyCondition($dbh, $primaryColumn, $offset);
146
+ }
147
+ $query .= $where.$orderby.$limitStr.$offsetStr;
148
+
149
+ if (($result = mysqli_query($dbh, $query)) === false) {
150
+ if (is_callable($logCallback)) {
151
+ call_user_func($logCallback, $dbh, $result, $query);
152
+ }
153
+ throw new Exception('SELECT ERROR: '.mysqli_error($dbh));
154
+ }
155
+
156
+ if (is_callable($logCallback)) {
157
+ call_user_func($logCallback, $dbh, $result, $query);
158
+ }
159
+
160
+ if ($primaryColumn == false) {
161
+ $lastRowOffset = $offset + $result->num_rows;
162
+ } else {
163
+ if ($result->num_rows == 0) {
164
+ $lastRowOffset = $offset;
165
+ } else {
166
+ $result->data_seek(($result->num_rows - 1));
167
+ $row = $result->fetch_assoc();
168
+ if (is_array($primaryColumn)) {
169
+ $lastRowOffset = array();
170
+ foreach ($primaryColumn as $col) {
171
+ $lastRowOffset[$col] = $row[$col];
172
+ }
173
+ } else {
174
+ $lastRowOffset = $row[$primaryColumn];
175
+ }
176
+ $result->data_seek(0);
177
+ }
178
+ }
179
+
180
+ return $result;
181
+ }
182
+
183
+ /**
184
+ * Depending on the structure type of the primary key returns the condition to position at the right offset
185
+ *
186
+ * @param string|string[] $primaryColumn
187
+ * @param mixed $offset
188
+ * @return string
189
+ */
190
+ protected static function getOffsetKeyCondition(\mysqli $dbh, $primaryColumn, $offset)
191
+ {
192
+ $condition = '';
193
+
194
+ if ($offset === 0) {
195
+ return '';
196
+ }
197
+
198
+ // COUPOUND KEY
199
+ if (is_array($primaryColumn)) {
200
+ foreach ($primaryColumn as $colIndex => $col) {
201
+ if (is_array($offset) && isset($offset[$col]) && $offset[$col] > 0) {
202
+ $condition .= ($colIndex == 0 ? '' : ' OR ');
203
+ $condition .= ' (';
204
+ for ($prevColIndex = 0; $prevColIndex < $colIndex; $prevColIndex++) {
205
+ $condition .= ' `'.$primaryColumn[$prevColIndex].'` = "'.mysqli_real_escape_string($dbh, $offset[$primaryColumn[$prevColIndex]]).'" AND ';
206
+ }
207
+ $condition .= ' `'.$col.'` > "'.mysqli_real_escape_string($dbh, $offset[$col]).'")';
208
+ }
209
+ }
210
+ } else {
211
+ $condition = '`'.$primaryColumn.'` > "'.mysqli_real_escape_string($dbh, (is_scalar($offset) ? $offset : 0)).'"';
212
+ }
213
+
214
+ return (strlen($condition) ? ' AND ('.$condition.')' : '');
215
+ }
216
+
217
+ public static function getDBEngine(\mysqli $dbh)
218
+ {
219
+ $result = mysqli_query($dbh, "SHOW VARIABLES LIKE 'version%'");
220
+ $rows = @mysqli_fetch_all($result);
221
+ @mysqli_free_result($result);
222
+
223
+ $version = isset($rows[0][1]) ? $rows[0][1] : false;
224
+ $versionComment = isset($rows[1][1]) ? $rows[1][1] : false;
225
+
226
+ //Default is mysql
227
+ if ($version === false && $versionComment === false) {
228
+ return self::DB_ENGINE_MYSQL;
229
+ }
230
+
231
+ if (stripos($version, 'maria') !== false || stripos($versionComment, 'maria') !== false) {
232
+ return self::DB_ENGINE_MARIA;
233
+ }
234
+
235
+ if (stripos($version, 'percona') !== false || stripos($versionComment, 'percona') !== false) {
236
+ return self::DB_ENGINE_PERCONA;
237
+ }
238
+
239
+ return self::DB_ENGINE_MYSQL;
240
+ }
241
+ }
lib/snaplib/class.snaplib.u.io.php CHANGED
@@ -23,12 +23,44 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
23
  // Real upper bound of a signed int is 214748364.
24
  // The value chosen below, makes sure we have a buffer of ~4.7 million.
25
  const FileSizeLimit32BitPHP = 1900000000;
 
26
 
27
  public static function rmPattern($filePathPattern)
28
  {
29
  @array_map('unlink', glob($filePathPattern));
30
  }
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  public static function chmodPattern($filePathPattern, $mode)
33
  {
34
  $filePaths = glob($filePathPattern);
@@ -47,15 +79,10 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
47
  if ($overwriteIfExists) {
48
  self::rm($dest);
49
  } else {
50
- throw new Exception("Can't copy {$source} to {$dest} because {$dest} already exists!");
51
  }
52
  }
53
-
54
- if (copy($source, $dest) === false) {
55
- throw new Exception("Error copying {$source} to {$dest}");
56
- }
57
-
58
- return true;
59
  }
60
 
61
  /**
@@ -271,11 +298,7 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
271
  if (!function_exists('touch')) {
272
  return false;
273
  }
274
-
275
- if (!is_writeable($filepath)) {
276
- return false;
277
- }
278
-
279
  if ($time === null) {
280
  $time = time();
281
  }
@@ -306,17 +329,50 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
306
  }
307
  }
308
 
 
 
 
 
 
 
 
309
  public static function fwrite($handle, $string)
310
  {
311
  $bytes_written = @fwrite($handle, $string);
312
 
313
- if ($bytes_written === false) {
314
  throw new Exception('Error writing to file.');
315
  } else {
316
  return $bytes_written;
317
  }
318
  }
319
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  public static function fgets($handle, $length)
321
  {
322
  $line = fgets($handle, $length);
@@ -347,14 +403,14 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
347
  $position = @ftell($file_handle);
348
 
349
  if ($position === false) {
350
- throw new Exception("Couldn't retrieve file offset for $filepath");
351
  } else {
352
  return $position;
353
  }
354
  }
355
 
356
  /**
357
- * Safely remove a directory and recursively files adnd directory upto multiple sublevels
358
  *
359
  * @param path $dir The full path to the directory to remove
360
  *
@@ -504,88 +560,87 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
504
 
505
  if (is_int($mode)) {
506
  $octalMode = $mode;
507
- } else if (is_string($mode)) {
508
- $mode = trim($mode);
509
- if (preg_match('/([0-7]{1,3})/', $mode)) {
510
- $octalMode = intval(('0'.$mode), 8);
511
- } else if (preg_match_all('/(a|[ugo]{1,3})([-=+])([rwx]{1,3})/', $mode, $gMatch, PREG_SET_ORDER)) {
512
- if (!function_exists('fileperms')) {
513
- return false;
514
- }
515
 
516
- // start by file permission
517
- $octalMode = (fileperms($file) & 0777);
518
 
519
- foreach ($gMatch as $matches) {
520
- // [ugo] or a = ugo
521
- $group = $matches[1];
522
- if ($group === 'a') {
523
- $group = 'ugo';
524
- }
525
- // can be + - =
526
- $action = $matches[2];
527
- // [rwx]
528
- $gPerms = $matches[3];
529
-
530
- // reset octal group perms
531
- $octalGroupMode = 0;
532
-
533
- // Init sub perms
534
- $subPerm = 0;
535
- $subPerm += strpos($gPerms, 'x') !== false ? 1 : 0; // mask 001
536
- $subPerm += strpos($gPerms, 'w') !== false ? 2 : 0; // mask 010
537
- $subPerm += strpos($gPerms, 'r') !== false ? 4 : 0; // mask 100
538
-
539
- $ugoLen = strlen($group);
540
-
541
- if ($action === '=') {
542
- // generate octal group permsissions and ugo mask invert
543
- $ugoMaskInvert = 0777;
544
- for ($i = 0; $i < $ugoLen; $i++) {
545
- switch ($group[$i]) {
546
- case 'u':
547
- $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
548
- $ugoMaskInvert = $ugoMaskInvert & 077;
549
- break;
550
- case 'g':
551
- $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
552
- $ugoMaskInvert = $ugoMaskInvert & 0707;
553
- break;
554
- case 'o':
555
- $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
556
- $ugoMaskInvert = $ugoMaskInvert & 0770;
557
- break;
558
- }
559
- }
560
- // apply = action
561
- $octalMode = $octalMode & ($ugoMaskInvert | $octalGroupMode);
562
- } else {
563
- // generate octal group permsissions
564
- for ($i = 0; $i < $ugoLen; $i++) {
565
- switch ($group[$i]) {
566
- case 'u':
567
- $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
568
- break;
569
- case 'g':
570
- $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
571
- break;
572
- case 'o':
573
- $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
574
- break;
575
- }
576
  }
577
- // apply + or - action
578
- switch ($action) {
579
- case '+':
580
- $octalMode = $octalMode | $octalGroupMode;
 
 
 
 
 
 
 
 
581
  break;
582
- case '-':
583
- $octalMode = $octalMode & ~$octalGroupMode;
584
  break;
585
  }
586
  }
 
 
 
 
 
 
 
 
 
587
  }
588
  }
 
 
589
  }
590
 
591
  // if input permissions are equal at file permissions return true without performing chmod
@@ -600,6 +655,25 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
600
  return @chmod($file, $octalMode);
601
  }
602
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  /**
604
  * this function creates a folder if it does not exist and performs a chmod.
605
  * it is different from the normal mkdir function to which an umask is applied to the input permissions.
@@ -613,7 +687,7 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
613
  * @param string $path
614
  * @param int|string $mode
615
  * @param bool $recursive
616
- * @param resource $context // not used for windows bug
617
  * @return boolean bool TRUE on success or FALSE on failure.
618
  *
619
  * @todo check recursive true and multiple chmod
@@ -757,12 +831,16 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
757
  */
758
  public static function getRelativePath($path, $mainPath)
759
  {
 
 
 
 
760
  $safePath = self::safePathUntrailingslashit($path);
761
  $safeMainPath = self::safePathUntrailingslashit($mainPath);
762
 
763
- if (empty($mainPath)) {
764
- return ltrim($safePath, '/');
765
- } else if (strpos($safePath, $safeMainPath) === 0) {
766
  return ltrim(substr($safePath, strlen($safeMainPath)), '/');
767
  } else {
768
  return false;
@@ -856,6 +934,60 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
856
  return preg_replace('/^(?:[A-Za-z]:)?[\/](.*)/', '$1', $path);
857
  }
858
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
859
  /**
860
  * @param string $path Path to the file
861
  * @param int $n Number of lines to get
@@ -906,6 +1038,176 @@ if (!class_exists('DupLiteSnapLibIOU', false)) {
906
  return array_reverse($result);
907
  }
908
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
909
  /**
910
  * Returns a path to the base root folder of path taking into account the
911
  * open_basedir setting.
23
  // Real upper bound of a signed int is 214748364.
24
  // The value chosen below, makes sure we have a buffer of ~4.7 million.
25
  const FileSizeLimit32BitPHP = 1900000000;
26
+ const FWRITE_CHUNK_SIZE = 4096; // bytes
27
 
28
  public static function rmPattern($filePathPattern)
29
  {
30
  @array_map('unlink', glob($filePathPattern));
31
  }
32
 
33
+ /**
34
+ *
35
+ * @param string $path
36
+ * @param array $args // array key / val where key is the var name in include
37
+ * @param bool $required
38
+ * @return string
39
+ * @throws Exception // thorw exception if is $required and file can't be read
40
+ */
41
+ public static function getInclude($path, $args = array(), $required = true)
42
+ {
43
+ if (!is_readable($path)) {
44
+ if ($required) {
45
+ throw new Exception('Can\'t read required file '.$path);
46
+ } else {
47
+ return '';
48
+ }
49
+ }
50
+
51
+ foreach ($args as $var => $value) {
52
+ ${$var} = $value;
53
+ }
54
+
55
+ ob_start();
56
+ if ($required) {
57
+ require ($path);
58
+ } else {
59
+ include ($path);
60
+ }
61
+ return ob_get_clean();
62
+ }
63
+
64
  public static function chmodPattern($filePathPattern, $mode)
65
  {
66
  $filePaths = glob($filePathPattern);
79
  if ($overwriteIfExists) {
80
  self::rm($dest);
81
  } else {
82
+ return false;
83
  }
84
  }
85
+ return copy($source, $dest);
 
 
 
 
 
86
  }
87
 
88
  /**
298
  if (!function_exists('touch')) {
299
  return false;
300
  }
301
+
 
 
 
 
302
  if ($time === null) {
303
  $time = time();
304
  }
329
  }
330
  }
331
 
332
+ /**
333
+ *
334
+ * @param resource $handle
335
+ * @param srtring $string
336
+ * @return int
337
+ * @throws Exception
338
+ */
339
  public static function fwrite($handle, $string)
340
  {
341
  $bytes_written = @fwrite($handle, $string);
342
 
343
+ if ($bytes_written != strlen($string)) {
344
  throw new Exception('Error writing to file.');
345
  } else {
346
  return $bytes_written;
347
  }
348
  }
349
 
350
+ /**
351
+ * wrinte file in chunk mode. For big data.
352
+ * @param resource $handle
353
+ * @param string $content
354
+ * @return int
355
+ * @throws Exception
356
+ */
357
+ public static function fwriteChunked($handle, $content)
358
+ {
359
+ $pieces = str_split($content, self::FWRITE_CHUNK_SIZE);
360
+ $written = 0;
361
+
362
+ foreach ($pieces as $piece) {
363
+ if (($fwResult = @fwrite($handle, $piece, self::FWRITE_CHUNK_SIZE)) === false) {
364
+ throw new Exception('Error writing to file.');
365
+ }
366
+ $written += $fwResult;
367
+ }
368
+
369
+ if ($written != strlen($content)) {
370
+ throw new Exception('Error writing to file.');
371
+ }
372
+
373
+ return $written;
374
+ }
375
+
376
  public static function fgets($handle, $length)
377
  {
378
  $line = fgets($handle, $length);
403
  $position = @ftell($file_handle);
404
 
405
  if ($position === false) {
406
+ throw new Exception("Couldn't retrieve file offset.");
407
  } else {
408
  return $position;
409
  }
410
  }
411
 
412
  /**
413
+ * Safely remove a directory and recursively files and directory upto multiple sublevels
414
  *
415
  * @param path $dir The full path to the directory to remove
416
  *
560
 
561
  if (is_int($mode)) {
562
  $octalMode = $mode;
563
+ } else if (is_numeric($mode)) {
564
+ $octalMode = intval((($mode[0] === '0' ? '' : '0').$mode), 8);
565
+ } else if (is_string($mode) && preg_match_all('/(a|[ugo]{1,3})([-=+])([rwx]{1,3})/', $mode, $gMatch, PREG_SET_ORDER)) {
566
+ if (!function_exists('fileperms')) {
567
+ return false;
568
+ }
 
 
569
 
570
+ // start by file permission
571
+ $octalMode = (fileperms($file) & 0777);
572
 
573
+ foreach ($gMatch as $matches) {
574
+ // [ugo] or a = ugo
575
+ $group = $matches[1];
576
+ if ($group === 'a') {
577
+ $group = 'ugo';
578
+ }
579
+ // can be + - =
580
+ $action = $matches[2];
581
+ // [rwx]
582
+ $gPerms = $matches[3];
583
+
584
+ // reset octal group perms
585
+ $octalGroupMode = 0;
586
+
587
+ // Init sub perms
588
+ $subPerm = 0;
589
+ $subPerm += strpos($gPerms, 'x') !== false ? 1 : 0; // mask 001
590
+ $subPerm += strpos($gPerms, 'w') !== false ? 2 : 0; // mask 010
591
+ $subPerm += strpos($gPerms, 'r') !== false ? 4 : 0; // mask 100
592
+
593
+ $ugoLen = strlen($group);
594
+
595
+ if ($action === '=') {
596
+ // generate octal group permsissions and ugo mask invert
597
+ $ugoMaskInvert = 0777;
598
+ for ($i = 0; $i < $ugoLen; $i++) {
599
+ switch ($group[$i]) {
600
+ case 'u':
601
+ $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
602
+ $ugoMaskInvert = $ugoMaskInvert & 077;
603
+ break;
604
+ case 'g':
605
+ $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
606
+ $ugoMaskInvert = $ugoMaskInvert & 0707;
607
+ break;
608
+ case 'o':
609
+ $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
610
+ $ugoMaskInvert = $ugoMaskInvert & 0770;
611
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
  }
613
+ }
614
+ // apply = action
615
+ $octalMode = $octalMode & ($ugoMaskInvert | $octalGroupMode);
616
+ } else {
617
+ // generate octal group permsissions
618
+ for ($i = 0; $i < $ugoLen; $i++) {
619
+ switch ($group[$i]) {
620
+ case 'u':
621
+ $octalGroupMode = $octalGroupMode | $subPerm << 6; // mask xxx000000
622
+ break;
623
+ case 'g':
624
+ $octalGroupMode = $octalGroupMode | $subPerm << 3; // mask 000xxx000
625
  break;
626
+ case 'o':
627
+ $octalGroupMode = $octalGroupMode | $subPerm; // mask 000000xxx
628
  break;
629
  }
630
  }
631
+ // apply + or - action
632
+ switch ($action) {
633
+ case '+':
634
+ $octalMode = $octalMode | $octalGroupMode;
635
+ break;
636
+ case '-':
637
+ $octalMode = $octalMode & ~$octalGroupMode;
638
+ break;
639
+ }
640
  }
641
  }
642
+ } else {
643
+ return true;
644
  }
645
 
646
  // if input permissions are equal at file permissions return true without performing chmod
655
  return @chmod($file, $octalMode);
656
  }
657
 
658
+ /**
659
+ * return file perms in string
660
+ *
661
+ * @param int|string $perms
662
+ * @return string|bool // false if fail
663
+ */
664
+ public static function permsToString($perms)
665
+ {
666
+ if (is_int($perms)) {
667
+ return decoct($perms);
668
+ } else if (is_numeric($perms)) {
669
+ return ($perms[0] === '0' ? '' : '0').$perms;
670
+ } else if (is_string($perms)) {
671
+ return $perms;
672
+ } else {
673
+ false;
674
+ }
675
+ }
676
+
677
  /**
678
  * this function creates a folder if it does not exist and performs a chmod.
679
  * it is different from the normal mkdir function to which an umask is applied to the input permissions.
687
  * @param string $path
688
  * @param int|string $mode
689
  * @param bool $recursive
690
+ * @param resource $context // not used fo windows bug
691
  * @return boolean bool TRUE on success or FALSE on failure.
692
  *
693
  * @todo check recursive true and multiple chmod
831
  */
832
  public static function getRelativePath($path, $mainPath)
833
  {
834
+ if (strlen($mainPath) == 0) {
835
+ return ltrim(self::safePathUntrailingslashit($path), '/');
836
+ }
837
+
838
  $safePath = self::safePathUntrailingslashit($path);
839
  $safeMainPath = self::safePathUntrailingslashit($mainPath);
840
 
841
+ if ($safePath === $safeMainPath) {
842
+ return '';
843
+ } else if (strpos($safePath, self::trailingslashit($safeMainPath)) === 0) {
844
  return ltrim(substr($safePath, strlen($safeMainPath)), '/');
845
  } else {
846
  return false;
934
  return preg_replace('/^(?:[A-Za-z]:)?[\/](.*)/', '$1', $path);
935
  }
936
 
937
+ /**
938
+ * Returns the last N lines of a file. Simular to tail command
939
+ *
940
+ * @param string $filepath The full path to the file to be tailed
941
+ * @param int $lines The number of lines to return with each tail call
942
+ *
943
+ * @return string The last N parts of the file
944
+ */
945
+ public static function tailFile($filepath, $lines = 2)
946
+ {
947
+ // Open file
948
+ $f = @fopen($filepath, "rb");
949
+ if ($f === false)
950
+ return false;
951
+
952
+ // Sets buffer size
953
+ $buffer = 256;
954
+
955
+ // Jump to last character
956
+ fseek($f, -1, SEEK_END);
957
+
958
+ // Read it and adjust line number if necessary
959
+ // (Otherwise the result would be wrong if file doesn't end with a blank line)
960
+ if (fread($f, 1) != "\n")
961
+ $lines -= 1;
962
+
963
+ // Start reading
964
+ $output = '';
965
+ $chunk = '';
966
+
967
+ // While we would like more
968
+ while (ftell($f) > 0 && $lines >= 0) {
969
+ // Figure out how far back we should jump
970
+ $seek = min(ftell($f), $buffer);
971
+ // Do the jump (backwards, relative to where we are)
972
+ fseek($f, -$seek, SEEK_CUR);
973
+ // Read a chunk and prepend it to our output
974
+ $output = ($chunk = fread($f, $seek)).$output;
975
+ // Jump back to where we started reading
976
+ fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);
977
+ // Decrease our line counter
978
+ $lines -= substr_count($chunk, "\n");
979
+ }
980
+
981
+ // While we have too many lines
982
+ // (Because of buffer size we might have read too many)
983
+ while ($lines++ < 0) {
984
+ // Find first newline and remove all text before that
985
+ $output = substr($output, strpos($output, "\n") + 1);
986
+ }
987
+ fclose($f);
988
+ return trim($output);
989
+ }
990
+
991
  /**
992
  * @param string $path Path to the file
993
  * @param int $n Number of lines to get
1038
  return array_reverse($result);
1039
  }
1040
 
1041
+ /**
1042
+ * return a list of paths
1043
+ *
1044
+ * @param string $dir
1045
+ * @param callable $callback
1046
+ * @param array $options // array(
1047
+ * 'regexFile' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
1048
+ * 'regexFolder' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
1049
+ * 'checkFullPath' => bool, // if false only current file/folder name is passed at regex if true is passed the full path
1050
+ * 'recursive' => bool, // if false check only passed folder or all sub folder recursively
1051
+ * 'invert' => bool, // if false pass invert the result
1052
+ * 'childFirst' => bool // if false is parsed parent folters first or child folders first
1053
+ * )
1054
+ *
1055
+ * @return boolean
1056
+ */
1057
+ public static function regexGlob($dir, $options)
1058
+ {
1059
+ $result = array();
1060
+
1061
+ self::regexGlobCallback($dir, function ($path) use (&$result) {
1062
+ $result[] = $path;
1063
+ }, $options);
1064
+
1065
+ return $result;
1066
+ }
1067
+
1068
+ /**
1069
+ * execute the callback function foreach right element, private function for optimization
1070
+ *
1071
+ * @param string $dir
1072
+ * @param callable $callback
1073
+ * @param array $options // array(
1074
+ * 'regexFile' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
1075
+ * 'regexFolder' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
1076
+ * 'checkFullPath' => bool, // if false only current file/folder name is passed at regex if true is passed the full path
1077
+ * 'recursive' => bool, // if false check only passed folder or all sub folder recursively
1078
+ * 'invert' => bool, // if false pass invert the result
1079
+ * 'childFirst' => bool // if false is parsed parent folters first or child folders first
1080
+ * )
1081
+ *
1082
+ * @return boolean
1083
+ */
1084
+ protected static function regexGlobCallbackPrivate($dir, $callback, $options)
1085
+ {
1086
+ if (!is_dir($dir) || !is_readable($dir)) {
1087
+ return false;
1088
+ }
1089
+
1090
+ if (($dh = opendir($dir)) == false) {
1091
+ return false;
1092
+ }
1093
+
1094
+ $trailingslashitDir = self::trailingslashit($dir);
1095
+
1096
+ while (($elem = readdir($dh)) !== false) {
1097
+ if ($elem === '.' || $elem === '..') {
1098
+ continue;
1099
+ }
1100
+
1101
+ $fullPath = $trailingslashitDir.$elem;
1102
+ $regex = is_dir($fullPath) ? $options['regexFolder'] : $options['regexFile'];
1103
+ $pathCheck = $options['checkFullPath'] ? $fullPath : $elem;
1104
+
1105
+ if (is_bool($regex)) {
1106
+ $match = ($regex xor $options['invert']);
1107
+ } else {
1108
+ $match = false;
1109
+ foreach ($regex as $currentRegex) {
1110
+ if (preg_match($currentRegex, $pathCheck) === 1) {
1111
+ $match = true;
1112
+ break;
1113
+ }
1114
+ }
1115
+
1116
+ if ($options['invert']) {
1117
+ $match = !$match;
1118
+ }
1119
+ }
1120
+
1121
+ if ($match) {
1122
+ if ($options['recursive'] && $options['childFirst'] === true && is_dir($fullPath)) {
1123
+ self::regexGlobCallbackPrivate($fullPath, $callback, $options);
1124
+ }
1125
+
1126
+ call_user_func($callback, $fullPath);
1127
+
1128
+ if ($options['recursive'] && $options['childFirst'] === false && is_dir($fullPath)) {
1129
+ self::regexGlobCallbackPrivate($fullPath, $callback, $options);
1130
+ }
1131
+ }
1132
+ }
1133
+ closedir($dh);
1134
+
1135
+ return true;
1136
+ }
1137
+
1138
+ /**
1139
+ * execute the callback function foreach right element (folder or files)
1140
+ *
1141
+ * @param string $dir
1142
+ * @param callable $callback
1143
+ * @param array $options // array(
1144
+ * 'regexFile' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
1145
+ * 'regexFolder' => [bool|string|array], // if is bool alrays or never match, if is string o array of string check if rexeses match file name
1146
+ * 'checkFullPath' => bool, // if false only current file/folder name is passed at regex if true is passed the full path
1147
+ * 'recursive' => bool, // if false check only passed folder or all sub folder recursively
1148
+ * 'invert' => bool, // if false pass invert the result
1149
+ * 'childFirst' => bool // if false is parsed parent folters first or child folders first
1150
+ * )
1151
+ *
1152
+ * @return boolean
1153
+ */
1154
+ public static function regexGlobCallback($dir, $callback, $options = array())
1155
+ {
1156
+ if (!is_callable($callback)) {
1157
+ return false;
1158
+ }
1159
+
1160
+ $options = array_merge(array(
1161
+ 'regexFile' => true,
1162
+ 'regexFolder' => true,
1163
+ 'checkFullPath' => false,
1164
+ 'recursive' => false,
1165
+ 'invert' => false,
1166
+ 'childFirst' => false
1167
+ ), (array) $options);
1168
+
1169
+ if (is_scalar($options['regexFile']) && !is_bool($options['regexFile'])) {
1170
+ $options['regexFile'] = array($options['regexFile']);
1171
+ }
1172
+
1173
+ if (is_scalar($options['regexFolder']) && !is_bool($options['regexFolder'])) {
1174
+ $options['regexFolder'] = array($options['regexFolder']);
1175
+ }
1176
+
1177
+ return self::regexGlobCallbackPrivate(self::safePath($dir), $callback, $options);
1178
+ }
1179
+
1180
+ public static function emptyDir($dir)
1181
+ {
1182
+ $dir = self::safePathTrailingslashit($dir);
1183
+ if (!is_dir($dir) || !is_readable($dir)) {
1184
+ return false;
1185
+ }
1186
+
1187
+ if (($dh = opendir($dir)) == false) {
1188
+ return false;
1189
+ }
1190
+
1191
+ $listToDelete = array();
1192
+
1193
+ while (($elem = readdir($dh)) !== false) {
1194
+ if ($elem === '.' || $elem === '..') {
1195
+ continue;
1196
+ }
1197
+
1198
+ $fullPath = $dir.$elem;
1199
+ if (is_writable($fullPath)) {
1200
+ $listToDelete[] = $fullPath;
1201
+ }
1202
+ }
1203
+ closedir($dh);
1204
+
1205
+ foreach ($listToDelete as $path) {
1206
+ self::rrmdir($path);
1207
+ }
1208
+ return true;
1209
+ }
1210
+
1211
  /**
1212
  * Returns a path to the base root folder of path taking into account the
1213
  * open_basedir setting.
lib/snaplib/class.snaplib.u.json.php CHANGED
@@ -89,15 +89,6 @@ if (!class_exists('DupLiteSnapJsonU', false)) {
89
  return call_user_func_array('json_encode', $args);
90
  }
91
 
92
- /**
93
- * @param mixed $val object to be encoded
94
- * @return string escaped json string
95
- */
96
- public static function json_encode_esc_attr($val)
97
- {
98
- return esc_attr(json_encode($val));
99
- }
100
-
101
  /**
102
  * wp_json_encode with pretty print if define exists
103
  *
@@ -291,5 +282,30 @@ if (!class_exists('DupLiteSnapJsonU', false)) {
291
 
292
  return '';
293
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  }
295
  }
89
  return call_user_func_array('json_encode', $args);
90
  }
91
 
 
 
 
 
 
 
 
 
 
92
  /**
93
  * wp_json_encode with pretty print if define exists
94
  *
282
 
283
  return '';
284
  }
285
+
286
+ /**
287
+ * @param mixed $val object to be encoded
288
+ * @return string escaped json string
289
+ */
290
+ public static function json_encode_esc_attr($val)
291
+ {
292
+ return esc_attr(json_encode($val));
293
+ }
294
+
295
+ /**
296
+ * this function return a json encoded string without quotes at the beginning and the end
297
+ *
298
+ * @param string $string
299
+ * @return string
300
+ * @throws Exception
301
+ */
302
+ public static function getJsonWithoutQuotes($string)
303
+ {
304
+ if (!is_string($string)) {
305
+ throw new Exception('the function getJsonStringWithoutQuotes take only strings');
306
+ }
307
+
308
+ return substr(self::wp_json_encode($string), 1, -1);
309
+ }
310
  }
311
  }
lib/snaplib/class.snaplib.u.orig.files.manager.php ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Original installer files manager
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2 Full Documentation
7
+ *
8
+ * @package SC\DUPX\U
9
+ *
10
+ */
11
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
12
+
13
+ if (!class_exists('DupLiteSnapLibOrigFileManager', false)) {
14
+
15
+ /**
16
+ * Original installer files manager
17
+ *
18
+ * This class saves a file or folder in the original files folder and saves the original location persistent.
19
+ * By entry we mean a file or a folder but not the files contained within it.
20
+ * In this way it is possible, for example, to move an entire plugin to restore it later.
21
+ *
22
+ */
23
+ class DupLiteSnapLibOrigFileManager
24
+ {
25
+
26
+ const MODE_MOVE = 'move';
27
+ const MODE_COPY = 'copy';
28
+ const ORIG_FOLDER_PREFIX = 'original_files_';
29
+ const PERSISTANCE_FILE_NAME = 'entries_stored.json';
30
+
31
+ /**
32
+ *
33
+ * @var string
34
+ */
35
+ protected $persistanceFile = null;
36
+
37
+ /**
38
+ *
39
+ * @var string
40
+ */
41
+ protected $origFilesFolder = null;
42
+
43
+ /**
44
+ *
45
+ * @var array
46
+ */
47
+ protected $origFolderEntries = array();
48
+
49
+ /**
50
+ *
51
+ * @var string
52
+ */
53
+ protected $rootPath = null;
54
+
55
+ public function __construct($root, $origFolderParentPath, $hash)
56
+ {
57
+ $this->rootPath = DupLiteSnapLibIOU::safePathUntrailingslashit($root, true);
58
+ $this->origFilesFolder = DupLiteSnapLibIOU::safePathTrailingslashit($origFolderParentPath, true).self::ORIG_FOLDER_PREFIX.$hash;
59
+ $this->persistanceFile = $this->origFilesFolder.'/'.self::PERSISTANCE_FILE_NAME;
60
+ }
61
+
62
+ /**
63
+ * create a main folder if don't exist and load the entries
64
+ *
65
+ * @param boolen $reset
66
+ */
67
+ public function init($reset = false)
68
+ {
69
+ $this->createMainFolder($reset);
70
+ $this->load();
71
+ }
72
+
73
+ /**
74
+ *
75
+ * @param boolean $reset // if true delete current folder
76
+ * @return boolean // return true if succeded
77
+ * @throws Exception
78
+ */
79
+ public function createMainFolder($reset = false)
80
+ {
81
+ if ($reset) {
82
+ $this->deleteMainFolder();
83
+ }
84
+
85
+ if (!file_exists($this->origFilesFolder)) {
86
+ if (!DupLiteSnapLibIOU::mkdir($this->origFilesFolder, 'u+rwx')) {
87
+ throw new Exception('Can\'t create the original files folder '.DupLiteSnapLibLogger::varToString($this->origFilesFolder));
88
+ }
89
+ }
90
+
91
+ $htaccessFile = $this->origFilesFolder.'/.htaccess';
92
+ if (!file_exists($htaccessFile)) {
93
+ $htfile = @fopen($htaccessFile, 'w');
94
+ $content = <<<HTACCESS
95
+ Order Allow,Deny
96
+ Deny from All
97
+ HTACCESS;
98
+ @fwrite($htfile, $content);
99
+ @fclose($htfile);
100
+ }
101
+
102
+ if (!file_exists($this->persistanceFile)) {
103
+ $this->save();
104
+ }
105
+
106
+ return true;
107
+ }
108
+
109
+ /**
110
+ * @return string Main folder path
111
+ * @throws Exception
112
+ */
113
+ public function getMainFolder()
114
+ {
115
+ if (!file_exists($this->origFilesFolder)) {
116
+ throw new Exception('Can\'t get the original files folder '.DupLiteSnapLibLogger::varToString($this->origFilesFolder));
117
+ }
118
+
119
+ return $this->origFilesFolder;
120
+ }
121
+
122
+ /**
123
+ * delete origianl files folder
124
+ *
125
+ * @return boolean
126
+ * @throws Exception
127
+ */
128
+ public function deleteMainFolder()
129
+ {
130
+ if (file_exists($this->origFilesFolder) && !DupLiteSnapLibIOU::rrmdir($this->origFilesFolder)) {
131
+ throw new Exception('Can\'t delete the original files folder '.DupLiteSnapLibLogger::varToString($this->origFilesFolder));
132
+ }
133
+ $this->origFolderEntries = array();
134
+
135
+ return true;
136
+ }
137
+
138
+ /**
139
+ * add a entry on original folder.
140
+ *
141
+ * @param string $identifier // entry identifier
142
+ * @param string $path // entry path. can be a file or a folder
143
+ * @param string $mode // MODE_MOVE move the item in original folder
144
+ * MODE_COPY copy the item in original folder
145
+ * @param bool|string $rename // if rename is a string the item is renamed in original folder.
146
+ * @return boolean // true if succeded
147
+ * @throws Exception
148
+ */
149
+ public function addEntry($identifier, $path, $mode = self::MODE_MOVE, $rename = false)
150
+ {
151
+ if (!file_exists($path)) {
152
+ return false;
153
+ }
154
+
155
+ $baseName = empty($rename) ? basename($path) : $rename;
156
+
157
+ if (($relativePath = DupLiteSnapLibIOU::getRelativePath($path, $this->rootPath)) === false) {
158
+ $isRelative = false;
159
+ } else {
160
+ $isRelative = true;
161
+ }
162
+ $parentFolder = $isRelative ? dirname($relativePath) : DupLiteSnapLibIOU::removeRootPath(dirname($path));
163
+ if (empty($parentFolder) || $parentFolder === '.') {
164
+ $parentFolder = '';
165
+ } else {
166
+ $parentFolder .= '/';
167
+ }
168
+ $targetFolder = $this->origFilesFolder.'/'.$parentFolder;
169
+ if (!file_exists($targetFolder)) {
170
+ DupLiteSnapLibIOU::mkdir_p($targetFolder);
171
+ }
172
+ $dest = $targetFolder.$baseName;
173
+
174
+ switch ($mode) {
175
+ case self::MODE_MOVE:
176
+ if (!DupLiteSnapLibIOU::rename($path, $dest)) {
177
+ throw new Exception('Can\'t move the original file '.DupLiteSnapLibLogger::varToString($path));
178
+ }
179
+ break;
180
+ case self::MODE_COPY:
181
+ if (!DupLiteSnapLibIOU::rcopy($path, $dest)) {
182
+ throw new Exception('Can\'t copy the original file '.DupLiteSnapLibLogger::varToString($path));
183
+ }
184
+ break;
185
+ default:
186
+ throw new Exception('invalid mode addEntry');
187
+ }
188
+
189
+ $this->origFolderEntries[$identifier] = array(
190
+ 'baseName' => $baseName,
191
+ 'source' => $isRelative ? $relativePath : $path,
192
+ 'stored' => $parentFolder.$baseName,
193
+ 'mode' => $mode,
194
+ 'isRelative' => $isRelative
195
+ );
196
+
197
+ $this->save();
198
+ return true;
199
+ }
200
+
201
+ /**
202
+ * get entry info from itendifier
203
+ *
204
+ * @param string $identifier
205
+ * @return boolean // false if entry don't exists
206
+ */
207
+ public function getEntry($identifier)
208
+ {
209
+ if (isset($this->origFolderEntries[$identifier])) {
210
+ return $this->origFolderEntries[$identifier];
211
+ } else {
212
+ return false;
213
+ }
214
+ }
215
+
216
+ /**
217
+ * get entry stored path in original folder
218
+ *
219
+ * @param string $identifier
220
+ * @return boolean // false if entry don't exists
221
+ */
222
+ public function getEntryStoredPath($identifier)
223
+ {
224
+ if (isset($this->origFolderEntries[$identifier])) {
225
+ return $this->origFilesFolder.'/'.$this->origFolderEntries[$identifier]['stored'];
226
+ } else {
227
+ return false;
228
+ }
229
+ }
230
+
231
+ public function isRelative($identifier)
232
+ {
233
+ if (isset($this->origFolderEntries[$identifier])) {
234
+ $this->origFolderEntries[$identifier]['isRelative'];
235
+ } else {
236
+ return false;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * get entry target restore path
242
+ *
243
+ * @param string $identifier
244
+ * @param type $defaultIfIsAbsolute
245
+ * @return boolean // false if entry don't exists
246
+ */
247
+ public function getEntryTargetPath($identifier, $defaultIfIsAbsolute = null)
248
+ {
249
+ if (isset($this->origFolderEntries[$identifier])) {
250
+ if ($this->origFolderEntries[$identifier]['isRelative']) {
251
+ return $this->rootPath.'/'.$this->origFolderEntries[$identifier]['source'];
252
+ } else {
253
+ if (is_null($defaultIfIsAbsolute)) {
254
+ return $this->origFolderEntries[$identifier]['source'];
255
+ } else {
256
+ return $defaultIfIsAbsolute;
257
+ }
258
+ }
259
+ } else {
260
+ return false;
261
+ }
262
+ }
263
+
264
+ /**
265
+ * this function restore current entry in original position.
266
+ * If mode is copy it simply delete the entry else move the entry in original position
267
+ *
268
+ * @param string $identifier // identified of current entrye
269
+ * @param boolean $save // update saved entries
270
+ * @return boolean // true if succeded
271
+ * @throws Exception
272
+ */
273
+ public function restoreEntry($identifier, $save = true, $defaultIfIsntRelative = null)
274
+ {
275
+ if (!isset($this->origFolderEntries[$identifier])) {
276
+ return false;
277
+ }
278
+
279
+ $stored = $this->getEntryStoredPath($identifier);
280
+ if (($original = $this->getEntryTargetPath($identifier, $defaultIfIsntRelative)) === false) {
281
+ return false;
282
+ }
283
+
284
+ switch ($this->origFolderEntries[$identifier]['mode']) {
285
+ case self::MODE_MOVE:
286
+ if (!DupLiteSnapLibIOU::rename($stored, $original)) {
287
+ throw new Exception('Can\'t move the original file '.DupLiteSnapLibLogger::varToString($stored));
288
+ }
289
+ break;
290
+ case self::MODE_COPY:
291
+ if (!DupLiteSnapLibIOU::rrmdir($stored)) {
292
+ throw new Exception('Can\'t delete entry '.DupLiteSnapLibLogger::varToString($stored));
293
+ }
294
+ break;
295
+ default:
296
+ throw new Exception('invalid mode addEntry');
297
+ }
298
+
299
+ unset($this->origFolderEntries[$identifier]);
300
+ if ($save) {
301
+ $this->save();
302
+ }
303
+ return true;
304
+ }
305
+
306
+ /**
307
+ * put all entries on original position and empty original folder
308
+ *
309
+ * @return boolean
310
+ */
311
+ public function restoreAll($exclude = array())
312
+ {
313
+ foreach (array_keys($this->origFolderEntries) as $ident) {
314
+ if (in_array($ident, $exclude)) {
315
+ continue;
316
+ }
317
+ $this->restoreEntry($ident, false);
318
+ }
319
+ $this->save();
320
+ return true;
321
+ }
322
+
323
+ /**
324
+ * save notices from json file
325
+ */
326
+ public function save()
327
+ {
328
+ if (!file_put_contents($this->persistanceFile, DupLiteSnapJsonU::wp_json_encode_pprint($this->origFolderEntries))) {
329
+ throw new Exception('Can\'t write persistence file');
330
+ }
331
+ return true;
332
+ }
333
+
334
+ /**
335
+ * load notice from json file
336
+ */
337
+ private function load()
338
+ {
339
+ if (file_exists($this->persistanceFile)) {
340
+ $json = file_get_contents($this->persistanceFile);
341
+ $this->origFolderEntries = json_decode($json, true);
342
+ } else {
343
+ $this->origFolderEntries = array();
344
+ }
345
+ return true;
346
+ }
347
+ }
348
+ }
lib/snaplib/class.snaplib.u.os.php CHANGED
@@ -22,7 +22,7 @@ if (!class_exists('DupLiteSnapLibOSU', false)) {
22
 
23
  /**
24
  * return true if current SO is windows
25
- *
26
  * @staticvar bool $isWindows
27
  * @return bool
28
  */
@@ -35,6 +35,15 @@ if (!class_exists('DupLiteSnapLibOSU', false)) {
35
  return $isWindows;
36
  }
37
 
 
 
 
 
 
 
 
 
 
38
  /**
39
  * return current SO path path len
40
  * @staticvar int $maxPath
@@ -54,4 +63,4 @@ if (!class_exists('DupLiteSnapLibOSU', false)) {
54
  return $maxPath;
55
  }
56
  }
57
- }
22
 
23
  /**
24
  * return true if current SO is windows
25
+ *
26
  * @staticvar bool $isWindows
27
  * @return bool
28
  */
35
  return $isWindows;
36
  }
37
 
38
+ public static function isOSX()
39
+ {
40
+ static $isOSX = null;
41
+ if (is_null($isOSX)) {
42
+ $isOSX = (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
43
+ }
44
+ return $isOSX;
45
+ }
46
+
47
  /**
48
  * return current SO path path len
49
  * @staticvar int $maxPath
63
  return $maxPath;
64
  }
65
  }
66
+ }
lib/snaplib/class.snaplib.u.string.php CHANGED
@@ -115,5 +115,15 @@ if (!class_exists('DupLiteSnapLibStringU', false)) {
115
  }
116
  return $str;
117
  }
 
 
 
 
 
 
 
 
 
 
118
  }
119
- }
115
  }
116
  return $str;
117
  }
118
+
119
+ /**
120
+ *
121
+ * @param string $string
122
+ * @return boolean
123
+ */
124
+ public static function isHTML($string)
125
+ {
126
+ return ($string != strip_tags($string));
127
+ }
128
  }
129
+ }
lib/snaplib/class.snaplib.u.url.php CHANGED
@@ -17,6 +17,18 @@ if (!class_exists('DupLiteSnapLibURLU', false)) {
17
  class DupLiteSnapLibURLU
18
  {
19
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  /**
21
  * Append a new query value to the end of a URL
22
  *
@@ -34,32 +46,137 @@ if (!class_exists('DupLiteSnapLibURLU', false)) {
34
  return $modified_url;
35
  }
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  /**
38
  * Fetches current URL via php
39
  *
40
  * @param bool $queryString If true the query string will also be returned.
 
41
  *
42
  * @returns The current page url
43
  */
44
- public static function getCurrentUrl($queryString = true)
45
  {
46
- $protocol = 'http';
 
 
 
 
 
 
 
47
  if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
48
  $_SERVER ['HTTPS'] = 'on';
49
  }
50
- if ($_SERVER['SERVER_PORT'] == 443 || (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')) {
51
- $protocol .= 's';
52
- $protocolPort = $_SERVER['SERVER_PORT'];
 
 
 
 
 
 
 
 
 
 
53
  } else {
54
- $protocolPort = 80;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  }
56
- $host = $_SERVER['HTTP_HOST'];
57
- $port = $_SERVER['SERVER_PORT'];
58
- $request = $_SERVER['SCRIPT_NAME'];
59
 
60
- $query = ($queryString === TRUE) ? $_SERVER['QUERY_STRING'] : "";
61
- $url = $protocol.'://'.$host.($port == $protocolPort ? '' : ':'.$port).$request.(empty($query) ? '' : '?'.$query);
62
- return $url;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
64
  }
65
- }
17
  class DupLiteSnapLibURLU
18
  {
19
 
20
+ protected static $DEF_ARRAY_PARSE_URL = array(
21
+ 'scheme' => false,
22
+ 'host' => false,
23
+ 'port' => false,
24
+ 'user' => false,
25
+ 'pass' => false,
26
+ 'path' => '',
27
+ 'scheme' => false,
28
+ 'query' => false,
29
+ 'fragment' => false
30
+ );
31
+
32
  /**
33
  * Append a new query value to the end of a URL
34
  *
46
  return $modified_url;
47
  }
48
 
49
+ /**
50
+ * add www. in url if don't have
51
+ *
52
+ * @param string $url
53
+ * @return string
54
+ */
55
+ public static function wwwAdd($url)
56
+ {
57
+ return preg_replace('/^((?:\w+\:)?\/\/)(?!www\.)(.+)/', '$1www.$2', $url);
58
+ }
59
+
60
+ /**
61
+ * remove www. in url if don't have
62
+ *
63
+ * @param string $url
64
+ * @return string
65
+ */
66
+ public static function wwwRemove($url)
67
+ {
68
+ return preg_replace('/^((?:\w+\:)?\/\/)www\.(.+)/', '$1$2', $url);
69
+ }
70
+
71
  /**
72
  * Fetches current URL via php
73
  *
74
  * @param bool $queryString If true the query string will also be returned.
75
+ * @param int $getParentDirLevel if 0 get current script name or parent folder, if 1 parent folder if 2 parent of parent folder ...
76
  *
77
  * @returns The current page url
78
  */
79
+ public static function getCurrentUrl($queryString = true, $requestUri = false, $getParentDirLevel = 0)
80
  {
81
+ // *** HOST
82
+ if (isset($_SERVER['HTTP_X_ORIGINAL_HOST'])) {
83
+ $host = $_SERVER['HTTP_X_ORIGINAL_HOST'];
84
+ } else {
85
+ $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']; //WAS SERVER_NAME and caused problems on some boxes
86
+ }
87
+
88
+ // *** PROTOCOL
89
  if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
90
  $_SERVER ['HTTPS'] = 'on';
91
  }
92
+ if (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'https') {
93
+ $_SERVER ['HTTPS'] = 'on';
94
+ }
95
+ if (isset($_SERVER['HTTP_CF_VISITOR'])) {
96
+ $visitor = json_decode($_SERVER['HTTP_CF_VISITOR']);
97
+ if ($visitor->scheme == 'https') {
98
+ $_SERVER ['HTTPS'] = 'on';
99
+ }
100
+ }
101
+ $protocol = 'http'.((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on') ? 's' : '');
102
+
103
+ if ($requestUri) {
104
+ $serverUrlSelf = preg_replace('/\?.*$/', '', $_SERVER['REQUEST_URI']);
105
  } else {
106
+ // *** SCRIPT NAME
107
+ $serverUrlSelf = $_SERVER['SCRIPT_NAME'];
108
+ for ($i = 0; $i < $getParentDirLevel; $i++) {
109
+ $serverUrlSelf = preg_match('/^[\\\\\/]?$/', dirname($serverUrlSelf)) ? '' : dirname($serverUrlSelf);
110
+ }
111
+ }
112
+
113
+ // *** QUERY STRING
114
+ $query = ($queryString && isset($_SERVER['QUERY_STRING']) && strlen($_SERVER['QUERY_STRING']) > 0 ) ? '?'.$_SERVER['QUERY_STRING'] : '';
115
+
116
+ return $protocol.'://'.$host.$serverUrlSelf.$query;
117
+ }
118
+
119
+ /**
120
+ * this function is a native PHP parse_url wrapper
121
+ * this function returns an associative array with all the keys present and the values = false if they do not exist.
122
+ *
123
+ * @param string $url <p>The URL to parse. Invalid characters are replaced by <i>_</i>.</p>
124
+ * @param int $component
125
+ * @return mixed <p>On seriously malformed URLs, <b>parse_url()</b> may return <b><code>FALSE</code></b>.</p><p>If the <code>component</code> parameter is omitted, an associative <code>array</code> is returned. At least one element will be present within the array. Potential keys within this array are:</p><ul> <li> scheme - e.g. http </li> <li> host </li> <li> port </li> <li> user </li> <li> pass </li> <li> path </li> <li> query - after the question mark <i>&#63;</i> </li> <li> fragment - after the hashmark <i>#</i> </li> </ul><p>If the <code>component</code> parameter is specified, <b>parse_url()</b> returns a <code>string</code> (or an <code>integer</code>, in the case of <b><code>PHP_URL_PORT</code></b>) instead of an <code>array</code>. If the requested component doesn't exist within the given URL, <b><code>NULL</code></b> will be returned.</p>
126
+ */
127
+ public static function parseUrl($url, $component = -1)
128
+ {
129
+ $result = parse_url($url, $component);
130
+ if (is_array($result)) {
131
+ $result = array_merge(self::$DEF_ARRAY_PARSE_URL, $result);
132
  }
 
 
 
133
 
134
+ return $result;
135
+ }
136
+
137
+ /**
138
+ * this function build a url from array result of parse url.
139
+ * if work with both parse_url native function result and snap parseUrl result
140
+ *
141
+ * @param array $parts
142
+ * @return bool|string return false if param isn't array
143
+ */
144
+ public static function buildUrl($parts)
145
+ {
146
+ if (!is_array($parts)) {
147
+ return false;
148
+ }
149
+
150
+ $result = '';
151
+ $result .= (isset($parts['scheme']) && $parts['scheme'] !== false) ? $parts['scheme'].':' : '';
152
+ $result .= (
153
+ (isset($parts['user']) && $parts['user'] !== false) ||
154
+ (isset($parts['host']) && $parts['host'] !== false)) ? '//' : '';
155
+
156
+ $result .= (isset($parts['user']) && $parts['user'] !== false) ? $parts['user'] : '';
157
+ $result .= (isset($parts['pass']) && $parts['pass'] !== false) ? ':'.$parts['pass'] : '';
158
+ $result .= (isset($parts['user']) && $parts['user'] !== false) ? '@' : '';
159
+
160
+ $result .= (isset($parts['host']) && $parts['host'] !== false) ? $parts['host'] : '';
161
+ $result .= (isset($parts['port']) && $parts['port'] !== false) ? ':'.$parts['port'] : '';
162
+
163
+ $result .= (isset($parts['path']) && $parts['path'] !== false) ? $parts['path'] : '';
164
+ $result .= (isset($parts['query']) && $parts['query'] !== false) ? '?'.$parts['query'] : '';
165
+ $result .= (isset($parts['fragment']) && $parts['fragment'] !== false) ? '#'.$parts['fragment'] : '';
166
+
167
+ return $result;
168
+ }
169
+
170
+ /**
171
+ * encode alla chars
172
+ *
173
+ * @param string $url
174
+ * @return string
175
+ */
176
+ public static function urlEncodeAll($url)
177
+ {
178
+ $hex = unpack('H*', urldecode($url));
179
+ return preg_replace('~..~', '%$0', strtoupper($hex[1]));
180
  }
181
  }
182
+ }
lib/snaplib/class.snaplib.u.util.php CHANGED
@@ -31,13 +31,25 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
31
  }
32
  }
33
 
34
- public static function getCallingFunctionName()
 
 
 
 
 
35
  {
36
- $callers = debug_backtrace();
37
- $functionName = $callers[2]['function'];
38
- $className = isset($callers[2]['class']) ? $callers[2]['class'] : '';
 
 
 
 
 
 
 
39
 
40
- return "{$className}::{$functionName}";
41
  }
42
 
43
  public static function getWorkPercent($startingPercent, $endingPercent, $totalTaskCount, $currentTaskCount)
@@ -45,10 +57,10 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
45
  if ($totalTaskCount > 0) {
46
  $percent = $startingPercent + (($endingPercent - $startingPercent) * ($currentTaskCount / (float) $totalTaskCount));
47
  } else {
48
- $percent = 0;
49
  }
50
 
51
- return $percent;
52
  }
53
 
54
  public static function make_hash()
@@ -121,27 +133,6 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
121
  return $grouped;
122
  }
123
 
124
-
125
- /**
126
- * Implemented array_key_first
127
- *
128
- * @link https://www.php.net/manual/en/function.array-key-first.php
129
- * @param array $arr
130
- * @return int|string|null
131
- */
132
- public static function arrayKeyFirst($arr)
133
- {
134
- if (!function_exists('array_key_first')) {
135
- foreach ($arr as $key => $unused) {
136
- return $key;
137
- }
138
- return null;
139
- } else {
140
- return array_key_first($arr);
141
- }
142
- }
143
-
144
-
145
  /**
146
  * Converts human readable types (10GB) to bytes
147
  *
@@ -188,7 +179,7 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
188
  }
189
 
190
  /**
191
- * remove all non stamo chars from string
192
  *
193
  * @param string $string
194
  * @return string
@@ -197,7 +188,7 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
197
  {
198
  return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);
199
  }
200
-
201
  /**
202
  * remove all non stamp chars from string and newline
203
  * trim string
@@ -206,10 +197,10 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
206
  * @return string
207
  */
208
  public static function sanitize_non_stamp_chars_and_newline($string)
209
- {
210
  return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\r\n]/u', '', $string);
211
  }
212
-
213
  /**
214
  * remove all non stamp chars from string and newline
215
  * trim string
@@ -218,9 +209,9 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
218
  * @return string
219
  */
220
  public static function sanitize_non_stamp_chars_newline_and_trim($string)
221
- {
222
  return trim(self::sanitize_non_stamp_chars_and_newline($string));
223
- }
224
 
225
  /**
226
  * Determines whether a PHP ini value is changeable at runtime.
@@ -236,6 +227,11 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
236
  */
237
  public static function wp_is_ini_value_changeable($setting)
238
  {
 
 
 
 
 
239
  if (function_exists('wp_is_ini_value_changeable')) {
240
  return wp_is_ini_value_changeable($setting);
241
  }
@@ -276,6 +272,145 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
276
  return min((int) $max, max((int) $min, (int) $val));
277
  }
278
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  /**
280
  * Gets a specific external variable by name and optionally filters it
281
  * @param int $type <p>One of <b><code>INPUT_GET</code></b>, <b><code>INPUT_POST</code></b>, <b><code>INPUT_COOKIE</code></b>, <b><code>INPUT_SERVER</code></b>, or <b><code>INPUT_ENV</code></b>.</p>
@@ -295,5 +430,34 @@ if (!class_exists('DupLiteSnapLibUtil', false)) {
295
 
296
  return filter_input(INPUT_POST, $variable_name, $filter, $options);
297
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  }
299
  }
31
  }
32
  }
33
 
34
+ /**
35
+ * Gets the calling function name from where this method is called
36
+ *
37
+ * @return string Returns the calling function name from where this method is called
38
+ */
39
+ public static function getCallingFunctionName($backTraceBack = 0)
40
  {
41
+ $callers = debug_backtrace();
42
+ $backTraceL1 = 1 + $backTraceBack;
43
+ $backTraceL2 = 2 + $backTraceBack;
44
+ $result = '['.str_pad(basename($callers[$backTraceL1]['file']), 25, '_', STR_PAD_RIGHT).':'.str_pad($callers[$backTraceL1]['line'], 4, ' ', STR_PAD_LEFT).']';
45
+ if (isset($callers[$backTraceL2]) && (isset($callers[$backTraceL2]['class']) || isset($callers[$backTraceL2]['function']))) {
46
+ $result .= ' [';
47
+ $result .= isset($callers[$backTraceL2]['class']) ? $callers[$backTraceL2]['class'].'::' : '';
48
+ $result .= isset($callers[$backTraceL2]['function']) ? $callers[$backTraceL2]['function'] : '';
49
+ $result .= ']';
50
+ }
51
 
52
+ return str_pad($result, 80, '_', STR_PAD_RIGHT);
53
  }
54
 
55
  public static function getWorkPercent($startingPercent, $endingPercent, $totalTaskCount, $currentTaskCount)
57
  if ($totalTaskCount > 0) {
58
  $percent = $startingPercent + (($endingPercent - $startingPercent) * ($currentTaskCount / (float) $totalTaskCount));
59
  } else {
60
+ $percent = $startingPercent;
61
  }
62
 
63
+ return min(max($startingPercent, $percent), $endingPercent);
64
  }
65
 
66
  public static function make_hash()
133
  return $grouped;
134
  }
135
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  /**
137
  * Converts human readable types (10GB) to bytes
138
  *
179
  }
180
 
181
  /**
182
+ * remove all non stamp chars from string
183
  *
184
  * @param string $string
185
  * @return string
188
  {
189
  return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);
190
  }
191
+
192
  /**
193
  * remove all non stamp chars from string and newline
194
  * trim string
197
  * @return string
198
  */
199
  public static function sanitize_non_stamp_chars_and_newline($string)
200
+ {
201
  return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\r\n]/u', '', $string);
202
  }
203
+
204
  /**
205
  * remove all non stamp chars from string and newline
206
  * trim string
209
  * @return string
210
  */
211
  public static function sanitize_non_stamp_chars_newline_and_trim($string)
212
+ {
213
  return trim(self::sanitize_non_stamp_chars_and_newline($string));
214
+ }
215
 
216
  /**
217
  * Determines whether a PHP ini value is changeable at runtime.
227
  */
228
  public static function wp_is_ini_value_changeable($setting)
229
  {
230
+ // if ini_set is disabled can change the values
231
+ if (!function_exists('ini_set')) {
232
+ return false;
233
+ }
234
+
235
  if (function_exists('wp_is_ini_value_changeable')) {
236
  return wp_is_ini_value_changeable($setting);
237
  }
272
  return min((int) $max, max((int) $min, (int) $val));
273
  }
274
 
275
+ /**
276
+ * Find matching string from $strArr1 and $strArr2 until first numeric occurence
277
+ *
278
+ * @param array $strArr1 array of strings
279
+ * @param array $strArr2 array of strings
280
+ * @return string matching str which will be best for replacement
281
+ */
282
+ public static function getMatchingStrFromArrayElemsUntilFirstNumeric($strArr1, $strArr2)
283
+ {
284
+ $matchingStr = '';
285
+ $strPartialArr = array();
286
+ foreach ($strArr1 as $str1) {
287
+ $str1_str_length = strlen($str1);
288
+ $tempStr1Chars = str_split($str1);
289
+ $tempPartialStr = '';
290
+ // The flag is for whether non-numeric character passed after numeric character occurence in str1. For ex. str1 is utf8mb4, the flag wil be true when parsing m after utf8.
291
+ $numericCharPassFlag = false;
292
+ $charPositionInStr1 = 0;
293
+ while ($charPositionInStr1 < $str1_str_length) {
294
+ if ($numericCharPassFlag && !is_numeric($tempStr1Chars[$charPositionInStr1])) {
295
+ break;
296
+ }
297
+ if (is_numeric($tempStr1Chars[$charPositionInStr1])) {
298
+ $numericCharPassFlag = true;
299
+ }
300
+ $tempPartialStr .= $tempStr1Chars[$charPositionInStr1];
301
+ $charPositionInStr1++;
302
+ }
303
+ $strPartialArr[] = $tempPartialStr;
304
+ }
305
+ foreach ($strPartialArr as $strPartial) {
306
+ if (!empty($matchingStr)) {
307
+ break;
308
+ }
309
+ foreach ($strArr2 as $str2) {
310
+ if (0 === stripos($str2, $strPartial)) {
311
+ $matchingStr = $str2;
312
+ break;
313
+ }
314
+ }
315
+ }
316
+
317
+ return $matchingStr;
318
+ }
319
+
320
+ /**
321
+ * Find matching string from $strArr1 and $strArr2
322
+ *
323
+ * @param array $strArr1 array of strings
324
+ * @param array $strArr2 array of strings
325
+ * @param boolean $match_until_first_numeric only match until first numeric occurrence
326
+ * @return string matching str which will be best for replacement
327
+ */
328
+ public static function getMatchingStrFromArrayElemsBasedOnUnderScore($strArr1, $strArr2)
329
+ {
330
+ $matchingStr = '';
331
+
332
+ $str1PartialFirstArr = array();
333
+ $str1PartialFirstArr = array();
334
+ $str1PartialStartNMiddleArr = array();
335
+ $str1PartialMiddleNLastArr = array();
336
+ $str1PartialLastArr = array();
337
+ foreach ($strArr1 as $str1) {
338
+ $str1PartialArr = explode('_', $str1);
339
+ $str1_parts_count = count($str1PartialArr);
340
+ $str1PartialFirstArr[] = $str1PartialArr[0];
341
+ $str1LastPartIndex = $str1_parts_count - 1;
342
+ if ($str1LastPartIndex > 0) {
343
+ $str1PartialLastArr[] = $str1PartialArr[$str1LastPartIndex];
344
+ $str1PartialStartNMiddleArr[] = substr($str1, 0, strripos($str1, '_'));
345
+ $str1PartialMiddleNLastArr[] = substr($str1, stripos($str1, '_') + 1);
346
+ }
347
+ }
348
+ for ($caseNo = 1; $caseNo <= 5; $caseNo++) {
349
+ if (!empty($matchingStr)) {
350
+ break;
351
+ }
352
+ foreach ($strArr2 as $str2) {
353
+ switch ($caseNo) {
354
+ // Both Start and End match
355
+ case 1:
356
+ $str2PartialArr = explode('_', $str2);
357
+ $str2FirstPart = $str2PartialArr[0];
358
+ $str2PartsCount = count($str2PartialArr);
359
+ $str2LastPartIndex = $str2PartsCount - 1;
360
+ if ($str2LastPartIndex > 0) {
361
+ $str2LastPart = $str2PartialArr[$str2LastPartIndex];
362
+ } else {
363
+ $str2LastPart = '';
364
+ }
365
+ if (!empty($str2LastPart) && !empty($str1PartialLastArr) && in_array($str2FirstPart, $str1PartialFirstArr) && in_array($str2LastPart, $str1PartialLastArr)) {
366
+ $matchingStr = $str2;
367
+ }
368
+ break;
369
+ // Start Middle Match
370
+ case 2:
371
+ $str2PartialFirstNMiddleParts = substr($str2, 0, strripos($str2, '_'));
372
+ if (in_array($str2PartialFirstNMiddleParts, $str1PartialStartNMiddleArr)) {
373
+ $matchingStr = $str2;
374
+ }
375
+ break;
376
+ // End Middle Match
377
+ case 3:
378
+ $str2PartialMiddleNLastParts = stripos($str2, '_') !== false ? substr($str2, stripos($str2, '_') + 1) : '';
379
+ if (!empty($str2PartialMiddleNLastParts) && in_array($str2PartialMiddleNLastParts, $str1PartialMiddleNLastArr)) {
380
+ $matchingStr = $str2;
381
+ }
382
+ break;
383
+ // Start Match
384
+ case 4:
385
+ $str2PartialArr = explode('_', $str2);
386
+ $str2FirstPart = $str2PartialArr[0];
387
+ if (in_array($str2FirstPart, $str1PartialFirstArr)) {
388
+ $matchingStr = $str2;
389
+ }
390
+ break;
391
+ // End Match
392
+ case 5:
393
+ $str2PartialArr = explode('_', $str2);
394
+ $str2PartsCount = count($str2PartialArr);
395
+ $str2LastPartIndex = $str2PartsCount - 1;
396
+ if ($str2LastPartIndex > 0) {
397
+ $str2LastPart = $str2PartialArr[$str2LastPartIndex];
398
+ } else {
399
+ $str2LastPart = '';
400
+ }
401
+ if (!empty($str2LastPart) && in_array($str2LastPart, $str1PartialLastArr)) {
402
+ $matchingStr = $str2;
403
+ }
404
+ break;
405
+ }
406
+ if (!empty($matchingStr)) {
407
+ break;
408
+ }
409
+ }
410
+ }
411
+ return $matchingStr;
412
+ }
413
+
414
  /**
415
  * Gets a specific external variable by name and optionally filters it
416
  * @param int $type <p>One of <b><code>INPUT_GET</code></b>, <b><code>INPUT_POST</code></b>, <b><code>INPUT_COOKIE</code></b>, <b><code>INPUT_SERVER</code></b>, or <b><code>INPUT_ENV</code></b>.</p>
430
 
431
  return filter_input(INPUT_POST, $variable_name, $filter, $options);
432
  }
433
+
434
+ /**
435
+ * Implemented array_key_first
436
+ *
437
+ * @link https://www.php.net/manual/en/function.array-key-first.php
438
+ * @param array $arr
439
+ * @return int|string|null
440
+ */
441
+ public static function arrayKeyFirst($arr)
442
+ {
443
+ if (!function_exists('array_key_first')) {
444
+ foreach ($arr as $key => $unused) {
445
+ return $key;
446
+ }
447
+ return null;
448
+ } else {
449
+ return array_key_first($arr);
450
+ }
451
+ }
452
+
453
+ /**
454
+ * Get number of bit supported by PHP
455
+ *
456
+ * @return string
457
+ */
458
+ public static function getArchitectureString()
459
+ {
460
+ return (PHP_INT_SIZE * 8).'-bit';
461
+ }
462
  }
463
  }
lib/snaplib/class.snaplib.u.wp.php CHANGED
@@ -28,6 +28,12 @@ if (!class_exists('DupLiteSnapLibUtilWp', false)) {
28
  private static $corePathList = null;
29
  private static $safeAbsPath = null;
30
 
 
 
 
 
 
 
31
  /**
32
  * return safe ABSPATH without last /
33
  * perform safe function only one time
@@ -38,7 +44,7 @@ if (!class_exists('DupLiteSnapLibUtilWp', false)) {
38
  {
39
  if (is_null(self::$safeAbsPath)) {
40
  if (defined('ABSPATH')) {
41
- self::$safeAbsPath = rtrim(DupLiteSnapLibIOU::safePath(ABSPATH), '/');
42
  } else {
43
  self::$safeAbsPath = '';
44
  }
@@ -47,6 +53,90 @@ if (!class_exists('DupLiteSnapLibUtilWp', false)) {
47
  return self::$safeAbsPath;
48
  }
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  /**
51
  * check if path is in wordpress core list
52
  *
@@ -67,8 +157,6 @@ if (!class_exists('DupLiteSnapLibUtilWp', false)) {
67
  $path = rtrim(DupLiteSnapLibIOU::safePath($path), '/');
68
  }
69
 
70
-
71
-
72
  switch ($fullPath) {
73
  case self::PATH_FULL:
74
  $absPath = self::getSafeAbsPath();
@@ -78,7 +166,9 @@ if (!class_exists('DupLiteSnapLibUtilWp', false)) {
78
  $relPath = ltrim(substr($path, strlen($absPath)), '/');
79
  break;
80
  case self::PATH_RELATIVE:
81
- $relPath = ltrim($path, '/');
 
 
82
  break;
83
  case self::PATH_AUTO:
84
  default:
@@ -130,5 +220,28 @@ if (!class_exists('DupLiteSnapLibUtilWp', false)) {
130
  }
131
  return self::$corePathList;
132
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  }
134
- }
28
  private static $corePathList = null;
29
  private static $safeAbsPath = null;
30
 
31
+ /**
32
+ *
33
+ * @var string if not empty alters isWpCore's operation
34
+ */
35
+ private static $wpCoreRelativePath = '';
36
+
37
  /**
38
  * return safe ABSPATH without last /
39
  * perform safe function only one time
44
  {
45
  if (is_null(self::$safeAbsPath)) {
46
  if (defined('ABSPATH')) {
47
+ self::$safeAbsPath = DupLiteSnapLibIOU::safePathUntrailingslashit(ABSPATH);
48
  } else {
49
  self::$safeAbsPath = '';
50
  }
53
  return self::$safeAbsPath;
54
  }
55
 
56
+ /**
57
+ *
58
+ * @param string $folder
59
+ * @return boolean // return true if folder is wordpress home folder
60
+ *
61
+ */
62
+ public static function isWpHomeFolder($folder)
63
+ {
64
+ $indexPhp = DupLiteSnapLibIOU::trailingslashit($folder).'index.php';
65
+ if (!file_exists($indexPhp)) {
66
+ return false;
67
+ }
68
+
69
+ if (($indexContent = file_get_contents($indexPhp)) === false) {
70
+ return false;
71
+ }
72
+
73
+ return (preg_match('/require\s*[\s\(].*[\'"].*wp-blog-header.php[\'"]\s*\)?/', $indexContent) === 1);
74
+ }
75
+
76
+ /**
77
+ * This function is the equivalent of the get_home_path function but with various fixes
78
+ *
79
+ * @staticvar string $home_path
80
+ * @return string
81
+ */
82
+ public static function getHomePath()
83
+ {
84
+ static $home_path = null;
85
+
86
+ if (is_null($home_path)) {
87
+ // outside wordpress this function makes no sense
88
+ if (!defined('ABSPATH')) {
89
+ $home_path = false;
90
+ return $home_path;
91
+ }
92
+
93
+ if (isset($_SERVER['SCRIPT_FILENAME']) && is_readable($_SERVER['SCRIPT_FILENAME'])) {
94
+ $scriptFilename = $_SERVER['SCRIPT_FILENAME'];
95
+ } else {
96
+ $files = get_included_files();
97
+ $scriptFilename = array_shift($files);
98
+ }
99
+
100
+ $realScriptDirname = DupLiteSnapLibIOU::safePathTrailingslashit(dirname($scriptFilename), true);
101
+ $realAbsPath = DupLiteSnapLibIOU::safePathTrailingslashit(ABSPATH, true);
102
+
103
+ if (strpos($realScriptDirname, $realAbsPath) === 0) {
104
+ // normalize URLs without www
105
+ $home = DupLiteSnapLibURLU::wwwRemove(set_url_scheme(get_option('home'), 'http'));
106
+ $siteurl = DupLiteSnapLibURLU::wwwRemove(set_url_scheme(get_option('siteurl'), 'http'));
107
+
108
+ if (!empty($home) && 0 !== strcasecmp($home, $siteurl)) {
109
+ if (stripos($siteurl, $home) === 0) {
110
+ $wp_path_rel_to_home = str_ireplace($home, '', $siteurl); /* $siteurl - $home */
111
+ $pos = strripos(str_replace('\\', '/', $scriptFilename), DupLiteSnapLibIOU::trailingslashit($wp_path_rel_to_home));
112
+ $home_path = substr($scriptFilename, 0, $pos);
113
+ $home_path = DupLiteSnapLibIOU::trailingslashit($home_path);
114
+ } else {
115
+ $home_path = ABSPATH;
116
+ }
117
+ } else {
118
+ $home_path = ABSPATH;
119
+ }
120
+ } else {
121
+ // On frontend the home path is the folder of index.php
122
+ $home_path = DupLiteSnapLibIOU::trailingslashit(dirname($scriptFilename));
123
+ }
124
+
125
+ // make sure the folder exists or consider ABSPATH
126
+ if (!file_exists($home_path)) {
127
+ $home_path = ABSPATH;
128
+ }
129
+
130
+ $home_path = str_replace('\\', '/', $home_path);
131
+ }
132
+ return $home_path;
133
+ }
134
+
135
+ public static function setWpCoreRelativeAbsPath($string = '')
136
+ {
137
+ self::$wpCoreRelativePath = (string) $string;
138
+ }
139
+
140
  /**
141
  * check if path is in wordpress core list
142
  *
157
  $path = rtrim(DupLiteSnapLibIOU::safePath($path), '/');
158
  }
159
 
 
 
160
  switch ($fullPath) {
161
  case self::PATH_FULL:
162
  $absPath = self::getSafeAbsPath();
166
  $relPath = ltrim(substr($path, strlen($absPath)), '/');
167
  break;
168
  case self::PATH_RELATIVE:
169
+ if (($relPath = DupLiteSnapLibIOU::getRelativePath($path, self::$wpCoreRelativePath)) === false) {
170
+ return false;
171
+ }
172
  break;
173
  case self::PATH_AUTO:
174
  default:
220
  }
221
  return self::$corePathList;
222
  }
223
+
224
+ /**
225
+ * return object list of sites
226
+ *
227
+ * @return boolean
228
+ */
229
+ public static function getSites($args = array())
230
+ {
231
+ if (!function_exists('is_multisite') || !is_multisite()) {
232
+ return false;
233
+ }
234
+
235
+ if (function_exists('get_sites')) {
236
+ return get_sites($args);
237
+ } else {
238
+ $result = array();
239
+ $blogs = wp_get_sites($args);
240
+ foreach ($blogs as $blog) {
241
+ $result[] = (object) $blog;
242
+ }
243
+ return $result;
244
+ }
245
+ }
246
  }
247
+ }
lib/snaplib/snaplib.all.php CHANGED
@@ -22,13 +22,15 @@ if (!defined('DUPLITE_SNAPLIB_INCLUDE_ALL')) {
22
  require_once($dir.'/class.snaplib.logger.php');
23
  require_once($dir.'/class.snaplib.u.util.php');
24
  require_once($dir.'/class.snaplib.u.io.php');
 
25
  require_once($dir.'/class.snaplib.u.json.php');
26
  require_once($dir.'/class.snaplib.jsonSerializable.abstract.php');
27
  require_once($dir.'/class.snaplib.u.net.php');
 
28
  require_once($dir.'/class.snaplib.u.os.php');
29
  require_once($dir.'/class.snaplib.u.stream.php');
30
  require_once($dir.'/class.snaplib.u.string.php');
31
  require_once($dir.'/class.snaplib.u.ui.php');
32
  require_once($dir.'/class.snaplib.u.url.php');
33
  require_once($dir.'/class.snaplib.u.wp.php');
34
- }
22
  require_once($dir.'/class.snaplib.logger.php');
23
  require_once($dir.'/class.snaplib.u.util.php');
24
  require_once($dir.'/class.snaplib.u.io.php');
25
+ require_once($dir.'/class.snaplib.u.db.php');
26
  require_once($dir.'/class.snaplib.u.json.php');
27
  require_once($dir.'/class.snaplib.jsonSerializable.abstract.php');
28
  require_once($dir.'/class.snaplib.u.net.php');
29
+ require_once($dir.'/class.snaplib.u.orig.files.manager.php');
30
  require_once($dir.'/class.snaplib.u.os.php');
31
  require_once($dir.'/class.snaplib.u.stream.php');
32
  require_once($dir.'/class.snaplib.u.string.php');
33
  require_once($dir.'/class.snaplib.u.ui.php');
34
  require_once($dir.'/class.snaplib.u.url.php');
35
  require_once($dir.'/class.snaplib.u.wp.php');
36
+ }
readme.txt CHANGED
@@ -2,9 +2,9 @@
2
  Contributors: corylamleorg, bobriley
3
  Tags: migration, backup, duplicate, move, migrate, restore, transfer, clone, automate, copy site, migrator
4
  Requires at least: 4.0
5
- Tested up to: 5.6
6
- Requires PHP: 5.2.17
7
- Stable tag: 1.3.40.1
8
  License: GPLv2
9
 
10
  WordPress migration and backups are much easier with Duplicator! Clone, backup, move and transfer an entire site from one location to another.
2
  Contributors: corylamleorg, bobriley
3
  Tags: migration, backup, duplicate, move, migrate, restore, transfer, clone, automate, copy site, migrator
4
  Requires at least: 4.0
5
+ Tested up to: 5.7
6
+ Requires PHP: 5.3.8
7
+ Stable tag: 1.4.0
8
  License: GPLv2
9
 
10
  WordPress migration and backups are much easier with Duplicator! Clone, backup, move and transfer an entire site from one location to another.
tools/DuplicatorPhpVersionCheck.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * These functions are performed before including any other Duplicator file so
4
+ * do not use any Duplicator library or feature and use code compatible with PHP 5.2
5
+ *
6
+ */
7
+ defined('ABSPATH') || exit;
8
+
9
+ // In the future it will be included on both PRO and LITE so you need to check if the define exists.
10
+ if (!class_exists('DuplicatorPhpVersionCheck')) {
11
+
12
+ class DuplicatorPhpVersionCheck
13
+ {
14
+
15
+ protected static $minVer = null;
16
+ protected static $suggestedVer = null;
17
+
18
+ public static function check($minVer, $suggestedVer)
19
+ {
20
+ self::$minVer = $minVer;
21
+ self::$suggestedVer = $suggestedVer;
22
+
23
+ if (version_compare(PHP_VERSION, self::$minVer, '<')) {
24
+ if (is_multisite()) {
25
+ add_action('network_admin_notices', array(__CLASS__, 'notice'));
26
+ } else {
27
+ add_action('admin_notices', array(__CLASS__, 'notice'));
28
+ }
29
+ return false;
30
+ } else {
31
+ return true;
32
+ }
33
+ }
34
+
35
+ public static function notice()
36
+ {
37
+ ?>
38
+ <div class="error notice">
39
+ <p>
40
+ <?php
41
+ $str = 'DUPLICATOR: '.__('Your system is running a very old version of PHP (%s) that is no longer suppported by Duplicator.', 'duplicator');
42
+ printf($str, PHP_VERSION);
43
+ ?>
44
+ </p>
45
+ <p>
46
+ <?php
47
+ $str = __('Please ask your host or server administrator to update to PHP %1s or greater. If this is not possible, ', 'duplicator');
48
+ $str .= '<a href="https://snapcreek.com/ticket" target="blank">';
49
+ $str .= __('open a ticket', 'duplicator');
50
+ $str .= '</a>';
51
+ $str .= __(' to request a previous version of Duplicator compatible with PHP %2s.', 'duplicator');
52
+ printf($str, self::$suggestedVer, PHP_VERSION);
53
+ ?>
54
+ </p>
55
+ </div>
56
+ <?php
57
+ }
58
+ }
59
+ }
tools/Lite/Requirements.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class that collects the functions of initial checks on the requirements to run the plugin
4
+ *
5
+ * Standard: PSR-2
6
+ * @link http://www.php-fig.org/psr/psr-2
7
+ *
8
+ * @package Duplicator
9
+ * @copyright (c) 2021, Snapcreek LLC
10
+ *
11
+ */
12
+
13
+ namespace Duplicator\Lite;
14
+
15
+ defined('ABSPATH') || exit;
16
+
17
+ class Requirements
18
+ {
19
+ const DUP_PRO_PLUGIN_KEY = 'duplicator-pro/duplicator-pro.php';
20
+
21
+ /**
22
+ *
23
+ * @var string // current plugin file full path
24
+ */
25
+ protected static $pluginFile = '';
26
+
27
+ /**
28
+ *
29
+ * @var string // message on deactivation
30
+ */
31
+ protected static $deactivationMessage = '';
32
+
33
+ /**
34
+ * This function checks the requirements to run Duplicator.
35
+ * At this point WordPress is not yet completely initialized so functionality is limited.
36
+ * It need to hook into "admin_init" to get the full functionality of WordPress.
37
+ *
38
+ * @param string $pluginFile // main plugin file path
39
+ * @return boolean // true if plugin can be executed
40
+ */
41
+ public static function canRun($pluginFile)
42
+ {
43
+ $result = true;
44
+ self::$pluginFile = $pluginFile;
45
+
46
+ if ($result === true && is_multisite()) {
47
+ /* Deactivation of the plugin disabled in favor of a notification for the next version
48
+ * Uncomment this to enable the logic.
49
+ *
50
+ add_action('admin_init', array(__CLASS__, 'addMultisiteNotice'));
51
+ self::$deactivationMessage = __('Can\'t enable Duplicator LITE in a multisite installation', 'duplicator');
52
+ $result = false;
53
+ */
54
+
55
+ // TEMP WARNING NOTICE, remove this when the deactiovation logic is enable
56
+ add_action('admin_init', array(__CLASS__, 'addTempWarningMultisiteNotice'));
57
+ }
58
+
59
+
60
+ if ($result === true && self::isPluginActive(self::DUP_PRO_PLUGIN_KEY)) {
61
+ /* Deactivation of the plugin disabled in favor of a notification for the next version
62
+ * Uncomment this to enable the logic.
63
+ *
64
+ add_action('admin_init', array(__CLASS__, 'addProEnableNotice'));
65
+ self::$deactivationMessage = __('Can\'t enable Duplicator LITE if the PRO version is enabled', 'duplicator');
66
+ $result = false;
67
+ */
68
+
69
+ // TEMP WARNING NOTICE, remove this when the deactiovation logic is enable
70
+ add_action('admin_init', array(__CLASS__, 'addTempWarningProEnableNotice'));
71
+ }
72
+
73
+ if ($result === false) {
74
+ register_activation_hook($pluginFile, array(__CLASS__, 'deactivateOnActivation'));
75
+ }
76
+
77
+ return $result;
78
+ }
79
+
80
+ /**
81
+ *
82
+ * @param string $plugin
83
+ * @return boolean // return true if plugin key is active and plugin file exists
84
+ */
85
+ protected static function isPluginActive($plugin)
86
+ {
87
+ $isActive = false;
88
+ if (in_array($plugin, (array) get_option('active_plugins', array()))) {
89
+ $isActive = true;
90
+ }
91
+
92
+ if (is_multisite()) {
93
+ $plugins = get_site_option('active_sitewide_plugins');
94
+ if (isset($plugins[$plugin])) {
95
+ $isActive = true;
96
+ }
97
+ }
98
+
99
+ return ($isActive && file_exists(WP_PLUGIN_DIR . '/' . $plugin));
100
+ }
101
+
102
+ /**
103
+ * display admin notice only if user can manage plugins.
104
+ */
105
+ public static function addProEnableNotice()
106
+ {
107
+ if (current_user_can('activate_plugins')) {
108
+ add_action('admin_notices', array(__CLASS__, 'proEnabledNotice'));
109
+ }
110
+ }
111
+
112
+ /**
113
+ * display admin notice
114
+ */
115
+ public static function addMultisiteNotice()
116
+ {
117
+ if (current_user_can('activate_plugins')) {
118
+ add_action('admin_notices', array(__CLASS__, 'multisiteNotice'));
119
+ }
120
+ }
121
+
122
+ /**
123
+ * display admin notice only if user can manage plugins.
124
+ */
125
+ public static function addTempWarningProEnableNotice()
126
+ {
127
+ if (current_user_can('activate_plugins') && false === get_option(\DUP_UI_Notice::OPTION_KEY_IS_PRO_ENABLE_NOTICE_DISMISSED, false)) {
128
+ add_action('admin_notices', array(__CLASS__, 'tempWarningProEnableNotice'));
129
+ }
130
+ }
131
+
132
+ public static function addTempWarningMultisiteNotice()
133
+ {
134
+ if (current_user_can('activate_plugins') && !is_plugin_active_for_network(plugin_basename(self::$pluginFile)) && false === get_option(\DUP_UI_Notice::OPTION_KEY_IS_MU_NOTICE_DISMISSED, false)) {
135
+ add_action('admin_notices', array(__CLASS__, 'tempWarningMultisiteNotice'));
136
+ }
137
+ }
138
+
139
+ /**
140
+ * deactivate current plugin on activation
141
+ */
142
+ public static function deactivateOnActivation()
143
+ {
144
+ deactivate_plugins(plugin_basename(self::$pluginFile));
145
+ wp_die(self::$deactivationMessage);
146
+ }
147
+
148
+ /**
149
+ * Display admin notice if duplicator pro is enabled
150
+ */
151
+ public static function proEnabledNotice()
152
+ {
153
+ ?>
154
+ <div class="error notice">
155
+ <p>
156
+ <?php
157
+ echo 'DUPLICATOR LITE: ' . __('Duplicator LITE cannot be work if Duplicator PRO is active.', 'duplicator');
158
+ ?>
159
+ </p>
160
+ <p>
161
+ <?php
162
+ echo __('If you want to use Duplicator LITE you must first deactivate the PRO version', 'duplicator');
163
+ ?><br>
164
+ <b>
165
+ <?php
166
+ echo __('Please disable the LITE version if it is not needed.', 'duplicator');
167
+ ?>
168
+ </b>
169
+ </p>
170
+ </div>
171
+ <?php
172
+ }
173
+
174
+ /**
175
+ * Display admin notice if duplicator pro is enabled
176
+ */
177
+ public static function multisiteNotice()
178
+ {
179
+ ?>
180
+ <div class="error notice">
181
+ <p>
182
+ <?php
183
+ echo 'DUPLICATOR LITE: ' . __('Duplicator LITE can\'t work on multisite installation.', 'duplicator');
184
+ ?>
185
+ </p>
186
+ <p>
187
+ <?php
188
+ echo __('The PRO version also works in multi-site installations.', 'duplicator');
189
+ ?>
190
+ </p>
191
+ </div>
192
+ <?php
193
+ }
194
+
195
+ /**
196
+ * Display admin notice if duplicator pro is enabled
197
+ */
198
+ public static function tempWarningProEnableNotice()
199
+ {
200
+ ?>
201
+ <div class="notice notice-warning duplicator-admin-notice is-dismissible" data-to-dismiss="<?php echo \DUP_UI_Notice::OPTION_KEY_IS_PRO_ENABLE_NOTICE_DISMISSED;?>">
202
+ <p>
203
+ <?php
204
+ echo '<i class="fas fa-exclamation-circle"></i> ' . __('NOTICE: Duplicator is undergoing changes to enhance its backend logic. These changes will prevent Duplicator Lite &amp; Duplicator Pro from being activated at the same time.', 'duplicator');
205
+ echo "<br/>";
206
+ echo '<i>' . __('This message is simply a notice to inform users that the changes will be coming soon.', 'duplicator') . '</i>';
207
+ ?>
208
+ </p>
209
+ </div>
210
+ <?php
211
+ }
212
+
213
+ /**
214
+ * Display admin notice if duplicator pro is enabled
215
+ */
216
+ public static function tempWarningMultisiteNotice()
217
+ {
218
+ ?>
219
+ <div class="notice notice-warning duplicator-admin-notice is-dismissible" data-to-dismiss="<?php echo \DUP_UI_Notice::OPTION_KEY_IS_MU_NOTICE_DISMISSED;?>">
220
+ <p>
221
+ <?php
222
+ echo '<i class="fas fa-exclamation-circle"></i> ' . __('NOTICE: Duplicator Lite cannot be activated individually in the sub-sites of a multisite installation but must be activated only on the network. '
223
+ . 'Please deactivate Duplicator Lite at this site and activate it on the network.', 'duplicator');
224
+ ?>
225
+ </p>
226
+ </div>
227
+ <?php
228
+ }
229
+ }
uninstall.php CHANGED
@@ -6,6 +6,15 @@
6
  if (!defined('WP_UNINSTALL_PLUGIN')) {
7
  exit;
8
  }
 
 
 
 
 
 
 
 
 
9
  require_once 'helper.php';
10
  require_once 'define.php';
11
  require_once 'lib/snaplib/snaplib.all.php';
@@ -54,6 +63,10 @@ if (DUP_Settings::Get('uninstall_files')) {
54
  if (strstr($file, '_scan.json'))
55
  @unlink("{$file}");
56
  }
 
 
 
 
57
  // before 1.3.38 the [HASH]_wp-config.txt was present in main storage area
58
  foreach (glob("{$ssdir}/*_wp-config.txt") as $file) {
59
  if (strstr($file, '_wp-config.txt'))
6
  if (!defined('WP_UNINSTALL_PLUGIN')) {
7
  exit;
8
  }
9
+
10
+ // CHECK PHP VERSION
11
+ define('DUPLICATOR_LITE_PHP_MINIMUM_VERSION', '5.3.8');
12
+ define('DUPLICATOR_LITE_PHP_SUGGESTED_VERSION', '5.6.20');
13
+ require_once(dirname(__FILE__)."/tools/DuplicatorPhpVersionCheck.php");
14
+ if (DuplicatorPhpVersionCheck::check(DUPLICATOR_LITE_PHP_MINIMUM_VERSION, DUPLICATOR_LITE_PHP_SUGGESTED_VERSION) === false) {
15
+ return;
16
+ }
17
+
18
  require_once 'helper.php';
19
  require_once 'define.php';
20
  require_once 'lib/snaplib/snaplib.all.php';
63
  if (strstr($file, '_scan.json'))
64
  @unlink("{$file}");
65
  }
66
+ foreach (glob("{$ssdir_tmp}/*_scan.json") as $file) {
67
+ if (strstr($file, '_scan.json'))
68
+ @unlink("{$file}");
69
+ }
70
  // before 1.3.38 the [HASH]_wp-config.txt was present in main storage area
71
  foreach (glob("{$ssdir}/*_wp-config.txt") as $file) {
72
  if (strstr($file, '_wp-config.txt'))
views/packages/main/packages.php CHANGED
@@ -153,11 +153,7 @@ if (DUP_Settings::Get('installer_name_mode') == DUP_Settings::INSTALLER_NAME_MOD
153
  <th style="width: 70px;"><?php esc_html_e("Size", 'duplicator') ?></th>
154
  <th><?php esc_html_e("Package Name", 'duplicator') ?></th>
155
  <th class="inst-name">
156
- <a href='admin.php?page=duplicator-settings&tab=packageadmin.php?page=duplicator-settings&tab=package#duplicator-installer-settings'>
157
- <?php
158
- esc_html_e("Installer Name", 'duplicator');
159
- ?>
160
- </a>
161
  <i class="fas fa-question-circle fa-sm"
162
  data-tooltip-title="<?php esc_html_e("Installer Name:", 'duplicator'); ?>"
163
  data-tooltip="<?php echo esc_attr($packageExeNameModeMsg); ?>" >
@@ -238,7 +234,9 @@ if (DUP_Settings::Get('installer_name_mode') == DUP_Settings::INSTALLER_NAME_MOD
238
  }
239
  $installerName = $Package->getInstDownloadName();
240
  ?>
241
- <i class="fas <?php echo $lockIcon; ?>"></i>
 
 
242
  <input type="text" readonly="readonly" value="<?php echo esc_attr($installerName); ?>" title="<?php echo esc_attr($installerName); ?>" onfocus="jQuery(this).select();"/>
243
  <span data-dup-copy-text="<?php echo $installerName; ?>" ><i class='far fa-copy' style='cursor: pointer'></i>
244
  </td>
153
  <th style="width: 70px;"><?php esc_html_e("Size", 'duplicator') ?></th>
154
  <th><?php esc_html_e("Package Name", 'duplicator') ?></th>
155
  <th class="inst-name">
156
+ <?php esc_html_e("Installer Name", 'duplicator'); ?>
 
 
 
 
157
  <i class="fas fa-question-circle fa-sm"
158
  data-tooltip-title="<?php esc_html_e("Installer Name:", 'duplicator'); ?>"
159
  data-tooltip="<?php echo esc_attr($packageExeNameModeMsg); ?>" >
234
  }
235
  $installerName = $Package->getInstDownloadName();
236
  ?>
237
+ <a href="admin.php?page=duplicator-settings&tab=packageadmin.php?page=duplicator-settings&tab=package#duplicator-installer-settings" title="<?php esc_html_e("Click to open settings page.", 'duplicator') ?>">
238
+ <i class="fas <?php echo $lockIcon; ?>"></i>
239
+ </a>
240
  <input type="text" readonly="readonly" value="<?php echo esc_attr($installerName); ?>" title="<?php echo esc_attr($installerName); ?>" onfocus="jQuery(this).select();"/>
241
  <span data-dup-copy-text="<?php echo $installerName; ?>" ><i class='far fa-copy' style='cursor: pointer'></i>
242
  </td>
views/packages/main/s2.scan1.php CHANGED
@@ -1,449 +1,449 @@
1
- <?php
2
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
- //Nonce Check
4
- if (! isset( $_POST['dup_form_opts_nonce_field'] ) || ! wp_verify_nonce( sanitize_text_field($_POST['dup_form_opts_nonce_field']), 'dup_form_opts' ) ) {
5
- DUP_UI_Notice::redirect('admin.php?page=duplicator&tab=new1&_wpnonce='.wp_create_nonce('new1-package'));
6
- }
7
-
8
- global $wp_version;
9
- wp_enqueue_script('dup-handlebars');
10
-
11
- if (empty($_POST)) {
12
- //F5 Refresh Check
13
- $redirect = admin_url('admin.php?page=duplicator&tab=new1');
14
- $redirect_nonce_url = wp_nonce_url($redirect, 'new1-package');
15
- die("<script>window.location.href = '{$reredirect_nonce_url}'</script>");
16
- }
17
-
18
- $Package = new DUP_Package();
19
- $Package->saveActive($_POST);
20
-
21
- DUP_Settings::Set('active_package_id', -1);
22
- DUP_Settings::Save();
23
-
24
- $Package = DUP_Package::getActive();
25
-
26
- $mysqldump_on = DUP_Settings::Get('package_mysqldump') && DUP_DB::getMySqlDumpPath();
27
- $mysqlcompat_on = isset($Package->Database->Compatible) && strlen($Package->Database->Compatible);
28
- $mysqlcompat_on = ($mysqldump_on && $mysqlcompat_on) ? true : false;
29
- $dbbuild_mode = ($mysqldump_on) ? 'mysqldump' : 'PHP';
30
- $zip_check = DUP_Util::getZipPath();
31
-
32
- $action_url = admin_url('admin.php?page=duplicator&tab=new3');
33
- $action_nonce_url = wp_nonce_url($action_url, 'new3-package');
34
- ?>
35
-
36
- <style>
37
- /*PROGRESS-BAR - RESULTS - ERROR */
38
- form#form-duplicator {text-align:center; max-width:650px; min-height:200px; margin:0px auto 0px auto; padding:0px;}
39
- div.dup-progress-title {font-size:22px; padding:5px 0 20px 0; font-weight:bold}
40
- div#dup-msg-success {padding:0 5px 5px 5px; text-align:left}
41
- div#dup-msg-success div.details {padding:10px 15px 10px 15px; margin:5px 0 15px 0; background:#fff; border-radius:5px; border:1px solid #ddd; box-shadow:0 8px 6px -6px #999; }
42
- div#dup-msg-success div.details-title {font-size:20px; border-bottom:1px solid #dfdfdf; padding:5px; margin:0 0 10px 0; font-weight:bold}
43
- div#dup-msg-success-subtitle {color:#999; margin:0; font-size:11px}
44
- div.dup-scan-filter-status {display:inline; font-size:11px; margin-right:10px; color:#630f0f;}
45
- div#dup-msg-error {color:#A62426; padding:5px; max-width:790px;}
46
- div#dup-msg-error-response-text { max-height:500px; overflow-y:scroll; border:1px solid silver; border-radius:3px; padding:10px;background:#fff}
47
- div.dup-hdr-error-details {text-align:left; margin:20px 0}
48
- i[data-tooltip].fa-question-circle {color:#555}
49
-
50
- /*SCAN ITEMS: Sections */
51
- div.scan-header { font-size:16px; padding:7px 5px 7px 7px; font-weight:bold; background-color:#E0E0E0; border-bottom:0px solid #C0C0C0 }
52
- div.scan-header-details {float:right; margin-top:-5px}
53
- div.scan-item {border:1px solid #E0E0E0; border-bottom:none;}
54
- div.scan-item-first { border-top-right-radius:4px; border-top-left-radius:4px}
55
- div.scan-item-last {border-bottom:1px solid #E0E0E0}
56
- div.scan-item div.title {background-color:#F1F1F1; width:100%; padding:4px 0 4px 0; cursor:pointer; height:20px;}
57
- div.scan-item div.title:hover {background-color:#ECECEC;}
58
- div.scan-item div.text {font-weight:bold; font-size:14px; float:left; position:relative; left:10px}
59
- div.scan-item div.badge {float:right; border-radius:4px; color:#fff; min-width:40px; text-align:center; position:relative; right:10px; font-size:12px; padding:0 3px 1px 3px}
60
- div.scan-item div.badge-pass {background:#197b19;}
61
- div.scan-item div.badge-warn {background:#636363;}
62
- div.scan-item div.info {display:none; padding:10px; background:#fff}
63
- div.scan-good {display:inline-block; color:green;font-weight:bold;}
64
- div.scan-warn {display:inline-block; color:#d61212;font-weight:bold;}
65
- div.dup-more-details {float:right; font-size:14px}
66
- div.dup-more-details a{color:black}
67
- div.dup-more-details a:hover {color:#777; cursor:pointer}
68
- div.dup-more-details:hover {color:#777; cursor:pointer}
69
-
70
- /*FILES */
71
- div#data-arc-size1 {display:inline-block; font-size:11px; margin-right:1px;}
72
- sup.dup-small-ext-type {font-size:11px; font-weight: normal; font-style: italic}
73
- i.data-size-help { font-size:12px; display:inline-block; margin:0; padding:0}
74
- div.dup-data-size-uncompressed {font-size:10px; text-align: right; padding:0; margin:-7px 0 0 0; font-style: italic; font-weight: normal; border:0px solid red; clear:both}
75
- div.hb-files-style div.container {border:1px solid #E0E0E0; border-radius:4px; margin:5px 0 10px 0}
76
- div.hb-files-style div.container b {font-weight:bold}
77
- div.hb-files-style div.container div.divider {margin-bottom:2px; font-weight:bold}
78
- div.hb-files-style div.data {padding:8px; line-height:21px; height:175px; overflow-y:scroll; }
79
- div.hb-files-style div.hdrs {padding:0 4px 4px 6px; border-bottom:1px solid #E0E0E0; font-weight:bold}
80
- div.hb-files-style div.hdrs sup i.fa {font-size:11px}
81
- div.hb-files-style div.hdrs-up-down {float:right; margin:2px 12px 0 0}
82
- div.hb-files-style i.dup-nav-toggle:hover {cursor:pointer; color:#999}
83
- div.hb-files-style div.directory {margin-left:12px}
84
- div.hb-files-style div.directory i.size {font-size:11px; font-style:normal; display:inline-block; min-width:50px}
85
- div.hb-files-style div.directory i.count {font-size:11px; font-style:normal; display:inline-block; min-width:20px}
86
- div.hb-files-style div.directory i.empty {width:15px; display:inline-block}
87
- div.hb-files-style div.directory i.dup-nav {cursor:pointer}
88
- div.hb-files-style div.directory i.fa {width:8px}
89
- div.hb-files-style div.directory i.chk-off {width:20px; color:#777; cursor: help; margin:0; font-size:1.25em}
90
- div.hb-files-style div.directory label {font-weight:bold; cursor:pointer; vertical-align:top;display:inline-block; width:475px; white-space: nowrap; overflow:hidden; text-overflow:ellipsis;}
91
- div.hb-files-style div.directory label:hover {color:#025d02}
92
- div.hb-files-style div.files {padding:2px 0 0 35px; font-size:12px; display:none; line-height:18px}
93
- div.hb-files-style div.files i.size {font-style:normal; display:inline-block; min-width:50px}
94
- div.hb-files-style div.files label {font-weight: normal; font-size:11px; vertical-align:top;display:inline-block;width:450px; white-space: nowrap; overflow:hidden; text-overflow:ellipsis;}
95
- div.hb-files-style div.files label:hover {color:#025d02; cursor: pointer}
96
- div.hb-files-style div.apply-btn {text-align:right; margin: 1px 0 10px 0; width:100%}
97
- div.hb-files-style div.apply-warn {float:left; font-size:11px; color:maroon; margin-top:-7px; font-style: italic; display:none; text-align: left}
98
-
99
- div#size-more-details {display:none; margin:5px 0 20px 0; border:1px solid #dfdfdf; padding:8px; border-radius: 4px; background-color: #F1F1F1}
100
- div#size-more-details ul {list-style-type:circle; padding-left:20px; margin:0}
101
- div#size-more-details li {margin:0}
102
-
103
- /*DATABASE*/
104
- div#dup-scan-db-info {margin-top:5px}
105
- div#data-db-tablelist {max-height:250px; overflow-y:scroll; border:1px solid silver; padding:8px; background: #efefef; border-radius: 4px}
106
- div#data-db-tablelist td{padding:0 5px 3px 20px; min-width:100px}
107
- div#data-db-size1, div#data-ll-totalsize {display:inline-block; font-size:11px; margin-right:1px;}
108
- /*FILES */
109
- div#dup-confirm-area {color:maroon; display:none; text-align: center; font-size:14px; line-height:24px; font-weight: bold; margin: -5px 0 10px 0}
110
- div#dup-confirm-area label {font-size:14px !important}
111
-
112
- /*WARNING-CONTINUE*/
113
- div#dup-scan-warning-continue {display:none; text-align:center; padding:0 0 15px 0}
114
- div#dup-scan-warning-continue div.msg1 label{font-size:16px; color:#630f0f}
115
- div#dup-scan-warning-continue div.msg2 {padding:2px; line-height:13px}
116
- div#dup-scan-warning-continue div.msg2 label {font-size:11px !important}
117
- div.dup-pro-support {text-align:center; font-style:italic; font-size:13px; margin-top:20px;font-weight:bold}
118
-
119
- /*DIALOG WINDOWS*/
120
- div#arc-details-dlg {font-size:12px; line-height:18px !important}
121
- div#arc-details-dlg h2 {margin:0; padding:0 0 5px 0; border-bottom:1px solid #dfdfdf;}
122
- div#arc-details-dlg hr {margin:3px 0 10px 0}
123
- div#arc-details-dlg table#db-area {margin:0; width:98%}
124
- div#arc-details-dlg table#db-area td {padding:0;}
125
- div#arc-details-dlg table#db-area td:first-child {font-weight:bold; white-space:nowrap; width:100px}
126
- div#arc-details-dlg div.filter-area {height:245px; overflow-y:scroll; border:1px solid #dfdfdf; padding:8px; margin:2px 0}
127
- div#arc-details-dlg div.file-info {padding:0 0 10px 15px; width:500px; white-space:nowrap;}
128
- div#arc-details-dlg div.file-info i.fa-question-circle { margin-right: 5px; font-size: 11px;}
129
-
130
- div#arc-paths-dlg textarea.path-dirs,
131
- textarea.path-files {font-size:12px; border: 1px solid silver; padding: 10px; background: #fff; margin:5px; height:125px; width:100%; white-space:pre}
132
- div#arc-paths-dlg div.copy-button {float:right;}
133
- div#arc-paths-dlg div.copy-button button {font-size:12px}
134
-
135
- /*FOOTER*/
136
- div.dup-button-footer {text-align:center; margin:0}
137
- button.button {font-size:15px !important; height:30px !important; font-weight:bold; padding:3px 5px 5px 5px !important;}
138
- i.scan-warn {color:#630f0f;}
139
- </style>
140
-
141
- <?php
142
- $validator = $Package->validateInputs();
143
- if (!$validator->isSuccess()) {
144
- ?>
145
- <form id="form-duplicator" method="post" action="<?php echo $action_nonce_url; ?>">
146
- <!-- ERROR MESSAGE -->
147
- <div id="dup-msg-error" >
148
- <div class="dup-hdr-error"><i class="fa fa-exclamation-circle"></i> <?php _e('Input fields not valid', 'duplicator'); ?></div>
149
- <i><?php esc_html_e('Please try again!', 'duplicator'); ?></i><br/>
150
- <div class="dup-hdr-error-details">
151
- <b><?php esc_html_e("Error Message:", 'duplicator'); ?></b>
152
- <div id="dup-msg-error-response-text">
153
- <ul>
154
- <?php
155
- $validator->getErrorsFormat("<li>%s</li>");
156
- ?>
157
- </ul>
158
- </div>
159
- </div>
160
- </div>
161
- <input type="button" value="&#9664; <?php esc_html_e("Back", 'duplicator') ?>" onclick="window.location.assign('?page=duplicator&tab=new1&_wpnonce=<?php echo wp_create_nonce('new1-package'); ?>')" class="button button-large" />
162
- </form>
163
- <?php
164
- return;
165
- }
166
- ?>
167
-
168
- <!-- =========================================
169
- TOOL BAR:STEPS -->
170
- <table id="dup-toolbar">
171
- <tr valign="top">
172
- <td style="white-space:nowrap">
173
- <div id="dup-wiz">
174
- <div id="dup-wiz-steps">
175
- <div class="completed-step"><a>1-<?php esc_html_e('Setup', 'duplicator'); ?></a></div>
176
- <div class="active-step"><a>2-<?php esc_html_e('Scan', 'duplicator'); ?> </a></div>
177
- <div><a>3-<?php esc_html_e('Build', 'duplicator'); ?> </a></div>
178
- </div>
179
- <div id="dup-wiz-title">
180
- <?php esc_html_e('Step 2: System Scan', 'duplicator'); ?>
181
- </div>
182
- </div>
183
- </td>
184
- <td>
185
- <a href="?page=duplicator" class="button"><i class="fa fa-archive fa-sm"></i> <?php esc_html_e('Packages', 'duplicator'); ?></a>
186
- <a href="javascript:void(0)" class="button disabled"> <?php esc_html_e("Create New", 'duplicator'); ?></a>
187
- </td>
188
- </tr>
189
- </table>
190
- <hr class="dup-toolbar-line">
191
-
192
- <form id="form-duplicator" method="post" action="<?php echo $action_nonce_url; ?>">
193
- <?php wp_nonce_field('dup_form_opts', 'dup_form_opts_nonce_field', false); ?>
194
-
195
- <!-- PROGRESS BAR -->
196
- <div id="dup-progress-bar-area">
197
- <div class="dup-progress-title"><i class="fas fa-circle-notch fa-spin"></i> <?php esc_html_e('Scanning Site', 'duplicator'); ?></div>
198
- <div id="dup-progress-bar"></div>
199
- <b><?php esc_html_e('Please Wait...', 'duplicator'); ?></b><br/><br/>
200
- <i><?php esc_html_e('Keep this window open during the scan process.', 'duplicator'); ?></i><br/>
201
- <i><?php esc_html_e('This can take several minutes.', 'duplicator'); ?></i><br/>
202
- </div>
203
-
204
- <!-- ERROR MESSAGE -->
205
- <div id="dup-msg-error" style="display:none">
206
- <div class="dup-hdr-error"><i class="fa fa-exclamation-circle"></i> <?php esc_html_e('Scan Error', 'duplicator'); ?></div>
207
- <i><?php esc_html_e('Please try again!', 'duplicator'); ?></i><br/>
208
- <div class="dup-hdr-error-details">
209
- <b><?php esc_html_e("Server Status:", 'duplicator'); ?></b> &nbsp;
210
- <div id="dup-msg-error-response-status" style="display:inline-block"></div><br/>
211
-
212
- <b><?php esc_html_e("Error Message:", 'duplicator'); ?></b>
213
- <div id="dup-msg-error-response-text"></div>
214
- </div>
215
- </div>
216
-
217
- <!-- SUCCESS MESSAGE -->
218
- <div id="dup-msg-success" style="display:none">
219
-
220
- <div style="text-align:center">
221
- <div class="dup-hdr-success"><i class="far fa-check-square fa-lg"></i> <?php esc_html_e('Scan Complete', 'duplicator'); ?></div>
222
- <div id="dup-msg-success-subtitle">
223
- <?php esc_html_e('Process Time:', 'duplicator'); ?> <span id="data-rpt-scantime"></span>
224
- </div>
225
- </div>
226
-
227
- <div class="details">
228
- <?php
229
- include ('s2.scan2.php');
230
- echo '<br/>';
231
- include ('s2.scan3.php');
232
- ?>
233
- </div>
234
-
235
- <!-- WARNING CONTINUE -->
236
- <div id="dup-scan-warning-continue">
237
- <div class="msg1">
238
- <label for="dup-scan-warning-continue-checkbox">
239
- <?php esc_html_e('A notice status has been detected, are you sure you want to continue?', 'duplicator');?>
240
- </label>
241
- <div style="padding:8px 0">
242
- <input type="checkbox" id="dup-scan-warning-continue-checkbox" onclick="Duplicator.Pack.warningContinue(this)"/>
243
- <label for="dup-scan-warning-continue-checkbox"><?php esc_html_e('Yes. Continue with the build process!', 'duplicator');?></label>
244
- </div>
245
- </div>
246
- <div class="msg2">
247
- <label for="dup-scan-warning-continue-checkbox">
248
- <?php
249
- _e("Scan checks are not required to pass, however they could cause issues on some systems.", 'duplicator');
250
- echo '<br/>';
251
- _e("Please review the details for each section by clicking on the detail title.", 'duplicator');
252
- ?>
253
- </label>
254
- </div>
255
- </div>
256
-
257
- <div id="dup-confirm-area">
258
- <label for="duplicator-confirm-check"><?php esc_html_e('Do you want to continue?', 'duplicator');
259
- echo '<br/> ';
260
- esc_html_e('At least one or more checkboxes was checked in "Quick Filters".', 'duplicator') ?><br/>
261
- <i style="font-weight:normal"><?php esc_html_e('To apply a "Quick Filter" click the "Add Filters & Rescan" button', 'duplicator') ?></i><br/>
262
- <input type="checkbox" id="duplicator-confirm-check" onclick="jQuery('#dup-build-button').removeAttr('disabled');">
263
- <?php esc_html_e('Yes. Continue without applying any file filters.', 'duplicator') ?></label><br/>
264
- </div>
265
-
266
- <div class="dup-button-footer" style="display:none">
267
- <input type="button" value="&#9664; <?php esc_html_e("Back", 'duplicator') ?>" onclick="window.location.assign('?page=duplicator&tab=new1&_wpnonce=<?php echo wp_create_nonce('new1-package');?>')" class="button button-large" />
268
- <input type="button" value="<?php esc_attr_e("Rescan", 'duplicator') ?>" onclick="Duplicator.Pack.rescan()" class="button button-large" />
269
- <input type="submit" onclick="return Duplicator.Pack.startBuild();" value="<?php esc_attr_e("Build", 'duplicator') ?> &#9654" class="button button-primary button-large" id="dup-build-button" />
270
- </div>
271
- </div>
272
-
273
- </form>
274
-
275
- <script>
276
- jQuery(document).ready(function($)
277
- {
278
- // Performs ajax call to get scanner retults via JSON response
279
- Duplicator.Pack.runScanner = function()
280
- {
281
- var data = {action : 'duplicator_package_scan',file_notice:'<?= $core_file_notice; ?>',dir_notice:'<?= $core_dir_notice; ?>', nonce: '<?php echo wp_create_nonce('duplicator_package_scan'); ?>'}
282
- $.ajax({
283
- type: "POST",
284
- dataType: "text",
285
- cache: false,
286
- url: ajaxurl,
287
- timeout: 10000000,
288
- data: data,
289
- complete: function() {$('.dup-button-footer').show()},
290
- success: function(respData, textStatus, xHr) {
291
- try {
292
- var data = Duplicator.parseJSON(respData);
293
- } catch(err) {
294
- console.error(err);
295
- console.error('JSON parse failed for response data: ' + respData);
296
- $('#dup-progress-bar-area').hide();
297
- var status = xHr.status + ' -' + xHr.statusText;
298
- $('#dup-msg-error-response-status').html(status)
299
- $('#dup-msg-error-response-text').html(xHr.responseText);
300
- $('#dup-msg-error').show(200);
301
- console.log(data);
302
- return false;
303
- }
304
- Duplicator.Pack.loadScanData(data);
305
- },
306
- error: function(data) {
307
- $('#dup-progress-bar-area').hide();
308
- var status = data.status + ' -' + data.statusText;
309
- $('#dup-msg-error-response-status').html(status)
310
- $('#dup-msg-error-response-text').html(data.responseText);
311
- $('#dup-msg-error').show(200);
312
- console.log(data);
313
- }
314
- });
315
- }
316
-
317
- //Loads the scanner data results into the various sections of the screen
318
- Duplicator.Pack.loadScanData = function(data)
319
- {
320
- $('#dup-progress-bar-area').hide();
321
-
322
- //ERROR: Data object is corrupt or empty return error
323
- if (data == undefined || data.RPT == undefined) {
324
- Duplicator.Pack.intErrorView();
325
- console.log('JSON Report Data:');
326
- console.log(data);
327
- return;
328
- }
329
-
330
- $('#data-rpt-scantime').text(data.RPT.ScanTime || 0);
331
- Duplicator.Pack.intServerData(data);
332
- Duplicator.Pack.initArchiveFilesData(data);
333
- Duplicator.Pack.initArchiveDBData(data);
334
-
335
- //Addon Sites
336
- $('#data-arc-status-addonsites').html(Duplicator.Pack.setScanStatus(data.ARC.Status.AddonSites));
337
- if (data.ARC.FilterInfo.Dirs.AddonSites !== undefined && data.ARC.FilterInfo.Dirs.AddonSites.length > 0) {
338
- $("#addonsites-block").show();
339
- }
340
-
341
- $('#dup-msg-success').show();
342
-
343
- //Waring Check
344
- var warnCount = data.RPT.Warnings || 0;
345
- if (warnCount > 0) {
346
- $('#dup-scan-warning-continue').show();
347
- $('#dup-build-button').prop("disabled",true).removeClass('button-primary');
348
- if ($('#dup-scan-warning-continue-checkbox').is(':checked')) {
349
- $('#dup-build-button').removeAttr('disabled').addClass('button-primary');
350
- }
351
- } else {
352
- $('#dup-scan-warning-continue').hide();
353
- $('#dup-build-button').prop("disabled",false).addClass('button-primary');
354
- }
355
-
356
- <?php if (DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::DupArchive) :?>
357
- Duplicator.Pack.initLiteLimitData(data);
358
- <?php endif; ?>
359
- }
360
-
361
- Duplicator.Pack.startBuild = function()
362
- {
363
- if ($('#duplicator-confirm-check').is(":checked")) {
364
- $('#form-duplicator').submit();
365
- return true;
366
- }
367
-
368
- var sizeChecks = $('#hb-files-large-result input:checked');
369
- var addonChecks = $('#hb-addon-sites-result input:checked');
370
- var utf8Checks = $('#hb-files-utf8-result input:checked');
371
- if (sizeChecks.length > 0 || addonChecks.length > 0 || utf8Checks.length > 0) {
372
- $('#dup-confirm-area').show();
373
- $('#dup-build-button').prop('disabled', true);
374
- return false;
375
- } else {
376
- $('#form-duplicator').submit();
377
- }
378
- }
379
-
380
- //Toggles each scan item to hide/show details
381
- Duplicator.Pack.toggleScanItem = function(item)
382
- {
383
- var $info = $(item).parents('div.scan-item').children('div.info');
384
- var $text = $(item).find('div.text i.fa');
385
- if ($info.is(":hidden")) {
386
- $text.addClass('fa-caret-down').removeClass('fa-caret-right');
387
- $info.show();
388
- } else {
389
- $text.addClass('fa-caret-right').removeClass('fa-caret-down');
390
- $info.hide(250);
391
- }
392
- }
393
-
394
- //Returns the scanner without a page refresh
395
- Duplicator.Pack.rescan = function()
396
- {
397
- $('#dup-msg-success,#dup-msg-error, #dup-confirm-area, .dup-button-footer').hide();
398
- $('#dup-progress-bar-area').show();
399
- Duplicator.Pack.runScanner();
400
- }
401
-
402
- //Allows user to continue with build if warnings found
403
- Duplicator.Pack.warningContinue = function(checkbox)
404
- {
405
- ($(checkbox).is(':checked'))
406
- ? $('#dup-build-button').prop('disabled',false).addClass('button-primary')
407
- : $('#dup-build-button').prop('disabled',true).removeClass('button-primary');
408
- }
409
-
410
- //Show the error message if the JSON data is corrupted
411
- Duplicator.Pack.intErrorView = function()
412
- {
413
- var html_msg;
414
- html_msg = '<?php esc_html_e("Unable to perform a full scan, please try the following actions:", 'duplicator') ?><br/><br/>';
415
- html_msg += '<?php esc_html_e("1. Go back and create a root path directory filter to validate the site is scan-able.", 'duplicator') ?><br/>';
416
- html_msg += '<?php esc_html_e("2. Continue to add/remove filters to isolate which path is causing issues.", 'duplicator') ?><br/>';
417
- html_msg += '<?php esc_html_e("3. This message will go away once the correct filters are applied.", 'duplicator') ?><br/><br/>';
418
-
419
- html_msg += '<?php esc_html_e("Common Issues:", 'duplicator') ?><ul>';
420
- html_msg += '<li><?php esc_html_e("- On some budget hosts scanning over 30k files can lead to timeout/gateway issues. Consider scanning only your main WordPress site and avoid trying to backup other external directories.", 'duplicator') ?></li>';
421
- html_msg += '<li><?php esc_html_e("- Symbolic link recursion can cause timeouts. Ask your server admin if any are present in the scan path. If they are add the full path as a filter and try running the scan again.", 'duplicator') ?></li>';
422
- html_msg += '</ul>';
423
- $('#dup-msg-error-response-status').html('Scan Path Error [<?php echo duplicator_get_abs_path(); ?>]');
424
- $('#dup-msg-error-response-text').html(html_msg);
425
- $('#dup-msg-error').show(200);
426
- }
427
-
428
- //Sets various can statuses
429
- Duplicator.Pack.setScanStatus = function(status)
430
- {
431
- var result;
432
- switch (status) {
433
- case false : result = '<div class="scan-warn"><i class="fa fa-exclamation-triangle fa-sm"></i></div>'; break;
434
- case 'Warn' : result = '<div class="badge badge-warn"><?php esc_html_e("Notice", 'duplicator') ?></div>'; break;
435
- case true : result = '<div class="scan-good"><i class="fa fa-check"></i></div>'; break;
436
- case 'Good' : result = '<div class="badge badge-pass"><?php esc_html_e("Good", 'duplicator') ?></div>'; break;
437
- case 'Fail' : result = '<div class="badge badge-warn"><?php esc_html_e("Fail", 'duplicator') ?></div>'; break;
438
- default :
439
- result = 'unable to read';
440
- }
441
- return result;
442
- }
443
-
444
- //PAGE INIT:
445
- Duplicator.UI.AnimateProgressBar('dup-progress-bar');
446
- Duplicator.Pack.runScanner();
447
-
448
- });
449
  </script>
1
+ <?php
2
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+ //Nonce Check
4
+ if (! isset( $_POST['dup_form_opts_nonce_field'] ) || ! wp_verify_nonce( sanitize_text_field($_POST['dup_form_opts_nonce_field']), 'dup_form_opts' ) ) {
5
+ DUP_UI_Notice::redirect('admin.php?page=duplicator&tab=new1&_wpnonce='.wp_create_nonce('new1-package'));
6
+ }
7
+
8
+ global $wp_version;
9
+ wp_enqueue_script('dup-handlebars');
10
+
11
+ if (empty($_POST)) {
12
+ //F5 Refresh Check
13
+ $redirect = admin_url('admin.php?page=duplicator&tab=new1');
14
+ $redirect_nonce_url = wp_nonce_url($redirect, 'new1-package');
15
+ die("<script>window.location.href = '{$reredirect_nonce_url}'</script>");
16
+ }
17
+
18
+ $Package = new DUP_Package();
19
+ $Package->saveActive($_POST);
20
+
21
+ DUP_Settings::Set('active_package_id', -1);
22
+ DUP_Settings::Save();
23
+
24
+ $Package = DUP_Package::getActive();
25
+
26
+ $mysqldump_on = DUP_Settings::Get('package_mysqldump') && DUP_DB::getMySqlDumpPath();
27
+ $mysqlcompat_on = isset($Package->Database->Compatible) && strlen($Package->Database->Compatible);
28
+ $mysqlcompat_on = ($mysqldump_on && $mysqlcompat_on) ? true : false;
29
+ $dbbuild_mode = ($mysqldump_on) ? 'mysqldump' : 'PHP';
30
+ $zip_check = DUP_Util::getZipPath();
31
+
32
+ $action_url = admin_url('admin.php?page=duplicator&tab=new3');
33
+ $action_nonce_url = wp_nonce_url($action_url, 'new3-package');
34
+ ?>
35
+
36
+ <style>
37
+ /*PROGRESS-BAR - RESULTS - ERROR */
38
+ form#form-duplicator {text-align:center; max-width:750px; min-height:200px; margin:0px auto 0px auto; padding:0px;}
39
+ div.dup-progress-title {font-size:22px; padding:5px 0 20px 0; font-weight:bold}
40
+ div#dup-msg-success {padding:0 5px 5px 5px; text-align:left}
41
+ div#dup-msg-success div.details {padding:10px 15px 10px 15px; margin:5px 0 15px 0; background:#fff; border-radius:5px; border:1px solid #ddd; box-shadow:0 8px 6px -6px #999; }
42
+ div#dup-msg-success div.details-title {font-size:20px; border-bottom:1px solid #dfdfdf; padding:5px; margin:0 0 10px 0; font-weight:bold}
43
+ div#dup-msg-success-subtitle {color:#999; margin:0; font-size:11px}
44
+ div.dup-scan-filter-status {display:inline; font-size:11px; margin-right:10px; color:#630f0f;}
45
+ div#dup-msg-error {color:#A62426; padding:5px; max-width:790px;}
46
+ div#dup-msg-error-response-text { max-height:500px; overflow-y:scroll; border:1px solid silver; border-radius:3px; padding:10px;background:#fff}
47
+ div.dup-hdr-error-details {text-align:left; margin:20px 0}
48
+ i[data-tooltip].fa-question-circle {color:#555}
49
+
50
+ /*SCAN ITEMS: Sections */
51
+ div.scan-header { font-size:16px; padding:7px 5px 7px 7px; font-weight:bold; background-color:#E0E0E0; border-bottom:0px solid #C0C0C0 }
52
+ div.scan-header-details {float:right; margin-top:-5px}
53
+ div.scan-item {border:1px solid #E0E0E0; border-bottom:none;}
54
+ div.scan-item-first { border-top-right-radius:4px; border-top-left-radius:4px}
55
+ div.scan-item-last {border-bottom:1px solid #E0E0E0}
56
+ div.scan-item div.title {background-color:#F1F1F1; width:100%; padding:8px 0 8px 0; cursor:pointer; height:20px;}
57
+ div.scan-item div.title:hover {background-color:#ECECEC;}
58
+ div.scan-item div.text {font-weight:bold; font-size:14px; float:left; position:relative; left:10px}
59
+ div.scan-item div.badge {float:right; border-radius:4px; color:#fff; min-width:40px; text-align:center; position:relative; right:10px; font-size:12px; padding:0 3px 1px 3px}
60
+ div.scan-item div.badge-pass {background:#197b19;}
61
+ div.scan-item div.badge-warn {background:#636363;}
62
+ div.scan-item div.info {display:none; padding:10px; background:#fff}
63
+ div.scan-good {display:inline-block; color:green;font-weight:bold;}
64
+ div.scan-warn {display:inline-block; color:#d61212;font-weight:bold;}
65
+ div.dup-more-details {float:right; font-size:14px}
66
+ div.dup-more-details a{color:black}
67
+ div.dup-more-details a:hover {color:#777; cursor:pointer}
68
+ div.dup-more-details:hover {color:#777; cursor:pointer}
69
+
70
+ /*FILES */
71
+ div#data-arc-size1 {display:inline-block; font-size:11px; margin-right:1px;}
72
+ sup.dup-small-ext-type {font-size:11px; font-weight: normal; font-style: italic}
73
+ i.data-size-help { font-size:12px; display:inline-block; margin:0; padding:0}
74
+ div.dup-data-size-uncompressed {font-size:10px; text-align: right; padding:0; margin:-7px 0 0 0; font-style: italic; font-weight: normal; border:0px solid red; clear:both}
75
+ div.hb-files-style div.container {border:1px solid #E0E0E0; border-radius:4px; margin:5px 0 10px 0}
76
+ div.hb-files-style div.container b {font-weight:bold}
77
+ div.hb-files-style div.container div.divider {margin-bottom:2px; font-weight:bold}
78
+ div.hb-files-style div.data {padding:8px; line-height:21px; height:175px; overflow-y:scroll; }
79
+ div.hb-files-style div.hdrs {padding:0 4px 4px 6px; border-bottom:1px solid #E0E0E0; font-weight:bold}
80
+ div.hb-files-style div.hdrs sup i.fa {font-size:11px}
81
+ div.hb-files-style div.hdrs-up-down {float:right; margin:2px 12px 0 0}
82
+ div.hb-files-style i.dup-nav-toggle:hover {cursor:pointer; color:#999}
83
+ div.hb-files-style div.directory {margin-left:12px}
84
+ div.hb-files-style div.directory i.size {font-size:11px; font-style:normal; display:inline-block; min-width:50px}
85
+ div.hb-files-style div.directory i.count {font-size:11px; font-style:normal; display:inline-block; min-width:20px}
86
+ div.hb-files-style div.directory i.empty {width:15px; display:inline-block}
87
+ div.hb-files-style div.directory i.dup-nav {cursor:pointer}
88
+ div.hb-files-style div.directory i.fa {width:8px}
89
+ div.hb-files-style div.directory i.chk-off {width:20px; color:#777; cursor: help; margin:0; font-size:1.25em}
90
+ div.hb-files-style div.directory label {font-weight:bold; cursor:pointer; vertical-align:top;display:inline-block; width:475px; white-space: nowrap; overflow:hidden; text-overflow:ellipsis;}
91
+ div.hb-files-style div.directory label:hover {color:#025d02}
92
+ div.hb-files-style div.files {padding:2px 0 0 35px; font-size:12px; display:none; line-height:18px}
93
+ div.hb-files-style div.files i.size {font-style:normal; display:inline-block; min-width:50px}
94
+ div.hb-files-style div.files label {font-weight: normal; font-size:11px; vertical-align:top;display:inline-block;width:450px; white-space: nowrap; overflow:hidden; text-overflow:ellipsis;}
95
+ div.hb-files-style div.files label:hover {color:#025d02; cursor: pointer}
96
+ div.hb-files-style div.apply-btn {text-align:right; margin: 1px 0 10px 0; width:100%}
97
+ div.hb-files-style div.apply-warn {float:left; font-size:11px; color:maroon; margin-top:-7px; font-style: italic; display:none; text-align: left}
98
+
99
+ div#size-more-details {display:none; margin:5px 0 20px 0; border:1px solid #dfdfdf; padding:8px; border-radius: 4px; background-color: #F1F1F1}
100
+ div#size-more-details ul {list-style-type:circle; padding-left:20px; margin:0}
101
+ div#size-more-details li {margin:0}
102
+
103
+ /*DATABASE*/
104
+ div#dup-scan-db-info {margin-top:5px}
105
+ div#data-db-tablelist {max-height:250px; overflow-y:scroll; border:1px solid silver; padding:8px; background: #efefef; border-radius: 4px}
106
+ div#data-db-tablelist td{padding:0 5px 3px 20px; min-width:100px}
107
+ div#data-db-size1, div#data-ll-totalsize {display:inline-block; font-size:11px; margin-right:1px;}
108
+ /*FILES */
109
+ div#dup-confirm-area {color:maroon; display:none; text-align: center; font-size:14px; line-height:24px; font-weight: bold; margin: -5px 0 10px 0}
110
+ div#dup-confirm-area label {font-size:14px !important}
111
+
112
+ /*WARNING-CONTINUE*/
113
+ div#dup-scan-warning-continue {display:none; text-align:center; padding:0 0 15px 0}
114
+ div#dup-scan-warning-continue div.msg1 label{font-size:16px; color:#630f0f}
115
+ div#dup-scan-warning-continue div.msg2 {padding:2px; line-height:13px}
116
+ div#dup-scan-warning-continue div.msg2 label {font-size:11px !important}
117
+ div.dup-pro-support {text-align:center; font-style:italic; font-size:13px; margin-top:20px;font-weight:bold}
118
+
119
+ /*DIALOG WINDOWS*/
120
+ div#arc-details-dlg {font-size:12px; line-height:18px !important}
121
+ div#arc-details-dlg h2 {margin:0; padding:0 0 5px 0; border-bottom:1px solid #dfdfdf;}
122
+ div#arc-details-dlg hr {margin:3px 0 10px 0}
123
+ div#arc-details-dlg table#db-area {margin:0; width:98%}
124
+ div#arc-details-dlg table#db-area td {padding:0;}
125
+ div#arc-details-dlg table#db-area td:first-child {font-weight:bold; white-space:nowrap; width:100px}
126
+ div#arc-details-dlg div.filter-area {height:245px; overflow-y:scroll; border:1px solid #dfdfdf; padding:8px; margin:2px 0}
127
+ div#arc-details-dlg div.file-info {padding:0 0 10px 15px; width:500px; white-space:nowrap;}
128
+ div#arc-details-dlg div.file-info i.fa-question-circle { margin-right: 5px; font-size: 11px;}
129
+
130
+ div#arc-paths-dlg textarea.path-dirs,
131
+ textarea.path-files {font-size:12px; border: 1px solid silver; padding: 10px; background: #fff; margin:5px; height:125px; width:100%; white-space:pre}
132
+ div#arc-paths-dlg div.copy-button {float:right;}
133
+ div#arc-paths-dlg div.copy-button button {font-size:12px}
134
+
135
+ /*FOOTER*/
136
+ div.dup-button-footer {text-align:center; margin:0}
137
+ button.button {font-size:15px !important; height:30px !important; font-weight:bold; padding:3px 5px 5px 5px !important;}
138
+ i.scan-warn {color:#630f0f;}
139
+ </style>
140
+
141
+ <?php
142
+ $validator = $Package->validateInputs();
143
+ if (!$validator->isSuccess()) {
144
+ ?>
145
+ <form id="form-duplicator" method="post" action="<?php echo $action_nonce_url; ?>">
146
+ <!-- ERROR MESSAGE -->
147
+ <div id="dup-msg-error" >
148
+ <div class="dup-hdr-error"><i class="fa fa-exclamation-circle"></i> <?php _e('Input fields not valid', 'duplicator'); ?></div>
149
+ <i><?php esc_html_e('Please try again!', 'duplicator'); ?></i><br/>
150
+ <div class="dup-hdr-error-details">
151
+ <b><?php esc_html_e("Error Message:", 'duplicator'); ?></b>
152
+ <div id="dup-msg-error-response-text">
153
+ <ul>
154
+ <?php
155
+ $validator->getErrorsFormat("<li>%s</li>");
156
+ ?>
157
+ </ul>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ <input type="button" value="&#9664; <?php esc_html_e("Back", 'duplicator') ?>" onclick="window.location.assign('?page=duplicator&tab=new1&_wpnonce=<?php echo wp_create_nonce('new1-package'); ?>')" class="button button-large" />
162
+ </form>
163
+ <?php
164
+ return;
165
+ }
166
+ ?>
167
+
168
+ <!-- =========================================
169
+ TOOL BAR:STEPS -->
170
+ <table id="dup-toolbar">
171
+ <tr valign="top">
172
+ <td style="white-space:nowrap">
173
+ <div id="dup-wiz">
174
+ <div id="dup-wiz-steps">
175
+ <div class="completed-step"><a>1-<?php esc_html_e('Setup', 'duplicator'); ?></a></div>
176
+ <div class="active-step"><a>2-<?php esc_html_e('Scan', 'duplicator'); ?> </a></div>
177
+ <div><a>3-<?php esc_html_e('Build', 'duplicator'); ?> </a></div>
178
+ </div>
179
+ <div id="dup-wiz-title">
180
+ <?php esc_html_e('Step 2: System Scan', 'duplicator'); ?>
181
+ </div>
182
+ </div>
183
+ </td>
184
+ <td>
185
+ <a href="?page=duplicator" class="button"><i class="fa fa-archive fa-sm"></i> <?php esc_html_e('Packages', 'duplicator'); ?></a>
186
+ <a href="javascript:void(0)" class="button disabled"> <?php esc_html_e("Create New", 'duplicator'); ?></a>
187
+ </td>
188
+ </tr>
189
+ </table>
190
+ <hr class="dup-toolbar-line">
191
+
192
+ <form id="form-duplicator" method="post" action="<?php echo $action_nonce_url; ?>">
193
+ <?php wp_nonce_field('dup_form_opts', 'dup_form_opts_nonce_field', false); ?>
194
+
195
+ <!-- PROGRESS BAR -->
196
+ <div id="dup-progress-bar-area">
197
+ <div class="dup-progress-title"><i class="fas fa-circle-notch fa-spin"></i> <?php esc_html_e('Scanning Site', 'duplicator'); ?></div>
198
+ <div id="dup-progress-bar"></div>
199
+ <b><?php esc_html_e('Please Wait...', 'duplicator'); ?></b><br/><br/>
200
+ <i><?php esc_html_e('Keep this window open during the scan process.', 'duplicator'); ?></i><br/>
201
+ <i><?php esc_html_e('This can take several minutes.', 'duplicator'); ?></i><br/>
202
+ </div>
203
+
204
+ <!-- ERROR MESSAGE -->
205
+ <div id="dup-msg-error" style="display:none">
206
+ <div class="dup-hdr-error"><i class="fa fa-exclamation-circle"></i> <?php esc_html_e('Scan Error', 'duplicator'); ?></div>
207
+ <i><?php esc_html_e('Please try again!', 'duplicator'); ?></i><br/>
208
+ <div class="dup-hdr-error-details">
209
+ <b><?php esc_html_e("Server Status:", 'duplicator'); ?></b> &nbsp;
210
+ <div id="dup-msg-error-response-status" style="display:inline-block"></div><br/>
211
+
212
+ <b><?php esc_html_e("Error Message:", 'duplicator'); ?></b>
213
+ <div id="dup-msg-error-response-text"></div>
214
+ </div>
215
+ </div>
216
+
217
+ <!-- SUCCESS MESSAGE -->
218
+ <div id="dup-msg-success" style="display:none">
219
+
220
+ <div style="text-align:center">
221
+ <div class="dup-hdr-success"><i class="far fa-check-square fa-lg"></i> <?php esc_html_e('Scan Complete', 'duplicator'); ?></div>
222
+ <div id="dup-msg-success-subtitle">
223
+ <?php esc_html_e('Process Time:', 'duplicator'); ?> <span id="data-rpt-scantime"></span>
224
+ </div>
225
+ </div>
226
+
227
+ <div class="details">
228
+ <?php
229
+ include ('s2.scan2.php');
230
+ echo '<br/>';
231
+ include ('s2.scan3.php');
232
+ ?>
233
+ </div>
234
+
235
+ <!-- WARNING CONTINUE -->
236
+ <div id="dup-scan-warning-continue">
237
+ <div class="msg1">
238
+ <label for="dup-scan-warning-continue-checkbox">
239
+ <?php esc_html_e('A notice status has been detected, are you sure you want to continue?', 'duplicator');?>
240
+ </label>
241
+ <div style="padding:8px 0">
242
+ <input type="checkbox" id="dup-scan-warning-continue-checkbox" onclick="Duplicator.Pack.warningContinue(this)"/>
243
+ <label for="dup-scan-warning-continue-checkbox"><?php esc_html_e('Yes. Continue with the build process!', 'duplicator');?></label>
244
+ </div>
245
+ </div>
246
+ <div class="msg2">
247
+ <label for="dup-scan-warning-continue-checkbox">
248
+ <?php
249
+ _e("Scan checks are not required to pass, however they could cause issues on some systems.", 'duplicator');
250
+ echo '<br/>';
251
+ _e("Please review the details for each section by clicking on the detail title.", 'duplicator');
252
+ ?>
253
+ </label>
254
+ </div>
255
+ </div>
256
+
257
+ <div id="dup-confirm-area">
258
+ <label for="duplicator-confirm-check"><?php esc_html_e('Do you want to continue?', 'duplicator');
259
+ echo '<br/> ';
260
+ esc_html_e('At least one or more checkboxes was checked in "Quick Filters".', 'duplicator') ?><br/>
261
+ <i style="font-weight:normal"><?php esc_html_e('To apply a "Quick Filter" click the "Add Filters & Rescan" button', 'duplicator') ?></i><br/>
262
+ <input type="checkbox" id="duplicator-confirm-check" onclick="jQuery('#dup-build-button').removeAttr('disabled');">
263
+ <?php esc_html_e('Yes. Continue without applying any file filters.', 'duplicator') ?></label><br/>
264
+ </div>
265
+
266
+ <div class="dup-button-footer" style="display:none">
267
+ <input type="button" value="&#9664; <?php esc_html_e("Back", 'duplicator') ?>" onclick="window.location.assign('?page=duplicator&tab=new1&_wpnonce=<?php echo wp_create_nonce('new1-package');?>')" class="button button-large" />
268
+ <input type="button" value="<?php esc_attr_e("Rescan", 'duplicator') ?>" onclick="Duplicator.Pack.rescan()" class="button button-large" />
269
+ <input type="submit" onclick="return Duplicator.Pack.startBuild();" value="<?php esc_attr_e("Build", 'duplicator') ?> &#9654" class="button button-primary button-large" id="dup-build-button" />
270
+ </div>
271
+ </div>
272
+
273
+ </form>
274
+
275
+ <script>
276
+ jQuery(document).ready(function($)
277
+ {
278
+ // Performs ajax call to get scanner retults via JSON response
279
+ Duplicator.Pack.runScanner = function()
280
+ {
281
+ var data = {action : 'duplicator_package_scan',file_notice:'<?= $core_file_notice; ?>',dir_notice:'<?= $core_dir_notice; ?>', nonce: '<?php echo wp_create_nonce('duplicator_package_scan'); ?>'}
282
+ $.ajax({
283
+ type: "POST",
284
+ dataType: "text",
285
+ cache: false,
286
+ url: ajaxurl,
287
+ timeout: 10000000,
288
+ data: data,
289
+ complete: function() {$('.dup-button-footer').show()},
290
+ success: function(respData, textStatus, xHr) {
291
+ try {
292
+ var data = Duplicator.parseJSON(respData);
293
+ } catch(err) {
294
+ console.error(err);
295
+ console.error('JSON parse failed for response data: ' + respData);
296
+ $('#dup-progress-bar-area').hide();
297
+ var status = xHr.status + ' -' + xHr.statusText;
298
+ $('#dup-msg-error-response-status').html(status)
299
+ $('#dup-msg-error-response-text').html(xHr.responseText);
300
+ $('#dup-msg-error').show(200);
301
+ console.log(data);
302
+ return false;
303
+ }
304
+ Duplicator.Pack.loadScanData(data);
305
+ },
306
+ error: function(data) {
307
+ $('#dup-progress-bar-area').hide();
308
+ var status = data.status + ' -' + data.statusText;
309
+ $('#dup-msg-error-response-status').html(status)
310
+ $('#dup-msg-error-response-text').html(data.responseText);
311
+ $('#dup-msg-error').show(200);
312
+ console.log(data);
313
+ }
314
+ });
315
+ }
316
+
317
+ //Loads the scanner data results into the various sections of the screen
318
+ Duplicator.Pack.loadScanData = function(data)
319
+ {
320
+ $('#dup-progress-bar-area').hide();
321
+
322
+ //ERROR: Data object is corrupt or empty return error
323
+ if (data == undefined || data.RPT == undefined) {
324
+ Duplicator.Pack.intErrorView();
325
+ console.log('JSON Report Data:');
326
+ console.log(data);
327
+ return;
328
+ }
329
+
330
+ $('#data-rpt-scantime').text(data.RPT.ScanTime || 0);
331
+ Duplicator.Pack.intServerData(data);
332
+ Duplicator.Pack.initArchiveFilesData(data);
333
+ Duplicator.Pack.initArchiveDBData(data);
334
+
335
+ //Addon Sites
336
+ $('#data-arc-status-addonsites').html(Duplicator.Pack.setScanStatus(data.ARC.Status.AddonSites));
337
+ if (data.ARC.FilterInfo.Dirs.AddonSites !== undefined && data.ARC.FilterInfo.Dirs.AddonSites.length > 0) {
338
+ $("#addonsites-block").show();
339
+ }
340
+
341
+ $('#dup-msg-success').show();
342
+
343
+ //Waring Check
344
+ var warnCount = data.RPT.Warnings || 0;
345
+ if (warnCount > 0) {
346
+ $('#dup-scan-warning-continue').show();
347
+ $('#dup-build-button').prop("disabled",true).removeClass('button-primary');
348
+ if ($('#dup-scan-warning-continue-checkbox').is(':checked')) {
349
+ $('#dup-build-button').removeAttr('disabled').addClass('button-primary');
350
+ }
351
+ } else {
352
+ $('#dup-scan-warning-continue').hide();
353
+ $('#dup-build-button').prop("disabled",false).addClass('button-primary');
354
+ }
355
+
356
+ <?php if (DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::DupArchive) :?>
357
+ Duplicator.Pack.initLiteLimitData(data);
358
+ <?php endif; ?>
359
+ }
360
+
361
+ Duplicator.Pack.startBuild = function()
362
+ {
363
+ if ($('#duplicator-confirm-check').is(":checked")) {
364
+ $('#form-duplicator').submit();
365
+ return true;
366
+ }
367
+
368
+ var sizeChecks = $('#hb-files-large-result input:checked');
369
+ var addonChecks = $('#hb-addon-sites-result input:checked');
370
+ var utf8Checks = $('#hb-files-utf8-result input:checked');
371
+ if (sizeChecks.length > 0 || addonChecks.length > 0 || utf8Checks.length > 0) {
372
+ $('#dup-confirm-area').show();
373
+ $('#dup-build-button').prop('disabled', true);
374
+ return false;
375
+ } else {
376
+ $('#form-duplicator').submit();
377
+ }
378
+ }
379
+
380
+ //Toggles each scan item to hide/show details
381
+ Duplicator.Pack.toggleScanItem = function(item)
382
+ {
383
+ var $info = $(item).parents('div.scan-item').children('div.info');
384
+ var $text = $(item).find('div.text i.fa');
385
+ if ($info.is(":hidden")) {
386
+ $text.addClass('fa-caret-down').removeClass('fa-caret-right');
387
+ $info.show();
388
+ } else {
389
+ $text.addClass('fa-caret-right').removeClass('fa-caret-down');
390
+ $info.hide(250);
391
+ }
392
+ }
393
+
394
+ //Returns the scanner without a page refresh
395
+ Duplicator.Pack.rescan = function()
396
+ {
397
+ $('#dup-msg-success,#dup-msg-error, #dup-confirm-area, .dup-button-footer').hide();
398
+ $('#dup-progress-bar-area').show();
399
+ Duplicator.Pack.runScanner();
400
+ }
401
+
402
+ //Allows user to continue with build if warnings found
403
+ Duplicator.Pack.warningContinue = function(checkbox)
404
+ {
405
+ ($(checkbox).is(':checked'))
406
+ ? $('#dup-build-button').prop('disabled',false).addClass('button-primary')
407
+ : $('#dup-build-button').prop('disabled',true).removeClass('button-primary');
408
+ }
409
+
410
+ //Show the error message if the JSON data is corrupted
411
+ Duplicator.Pack.intErrorView = function()
412
+ {
413
+ var html_msg;
414
+ html_msg = '<?php esc_html_e("Unable to perform a full scan, please try the following actions:", 'duplicator') ?><br/><br/>';
415
+ html_msg += '<?php esc_html_e("1. Go back and create a root path directory filter to validate the site is scan-able.", 'duplicator') ?><br/>';
416
+ html_msg += '<?php esc_html_e("2. Continue to add/remove filters to isolate which path is causing issues.", 'duplicator') ?><br/>';
417
+ html_msg += '<?php esc_html_e("3. This message will go away once the correct filters are applied.", 'duplicator') ?><br/><br/>';
418
+
419
+ html_msg += '<?php esc_html_e("Common Issues:", 'duplicator') ?><ul>';
420
+ html_msg += '<li><?php esc_html_e("- On some budget hosts scanning over 30k files can lead to timeout/gateway issues. Consider scanning only your main WordPress site and avoid trying to backup other external directories.", 'duplicator') ?></li>';
421
+ html_msg += '<li><?php esc_html_e("- Symbolic link recursion can cause timeouts. Ask your server admin if any are present in the scan path. If they are add the full path as a filter and try running the scan again.", 'duplicator') ?></li>';
422
+ html_msg += '</ul>';
423
+ $('#dup-msg-error-response-status').html('Scan Path Error [<?php echo duplicator_get_abs_path(); ?>]');
424
+ $('#dup-msg-error-response-text').html(html_msg);
425
+ $('#dup-msg-error').show(200);
426
+ }
427
+
428
+ //Sets various can statuses
429
+ Duplicator.Pack.setScanStatus = function(status)
430
+ {
431
+ var result;
432
+ switch (status) {
433
+ case false : result = '<div class="scan-warn"><i class="fa fa-exclamation-triangle fa-sm"></i></div>'; break;
434
+ case 'Warn' : result = '<div class="badge badge-warn"><?php esc_html_e("Notice", 'duplicator') ?></div>'; break;
435
+ case true : result = '<div class="scan-good"><i class="fa fa-check"></i></div>'; break;
436
+ case 'Good' : result = '<div class="badge badge-pass"><?php esc_html_e("Good", 'duplicator') ?></div>'; break;
437
+ case 'Fail' : result = '<div class="badge badge-warn"><?php esc_html_e("Fail", 'duplicator') ?></div>'; break;
438
+ default :
439
+ result = 'unable to read';
440
+ }
441
+ return result;
442
+ }
443
+
444
+ //PAGE INIT:
445
+ Duplicator.UI.AnimateProgressBar('dup-progress-bar');
446
+ Duplicator.Pack.runScanner();
447
+
448
+ });
449
  </script>
views/packages/main/s2.scan2.php CHANGED
@@ -1,214 +1,231 @@
1
- <?php
2
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
- ?>
4
- <!-- ================================================================
5
- SERVER -->
6
- <div class="details-title">
7
- <i class="fa fa-hdd-o"></i> <?php esc_html_e("Server", 'duplicator'); ?>
8
- <div class="dup-more-details" title="<?php esc_attr_e('Show Diagnostics', 'duplicator');?>">
9
- <a href="?page=duplicator-tools&tab=diagnostics" target="_blank"><i class="fa fa-microchip"></i></a>
10
- </div>
11
- </div>
12
-
13
- <!-- ============
14
- PHP SETTINGS -->
15
- <div class="scan-item">
16
-
17
- <?php
18
-
19
- //TODO Login Need to go here
20
-
21
- $core_dir_included = array();
22
- $core_files_included = array();
23
- //by default fault
24
- $core_dir_notice = false;
25
- $core_file_notice = false;
26
-
27
- if (!$Package->Archive->ExportOnlyDB && isset($_POST['filter-on']) && isset($_POST['filter-dirs'])) {
28
-
29
- //findout matched core directories
30
- $filter_dirs = explode(";", trim(sanitize_text_field(($_POST['filter-dirs']))));
31
-
32
- // clean possible blank spaces before and after the paths
33
- for ($i = 0; $i < count($filter_dirs); $i++) {
34
- $filter_dirs[$i] = trim($filter_dirs[$i]);
35
- $filter_dirs[$i] = (substr($filter_dirs[$i], -1) == "/") ? substr($filter_dirs[$i],0, strlen($filter_dirs[$i])-1):$filter_dirs[$i] ;
36
-
37
- }
38
- $core_dir_included = array_intersect($filter_dirs,
39
- DUP_Util::getWPCoreDirs());
40
- if (count($core_dir_included)) $core_dir_notice = true;
41
-
42
-
43
- //find out core files
44
- $filter_files = explode(";", trim($_POST['filter-files']));
45
-
46
- // clean possible blank spaces before and after the paths
47
- for ($i = 0; $i < count($filter_files); $i++) {
48
- $filter_files[$i] = trim($filter_files[$i]);
49
- }
50
- $core_files_included = array_intersect($filter_files,
51
- DUP_Util::getWPCoreFiles());
52
- if (count($core_files_included)) $core_file_notice = true;
53
- }
54
- ?>
55
- <div class='title' onclick="Duplicator.Pack.toggleScanItem(this);">
56
- <div class="text"><i class="fa fa-caret-right"></i> <?php esc_html_e('Setup', 'duplicator');?></div>
57
- <div id="data-srv-php-all"></div>
58
- </div>
59
- <div class="info">
60
- <?php
61
- //WEB SERVER
62
- $web_servers = implode(', ', $GLOBALS['DUPLICATOR_SERVER_LIST']);
63
- echo '<span id="data-srv-php-websrv"></span>&nbsp;<b>' . esc_html__('Web Server', 'duplicator') . ":</b>&nbsp; '".esc_attr($_SERVER['SERVER_SOFTWARE'])."' <br/>";
64
- _e("Supported web servers: ", 'duplicator');
65
- echo "<i>".esc_html($web_servers)."</i>";
66
-
67
- //PHP VERSION
68
- echo '<hr size="1" /><span id="data-srv-php-version"></span>&nbsp;<b>' . esc_html__('PHP Version', 'duplicator') . "</b> <br/>";
69
- _e('The minimum PHP version supported by Duplicator is 5.2.9. It is highly recommended to use PHP 5.3+ for improved stability. For international language support please use PHP 7.0+.', 'duplicator');
70
-
71
- //OPEN_BASEDIR
72
- $test = ini_get("open_basedir");
73
- $test = ($test) ? 'ON' : 'OFF';
74
- echo '<hr size="1" /><span id="data-srv-php-openbase"></span>&nbsp;<b>' . esc_html__('PHP Open Base Dir', 'duplicator') . ":</b>&nbsp; '{$test}' <br/>";
75
- _e('Issues might occur when [open_basedir] is enabled. Work with your server admin to disable this value in the php.ini file if you’re having issues building a package.', 'duplicator');
76
- echo "&nbsp;<i><a href='http://php.net/manual/en/ini.core.php#ini.open-basedir' target='_blank'>[" . esc_html__('details', 'duplicator') . "]</a></i><br/>";
77
-
78
- //MAX_EXECUTION_TIME
79
- $test = (@set_time_limit(0)) ? 0 : ini_get("max_execution_time");
80
- echo '<hr size="1" /><span id="data-srv-php-maxtime"></span>&nbsp;<b>' . esc_html__('PHP Max Execution Time', 'duplicator') . ":</b>&nbsp; '{$test}' <br/>";
81
- _e('Timeouts may occur for larger packages when [max_execution_time] time in the php.ini is too low. A value of 0 (recommended) indicates that PHP has no time limits. '
82
- . 'An attempt is made to override this value if the server allows it.', 'duplicator');
83
- echo '<br/><br/>';
84
- _e('Note: Timeouts can also be set at the web server layer, so if the PHP max timeout passes and you still see a build timeout messages, then your web server could be killing '
85
- . 'the process. If you are on a budget host and limited on processing time, consider using the database or file filters to shrink the size of your overall package. '
86
- . 'However use caution as excluding the wrong resources can cause your install to not work properly.', 'duplicator');
87
- echo "&nbsp;<i><a href='http://www.php.net/manual/en/info.configuration.php#ini.max-execution-time' target='_blank'>[" . esc_html__('details', 'duplicator') . "]</a></i>";
88
-
89
- if ($zip_check != null) {
90
- echo '<br/><br/>';
91
- echo '<span style="font-weight:bold">';
92
- _e('Get faster builds with Duplicator Pro with access to shell_exec zip.', 'duplicator');
93
- echo '</span>';
94
- echo "&nbsp;<i><a href='https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_max_execution_time_warn&utm_campaign=duplicator_pro' target='_blank'>[" . esc_html__('details', 'duplicator') . "]</a></i>";
95
- }
96
- ?>
97
- </div>
98
- </div>
99
-
100
- <!-- ============
101
- WP SETTINGS -->
102
- <div class="scan-item scan-item-last">
103
-
104
-
105
- <div class="title" onclick="Duplicator.Pack.toggleScanItem(this);">
106
- <div class="text"><i class="fa fa-caret-right"></i> <?php esc_html_e('WordPress', 'duplicator');?></div>
107
- <div id="data-srv-wp-all"></div>
108
- </div>
109
- <div class="info">
110
- <?php
111
- //VERSION CHECK
112
- echo '<span id="data-srv-wp-version"></span>&nbsp;<b>' . esc_html__('WordPress Version', 'duplicator') . ":</b>&nbsp; '{$wp_version}' <br/>";
113
- printf(__('It is recommended to have a version of WordPress that is greater than %1$s. Older version of WordPress can lead to migration issues and are a security risk. '
114
- . 'If possible please update your WordPress site to the latest version.', 'duplicator'), DUPLICATOR_SCAN_MIN_WP);
115
-
116
- //CORE FILES
117
- echo '<hr size="1" /><span id="data-srv-wp-core"></span>&nbsp;<b>' . esc_html__('Core Files', 'duplicator') . "</b> <br/>";
118
-
119
-
120
- $filter_text="";
121
- if($core_dir_notice) {
122
- echo '<small id="data-srv-wp-core-missing-dirs">';
123
- esc_html_e("The core WordPress paths below will <u>not</u> be included in the archive. These paths are required for WordPress to function!");
124
- echo "<br/>";
125
- foreach($core_dir_included as $core_dir) {
126
- echo '&nbsp; &nbsp; <b><i class="fa fa-exclamation-circle scan-warn"></i>&nbsp;'. $core_dir . '</b><br/>';
127
- }
128
- echo '</small><br/>';
129
- $filter_text="directories";
130
- }
131
-
132
- if($core_file_notice) {
133
- echo '<small id="data-srv-wp-core-missing-dirs">';
134
- esc_html_e("The core WordPress file below will <u>not</u> be included in the archive. This file is required for WordPress to function!");
135
- echo "<br/>";
136
- foreach($core_files_included as $core_file) {
137
- echo '&nbsp; &nbsp; <b><i class="fa fa-exclamation-circle scan-warn"></i>&nbsp;'. $core_file . '</b><br/>';
138
- }
139
- echo '</small><br/>';
140
- $filter_text .= (strlen($filter_text) > 0) ? " and file" : "files";
141
-
142
- }
143
-
144
- if(strlen($filter_text) > 0) {
145
- echo '<small>';
146
- esc_html_e("Note: Please change the {$filter_text} filters if you wish to include the WordPress core files otherwise the data will have to be manually copied"
147
- . " to the new location for the site to function properly.", 'duplicator');
148
- echo '</small>';
149
- }
150
-
151
-
152
- if(!$core_dir_notice && !$core_file_notice):
153
- esc_html_e("If the scanner is unable to locate the wp-config.php file in the root directory, then you will need to manually copy it to its new location. "
154
- . "This check will also look for core WordPress paths that should be included in the archive for WordPress to work correctly.", 'duplicator');
155
- endif;
156
-
157
-
158
-
159
- //CACHE DIR
160
- /*
161
- $cache_path = DUP_Util::safePath(WP_CONTENT_DIR) . '/cache';
162
- $cache_size = DUP_Util::byteSize(DUP_Util::getDirectorySize($cache_path));
163
- echo '<hr size="1" /><span id="data-srv-wp-cache"></span>&nbsp;<b>' . esc_html__('Cache Path', 'duplicator') . ":</b>&nbsp; '".esc_html($cache_path)."' (".esc_html($cache_size).") <br/>";
164
- _e("Cached data will lead to issues at install time and increases your archive size. Empty your cache directory before building the package by using "
165
- . "your cache plugins clear cache feature. Use caution if manually removing files the cache folder. The cache "
166
- . "size minimum threshold that triggers this warning is currently set at ", 'duplicator');
167
- echo esc_html(DUP_Util::byteSize(DUPLICATOR_SCAN_CACHESIZE)) . '.';
168
- */
169
-
170
- //MU SITE
171
- if (is_multisite()) {
172
- echo '<hr size="1" /><span><div class="scan-warn"><i class="fa fa-exclamation-triangle fa-sm"></i></div></span>&nbsp;<b>' . esc_html__('Multisite: Unsupported', 'duplicator') . "</b> <br/>";
173
- esc_html_e('Duplicator does not support WordPress multisite migrations. We recommend using Duplicator Pro which currently supports full multisite migrations and subsite to '
174
- . 'standalone site migrations.', 'duplicator');
175
- echo '<br/><br/>';
176
-
177
- esc_html_e('While it is not recommended you can still continue with the build of this package. Please note that at install time additional manual custom configurations will '
178
- . 'need to be made to finalize this multisite migration.', 'duplicator');
179
- echo "&nbsp;<i><a href='https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_is_mu_warn&utm_campaign=duplicator_pro' target='_blank'>[" . esc_html__('upgrade to pro', 'duplicator') . "]</a></i>";
180
- } else {
181
- echo '<hr size="1" /><span><div class="scan-good"><i class="fa fa-check"></i></div></span>&nbsp;<b>' . esc_html__('Multisite: N/A', 'duplicator') . "</b> <br/>";
182
- esc_html_e('This is not a multisite install so duplication will proceed without issue. Duplicator does not officially support multisite. However, Duplicator Pro supports '
183
- . 'duplication of a full multisite network and also has the ability to install a multisite subsite as a standalone site.', 'duplicator');
184
- echo "&nbsp;<i><a href='https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_is_mu_warn&utm_campaign=duplicator_pro' target='_blank'>[" . esc_html__('upgrade to pro', 'duplicator') . "]</a></i>";
185
- }
186
- ?>
187
- </div>
188
- </div>
189
-
190
- <script>
191
- (function($){
192
-
193
- //Ints the various server data responses from the scan results
194
- Duplicator.Pack.intServerData= function(data)
195
- {
196
- $('#data-srv-php-websrv').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.websrv));
197
- $('#data-srv-php-openbase').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.openbase));
198
- $('#data-srv-php-maxtime').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.maxtime));
199
- $('#data-srv-php-version').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.version));
200
- $('#data-srv-php-openssl').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.openssl));
201
- $('#data-srv-php-all').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.ALL));
202
-
203
- $('#data-srv-wp-version').html(Duplicator.Pack.setScanStatus(data.SRV.WP.version));
204
- $('#data-srv-wp-core').html(Duplicator.Pack.setScanStatus(data.SRV.WP.core));
205
- // $('#data-srv-wp-cache').html(Duplicator.Pack.setScanStatus(data.SRV.WP.cache));
206
- var duplicatorScanWPStatus = $('#data-srv-wp-all');
207
- duplicatorScanWPStatus.html(Duplicator.Pack.setScanStatus(data.SRV.WP.ALL));
208
- if ('Warn' == data.SRV.WP.ALL) {
209
- duplicatorScanWPStatus.parent().click();
210
- }
211
- }
212
-
213
- })(jQuery);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  </script>
1
+ <?php
2
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+ ?>
4
+ <!-- ================================================================
5
+ SERVER -->
6
+ <div class="details-title">
7
+ <i class="fa fa-hdd-o"></i> <i class="far fa-hdd fa-sm"></i> <?php esc_html_e("Setup", 'duplicator'); ?>
8
+ <div class="dup-more-details" title="<?php esc_attr_e('Show Diagnostics', 'duplicator');?>">
9
+ <a href="?page=duplicator-tools&tab=diagnostics" target="_blank"><i class="fa fa-microchip"></i></a>
10
+ </div>
11
+ </div>
12
+
13
+ <!-- ============
14
+ PHP SETTINGS -->
15
+ <div class="scan-item">
16
+
17
+ <?php
18
+
19
+ //TODO Login Need to go here
20
+
21
+ $core_dir_included = array();
22
+ $core_files_included = array();
23
+ //by default fault
24
+ $core_dir_notice = false;
25
+ $core_file_notice = false;
26
+
27
+ if (!$Package->Archive->ExportOnlyDB && isset($_POST['filter-on']) && isset($_POST['filter-dirs'])) {
28
+
29
+ //findout matched core directories
30
+ $filter_dirs = explode(";", trim(sanitize_text_field(($_POST['filter-dirs']))));
31
+
32
+ // clean possible blank spaces before and after the paths
33
+ for ($i = 0; $i < count($filter_dirs); $i++) {
34
+ $filter_dirs[$i] = trim($filter_dirs[$i]);
35
+ $filter_dirs[$i] = (substr($filter_dirs[$i], -1) == "/") ? substr($filter_dirs[$i],0, strlen($filter_dirs[$i])-1):$filter_dirs[$i] ;
36
+
37
+ }
38
+ $core_dir_included = array_intersect($filter_dirs,
39
+ DUP_Util::getWPCoreDirs());
40
+ if (count($core_dir_included)) $core_dir_notice = true;
41
+
42
+
43
+ //find out core files
44
+ $filter_files = explode(";", trim($_POST['filter-files']));
45
+
46
+ // clean possible blank spaces before and after the paths
47
+ for ($i = 0; $i < count($filter_files); $i++) {
48
+ $filter_files[$i] = trim($filter_files[$i]);
49
+ }
50
+ $core_files_included = array_intersect($filter_files,
51
+ DUP_Util::getWPCoreFiles());
52
+ if (count($core_files_included)) $core_file_notice = true;
53
+ }
54
+ ?>
55
+ <div class='title' onclick="Duplicator.Pack.toggleScanItem(this);">
56
+ <div class="text"><i class="fa fa-caret-right"></i> <?php esc_html_e('System', 'duplicator');?></div>
57
+ <div id="data-srv-sys-all"></div>
58
+ </div>
59
+ <div class="info">
60
+ <?php
61
+ //WEB SERVER
62
+ $web_servers = implode(', ', $GLOBALS['DUPLICATOR_SERVER_LIST']);
63
+ echo '<span id="data-srv-php-websrv"></span>&nbsp;<b>' . esc_html__('Web Server', 'duplicator') . ":</b>&nbsp; '".esc_attr($_SERVER['SERVER_SOFTWARE'])."' <br/>";
64
+ _e("Supported web servers: ", 'duplicator');
65
+ echo "<i>".esc_html($web_servers)."</i>";
66
+
67
+ //PHP VERSION
68
+ echo '<hr size="1" /><span id="data-srv-php-version"></span>&nbsp;<b>' . esc_html__('PHP Version', 'duplicator') . "</b> <br/>";
69
+ _e('The minimum PHP version supported by Duplicator is 5.2.9. It is highly recommended to use PHP 5.3+ for improved stability. For international language support please use PHP 7.0+.', 'duplicator');
70
+
71
+ //OPEN_BASEDIR
72
+ $test = ini_get("open_basedir");
73
+ $test = ($test) ? 'ON' : 'OFF';
74
+ echo '<hr size="1" /><span id="data-srv-php-openbase"></span>&nbsp;<b>' . esc_html__('PHP Open Base Dir', 'duplicator') . ":</b>&nbsp; '{$test}' <br/>";
75
+ _e('Issues might occur when [open_basedir] is enabled. Work with your server admin to disable this value in the php.ini file if you’re having issues building a package.', 'duplicator');
76
+ echo "&nbsp;<i><a href='http://php.net/manual/en/ini.core.php#ini.open-basedir' target='_blank'>[" . esc_html__('details', 'duplicator') . "]</a></i><br/>";
77
+
78
+ //MAX_EXECUTION_TIME
79
+ $test = (@set_time_limit(0)) ? 0 : ini_get("max_execution_time");
80
+ echo '<hr size="1" /><span id="data-srv-php-maxtime"></span>&nbsp;<b>' . esc_html__('PHP Max Execution Time', 'duplicator') . ":</b>&nbsp; '{$test}' <br/>";
81
+ _e('Timeouts may occur for larger packages when [max_execution_time] time in the php.ini is too low. A value of 0 (recommended) indicates that PHP has no time limits. '
82
+ . 'An attempt is made to override this value if the server allows it.', 'duplicator');
83
+ echo '<br/><br/>';
84
+ _e('Note: Timeouts can also be set at the web server layer, so if the PHP max timeout passes and you still see a build timeout messages, then your web server could be killing '
85
+ . 'the process. If you are on a budget host and limited on processing time, consider using the database or file filters to shrink the size of your overall package. '
86
+ . 'However use caution as excluding the wrong resources can cause your install to not work properly.', 'duplicator');
87
+ echo "&nbsp;<i><a href='http://www.php.net/manual/en/info.configuration.php#ini.max-execution-time' target='_blank'>[" . esc_html__('details', 'duplicator') . "]</a></i>";
88
+ if ($zip_check != null) {
89
+ echo '<br/><br/>';
90
+ echo '<span style="font-weight:bold">';
91
+ _e('Get faster builds with Duplicator Pro with access to shell_exec zip.', 'duplicator');
92
+ echo '</span>';
93
+ echo "&nbsp;<i><a href='https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_max_execution_time_warn&utm_campaign=duplicator_pro' target='_blank'>[" . esc_html__('details', 'duplicator') . "]</a></i>";
94
+ }
95
+
96
+ //MANAGED HOST
97
+ $test = DUP_Custom_Host_Manager::getInstance()->isManaged() ? "true" : "false";
98
+ echo '<hr size="1" /><span id="data-srv-sys-managedHost"></span>&nbsp;<b>' . esc_html__('Managed Host', 'duplicator') . ":</b>&nbsp; '{$test}' <br/>";
99
+ _e('A managed host is a WordPress host that tightly controls the server environment so that the software running on it can be closely ‘managed’ by the hosting company. '
100
+ .'Managed hosts typically have constraints imposed to facilitate this management, including the locking down of certain files and directories as well as non-standard configurations.', 'duplicator');
101
+ echo '<br/><br/>';
102
+ _e('Duplicator Lite allows users to build a package on managed hosts, however, the installer may not properly install packages created on managed hosts due to the non-standard configurations of managed hosts. '
103
+ .'It is also possible the package engine of Duplicator Lite won’t be able to capture all of the necessary data of a site running on a managed host.', 'duplicator');
104
+ echo '<br/><br/>';
105
+ _e('<b>Due to these constraints Lite does not officially support the migration of managed hosts.</b> '
106
+ .'It’s possible one could get the package to install but it may require custom manual effort. '
107
+ .'To get support and the advanced installer processing required for managed host support we encourage users to <i>'
108
+ .'<a href="https://snapcreek.com/duplicator/?utm_source=duplicator_free&amp;utm_medium=wordpress_plugin&amp;utm_content=free_is_mu_warn&amp;utm_campaign=duplicator_pro" target="_blank">upgrade to Duplicator Pro</a></i>. '
109
+ .'Pro has more sophisticated package and installer logic and accounts for odd configurations associated with managed hosts.', 'duplicator');
110
+ echo '<br/><br/>';
111
+
112
+ ?>
113
+ </div>
114
+ </div>
115
+
116
+ <!-- ============
117
+ WP SETTINGS -->
118
+ <div class="scan-item scan-item-last">
119
+
120
+
121
+ <div class="title" onclick="Duplicator.Pack.toggleScanItem(this);">
122
+ <div class="text"><i class="fa fa-caret-right"></i> <?php esc_html_e('WordPress', 'duplicator');?></div>
123
+ <div id="data-srv-wp-all"></div>
124
+ </div>
125
+ <div class="info">
126
+ <?php
127
+ //VERSION CHECK
128
+ echo '<span id="data-srv-wp-version"></span>&nbsp;<b>' . esc_html__('WordPress Version', 'duplicator') . ":</b>&nbsp; '{$wp_version}' <br/>";
129
+ printf(__('It is recommended to have a version of WordPress that is greater than %1$s. Older version of WordPress can lead to migration issues and are a security risk. '
130
+ . 'If possible please update your WordPress site to the latest version.', 'duplicator'), DUPLICATOR_SCAN_MIN_WP);
131
+
132
+ //CORE FILES
133
+ echo '<hr size="1" /><span id="data-srv-wp-core"></span>&nbsp;<b>' . esc_html__('Core Files', 'duplicator') . "</b> <br/>";
134
+
135
+
136
+ $filter_text="";
137
+ if($core_dir_notice) {
138
+ echo '<small id="data-srv-wp-core-missing-dirs">';
139
+ esc_html_e("The core WordPress paths below will <u>not</u> be included in the archive. These paths are required for WordPress to function!");
140
+ echo "<br/>";
141
+ foreach($core_dir_included as $core_dir) {
142
+ echo '&nbsp; &nbsp; <b><i class="fa fa-exclamation-circle scan-warn"></i>&nbsp;'. $core_dir . '</b><br/>';
143
+ }
144
+ echo '</small><br/>';
145
+ $filter_text="directories";
146
+ }
147
+
148
+ if($core_file_notice) {
149
+ echo '<small id="data-srv-wp-core-missing-dirs">';
150
+ esc_html_e("The core WordPress file below will <u>not</u> be included in the archive. This file is required for WordPress to function!");
151
+ echo "<br/>";
152
+ foreach($core_files_included as $core_file) {
153
+ echo '&nbsp; &nbsp; <b><i class="fa fa-exclamation-circle scan-warn"></i>&nbsp;'. $core_file . '</b><br/>';
154
+ }
155
+ echo '</small><br/>';
156
+ $filter_text .= (strlen($filter_text) > 0) ? " and file" : "files";
157
+
158
+ }
159
+
160
+ if(strlen($filter_text) > 0) {
161
+ echo '<small>';
162
+ esc_html_e("Note: Please change the {$filter_text} filters if you wish to include the WordPress core files otherwise the data will have to be manually copied"
163
+ . " to the new location for the site to function properly.", 'duplicator');
164
+ echo '</small>';
165
+ }
166
+
167
+
168
+ if(!$core_dir_notice && !$core_file_notice):
169
+ esc_html_e("If the scanner is unable to locate the wp-config.php file in the root directory, then you will need to manually copy it to its new location. "
170
+ . "This check will also look for core WordPress paths that should be included in the archive for WordPress to work correctly.", 'duplicator');
171
+ endif;
172
+
173
+
174
+
175
+ //CACHE DIR
176
+ /*
177
+ $cache_path = DUP_Util::safePath(WP_CONTENT_DIR) . '/cache';
178
+ $cache_size = DUP_Util::byteSize(DUP_Util::getDirectorySize($cache_path));
179
+ echo '<hr size="1" /><span id="data-srv-wp-cache"></span>&nbsp;<b>' . esc_html__('Cache Path', 'duplicator') . ":</b>&nbsp; '".esc_html($cache_path)."' (".esc_html($cache_size).") <br/>";
180
+ _e("Cached data will lead to issues at install time and increases your archive size. Empty your cache directory before building the package by using "
181
+ . "your cache plugins clear cache feature. Use caution if manually removing files the cache folder. The cache "
182
+ . "size minimum threshold that triggers this warning is currently set at ", 'duplicator');
183
+ echo esc_html(DUP_Util::byteSize(DUPLICATOR_SCAN_CACHESIZE)) . '.';
184
+ */
185
+
186
+ //MU SITE
187
+ if (is_multisite()) {
188
+ echo '<hr size="1" /><span><div class="scan-warn"><i class="fa fa-exclamation-triangle fa-sm"></i></div></span>&nbsp;<b>' . esc_html__('Multisite: Unsupported', 'duplicator') . "</b> <br/>";
189
+ esc_html_e('Duplicator does not support WordPress multisite migrations. We recommend using Duplicator Pro which currently supports full multisite migrations and subsite to '
190
+ . 'standalone site migrations.', 'duplicator');
191
+ echo '<br/><br/>';
192
+
193
+ esc_html_e('While it is not recommended you can still continue with the build of this package. Please note that at install time additional manual custom configurations will '
194
+ . 'need to be made to finalize this multisite migration.', 'duplicator');
195
+ echo "&nbsp;<i><a href='https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_is_mu_warn&utm_campaign=duplicator_pro' target='_blank'>[" . esc_html__('upgrade to pro', 'duplicator') . "]</a></i>";
196
+ } else {
197
+ echo '<hr size="1" /><span><div class="scan-good"><i class="fa fa-check"></i></div></span>&nbsp;<b>' . esc_html__('Multisite: N/A', 'duplicator') . "</b> <br/>";
198
+ esc_html_e('This is not a multisite install so duplication will proceed without issue. Duplicator does not officially support multisite. However, Duplicator Pro supports '
199
+ . 'duplication of a full multisite network and also has the ability to install a multisite subsite as a standalone site.', 'duplicator');
200
+ echo "&nbsp;<i><a href='https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_is_mu_warn&utm_campaign=duplicator_pro' target='_blank'>[" . esc_html__('upgrade to pro', 'duplicator') . "]</a></i>";
201
+ }
202
+ ?>
203
+ </div>
204
+ </div>
205
+
206
+ <script>
207
+ (function($){
208
+
209
+ //Ints the various server data responses from the scan results
210
+ Duplicator.Pack.intServerData= function(data)
211
+ {
212
+ $('#data-srv-php-websrv').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.websrv));
213
+ $('#data-srv-php-openbase').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.openbase));
214
+ $('#data-srv-php-maxtime').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.maxtime));
215
+ $('#data-srv-php-version').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.version));
216
+ $('#data-srv-php-openssl').html(Duplicator.Pack.setScanStatus(data.SRV.PHP.openssl));
217
+ $('#data-srv-sys-managedHost').html(Duplicator.Pack.setScanStatus(data.SRV.SYS.managedHost));
218
+ $('#data-srv-sys-all').html(Duplicator.Pack.setScanStatus(data.SRV.SYS.ALL));
219
+
220
+ $('#data-srv-wp-version').html(Duplicator.Pack.setScanStatus(data.SRV.WP.version));
221
+ $('#data-srv-wp-core').html(Duplicator.Pack.setScanStatus(data.SRV.WP.core));
222
+ // $('#data-srv-wp-cache').html(Duplicator.Pack.setScanStatus(data.SRV.WP.cache));
223
+ var duplicatorScanWPStatus = $('#data-srv-wp-all');
224
+ duplicatorScanWPStatus.html(Duplicator.Pack.setScanStatus(data.SRV.WP.ALL));
225
+ if ('Warn' == data.SRV.WP.ALL) {
226
+ duplicatorScanWPStatus.parent().click();
227
+ }
228
+ }
229
+
230
+ })(jQuery);
231
  </script>
views/packages/main/s2.scan3.php CHANGED
@@ -455,6 +455,32 @@ DATABASE -->
455
  </div>
456
  </div>
457
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  $procedures = $GLOBALS['wpdb']->get_col("SHOW PROCEDURE STATUS WHERE `Db` = '{$wpdb->dbname}'", 1);
459
  if (count($procedures)) { ?>
460
  <div id="showcreateproc-block" class="scan-item scan-item-last">
@@ -856,6 +882,7 @@ jQuery(document).ready(function($)
856
  $('#data-arc-status-size').html(Duplicator.Pack.setScanStatus(data.ARC.Status.Size));
857
  $('#data-arc-status-names').html(Duplicator.Pack.setScanStatus(data.ARC.Status.Names));
858
  $('#data-arc-status-unreadablefiles').html(Duplicator.Pack.setScanStatus(data.ARC.Status.UnreadableItems));
 
859
 
860
  $('#data-arc-status-migratepackage').html(Duplicator.Pack.setScanStatus(data.ARC.Status.MigratePackage));
861
  + $('#data-arc-status-showcreateproc').html(Duplicator.Pack.setScanStatus(data.ARC.Status.showCreateProcStatus));
@@ -918,6 +945,14 @@ jQuery(document).ready(function($)
918
  $('#showcreateproc-package-result').html(html);
919
  }
920
 
 
 
 
 
 
 
 
 
921
  Duplicator.UI.loadQtip();
922
  }
923
 
455
  </div>
456
  </div>
457
  <?php
458
+ $triggers = $GLOBALS['wpdb']->get_col("SHOW TRIGGERS", 1);
459
+ if (count($triggers)) { ?>
460
+ <div class="scan-item scan-item-last">
461
+ <div class='title' onclick="Duplicator.Pack.toggleScanItem(this);">
462
+ <div class="text"><i class="fa fa-caret-right"></i> <?php esc_html_e('Contains Triggers', 'duplicator');?></div>
463
+ <div id="data-arc-status-triggers"></div>
464
+ </div>
465
+ <div class="info">
466
+ <script id="hb-triggers-result" type="text/x-handlebars-template">
467
+ <div class="container">
468
+ <div class="data">
469
+ <span class="color:maroon">
470
+ <?php
471
+ $lnk = '<a href="https://dev.mysql.com/doc/refman/8.0/en/triggers.html" target="_blank">' . esc_html__('triggers', 'duplicator') . '</a>';
472
+ printf(__('This database makes use of %1$s which can manually be imported at install time. Instructions and SQL statement queries will be '
473
+ . 'provided at install time for users to execute. No actions need to be performed at this time, this message is simply a notice.', 'duplicator'), $lnk);
474
+ ?>
475
+ </span>
476
+ </div>
477
+ </div>
478
+ </script>
479
+ <div id="triggers-result"></div>
480
+ </div>
481
+ </div>
482
+ <?php } ?>
483
+ <?php
484
  $procedures = $GLOBALS['wpdb']->get_col("SHOW PROCEDURE STATUS WHERE `Db` = '{$wpdb->dbname}'", 1);
485
  if (count($procedures)) { ?>
486
  <div id="showcreateproc-block" class="scan-item scan-item-last">
882
  $('#data-arc-status-size').html(Duplicator.Pack.setScanStatus(data.ARC.Status.Size));
883
  $('#data-arc-status-names').html(Duplicator.Pack.setScanStatus(data.ARC.Status.Names));
884
  $('#data-arc-status-unreadablefiles').html(Duplicator.Pack.setScanStatus(data.ARC.Status.UnreadableItems));
885
+ $('#data-arc-status-triggers').html(Duplicator.Pack.setScanStatus(data.DB.Status.Triggers));
886
 
887
  $('#data-arc-status-migratepackage').html(Duplicator.Pack.setScanStatus(data.ARC.Status.MigratePackage));
888
  + $('#data-arc-status-showcreateproc').html(Duplicator.Pack.setScanStatus(data.ARC.Status.showCreateProcStatus));
945
  $('#showcreateproc-package-result').html(html);
946
  }
947
 
948
+ //TRIGGERS
949
+ if ($("#hb-triggers-result").length) {
950
+ var template = $('#hb-triggers-result').html();
951
+ var templateScript = Handlebars.compile(template);
952
+ var html = templateScript(data);
953
+ $('#triggers-result').html(html);
954
+ }
955
+
956
  Duplicator.UI.loadQtip();
957
  }
958
 
views/settings/controller.php CHANGED
@@ -2,7 +2,7 @@
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
 
4
  DUP_Handler::init_error_handler();
5
- DUP_Util::hasCapability('manage_options');
6
 
7
  global $wpdb;
8
 
2
  defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
 
4
  DUP_Handler::init_error_handler();
5
+ DUP_Util::hasCapability('export');
6
 
7
  global $wpdb;
8
 
views/settings/general.php CHANGED
@@ -114,8 +114,12 @@ $unhook_third_party_css = DUP_Settings::Get('unhook_third_party_css');
114
  <tr valign="top">
115
  <th scope="row"><label><?php esc_html_e("Version", 'duplicator'); ?></label></th>
116
  <td>
117
- <?php echo DUPLICATOR_VERSION ?> &nbsp;
118
- <i><small>(<?php echo DUPLICATOR_VERSION_BUILD ?>)</small></i>
 
 
 
 
119
  </td>
120
  </tr>
121
  <tr valign="top">
114
  <tr valign="top">
115
  <th scope="row"><label><?php esc_html_e("Version", 'duplicator'); ?></label></th>
116
  <td>
117
+ <?php
118
+ echo DUPLICATOR_VERSION . ' &nbsp; ';
119
+ echo (stristr(DUPLICATOR_VERSION_BUILD, 'rc'))
120
+ ? "<span style='color:red'>[" . DUPLICATOR_VERSION_BUILD . "]</span>"
121
+ : "<span style='color:gray'>[" . DUPLICATOR_VERSION_BUILD . "]</span>";
122
+ ?>
123
  </td>
124
  </tr>
125
  <tr valign="top">
views/settings/gopro.php CHANGED
@@ -1,259 +1,267 @@
1
- <?php
2
- defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
- DUP_Util::hasCapability('export');
4
-
5
- require_once(DUPLICATOR_PLUGIN_PATH . '/assets/js/javascript.php');
6
- require_once(DUPLICATOR_PLUGIN_PATH . '/views/inc.header.php');
7
- ?>
8
- <style>
9
- /*================================================
10
- PAGE-SUPPORT:*/
11
- div.dup-pro-area {
12
- padding:10px 70px; max-width:750px; width:90%; margin:auto; text-align:center;
13
- background:#fff; border-radius:20px;
14
- box-shadow:inset 0px 0px 67px 20px rgba(241,241,241,1);
15
- }
16
- i.dup-gopro-help {color:#777 !important; margin-left:5px; font-size:14px; }
17
- td.group-header {background-color:#D5D5D5; color: #000; font-size: 20px; padding:7px !important; font-weight: bold}
18
- div.dup-compare-area {width:400px; float:left; border:1px solid #dfdfdf; border-radius:4px; margin:10px; line-height:18px;box-shadow:0 8px 6px -6px #ccc;}
19
- div.feature {background:#fff; padding:15px; margin:2px; text-align:center; min-height:20px}
20
- div.feature a {font-size:18px; font-weight:bold;}
21
- div.dup-compare-area div.feature div.info {display:none; padding:7px 7px 5px 7px; font-style:italic; color:#555; font-size:14px}
22
- div.dup-gopro-header {text-align:center; margin:5px 0 15px 0; font-size:18px; line-height:30px}
23
- div.dup-gopro-header b {font-size:35px}
24
- button.dup-check-it-btn {box-shadow:5px 5px 5px 0px #999 !important; font-size:20px !important; height:45px !important; padding:7px 30px 7px 30px !important; color:white!important; background-color: #3e8f3e!important; font-weight: bold!important;
25
- color: white;
26
- font-weight: bold;}
27
-
28
- #comparison-table { margin-top:25px; border-spacing:0px; width:100%}
29
- #comparison-table th { color:#E21906;}
30
- #comparison-table td, #comparison-table th { font-size:1.2rem; padding:11px; }
31
- #comparison-table .feature-column { text-align:left; width:46%}
32
- #comparison-table .check-column { text-align:center; width:27% }
33
- #comparison-table tr:nth-child(2n+2) { background-color:#f6f6f6; }
34
- .button.button-large.dup-check-it-btn { line-height: 28px; }
35
- </style>
36
-
37
- <div class="dup-pro-area">
38
- <img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/logo-dpro-300x50.png"); ?>" />
39
- <div style="font-size:18px; font-style:italic; color:gray; border-bottom: 1px solid silver; padding-bottom:10px; margin-bottom: -30px">
40
- <?php esc_html_e('The simplicity of Duplicator', 'duplicator') ?>
41
- <?php esc_html_e('with power for everyone.', 'duplicator') ?>
42
- </div>
43
-
44
- <table id="comparison-table">
45
- <tr>
46
- <th class="feature-column"><?php esc_html_e('Feature', 'duplicator') ?></th>
47
- <th class="check-column"><?php esc_html_e('Free', 'duplicator') ?></th>
48
- <th class="check-column"><?php esc_html_e('Professional', 'duplicator') ?></th>
49
- </tr>
50
- <tr>
51
- <td class="feature-column"><?php esc_html_e('Backup Files & Database', 'duplicator') ?></td>
52
- <td class="check-column"><i class="fa fa-check"></i></td>
53
- <td class="check-column"><i class="fa fa-check"></i></td>
54
- </tr>
55
- <tr>
56
- <td class="feature-column"><?php esc_html_e('File Filters', 'duplicator') ?></td>
57
- <td class="check-column"><i class="fa fa-check"></i></td>
58
- <td class="check-column"><i class="fa fa-check"></i></td>
59
- </tr>
60
- <tr>
61
- <td class="feature-column"><?php esc_html_e('Database Table Filters', 'duplicator') ?></td>
62
- <td class="check-column"><i class="fa fa-check"></i></td>
63
- <td class="check-column"><i class="fa fa-check"></i></td>
64
- </tr>
65
- <tr>
66
- <td class="feature-column"><?php esc_html_e('Migration Wizard', 'duplicator') ?></td>
67
- <td class="check-column"><i class="fa fa-check"></i></td>
68
- <td class="check-column"><i class="fa fa-check"></i></td>
69
- </tr>
70
- <tr>
71
- <td class="feature-column"><?php esc_html_e('Drag and Drop Installs', 'duplicator') ?><sup>
72
- <i class="fa fa-question-circle dup-gopro-help"
73
- data-tooltip-title="<?php esc_attr_e("Drag and Drop Site Overwrites", 'duplicator'); ?>"
74
- data-tooltip="<?php esc_attr_e('Overwrite a live site just by dragging an archive to the destination site. No FTP or database creation required!', 'duplicator'); ?>"/></i></sup>
75
- </td>
76
- <td class="check-column"></td>
77
- <td class="check-column"><i class="fa fa-check"></i></td>
78
- </tr>
79
- <tr>
80
- <td class="feature-column"><?php esc_html_e('Scheduled Backups', 'duplicator') ?></td>
81
- <td class="check-column"></td>
82
- <td class="check-column"><i class="fa fa-check"></i></td>
83
- </tr>
84
- <tr>
85
- <td class="feature-column">
86
- <img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/amazon-64.png") ?>" style='height:16px; width:16px' />
87
- <?php esc_html_e('Amazon S3 Storage', 'duplicator') ?>
88
- </td>
89
- <td class="check-column"></td>
90
- <td class="check-column"><i class="fa fa-check"></i></td>
91
- </tr>
92
- <tr>
93
- <td class="feature-column">
94
- <img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/dropbox-64.png"); ?>" style='height:16px; width:16px' />
95
- <?php esc_html_e('Dropbox Storage ', 'duplicator') ?>
96
- </td>
97
- <td class="check-column"></td>
98
- <td class="check-column"><i class="fa fa-check"></i></td>
99
- </tr>
100
- <tr>
101
- <td class="feature-column">
102
- <img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/google_drive_64px.png"); ?>" style='height:16px; width:16px' />
103
- <?php esc_html_e('Google Drive Storage', 'duplicator') ?>
104
- </td>
105
- <td class="check-column"></td>
106
- <td class="check-column"><i class="fa fa-check"></i></td>
107
- </tr>
108
- <tr>
109
- <td class="feature-column">
110
- <img src="<?php echo DUPLICATOR_PLUGIN_URL ?>assets/img/onedrive-48px.png" style='height:16px; width:16px' />
111
- <?php esc_html_e('Microsoft OneDrive Storage', 'duplicator') ?>
112
- </td>
113
- <td class="check-column"></td>
114
- <td class="check-column"><i class="fa fa-check"></i></td>
115
- </tr>
116
- <tr>
117
- <td class="feature-column">
118
- <img src="<?php echo DUPLICATOR_PLUGIN_URL ?>assets/img/ftp-64.png" style='height:16px; width:16px' />
119
- <?php esc_html_e('Remote FTP/SFTP Storage', 'duplicator') ?>
120
- </td>
121
- <td class="check-column"></td>
122
- <td class="check-column"><i class="fa fa-check"></i></td>
123
- </tr>
124
- <tr>
125
- <td class="feature-column"><?php esc_html_e('Large Site Support', 'duplicator') ?><sup>
126
- <i class="fa fa-question-circle dup-gopro-help"
127
- data-tooltip-title="<?php esc_attr_e("Large Site Support", 'duplicator'); ?>"
128
- data-tooltip="<?php esc_attr_e('Advanced archive engine processes multi-gig sites - even on stubborn budget hosts!', 'duplicator'); ?>"/></i></sup>
129
- </td>
130
- <td class="check-column"></td>
131
- <td class="check-column"><i class="fa fa-check"></i></td>
132
- </tr>
133
- <td class="feature-column"><?php esc_html_e('Streamlined Installer', 'duplicator') ?><sup>
134
- <i class="fa fa-question-circle dup-gopro-help"
135
- data-tooltip-title="<?php esc_attr_e("Streamlined Installer", 'duplicator'); ?>"
136
- data-tooltip="<?php esc_attr_e('Installer now has two modes: Basic and Advanced. Advanced is like an enhanced Duplicator Lite installer, while Basic is streamlined and only two steps!', 'duplicator'); ?>"/></i></sup>
137
- </td>
138
- <td class="check-column"></td>
139
- <td class="check-column"><i class="fa fa-check"></i></td>
140
- </tr>
141
- <tr>
142
- <td class="feature-column"><?php esc_html_e('Recovery Points', 'duplicator') ?><sup>
143
- <i class="fa fa-question-circle dup-gopro-help"
144
- data-tooltip-title="<?php esc_attr_e("Recovery Points", 'duplicator'); ?>"
145
- data-tooltip="<?php esc_attr_e('Recovery Points provide great protection against mistakes and bad updates. Simply mark a package as the "Recovery Point", and if anything goes wrong just browse to the Recovery URL for fast site restoration.', 'duplicator'); ?>"/></i></sup>
146
- <td class="check-column"></td>
147
- <td class="check-column"><i class="fa fa-check"></i></td>
148
- </tr>
149
- <tr>
150
- <td class="feature-column"><?php esc_html_e('Managed Hosting Support', 'duplicator') ?><sup>
151
- <i class="fa fa-question-circle dup-gopro-help"
152
- data-tooltip-title="<?php esc_attr_e("Managed Hosting Support", 'duplicator'); ?>"
153
- data-tooltip="<?php esc_attr_e('In addition to the many standard hosts we\'ve always supported, Duplicator Pro now supports WordPress.com, WPEngine, GoDaddy Managed, Liquid Web Managed and more!', 'duplicator'); ?>"/></i></sup>
154
- <td class="check-column"></td>
155
- <td class="check-column"><i class="fa fa-check"></i></td>
156
- </tr>
157
- <tr>
158
- <td class="feature-column"><?php esc_html_e('Server Throttling', 'duplicator') ?></td>
159
- <td class="check-column"></td>
160
- <td class="check-column"><i class="fa fa-check"></i></td>
161
- </tr>
162
- <tr>
163
- <td class="feature-column"><?php esc_html_e('Background Processing', 'duplicator') ?></td>
164
- <td class="check-column"></td>
165
- <td class="check-column"><i class="fa fa-check"></i></td>
166
- </tr>
167
- <tr>
168
- <td class="feature-column"><?php esc_html_e('Installer Passwords', 'duplicator') ?></td>
169
- <td class="check-column"></td>
170
- <td class="check-column"><i class="fa fa-check"></i></td>
171
- </tr>
172
- <tr>
173
- <td class="feature-column"><?php esc_html_e(' Regenerate Salts', 'duplicator') ?><sup>
174
- <i class="fa fa-question-circle dup-gopro-help"
175
- data-tooltip-title="<?php esc_attr_e("Regenerate Salts", 'duplicator'); ?>"
176
- data-tooltip="<?php esc_attr_e('Installer contains option to regenerate salts in the wp-config.php file. This feature is only available with Freelancer, Business or Gold licenses.', 'duplicator'); ?>"/></i></sup>
177
- </td>
178
- <td class="check-column"></td>
179
- <td class="check-column"><i class="fa fa-check"></i></td>
180
- </tr>
181
- <tr>
182
- <td class="feature-column"><?php esc_html_e('WP-Config Control Plus', 'duplicator') ?><sup>
183
- <i class="fa fa-question-circle dup-gopro-help"
184
- data-tooltip-title="<?php esc_attr_e("WP-Config Control Plus", 'duplicator'); ?>"
185
- data-tooltip="<?php esc_attr_e('Control many wp-config.php settings right from the installer!', 'duplicator'); ?>"/></i></sup>
186
- </td>
187
- <td class="check-column"></td>
188
- <td class="check-column"><i class="fa fa-check"></i></td>
189
- </tr>
190
- <tr>
191
- <td class="feature-column">
192
- <img src="<?php echo DUPLICATOR_PLUGIN_URL ?>assets/img/cpanel-48.png" style="width:16px; height:12px" />
193
- <?php esc_html_e('cPanel Database API', 'duplicator') ?>
194
- <sup>
195
- <i class="fa fa-question-circle dup-gopro-help"
196
- data-tooltip-title="<?php esc_attr_e("cPanel", 'duplicator'); ?>"
197
- data-tooltip="<?php esc_attr_e('Create the database and database user directly in the installer. No need to browse to your host\'s cPanel application.', 'duplicator'); ?>"/></i></sup>
198
- </td>
199
- <td class="check-column"></td>
200
- <td class="check-column"><i class="fa fa-check"></i></td>
201
- </tr>
202
- <tr>
203
- <td class="feature-column"><?php esc_html_e('Multisite Network Migration', 'duplicator') ?></td>
204
- <td class="check-column"></td>
205
- <td class="check-column"><i class="fa fa-check"></i></td>
206
- </tr>
207
- <tr>
208
- <td class="feature-column"><?php esc_html_e('Multisite Subsite &gt; Standalone', 'duplicator') ?><sup>
209
- <i class="fa fa-question-circle dup-gopro-help"
210
- data-tooltip-title="<?php esc_attr_e("Multisite", 'duplicator'); ?>"
211
- data-tooltip="<?php esc_attr_e('Install an individual subsite from a Multisite as a standalone site. This feature is only available with Business or Gold licenses.', 'duplicator'); ?>"/></i></sup>
212
- </td>
213
- <td class="check-column"></td>
214
- <td class="check-column"><i class="fa fa-check"></i></td>
215
- </tr>
216
-
217
- <tr>
218
- <td class="feature-column"><?php esc_html_e('Custom Search & Replace', 'duplicator') ?></td>
219
- <td class="check-column"></td>
220
- <td class="check-column"><i class="fa fa-check"></i></td>
221
- </tr>
222
-
223
- <tr>
224
- <td class="feature-column"><?php esc_html_e('Email Alerts', 'duplicator') ?></td>
225
- <td class="check-column"></td>
226
- <td class="check-column"><i class="fa fa-check"></i></td>
227
- </tr>
228
-
229
- <tr>
230
- <td class="feature-column"><?php esc_html_e('Manual Transfers', 'duplicator') ?></td>
231
- <td class="check-column"></td>
232
- <td class="check-column"><i class="fa fa-check"></i></td>
233
- </tr>
234
- <tr>
235
- <td class="feature-column">
236
- <?php esc_html_e('Active Customer Support', 'duplicator') ?>
237
- <sup><i class="fa fa-question-circle dup-gopro-help"
238
- data-tooltip-title="<?php esc_attr_e("Support", 'duplicator'); ?>"
239
- data-tooltip="<?php esc_attr_e('Pro users get top priority for any requests to our support desk. In most cases responses will be answered in under 24 hours.', 'duplicator'); ?>"/></i></sup>
240
- </td>
241
- <td class="check-column"></td>
242
- <td class="check-column"><i class="fa fa-check"></i></td>
243
- </tr>
244
- <tr>
245
- <td class="feature-column"><?php esc_html_e('Plus Many Other Features...', 'duplicator') ?></td>
246
- <td class="check-column"></td>
247
- <td class="check-column"><i class="fa fa-check"></i></td>
248
- </tr>
249
- </table>
250
-
251
- <br style="clear:both" />
252
- <p style="text-align:center">
253
- <button onclick="window.open('https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_go_pro&utm_campaign=duplicator_pro');" class="button button-large dup-check-it-btn" >
254
- <?php esc_html_e('Check It Out!', 'duplicator') ?>
255
- </button>
256
- </p>
257
- <br/><br/>
258
- </div>
259
- <br/><br/>
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
3
+ DUP_Util::hasCapability('export');
4
+
5
+ require_once(DUPLICATOR_PLUGIN_PATH . '/assets/js/javascript.php');
6
+ require_once(DUPLICATOR_PLUGIN_PATH . '/views/inc.header.php');
7
+ ?>
8
+ <style>
9
+ /*================================================
10
+ PAGE-SUPPORT:*/
11
+ div.dup-pro-area {
12
+ padding:10px 70px; max-width:750px; width:90%; margin:auto; text-align:center;
13
+ background:#fff; border-radius:20px;
14
+ box-shadow:inset 0px 0px 67px 20px rgba(241,241,241,1);
15
+ }
16
+ i.dup-gopro-help {color:#777 !important; margin-left:5px; font-size:14px; }
17
+ td.group-header {background-color:#D5D5D5; color: #000; font-size: 20px; padding:7px !important; font-weight: bold}
18
+ div.dup-compare-area {width:400px; float:left; border:1px solid #dfdfdf; border-radius:4px; margin:10px; line-height:18px;box-shadow:0 8px 6px -6px #ccc;}
19
+ div.feature {background:#fff; padding:15px; margin:2px; text-align:center; min-height:20px}
20
+ div.feature a {font-size:18px; font-weight:bold;}
21
+ div.dup-compare-area div.feature div.info {display:none; padding:7px 7px 5px 7px; font-style:italic; color:#555; font-size:14px}
22
+ div.dup-gopro-header {text-align:center; margin:5px 0 15px 0; font-size:18px; line-height:30px}
23
+ div.dup-gopro-header b {font-size:35px}
24
+ button.dup-check-it-btn {box-shadow:5px 5px 5px 0px #999 !important; font-size:20px !important; height:45px !important; padding:7px 30px 7px 30px !important; color:white!important; background-color: #3e8f3e!important; font-weight: bold!important;
25
+ color: white;
26
+ font-weight: bold;}
27
+
28
+ #comparison-table { margin-top:25px; border-spacing:0px; width:100%}
29
+ #comparison-table th { color:#E21906;}
30
+ #comparison-table td, #comparison-table th { font-size:1.2rem; padding:11px; }
31
+ #comparison-table .feature-column { text-align:left; width:46%}
32
+ #comparison-table .check-column { text-align:center; width:27% }
33
+ #comparison-table tr:nth-child(2n+2) { background-color:#f6f6f6; }
34
+ .button.button-large.dup-check-it-btn { line-height: 28px; }
35
+ </style>
36
+
37
+ <div class="dup-pro-area">
38
+ <img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/logo-dpro-300x50.png"); ?>" />
39
+ <div style="font-size:18px; font-style:italic; color:gray; border-bottom: 1px solid silver; padding-bottom:10px; margin-bottom: -30px">
40
+ <?php esc_html_e('The simplicity of Duplicator', 'duplicator') ?>
41
+ <?php esc_html_e('with power for everyone.', 'duplicator') ?>
42
+ </div>
43
+
44
+ <table id="comparison-table">
45
+ <tr>
46
+ <th class="feature-column"><?php esc_html_e('Feature', 'duplicator') ?></th>
47
+ <th class="check-column"><?php esc_html_e('Free', 'duplicator') ?></th>
48
+ <th class="check-column"><?php esc_html_e('Professional', 'duplicator') ?></th>
49
+ </tr>
50
+ <tr>
51
+ <td class="feature-column"><?php esc_html_e('Backup Files & Database', 'duplicator') ?></td>
52
+ <td class="check-column"><i class="fa fa-check"></i></td>
53
+ <td class="check-column"><i class="fa fa-check"></i></td>
54
+ </tr>
55
+ <tr>
56
+ <td class="feature-column"><?php esc_html_e('File Filters', 'duplicator') ?></td>
57
+ <td class="check-column"><i class="fa fa-check"></i></td>
58
+ <td class="check-column"><i class="fa fa-check"></i></td>
59
+ </tr>
60
+ <tr>
61
+ <td class="feature-column"><?php esc_html_e('Database Table Filters', 'duplicator') ?></td>
62
+ <td class="check-column"><i class="fa fa-check"></i></td>
63
+ <td class="check-column"><i class="fa fa-check"></i></td>
64
+ </tr>
65
+ <tr>
66
+ <td class="feature-column"><?php esc_html_e('Migration Wizard', 'duplicator') ?></td>
67
+ <td class="check-column"><i class="fa fa-check"></i></td>
68
+ <td class="check-column"><i class="fa fa-check"></i></td>
69
+ </tr>
70
+ <tr>
71
+ <td class="feature-column"><?php esc_html_e('Drag and Drop Installs', 'duplicator') ?><sup>
72
+ <i class="fa fa-question-circle dup-gopro-help"
73
+ data-tooltip-title="<?php esc_attr_e("Drag and Drop Site Overwrites", 'duplicator'); ?>"
74
+ data-tooltip="<?php esc_attr_e('Overwrite a live site just by dragging an archive to the destination site. No FTP or database creation required!', 'duplicator'); ?>"/></i></sup>
75
+ </td>
76
+ <td class="check-column"></td>
77
+ <td class="check-column"><i class="fa fa-check"></i></td>
78
+ </tr>
79
+ <tr>
80
+ <td class="feature-column"><?php esc_html_e('Scheduled Backups', 'duplicator') ?></td>
81
+ <td class="check-column"></td>
82
+ <td class="check-column"><i class="fa fa-check"></i></td>
83
+ </tr>
84
+ <tr>
85
+ <td class="feature-column">
86
+ <img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/amazon-64.png") ?>" style='height:16px; width:16px' />
87
+ <?php esc_html_e('Amazon S3 Storage', 'duplicator') ?>
88
+ </td>
89
+ <td class="check-column"></td>
90
+ <td class="check-column"><i class="fa fa-check"></i></td>
91
+ </tr>
92
+ <tr>
93
+ <td class="feature-column">
94
+ <img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/dropbox-64.png"); ?>" style='height:16px; width:16px' />
95
+ <?php esc_html_e('Dropbox Storage ', 'duplicator') ?>
96
+ </td>
97
+ <td class="check-column"></td>
98
+ <td class="check-column"><i class="fa fa-check"></i></td>
99
+ </tr>
100
+ <tr>
101
+ <td class="feature-column">
102
+ <img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/google_drive_64px.png"); ?>" style='height:16px; width:16px' />
103
+ <?php esc_html_e('Google Drive Storage', 'duplicator') ?>
104
+ </td>
105
+ <td class="check-column"></td>
106
+ <td class="check-column"><i class="fa fa-check"></i></td>
107
+ </tr>
108
+ <tr>
109
+ <td class="feature-column">
110
+ <img src="<?php echo DUPLICATOR_PLUGIN_URL ?>assets/img/onedrive-48px.png" style='height:16px; width:16px' />
111
+ <?php esc_html_e('Microsoft OneDrive Storage', 'duplicator') ?>
112
+ </td>
113
+ <td class="check-column"></td>
114
+ <td class="check-column"><i class="fa fa-check"></i></td>
115
+ </tr>
116
+ <tr>
117
+ <td class="feature-column">
118
+ <img src="<?php echo DUPLICATOR_PLUGIN_URL ?>assets/img/logo_wasbi.png" style='height:16px; width:16px' />
119
+ <?php esc_html_e('Wasabi Storage', 'duplicator') ?>
120
+ </td>
121
+ <td class="check-column"></td>
122
+ <td class="check-column"><i class="fa fa-check"></i></td>
123
+ </tr>
124
+ <tr>
125
+ <td class="feature-column">
126
+ <img src="<?php echo DUPLICATOR_PLUGIN_URL ?>assets/img/ftp-64.png" style='height:16px; width:16px' />
127
+ <?php esc_html_e('Remote FTP/SFTP Storage', 'duplicator') ?>
128
+ </td>
129
+ <td class="check-column"></td>
130
+ <td class="check-column"><i class="fa fa-check"></i></td>
131
+ </tr>
132
+ <tr>
133
+ <td class="feature-column"><?php esc_html_e('Large Site Support', 'duplicator') ?><sup>
134
+ <i class="fa fa-question-circle dup-gopro-help"
135
+ data-tooltip-title="<?php esc_attr_e("Large Site Support", 'duplicator'); ?>"
136
+ data-tooltip="<?php esc_attr_e('Advanced archive engine processes multi-gig sites - even on stubborn budget hosts!', 'duplicator'); ?>"/></i></sup>
137
+ </td>
138
+ <td class="check-column"></td>
139
+ <td class="check-column"><i class="fa fa-check"></i></td>
140
+ </tr>
141
+ <td class="feature-column"><?php esc_html_e('Streamlined Installer', 'duplicator') ?><sup>
142
+ <i class="fa fa-question-circle dup-gopro-help"
143
+ data-tooltip-title="<?php esc_attr_e("Streamlined Installer", 'duplicator'); ?>"
144
+ data-tooltip="<?php esc_attr_e('Installer now has two modes: Basic and Advanced. Advanced is like an enhanced Duplicator Lite installer, while Basic is streamlined and only two steps!', 'duplicator'); ?>"/></i></sup>
145
+ </td>
146
+ <td class="check-column"></td>
147
+ <td class="check-column"><i class="fa fa-check"></i></td>
148
+ </tr>
149
+ <tr>
150
+ <td class="feature-column"><?php esc_html_e('Recovery Points', 'duplicator') ?><sup>
151
+ <i class="fa fa-question-circle dup-gopro-help"
152
+ data-tooltip-title="<?php esc_attr_e("Recovery Points", 'duplicator'); ?>"
153
+ data-tooltip="<?php esc_attr_e('Recovery Points provide great protection against mistakes and bad updates. Simply mark a package as the "Recovery Point", and if anything goes wrong just browse to the Recovery URL for fast site restoration.', 'duplicator'); ?>"/></i></sup>
154
+ <td class="check-column"></td>
155
+ <td class="check-column"><i class="fa fa-check"></i></td>
156
+ </tr>
157
+ <tr>
158
+ <td class="feature-column"><?php esc_html_e('Managed Hosting Support', 'duplicator') ?><sup>
159
+ <i class="fa fa-question-circle dup-gopro-help"
160
+ data-tooltip-title="<?php esc_attr_e("Managed Hosting Support", 'duplicator'); ?>"
161
+ data-tooltip="<?php esc_attr_e('In addition to the many standard hosts we\'ve always supported, Duplicator Pro now supports WordPress.com, WPEngine, GoDaddy Managed, Liquid Web Managed and more!', 'duplicator'); ?>"/></i></sup>
162
+ <td class="check-column"></td>
163
+ <td class="check-column"><i class="fa fa-check"></i></td>
164
+ </tr>
165
+ <tr>
166
+ <td class="feature-column"><?php esc_html_e('Server Throttling', 'duplicator') ?></td>
167
+ <td class="check-column"></td>
168
+ <td class="check-column"><i class="fa fa-check"></i></td>
169
+ </tr>
170
+ <tr>
171
+ <td class="feature-column"><?php esc_html_e('Background Processing', 'duplicator') ?></td>
172
+ <td class="check-column"></td>
173
+ <td class="check-column"><i class="fa fa-check"></i></td>
174
+ </tr>
175
+ <tr>
176
+ <td class="feature-column"><?php esc_html_e('Installer Passwords', 'duplicator') ?></td>
177
+ <td class="check-column"></td>
178
+ <td class="check-column"><i class="fa fa-check"></i></td>
179
+ </tr>
180
+ <tr>
181
+ <td class="feature-column"><?php esc_html_e(' Regenerate Salts', 'duplicator') ?><sup>
182
+ <i class="fa fa-question-circle dup-gopro-help"
183
+ data-tooltip-title="<?php esc_attr_e("Regenerate Salts", 'duplicator'); ?>"
184
+ data-tooltip="<?php esc_attr_e('Installer contains option to regenerate salts in the wp-config.php file. This feature is only available with Freelancer, Business or Gold licenses.', 'duplicator'); ?>"/></i></sup>
185
+ </td>
186
+ <td class="check-column"></td>
187
+ <td class="check-column"><i class="fa fa-check"></i></td>
188
+ </tr>
189
+ <tr>
190
+ <td class="feature-column"><?php esc_html_e('WP-Config Control Plus', 'duplicator') ?><sup>
191
+ <i class="fa fa-question-circle dup-gopro-help"
192
+ data-tooltip-title="<?php esc_attr_e("WP-Config Control Plus", 'duplicator'); ?>"
193
+ data-tooltip="<?php esc_attr_e('Control many wp-config.php settings right from the installer!', 'duplicator'); ?>"/></i></sup>
194
+ </td>
195
+ <td class="check-column"></td>
196
+ <td class="check-column"><i class="fa fa-check"></i></td>
197
+ </tr>
198
+ <tr>
199
+ <td class="feature-column">
200
+ <img src="<?php echo DUPLICATOR_PLUGIN_URL ?>assets/img/cpanel-48.png" style="width:16px; height:12px" />
201
+ <?php esc_html_e('cPanel Database API', 'duplicator') ?>
202
+ <sup>
203
+ <i class="fa fa-question-circle dup-gopro-help"
204
+ data-tooltip-title="<?php esc_attr_e("cPanel", 'duplicator'); ?>"
205
+ data-tooltip="<?php esc_attr_e('Create the database and database user directly in the installer. No need to browse to your host\'s cPanel application.', 'duplicator'); ?>"/></i></sup>
206
+ </td>
207
+ <td class="check-column"></td>
208
+ <td class="check-column"><i class="fa fa-check"></i></td>
209
+ </tr>
210
+ <tr>
211
+ <td class="feature-column"><?php esc_html_e('Multisite Network Migration', 'duplicator') ?></td>
212
+ <td class="check-column"></td>
213
+ <td class="check-column"><i class="fa fa-check"></i></td>
214
+ </tr>
215
+ <tr>
216
+ <td class="feature-column"><?php esc_html_e('Multisite Subsite &gt; Standalone', 'duplicator') ?><sup>
217
+ <i class="fa fa-question-circle dup-gopro-help"
218
+ data-tooltip-title="<?php esc_attr_e("Multisite", 'duplicator'); ?>"
219
+ data-tooltip="<?php esc_attr_e('Install an individual subsite from a Multisite as a standalone site. This feature is only available with Business or Gold licenses.', 'duplicator'); ?>"/></i></sup>
220
+ </td>
221
+ <td class="check-column"></td>
222
+ <td class="check-column"><i class="fa fa-check"></i></td>
223
+ </tr>
224
+
225
+ <tr>
226
+ <td class="feature-column"><?php esc_html_e('Custom Search & Replace', 'duplicator') ?></td>
227
+ <td class="check-column"></td>
228
+ <td class="check-column"><i class="fa fa-check"></i></td>
229
+ </tr>
230
+
231
+ <tr>
232
+ <td class="feature-column"><?php esc_html_e('Email Alerts', 'duplicator') ?></td>
233
+ <td class="check-column"></td>
234
+ <td class="check-column"><i class="fa fa-check"></i></td>
235
+ </tr>
236
+
237
+ <tr>
238
+ <td class="feature-column"><?php esc_html_e('Manual Transfers', 'duplicator') ?></td>
239
+ <td class="check-column"></td>
240
+ <td class="check-column"><i class="fa fa-check"></i></td>
241
+ </tr>
242
+ <tr>
243
+ <td class="feature-column">
244
+ <?php esc_html_e('Active Customer Support', 'duplicator') ?>
245
+ <sup><i class="fa fa-question-circle dup-gopro-help"
246
+ data-tooltip-title="<?php esc_attr_e("Support", 'duplicator'); ?>"
247
+ data-tooltip="<?php esc_attr_e('Pro users get top priority for any requests to our support desk. In most cases responses will be answered in under 24 hours.', 'duplicator'); ?>"/></i></sup>
248
+ </td>
249
+ <td class="check-column"></td>
250
+ <td class="check-column"><i class="fa fa-check"></i></td>
251
+ </tr>
252
+ <tr>
253
+ <td class="feature-column"><?php esc_html_e('Plus Many Other Features...', 'duplicator') ?></td>
254
+ <td class="check-column"></td>
255
+ <td class="check-column"><i class="fa fa-check"></i></td>
256
+ </tr>
257
+ </table>
258
+
259
+ <br style="clear:both" />
260
+ <p style="text-align:center">
261
+ <button onclick="window.open('https://snapcreek.com/duplicator/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_content=free_go_pro&utm_campaign=duplicator_pro');" class="button button-large dup-check-it-btn" >
262
+ <?php esc_html_e('Check It Out!', 'duplicator') ?>
263
+ </button>
264
+ </p>
265
+ <br/><br/>
266
+ </div>
267
+ <br/><br/>
views/tools/import.php CHANGED
@@ -15,7 +15,7 @@ defined('ABSPATH') || defined('DUPXABSPATH') || exit;
15
  echo '<h2><i class="fas fa-arrow-alt-circle-down"></i> ' . esc_html__('Drag and Drop imports are available in Duplicator Pro.', 'duplicator') . '</h2>';
16
  esc_html_e('The Import feature lets you skip the FTP and database creation steps when installing a site.', 'duplicator');
17
  echo '<br/>';
18
- esc_html_e('Just drag and drop an archive to quickly replace an existing WordPress installation!', 'duplicator');
19
  ?>
20
  </div>
21
  <p style="text-align:center">
15
  echo '<h2><i class="fas fa-arrow-alt-circle-down"></i> ' . esc_html__('Drag and Drop imports are available in Duplicator Pro.', 'duplicator') . '</h2>';
16
  esc_html_e('The Import feature lets you skip the FTP and database creation steps when installing a site.', 'duplicator');
17
  echo '<br/>';
18
+ esc_html_e('Just drag and drop a Duplicator Pro archive to quickly replace an existing WordPress installation!', 'duplicator');
19
  ?>
20
  </div>
21
  <p style="text-align:center">