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