1 <?php
  2 
  3 /**
  4  * @package redaxo\core
  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