1 <?php
2
3 4 5
6 class rex_system_report
7 {
8 private function __construct()
9 {
10 }
11
12 public static function factory()
13 {
14 return new self();
15 }
16
17 public function get()
18 {
19 $data = [];
20
21 $rexVersion = rex::getVersion();
22 $hash = rex::getVersionHash(rex_path::base());
23 if ($hash) {
24 $rexVersion .= '#' . $hash;
25 }
26
27 $data['REDAXO'] = [
28 'Version' => $rexVersion,
29 ];
30
31 $data['PHP'] = [
32 'Version' => PHP_VERSION,
33 'OPcache' => extension_loaded('Zend OPcache') && ini_get('opcache.enable'),
34 'Xdebug' => extension_loaded('xdebug'),
35 ];
36
37 foreach (rex::getProperty('db') as $dbId => $db) {
38 if (empty($db['name'])) {
39 continue;
40 }
41
42 $dbCharacterSet = rex_sql::factory($dbId)->getArray(
43 'SELECT default_character_set_name, default_collation_name FROM information_schema.SCHEMATA WHERE schema_name = ?',
44 [$db['name']]
45 )[0];
46
47 $data['Database'.(1 === $dbId ? '' : " $dbId")] = [
48 'Version' => rex_sql::getServerVersion(),
49 'Character set' => "$dbCharacterSet[default_character_set_name] ($dbCharacterSet[default_collation_name])",
50 ];
51 }
52
53 $server = [
54 'OS' => PHP_OS,
55 'SAPI' => PHP_SAPI,
56 ];
57
58 if (isset($_SERVER['SERVER_SOFTWARE']) && preg_match('@^[^/]+(?:/[\d.]+)?@', $_SERVER['SERVER_SOFTWARE'], $match)) {
59 $server['Webserver'] = $match[0];
60 }
61
62 $data['Server'] = $server;
63
64 if ('cli' !== PHP_SAPI) {
65 $data['Request'] = [
66 'Browser' => $this->getBrowser(),
67 'Protocol' => $_SERVER['SERVER_PROTOCOL'],
68 'HTTPS' => rex_request::isHttps(),
69 ];
70 }
71
72 $packages = [];
73 foreach (rex_package::getAvailablePackages() as $package) {
74 $packages[$package->getPackageId()] = $package->getVersion();
75 }
76
77 $data['Packages'] = $packages;
78
79 return $data;
80 }
81
82 public function asMarkdown()
83 {
84 $report = $this->get();
85
86 $content = '';
87
88 foreach ($report as $groupLabel => $group) {
89 $rows = [];
90 $labelWidth = max(13, mb_strlen($groupLabel));
91 $valueWidth = 10;
92
93 foreach ($group as $label => $value) {
94 if (is_bool($value)) {
95 $value = $value ? 'yes' : 'no';
96 }
97
98 $rows[$label] = $value;
99 $labelWidth = max($labelWidth, mb_strlen($label));
100 $valueWidth = min(30, max($valueWidth, mb_strlen($value)));
101 }
102
103 $content .= '| '.str_pad($groupLabel, $labelWidth).' | '.str_repeat(' ', $valueWidth)." |\n";
104 $content .= '| '.str_repeat('-', $labelWidth - 1).': | :'.str_repeat('-', $valueWidth - 1)." |\n";
105
106 foreach ($rows as $label => $value) {
107 $content .= '| '.str_pad($label, $labelWidth, ' ', STR_PAD_LEFT).' | '.str_pad($value, $valueWidth)." |\n";
108 }
109
110 $content .= "\n\n";
111 }
112
113 $content = rtrim($content);
114
115 return <<<OUTPUT
116 <details>
117 <summary>System report (REDAXO {$report['REDAXO']['Version']}, PHP {$report['PHP']['Version']})</summary>
118
119 $content
120
121 </details>
122 OUTPUT;
123 }
124
125 private function getBrowser()
126 {
127 if (!isset($_SERVER['HTTP_USER_AGENT'])) {
128 return '(unknown)';
129 }
130
131 $browser = $_SERVER['HTTP_USER_AGENT'];
132
133 if (preg_match('@\bSeamonkey/\S+@i', $browser, $match)) {
134 return $match[0];
135 }
136 if (preg_match('@\bFirefox/\S+@i', $browser, $match)) {
137 return $match[0];
138 }
139 if (preg_match('@\b(?:OPR|Opera)/(\S+)@i', $browser, $match)) {
140 return 'Opera/'.$match[1];
141 }
142 if (preg_match('@\bEdge/\S+@i', $browser, $match)) {
143 return $match[0];
144 }
145 if (preg_match('@\bChromium/\S+@i', $browser, $match)) {
146 return $match[0];
147 }
148 if (preg_match('@\bChrome/\S+@i', $browser, $match)) {
149 return $match[0];
150 }
151 if (preg_match('@\bVersion/(\S+) Safari/\S+@i', $browser, $match)) {
152 return 'Safari/'.$match[1];
153 }
154 if (preg_match('@\bMSIE/\S+@i', $browser, $match)) {
155 return $match[0];
156 }
157
158 return $browser;
159 }
160 }
161