From b6cc17a28bd38c67534d18af62b8115adee1ef09 Mon Sep 17 00:00:00 2001 From: "Km.Van" Date: Mon, 14 Nov 2022 12:59:20 +0800 Subject: [PATCH 1/3] fix body color --- src/Components/Bootstrap/components/global.scss | 2 +- src/Components/ColorScheme/components/config.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Bootstrap/components/global.scss b/src/Components/Bootstrap/components/global.scss index 959c7c12..be876875 100644 --- a/src/Components/Bootstrap/components/global.scss +++ b/src/Components/Bootstrap/components/global.scss @@ -29,7 +29,7 @@ } body { background: var(--x-body-bg); - color: var(--x-x-body-fg); + color: var(--x-body-fg); font-family: 'Noto Sans CJK SC', 'Helvetica Neue', Helvetica, Arial, Verdana, Geneva, sans-serif; padding: var(--x-gutter); diff --git a/src/Components/ColorScheme/components/config.scss b/src/Components/ColorScheme/components/config.scss index 5a0c378c..de4c08e1 100644 --- a/src/Components/ColorScheme/components/config.scss +++ b/src/Components/ColorScheme/components/config.scss @@ -7,7 +7,7 @@ $bg: #f8f8f8; --x-fg: #{$fg}; --x-bg: #{$bg}; --x-html-bg: var(--x-fg); - --x-x-body-fg: var(--x-bg); + --x-body-fg: var(--x-fg); --x-body-bg: var(--x-bg); --x-gutter: 1rem; --x-app-border-color: var(--x-fg); From a38ea7b0b1193349395c38e13a1b9f3f18e40481 Mon Sep 17 00:00:00 2001 From: "Km.Van" Date: Mon, 14 Nov 2022 13:00:18 +0800 Subject: [PATCH 2/3] update to 8.13 --- AppConfig.json | 2 +- CHANGELOG.md | 6 ++++++ dist/prober.php | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/AppConfig.json b/AppConfig.json index 6908f3c5..65854789 100644 --- a/AppConfig.json +++ b/AppConfig.json @@ -1,5 +1,5 @@ { - "APP_VERSION": "8.12", + "APP_VERSION": "8.13", "APP_NAME": "X Prober", "APP_URL": "https://github.com/kmvan/x-prober", "AUTHOR_URL": "https://inn-studio.com/prober", diff --git a/CHANGELOG.md b/CHANGELOG.md index cc1cf24a..fa2d59d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All Notable changes to `X-Prober` will be documented in this file +## 8.13.0 - 2022-11-14 + +### Fix + +- Fix body color + ## 8.12.0 - 2022-11-14 ### Remove diff --git a/dist/prober.php b/dist/prober.php index 1fdb1123..432e114c 100644 --- a/dist/prober.php +++ b/dist/prober.php @@ -1,7 +1,7 @@ ID)) { return $conf; } $conf[$this->ID] = array( 'version' => \PHP_VERSION, 'sapi' => \PHP_SAPI, 'displayErrors' => (bool) \ini_get('display_errors'), 'errorReporting' => (int) \ini_get('error_reporting'), 'memoryLimit' => (string) \ini_get('memory_limit'), 'postMaxSize' => (string) \ini_get('post_max_size'), 'uploadMaxFilesize' => (string) \ini_get('upload_max_filesize'), 'maxInputVars' => (int) \ini_get('max_input_vars'), 'maxExecutionTime' => (int) \ini_get('max_execution_time'), 'defaultSocketTimeout' => (int) \ini_get('default_socket_timeout'), 'allowUrlFopen' => (bool) \ini_get('allow_url_fopen'), 'smtp' => (bool) \ini_get('SMTP'), 'disableFunctions' => XconfigApi::isDisabled('phpDisabledFunctions') ? array() : array_filter(explode(',', (string) \ini_get('disable_functions'))), 'disableClasses' => XconfigApi::isDisabled('phpDisabledClasses') ? array() : array_filter(explode(',', (string) \ini_get('disable_classes'))), ); return $conf; }); } } namespace InnStudio\Prober\Components\PhpInfo; use InnStudio\Prober\Components\Config\ConfigApi; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class FetchLatestPhpVersion extends PhpInfoConstants { public function __construct() { EventsApi::on('init', function ($action) { if (XconfigApi::isDisabled($this->ID)) { return $action; } if ('latest-php-version' !== $action) { return $action; } $response = new RestResponse(); $content = file_get_contents('https://www.php.net/releases/?json'); if ( ! $content) { $response->setStatus(StatusCode::$NOT_FOUND)->end(); } $versions = json_decode($content, true); if ( ! $versions) { $response->setStatus(StatusCode::$NOT_FOUND)->end(); } $version = isset($versions[ConfigApi::$LATEST_PHP_STABLE_VERSION]['version']) ? $versions[ConfigApi::$LATEST_PHP_STABLE_VERSION]['version'] : ''; if ( ! $version) { $response->setStatus(StatusCode::$NOT_FOUND)->end(); } $response->setData(array( 'version' => $version, 'date' => $versions[ConfigApi::$LATEST_PHP_STABLE_VERSION]['date'], ))->json()->end(); }); } } namespace InnStudio\Prober\Components\PhpInfo; final class PhpInfo { public function __construct() { new Conf(); new FetchLatestPhpVersion(); } } namespace InnStudio\Prober\Components\PhpInfo; class PhpInfoConstants { protected $ID = 'phpInfo'; } namespace InnStudio\Prober\Components\Events; final class EventsApi { private static $events = array(); private static $PRIORITY_ID = 'priority'; private static $CALLBACK_ID = 'callback'; public static function on($name, $callback, $priority = 10) { if ( ! isset(self::$events[$name])) { self::$events[$name] = array(); } self::$events[$name][] = array( self::$PRIORITY_ID => $priority, self::$CALLBACK_ID => $callback, ); } public static function emit() { $args = \func_get_args(); $name = $args[0]; $return = isset($args[1]) ? $args[1] : null; unset($args[0], $args[1]); $events = isset(self::$events[$name]) ? self::$events[$name] : false; if ( ! $events) { return $return; } $sortArr = array(); foreach ($events as $k => $filter) { $sortArr[$k] = $filter[self::$PRIORITY_ID]; } array_multisort($sortArr, $events); foreach ($events as $filter) { $return = \call_user_func_array($filter[self::$CALLBACK_ID], array($return, $args)); } return $return; } } namespace InnStudio\Prober\Components\PhpInfoDetail; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class PhpInfoDetail extends PhpInfoDetailConstants { public function __construct() { EventsApi::on('init', function ($action) { if (XconfigApi::isDisabled($this->ID)) { return $action; } if ($this->ID !== $action) { return $action; } phpinfo(); exit; }); } } namespace InnStudio\Prober\Components\PhpInfoDetail; class PhpInfoDetailConstants { protected $ID = 'phpInfoDetail'; } namespace InnStudio\Prober\Components\Ping; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends PingConstants { public function __construct() { EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $conf[$this->ID] = array(); return $conf; }); } } namespace InnStudio\Prober\Components\Ping; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Ping extends PingConstants { public function __construct() { new Conf(); EventsApi::on('init', function ($action) { if (XconfigApi::isDisabled($this->ID)) { return $action; } if ($this->ID !== $action) { return $action; } $response = new RestResponse(array( 'time' => \defined('XPROBER_TIMER') ? microtime(true) - XPROBER_TIMER : 0, )); $response->json()->end(); }); } } namespace InnStudio\Prober\Components\Ping; class PingConstants { protected $ID = 'ping'; } namespace InnStudio\Prober\Components\PhpExtensions; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends PhpExtensionsConstants { public function __construct() { EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $jitEnabled = false; if (\function_exists('opcache_get_status')) { $status = opcache_get_status(); if (isset($status['jit']['enabled']) && true === $status['jit']['enabled']) { $jitEnabled = true; } } $conf[$this->ID] = array( 'redis' => \extension_loaded('redis') && class_exists('Redis'), 'sqlite3' => \extension_loaded('sqlite3') && class_exists('Sqlite3'), 'memcache' => \extension_loaded('memcache') && class_exists('Memcache'), 'memcached' => \extension_loaded('memcached') && class_exists('Memcached'), 'opcache' => \function_exists('opcache_get_status'), 'opcacheEnabled' => $this->isOpcEnabled(), 'opcacheJitEnabled' => $jitEnabled, 'swoole' => \extension_loaded('swoole') && \function_exists('swoole_version'), 'imagick' => \extension_loaded('imagick') && class_exists('Imagick'), 'gmagick' => \extension_loaded('gmagick'), 'exif' => \extension_loaded('exif') && \function_exists('exif_imagetype'), 'fileinfo' => \extension_loaded('fileinfo'), 'simplexml' => \extension_loaded('simplexml'), 'sockets' => \extension_loaded('sockets') && \function_exists('socket_accept'), 'mysqli' => \extension_loaded('mysqli') && class_exists('mysqli'), 'zip' => \extension_loaded('zip') && class_exists('ZipArchive'), 'mbstring' => \extension_loaded('mbstring') && \function_exists('mb_substr'), 'phalcon' => \extension_loaded('phalcon'), 'xdebug' => \extension_loaded('xdebug'), 'zendOptimizer' => \function_exists('zend_optimizer_version'), 'ionCube' => \extension_loaded('ioncube loader'), 'sourceGuardian' => \extension_loaded('sourceguardian'), 'ldap' => \function_exists('ldap_connect'), 'curl' => \function_exists('curl_init'), 'loadedExtensions' => XconfigApi::isDisabled('phpExtensionsLoaded') ? array() : get_loaded_extensions(), ); return $conf; }); } private function isOpcEnabled() { $isOpcEnabled = \function_exists('opcache_get_configuration'); if ($isOpcEnabled) { $isOpcEnabled = opcache_get_configuration(); $isOpcEnabled = isset($isOpcEnabled['directives']['opcache.enable']) && true === $isOpcEnabled['directives']['opcache.enable']; } return $isOpcEnabled; } } namespace InnStudio\Prober\Components\PhpExtensions; class PhpExtensionsConstants { protected $ID = 'phpExtensions'; } namespace InnStudio\Prober\Components\PhpExtensions; final class PhpExtensions { public function __construct() { new Conf(); } } namespace InnStudio\Prober\Components\Footer; use InnStudio\Prober\Components\Events\EventsApi; final class Footer { private $ID = 'footer'; public function __construct() { EventsApi::on('conf', function (array $conf) { $conf[$this->ID] = array( 'memUsage' => memory_get_usage(), 'time' => microtime(true) - (\defined('XPROBER_TIMER') ? XPROBER_TIMER : 0), ); return $conf; }, \PHP_INT_MAX); } } namespace InnStudio\Prober\Components\TemperatureSensor; use Exception; use InnStudio\Prober\Components\Config\ConfigApi; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; final class TemperatureSensor { public function __construct() { EventsApi::on('init', function ($action) { if ('temperature-sensor' !== $action) { return $action; } $response = new RestResponse(); $items = $this->getItems(); if ($items) { $response->setData($items)->json()->end(); } $cpuTemp = $this->getCpuTemp(); if ( ! $cpuTemp) { $response->setStatus(StatusCode::$NO_CONTENT); } $items[] = array( 'id' => 'cpu', 'name' => 'CPU', 'celsius' => round((float) $cpuTemp / 1000, 2), ); $response->setData($items)->json()->end(); }); } private function curl($url) { if ( ! \function_exists('curl_init')) { return; } $ch = curl_init(); curl_setopt_array($ch, array( \CURLOPT_URL => $url, \CURLOPT_RETURNTRANSFER => true, )); $res = curl_exec($ch); curl_close($ch); return (string) $res; } private function getItems() { $items = array(); foreach (ConfigApi::$APP_TEMPERATURE_SENSOR_PORTS as $port) { $res = $this->curl(ConfigApi::$APP_TEMPERATURE_SENSOR_URL . ":{$port}"); if ( ! $res) { continue; } $item = json_decode($res, true); if ( ! $item || ! \is_array($item)) { continue; } $items = $item; break; } return $items; } private function getCpuTemp() { try { $path = '/sys/class/thermal/thermal_zone0/temp'; return file_exists($path) ? (int) file_get_contents($path) : 0; } catch (Exception $e) { return 0; } } } namespace InnStudio\Prober\Components\ServerStatus; final class ServerStatus { public function __construct() { new Conf(); new Fetch(); } } namespace InnStudio\Prober\Components\ServerStatus; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsCpu; use InnStudio\Prober\Components\Utils\UtilsMemory; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends ServerStatusConstants { public function __construct() { EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $conf[$this->ID] = array( 'sysLoad' => UtilsCpu::getLoadAvg(), 'memRealUsage' => array( 'value' => UtilsMemory::getMemoryUsage('MemRealUsage'), 'max' => UtilsMemory::getMemoryUsage('MemTotal'), ), 'memBuffers' => array( 'value' => UtilsMemory::getMemoryUsage('Buffers'), 'max' => UtilsMemory::getMemoryUsage('MemUsage'), ), 'memCached' => array( 'value' => UtilsMemory::getMemoryUsage('Cached'), 'max' => UtilsMemory::getMemoryUsage('MemUsage'), ), 'swapUsage' => array( 'value' => UtilsMemory::getMemoryUsage('SwapUsage'), 'max' => UtilsMemory::getMemoryUsage('SwapTotal'), ), 'swapCached' => array( 'value' => UtilsMemory::getMemoryUsage('SwapCached'), 'max' => UtilsMemory::getMemoryUsage('SwapUsage'), ), ); return $conf; }); } } namespace InnStudio\Prober\Components\ServerStatus; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsCpu; use InnStudio\Prober\Components\Utils\UtilsMemory; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Fetch extends ServerStatusConstants { public function __construct() { EventsApi::on('fetch', array($this, 'filter')); EventsApi::on('nodes', array($this, 'filter')); } public function filter(array $items) { if (XconfigApi::isDisabled($this->ID)) { return $items; } $items[$this->ID] = array( 'sysLoad' => UtilsCpu::getLoadAvg(), 'cpuUsage' => UtilsCpu::getUsage(), 'memRealUsage' => array( 'value' => UtilsMemory::getMemoryUsage('MemRealUsage'), 'max' => UtilsMemory::getMemoryUsage('MemTotal'), ), 'memBuffers' => array( 'value' => UtilsMemory::getMemoryUsage('Buffers'), 'max' => UtilsMemory::getMemoryUsage('MemUsage'), ), 'memCached' => array( 'value' => UtilsMemory::getMemoryUsage('Cached'), 'max' => UtilsMemory::getMemoryUsage('MemUsage'), ), 'swapUsage' => array( 'value' => UtilsMemory::getMemoryUsage('SwapUsage'), 'max' => UtilsMemory::getMemoryUsage('SwapTotal'), ), 'swapCached' => array( 'value' => UtilsMemory::getMemoryUsage('SwapCached'), 'max' => UtilsMemory::getMemoryUsage('SwapUsage'), ), ); return $items; } } namespace InnStudio\Prober\Components\ServerStatus; class ServerStatusConstants { protected $ID = 'serverStatus'; } namespace InnStudio\Prober\Components\Style; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsApi; final class Style { public function __construct() { EventsApi::on('init', function ($action) { if ('style' !== $action) { return $action; } $this->output(); }); } private function output() { UtilsApi::setFileCacheHeader(); header('Content-type: text/css'); echo <<<'HTML' .src-Components-Card-components-styles-module__des--EgOss{padding:calc(var(--x-gutter)/2) var(--x-gutter);background-color:rgba(255,255,255,.3);color:var(--x-body-fg);border-radius:var(--x-radius);margin-bottom:var(--x-gutter)}.src-Components-Card-components-styles-module__link--QMvaX::before{content:"👆 "}.src-Components-Card-components-styles-module__ruby--lRf3T{background:var(--x-benchmark-ruby-bg);cursor:pointer}.src-Components-Card-components-styles-module__ruby--lRf3T:hover{text-decoration:underline}.src-Components-Card-components-styles-module__ruby--lRf3T rt{font-size:.75rem;opacity:.5}.src-Components-Card-components-styles-module__ruby--lRf3T[data-is-result]{font-weight:bold}.src-Components-Card-components-styles-module__error--RxEjQ{padding:var(--x-gutter)}.src-Components-Card-components-styles-module__title--sQBIC{word-break:normal;padding:calc(var(--x-gutter)/2) 0;flex:0 0 8rem;color:var(--x-card-title-fg)}@media(min-width: 375px){.src-Components-Card-components-styles-module__title--sQBIC{flex:0 0 9rem}}@media(min-width: 425px){.src-Components-Card-components-styles-module__title--sQBIC{flex:0 0 10rem}}@media(min-width: 768px){.src-Components-Card-components-styles-module__title--sQBIC{flex:0 0 11rem}}.src-Components-Card-components-styles-module__group--onjSH{display:flex;width:100%;align-items:center;border-bottom:1px dashed var(--x-card-border-color)}.src-Components-Card-components-styles-module__group--onjSH:hover{background:var(--x-card-bg-hover)}.src-Components-Card-components-styles-module__content--Ibvay{flex-grow:1;padding:calc(var(--x-gutter)/2) 0}.src-Components-Card-components-styles-module__fieldset--GoXuV{position:relative;border:5px solid var(--x-card-border-color);border-radius:calc(var(--x-gutter)*1.5);background:var(--x-card-bg);margin-bottom:calc(var(--x-gutter)*1.5);padding:calc(var(--x-gutter)*1.5) 0 0;box-shadow:var(--x-card-box-shadow);scroll-margin-top:50px}.src-Components-Card-components-styles-module__body--aNmjc{padding:0 calc(var(--x-gutter)/2)}@media(min-width: 425px){.src-Components-Card-components-styles-module__body--aNmjc{padding:0 var(--x-gutter)}}.src-Components-Card-components-styles-module__arrow--YXo0g{color:var(--x-card-title-fg);padding:0 .5rem;cursor:pointer;opacity:.5}.src-Components-Card-components-styles-module__arrow--YXo0g:active,.src-Components-Card-components-styles-module__arrow--YXo0g:hover{text-decoration:none;opacity:1;color:var(--x-card-title-fg)}.src-Components-Card-components-styles-module__arrow--YXo0g[data-disabled],.src-Components-Card-components-styles-module__arrow--YXo0g[data-disabled]:hover{cursor:not-allowed;opacity:.1}.src-Components-Card-components-styles-module__legend--fgO2f{display:flex;justify-content:center;align-items:center;position:absolute;left:50%;top:0;transform:translate(-50%, -50%);background:var(--x-card-legend-bg);padding:.5rem 1rem;border-radius:5rem;color:var(--x-card-legend-fg);margin:0 auto;white-space:nowrap}.src-Components-Card-components-styles-module__legendText--q65Xw{padding:0 .5rem}.src-Components-Card-components-styles-module__multiItemContainer--CAVDM{display:flex;flex-wrap:wrap;margin-bottom:-0.2rem} -:root{--x-max-width: 1680px;--x-radius: 2rem;--x-fg: #333;--x-bg: #f8f8f8;--x-html-bg: var(--x-fg);--x-x-body-fg: var(--x-bg);--x-body-bg: var(--x-bg);--x-gutter: 1rem;--x-app-border-color: var(--x-fg);--x-app-bg: var(--x-bg);--x-footer-fg: var(--x-bg);--x-footer-bg: var(--x-fg);--x-benchmark-ruby-bg: rgba(#000, 0.05);--x-card-bg: rgba(51 51 51 / 0.03);--x-card-bg-hover: linear-gradient( to right, transparent, #0000001a, transparent );--x-card-legend-fg: var(--x-bg);--x-card-legend-bg: linear-gradient(#1b1b1b, var(--x-fg));--x-card-title-fg: var(--x-fg);--x-card-title-bg: var(--x-bg);--x-card-border-color: rgba(51 51 51 / 10%);--x-card-hover-bg: linear-gradient( to right, transparent, rgba(#000, 0.1), transparent );--x-card-box-shadow: rgb(51 51 51 / 30%) 0px -1px 0px, rgb(255 255 255) 0px 1px 0px inset, rgb(51 51 51 / 30%) 0px -1px 0px inset, rgb(255 255 255) 0px 1px 0px;--x-title-fg: var(--x-bg);--x-title-bg: var(--x-fg);--x-title-box-shadow: 0 1px 0 #000;--x-star-me-fg: var(--x-bg);--x-star-me-bg: var(--x-fg);--x-star-me-hover-fg: #fff;--x-star-me-hover-bg: var(--x-fg);--x-star-me-border-color: linear-gradient( 90deg, transparent, #fff, transparent );--x-nav-fg: var(--x-bg);--x-nav-fg-hover: var(--x-fg);--x-nav-fg-active: var(--x-fg);--x-nav-bg: var(--x-fg);--x-nav-bg-hover: linear-gradient( rgba(255 255 255 / 0.85), rgba(255 255 255 / 0.65) );--x-nav-bg-active: linear-gradient( rgba(255 255 255 / 0.95), rgba(255 255 255 / 0.75) );--x-nav-border-color: rgba(255 255 255 / 0.1);--x-status-ok-fg: #fff;--x-status-ok-bg: linear-gradient(#009c00, #00e800);--x-status-error-fg: #fff;--x-status-error-bg: linear-gradient(#797979, #b9b9b9);--x-search-fg: var(--x-fg);--x-search-bg: rgba(0 0 0 / 0.05);--x-search-bg-hover: rgba(0 0 0 / 0.15);--x-progress-fg: var(--x-bg);--x-progress-bg: var(--x-fg);--x-progress-value-bg: #0c0;--x-progress-value-after-bg: linear-gradient( rgba(255 255 255 / 0.45), transparent );--x-progress-value-before-bg: linear-gradient( to right, rgba(255 255 255/ 0.1), rgba(255 255 255/ 0.95), rgba(255 255 255/ 0.1) );--x-network-stats-tx-fg: #c24b00;--x-network-stats-rx-fg: #007400;--x-network-node-fg: var(--x-fg);--x-network-node-bg: #373c381a;--x-network-node-border-color: #373c381a;--x-network-node-row-bg: linear-gradient( to right, transparent, rgba(255 255 255 / 0.5), transparent );--x-ping-btn-fg: var(--x-bg);--x-ping-btn-bg: var(--x-fg);--x-ping-result-fg: var(--x-bg);--x-ping-result-bg: var(--x-fg);--x-ping-result-scrollbar-bg: var(--x-fg);--x-sys-load-fg: var(--x-bg);--x-sys-load-bg: var(--x-fg);--x-toast-fg: var(--x-bg);--x-toast-bg: var(--x-fg)} +:root{--x-max-width: 1680px;--x-radius: 2rem;--x-fg: #333;--x-bg: #f8f8f8;--x-html-bg: var(--x-fg);--x-body-fg: var(--x-fg);--x-body-bg: var(--x-bg);--x-gutter: 1rem;--x-app-border-color: var(--x-fg);--x-app-bg: var(--x-bg);--x-footer-fg: var(--x-bg);--x-footer-bg: var(--x-fg);--x-benchmark-ruby-bg: rgba(#000, 0.05);--x-card-bg: rgba(51 51 51 / 0.03);--x-card-bg-hover: linear-gradient( to right, transparent, #0000001a, transparent );--x-card-legend-fg: var(--x-bg);--x-card-legend-bg: linear-gradient(#1b1b1b, var(--x-fg));--x-card-title-fg: var(--x-fg);--x-card-title-bg: var(--x-bg);--x-card-border-color: rgba(51 51 51 / 10%);--x-card-hover-bg: linear-gradient( to right, transparent, rgba(#000, 0.1), transparent );--x-card-box-shadow: rgb(51 51 51 / 30%) 0px -1px 0px, rgb(255 255 255) 0px 1px 0px inset, rgb(51 51 51 / 30%) 0px -1px 0px inset, rgb(255 255 255) 0px 1px 0px;--x-title-fg: var(--x-bg);--x-title-bg: var(--x-fg);--x-title-box-shadow: 0 1px 0 #000;--x-star-me-fg: var(--x-bg);--x-star-me-bg: var(--x-fg);--x-star-me-hover-fg: #fff;--x-star-me-hover-bg: var(--x-fg);--x-star-me-border-color: linear-gradient( 90deg, transparent, #fff, transparent );--x-nav-fg: var(--x-bg);--x-nav-fg-hover: var(--x-fg);--x-nav-fg-active: var(--x-fg);--x-nav-bg: var(--x-fg);--x-nav-bg-hover: linear-gradient( rgba(255 255 255 / 0.85), rgba(255 255 255 / 0.65) );--x-nav-bg-active: linear-gradient( rgba(255 255 255 / 0.95), rgba(255 255 255 / 0.75) );--x-nav-border-color: rgba(255 255 255 / 0.1);--x-status-ok-fg: #fff;--x-status-ok-bg: linear-gradient(#009c00, #00e800);--x-status-error-fg: #fff;--x-status-error-bg: linear-gradient(#797979, #b9b9b9);--x-search-fg: var(--x-fg);--x-search-bg: rgba(0 0 0 / 0.05);--x-search-bg-hover: rgba(0 0 0 / 0.15);--x-progress-fg: var(--x-bg);--x-progress-bg: var(--x-fg);--x-progress-value-bg: #0c0;--x-progress-value-after-bg: linear-gradient( rgba(255 255 255 / 0.45), transparent );--x-progress-value-before-bg: linear-gradient( to right, rgba(255 255 255/ 0.1), rgba(255 255 255/ 0.95), rgba(255 255 255/ 0.1) );--x-network-stats-tx-fg: #c24b00;--x-network-stats-rx-fg: #007400;--x-network-node-fg: var(--x-fg);--x-network-node-bg: #373c381a;--x-network-node-border-color: #373c381a;--x-network-node-row-bg: linear-gradient( to right, transparent, rgba(255 255 255 / 0.5), transparent );--x-ping-btn-fg: var(--x-bg);--x-ping-btn-bg: var(--x-fg);--x-ping-result-fg: var(--x-bg);--x-ping-result-bg: var(--x-fg);--x-ping-result-scrollbar-bg: var(--x-fg);--x-sys-load-fg: var(--x-bg);--x-sys-load-bg: var(--x-fg);--x-toast-fg: var(--x-bg);--x-toast-bg: var(--x-fg)} .src-Components-Container-components-styles-module__main--rQ91J{margin-left:auto;margin-right:auto;padding-left:calc(var(--x-gutter)/2);padding-right:calc(var(--x-gutter)/2);max-width:var(--x-max-width)}@media(min-width: 768px){.src-Components-Container-components-styles-module__main--rQ91J{padding-left:var(--x-gutter);padding-right:var(--x-gutter)}} .src-Components-Grid-components-styles-module__container--EXgkw{display:flex;flex-wrap:wrap;margin-left:calc(var(--x-gutter)*-0.5);margin-right:calc(var(--x-gutter)*-0.5)}.src-Components-Grid-components-styles-module__grid--qbVV1{padding-left:calc(var(--x-gutter)*.5);padding-right:calc(var(--x-gutter)*.5);flex:1 0 100%;width:100%}@media(min-width: 320px){.src-Components-Grid-components-styles-module__grid--qbVV1[data-xs="1"]{flex:0 0 100%;width:100%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xs="2"]{flex:0 0 50%;width:50%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xs="3"]{flex:0 0 33.3333333333%;width:33.3333333333%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xs="4"]{flex:0 0 25%;width:25%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xs="5"]{flex:0 0 20%;width:20%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xs="6"]{flex:0 0 16.6666666667%;width:16.6666666667%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xs="7"]{flex:0 0 14.2857142857%;width:14.2857142857%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xs="8"]{flex:0 0 12.5%;width:12.5%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xs="9"]{flex:0 0 11.1111111111%;width:11.1111111111%}}@media(min-width: 375px){.src-Components-Grid-components-styles-module__grid--qbVV1[data-sm="1"]{flex:0 0 100%;width:100%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-sm="2"]{flex:0 0 50%;width:50%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-sm="3"]{flex:0 0 33.3333333333%;width:33.3333333333%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-sm="4"]{flex:0 0 25%;width:25%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-sm="5"]{flex:0 0 20%;width:20%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-sm="6"]{flex:0 0 16.6666666667%;width:16.6666666667%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-sm="7"]{flex:0 0 14.2857142857%;width:14.2857142857%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-sm="8"]{flex:0 0 12.5%;width:12.5%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-sm="9"]{flex:0 0 11.1111111111%;width:11.1111111111%}}@media(min-width: 425px){.src-Components-Grid-components-styles-module__grid--qbVV1[data-md="1"]{flex:0 0 100%;width:100%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-md="2"]{flex:0 0 50%;width:50%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-md="3"]{flex:0 0 33.3333333333%;width:33.3333333333%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-md="4"]{flex:0 0 25%;width:25%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-md="5"]{flex:0 0 20%;width:20%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-md="6"]{flex:0 0 16.6666666667%;width:16.6666666667%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-md="7"]{flex:0 0 14.2857142857%;width:14.2857142857%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-md="8"]{flex:0 0 12.5%;width:12.5%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-md="9"]{flex:0 0 11.1111111111%;width:11.1111111111%}}@media(min-width: 768px){.src-Components-Grid-components-styles-module__grid--qbVV1[data-lg="1"]{flex:0 0 100%;width:100%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-lg="2"]{flex:0 0 50%;width:50%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-lg="3"]{flex:0 0 33.3333333333%;width:33.3333333333%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-lg="4"]{flex:0 0 25%;width:25%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-lg="5"]{flex:0 0 20%;width:20%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-lg="6"]{flex:0 0 16.6666666667%;width:16.6666666667%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-lg="7"]{flex:0 0 14.2857142857%;width:14.2857142857%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-lg="8"]{flex:0 0 12.5%;width:12.5%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-lg="9"]{flex:0 0 11.1111111111%;width:11.1111111111%}}@media(min-width: 1024px){.src-Components-Grid-components-styles-module__grid--qbVV1[data-xl="1"]{flex:0 0 100%;width:100%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xl="2"]{flex:0 0 50%;width:50%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xl="3"]{flex:0 0 33.3333333333%;width:33.3333333333%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xl="4"]{flex:0 0 25%;width:25%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xl="5"]{flex:0 0 20%;width:20%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xl="6"]{flex:0 0 16.6666666667%;width:16.6666666667%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xl="7"]{flex:0 0 14.2857142857%;width:14.2857142857%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xl="8"]{flex:0 0 12.5%;width:12.5%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xl="9"]{flex:0 0 11.1111111111%;width:11.1111111111%}}@media(min-width: 1440px){.src-Components-Grid-components-styles-module__grid--qbVV1[data-xxl="1"]{flex:0 0 100%;width:100%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xxl="2"]{flex:0 0 50%;width:50%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xxl="3"]{flex:0 0 33.3333333333%;width:33.3333333333%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xxl="4"]{flex:0 0 25%;width:25%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xxl="5"]{flex:0 0 20%;width:20%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xxl="6"]{flex:0 0 16.6666666667%;width:16.6666666667%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xxl="7"]{flex:0 0 14.2857142857%;width:14.2857142857%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xxl="8"]{flex:0 0 12.5%;width:12.5%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-xxl="9"]{flex:0 0 11.1111111111%;width:11.1111111111%}}@media(min-width: 2560px){.src-Components-Grid-components-styles-module__grid--qbVV1[data-4k="1"]{flex:0 0 100%;width:100%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-4k="2"]{flex:0 0 50%;width:50%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-4k="3"]{flex:0 0 33.3333333333%;width:33.3333333333%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-4k="4"]{flex:0 0 25%;width:25%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-4k="5"]{flex:0 0 20%;width:20%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-4k="6"]{flex:0 0 16.6666666667%;width:16.6666666667%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-4k="7"]{flex:0 0 14.2857142857%;width:14.2857142857%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-4k="8"]{flex:0 0 12.5%;width:12.5%}.src-Components-Grid-components-styles-module__grid--qbVV1[data-4k="9"]{flex:0 0 11.1111111111%;width:11.1111111111%}} .src-Components-Utils-components-alert-styles-module__main--fj45p{display:inline-flex;border-radius:var(--x-radius);align-items:center;justify-content:center;font-family:"Arial Black",sans-serif;font-weight:bolder;min-width:2em;padding:0 .5rem;white-space:nowrap;cursor:pointer;text-shadow:0 1px 1px #000}.src-Components-Utils-components-alert-styles-module__main--fj45p:active{transform:scale3d(0.95, 0.95, 1)}.src-Components-Utils-components-alert-styles-module__main--fj45p[data-ok]{background:var(--x-status-ok-bg);color:var(--x-status-ok-fg)}.src-Components-Utils-components-alert-styles-module__main--fj45p[data-error]{background:var(--x-status-error-bg);color:var(--x-status-error-fg)}.src-Components-Utils-components-alert-styles-module__main--fj45p[data-ok][data-icon]::before{content:"✓"}.src-Components-Utils-components-alert-styles-module__main--fj45p[data-error][data-icon]::before{content:"×"} @@ -18,7 +18,7 @@ .src-Components-ServerBenchmark-components-styles-module__btn--DR6pA{display:block}.src-Components-ServerBenchmark-components-styles-module__aff--U6apK{word-break:normal} .src-Components-Title-components-styles-module__h1--z5lLy{background:var(--x-title-bg);position:fixed;top:0;left:50%;justify-content:center;text-align:center;margin:0;min-width:60vw;width:50vw;font-size:var(--x-gutter);line-height:1;border-radius:0 0 var(--x-radius) var(--x-radius);z-index:10;box-shadow:var(--x-title-box-shadow);transform:translateX(-50%)}.src-Components-Title-components-styles-module__link--_O32A{display:block;padding:var(--x-gutter);color:var(--x-title-fg)}.src-Components-Title-components-styles-module__link--_O32A:hover{color:var(--x-title-fg)} .src-Components-Toast-components-styles-module__main--yKV4Y{position:fixed;bottom:4rem;width:20rem;max-width:80vw;left:50%;transform:translateX(-50%);background:var(--x-toast-bg);color:var(--x-toast-fg);border-radius:var(--x-gutter);padding:calc(var(--x-gutter)*.5) var(--x-gutter);cursor:pointer;word-break:normal;text-align:center;backdrop-filter:blur(5px)} -@media(min-width: 1024px){::-webkit-scrollbar-track{background-color:rgba(0,0,0,0)}::-webkit-scrollbar{width:var(--x-gutter);background-color:rgba(0,0,0,0)}::-webkit-scrollbar-thumb{border-radius:var(--x-gutter) 0 0 var(--x-gutter);background-color:#ccc}::-webkit-scrollbar-thumb:hover{background-color:#fff}}*{box-sizing:border-box;word-break:break-all;padding:0;margin:0}html{font-size:75%;background:var(--x-html-bg);scroll-behavior:smooth}body{background:var(--x-body-bg);color:var(--x-x-body-fg);font-family:"Noto Sans CJK SC","Helvetica Neue",Helvetica,Arial,Verdana,Geneva,sans-serif;padding:var(--x-gutter);margin:0;line-height:1.5}a{cursor:pointer;color:var(--x-fg);text-decoration:none}a:hover,a:active{color:var(--x-fg);text-decoration:underline} +@media(min-width: 1024px){::-webkit-scrollbar-track{background-color:rgba(0,0,0,0)}::-webkit-scrollbar{width:var(--x-gutter);background-color:rgba(0,0,0,0)}::-webkit-scrollbar-thumb{border-radius:var(--x-gutter) 0 0 var(--x-gutter);background-color:#ccc}::-webkit-scrollbar-thumb:hover{background-color:#fff}}*{box-sizing:border-box;word-break:break-all;padding:0;margin:0}html{font-size:75%;background:var(--x-html-bg);scroll-behavior:smooth}body{background:var(--x-body-bg);color:var(--x-body-fg);font-family:"Noto Sans CJK SC","Helvetica Neue",Helvetica,Arial,Verdana,Geneva,sans-serif;padding:var(--x-gutter);margin:0;line-height:1.5}a{cursor:pointer;color:var(--x-fg);text-decoration:none}a:hover,a:active{color:var(--x-fg);text-decoration:underline} .src-Components-Bootstrap-components-styles-module__app--llWF8{padding:calc(var(--x-gutter)*3.5) 0 calc(var(--x-gutter)*2);background:var(--x-app-bg)}.src-Components-Bootstrap-components-styles-module__app--llWF8::before,.src-Components-Bootstrap-components-styles-module__app--llWF8::after{position:fixed;left:0;top:0;right:0;bottom:calc(var(--x-gutter)*2);border:var(--x-gutter) solid var(--x-app-border-color);pointer-events:none;z-index:1;content:""}.src-Components-Bootstrap-components-styles-module__app--llWF8::after{border-radius:calc(var(--x-gutter)*3)} HTML; From b4126e54cf8af51451ff42e501ab0dbfa03036bb Mon Sep 17 00:00:00 2001 From: "Km.Van" Date: Mon, 14 Nov 2022 13:00:39 +0800 Subject: [PATCH 3/3] update to 8.13 --- dist/prober.php | 2 +- src/Components/Config/ConfigApi.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/prober.php b/dist/prober.php index 432e114c..0c82f9bd 100644 --- a/dist/prober.php +++ b/dist/prober.php @@ -45,4 +45,4 @@ HTML; -} } namespace InnStudio\Prober\Components\Updater; use InnStudio\Prober\Components\Config\ConfigApi; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; final class Updater { public function __construct() { EventsApi::on('init', function ($action) { if ('update' !== $action) { return $action; } $response = new RestResponse(); if ( ! is_writable(__FILE__)) { $response->setStatus(StatusCode::$INSUFFICIENT_STORAGE)->end(); } $code = ''; foreach (ConfigApi::$UPDATE_PHP_URLS as $url) { $code = (string) file_get_contents($url); if ('' !== trim($code)) { break; } } if ( ! $code) { $response->setStatus(StatusCode::$NOT_FOUND)->end(); } if (\defined('XPROBER_IS_DEV') && XPROBER_IS_DEV) { $response->end(); } if ((bool) file_put_contents(__FILE__, $code)) { if (\function_exists('opcache_invalidate')) { opcache_invalidate(__FILE__, true) || opcache_reset(); } $response->end(); } $response->setStatus(StatusCode::$INTERNAL_SERVER_ERROR)->end(); }); } } namespace InnStudio\Prober\Components\NetworkStats; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsApi; use InnStudio\Prober\Components\Utils\UtilsNetwork; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends NetworkStatsConstants { public function __construct() { UtilsApi::isWin() || EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $conf[$this->ID] = array( 'networks' => UtilsNetwork::getStats(), 'timestamp' => time(), ); return $conf; }); } } namespace InnStudio\Prober\Components\NetworkStats; final class NetworkStats { public function __construct() { new Conf(); new Fetch(); } } namespace InnStudio\Prober\Components\NetworkStats; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsApi; use InnStudio\Prober\Components\Utils\UtilsNetwork; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Fetch extends NetworkStatsConstants { public function __construct() { if ( ! UtilsApi::isWin()) { EventsApi::on('fetch', array($this, 'filter')); EventsApi::on('nodes', array($this, 'filter')); } } public function filter(array $items) { if (XconfigApi::isDisabled($this->ID)) { return $items; } $items[$this->ID] = array( 'networks' => UtilsNetwork::getStats(), 'timestamp' => time(), ); return $items; } } namespace InnStudio\Prober\Components\NetworkStats; class NetworkStatsConstants { protected $ID = 'networkStats'; } namespace InnStudio\Prober\Components\Fetch; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; final class Fetch { public function __construct() { EventsApi::on('init', function ($action) { if ('fetch' === $action) { EventsApi::emit('fetchBefore'); $response = new RestResponse(EventsApi::emit('fetch', array())); $response->json()->end(); } return $action; }, 100); } } namespace InnStudio\Prober\Components\Nodes; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends NodesApi { public function __construct() { EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $conf[$this->ID] = array( 'items' => $this->getNodes(), ); return $conf; }); } } namespace InnStudio\Prober\Components\Nodes; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; final class Fetch extends NodesApi { public function __construct() { EventsApi::on('init', function ($action) { switch ($action) { case 'nodes': EventsApi::emit('fetchNodesBefore'); $response = new RestResponse(EventsApi::emit('nodes', array())); $response->json()->end(); case 'node': EventsApi::emit('fetchNodeBefore'); $nodeId = filter_input(\INPUT_GET, 'nodeId', \FILTER_DEFAULT); $response = new RestResponse(); if ( ! $nodeId) { $response->setStatus(StatusCode::$BAD_REQUEST)->json()->end(); } $data = $this->getNodeData($nodeId); if ( ! $data) { $response->setStatus(StatusCode::$NO_CONTENT)->json()->end(); } $response->setData($data)->json()->end(); } return $action; }, 100); } private function getNodeData($nodeId) { foreach ($this->getNodes() as $item) { if ( ! isset($item['id']) || ! isset($item['url']) || $item['id'] !== $nodeId) { continue; } return $this->getRemoteContent("{$item['url']}?action=fetch"); } } private function getRemoteContent($url) { $content = ''; if (\function_exists('curl_init')) { $ch = curl_init(); curl_setopt_array($ch, array( \CURLOPT_URL => $url, \CURLOPT_RETURNTRANSFER => true, )); $content = curl_exec($ch); curl_close($ch); return json_decode($content, true) ?: null; } return json_decode(file_get_contents($url), true) ?: null; } } namespace InnStudio\Prober\Components\Nodes; use InnStudio\Prober\Components\Xconfig\XconfigApi; class NodesApi { public $ID = 'nodes'; public function getNodes() { $items = XconfigApi::getNodes(); if ( ! $items || ! \is_array($items)) { return array(); } return array_filter(array_map(function ($item) { if (2 !== \count($item)) { return; } return array( 'id' => $item[0], 'url' => $item[1], ); }, $items)); } } namespace InnStudio\Prober\Components\Nodes; final class Nodes { public function __construct() { new Conf(); new Fetch(); } } namespace InnStudio\Prober\Components\Config; class ConfigApi { public static $APP_VERSION = '8.12'; public static $APP_NAME = 'X Prober'; public static $APP_URL = 'https://github.com/kmvan/x-prober'; public static $APP_CONFIG_URLS = array('https://raw.githubusercontent.com/kmvan/x-prober/master/AppConfig.json', 'https://api.inn-studio.com/download/?id=xprober-config'); public static $APP_CONFIG_URL_DEV = 'http://localhost:8000/AppConfig.json'; public static $APP_TEMPERATURE_SENSOR_URL = 'http://127.0.0.1'; public static $APP_TEMPERATURE_SENSOR_PORTS = array(2048, 4096); public static $AUTHOR_URL = 'https://inn-studio.com/prober'; public static $UPDATE_PHP_URLS = array('https://raw.githubusercontent.com/kmvan/x-prober/master/dist/prober.php', 'https://api.inn-studio.com/download/?id=xprober'); public static $AUTHOR_NAME = 'INN STUDIO'; public static $LATEST_PHP_STABLE_VERSION = '8'; public static $LATEST_NGINX_STABLE_VERSION = '1.20.1'; } namespace InnStudio\Prober\Components\Database; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Xconfig\XconfigApi; use PDO; use SQLite3; final class Conf extends DatabaseConstants { public function __construct() { EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $sqlite3Version = class_exists('SQLite3') ? SQLite3::version() : false; $conf[$this->ID] = array( 'sqlite3' => $sqlite3Version ? $sqlite3Version['versionString'] : false, 'sqliteLibversion' => \function_exists('sqlite_libversion') ? sqlite_libversion() : false, 'mysqliClientVersion' => \function_exists('mysqli_get_client_version') ? mysqli_get_client_version() : false, 'mongo' => class_exists('Mongo'), 'mongoDb' => class_exists('MongoDB'), 'postgreSql' => \function_exists('pg_connect'), 'paradox' => \function_exists('px_new'), 'msSql' => \function_exists('sqlsrv_server_info'), 'pdo' => class_exists('PDO') ? implode(',', PDO::getAvailableDrivers()) : false, ); return $conf; }); } } namespace InnStudio\Prober\Components\Database; class DatabaseConstants { protected $ID = 'database'; } namespace InnStudio\Prober\Components\Database; final class Database { public function __construct() { new Conf(); } } namespace InnStudio\Prober\Components\Xconfig; use InnStudio\Prober\Components\Utils\UtilsApi; final class XconfigApi { private static $conf; private static $filename = 'xconfig.json'; public static function isDisabled($id) { return \in_array($id, self::get('disabled') ?: array(), true); } public static function getNodes() { return self::get('nodes') ?: array(); } public static function get($id = null) { self::setConf(); if ($id) { return isset(self::$conf[$id]) ? self::$conf[$id] : null; } return self::$conf; } private static function getFilePath() { if ( ! \defined('\\XPROBER_DIR')) { return ''; } if (\defined('\\XPROBER_IS_DEV') && XPROBER_IS_DEV) { return \dirname(XPROBER_DIR) . '/' . self::$filename; } return XPROBER_DIR . '/' . self::$filename; } private static function setConf() { if (null !== self::$conf) { return; } if ( ! is_readable(self::getFilePath())) { self::$conf = null; return; } $conf = UtilsApi::jsonDecode(file_get_contents(self::getFilePath())); if ( ! $conf) { self::$conf = null; return; } self::$conf = $conf; } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Utils\UtilsServerIp; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class ServerInitIpv4 extends ServerInfoConstants { public function __construct() { EventsApi::on('init', function ($action) { if ('serverIpv4' !== $action) { return $action; } if (XconfigApi::isDisabled($this->ID)) { return $action; } if (XconfigApi::isDisabled($this->FEATURE_SERVER_IP)) { return $action; } $response = new RestResponse(); $response->setData(array( 'ip' => UtilsServerIp::getV4(), ))->json()->end(); }); } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsCpu; use InnStudio\Prober\Components\Utils\UtilsDisk; use InnStudio\Prober\Components\Utils\UtilsTime; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends ServerInfoConstants { public function __construct() { EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $conf[$this->ID] = array( 'serverName' => $this->getServerInfo('SERVER_NAME'), 'serverUtcTime' => UtilsTime::getUtcTime(), 'serverTime' => UtilsTime::getTime(), 'serverUptime' => UtilsTime::getUptime(), 'serverIp' => XconfigApi::isDisabled('serverIp') ? '-' : $this->getServerInfo('SERVER_ADDR'), 'serverSoftware' => $this->getServerInfo('SERVER_SOFTWARE'), 'phpVersion' => \PHP_VERSION, 'cpuModel' => UtilsCpu::getModel(), 'serverOs' => php_uname(), 'scriptPath' => __FILE__, 'diskUsage' => array( 'value' => UtilsDisk::getTotal() - UtilsDisk::getFree(), 'max' => UtilsDisk::getTotal(), ), ); return $conf; }); } private function getServerInfo($key) { return isset($_SERVER[$key]) ? $_SERVER[$key] : ''; } } namespace InnStudio\Prober\Components\ServerInfo; final class ServerInfo { public function __construct() { new Conf(); new Fetch(); new ServerInitIpv4(); new ServerInitIpv6(); new ServerLocationIpv4(); } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Utils\UtilsServerIp; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class ServerInitIpv6 extends ServerInfoConstants { public function __construct() { EventsApi::on('init', function ($action) { if ('serverIpv6' !== $action) { return $action; } if (XconfigApi::isDisabled($this->ID)) { return $action; } if (XconfigApi::isDisabled($this->FEATURE_SERVER_IP)) { return $action; } $response = new RestResponse(); $response->setData(array( 'ip' => UtilsServerIp::getV6(), ))->json()->end(); }); } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; use InnStudio\Prober\Components\Utils\UtilsLocation; use InnStudio\Prober\Components\Utils\UtilsServerIp; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class ServerLocationIpv4 extends ServerInfoConstants { public function __construct() { EventsApi::on('init', function ($action) { if ('serverLocationIpv4' !== $action) { return $action; } if (XconfigApi::isDisabled($this->ID)) { return $action; } if (XconfigApi::isDisabled($this->FEATURE_SERVER_IP)) { return $action; } $response = new RestResponse(); $ip = UtilsServerIp::getV4(); if ( ! $ip) { $response->setStatus(StatusCode::$BAD_REQUEST)->json()->end(); } $response->setData(UtilsLocation::getLocation($ip))->json()->end(); }); } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsDisk; use InnStudio\Prober\Components\Utils\UtilsTime; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Fetch extends ServerInfoConstants { public function __construct() { EventsApi::on('fetch', array($this, 'filter')); EventsApi::on('nodes', array($this, 'filter')); } public function filter(array $items) { if (XconfigApi::isDisabled($this->ID)) { return $items; } $items[$this->ID] = array( 'serverUtcTime' => UtilsTime::getUtcTime(), 'serverTime' => UtilsTime::getTime(), 'serverUptime' => UtilsTime::getUptime(), 'diskUsage' => array( 'value' => UtilsDisk::getTotal() - UtilsDisk::getFree(), 'max' => UtilsDisk::getTotal(), ), ); return $items; } } namespace InnStudio\Prober\Components\ServerInfo; class ServerInfoConstants { protected $ID = 'serverInfo'; protected $FEATURE_SERVER_IP = 'serverIp'; } namespace InnStudio\Prober\Components\Utils; final class UtilsDisk { public static function getTotal() { if ( ! \function_exists('disk_total_space')) { return 0; } static $space = null; if (null === $space) { $space = (float) disk_total_space(__DIR__); } return $space; } public static function getFree() { if ( ! \function_exists('disk_total_space')) { return 0; } static $space = null; if (null === $space) { $space = (float) disk_free_space(__DIR__); } return $space; } } namespace InnStudio\Prober\Components\Utils; final class UtilsClientIp { public static function getV4() { $keys = array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'); foreach ($keys as $key) { if ( ! isset($_SERVER[$key])) { continue; } $ip = array_filter(explode(',', $_SERVER[$key])); $ip = filter_var(end($ip), \FILTER_VALIDATE_IP); if ($ip) { return $ip; } } return ''; } } namespace InnStudio\Prober\Components\Utils; final class UtilsMemory { public static function getMemoryUsage($key) { $key = ucfirst($key); if (UtilsApi::isWin()) { return 0; } static $memInfo = null; if (null === $memInfo) { $memInfoFile = '/proc/meminfo'; if ( ! @is_readable($memInfoFile)) { $memInfo = 0; return 0; } $memInfo = file_get_contents($memInfoFile); $memInfo = str_replace(array( ' kB', ' ', ), '', $memInfo); $lines = array(); foreach (explode("\n", $memInfo) as $line) { if ( ! $line) { continue; } $line = explode(':', $line); $lines[$line[0]] = (float) $line[1] * 1024; } $memInfo = $lines; } if ( ! isset($memInfo['MemTotal'])) { return 0; } switch ($key) { case 'MemRealUsage': if (isset($memInfo['MemAvailable'])) { return $memInfo['MemTotal'] - $memInfo['MemAvailable']; } if (isset($memInfo['MemFree'])) { if (isset($memInfo['Buffers'], $memInfo['Cached'])) { return $memInfo['MemTotal'] - $memInfo['MemFree'] - $memInfo['Buffers'] - $memInfo['Cached']; } return $memInfo['MemTotal'] - $memInfo['Buffers']; } return 0; case 'MemUsage': return isset($memInfo['MemFree']) ? $memInfo['MemTotal'] - $memInfo['MemFree'] : 0; case 'SwapUsage': if ( ! isset($memInfo['SwapTotal']) || ! isset($memInfo['SwapFree'])) { return 0; } return $memInfo['SwapTotal'] - $memInfo['SwapFree']; } return isset($memInfo[$key]) ? $memInfo[$key] : 0; } } namespace InnStudio\Prober\Components\Utils; final class UtilsLocation { public static function getLocation($ip) { $url = "http://api.ipstack.com/{$ip}?access_key=e4394fd12dbbefa08612306ca05baca3&format=1"; $content = ''; if (\function_exists('\\curl_init')) { $ch = curl_init(); curl_setopt_array($ch, array( \CURLOPT_URL => $url, \CURLOPT_RETURNTRANSFER => true, )); $content = curl_exec($ch); curl_close($ch); } else { $content = file_get_contents($url); } $item = json_decode($content, true) ?: null; if ( ! $item) { return; } return array( 'country' => isset($item['country_name']) ? $item['country_name'] : '', 'region' => isset($item['region_name']) ? $item['region_name'] : '', 'city' => isset($item['city']) ? $item['city'] : '', 'flag' => isset($item['location']['country_flag_emoji']) ? $item['location']['country_flag_emoji'] : '', ); } } namespace InnStudio\Prober\Components\Utils; final class UtilsTime { public static function getTime() { return date('Y-m-d H:i:s'); } public static function getUtcTime() { return gmdate('Y/m/d H:i:s'); } public static function getUptime() { $filePath = '/proc/uptime'; if ( ! @is_file($filePath)) { return array( 'days' => 0, 'hours' => 0, 'mins' => 0, 'secs' => 0, ); } $str = file_get_contents($filePath); $num = (float) $str; $secs = (int) fmod($num, 60); $num = (int) ($num / 60); $mins = (int) $num % 60; $num = (int) ($num / 60); $hours = (int) $num % 24; $num = (int) ($num / 24); $days = (int) $num; return array( 'days' => $days, 'hours' => $hours, 'mins' => $mins, 'secs' => $secs, ); } } namespace InnStudio\Prober\Components\Utils; final class UtilsApi { public static function jsonDecode($json, $depth = 512, $options = 0) { $json = preg_replace("#(/\\*([^*]|[\r\n]|(\\*+([^*/]|[\r\n])))*\\*+/)|([\\s\t]//.*)|(^//.*)#", '', $json); if (\PHP_VERSION_ID >= 50400) { return json_decode($json, true, $depth, $options); } if (\PHP_VERSION_ID >= 50300) { return json_decode($json, true, $depth); } return json_decode($json, true); } public static function setFileCacheHeader() { $seconds = 3600 * 24 * 30 * 12; $ts = gmdate('D, d M Y H:i:s', (int) $_SERVER['REQUEST_TIME'] + $seconds) . ' GMT'; header("Expires: {$ts}"); header('Pragma: cache'); header("Cache-Control: public, max-age={$seconds}"); } public static function getErrNameByCode($code) { if (0 === (int) $code) { return ''; } $levels = array( \E_ALL => 'E_ALL', \E_USER_DEPRECATED => 'E_USER_DEPRECATED', \E_DEPRECATED => 'E_DEPRECATED', \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', \E_STRICT => 'E_STRICT', \E_USER_NOTICE => 'E_USER_NOTICE', \E_USER_WARNING => 'E_USER_WARNING', \E_USER_ERROR => 'E_USER_ERROR', \E_COMPILE_WARNING => 'E_COMPILE_WARNING', \E_COMPILE_ERROR => 'E_COMPILE_ERROR', \E_CORE_WARNING => 'E_CORE_WARNING', \E_CORE_ERROR => 'E_CORE_ERROR', \E_NOTICE => 'E_NOTICE', \E_PARSE => 'E_PARSE', \E_WARNING => 'E_WARNING', \E_ERROR => 'E_ERROR', ); $result = ''; foreach ($levels as $number => $name) { if (($code & $number) === $number) { $result .= ('' !== $result ? ', ' : '') . $name; } } return $result; } public static function isWin() { return \PHP_OS === 'WINNT'; } } namespace InnStudio\Prober\Components\Utils; final class UtilsNetwork { public static function getStats() { $filePath = '/proc/net/dev'; if ( ! @is_readable($filePath)) { return; } static $eths = null; if (null !== $eths) { return $eths; } $lines = file($filePath); unset($lines[0], $lines[1]); $eths = array(); foreach ($lines as $line) { $line = preg_replace('/\\s+/', ' ', trim($line)); $lineArr = explode(':', $line); $numberArr = explode(' ', trim($lineArr[1])); $rx = (float) $numberArr[0]; $tx = (float) $numberArr[8]; if ( ! $rx && ! $tx) { continue; } $eths[] = array( 'id' => $lineArr[0], 'rx' => $rx, 'tx' => $tx, ); } return $eths; } } namespace InnStudio\Prober\Components\Utils; final class UtilsServerIp { public static function getV4() { return self::getV4ViaInnStudioCom() ?: self::getV4ViaIpv6TestCom() ?: self::getV4Local(); } public static function getV6() { return self::getV6ViaInnStudioCom() ?: self::getV6ViaIpv6TestCom() ?: self::getV6Local(); } private static function getV4Local() { $content = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : ''; return filter_var($content, \FILTER_VALIDATE_IP, array( 'flags' => \FILTER_FLAG_IPV4, )) ?: ''; } private static function getV6Local() { $content = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : ''; return filter_var($content, \FILTER_VALIDATE_IP, array( 'flags' => \FILTER_FLAG_IPV6, )) ?: ''; } private static function getV4ViaInnStudioCom() { return self::getContent('https://ipv4.inn-studio.com/ip/', 4); } private static function getV6ViaInnStudioCom() { return self::getContent('https://ipv6.inn-studio.com/ip/', 6); } private static function getV4ViaIpv6TestCom() { return self::getContent('https://v4.ipv6-test.com/api/myip.php', 4); } private static function getV6ViaIpv6TestCom() { return self::getContent('https://v6.ipv6-test.com/api/myip.php', 6); } private static function getContent($url, $type) { $content = ''; if (\function_exists('curl_init')) { $ch = curl_init(); curl_setopt_array($ch, array( \CURLOPT_URL => $url, \CURLOPT_RETURNTRANSFER => true, )); $content = curl_exec($ch); curl_close($ch); } else { $content = file_get_contents($url); } return (string) filter_var($content, \FILTER_VALIDATE_IP, array( 'flags' => 6 === $type ? \FILTER_FLAG_IPV6 : \FILTER_FLAG_IPV4, )) ?: ''; } } namespace InnStudio\Prober\Components\Utils; use COM; final class UtilsCpu { public static function getLoadAvg() { if (UtilsApi::isWin()) { return array(0, 0, 0); } return array_map(function ($load) { return (float) sprintf('%.2f', $load); }, sys_getloadavg()); } public static function getModel() { $filePath = '/proc/cpuinfo'; if ( ! @is_readable($filePath)) { return ''; } $content = file_get_contents($filePath); $cores = substr_count($content, 'cache size'); $lines = explode("\n", $content); $modelName = explode(':', $lines[4]); $modelName = trim($modelName[1]); $cacheSize = explode(':', $lines[8]); $cacheSize = trim($cacheSize[1]); return "{$cores} x {$modelName} / " . sprintf('%s cache', $cacheSize); } public static function getWinUsage() { $usage = array( 'idle' => 100, 'user' => 0, 'sys' => 0, 'nice' => 0, ); if (class_exists('COM')) { $wmi = new COM('Winmgmts://'); $server = $wmi->execquery('SELECT LoadPercentage FROM Win32_Processor'); $total = 0; foreach ($server as $cpu) { $total += (int) $cpu->loadpercentage; } $total = (float) $total / \count($server); $usage['idle'] = 100 - $total; $usage['user'] = $total; } else { if ( ! \function_exists('exec')) { return $usage; } $p = array(); exec('wmic cpu get LoadPercentage', $p); if (isset($p[1])) { $percent = (int) $p[1]; $usage['idle'] = 100 - $percent; $usage['user'] = $percent; } } return $usage; } public static function getUsage() { static $cpu = null; if (null !== $cpu) { return $cpu; } if (UtilsApi::isWin()) { $cpu = self::getWinUsage(); return $cpu; } $filePath = '/proc/stat'; if ( ! @is_readable($filePath)) { $cpu = array(); return array( 'user' => 0, 'nice' => 0, 'sys' => 0, 'idle' => 100, ); } $stat1 = file($filePath); sleep(1); $stat2 = file($filePath); $info1 = explode(' ', preg_replace('!cpu +!', '', $stat1[0])); $info2 = explode(' ', preg_replace('!cpu +!', '', $stat2[0])); $dif = array(); $dif['user'] = $info2[0] - $info1[0]; $dif['nice'] = $info2[1] - $info1[1]; $dif['sys'] = $info2[2] - $info1[2]; $dif['idle'] = $info2[3] - $info1[3]; $total = array_sum($dif); $cpu = array(); foreach ($dif as $x => $y) { $cpu[$x] = round($y / $total * 100, 1); } return $cpu; } } namespace InnStudio\Prober\Components\ServerBenchmark; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends ServerBenchmarkConstants { public function __construct() { EventsApi::on('conf', function (array $conf) { $conf[$this->ID] = array( 'disabledMyServerBenchmark' => XconfigApi::isDisabled('myServerBenchmark'), ); return $conf; }); } } namespace InnStudio\Prober\Components\ServerBenchmark; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Init extends ServerBenchmarkApi { public function __construct() { EventsApi::on('init', function ($action) { if (XconfigApi::isDisabled('myServerBenchmark')) { return $action; } if ('benchmark' !== $action) { return $action; } $this->render(); }); } private function render() { $remainingSeconds = $this->getRemainingSeconds(); $response = new RestResponse(); if ($remainingSeconds) { $response->setStatus(StatusCode::$TOO_MANY_REQUESTS); $response->setData(array( 'seconds' => $remainingSeconds, ))->json()->end(); } set_time_limit(0); $this->setExpired(); $this->setIsRunning(true); $marks = $this->getPoints(); $this->setIsRunning(false); $response->setData(array( 'marks' => $marks, ))->json()->end(); } } namespace InnStudio\Prober\Components\ServerBenchmark; final class ServerBenchmark { public function __construct() { new Init(); new Conf(); new FetchBefore(); } } namespace InnStudio\Prober\Components\ServerBenchmark; use InnStudio\Prober\Components\Events\EventsApi; final class FetchBefore extends ServerBenchmarkApi { public function __construct() { EventsApi::on('fetchBefore', array($this, 'filter')); EventsApi::on('fetchNodesBefore', array($this, 'filter')); EventsApi::on('fetchNodeBefore', array($this, 'filter')); } public function filter() { while ($this->isRunning()) { sleep(2); } } } namespace InnStudio\Prober\Components\ServerBenchmark; class ServerBenchmarkApi { private $EXPIRED = 60; public function getTmpRecorderPath() { return sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'xproberBenchmarkTimer'; } public function setRecorder(array $data) { return (bool) file_put_contents($this->getTmpRecorderPath(), json_encode(array_merge($this->getRecorder(), $data))); } public function setExpired() { return (bool) $this->setRecorder(array( 'expired' => (int) $_SERVER['REQUEST_TIME'] + $this->EXPIRED, )); } public function setIsRunning($isRunning) { return (bool) $this->setRecorder(array( 'isRunning' => true === (bool) $isRunning ? 1 : 0, )); } public function isRunning() { $recorder = $this->getRecorder(); return isset($recorder['isRunning']) ? 1 === (int) $recorder['isRunning'] : false; } public function getRemainingSeconds() { $recorder = $this->getRecorder(); $expired = isset($recorder['expired']) ? (int) $recorder['expired'] : 0; if ( ! $expired) { return 0; } return $expired > (int) $_SERVER['REQUEST_TIME'] ? $expired - (int) $_SERVER['REQUEST_TIME'] : 0; } public function getPointsByTime($time) { return pow(10, 3) - (int) ($time * pow(10, 3)); } public function getCpuPoints() { $data = 'inn-studio.com'; $hash = array('md5', 'sha512', 'sha256', 'crc32'); $start = microtime(true); $i = 0; while (microtime(true) - $start < .5) { foreach ($hash as $v) { hash($v, $data); } ++$i; } return $i; } public function getWritePoints() { $tmpDir = sys_get_temp_dir(); if ( ! is_writable($tmpDir)) { return 0; } $i = 0; $start = microtime(true); while (microtime(true) - $start < .5) { $filePath = "{$tmpDir}/innStudioWriteBenchmark:{$i}"; clearstatcache(true, $filePath); file_put_contents($filePath, $filePath); unlink($filePath); ++$i; } return $i; } public function getReadPoints() { $tmpDir = sys_get_temp_dir(); if ( ! is_readable($tmpDir)) { return 0; } $i = 0; $start = microtime(true); $filePath = "{$tmpDir}/innStudioIoBenchmark"; if ( ! file_exists($filePath)) { file_put_contents($filePath, 'innStudioReadBenchmark'); } while (microtime(true) - $start < .5) { clearstatcache(true, $filePath); file_get_contents($filePath); ++$i; } return $i; } public function getPoints() { return array( 'cpu' => $this->getMedian(array( $this->getCpuPoints(), $this->getCpuPoints(), $this->getCpuPoints(), )), 'write' => $this->getMedian(array( $this->getWritePoints(), $this->getWritePoints(), $this->getWritePoints(), )), 'read' => $this->getMedian(array( $this->getReadPoints(), $this->getReadPoints(), $this->getReadPoints(), )), ); } private function getRecorder() { $path = $this->getTmpRecorderPath(); $defaults = array( 'expired' => 0, 'running' => 0, ); if ( ! @is_readable($path)) { return $defaults; } $data = (string) file_get_contents($path); if ( ! $data) { return $defaults; } $data = json_decode($data, true); if ( ! $data) { return $defaults; } return array_merge($defaults, $data); } private function getMedian(array $arr) { $count = \count($arr); sort($arr); $mid = floor(($count - 1) / 2); return ($arr[$mid] + $arr[$mid + 1 - $count % 2]) / 2; } } namespace InnStudio\Prober\Components\ServerBenchmark; class ServerBenchmarkConstants { protected $ID = 'serverBenchmark'; } namespace InnStudio\Prober\Components\Rest; final class RestResponse { private $data; private $headers = array(); private $status = 200; public function __construct(array $data = null, $status = 200, array $headers = array()) { $this->setData($data); $this->setStatus($status); $this->setHeaders($headers); } public function setHeader($key, $value, $replace = true) { if ($replace || ! isset($this->headers[$key])) { $this->headers[$key] = $value; } else { $this->headers[$key] .= ", {$value}"; } } public function setHeaders(array $headers) { $this->headers = $headers; } public function getHeaders() { return $this->headers; } public function setStatus($status) { $this->status = $status; return $this; } public function getStatus() { return $this->status; } public function setData($data) { $this->data = $data; return $this; } public function getData() { return $this->data; } public function json() { $this->httpResponseCode($this->status); header('Content-Type: application/json'); header('Expires: 0'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Pragma: no-cache'); echo $this->toJson(); return $this; } public function end() { exit; } private function toJson() { $data = $this->getData(); if (null === $data) { return ''; } return json_encode($data); } private function httpResponseCode($code) { if (\function_exists('http_response_code')) { return http_response_code($code); } $statusCode = array( 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => '(Unused)', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 418 => "I'm a teapot", 419 => 'Authentication Timeout', 420 => 'Enhance Your Calm', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 424 => 'Method Failure', 425 => 'Unordered Collection', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 444 => 'No Response', 449 => 'Retry With', 450 => 'Blocked by Windows Parental Controls', 451 => 'Unavailable For Legal Reasons', 494 => 'Request Header Too Large', 495 => 'Cert Error', 496 => 'No Cert', 497 => 'HTTP to HTTPS', 499 => 'Client Closed Request', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 509 => 'Bandwidth Limit Exceeded', 510 => 'Not Extended', 511 => 'Network Authentication Required', 598 => 'Network read timeout error', 599 => 'Network connect timeout error', ); $msg = isset($statusCode[$code]) ? $statusCode[$code] : 'Unknow error'; $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0'); header("{$protocol} {$code} {$msg}"); } } namespace InnStudio\Prober\Components\Rest; final class StatusCode { public static $__default = 200; public static $CONTINUE = 100; public static $SWITCHING_PROTOCOLS = 101; public static $PROCESSING = 102; public static $OK = 200; public static $CREATED = 201; public static $ACCEPTED = 202; public static $NON_AUTHORITATIVE_INFORMATION = 203; public static $NO_CONTENT = 204; public static $RESET_CONTENT = 205; public static $PARTIAL_CONTENT = 206; public static $MULTI_STATUS = 207; public static $ALREADY_REPORTED = 208; public static $IM_USED = 226; public static $MULTIPLE_CHOICES = 300; public static $MOVED_PERMANENTLY = 301; public static $FOUND = 302; public static $SEE_OTHER = 303; public static $NOT_MODIFIED = 304; public static $USE_PROXY = 305; public static $SWITCH_PROXY = 306; public static $TEMPORARY_REDIRECT = 307; public static $PERMANENT_REDIRECT = 308; public static $BAD_REQUEST = 400; public static $UNAUTHORIZED = 401; public static $PAYMENT_REQUIRED = 402; public static $FORBIDDEN = 403; public static $NOT_FOUND = 404; public static $METHOD_NOT_ALLOWED = 405; public static $NOT_ACCEPTABLE = 406; public static $PROXY_AUTHENTICATION_REQUIRED = 407; public static $REQUEST_TIMEOUT = 408; public static $CONFLICT = 409; public static $GONE = 410; public static $LENGTH_REQUIRED = 411; public static $PRECONDITION_FAILED = 412; public static $REQUEST_ENTITY_TOO_LARGE = 413; public static $REQUEST_URI_TOO_LONG = 414; public static $UNSUPPORTED_MEDIA_TYPE = 415; public static $REQUESTED_RANGE_NOT_SATISFIABLE = 416; public static $EXPECTATION_FAILED = 417; public static $I_AM_A_TEAPOT = 418; public static $AUTHENTICATION_TIMEOUT = 419; public static $ENHANCE_YOUR_CALM = 420; public static $METHOD_FAILURE = 420; public static $UNPROCESSABLE_ENTITY = 422; public static $LOCKED = 423; public static $FAILED_DEPENDENCY = 424; public static $UNORDERED_COLLECTION = 425; public static $UPGRADE_REQUIRED = 426; public static $PRECONDITION_REQUIRED = 428; public static $TOO_MANY_REQUESTS = 429; public static $REQUEST_HEADER_FIELDS_TOO_LARGE = 431; public static $NO_RESPONSE = 444; public static $RETRY_WITH = 449; public static $BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS = 450; public static $REDIRECT = 451; public static $UNAVAILABLE_FOR_LEGAL_REASONS = 451; public static $REQUEST_HEADER_TOO_LARGE = 494; public static $CERT_ERROR = 495; public static $NO_CERT = 496; public static $HTTP_TO_HTTPS = 497; public static $CLIENT_CLOSED_REQUEST = 499; public static $INTERNAL_SERVER_ERROR = 500; public static $NOT_IMPLEMENTED = 501; public static $BAD_GATEWAY = 502; public static $SERVICE_UNAVAILABLE = 503; public static $GATEWAY_TIMEOUT = 504; public static $HTTP_VERSION_NOT_SUPPORTED = 505; public static $VARIANT_ALSO_NEGOTIATES = 506; public static $INSUFFICIENT_STORAGE = 507; public static $LOOP_DETECTED = 508; public static $BANDWIDTH_LIMIT_EXCEEDED = 509; public static $NOT_EXTENDED = 510; public static $NETWORK_AUTHENTICATION_REQUIRED = 511; public static $NETWORK_READ_TIMEOUT_ERROR = 598; public static $NETWORK_CONNECT_TIMEOUT_ERROR = 599; }new \InnStudio\Prober\Components\Database\Database(); new \InnStudio\Prober\Components\Fetch\Fetch(); new \InnStudio\Prober\Components\Footer\Footer(); new \InnStudio\Prober\Components\MyInfo\MyInfo(); new \InnStudio\Prober\Components\NetworkStats\NetworkStats(); new \InnStudio\Prober\Components\Nodes\Nodes(); new \InnStudio\Prober\Components\PhpExtensions\PhpExtensions(); new \InnStudio\Prober\Components\PhpInfo\PhpInfo(); new \InnStudio\Prober\Components\PhpInfoDetail\PhpInfoDetail(); new \InnStudio\Prober\Components\Ping\Ping(); new \InnStudio\Prober\Components\Script\Script(); new \InnStudio\Prober\Components\ServerBenchmark\ServerBenchmark(); new \InnStudio\Prober\Components\ServerInfo\ServerInfo(); new \InnStudio\Prober\Components\ServerStatus\ServerStatus(); new \InnStudio\Prober\Components\Style\Style(); new \InnStudio\Prober\Components\TemperatureSensor\TemperatureSensor(); new \InnStudio\Prober\Components\Timezone\Timezone(); new \InnStudio\Prober\Components\Updater\Updater(); new \InnStudio\Prober\Components\Bootstrap\Bootstrap(); \ No newline at end of file +} } namespace InnStudio\Prober\Components\Updater; use InnStudio\Prober\Components\Config\ConfigApi; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; final class Updater { public function __construct() { EventsApi::on('init', function ($action) { if ('update' !== $action) { return $action; } $response = new RestResponse(); if ( ! is_writable(__FILE__)) { $response->setStatus(StatusCode::$INSUFFICIENT_STORAGE)->end(); } $code = ''; foreach (ConfigApi::$UPDATE_PHP_URLS as $url) { $code = (string) file_get_contents($url); if ('' !== trim($code)) { break; } } if ( ! $code) { $response->setStatus(StatusCode::$NOT_FOUND)->end(); } if (\defined('XPROBER_IS_DEV') && XPROBER_IS_DEV) { $response->end(); } if ((bool) file_put_contents(__FILE__, $code)) { if (\function_exists('opcache_invalidate')) { opcache_invalidate(__FILE__, true) || opcache_reset(); } $response->end(); } $response->setStatus(StatusCode::$INTERNAL_SERVER_ERROR)->end(); }); } } namespace InnStudio\Prober\Components\NetworkStats; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsApi; use InnStudio\Prober\Components\Utils\UtilsNetwork; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends NetworkStatsConstants { public function __construct() { UtilsApi::isWin() || EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $conf[$this->ID] = array( 'networks' => UtilsNetwork::getStats(), 'timestamp' => time(), ); return $conf; }); } } namespace InnStudio\Prober\Components\NetworkStats; final class NetworkStats { public function __construct() { new Conf(); new Fetch(); } } namespace InnStudio\Prober\Components\NetworkStats; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsApi; use InnStudio\Prober\Components\Utils\UtilsNetwork; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Fetch extends NetworkStatsConstants { public function __construct() { if ( ! UtilsApi::isWin()) { EventsApi::on('fetch', array($this, 'filter')); EventsApi::on('nodes', array($this, 'filter')); } } public function filter(array $items) { if (XconfigApi::isDisabled($this->ID)) { return $items; } $items[$this->ID] = array( 'networks' => UtilsNetwork::getStats(), 'timestamp' => time(), ); return $items; } } namespace InnStudio\Prober\Components\NetworkStats; class NetworkStatsConstants { protected $ID = 'networkStats'; } namespace InnStudio\Prober\Components\Fetch; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; final class Fetch { public function __construct() { EventsApi::on('init', function ($action) { if ('fetch' === $action) { EventsApi::emit('fetchBefore'); $response = new RestResponse(EventsApi::emit('fetch', array())); $response->json()->end(); } return $action; }, 100); } } namespace InnStudio\Prober\Components\Nodes; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends NodesApi { public function __construct() { EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $conf[$this->ID] = array( 'items' => $this->getNodes(), ); return $conf; }); } } namespace InnStudio\Prober\Components\Nodes; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; final class Fetch extends NodesApi { public function __construct() { EventsApi::on('init', function ($action) { switch ($action) { case 'nodes': EventsApi::emit('fetchNodesBefore'); $response = new RestResponse(EventsApi::emit('nodes', array())); $response->json()->end(); case 'node': EventsApi::emit('fetchNodeBefore'); $nodeId = filter_input(\INPUT_GET, 'nodeId', \FILTER_DEFAULT); $response = new RestResponse(); if ( ! $nodeId) { $response->setStatus(StatusCode::$BAD_REQUEST)->json()->end(); } $data = $this->getNodeData($nodeId); if ( ! $data) { $response->setStatus(StatusCode::$NO_CONTENT)->json()->end(); } $response->setData($data)->json()->end(); } return $action; }, 100); } private function getNodeData($nodeId) { foreach ($this->getNodes() as $item) { if ( ! isset($item['id']) || ! isset($item['url']) || $item['id'] !== $nodeId) { continue; } return $this->getRemoteContent("{$item['url']}?action=fetch"); } } private function getRemoteContent($url) { $content = ''; if (\function_exists('curl_init')) { $ch = curl_init(); curl_setopt_array($ch, array( \CURLOPT_URL => $url, \CURLOPT_RETURNTRANSFER => true, )); $content = curl_exec($ch); curl_close($ch); return json_decode($content, true) ?: null; } return json_decode(file_get_contents($url), true) ?: null; } } namespace InnStudio\Prober\Components\Nodes; use InnStudio\Prober\Components\Xconfig\XconfigApi; class NodesApi { public $ID = 'nodes'; public function getNodes() { $items = XconfigApi::getNodes(); if ( ! $items || ! \is_array($items)) { return array(); } return array_filter(array_map(function ($item) { if (2 !== \count($item)) { return; } return array( 'id' => $item[0], 'url' => $item[1], ); }, $items)); } } namespace InnStudio\Prober\Components\Nodes; final class Nodes { public function __construct() { new Conf(); new Fetch(); } } namespace InnStudio\Prober\Components\Config; class ConfigApi { public static $APP_VERSION = '8.13'; public static $APP_NAME = 'X Prober'; public static $APP_URL = 'https://github.com/kmvan/x-prober'; public static $APP_CONFIG_URLS = array('https://raw.githubusercontent.com/kmvan/x-prober/master/AppConfig.json', 'https://api.inn-studio.com/download/?id=xprober-config'); public static $APP_CONFIG_URL_DEV = 'http://localhost:8000/AppConfig.json'; public static $APP_TEMPERATURE_SENSOR_URL = 'http://127.0.0.1'; public static $APP_TEMPERATURE_SENSOR_PORTS = array(2048, 4096); public static $AUTHOR_URL = 'https://inn-studio.com/prober'; public static $UPDATE_PHP_URLS = array('https://raw.githubusercontent.com/kmvan/x-prober/master/dist/prober.php', 'https://api.inn-studio.com/download/?id=xprober'); public static $AUTHOR_NAME = 'INN STUDIO'; public static $LATEST_PHP_STABLE_VERSION = '8'; public static $LATEST_NGINX_STABLE_VERSION = '1.20.1'; } namespace InnStudio\Prober\Components\Database; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Xconfig\XconfigApi; use PDO; use SQLite3; final class Conf extends DatabaseConstants { public function __construct() { EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $sqlite3Version = class_exists('SQLite3') ? SQLite3::version() : false; $conf[$this->ID] = array( 'sqlite3' => $sqlite3Version ? $sqlite3Version['versionString'] : false, 'sqliteLibversion' => \function_exists('sqlite_libversion') ? sqlite_libversion() : false, 'mysqliClientVersion' => \function_exists('mysqli_get_client_version') ? mysqli_get_client_version() : false, 'mongo' => class_exists('Mongo'), 'mongoDb' => class_exists('MongoDB'), 'postgreSql' => \function_exists('pg_connect'), 'paradox' => \function_exists('px_new'), 'msSql' => \function_exists('sqlsrv_server_info'), 'pdo' => class_exists('PDO') ? implode(',', PDO::getAvailableDrivers()) : false, ); return $conf; }); } } namespace InnStudio\Prober\Components\Database; class DatabaseConstants { protected $ID = 'database'; } namespace InnStudio\Prober\Components\Database; final class Database { public function __construct() { new Conf(); } } namespace InnStudio\Prober\Components\Xconfig; use InnStudio\Prober\Components\Utils\UtilsApi; final class XconfigApi { private static $conf; private static $filename = 'xconfig.json'; public static function isDisabled($id) { return \in_array($id, self::get('disabled') ?: array(), true); } public static function getNodes() { return self::get('nodes') ?: array(); } public static function get($id = null) { self::setConf(); if ($id) { return isset(self::$conf[$id]) ? self::$conf[$id] : null; } return self::$conf; } private static function getFilePath() { if ( ! \defined('\\XPROBER_DIR')) { return ''; } if (\defined('\\XPROBER_IS_DEV') && XPROBER_IS_DEV) { return \dirname(XPROBER_DIR) . '/' . self::$filename; } return XPROBER_DIR . '/' . self::$filename; } private static function setConf() { if (null !== self::$conf) { return; } if ( ! is_readable(self::getFilePath())) { self::$conf = null; return; } $conf = UtilsApi::jsonDecode(file_get_contents(self::getFilePath())); if ( ! $conf) { self::$conf = null; return; } self::$conf = $conf; } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Utils\UtilsServerIp; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class ServerInitIpv4 extends ServerInfoConstants { public function __construct() { EventsApi::on('init', function ($action) { if ('serverIpv4' !== $action) { return $action; } if (XconfigApi::isDisabled($this->ID)) { return $action; } if (XconfigApi::isDisabled($this->FEATURE_SERVER_IP)) { return $action; } $response = new RestResponse(); $response->setData(array( 'ip' => UtilsServerIp::getV4(), ))->json()->end(); }); } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsCpu; use InnStudio\Prober\Components\Utils\UtilsDisk; use InnStudio\Prober\Components\Utils\UtilsTime; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends ServerInfoConstants { public function __construct() { EventsApi::on('conf', function (array $conf) { if (XconfigApi::isDisabled($this->ID)) { return $conf; } $conf[$this->ID] = array( 'serverName' => $this->getServerInfo('SERVER_NAME'), 'serverUtcTime' => UtilsTime::getUtcTime(), 'serverTime' => UtilsTime::getTime(), 'serverUptime' => UtilsTime::getUptime(), 'serverIp' => XconfigApi::isDisabled('serverIp') ? '-' : $this->getServerInfo('SERVER_ADDR'), 'serverSoftware' => $this->getServerInfo('SERVER_SOFTWARE'), 'phpVersion' => \PHP_VERSION, 'cpuModel' => UtilsCpu::getModel(), 'serverOs' => php_uname(), 'scriptPath' => __FILE__, 'diskUsage' => array( 'value' => UtilsDisk::getTotal() - UtilsDisk::getFree(), 'max' => UtilsDisk::getTotal(), ), ); return $conf; }); } private function getServerInfo($key) { return isset($_SERVER[$key]) ? $_SERVER[$key] : ''; } } namespace InnStudio\Prober\Components\ServerInfo; final class ServerInfo { public function __construct() { new Conf(); new Fetch(); new ServerInitIpv4(); new ServerInitIpv6(); new ServerLocationIpv4(); } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Utils\UtilsServerIp; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class ServerInitIpv6 extends ServerInfoConstants { public function __construct() { EventsApi::on('init', function ($action) { if ('serverIpv6' !== $action) { return $action; } if (XconfigApi::isDisabled($this->ID)) { return $action; } if (XconfigApi::isDisabled($this->FEATURE_SERVER_IP)) { return $action; } $response = new RestResponse(); $response->setData(array( 'ip' => UtilsServerIp::getV6(), ))->json()->end(); }); } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; use InnStudio\Prober\Components\Utils\UtilsLocation; use InnStudio\Prober\Components\Utils\UtilsServerIp; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class ServerLocationIpv4 extends ServerInfoConstants { public function __construct() { EventsApi::on('init', function ($action) { if ('serverLocationIpv4' !== $action) { return $action; } if (XconfigApi::isDisabled($this->ID)) { return $action; } if (XconfigApi::isDisabled($this->FEATURE_SERVER_IP)) { return $action; } $response = new RestResponse(); $ip = UtilsServerIp::getV4(); if ( ! $ip) { $response->setStatus(StatusCode::$BAD_REQUEST)->json()->end(); } $response->setData(UtilsLocation::getLocation($ip))->json()->end(); }); } } namespace InnStudio\Prober\Components\ServerInfo; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Utils\UtilsDisk; use InnStudio\Prober\Components\Utils\UtilsTime; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Fetch extends ServerInfoConstants { public function __construct() { EventsApi::on('fetch', array($this, 'filter')); EventsApi::on('nodes', array($this, 'filter')); } public function filter(array $items) { if (XconfigApi::isDisabled($this->ID)) { return $items; } $items[$this->ID] = array( 'serverUtcTime' => UtilsTime::getUtcTime(), 'serverTime' => UtilsTime::getTime(), 'serverUptime' => UtilsTime::getUptime(), 'diskUsage' => array( 'value' => UtilsDisk::getTotal() - UtilsDisk::getFree(), 'max' => UtilsDisk::getTotal(), ), ); return $items; } } namespace InnStudio\Prober\Components\ServerInfo; class ServerInfoConstants { protected $ID = 'serverInfo'; protected $FEATURE_SERVER_IP = 'serverIp'; } namespace InnStudio\Prober\Components\Utils; final class UtilsDisk { public static function getTotal() { if ( ! \function_exists('disk_total_space')) { return 0; } static $space = null; if (null === $space) { $space = (float) disk_total_space(__DIR__); } return $space; } public static function getFree() { if ( ! \function_exists('disk_total_space')) { return 0; } static $space = null; if (null === $space) { $space = (float) disk_free_space(__DIR__); } return $space; } } namespace InnStudio\Prober\Components\Utils; final class UtilsClientIp { public static function getV4() { $keys = array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'); foreach ($keys as $key) { if ( ! isset($_SERVER[$key])) { continue; } $ip = array_filter(explode(',', $_SERVER[$key])); $ip = filter_var(end($ip), \FILTER_VALIDATE_IP); if ($ip) { return $ip; } } return ''; } } namespace InnStudio\Prober\Components\Utils; final class UtilsMemory { public static function getMemoryUsage($key) { $key = ucfirst($key); if (UtilsApi::isWin()) { return 0; } static $memInfo = null; if (null === $memInfo) { $memInfoFile = '/proc/meminfo'; if ( ! @is_readable($memInfoFile)) { $memInfo = 0; return 0; } $memInfo = file_get_contents($memInfoFile); $memInfo = str_replace(array( ' kB', ' ', ), '', $memInfo); $lines = array(); foreach (explode("\n", $memInfo) as $line) { if ( ! $line) { continue; } $line = explode(':', $line); $lines[$line[0]] = (float) $line[1] * 1024; } $memInfo = $lines; } if ( ! isset($memInfo['MemTotal'])) { return 0; } switch ($key) { case 'MemRealUsage': if (isset($memInfo['MemAvailable'])) { return $memInfo['MemTotal'] - $memInfo['MemAvailable']; } if (isset($memInfo['MemFree'])) { if (isset($memInfo['Buffers'], $memInfo['Cached'])) { return $memInfo['MemTotal'] - $memInfo['MemFree'] - $memInfo['Buffers'] - $memInfo['Cached']; } return $memInfo['MemTotal'] - $memInfo['Buffers']; } return 0; case 'MemUsage': return isset($memInfo['MemFree']) ? $memInfo['MemTotal'] - $memInfo['MemFree'] : 0; case 'SwapUsage': if ( ! isset($memInfo['SwapTotal']) || ! isset($memInfo['SwapFree'])) { return 0; } return $memInfo['SwapTotal'] - $memInfo['SwapFree']; } return isset($memInfo[$key]) ? $memInfo[$key] : 0; } } namespace InnStudio\Prober\Components\Utils; final class UtilsLocation { public static function getLocation($ip) { $url = "http://api.ipstack.com/{$ip}?access_key=e4394fd12dbbefa08612306ca05baca3&format=1"; $content = ''; if (\function_exists('\\curl_init')) { $ch = curl_init(); curl_setopt_array($ch, array( \CURLOPT_URL => $url, \CURLOPT_RETURNTRANSFER => true, )); $content = curl_exec($ch); curl_close($ch); } else { $content = file_get_contents($url); } $item = json_decode($content, true) ?: null; if ( ! $item) { return; } return array( 'country' => isset($item['country_name']) ? $item['country_name'] : '', 'region' => isset($item['region_name']) ? $item['region_name'] : '', 'city' => isset($item['city']) ? $item['city'] : '', 'flag' => isset($item['location']['country_flag_emoji']) ? $item['location']['country_flag_emoji'] : '', ); } } namespace InnStudio\Prober\Components\Utils; final class UtilsTime { public static function getTime() { return date('Y-m-d H:i:s'); } public static function getUtcTime() { return gmdate('Y/m/d H:i:s'); } public static function getUptime() { $filePath = '/proc/uptime'; if ( ! @is_file($filePath)) { return array( 'days' => 0, 'hours' => 0, 'mins' => 0, 'secs' => 0, ); } $str = file_get_contents($filePath); $num = (float) $str; $secs = (int) fmod($num, 60); $num = (int) ($num / 60); $mins = (int) $num % 60; $num = (int) ($num / 60); $hours = (int) $num % 24; $num = (int) ($num / 24); $days = (int) $num; return array( 'days' => $days, 'hours' => $hours, 'mins' => $mins, 'secs' => $secs, ); } } namespace InnStudio\Prober\Components\Utils; final class UtilsApi { public static function jsonDecode($json, $depth = 512, $options = 0) { $json = preg_replace("#(/\\*([^*]|[\r\n]|(\\*+([^*/]|[\r\n])))*\\*+/)|([\\s\t]//.*)|(^//.*)#", '', $json); if (\PHP_VERSION_ID >= 50400) { return json_decode($json, true, $depth, $options); } if (\PHP_VERSION_ID >= 50300) { return json_decode($json, true, $depth); } return json_decode($json, true); } public static function setFileCacheHeader() { $seconds = 3600 * 24 * 30 * 12; $ts = gmdate('D, d M Y H:i:s', (int) $_SERVER['REQUEST_TIME'] + $seconds) . ' GMT'; header("Expires: {$ts}"); header('Pragma: cache'); header("Cache-Control: public, max-age={$seconds}"); } public static function getErrNameByCode($code) { if (0 === (int) $code) { return ''; } $levels = array( \E_ALL => 'E_ALL', \E_USER_DEPRECATED => 'E_USER_DEPRECATED', \E_DEPRECATED => 'E_DEPRECATED', \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', \E_STRICT => 'E_STRICT', \E_USER_NOTICE => 'E_USER_NOTICE', \E_USER_WARNING => 'E_USER_WARNING', \E_USER_ERROR => 'E_USER_ERROR', \E_COMPILE_WARNING => 'E_COMPILE_WARNING', \E_COMPILE_ERROR => 'E_COMPILE_ERROR', \E_CORE_WARNING => 'E_CORE_WARNING', \E_CORE_ERROR => 'E_CORE_ERROR', \E_NOTICE => 'E_NOTICE', \E_PARSE => 'E_PARSE', \E_WARNING => 'E_WARNING', \E_ERROR => 'E_ERROR', ); $result = ''; foreach ($levels as $number => $name) { if (($code & $number) === $number) { $result .= ('' !== $result ? ', ' : '') . $name; } } return $result; } public static function isWin() { return \PHP_OS === 'WINNT'; } } namespace InnStudio\Prober\Components\Utils; final class UtilsNetwork { public static function getStats() { $filePath = '/proc/net/dev'; if ( ! @is_readable($filePath)) { return; } static $eths = null; if (null !== $eths) { return $eths; } $lines = file($filePath); unset($lines[0], $lines[1]); $eths = array(); foreach ($lines as $line) { $line = preg_replace('/\\s+/', ' ', trim($line)); $lineArr = explode(':', $line); $numberArr = explode(' ', trim($lineArr[1])); $rx = (float) $numberArr[0]; $tx = (float) $numberArr[8]; if ( ! $rx && ! $tx) { continue; } $eths[] = array( 'id' => $lineArr[0], 'rx' => $rx, 'tx' => $tx, ); } return $eths; } } namespace InnStudio\Prober\Components\Utils; final class UtilsServerIp { public static function getV4() { return self::getV4ViaInnStudioCom() ?: self::getV4ViaIpv6TestCom() ?: self::getV4Local(); } public static function getV6() { return self::getV6ViaInnStudioCom() ?: self::getV6ViaIpv6TestCom() ?: self::getV6Local(); } private static function getV4Local() { $content = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : ''; return filter_var($content, \FILTER_VALIDATE_IP, array( 'flags' => \FILTER_FLAG_IPV4, )) ?: ''; } private static function getV6Local() { $content = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : ''; return filter_var($content, \FILTER_VALIDATE_IP, array( 'flags' => \FILTER_FLAG_IPV6, )) ?: ''; } private static function getV4ViaInnStudioCom() { return self::getContent('https://ipv4.inn-studio.com/ip/', 4); } private static function getV6ViaInnStudioCom() { return self::getContent('https://ipv6.inn-studio.com/ip/', 6); } private static function getV4ViaIpv6TestCom() { return self::getContent('https://v4.ipv6-test.com/api/myip.php', 4); } private static function getV6ViaIpv6TestCom() { return self::getContent('https://v6.ipv6-test.com/api/myip.php', 6); } private static function getContent($url, $type) { $content = ''; if (\function_exists('curl_init')) { $ch = curl_init(); curl_setopt_array($ch, array( \CURLOPT_URL => $url, \CURLOPT_RETURNTRANSFER => true, )); $content = curl_exec($ch); curl_close($ch); } else { $content = file_get_contents($url); } return (string) filter_var($content, \FILTER_VALIDATE_IP, array( 'flags' => 6 === $type ? \FILTER_FLAG_IPV6 : \FILTER_FLAG_IPV4, )) ?: ''; } } namespace InnStudio\Prober\Components\Utils; use COM; final class UtilsCpu { public static function getLoadAvg() { if (UtilsApi::isWin()) { return array(0, 0, 0); } return array_map(function ($load) { return (float) sprintf('%.2f', $load); }, sys_getloadavg()); } public static function getModel() { $filePath = '/proc/cpuinfo'; if ( ! @is_readable($filePath)) { return ''; } $content = file_get_contents($filePath); $cores = substr_count($content, 'cache size'); $lines = explode("\n", $content); $modelName = explode(':', $lines[4]); $modelName = trim($modelName[1]); $cacheSize = explode(':', $lines[8]); $cacheSize = trim($cacheSize[1]); return "{$cores} x {$modelName} / " . sprintf('%s cache', $cacheSize); } public static function getWinUsage() { $usage = array( 'idle' => 100, 'user' => 0, 'sys' => 0, 'nice' => 0, ); if (class_exists('COM')) { $wmi = new COM('Winmgmts://'); $server = $wmi->execquery('SELECT LoadPercentage FROM Win32_Processor'); $total = 0; foreach ($server as $cpu) { $total += (int) $cpu->loadpercentage; } $total = (float) $total / \count($server); $usage['idle'] = 100 - $total; $usage['user'] = $total; } else { if ( ! \function_exists('exec')) { return $usage; } $p = array(); exec('wmic cpu get LoadPercentage', $p); if (isset($p[1])) { $percent = (int) $p[1]; $usage['idle'] = 100 - $percent; $usage['user'] = $percent; } } return $usage; } public static function getUsage() { static $cpu = null; if (null !== $cpu) { return $cpu; } if (UtilsApi::isWin()) { $cpu = self::getWinUsage(); return $cpu; } $filePath = '/proc/stat'; if ( ! @is_readable($filePath)) { $cpu = array(); return array( 'user' => 0, 'nice' => 0, 'sys' => 0, 'idle' => 100, ); } $stat1 = file($filePath); sleep(1); $stat2 = file($filePath); $info1 = explode(' ', preg_replace('!cpu +!', '', $stat1[0])); $info2 = explode(' ', preg_replace('!cpu +!', '', $stat2[0])); $dif = array(); $dif['user'] = $info2[0] - $info1[0]; $dif['nice'] = $info2[1] - $info1[1]; $dif['sys'] = $info2[2] - $info1[2]; $dif['idle'] = $info2[3] - $info1[3]; $total = array_sum($dif); $cpu = array(); foreach ($dif as $x => $y) { $cpu[$x] = round($y / $total * 100, 1); } return $cpu; } } namespace InnStudio\Prober\Components\ServerBenchmark; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Conf extends ServerBenchmarkConstants { public function __construct() { EventsApi::on('conf', function (array $conf) { $conf[$this->ID] = array( 'disabledMyServerBenchmark' => XconfigApi::isDisabled('myServerBenchmark'), ); return $conf; }); } } namespace InnStudio\Prober\Components\ServerBenchmark; use InnStudio\Prober\Components\Events\EventsApi; use InnStudio\Prober\Components\Rest\RestResponse; use InnStudio\Prober\Components\Rest\StatusCode; use InnStudio\Prober\Components\Xconfig\XconfigApi; final class Init extends ServerBenchmarkApi { public function __construct() { EventsApi::on('init', function ($action) { if (XconfigApi::isDisabled('myServerBenchmark')) { return $action; } if ('benchmark' !== $action) { return $action; } $this->render(); }); } private function render() { $remainingSeconds = $this->getRemainingSeconds(); $response = new RestResponse(); if ($remainingSeconds) { $response->setStatus(StatusCode::$TOO_MANY_REQUESTS); $response->setData(array( 'seconds' => $remainingSeconds, ))->json()->end(); } set_time_limit(0); $this->setExpired(); $this->setIsRunning(true); $marks = $this->getPoints(); $this->setIsRunning(false); $response->setData(array( 'marks' => $marks, ))->json()->end(); } } namespace InnStudio\Prober\Components\ServerBenchmark; final class ServerBenchmark { public function __construct() { new Init(); new Conf(); new FetchBefore(); } } namespace InnStudio\Prober\Components\ServerBenchmark; use InnStudio\Prober\Components\Events\EventsApi; final class FetchBefore extends ServerBenchmarkApi { public function __construct() { EventsApi::on('fetchBefore', array($this, 'filter')); EventsApi::on('fetchNodesBefore', array($this, 'filter')); EventsApi::on('fetchNodeBefore', array($this, 'filter')); } public function filter() { while ($this->isRunning()) { sleep(2); } } } namespace InnStudio\Prober\Components\ServerBenchmark; class ServerBenchmarkApi { private $EXPIRED = 60; public function getTmpRecorderPath() { return sys_get_temp_dir() . \DIRECTORY_SEPARATOR . 'xproberBenchmarkTimer'; } public function setRecorder(array $data) { return (bool) file_put_contents($this->getTmpRecorderPath(), json_encode(array_merge($this->getRecorder(), $data))); } public function setExpired() { return (bool) $this->setRecorder(array( 'expired' => (int) $_SERVER['REQUEST_TIME'] + $this->EXPIRED, )); } public function setIsRunning($isRunning) { return (bool) $this->setRecorder(array( 'isRunning' => true === (bool) $isRunning ? 1 : 0, )); } public function isRunning() { $recorder = $this->getRecorder(); return isset($recorder['isRunning']) ? 1 === (int) $recorder['isRunning'] : false; } public function getRemainingSeconds() { $recorder = $this->getRecorder(); $expired = isset($recorder['expired']) ? (int) $recorder['expired'] : 0; if ( ! $expired) { return 0; } return $expired > (int) $_SERVER['REQUEST_TIME'] ? $expired - (int) $_SERVER['REQUEST_TIME'] : 0; } public function getPointsByTime($time) { return pow(10, 3) - (int) ($time * pow(10, 3)); } public function getCpuPoints() { $data = 'inn-studio.com'; $hash = array('md5', 'sha512', 'sha256', 'crc32'); $start = microtime(true); $i = 0; while (microtime(true) - $start < .5) { foreach ($hash as $v) { hash($v, $data); } ++$i; } return $i; } public function getWritePoints() { $tmpDir = sys_get_temp_dir(); if ( ! is_writable($tmpDir)) { return 0; } $i = 0; $start = microtime(true); while (microtime(true) - $start < .5) { $filePath = "{$tmpDir}/innStudioWriteBenchmark:{$i}"; clearstatcache(true, $filePath); file_put_contents($filePath, $filePath); unlink($filePath); ++$i; } return $i; } public function getReadPoints() { $tmpDir = sys_get_temp_dir(); if ( ! is_readable($tmpDir)) { return 0; } $i = 0; $start = microtime(true); $filePath = "{$tmpDir}/innStudioIoBenchmark"; if ( ! file_exists($filePath)) { file_put_contents($filePath, 'innStudioReadBenchmark'); } while (microtime(true) - $start < .5) { clearstatcache(true, $filePath); file_get_contents($filePath); ++$i; } return $i; } public function getPoints() { return array( 'cpu' => $this->getMedian(array( $this->getCpuPoints(), $this->getCpuPoints(), $this->getCpuPoints(), )), 'write' => $this->getMedian(array( $this->getWritePoints(), $this->getWritePoints(), $this->getWritePoints(), )), 'read' => $this->getMedian(array( $this->getReadPoints(), $this->getReadPoints(), $this->getReadPoints(), )), ); } private function getRecorder() { $path = $this->getTmpRecorderPath(); $defaults = array( 'expired' => 0, 'running' => 0, ); if ( ! @is_readable($path)) { return $defaults; } $data = (string) file_get_contents($path); if ( ! $data) { return $defaults; } $data = json_decode($data, true); if ( ! $data) { return $defaults; } return array_merge($defaults, $data); } private function getMedian(array $arr) { $count = \count($arr); sort($arr); $mid = floor(($count - 1) / 2); return ($arr[$mid] + $arr[$mid + 1 - $count % 2]) / 2; } } namespace InnStudio\Prober\Components\ServerBenchmark; class ServerBenchmarkConstants { protected $ID = 'serverBenchmark'; } namespace InnStudio\Prober\Components\Rest; final class RestResponse { private $data; private $headers = array(); private $status = 200; public function __construct(array $data = null, $status = 200, array $headers = array()) { $this->setData($data); $this->setStatus($status); $this->setHeaders($headers); } public function setHeader($key, $value, $replace = true) { if ($replace || ! isset($this->headers[$key])) { $this->headers[$key] = $value; } else { $this->headers[$key] .= ", {$value}"; } } public function setHeaders(array $headers) { $this->headers = $headers; } public function getHeaders() { return $this->headers; } public function setStatus($status) { $this->status = $status; return $this; } public function getStatus() { return $this->status; } public function setData($data) { $this->data = $data; return $this; } public function getData() { return $this->data; } public function json() { $this->httpResponseCode($this->status); header('Content-Type: application/json'); header('Expires: 0'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Pragma: no-cache'); echo $this->toJson(); return $this; } public function end() { exit; } private function toJson() { $data = $this->getData(); if (null === $data) { return ''; } return json_encode($data); } private function httpResponseCode($code) { if (\function_exists('http_response_code')) { return http_response_code($code); } $statusCode = array( 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => '(Unused)', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 418 => "I'm a teapot", 419 => 'Authentication Timeout', 420 => 'Enhance Your Calm', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 424 => 'Method Failure', 425 => 'Unordered Collection', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 444 => 'No Response', 449 => 'Retry With', 450 => 'Blocked by Windows Parental Controls', 451 => 'Unavailable For Legal Reasons', 494 => 'Request Header Too Large', 495 => 'Cert Error', 496 => 'No Cert', 497 => 'HTTP to HTTPS', 499 => 'Client Closed Request', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 509 => 'Bandwidth Limit Exceeded', 510 => 'Not Extended', 511 => 'Network Authentication Required', 598 => 'Network read timeout error', 599 => 'Network connect timeout error', ); $msg = isset($statusCode[$code]) ? $statusCode[$code] : 'Unknow error'; $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0'); header("{$protocol} {$code} {$msg}"); } } namespace InnStudio\Prober\Components\Rest; final class StatusCode { public static $__default = 200; public static $CONTINUE = 100; public static $SWITCHING_PROTOCOLS = 101; public static $PROCESSING = 102; public static $OK = 200; public static $CREATED = 201; public static $ACCEPTED = 202; public static $NON_AUTHORITATIVE_INFORMATION = 203; public static $NO_CONTENT = 204; public static $RESET_CONTENT = 205; public static $PARTIAL_CONTENT = 206; public static $MULTI_STATUS = 207; public static $ALREADY_REPORTED = 208; public static $IM_USED = 226; public static $MULTIPLE_CHOICES = 300; public static $MOVED_PERMANENTLY = 301; public static $FOUND = 302; public static $SEE_OTHER = 303; public static $NOT_MODIFIED = 304; public static $USE_PROXY = 305; public static $SWITCH_PROXY = 306; public static $TEMPORARY_REDIRECT = 307; public static $PERMANENT_REDIRECT = 308; public static $BAD_REQUEST = 400; public static $UNAUTHORIZED = 401; public static $PAYMENT_REQUIRED = 402; public static $FORBIDDEN = 403; public static $NOT_FOUND = 404; public static $METHOD_NOT_ALLOWED = 405; public static $NOT_ACCEPTABLE = 406; public static $PROXY_AUTHENTICATION_REQUIRED = 407; public static $REQUEST_TIMEOUT = 408; public static $CONFLICT = 409; public static $GONE = 410; public static $LENGTH_REQUIRED = 411; public static $PRECONDITION_FAILED = 412; public static $REQUEST_ENTITY_TOO_LARGE = 413; public static $REQUEST_URI_TOO_LONG = 414; public static $UNSUPPORTED_MEDIA_TYPE = 415; public static $REQUESTED_RANGE_NOT_SATISFIABLE = 416; public static $EXPECTATION_FAILED = 417; public static $I_AM_A_TEAPOT = 418; public static $AUTHENTICATION_TIMEOUT = 419; public static $ENHANCE_YOUR_CALM = 420; public static $METHOD_FAILURE = 420; public static $UNPROCESSABLE_ENTITY = 422; public static $LOCKED = 423; public static $FAILED_DEPENDENCY = 424; public static $UNORDERED_COLLECTION = 425; public static $UPGRADE_REQUIRED = 426; public static $PRECONDITION_REQUIRED = 428; public static $TOO_MANY_REQUESTS = 429; public static $REQUEST_HEADER_FIELDS_TOO_LARGE = 431; public static $NO_RESPONSE = 444; public static $RETRY_WITH = 449; public static $BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS = 450; public static $REDIRECT = 451; public static $UNAVAILABLE_FOR_LEGAL_REASONS = 451; public static $REQUEST_HEADER_TOO_LARGE = 494; public static $CERT_ERROR = 495; public static $NO_CERT = 496; public static $HTTP_TO_HTTPS = 497; public static $CLIENT_CLOSED_REQUEST = 499; public static $INTERNAL_SERVER_ERROR = 500; public static $NOT_IMPLEMENTED = 501; public static $BAD_GATEWAY = 502; public static $SERVICE_UNAVAILABLE = 503; public static $GATEWAY_TIMEOUT = 504; public static $HTTP_VERSION_NOT_SUPPORTED = 505; public static $VARIANT_ALSO_NEGOTIATES = 506; public static $INSUFFICIENT_STORAGE = 507; public static $LOOP_DETECTED = 508; public static $BANDWIDTH_LIMIT_EXCEEDED = 509; public static $NOT_EXTENDED = 510; public static $NETWORK_AUTHENTICATION_REQUIRED = 511; public static $NETWORK_READ_TIMEOUT_ERROR = 598; public static $NETWORK_CONNECT_TIMEOUT_ERROR = 599; }new \InnStudio\Prober\Components\Database\Database(); new \InnStudio\Prober\Components\Fetch\Fetch(); new \InnStudio\Prober\Components\Footer\Footer(); new \InnStudio\Prober\Components\MyInfo\MyInfo(); new \InnStudio\Prober\Components\NetworkStats\NetworkStats(); new \InnStudio\Prober\Components\Nodes\Nodes(); new \InnStudio\Prober\Components\PhpExtensions\PhpExtensions(); new \InnStudio\Prober\Components\PhpInfo\PhpInfo(); new \InnStudio\Prober\Components\PhpInfoDetail\PhpInfoDetail(); new \InnStudio\Prober\Components\Ping\Ping(); new \InnStudio\Prober\Components\Script\Script(); new \InnStudio\Prober\Components\ServerBenchmark\ServerBenchmark(); new \InnStudio\Prober\Components\ServerInfo\ServerInfo(); new \InnStudio\Prober\Components\ServerStatus\ServerStatus(); new \InnStudio\Prober\Components\Style\Style(); new \InnStudio\Prober\Components\TemperatureSensor\TemperatureSensor(); new \InnStudio\Prober\Components\Timezone\Timezone(); new \InnStudio\Prober\Components\Updater\Updater(); new \InnStudio\Prober\Components\Bootstrap\Bootstrap(); \ No newline at end of file diff --git a/src/Components/Config/ConfigApi.php b/src/Components/Config/ConfigApi.php index 5deb8bb6..29233976 100644 --- a/src/Components/Config/ConfigApi.php +++ b/src/Components/Config/ConfigApi.php @@ -7,7 +7,7 @@ class ConfigApi { - public static $APP_VERSION = '8.12'; + public static $APP_VERSION = '8.13'; public static $APP_NAME = 'X Prober'; public static $APP_URL = 'https://github.com/kmvan/x-prober'; public static $APP_CONFIG_URLS = array('https://raw.githubusercontent.com/kmvan/x-prober/master/AppConfig.json', 'https://api.inn-studio.com/download/?id=xprober-config');