Passed
Push — master ( 6b8ca8...3384db )
by Paul
04:57
created

System::getPhpDetails()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 0
cts 21
cp 0
rs 9.3142
c 0
b 0
f 0
cc 2
eloc 19
nc 2
nop 0
crap 6
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules;
4
5
use GeminiLabs\SiteReviews\Application;
6
use GeminiLabs\SiteReviews\Database\OptionManager;
7
use GeminiLabs\SiteReviews\Helper;
8
use Sinergi\BrowserDetector\Browser;
9
10
class System
11
{
12
	const PAD = 40;
13
	const WP_API_URL = 'https://api.wordpress.org/stats/php/1.0/';
14
15
	/**
16
	 * @return string
17
	 */
18
	public function get()
19
	{
20
		$details = [
21
			'version' => 'Plugin Details',
22
			'browser' => 'Browser Details',
23
			'server' => 'Server Details',
24
			'php' => 'PHP Configuration',
25
			'wordpress' => 'WordPress Configuration',
26
			'mu-plugin' => 'Must-Use Plugins',
27
			'multisite-plugin' => 'Network Active Plugins',
28
			'active-plugin' => 'Active Plugins',
29
			'inactive-plugin' => 'Inactive Plugins',
30
			'setting' => 'Plugin Settings',
31
		];
32
		$systemInfo = array_reduce( array_keys( $details ), function( $carry, $key ) use( $details ) {
33
			$methodName = glsr( Helper::class )->buildMethodName( 'get-'.$key.'-details' );
34
			if( method_exists( $this, $methodName ) && $systemDetails = $this->$methodName() ) {
35
				return $carry.$this->implode( $details[$key], $systemDetails );
36
			}
37
			return $carry;
38
		});
39
		return trim( $systemInfo );
40
	}
41
42
	/**
43
	 * @return array
44
	 */
45
	public function getActivePluginDetails()
46
	{
47
		$plugins = get_plugins();
48
		$activePlugins = (array)get_option( 'active_plugins', [] );
49
		$inactive = array_diff_key( $plugins, array_flip( $activePlugins ));
50
		return $this->normalizePluginList( array_diff_key( $plugins, $inactive ));
51
	}
52
53
	/**
54
	 * @return array
55
	 */
56
	public function getBrowserDetails()
57
	{
58
		$browser = new Browser;
59
		$name = esc_attr( $browser->getName() );
60
		$userAgent = esc_attr( $browser->getUserAgent()->getUserAgentString() );
61
		$version = esc_attr( $browser->getVersion() );
62
		return [
63
			'Browser Name' => sprintf( '%s %s', $name, $version ),
64
			'Browser UA' => $userAgent,
65
		];
66
	}
67
68
	/**
69
	 * @return array
70
	 */
71
	public function getInactivePluginDetails()
72
	{
73
		$activePlugins = (array)get_option( 'active_plugins', [] );
74
		return $this->normalizePluginList( array_diff_key( get_plugins(), array_flip( $activePlugins )));
75
	}
76
77
	/**
78
	 * @return void|array
79
	 */
80
	public function getMuPluginDetails()
81
	{
82
		$plugins = array_merge(
83
			get_mu_plugins(),
84
			get_plugins( '/../'.basename( WPMU_PLUGIN_DIR ))
85
		);
86
		if( empty( $plugins ))return;
87
		return $this->normalizePluginList( $plugins );
88
	}
89
90
	/**
91
	 * @return void|array
92
	 */
93
	public function getMultisitePluginDetails()
94
	{
95
		if( !is_multisite() || empty( get_site_option( 'active_sitewide_plugins', [] )))return;
96
		return $this->normalizePluginList( wp_get_active_network_plugins() );
97
	}
98
99
	/**
100
	 * @return aray
0 ignored issues
show
Bug introduced by
The type GeminiLabs\SiteReviews\Modules\aray was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
101
	 */
102
	public function getPhpDetails()
103
	{
104
		$displayErrors = ini_get( 'display_errors' )
105
			? 'On ('.ini_get( 'display_errors' ).')'
106
			: 'N/A';
107
		return [
0 ignored issues
show
Bug Best Practice introduced by
The expression return array('cURL' => v...'upload_max_filesize')) returns the type array<string,null|string> which is incompatible with the documented return type GeminiLabs\SiteReviews\Modules\aray.
Loading history...
108
			'cURL' => var_export( function_exists( 'curl_init' ), 1 ),
0 ignored issues
show
Bug introduced by
Are you sure the usage of var_export(function_exists('curl_init'), 1) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
109
			'Default Charset' => ini_get( 'default_charset' ),
110
			'Display Errors' => $displayErrors,
111
			'fsockopen' => var_export( function_exists( 'fsockopen' ), 1 ),
0 ignored issues
show
Bug introduced by
Are you sure the usage of var_export(function_exists('fsockopen'), 1) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
112
			'Max Execution Time' => ini_get( 'max_execution_time' ),
113
			'Max Input Nesting Level' => ini_get( 'max_input_nesting_level' ),
114
			'Max Input Vars' => ini_get( 'max_input_vars' ),
115
			'Memory Limit' => ini_get( 'memory_limit' ),
116
			'Post Max Size' => ini_get( 'post_max_size' ),
117
			'Session Cookie Path' => esc_html( ini_get( 'session.cookie_path' )),
118
			'Session Name' => esc_html( ini_get( 'session.name' )),
119
			'Session Save Path' => esc_html( ini_get( 'session.save_path' )),
120
			'Session Use Cookies' => var_export( wp_validate_boolean( ini_get( 'session.use_cookies' )), 1 ),
0 ignored issues
show
Bug introduced by
Are you sure the usage of var_export(wp_validate_b...sion.use_cookies')), 1) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
121
			'Session Use Only Cookies' => var_export( wp_validate_boolean( ini_get( 'session.use_only_cookies' )), 1 ),
0 ignored issues
show
Bug introduced by
Are you sure the usage of var_export(wp_validate_b...use_only_cookies')), 1) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
122
			'Upload Max Filesize' => ini_get( 'upload_max_filesize' ),
123
		];
124
	}
125
126
	/**
127
	 * @return array
128
	 */
129
	public function getServerDetails()
130
	{
131
		global $wpdb;
1 ignored issue
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
132
		return [
133
			'Host Name' => $this->getHostName(),
134
			'MySQL Version' => $wpdb->db_version(),
135
			'PHP Version' => PHP_VERSION,
136
			'Server Software' => filter_input( INPUT_SERVER, 'SERVER_SOFTWARE' ),
137
		];
138
	}
139
140
	/**
141
	 * @return array
142
	 */
143
	public function getSettingDetails()
144
	{
145
		$helper = glsr( Helper::class );
146
		$settings = glsr( OptionManager::class )->get( 'settings' );
147
		$settings = $helper->flattenArray( $settings );
148
		foreach( ['submissions.recaptcha.key', 'submissions.recaptcha.secret'] as $key ) {
149
			if( empty( $settings[$key] ))continue;
150
			$settings[$key] = str_repeat( '*', 10 );
151
		}
152
		$details = [];
153
		foreach( $settings as $key => $value ) {
154
			if( $helper->startsWith( 'translations', $key ) && $helper->endsWith( 'id', $key ))continue;
155
			$value = htmlspecialchars( trim( preg_replace('/\s\s+/', '\\n', $value )), ENT_QUOTES, 'UTF-8' );
156
			$details[$key] = $value;
157
		}
158
		return $details;
159
	}
160
161
	/**
162
	 * @return array
163
	 */
164
	public function getVersionDetails()
165
	{
166
		return [
167
			'Current version' => glsr()->version,
168
			'Previous version' => glsr( OptionManager::class )->get( 'version_upgraded_from' ),
169
		];
170
	}
171
172
	/**
173
	 * @return array
174
	 */
175
	public function getWordpressDetails()
176
	{
177
		global $wpdb;
1 ignored issue
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
178
		$theme = wp_get_theme();
179
		return [
180
			'Active Theme' => sprintf( '%s v%s', $theme->Name, $theme->Version ),
0 ignored issues
show
Bug introduced by
It seems like $theme->Name can also be of type false; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

180
			'Active Theme' => sprintf( '%s v%s', /** @scrutinizer ignore-type */ $theme->Name, $theme->Version ),
Loading history...
181
			'Home URL' => home_url(),
182
			'Language' => get_option( 'WPLANG', 'en_US' ),
183
			'Memory Limit' => WP_MEMORY_LIMIT,
184
			'Multisite' => var_export( is_multisite(), 1 ),
0 ignored issues
show
Bug introduced by
Are you sure the usage of var_export(is_multisite(), 1) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
185
			'Page For Posts ID' => get_option( 'page_for_posts' ),
186
			'Page On Front ID' => get_option( 'page_on_front' ),
187
			'Permalink Structure' => get_option( 'permalink_structure', 'default' ),
188
			'Post Stati' => implode( ', ', get_post_stati() ),
189
			'Remote Post' => $this->testRemotePost(),
190
			'Show On Front' => get_option( 'show_on_front' ),
191
			'Site URL' => site_url(),
192
			'Timezone' => get_option( 'timezone_string' ),
193
			'Version' => get_bloginfo( 'version' ),
194
			'WP Debug' => var_export( defined( 'WP_DEBUG' ), 1 ),
0 ignored issues
show
Bug introduced by
Are you sure the usage of var_export(defined('WP_DEBUG'), 1) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
195
			'WP Max Upload Size' => size_format( wp_max_upload_size() ),
196
			'WP Memory Limit' => WP_MEMORY_LIMIT,
197
		];
198
	}
199
200
	/**
201
	 * @return string
202
	 */
203
	protected function detectWebhostProvider()
204
	{
205
		$checks = [
206
			'.accountservergroup.com' => 'Site5',
207
			'.gridserver.com' => 'MediaTemple Grid',
208
			'.inmotionhosting.com' => 'InMotion Hosting',
209
			'.ovh.net' => 'OVH',
210
			'.pair.com' => 'pair Networks',
211
			'.stabletransit.com' => 'Rackspace Cloud',
212
			'.stratoserver.net' => 'STRATO',
213
			'.sysfix.eu' => 'SysFix.eu Power Hosting',
214
			'bluehost.com' => 'Bluehost',
215
			'DH_USER' => 'DreamHost',
216
			'Flywheel' => 'Flywheel',
217
			'ipagemysql.com' => 'iPage',
218
			'ipowermysql.com' => 'IPower',
219
			'localhost:/tmp/mysql5.sock' => 'ICDSoft',
220
			'mysqlv5' => 'NetworkSolutions',
221
			'PAGELYBIN' => 'Pagely',
222
			'secureserver.net' => 'GoDaddy',
223
			'WPE_APIKEY' => 'WP Engine',
224
		];
225
		$serverName = filter_input( INPUT_SERVER, 'SERVER_NAME' );
226
		foreach( $checks as $key => $value ) {
227
			if( defined( $key )
228
				|| filter_input( INPUT_SERVER, $key )
229
				|| strpos( $serverName, $key ) !== false
230
				|| strpos( DB_HOST, $key ) !== false
231
				|| strpos( php_uname(), $key ) !== false ) {
232
				return $host;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $host seems to be never defined.
Loading history...
233
			}
234
		}
235
		return implode( ',', array_filter( [DB_HOST, $serverName] ));
236
	}
237
238
	/**
239
	 * @return string
240
	 */
241
	protected function getHostName()
242
	{
243
		return sprintf( '%s (%s)',
244
			$this->detectWebhostProvider(),
245
			glsr( Helper::class )->getIpAddress()
246
		);
247
	}
248
249
	/**
250
	 * @return array
251
	 */
252
	protected function getWordpressPlugins()
253
	{
254
		$plugins = get_plugins();
255
		$activePlugins = (array)get_option( 'active_plugins', [] );
256
		$inactive = $this->normalizePluginList( array_diff_key( $plugins, array_flip( $activePlugins )));
257
		$active = $this->normalizePluginList( array_diff_key( $plugins, $inactive ));
258
		return $active + $inactive;
259
	}
260
261
	/**
262
	 * @param string $title
263
	 * @return string
264
	 */
265
	protected function implode( $title, array $details )
266
	{
267
		$strings = ['['.$title.']'];
268
		$padding = max( array_map( 'strlen', array_keys( $details )) );
269
		$padding = max( [$padding, static::PAD] );
270
		foreach( $details as $key => $value ) {
271
			$strings[] = is_string( $key )
272
				? sprintf( '%s : %s', str_pad( $key.' ', $padding, '.' ), $value )
273
				: ' - '.$value;
274
		}
275
		return implode( PHP_EOL, $strings ).PHP_EOL.PHP_EOL;
276
	}
277
278
	/**
279
	 * @return array
280
	 */
281
	protected function normalizePluginList( array $plugins )
282
	{
283
		$plugins = array_map( function( $plugin ) {
284
			return sprintf( '%s v%s', $plugin['Name'], $plugin['Version'] );
285
		}, $plugins );
286
		natcasesort( $plugins );
287
		return array_flip( $plugins );
288
	}
289
290
	/**
291
	 * @return string
292
	 */
293
	protected function testRemotePost()
294
	{
295
		$response = wp_remote_post( static::WP_API_URL );
296
		return !is_wp_error( $response )
297
			&& !empty( $response['response']['code'] )
298
			&& in_array( $response['response']['code'], range( 200, 299 ))
299
			? 'Works'
300
			: 'Does not work';
301
	}
302
}
303