Passed
Push — master ( 68f720...5e727b )
by Paul
10:53
created

SystemInfo::purgeSensitiveData()   A

Complexity

Conditions 5
Paths 1

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 15
c 1
b 0
f 0
dl 0
loc 22
ccs 0
cts 21
cp 0
rs 9.4555
cc 5
nc 1
nop 1
crap 30
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules;
4
5
use GeminiLabs\Sinergi\BrowserDetector\Browser;
6
use GeminiLabs\SiteReviews\Database\Cache;
7
use GeminiLabs\SiteReviews\Database\OptionManager;
8
use GeminiLabs\SiteReviews\Database\Query;
9
use GeminiLabs\SiteReviews\Database\SqlSchema;
10
use GeminiLabs\SiteReviews\Helper;
11
use GeminiLabs\SiteReviews\Helpers\Arr;
12
use GeminiLabs\SiteReviews\Helpers\Cast;
13
use GeminiLabs\SiteReviews\Helpers\Str;
14
use WP_Debug_Data;
0 ignored issues
show
Bug introduced by
The type WP_Debug_Data 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...
15
16
class SystemInfo
17
{
18
    const PAD = 40;
19
20
    /**
21
     * @return string
22
     */
23
    public function __toString()
24
    {
25
        return $this->get();
26
    }
27
28
    /**
29
     * @return string
30
     */
31
    public function get()
32
    {
33
        $data = $this->data();
34
        $details = [
35
            'plugin' => $this->getPluginDetails(),
36
            'addon' => $this->getAddonDetails(),
37
            'reviews' => $this->getReviewCounts(),
38
            'setting' => $this->getPluginSettings(),
39
            'browser' => $this->getBrowserDetails(),
40
            'database' => $this->getDatabaseDetails($data),
41
            'server' => $this->getServerDetails($data),
42
            'wordpress' => $this->getWordpressDetails($data),
43
            'mu-plugins' => $this->getMustUsePluginDetails(),
44
            'network-plugins' => $this->getNetworkActivatedPluginDetails(),
45
            'activated-plugins' => $this->getActivePluginDetails(),
46
            'inactive-plugins' => $this->getInactivePluginDetails(),
47
        ];
48
        $systemInfo = array_reduce(array_keys($details), function ($carry, $key) use ($details) {
49
            if (empty(Arr::get($details[$key], 'values'))) {
50
                return $carry;
51
            }
52
            $hook = 'system/'.Str::dashCase($key);
53
            $title = strtoupper(Arr::get($details[$key], 'title'));
54
            $values = glsr()->filterArray($hook, Arr::get($details[$key], 'values'));
55
            return $carry.$this->implode($title, $values);
56
        });
57
        return trim($systemInfo);
58
    }
59
60
    /**
61
     * @return array
62
     */
63
    public function getActivePluginDetails()
64
    {
65
        $plugins = get_plugins();
0 ignored issues
show
Bug introduced by
The function get_plugins was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

65
        $plugins = /** @scrutinizer ignore-call */ get_plugins();
Loading history...
66
        $active = glsr(OptionManager::class)->getWP('active_plugins', [], 'array');
67
        $inactive = array_diff_key($plugins, array_flip($active));
68
        $activePlugins = $this->normalizePluginList(array_diff_key($plugins, $inactive));
69
        return [
70
            'title' => 'Activated Plugins',
71
            'values' => $activePlugins,
72
        ];
73
    }
74
75
    /**
76
     * @return array
77
     */
78
    public function getAddonDetails()
79
    {
80
        $details = glsr()->filterArray('addon/system-info', []);
81
        ksort($details);
82
        return [
83
            'title' => 'Addon Details',
84
            'values' => $details,
85
        ];
86
    }
87
88
    /**
89
     * @return array
90
     */
91
    public function getBrowserDetails()
92
    {
93
        $browser = new Browser();
94
        $name = esc_attr($browser->getName());
0 ignored issues
show
Bug introduced by
The function esc_attr was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

94
        $name = /** @scrutinizer ignore-call */ esc_attr($browser->getName());
Loading history...
95
        $userAgent = esc_attr($browser->getUserAgent()->getUserAgentString());
96
        $version = esc_attr($browser->getVersion());
97
        return [
98
            'title' => 'Browser Details',
99
            'values' => [
100
                'Browser Name' => sprintf('%s %s', $name, $version),
101
                'Browser UA' => $userAgent,
102
            ],
103
        ];
104
    }
105
106
    /**
107
     * @param array $data
108
     * @return array
109
     */
110
    public function getDatabaseDetails($data)
111
    {
112
        $database = Arr::get($data, 'wp-database');
113
        return [
114
            'title' => 'Database Details',
115
            'values' => [
116
                'Charset' => Arr::get($database, 'database_charset'),
117
                'Collation' => Arr::get($database, 'database_collate'),
118
                'Extension' => Arr::get($database, 'extension'),
119
                'Table Engines' => implode(', ', glsr(SqlSchema::class)->tableEngines()),
120
                'Version (client)' => Arr::get($database, 'client_version'),
121
                'Version (server)' => Arr::get($database, 'server_version'),
122
            ],
123
        ];
124
    }
125
126
    /**
127
     * @return array
128
     */
129
    public function getInactivePluginDetails()
130
    {
131
        $active = glsr(OptionManager::class)->getWP('active_plugins', [], 'array');
132
        $inactive = $this->normalizePluginList(array_diff_key(get_plugins(), array_flip($active)));
0 ignored issues
show
Bug introduced by
The function get_plugins was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

132
        $inactive = $this->normalizePluginList(array_diff_key(/** @scrutinizer ignore-call */ get_plugins(), array_flip($active)));
Loading history...
133
        $networkActivated = $this->getNetworkActivatedPluginDetails();
134
        $networkActivated = Arr::consolidate(Arr::get($networkActivated, 'values'));
135
        $inactivePlugins = Helper::ifTrue(empty($networkActivated), $inactive, array_diff($inactive, $networkActivated));
136
        return [
137
            'title' => 'Inactive Plugins',
138
            'values' => $inactivePlugins,
139
        ];
140
    }
141
142
    /**
143
     * @return array
144
     */
145
    public function getMustUsePluginDetails()
146
    {
147
        $plugins = get_mu_plugins();
0 ignored issues
show
Bug introduced by
The function get_mu_plugins was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

147
        $plugins = /** @scrutinizer ignore-call */ get_mu_plugins();
Loading history...
148
        $muplugins = Helper::ifTrue(empty($plugins), [], function () use ($plugins) {
149
            return $this->normalizePluginList($plugins);
150
        });
151
        return [
152
            'title' => 'Must-Use Plugins',
153
            'values' => $muplugins,
154
        ];
155
    }
156
157
    /**
158
     * @return array
159
     */
160
    public function getNetworkActivatedPluginDetails()
161
    {
162
        $plugins = Arr::consolidate(get_site_option('active_sitewide_plugins', []));
0 ignored issues
show
Bug introduced by
The function get_site_option was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

162
        $plugins = Arr::consolidate(/** @scrutinizer ignore-call */ get_site_option('active_sitewide_plugins', []));
Loading history...
163
        if (!is_multisite() || empty($plugins)) {
0 ignored issues
show
Bug introduced by
The function is_multisite was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

163
        if (!/** @scrutinizer ignore-call */ is_multisite() || empty($plugins)) {
Loading history...
164
            return [];
165
        }
166
        $networkPlugins = $this->normalizePluginList(array_intersect_key(get_plugins(), $plugins));
0 ignored issues
show
Bug introduced by
The function get_plugins was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

166
        $networkPlugins = $this->normalizePluginList(array_intersect_key(/** @scrutinizer ignore-call */ get_plugins(), $plugins));
Loading history...
167
        return [
168
            'title' => 'Network Activated Plugins',
169
            'values' => $networkPlugins,
170
        ];
171
    }
172
173
    /**
174
     * @return array
175
     */
176
    public function getPluginDetails()
177
    {
178
        require_once ABSPATH.'/wp-admin/includes/plugin.php';
179
        return [
180
            'title' => 'Plugin Details',
181
            'values' => [
182
                'Console Level' => glsr(Console::class)->humanLevel(),
183
                'Console Size' => glsr(Console::class)->humanSize(),
184
                'Database Version' => glsr(OptionManager::class)->getWP(glsr()->prefix.'db_version'),
185
                'Last Migration Run' => glsr(Date::class)->localized(glsr(OptionManager::class)->get('last_migration_run'), 'unknown'),
186
                'Network Activated' => Helper::ifTrue(is_plugin_active_for_network(plugin_basename(glsr()->file)), 'Yes', 'No'),
0 ignored issues
show
Bug introduced by
The function plugin_basename was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

186
                'Network Activated' => Helper::ifTrue(is_plugin_active_for_network(/** @scrutinizer ignore-call */ plugin_basename(glsr()->file)), 'Yes', 'No'),
Loading history...
Bug introduced by
The function is_plugin_active_for_network was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

186
                'Network Activated' => Helper::ifTrue(/** @scrutinizer ignore-call */ is_plugin_active_for_network(plugin_basename(glsr()->file)), 'Yes', 'No'),
Loading history...
187
                'Version' => sprintf('%s (%s)', glsr()->version, glsr(OptionManager::class)->get('version_upgraded_from')),
188
            ],
189
        ];
190
    }
191
192
    /**
193
     * @return array
194
     */
195
    public function getPluginSettings()
196
    {
197
        $settings = glsr(OptionManager::class)->get('settings', []);
198
        $settings = Arr::flatten($settings, true);
199
        $settings = $this->purgeSensitiveData($settings);
200
        ksort($settings);
201
        $details = [];
202
        foreach ($settings as $key => $value) {
203
            if (Str::startsWith('strings', $key) && Str::endsWith('id', $key)) {
204
                continue;
205
            }
206
            $value = htmlspecialchars(trim(preg_replace('/\s\s+/u', '\\n', $value)), ENT_QUOTES, 'UTF-8');
207
            $details[$key] = $value;
208
        }
209
        return [
210
            'title' => 'Plugin Settings',
211
            'values' => $details,
212
        ];
213
    }
214
215
    /**
216
     * @return array
217
     */
218
    public function getReviewCounts()
219
    {
220
        $counts = glsr(Query::class)->ratings();
221
        array_walk($counts, function (&$ratings) use ($counts) {
222
            if (is_array($ratings)) {
223
                $ratings = array_sum($ratings).' ('.implode(', ', $ratings).')';
224
                return;
225
            }
226
            glsr_log()
227
                ->error('$ratings is not an array, possibly due to incorrectly imported reviews.')
228
                ->debug($ratings)
229
                ->debug($counts);
230
        });
231
        ksort($counts);
232
        return [
233
            'title' => 'Review Counts',
234
            'values' => wp_parse_args($counts, ['local' => 'No reviews']),
0 ignored issues
show
Bug introduced by
The function wp_parse_args was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

234
            'values' => /** @scrutinizer ignore-call */ wp_parse_args($counts, ['local' => 'No reviews']),
Loading history...
235
        ];
236
    }
237
238
    /**
239
     * @param array $data
240
     * @return array
241
     */
242
    public function getServerDetails($data)
243
    {
244
        $media = Arr::get($data, 'wp-media');
245
        $server = Arr::get($data, 'wp-server');
246
        return [
247
            'title' => 'Server Details',
248
            'values' => [
249
                'cURL Version' => Arr::get($server, 'curl_version'),
250
                'Display Errors' => Helper::ifEmpty($this->getIni('display_errors'), 'No'),
251
                'File Uploads' => Arr::get($media, 'file_uploads'),
252
                'GD version' => Arr::get($media, 'gd_version'),
253
                'Ghostscript version' => Arr::get($media, 'ghostscript_version'),
254
                'Host Name' => $this->getHostName(),
255
                'ImageMagick version' => Arr::get($media, 'imagemagick_version'),
256
                'Intl' => Helper::ifEmpty(phpversion('intl'), 'No'),
257
                'IPv6' => var_export(defined('AF_INET6'), true),
258
                'Max Effective File Size' => Arr::get($media, 'max_effective_size'),
259
                'Max Execution Time' => Arr::get($server, 'time_limit'),
260
                'Max File Uploads' => Arr::get($media, 'max_file_uploads'),
261
                'Max Input Time' => Arr::get($server, 'max_input_time'),
262
                'Max Input Variables' => Arr::get($server, 'max_input_variables'),
263
                'Memory Limit' => Arr::get($server, 'memory_limit'),
264
                'Multibyte' => Helper::ifEmpty(phpversion('mbstring'), 'No'),
265
                'Permalinks Supported' => Arr::get($server, 'pretty_permalinks'),
266
                'PHP Version' => Arr::get($server, 'php_version'),
267
                'Post Max Size' => Arr::get($server, 'php_post_max_size'),
268
                'SAPI' => Arr::get($server, 'php_sapi'),
269
                'Sendmail' => $this->getIni('sendmail_path'),
270
                'Server Architecture' => Arr::get($server, 'server_architecture'),
271
                'Server Software' => Arr::get($server, 'httpd_software'),
272
                'SUHOSIN Installed' => Arr::get($server, 'suhosin'),
273
                'Upload Max Filesize' => Arr::get($server, 'upload_max_filesize'),
274
            ],
275
        ];
276
    }
277
278
    /**
279
     * @param array $data
280
     * @return array
281
     */
282
    public function getWordpressDetails($data)
283
    {
284
        $constants = Arr::get($data, 'wp-constants');
285
        $wordpress = Arr::get($data, 'wp-core');
286
        return [
287
            'title' => 'WordPress Configuration',
288
            'values' => [
289
                'Email Domain' => substr(strrchr(glsr(OptionManager::class)->getWP('admin_email'), '@'), 1),
290
                'Environment' => Arr::get($wordpress, 'environment_type'),
291
                'Hidden From Search Engines' => Arr::get($wordpress, 'blog_public'),
292
                'Home URL' => Arr::get($wordpress, 'home_url'),
293
                'HTTPS' => Arr::get($wordpress, 'https_status'),
294
                'Language (site)' => Arr::get($wordpress, 'site_language'),
295
                'Language (user)' => Arr::get($wordpress, 'user_language'),
296
                'Multisite' => Arr::get($wordpress, 'multisite'),
297
                'Page For Posts ID' => glsr(OptionManager::class)->getWP('page_for_posts'),
298
                'Page On Front ID' => glsr(OptionManager::class)->getWP('page_on_front'),
299
                'Permalink Structure' => Arr::get($wordpress, 'permalink'),
300
                'Post Stati' => implode(', ', get_post_stati()),
0 ignored issues
show
Bug introduced by
The function get_post_stati was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

300
                'Post Stati' => implode(', ', /** @scrutinizer ignore-call */ get_post_stati()),
Loading history...
301
                'Remote Post' => glsr(Cache::class)->getRemotePostTest(),
302
                'SCRIPT_DEBUG' => Arr::get($constants, 'SCRIPT_DEBUG'),
303
                'Show On Front' => glsr(OptionManager::class)->getWP('show_on_front'),
304
                'Site URL' => Arr::get($wordpress, 'site_url'),
305
                'Theme (active)' => sprintf('%s v%s', Arr::get($data, 'wp-active-theme.name'), Arr::get($data, 'wp-active-theme.version')),
306
                'Theme (parent)' => Arr::get($data, 'wp-parent-theme.name', 'No'),
307
                'Timezone' => Arr::get($wordpress, 'timezone'),
308
                'User Count' => Arr::get($wordpress, 'user_count'),
309
                'Version' => Arr::get($wordpress, 'version'),
310
                'WP_CACHE' => Arr::get($constants, 'WP_CACHE'),
311
                'WP_DEBUG' => Arr::get($constants, 'WP_DEBUG'),
312
                'WP_DEBUG_DISPLAY' => Arr::get($constants, 'WP_DEBUG_DISPLAY'),
313
                'WP_DEBUG_LOG' => Arr::get($constants, 'WP_DEBUG_LOG'),
314
                'WP_MAX_MEMORY_LIMIT' => Arr::get($constants, 'WP_MAX_MEMORY_LIMIT'),
315
            ],
316
        ];
317
    }
318
319
    /**
320
     * @return array
321
     */
322
    public function data()
323
    {
324
        $data = WP_Debug_Data::debug_data();
325
        array_walk($data, function (&$section) {
326
            $fields = Arr::consolidate(Arr::get($section, 'fields'));
327
            array_walk($fields, function (&$values) {
328
                $values = Arr::get($values, 'value');
329
            });
330
            $section = $fields;
331
        });
332
        return $data;
333
    }
334
335
    /**
336
     * @return string
337
     */
338
    protected function getHostName()
339
    {
340
        return sprintf('%s (%s)', $this->detectWebhostProvider(), Helper::getIpAddress());
341
    }
342
343
    /**
344
     * @param string $name
345
     * @param string $disabledValue
346
     * @return string
347
     */
348
    protected function getIni($name, $disabledValue = 'ini_get() is disabled.')
349
    {
350
        return Helper::ifTrue(!function_exists('ini_get'), $disabledValue, function () use ($name) {
351
            return ini_get($name);
352
        });
353
    }
354
355
    /**
356
     * @param string $title
357
     * @return string
358
     */
359
    protected function implode($title, array $details)
360
    {
361
        $strings = ['['.$title.']'];
362
        $padding = max(array_map('strlen', array_keys($details)));
363
        $padding = max([$padding, static::PAD]);
364
        foreach ($details as $key => $value) {
365
            $pad = $padding - (mb_strlen($key, 'UTF-8') - strlen($key)); // handle unicode characters
366
            $strings[] = is_string($key)
367
                ? sprintf('%s : %s', str_pad($key, $pad, '.'), $value)
368
                : ' - '.$value;
369
        }
370
        return implode(PHP_EOL, $strings).PHP_EOL.PHP_EOL;
371
    }
372
373
    /**
374
     * @return string
375
     */
376
    protected function detectWebhostProvider()
377
    {
378
        $checks = [
379
            '.accountservergroup.com' => 'Site5',
380
            '.gridserver.com' => 'MediaTemple Grid',
381
            '.inmotionhosting.com' => 'InMotion Hosting',
382
            '.ovh.net' => 'OVH',
383
            '.pair.com' => 'pair Networks',
384
            '.stabletransit.com' => 'Rackspace Cloud',
385
            '.stratoserver.net' => 'STRATO',
386
            '.sysfix.eu' => 'SysFix.eu Power Hosting',
387
            'bluehost.com' => 'Bluehost',
388
            'DH_USER' => 'DreamHost',
389
            'Flywheel' => 'Flywheel',
390
            'ipagemysql.com' => 'iPage',
391
            'ipowermysql.com' => 'IPower',
392
            'localhost:/tmp/mysql5.sock' => 'ICDSoft',
393
            'mysqlv5' => 'NetworkSolutions',
394
            'PAGELYBIN' => 'Pagely',
395
            'secureserver.net' => 'GoDaddy',
396
            'WPE_APIKEY' => 'WP Engine',
397
        ];
398
        foreach ($checks as $key => $value) {
399
            if (!$this->isWebhostCheckValid($key)) {
400
                continue;
401
            }
402
            return $value;
403
        }
404
        return implode(',', array_filter([DB_HOST, filter_input(INPUT_SERVER, 'SERVER_NAME')]));
0 ignored issues
show
Bug introduced by
The constant GeminiLabs\SiteReviews\Modules\DB_HOST was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
405
    }
406
407
    /**
408
     * @param string $key
409
     * @return bool
410
     */
411
    protected function isWebhostCheckValid($key)
412
    {
413
        return defined($key)
414
            || filter_input(INPUT_SERVER, $key)
415
            || Str::contains($key, filter_input(INPUT_SERVER, 'SERVER_NAME'))
416
            || Str::contains($key, DB_HOST)
0 ignored issues
show
Bug introduced by
The constant GeminiLabs\SiteReviews\Modules\DB_HOST was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
417
            || Str::contains($key, php_uname());
418
    }
419
420
    /**
421
     * @return array
422
     */
423
    protected function normalizePluginList(array $plugins)
424
    {
425
        $plugins = array_map(function ($plugin) {
426
            return sprintf('%s v%s', Arr::get($plugin, 'Name'), Arr::get($plugin, 'Version'));
427
        }, $plugins);
428
        natcasesort($plugins);
429
        return array_flip($plugins);
430
    }
431
432
    /**
433
     * @return array
434
     */
435
    protected function purgeSensitiveData(array $settings)
436
    {
437
        $keys = glsr()->filterArray('addon/system-info/purge', [
438
            'licenses.' => 8,
439
            'submissions.recaptcha.key' => 0,
440
            'submissions.recaptcha.secret' => 0,
441
        ]);
442
        array_walk($settings, function (&$value, $setting) use ($keys) {
443
            foreach ($keys as $key => $preserve) {
444
                if (!is_string($key)) { // @compat for older addons
445
                    $key = $preserve;
446
                    $preserve = 0;
447
                }
448
                if (Str::startsWith($key, $setting) && !empty($value)) {
449
                    $preserve = Cast::toInt($preserve);
450
                    $value = substr($value, -$preserve, $preserve);
451
                    $value = str_pad($value, 13, '*', STR_PAD_LEFT);
452
                    break;
453
                }
454
            }
455
        });
456
        return $settings;
457
    }
458
}
459