1<?php
2if (!defined('PSI_CONFIG_FILE')) {
3    /**
4     * phpSysInfo version
5     */
6    define('PSI_VERSION', '3.3.4');
7    /**
8     * phpSysInfo configuration
9     */
10    define('PSI_CONFIG_FILE', PSI_APP_ROOT.'/phpsysinfo.ini');
11
12    define('ARRAY_EXP', '/^return array \([^;]*\);$/'); //array expression search
13
14    if (!is_readable(PSI_CONFIG_FILE)) {
15        echo "ERROR: phpsysinfo.ini does not exist or is not readable by the webserver in the phpsysinfo directory";
16        die();
17    } elseif (!($config = @parse_ini_file(PSI_CONFIG_FILE, true))) {
18        echo "ERROR: phpsysinfo.ini file is not parsable";
19        die();
20    } else {
21        foreach ($config as $name=>$group) {
22            if (strtoupper($name)=="MAIN") {
23                $name_prefix='PSI_';
24            } elseif (strtoupper(substr($name, 0, 7))=="SENSOR_") {
25                $name_prefix='PSI_'.strtoupper($name).'_';
26            } else {
27                $name_prefix='PSI_PLUGIN_'.strtoupper($name).'_';
28            }
29            foreach ($group as $param=>$value) {
30                if ((trim($value)==="") || (trim($value)==="0")) {
31                    define($name_prefix.strtoupper($param), false);
32                } elseif (trim($value)==="1") {
33                    define($name_prefix.strtoupper($param), true);
34                } else {
35                    if (strstr($value, ',')) {
36                        define($name_prefix.strtoupper($param), 'return '.var_export(preg_split('/\s*,\s*/', trim($value), -1, PREG_SPLIT_NO_EMPTY), 1).';');
37                    } else {
38                        define($name_prefix.strtoupper($param), trim($value));
39                    }
40                }
41            }
42        }
43    }
44
45    if (defined('PSI_ALLOWED') && is_string(PSI_ALLOWED)) {
46        if (preg_match(ARRAY_EXP, PSI_ALLOWED)) {
47            $allowed = eval(strtolower(PSI_ALLOWED));
48        } else {
49            $allowed = array(strtolower(PSI_ALLOWED));
50        }
51
52        if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
53            $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
54        } else {
55            if (isset($_SERVER["HTTP_CLIENT_IP"])) {
56                $ip = $_SERVER["HTTP_CLIENT_IP"];
57            } else {
58                $ip = $_SERVER["REMOTE_ADDR"];
59            }
60        }
61        $ip = preg_replace("/^::ffff:/", "", strtolower($ip));
62
63        if (!in_array($ip, $allowed, true)) {
64            echo "Client IP address not allowed";
65            die();
66        }
67    }
68
69    /* default error handler */
70    if (function_exists('errorHandlerPsi')) {
71        restore_error_handler();
72    }
73
74    /* fatal errors only */
75    $old_err_rep = error_reporting();
76    error_reporting(E_ERROR);
77
78    /* get git revision */
79    if (file_exists(PSI_APP_ROOT.'/.git/HEAD')) {
80        $contents = @file_get_contents(PSI_APP_ROOT.'/.git/HEAD');
81        if ($contents && preg_match("/^ref:\s+(.*)\/([^\/\s]*)/m", $contents, $matches)) {
82            $contents = @file_get_contents(PSI_APP_ROOT.'/.git/'.$matches[1]."/".$matches[2]);
83            if ($contents && preg_match("/^([^\s]*)/m", $contents, $revision)) {
84                define('PSI_VERSION_STRING', PSI_VERSION ."-".$matches[2]."-".substr($revision[1], 0, 7));
85            } else {
86                define('PSI_VERSION_STRING', PSI_VERSION ."-".$matches[2]);
87            }
88        }
89    }
90    /* get svn revision */
91    if (!defined('PSI_VERSION_STRING') && file_exists(PSI_APP_ROOT.'/.svn/entries')) {
92        $contents = @file_get_contents(PSI_APP_ROOT.'/.svn/entries');
93        if ($contents && preg_match("/dir\n(.+)/", $contents, $matches)) {
94            define('PSI_VERSION_STRING', PSI_VERSION."-r".$matches[1]);
95        } else {
96            define('PSI_VERSION_STRING', PSI_VERSION);
97        }
98    }
99    if (!defined('PSI_VERSION_STRING')) {
100        define('PSI_VERSION_STRING', PSI_VERSION);
101    }
102
103    if (!defined('PSI_OS')) { //if not overloaded in phpsysinfo.ini
104        /* get Linux code page */
105        if (PHP_OS == 'Linux') {
106            if (file_exists($fname = '/etc/sysconfig/i18n')
107               || file_exists($fname = '/etc/default/locale')
108               || file_exists($fname = '/etc/locale.conf')
109               || file_exists($fname = '/etc/sysconfig/language')
110               || file_exists($fname = '/etc/profile.d/lang.sh')
111               || file_exists($fname = '/etc/profile.d/i18n.sh')
112               || file_exists($fname = '/etc/profile')) {
113                $contents = @file_get_contents($fname);
114            } else {
115                $contents = false;
116                if (file_exists('/system/build.prop')) { //Android
117                    define('PSI_OS', 'Android');
118                    if (function_exists('exec') && @exec('uname -o 2>/dev/null', $unameo) && (sizeof($unameo)>0) && (($unameo0 = trim($unameo[0])) != "")) {
119                        define('PSI_UNAMEO', $unameo0); // is Android on Termux
120                    }
121                    if (!defined('PSI_MODE_POPEN')) { //if not overloaded in phpsysinfo.ini
122                        if (!function_exists("proc_open")) { //proc_open function test by executing 'pwd' command
123                            define('PSI_MODE_POPEN', true); //use popen() function - no stderr error handling (but with problems with timeout)
124                        } else {
125                            $out = '';
126                            $err = '';
127                            $pipes = array();
128                            $descriptorspec = array(0=>array("pipe", "r"), 1=>array("pipe", "w"), 2=>array("pipe", "w"));
129                            $process = proc_open("pwd 2>/dev/null ", $descriptorspec, $pipes);
130                            if (!is_resource($process)) {
131                                define('PSI_MODE_POPEN', true);
132                            } else {
133                                $w = null;
134                                $e = null;
135
136                                while (!(feof($pipes[1]) && feof($pipes[2]))) {
137                                    $read = array($pipes[1], $pipes[2]);
138
139                                    $n = stream_select($read, $w, $e, 5);
140
141                                    if (($n === false) || ($n === 0)) {
142                                        break;
143                                    }
144
145                                    foreach ($read as $r) {
146                                        if ($r == $pipes[1]) {
147                                            $out .= fread($r, 4096);
148                                        } elseif (feof($pipes[1]) && ($r == $pipes[2])) {//read STDERR after STDOUT
149                                            $err .= fread($r, 4096);
150                                        }
151                                    }
152                                }
153
154                                if (is_null($out) || (trim($out) == "") || (substr(trim($out), 0, 1) != "/")) {
155                                    define('PSI_MODE_POPEN', true);
156                                }
157                                fclose($pipes[0]);
158                                fclose($pipes[1]);
159                                fclose($pipes[2]);
160                                // It is important that you close any pipes before calling
161                                // proc_close in order to avoid a deadlock
162                                proc_close($process);
163                            }
164                        }
165                    }
166                }
167            }
168            if (!(defined('PSI_SYSTEM_CODEPAGE') && defined('PSI_SYSTEM_LANG')) //also if both not overloaded in phpsysinfo.ini
169               && $contents && (preg_match('/^(LANG="?[^"\n]*"?)/m', $contents, $matches)
170               || preg_match('/^RC_(LANG="?[^"\n]*"?)/m', $contents, $matches)
171               || preg_match('/^\s*export (LANG="?[^"\n]*"?)/m', $contents, $matches))) {
172                if (!defined('PSI_SYSTEM_CODEPAGE')) {
173                    if (file_exists($vtfname = '/sys/module/vt/parameters/default_utf8')
174                       && (trim(@file_get_contents($vtfname)) === "1")) {
175                            define('PSI_SYSTEM_CODEPAGE', 'UTF-8');
176                    } elseif (function_exists('exec') && @exec($matches[1].' locale -k LC_CTYPE 2>/dev/null', $lines)) { //if not overloaded in phpsysinfo.ini
177                        foreach ($lines as $line) {
178                            if (preg_match('/^charmap="?([^"]*)/', $line, $matches2)) {
179                                define('PSI_SYSTEM_CODEPAGE', $matches2[1]);
180                                break;
181                            }
182                        }
183                    }
184                }
185                if (!defined('PSI_SYSTEM_LANG') && function_exists('exec') && @exec($matches[1].' locale 2>/dev/null', $lines2)) { //also if not overloaded in phpsysinfo.ini
186                    foreach ($lines2 as $line) {
187                        if (preg_match('/^LC_MESSAGES="?([^\."@]*)/', $line, $matches2)) {
188                            $lang = "";
189                            if (is_readable(PSI_APP_ROOT.'/data/languages.ini') && ($langdata = @parse_ini_file(PSI_APP_ROOT.'/data/languages.ini', true))) {
190                                if (isset($langdata['Linux']['_'.$matches2[1]])) {
191                                    $lang = $langdata['Linux']['_'.$matches2[1]];
192                                }
193                            }
194                            if ($lang == "") {
195                                $lang = 'Unknown';
196                            }
197                            define('PSI_SYSTEM_LANG', $lang.' ('.$matches2[1].')');
198                            break;
199                        }
200                    }
201                }
202            }
203        } elseif (PHP_OS == 'Haiku') {
204            if (!(defined('PSI_SYSTEM_CODEPAGE') && defined('PSI_SYSTEM_LANG')) //also if both not overloaded in phpsysinfo.ini
205                && function_exists('exec') && @exec('locale --message 2>/dev/null', $lines)) {
206                foreach ($lines as $line) {
207                    if (preg_match('/^"?([^\."]*)\.?([^"]*)/', $line, $matches2)) {
208
209                        if (!defined('PSI_SYSTEM_CODEPAGE') && isset($matches2[2]) && !is_null($matches2[2]) && (trim($matches2[2]) != "")) { //also if not overloaded in phpsysinfo.ini
210                            define('PSI_SYSTEM_CODEPAGE', $matches2[2]);
211                        }
212
213                        if (!defined('PSI_SYSTEM_LANG')) { //if not overloaded in phpsysinfo.ini
214                            $lang = "";
215                            if (is_readable(PSI_APP_ROOT.'/data/languages.ini') && ($langdata = @parse_ini_file(PSI_APP_ROOT.'/data/languages.ini', true))) {
216                                if (isset($langdata['Linux']['_'.$matches2[1]])) {
217                                    $lang = $langdata['Linux']['_'.$matches2[1]];
218                                }
219                            }
220                            if ($lang == "") {
221                                $lang = 'Unknown';
222                            }
223                            define('PSI_SYSTEM_LANG', $lang.' ('.$matches2[1].')');
224                        }
225                        break;
226                    }
227                }
228            }
229        } elseif (PHP_OS == 'Darwin') {
230            if (!defined('PSI_SYSTEM_LANG') //if not overloaded in phpsysinfo.ini
231                && function_exists('exec') && @exec('defaults read /Library/Preferences/.GlobalPreferences AppleLocale 2>/dev/null', $lines)) {
232                $lang = "";
233                if (is_readable(PSI_APP_ROOT.'/data/languages.ini') && ($langdata = @parse_ini_file(PSI_APP_ROOT.'/data/languages.ini', true))) {
234                    if (isset($langdata['Linux']['_'.$lines[0]])) {
235                        $lang = $langdata['Linux']['_'.$lines[0]];
236                    }
237                }
238                if ($lang == "") {
239                    $lang = 'Unknown';
240                }
241                define('PSI_SYSTEM_LANG', $lang.' ('.$lines[0].')');
242            }
243        }
244    }
245
246    /* maximum time in seconds a script is allowed to run before it is terminated by the parser */
247    if (defined('PSI_MAX_TIMEOUT')) {
248        ini_set('max_execution_time', max(intval(PSI_MAX_TIMEOUT), 0));
249    } else {
250        ini_set('max_execution_time', 30);
251    }
252
253    /* executeProgram() timeout value in seconds */
254    if (defined('PSI_EXEC_TIMEOUT')) {
255        define('PSI_EXEC_TIMEOUT_INT', max(intval(PSI_EXEC_TIMEOUT), 1));
256    } else {
257        define('PSI_EXEC_TIMEOUT_INT', 30);
258    }
259
260    /* snmprealwalk() and executeProgram("snmpwalk") number of seconds until the first timeout */
261    if (defined('PSI_SNMP_TIMEOUT')) {
262        define('PSI_SNMP_TIMEOUT_INT', max(intval(PSI_SNMP_TIMEOUT), 1));
263    } else {
264        define('PSI_SNMP_TIMEOUT_INT', 3);
265    }
266
267    /* snmprealwalk() and executeProgram("snmpwalk") number of times to retry if timeouts occur */
268    if (defined('PSI_SNMP_RETRY')) {
269        define('PSI_SNMP_RETRY_INT', max(intval(PSI_SNMP_RETRY), 0));
270    } else {
271        define('PSI_SNMP_RETRY_INT', 0);
272    }
273
274    if (!defined('PSI_OS')) {
275        define('PSI_OS', PHP_OS);
276    }
277
278    if (!defined('PSI_SYSTEM_LANG')) {
279        define('PSI_SYSTEM_LANG', null);
280    }
281    if (!defined('PSI_SYSTEM_CODEPAGE')) { //if not overloaded in phpsysinfo.ini
282        if ((PSI_OS=='Android') || (PSI_OS=='Darwin')) {
283            define('PSI_SYSTEM_CODEPAGE', 'UTF-8');
284        } elseif (PSI_OS=='Minix') {
285            define('PSI_SYSTEM_CODEPAGE', 'CP437');
286        } elseif (PSI_OS!='WINNT') {
287            define('PSI_SYSTEM_CODEPAGE', null);
288        }
289    }
290
291    if (!defined('PSI_JSON_ISSUE')) { //if not overloaded in phpsysinfo.ini
292        if (!extension_loaded("xml")) {
293            die("phpSysInfo requires the xml extension to php in order to work properly.");
294        }
295        if (simplexml_load_string("<A><B><C/></B>\n</A>") !== simplexml_load_string("<A><B><C/></B></A>")) { // json_encode issue test
296            define('PSI_JSON_ISSUE', true); // Problem must be solved
297        }
298    }
299
300    /* restore error level */
301    error_reporting($old_err_rep);
302
303    /* restore error handler */
304    if (function_exists('errorHandlerPsi')) {
305        set_error_handler('errorHandlerPsi');
306    }
307}
308