PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.3.1
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.3.1
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 / Backend / Modules / SystemInfo.php
wp-staging / Backend / Modules Last commit date
Jobs 2 years ago Views 2 years ago SystemInfo.php 2 years ago
SystemInfo.php
867 lines
1 <?php
2
3 namespace WPStaging\Backend\Modules;
4
5 use WPStaging\Backend\Upgrade\Upgrade;
6 use WPStaging\Backup\Ajax\FileList\ListableBackupsCollection;
7 use WPStaging\Core\Utils\Browser;
8 use WPStaging\Core\WPStaging;
9 use WPStaging\Core\Utils\Multisite;
10 use WPStaging\Framework\Utils\Urls;
11 use WPStaging\Framework\Adapter\Database;
12 use WPStaging\Framework\BackgroundProcessing\Queue;
13 use WPStaging\Framework\Facades\Sanitize;
14 use WPStaging\Framework\Staging\Sites;
15 use WPStaging\Framework\SiteInfo;
16
17 // No Direct Access
18 if (!defined("WPINC")) {
19 die;
20 }
21
22 /**
23 * Class SystemInfo
24 * @package WPStaging\Backend\Modules
25 */
26 class SystemInfo
27 {
28 /**
29 * @var bool
30 */
31 private $isMultiSite;
32
33 /** @var mixed|Database */
34 private $database;
35
36 /**
37 * @var Urls
38 */
39 private $urlsHelper;
40
41 public function __construct()
42 {
43 $this->isMultiSite = is_multisite();
44 $this->urlsHelper = WPStaging::make(Urls::class);
45 $this->database = WPStaging::make(Database::class);
46 }
47
48 /**
49 * Magic method
50 * @return string
51 */
52 public function __toString()
53 {
54 return $this->get();
55 }
56
57 /**
58 * Get System Information as text
59 * @return string
60 */
61 public function get(): string
62 {
63 $output = $this->server();
64
65 $output .= $this->php();
66
67 $output .= $this->wp();
68
69 $output .= $this->getMultisiteInfo();
70
71 $output .= $this->wpstaging();
72
73 $output .= $this->plugins();
74
75 $output .= $this->multiSitePlugins();
76
77 $output .= $this->phpExtensions();
78
79 $output .= $this->browser();
80
81 $output .= PHP_EOL . "### End System Info ###";
82
83 return $output;
84 }
85
86 /**
87 * @param string $string
88 * @return string
89 */
90 public function header(string $string): string
91 {
92 return PHP_EOL . "### {$string} ###" . PHP_EOL . PHP_EOL;
93 }
94
95 /**
96 * Formatting title and the value
97 * @param string $title
98 * @param string|array $value
99 * @return string
100 */
101 public function info(string $title, $value): string
102 {
103 return str_pad($title, 56, ' ', STR_PAD_RIGHT) . print_r($value, true) . PHP_EOL;
104 }
105
106 /**
107 * WordPress Configuration
108 * @return string
109 */
110 public function wp(): string
111 {
112 global $wpdb;
113
114 $output = $this->header("WordPress");
115 $output .= $this->info("Site:", ($this->isMultiSite) ? 'Multi Site' : 'Single Site');
116 $output .= $this->info("WP Version:", get_bloginfo("version"));
117 $output .= $this->info("Installed in subdir:", ($this->isSubDir() ? 'Yes' : 'No'));
118 $output .= $this->info("Table Prefix:", $this->getTablePrefix());
119 $output .= $this->info("site_url():", site_url());
120 $output .= $this->info("home_url():", $this->urlsHelper->getHomeUrl());
121 $output .= $this->info("get_home_path():", get_home_path());
122 $output .= $this->info("ABSPATH:", ABSPATH);
123
124 $permissions = fileperms(ABSPATH);
125
126 $output .= $this->info("ABSPATH Fileperms:", $permissions);
127
128 $permissions = substr(sprintf('%o', $permissions), -4);
129
130 $output .= $this->info("ABSPATH Permissions:", $permissions);
131
132 $absPathStat = stat(ABSPATH);
133 if (!$absPathStat) {
134 $absPathStat = "";
135 } else {
136 $absPathStat = json_encode($absPathStat);
137 }
138
139 $output .= $this->info("ABSPATH Stat:", $absPathStat);
140 $output .= $this->constantInfo('WP_PLUGIN_DIR');
141 $output .= $this->constantInfo('WP_CONTENT_DIR');
142
143 $output .= $this->info("Is wp-content link:", is_link(WP_CONTENT_DIR) ? 'Yes' : 'No');
144 if (is_link(WP_CONTENT_DIR)) {
145 $output .= $this->info("wp-content link target:", readlink(WP_CONTENT_DIR));
146 $output .= $this->info("wp-content realpath:", realpath(WP_CONTENT_DIR));
147 }
148
149 $output .= $this->constantInfo('UPLOADS');
150
151 $uploads = wp_upload_dir();
152 $output .= $this->info("uploads['path']:", $uploads['path']);
153 $output .= $this->info("uploads['subdir']:", $uploads['subdir']);
154 $output .= $this->info("uploads['basedir']:", $uploads['basedir']);
155 $output .= $this->info("uploads['baseurl']:", $uploads['baseurl']);
156 $output .= $this->info("uploads['url']:", $uploads['url']);
157
158 $output .= $this->info("UPLOAD_PATH in wp-config.php:", (defined("UPLOAD_PATH")) ? UPLOAD_PATH : '[not set]');
159 $output .= $this->info("upload_path in " . $wpdb->prefix . 'options:', get_option("upload_path") ?: "[not set]");
160
161 $output .= $this->constantInfo('WP_TEMP_DIR');
162
163 $output .= $this->info("WP_DEBUG:", (defined("WP_DEBUG")) ? (WP_DEBUG ? "Enabled" : "Disabled") : "Not set");
164 $output .= $this->constantInfo('WP_MEMORY_LIMIT');
165 $output .= $this->constantInfo('WP_MAX_MEMORY_LIMIT');
166 $output .= $this->info("Active Theme:", $this->theme());
167 $output .= $this->info("Permalink Structure:", get_option("permalink_structure") ?: "Default");
168 $output .= $this->wpRemotePost();
169 $output .= $this->info("WPLANG:", (defined("WPLANG") && WPLANG) ? WPLANG : "en_US");
170 $output .= $this->info("Wordpress cron:", wp_json_encode(get_option('cron', [])));
171
172 return $output;
173 }
174
175 /**
176 * Theme Information
177 * @return string
178 */
179 public function theme(): string
180 {
181 // Versions earlier than 3.4
182 if (get_bloginfo("version") < "3.4") {
183 $themeData = get_theme_data(get_stylesheet_directory() . "/style.css");
184 return "{$themeData["Name"]} {$themeData["Version"]}";
185 }
186
187 $themeData = wp_get_theme();
188 return "{$themeData->Name} {$themeData->Version}";
189 }
190
191 /**
192 * Multisite information
193 * @return string
194 */
195 private function getMultisiteInfo(): string
196 {
197 if (!$this->isMultiSite) {
198 return '';
199 }
200
201 $multisite = new Multisite();
202
203 $output = $this->info("Multisite:", "Yes");
204 $output .= $this->info("Multisite Blog ID:", get_current_blog_id());
205 $output .= $this->info("MultiSite URL:", $multisite->getHomeURL());
206 $output .= $this->info("MultiSite URL without scheme:", $multisite->getHomeUrlWithoutScheme());
207 $output .= $this->info("MultiSite is Main Site:", is_main_site() ? 'Yes' : 'No');
208
209 $output .= $this->constantInfo('SUBDOMAIN_INSTALL');
210 $output .= $this->constantInfo('DOMAIN_CURRENT_SITE');
211 $output .= $this->constantInfo('PATH_CURRENT_SITE');
212 $output .= $this->constantInfo('SITE_ID_CURRENT_SITE');
213 $output .= $this->constantInfo('BLOG_ID_CURRENT_SITE');
214
215 $networkSites = get_sites();
216 $output .= PHP_EOL . $this->info("Network Sites:", count($networkSites)) . PHP_EOL;
217 foreach ($networkSites as $site) {
218 $siteDetails = get_blog_details($site->blog_id);
219 if (!$siteDetails) {
220 continue;
221 }
222
223 $output .= $this->info("Blog ID:", $site->blog_id);
224 $output .= $this->info("Home URL:", get_home_url($site->blog_id));
225 $output .= $this->info("Site URL:", get_site_url($site->blog_id));
226 $output .= $this->info("Domain:", $site->domain);
227 $output .= $this->info("Path:", $site->path);
228 $output .= PHP_EOL;
229 }
230
231 return $output;
232 }
233
234 /**
235 * Wp Staging plugin Information
236 * @return string
237 */
238 public function wpstaging(): string
239 {
240 $settings = (object)get_option('wpstg_settings', []);
241
242 $output = PHP_EOL . "## WP Staging ##" . PHP_EOL . PHP_EOL;
243
244 $output .= $this->info("Pro Version:", get_option('wpstgpro_version', '[not set]'));
245 $output .= $this->info("Pro License Key:", get_option('wpstg_license_key') ?: '[not set]');
246 // @see \WPStaging\Backend\Pro\Upgrade\Upgrade::OPTION_INSTALL_DATE
247 $output .= $this->info("Pro Install Date:", get_option('wpstgpro_install_date', '[not set]'));
248 // @see \WPStaging\Backend\Pro\Upgrade\Upgrade::OPTION_UPGRADE_DATE
249 $output .= $this->info("Pro Update Date:", get_option('wpstgpro_upgrade_date', '[not set]'));
250 $output .= $this->info("Free or Pro Install Date (legacy):", get_option('wpstg_installDate', '[not set]'));
251 $output .= $this->info("Free Version:", get_option('wpstg_version', '[not set]'));
252 $output .= $this->info("Free Install Date:", get_option(Upgrade::OPTION_INSTALL_DATE, '[not set]'));
253 $output .= $this->info("Free Update Date:", get_option(Upgrade::OPTION_UPGRADE_DATE, '[not set]'));
254 $output .= $this->info("Updated from Pro Version:", get_option('wpstgpro_version_upgraded_from') ?: "[not set]");
255 $output .= $this->info("Updated from Free Version:", get_option('wpstg_version_upgraded_from') ?: "[not set]");
256 $output .= $this->info("Is Staging Site:", (new SiteInfo())->isStagingSite() ? 'true' : 'false');
257 $output .= $this->getBackupDetails();
258 $output .= $this->getScheduleInfo();
259 $output .= $this->info("DB Query Limit:", isset($settings->queryLimit) ? $settings->queryLimit : '[not set]');
260 $output .= $this->info("DB Search & Replace Limit:", isset($settings->querySRLimit) ? $settings->querySRLimit : '[not set]');
261 $output .= $this->info("File Copy Limit:", isset($settings->fileLimit) ? $settings->fileLimit : '[not set]');
262 $output .= $this->info("Maximum File Size:", isset($settings->maxFileSize) ? $settings->maxFileSize : '[not set]');
263 $output .= $this->info("File Copy Batch Size:", isset($settings->batchSize) ? $settings->batchSize : '[not set]');
264 $output .= $this->info("CPU Load Priority:", isset($settings->cpuLoad) ? $settings->cpuLoad : '[not set]');
265 $output .= $this->info("Keep Permalinks:", isset($settings->keepPermalinks) ? $settings->keepPermalinks : '[not set]');
266 $output .= $this->info("Debug Mode:", isset($settings->debugMode) ? $settings->debugMode : '[NOT SET]');
267 $output .= $this->info("Optimize Active:", isset($settings->optimizer) ? $settings->optimizer : '[not set]');
268 $output .= $this->info("Delete on Uninstall:", isset($settings->unInstallOnDelete) ? $settings->unInstallOnDelete : '[not set]');
269 $output .= $this->info("Check Directory Size:", isset($settings->checkDirectorySize) ? $settings->checkDirectorySize : '[not set]');
270 $output .= $this->info("Access Permissions:", isset($settings->userRoles) ? $settings->userRoles : '[not set]');
271 $output .= $this->info("Users With Staging Access:", isset($settings->usersWithStagingAccess) ? $settings->usersWithStagingAccess : '[not set]');
272 $output .= $this->info("Admin Bar Color:", isset($settings->adminBarColor) ? $settings->adminBarColor : '[not set]');
273 $analyticsHasConsent = get_option('wpstg_analytics_has_consent');
274 $output .= $this->info("Send Usage Information:", !empty($analyticsHasConsent) ? 'true' : 'false');
275 $output .= $this->info("Send Backup Errors via E-Mail:", isset($settings->schedulesErrorReport) ? $settings->schedulesErrorReport : '[not set]');
276 $output .= $this->info("E-Mail Address:", isset($settings->schedulesReportEmail) ? $settings->schedulesReportEmail : '[not set]');
277
278 $output .= PHP_EOL . "-- Google Drive Settings" . PHP_EOL;
279
280 $googleDriveSettings = (array)get_option('wpstg_googledrive', []);
281 if (!empty($googleDriveSettings)) {
282 foreach ($googleDriveSettings as $key => $value) {
283 $output .= $this->info($key, empty($value) ? '[not set]' : $this->removeCredentials($key, $value));
284 }
285 }
286
287 $output .= PHP_EOL . "-- Amazon S3 Settings" . PHP_EOL;
288
289 $amazonS3Settings = (array)get_option('wpstg_amazons3', []);
290 if (!empty($amazonS3Settings)) {
291 foreach ($amazonS3Settings as $key => $value) {
292 $output .= $this->info($key, empty($value) ? '[not set]' : $this->removeCredentials($key, $value));
293 }
294 }
295
296 $output .= PHP_EOL . "-- DigitalOcean Spaces Settings" . PHP_EOL;
297
298 $digitalOceanSpacesSettings = (array)get_option('wpstg_digitalocean-spaces', []);
299 if (!empty($digitalOceanSpacesSettings)) {
300 foreach ($digitalOceanSpacesSettings as $key => $value) {
301 $output .= $this->info($key, empty($value) ? 'not set' : $this->removeCredentials($key, $value));
302 }
303 }
304
305 $output .= PHP_EOL . "-- Wasabi Settings" . PHP_EOL;
306
307 $wasabiSettings = (array)get_option('wpstg_wasabi-s3', []);
308 if (!empty($wasabiSettings)) {
309 foreach ($wasabiSettings as $key => $value) {
310 $output .= $this->info($key, empty($value) ? 'not set' : $this->removeCredentials($key, $value));
311 }
312 }
313
314 $output .= PHP_EOL . "-- Generic S3 Settings" . PHP_EOL;
315
316 $genericS3Settings = (array)get_option('wpstg_generic-s3', []);
317 if (!empty($genericS3Settings)) {
318 foreach ($genericS3Settings as $key => $value) {
319 $output .= $this->info($key, empty($value) ? 'not set' : $this->removeCredentials($key, $value));
320 }
321 }
322
323 $output .= PHP_EOL . "-- SFTP Settings" . PHP_EOL;
324
325 $sftpSettings = (array)get_option('wpstg_sftp', []);
326 if (!empty($sftpSettings)) {
327 foreach ($sftpSettings as $key => $value) {
328 $output .= $this->info($key, empty($value) ? '[not set]' : $this->removeCredentials($key, $value));
329 }
330 }
331
332 $output .= PHP_EOL . "-- Existing Staging Sites" . PHP_EOL . PHP_EOL;
333
334 // Clones data version > 2.x
335 // old name wpstg_existing_clones_beta
336 // New name since version 4.0.3 wpstg_staging_sites
337 $stagingSites = get_option(Sites::STAGING_SITES_OPTION, []);
338 if (is_array($stagingSites)) {
339 foreach ($stagingSites as $key => $clone) {
340 $path = !empty($clone['path']) ? $clone['path'] : '[not set]';
341
342 $output .= $this->info("Number:", isset($clone['number']) ? $clone['number'] : '[not set]');
343 $output .= $this->info("directoryName:", isset($clone['directoryName']) ? $clone['directoryName'] : '[not set]');
344 $output .= $this->info("Path:", $path);
345 $output .= $this->info("URL:", isset($clone['url']) ? $clone['url'] : '[not set]');
346 $output .= $this->info("DB Prefix:", isset($clone['prefix']) ? $clone['prefix'] : '[not set]');
347 $output .= $this->info("DB Prefix wp-config.php:", $this->getStagingPrefix($clone));
348 $output .= $this->info("WP STAGING Version:", isset($clone['version']) ? $clone['version'] : '[not set]');
349 $output .= $this->info("WP Version:", $this->getStagingWpVersion($path)) . PHP_EOL . PHP_EOL;
350 }
351 }
352
353 $output .= $this->info(Sites::STAGING_SITES_OPTION . ": ", serialize(get_option(Sites::STAGING_SITES_OPTION, [])));
354 $output .= $this->info(Sites::BACKUP_STAGING_SITES_OPTION . ": ", serialize(get_option(Sites::BACKUP_STAGING_SITES_OPTION, [])));
355 $output .= PHP_EOL;
356
357 $output .= "-- Legacy Options" . PHP_EOL . PHP_EOL;
358
359 $output .= $this->info("wpstg_existing_clones: ", serialize(get_option('wpstg_existing_clones')));
360 $output .= $this->info(Sites::OLD_STAGING_SITES_OPTION . ": ", serialize(get_option(Sites::OLD_STAGING_SITES_OPTION, [])));
361
362 return $output;
363 }
364
365 /**
366 * @return string
367 */
368 public function getWpStagingVersion(): string
369 {
370 if (defined('WPSTG_VERSION')) {
371 return WPSTG_VERSION;
372 }
373
374 if (defined('WPSTGPRO_VERSION')) {
375 return 'Pro ' . WPSTGPRO_VERSION;
376 }
377
378 return 'unknown';
379 }
380
381 /**
382 * Browser Information
383 * @return string
384 */
385 public function browser(): string
386 {
387 $output = $this->header("User Browser");
388 $output .= (new Browser());
389
390 return $output;
391 }
392
393 /**
394 * Check wp_remote_post() functionality
395 * @return string
396 */
397 public function wpRemotePost(): string
398 {
399 // Make sure wp_remote_post() is working
400 $wpRemotePost = "does not work";
401
402 // Send request
403 $response = wp_remote_post(
404 "https://www.paypal.com/cgi-bin/webscr",
405 [
406 "sslverify" => false,
407 "timeout" => 60,
408 "user-agent" => "WPSTG/" . WPStaging::getVersion(),
409 "body" => ["cmd" => "_notify-validate"]
410 ]
411 );
412
413 // Validate it worked
414 if (!is_wp_error($response) && $response["response"]["code"] >= 200 && $response["response"]["code"] < 300) {
415 $wpRemotePost = "works";
416 }
417
418 return $this->info("wp_remote_post():", $wpRemotePost);
419 }
420
421 /**
422 * List of Active Plugins
423 * @param array $plugins
424 * @param array $activePlugins
425 * @return string
426 */
427 public function activePlugins(array $plugins, array $activePlugins): string
428 {
429 $output = $this->header("WordPress Active Plugins");
430
431 foreach ($plugins as $path => $plugin) {
432 if (!in_array($path, $activePlugins)) {
433 continue;
434 }
435
436 $output .= $this->info($plugin["Name"] . ":", $plugin["Version"]);
437 }
438
439 return $output;
440 }
441
442 /**
443 * List of Inactive Plugins
444 * @param array $plugins
445 * @param array $activePlugins
446 * @return string
447 */
448 public function inactivePlugins(array $plugins, array $activePlugins): string
449 {
450 $output = $this->header("WordPress Inactive Plugins");
451
452 foreach ($plugins as $path => $plugin) {
453 if (in_array($path, $activePlugins)) {
454 continue;
455 }
456
457 $output .= $this->info($plugin["Name"] . ":", $plugin["Version"]);
458 }
459
460 return $output;
461 }
462
463 /**
464 * Get list of active and inactive plugins
465 * @return string
466 */
467 public function plugins(): string
468 {
469 // Get plugins and active plugins
470 $plugins = get_plugins();
471 $activePlugins = get_option("active_plugins", []);
472
473 // Active plugins
474 $output = $this->activePlugins($plugins, $activePlugins);
475 $output .= $this->inactivePlugins($plugins, $activePlugins);
476
477 return $output;
478 }
479
480 /**
481 * Multisite Plugins
482 * @return string
483 */
484 public function multiSitePlugins(): string
485 {
486 if (!$this->isMultiSite) {
487 return '';
488 }
489
490 $output = $this->header("Network Active Plugins");
491
492 $plugins = wp_get_active_network_plugins();
493 $activePlugins = get_site_option("active_sitewide_plugins", []);
494
495 foreach ($plugins as $pluginPath) {
496 $pluginBase = plugin_basename($pluginPath);
497
498 if (!array_key_exists($pluginBase, $activePlugins)) {
499 continue;
500 }
501
502 $plugin = get_plugin_data($pluginPath);
503
504 $output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
505 }
506
507 unset($plugins, $activePlugins);
508
509 return $output;
510 }
511
512 /**
513 * Server Information
514 * @return string
515 */
516 public function server(): string
517 {
518 $output = $this->header("Start System Info");
519
520 /** @var Database */
521 $database = WPStaging::make(Database::class);
522
523 $output .= $this->info("Webserver:", isset($_SERVER["SERVER_SOFTWARE"]) ? Sanitize::sanitizeString($_SERVER["SERVER_SOFTWARE"]) : '');
524 $output .= $this->info("MySQL Server Type:", $database->getServerType());
525 $output .= $this->info("MySQL Version:", $database->getSqlVersion($compact = true));
526 $output .= $this->info("MySQL Version Full Info:", $database->getSqlVersion());
527 $output .= $this->info("PHP Version:", PHP_VERSION);
528
529 return $output;
530 }
531
532 /**
533 * @return string
534 */
535 public function getMySqlServerType(): string
536 {
537 return $this->database->getServerType();
538 }
539
540 /**
541 * @return string
542 */
543 public function getMySqlFullVersion(): string
544 {
545 return $this->database->getSqlVersion();
546 }
547
548 /**
549 * @return string
550 */
551 public function getMySqlVersionCompact(): string
552 {
553 return $this->database->getSqlVersion($compact = true);
554 }
555
556 /**
557 * @return string
558 */
559 public function getPhpVersion(): string
560 {
561 return PHP_VERSION;
562 }
563
564 /**
565 * @return string
566 */
567 public function getWebServerInfo(): string
568 {
569 return isset($_SERVER["SERVER_SOFTWARE"]) ? Sanitize::sanitizeString($_SERVER["SERVER_SOFTWARE"]) : '';
570 }
571
572 /**
573 * PHP Configuration
574 * @return string
575 */
576 public function php(): string
577 {
578 $output = $this->info("PHP memory_limit:", ini_get("memory_limit"));
579 $output .= $this->info("PHP memory_limit in Bytes:", wp_convert_hr_to_bytes(ini_get("memory_limit")));
580 $output .= $this->info("PHP max_execution_time:", ini_get("max_execution_time"));
581 $output .= $this->info("PHP Safe Mode:", ($this->isSafeModeEnabled() ? "Enabled" : "Disabled"));
582 $output .= $this->info("PHP Upload Max File Size:", ini_get("upload_max_filesize"));
583 $output .= $this->info("PHP Post Max Size:", ini_get("post_max_size"));
584 $output .= $this->info("PHP Upload Max Filesize:", ini_get("upload_max_filesize"));
585 $output .= $this->info("PHP Max Input Vars:", ini_get("max_input_vars"));
586 $displayErrors = ini_get("display_errors");
587 $output .= $this->info("PHP display_errors:", ($displayErrors) ? "On ({$displayErrors})" : "N/A");
588 $output .= $this->info("PHP User:", $this->getPHPUser());
589
590 return $output;
591 }
592
593 /**
594 * @return string
595 */
596 public function getPHPUser(): string
597 {
598
599 $user = '';
600
601 if (extension_loaded('posix') && function_exists('posix_getpwuid')) {
602 $file = WPSTG_PLUGIN_DIR . 'Core/WPStaging.php';
603 $user = posix_getpwuid(fileowner($file));
604 return isset($user['name']) ? $user['name'] : 'can not detect PHP user name';
605 }
606
607 if (function_exists('exec') && @exec('echo EXEC') == 'EXEC') {
608 return exec('whoami');
609 }
610
611 return $user;
612 }
613
614 /**
615 * Check if PHP is on Safe Mode
616 * @return bool
617 */
618 public function isSafeModeEnabled(): bool
619 {
620 return (
621 version_compare(PHP_VERSION, "5.4.0", '<') &&
622 // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
623 @ini_get("safe_mode")
624 );
625 }
626
627 /**
628 * Checks if function exists or not
629 * @param string $functionName
630 * @return string
631 */
632 public function isSupported(string $functionName): string
633 {
634 return (function_exists($functionName)) ? "Supported" : "Not Supported";
635 }
636
637 /**
638 * Checks if class or extension is loaded / exists to determine if it is installed or not
639 * @param string $name
640 * @param bool $isClass
641 * @return string
642 */
643 public function isInstalled(string $name, bool $isClass = true): string
644 {
645 if ($isClass === true) {
646 return (class_exists($name)) ? "Installed" : "Not Installed";
647 } else {
648 return (extension_loaded($name)) ? "Installed" : "Not Installed";
649 }
650 }
651
652 /**
653 * Gets Installed Important PHP Extensions
654 * @return string
655 */
656 public function phpExtensions(): string
657 {
658 // Important PHP Extensions
659 $version = function_exists('curl_version') ? curl_version() : ['version' => 'Error: not available', 'ssl_version' => 'Error: not available', 'host' => 'Error: not available', 'protocols' => [], 'features' => []];
660
661 $bitfields = [
662 'CURL_VERSION_IPV6',
663 'CURL_VERSION_KERBEROS4',
664 'CURL_VERSION_SSL',
665 'CURL_VERSION_LIBZ'
666 ];
667
668 $output = $this->header("PHP Extensions");
669
670 $output .= $this->info("cURL:", $this->isSupported("curl_init"));
671 $output .= $this->info("cURL version:", $version['version']);
672 $output .= $this->info("cURL ssl version number:", $version['ssl_version']);
673 $output .= $this->info("cURL host:", $version['host']);
674
675 foreach ($version['protocols'] as $protocols) {
676 $output .= $this->info("cURL protocols:", $protocols);
677 }
678
679 foreach ($bitfields as $feature) {
680 $output .= $this->info($feature . ":", ($version['features'] & constant($feature) ? 'yes' : 'no'));
681 }
682
683
684 $output .= $this->info("fsockopen:", $this->isSupported("fsockopen"));
685 $output .= $this->info("SOAP Client:", $this->isInstalled("SoapClient"));
686 $output .= $this->info("Suhosin:", $this->isInstalled("suhosin", false));
687
688 return $output;
689 }
690
691 /**
692 * Check if WP is installed in subdir
693 * @return bool
694 */
695 private function isSubDir(): bool
696 {
697 // Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
698 // This is happening much more often than you would expect
699 $siteurl = preg_replace('#^https?://#', '', rtrim(get_option('siteurl'), '/'));
700 $home = preg_replace('#^https?://#', '', rtrim(get_option('home'), '/'));
701
702 if ($home !== $siteurl) {
703 return true;
704 }
705
706 return false;
707 }
708
709 /**
710 * Check and return prefix of the staging site
711 */
712
713 /**
714 * Try to get the staging prefix from wp-config.php of staging site
715 * @param array $clone
716 * @return string
717 */
718 private function getStagingPrefix(array $clone = []): string
719 {
720 // Throw error
721 $path = ABSPATH . $clone['directoryName'] . DIRECTORY_SEPARATOR . "wp-config.php";
722
723 if (!file_exists($path)) {
724 return 'File does not exist in: ' . $path;
725 }
726
727 if (($content = @file_get_contents($path)) === false) {
728 return 'Can\'t find staging wp-config.php';
729 } else {
730 // Get prefix from wp-config.php
731 //preg_match_all("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
732 preg_match("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
733 //wp_die(var_dump($matches));
734
735 if (!empty($matches[1])) {
736 return $matches[1];
737 } else {
738 return 'No table_prefix in wp-config.php';
739 }
740 }
741 }
742
743 /**
744 * Get staging site wordpress version number
745 * @param string $path
746 * @return string
747 */
748 private function getStagingWpVersion(string $path): string
749 {
750
751 if ($path === '[not set]') {
752 return "Error: Cannot detect WP version";
753 }
754
755 // Get version number of wp staging
756 $file = trailingslashit($path) . 'wp-includes/version.php';
757
758 if (!file_exists($file)) {
759 return "Error: Cannot detect WP version. File does not exist: $file";
760 }
761
762 $version = @file_get_contents($file);
763
764 $versionStaging = empty($version) ? 'unknown' : $version;
765
766 preg_match("/\\\$wp_version.*=.*'(.*)';/", $versionStaging, $matches);
767
768 if (empty($matches[1])) {
769 return "Error: Cannot detect WP version";
770 }
771
772 return $matches[1];
773 }
774
775 /**
776 * @param $key
777 * @param $value
778 * @return mixed|string
779 */
780 private function removeCredentials($key, $value)
781 {
782 $protectedFields = ['accessToken', 'refreshToken', 'accessKey', 'secretKey', 'password', 'passphrase'];
783 if (!empty($value) && in_array($key, $protectedFields)) {
784 return '[REMOVED]';
785 }
786
787 return empty($value) ? '[not set]' : $value;
788 }
789
790 /**
791 * @return string
792 */
793 private function getScheduleInfo(): string
794 {
795 $output = '';
796 $backupSchedules = get_option('wpstg_backup_schedules', []);
797 if (!empty($backupSchedules)) {
798 foreach ($backupSchedules as $key => $value) {
799 $output .= $this->info('Schedule ' . !empty($key) ? $key : '', empty($value) ? '[not set]' : print_r($value, true));
800 }
801 } else {
802 $output .= $this->info('wpstg_backup_schedules ', '[not set]');
803 }
804
805 /** @var Queue */
806 $queue = WPStaging::make(Queue::class);
807
808 $output .= $this->info("Backup All Actions in DB:", $queue->count());
809 $output .= $this->info("Backup Pending Actions (ready):", $queue->count(Queue::STATUS_READY));
810 $output .= $this->info("Backup Processing Actions (processing):", $queue->count(Queue::STATUS_PROCESSING));
811 $output .= $this->info("Backup Completed Actions (completed):", $queue->count(Queue::STATUS_COMPLETED));
812 $output .= $this->info("Backup Failed Actions (failed):", $queue->count(Queue::STATUS_FAILED));
813
814 return $output;
815 }
816
817 /**
818 * @return string
819 */
820 private function getTablePrefix(): string
821 {
822 global $wpdb;
823 $tablePrefix = "DB Prefix: " . $wpdb->prefix . ' ';
824 $tablePrefix .= "Length: " . strlen($wpdb->prefix) . " Status: ";
825 $tablePrefix .= (strlen($wpdb->prefix) > 16) ? " ERROR: Too long" : " Acceptable";
826
827 return $tablePrefix;
828 }
829
830 /**
831 * @return string
832 */
833 private function getBackupDetails(): string
834 {
835 $backups = WPStaging::make(ListableBackupsCollection::class)->getListableBackups();
836
837 $output = $this->info("Number of Backups:", count($backups));
838
839 $totalBackupSize = 0;
840 foreach ($backups as $backup) {
841 $totalBackupSize += (float)$backup->size;
842 }
843
844 $output .= $this->info("Backup Total File Size:", esc_html($totalBackupSize) . 'M');
845
846 return $output;
847 }
848
849 /**
850 * @param string $constantName
851 * @return string
852 */
853 protected function constantInfo(string $constantName): string
854 {
855 if (!defined($constantName)) {
856 return $this->info($constantName . ':', '[not set]');
857 }
858
859 $constantValue = constant($constantName);
860 if (is_bool($constantValue)) {
861 $constantValue = $constantValue ? 'Yes' : 'No';
862 }
863
864 return $this->info($constantName . ':', $constantValue);
865 }
866 }
867