PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 4.0.0
WP STAGING – WordPress Backup, Restore, Migration & Clone v4.0.0
4.9.3 4.9.2 4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / SiteInfo.php
wp-staging / Framework Last commit date
Adapter 1 year ago Analytics 1 year ago Assets 1 year ago BackgroundProcessing 1 year ago CloningProcess 1 year ago Collection 3 years ago Command 5 years ago Component 2 years ago DI 1 year ago Database 1 year ago DependencyResolver 2 years ago Exceptions 2 years ago Facades 1 year ago Filesystem 1 year ago Interfaces 5 years ago Job 1 year ago Language 1 year ago Mails 1 year ago Network 1 year ago Newsfeed 1 year ago Notices 1 year ago Performance 1 year ago Permalinks 1 year ago Queue 1 year ago Rest 2 years ago Security 1 year ago Settings 1 year ago TemplateEngine 1 year ago ThirdParty 1 year ago Traits 1 year ago Utils 1 year ago AnalyticsServiceProvider.php 2 years ago AssetServiceProvider.php 1 year ago CommonServiceProvider.php 1 year ago ErrorHandler.php 2 years ago NoticeServiceProvider.php 2 years ago SettingsServiceProvider.php 2 years ago SiteInfo.php 1 year ago Url.php 3 years ago
SiteInfo.php
362 lines
1 <?php
2
3 namespace WPStaging\Framework;
4
5 use WPStaging\Framework\Facades\Hooks;
6 use WPStaging\Framework\Facades\Sanitize;
7 use WPStaging\Staging\CloneOptions;
8
9 /**
10 * Class SiteInfo
11 *
12 * Provides information about the current site.
13 *
14 * @package WPStaging\Site
15 */
16 class SiteInfo
17 {
18 /**
19 * The key used in DB to store is cloneable feature in clone options
20 * @var string
21 */
22 const IS_CLONEABLE_KEY = 'isCloneable';
23
24 /**
25 * The file which make staging site cloneable
26 * This way is depreciated
27 * @var string
28 */
29 const CLONEABLE_FILE = '.wp-staging-cloneable';
30
31 /**
32 * The key used in DB to store whether site is staging or not
33 * @var string
34 */
35 const IS_STAGING_KEY = 'wpstg_is_staging_site';
36
37 /**
38 * The file which makes a site a staging site
39 * @var string
40 */
41 const STAGING_FILE = '.wp-staging';
42
43 /** @var string */
44 const HOSTED_ON_WP = 'wp.com';
45
46 /** @var string */
47 const HOSTED_ON_FLYWHEEL = 'flywheel';
48
49 /** @var string */
50 const HOSTED_ON_BITNAMI = 'bitnami';
51
52 /** @var string */
53 const OTHER_HOST = 'other';
54
55 /** @var string */
56 const FILTER_IS_WPSTG_TESTS = 'wpstg.tests.is_local_site';
57
58 /** @var string[] */
59 const LOCAL_HOSTNAMES = [
60 '.local',
61 '.test',
62 'localhost',
63 '.dev',
64 '10.0.0.',
65 '172.16.0.',
66 '192.168.0.'
67 ];
68
69 /**
70 * @var CloneOptions
71 */
72 private $cloneOptions;
73
74 /**
75 * @var array
76 */
77 private $errors = [];
78
79 public function __construct()
80 {
81 // TODO: inject using DI
82 $this->cloneOptions = new CloneOptions();
83 }
84
85 /**
86 * @return bool True if it is staging site. False otherwise.
87 */
88 public function isStagingSite(): bool
89 {
90 if (defined('WPSTAGING_DEV_SITE') && WPSTAGING_DEV_SITE === true) {
91 return true;
92 }
93
94 if (get_option(self::IS_STAGING_KEY) === "true") {
95 return true;
96 }
97
98 return file_exists(ABSPATH . self::STAGING_FILE);
99 }
100
101 /**
102 * @return bool True if it is staging site. False otherwise.
103 */
104 public function isCloneable(): bool
105 {
106 // Site should be cloneable if not staging i.e. production site
107 if (!$this->isStagingSite()) {
108 return true;
109 }
110
111 // Old condition to check if staging site is cloneable
112 if (file_exists(ABSPATH . self::CLONEABLE_FILE)) {
113 return true;
114 }
115
116 // New condition for checking whether staging is cloneable or not
117 return $this->cloneOptions->get(self::IS_CLONEABLE_KEY, false);
118 }
119
120 /**
121 * Check if WP is installed in subdirectory
122 * If siteurl and home are not identical we assume the site is located in a subdirectory
123 * related to that instruction https://wordpress.org/support/article/giving-wordpress-its-own-directory/
124 *
125 * @return bool
126 */
127 public function isInstalledInSubDir(): bool
128 {
129 $siteUrl = get_option('siteurl');
130 $homeUrl = get_option('home');
131
132 //Get URL path e.g.https://example.com/path will return /path
133 $siteUrlPath = wp_parse_url($siteUrl, PHP_URL_PATH);
134 $homeUrlPath = wp_parse_url($homeUrl, PHP_URL_PATH);
135
136 if ($siteUrlPath === null && $homeUrlPath === null || $siteUrlPath === $homeUrlPath) {
137 return false;
138 }
139
140 if ($siteUrlPath === null && $homeUrlPath !== null) {
141 return true;
142 }
143
144 return false;
145 }
146
147 /**
148 * Enable the cloning for current staging site.
149 *
150 * @return bool
151 */
152 public function enableStagingSiteCloning(): bool
153 {
154 // Early Bail: if site is not staging
155 if (!$this->isStagingSite()) {
156 return false;
157 }
158
159 // Early Bail: if cloning already enabled
160 if ($this->isCloneable()) {
161 return true;
162 }
163
164 return $this->cloneOptions->set(self::IS_CLONEABLE_KEY, true);
165 }
166
167 /**
168 * Enable the cloning for current staging site.
169 *
170 * @return bool
171 */
172 public function disableStagingSiteCloning(): bool
173 {
174 // Early Bail: if site is not staging
175 if (!$this->isStagingSite()) {
176 return false;
177 }
178
179 // Early Bail: if cloning already disabled
180 if (!$this->isCloneable()) {
181 return true;
182 }
183
184 // First try disabling if cloneable feature exist due to old way.
185 $cloneableFile = trailingslashit(ABSPATH) . self::CLONEABLE_FILE;
186 if (file_exists($cloneableFile) && !unlink($cloneableFile)) {
187 // Error if files exists but unable to unlink
188 return false;
189 }
190
191 // Staging site may have been made cloneable through both ways
192 // So now try disabling through new way
193 return (!file_exists($cloneableFile) && $this->cloneOptions->delete(self::IS_CLONEABLE_KEY));
194 }
195
196 /**
197 * @return bool True if "short_open_tags" is enabled, false if disabled.
198 */
199 public function isPhpShortTagsEnabled(): bool
200 {
201 return in_array(strtolower(ini_get('short_open_tags')), ['1', 'on', 'true']);
202 }
203
204 /**
205 * Is WP Bakery plugin active?
206 *
207 * @return bool
208 */
209 public function isWpBakeryActive(): bool
210 {
211 return defined('WPB_VC_VERSION');
212 }
213
214 /**
215 * Is Jetpack plugin active?
216 *
217 * @return bool
218 */
219 public function isJetpackActive(): bool
220 {
221 return class_exists('Jetpack');
222 }
223
224 /**
225 * @return string[]
226 */
227 public function getErrors(): array
228 {
229 return $this->errors;
230 }
231
232 /**
233 * @return bool
234 */
235 public function isBitnami(): bool
236 {
237 return ABSPATH === '/opt/bitnami/wordpress/';
238 }
239
240 /**
241 * @return bool
242 */
243 public function isWpContentOutsideAbspath(): bool
244 {
245 $wpContentDir = wp_normalize_path(WP_CONTENT_DIR);
246 $abspath = wp_normalize_path(ABSPATH);
247
248 return !(strpos($wpContentDir, $abspath) === 0);
249 }
250
251 /**
252 * @return bool
253 */
254 public function isFlywheel(): bool
255 {
256 if (!$this->isWpContentOutsideAbspath()) {
257 return false;
258 }
259
260 return file_exists(trailingslashit(wp_normalize_path(ABSPATH)) . '.fw-config.php');
261 }
262
263 /**
264 * @return bool
265 */
266 public function isHostedOnWordPressCom(): bool
267 {
268 if (!$this->isWpContentOutsideAbspath()) {
269 return false;
270 }
271
272 $parentDirectory = dirname(trailingslashit(wp_normalize_path(WP_CONTENT_DIR)));
273 $wpcomDetection = trailingslashit($parentDirectory) . '__wp__';
274 if (!is_link($wpcomDetection)) {
275 return false;
276 }
277
278 return true;
279 }
280
281 /**
282 * @return string
283 */
284 public function getHostingType(): string
285 {
286 if ($this->isFlywheel()) {
287 return self::HOSTED_ON_FLYWHEEL;
288 }
289
290 if ($this->isHostedOnWordPressCom()) {
291 return self::HOSTED_ON_WP;
292 }
293
294 if ($this->isBitnami()) {
295 return self::HOSTED_ON_BITNAMI;
296 }
297
298 return self::OTHER_HOST;
299 }
300
301 public function getPhpArchitecture(): string
302 {
303 return PHP_INT_SIZE === 8 ? '64-bit' : '32-bit';
304 }
305
306 public function getOsArchitecture(): string
307 {
308 try {
309 if (!function_exists('php_uname')) {
310 return 'N/A';
311 }
312
313 if (in_array('php_uname', explode(',', ini_get('disable_functions')))) {
314 return 'N/A';
315 }
316
317 return strpos(php_uname('m'), '64') !== false ? '64-bit' : '32-bit';
318 } catch (\Throwable $ex) {
319 return 'N/A';
320 }
321 }
322
323 /**
324 * @return bool
325 */
326 public function isHostedOnElementorCloud(): bool
327 {
328 $httpHost = !empty($_SERVER['HTTP_HOST']) ? Sanitize::sanitizeString($_SERVER['HTTP_HOST']) : '';
329 if (strpos($httpHost, 'elementor.cloud') !== false) {
330 return true;
331 }
332
333 $headers = headers_list();
334 foreach ($headers as $header) {
335 if (stripos($header, 'ec-source') !== false || stripos($header, 'ec-coldstart') !== false || stripos($header, 'EC-LB-OP-STATUS') !== false) {
336 return true;
337 }
338 }
339
340 return false;
341 }
342
343 /**
344 * Check if the website is installed locally.
345 * @return bool
346 */
347 public function isLocal(): bool
348 {
349 $siteUrl = get_site_url();
350 $isLocal = false;
351
352 foreach (self::LOCAL_HOSTNAMES as $hostname) {
353 if (strpos($siteUrl, $hostname) !== false) {
354 $isLocal = true;
355 break;
356 }
357 }
358
359 return Hooks::applyFilters(self::FILTER_IS_WPSTG_TESTS, $isLocal);
360 }
361 }
362