diff --git a/admin_opcacheinfo.php b/admin_opcacheinfo.php index 27654a44..82c4eb91 100644 --- a/admin_opcacheinfo.php +++ b/admin_opcacheinfo.php @@ -33,9 +33,9 @@ const AREA = 'admin'; require __DIR__ . '/lib/init.php'; use Froxlor\FroxlorLogger; +use Froxlor\UI\HTML; use Froxlor\UI\Panel\UI; use Froxlor\UI\Response; -use Froxlor\UI\HTML; if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_serversettings'] == '1') { if ($_POST['send'] == 'send') { @@ -57,252 +57,30 @@ if ($action == 'reset' && function_exists('opcache_reset') && $userinfo['change_ } } -if (!function_exists('opcache_get_configuration')) { +if (!extension_loaded('Zend OPcache')) { Response::standardError(lng('error.no_opcacheinfo')); } +$ocEnabled = ini_get('opcache.enable'); +if (empty($ocEnabled)) { + Response::standardError(lng('error.inactive_opcacheinfo')); +} + if ($page == 'showinfo' && $userinfo['change_serversettings'] == '1') { $time = time(); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed OPcache info"); - $optimizationLevels = [ - 1 << 0 => 'CSE, STRING construction', - 1 << 1 => 'Constant conversion and jumps', - 1 << 2 => '++, +=, series of jumps', - 1 << 3 => 'INIT_FCALL_BY_NAME -> DO_FCALL', - 1 << 4 => 'CFG based optimization', - 1 << 5 => 'DFA based optimization', - 1 << 6 => 'CALL GRAPH optimization', - 1 << 7 => 'SCCP (constant propagation)', - 1 << 8 => 'TMP VAR usage', - 1 << 9 => 'NOP removal', - 1 << 10 => 'Merge equal constants', - 1 << 11 => 'Adjust used stack', - 1 << 12 => 'Remove unused variables', - 1 << 13 => 'DCE (dead code elimination)', - 1 << 14 => '(unsafe) Collect constants', - 1 << 15 => 'Inline functions' - ]; - - $jitModes = [ - [ - 'flag' => 'CPU-specific optimization', - 'value' => [ - 'Disable CPU-specific optimization', - 'Enable use of AVX, if the CPU supports it' - ] - ], - [ - 'flag' => 'Register allocation', - 'value' => [ - 'Do not perform register allocation', - 'Perform block-local register allocation', - 'Perform global register allocation' - ] - ], - [ - 'flag' => 'Trigger', - 'value' => [ - 'Compile all functions on script load', - 'Compile functions on first execution', - 'Profile functions on first request and compile the hottest functions afterwards', - 'Profile on the fly and compile hot functions', - 'Currently unused', - 'Use tracing JIT. Profile on the fly and compile traces for hot code segments' - ] - ], - [ - 'flag' => 'Optimization level', - 'value' => [ - 'No JIT', - 'Minimal JIT (call standard VM handlers)', - 'Inline VM handlers', - 'Use type inference', - 'Use call graph', - 'Optimize whole script' - ] - ] - ]; - - $jitModeMapping = [ - 'tracing' => 1254, - 'on' => 1254, - 'function' => 1205 - ]; - - $status = opcache_get_status(false); - $config = opcache_get_configuration(); - $missingConfig = array_diff_key(ini_get_all('zend opcache', false), $config['directives']); - if (!empty($missingConfig)) { - $config['directives'] = array_merge($config['directives'], $missingConfig); - } - - $files = []; - if (!empty($status['scripts'])) { - uasort($status['scripts'], static function ($a, $b) { - return $a['hits'] <=> $b['hits']; - }); - foreach ($status['scripts'] as &$file) { - $file['full_path'] = str_replace('\\', '/', $file['full_path']); - $file['readable'] = [ - 'hits' => number_format($file['hits']), - 'memory_consumption' => bsize($file['memory_consumption']) - ]; - } - $files = array_values($status['scripts']); - } - - if ($config['directives']['opcache.file_cache_only'] || !empty($status['file_cache_only'])) { - $overview = false; - } else { - $status['opcache_statistics']['start_time'] = $status['opcache_statistics']['start_time'] ?? time(); - $status['opcache_statistics']['last_restart_time'] = $status['opcache_statistics']['last_restart_time'] ?? time(); - - $overview = array_merge( - $status['memory_usage'], - $status['opcache_statistics'], - [ - 'total_memory' => $config['directives']['opcache.memory_consumption'], - 'used_memory_percentage' => round(100 * ( - ($status['memory_usage']['used_memory'] + $status['memory_usage']['wasted_memory']) - / $config['directives']['opcache.memory_consumption'] - )), - 'hit_rate_percentage' => round($status['opcache_statistics']['opcache_hit_rate']), - 'used_key_percentage' => round(100 * ($status['opcache_statistics']['num_cached_keys'] - / $status['opcache_statistics']['max_cached_keys'] - )), - 'wasted_percentage' => round($status['memory_usage']['current_wasted_percentage'], 2), - 'readable' => [ - 'total_memory' => bsize($config['directives']['opcache.memory_consumption']), - 'used_memory' => bsize($status['memory_usage']['used_memory']), - 'free_memory' => bsize($status['memory_usage']['free_memory']), - 'wasted_memory' => bsize($status['memory_usage']['wasted_memory']), - 'num_cached_scripts' => number_format($status['opcache_statistics']['num_cached_scripts']), - 'hits' => number_format($status['opcache_statistics']['hits']), - 'misses' => number_format($status['opcache_statistics']['misses']), - 'blacklist_miss' => number_format($status['opcache_statistics']['blacklist_misses']), - 'num_cached_keys' => number_format($status['opcache_statistics']['num_cached_keys']), - 'max_cached_keys' => number_format($status['opcache_statistics']['max_cached_keys']), - 'interned' => null, - 'start_time' => (new DateTimeImmutable("@{$status['opcache_statistics']['start_time']}")) - ->setTimezone(new DateTimeZone(date_default_timezone_get())) - ->format('Y-m-d H:i:s'), - 'last_restart_time' => ($status['opcache_statistics']['last_restart_time'] == 0 - ? 'never' - : (new DateTimeImmutable("@{$status['opcache_statistics']['last_restart_time']}")) - ->setTimezone(new DateTimeZone(date_default_timezone_get())) - ->format('Y-m-d H:i:s') - ) - ] - ] - ); - } - - $preload = []; - if (!empty($status['preload_statistics']['scripts'])) { - $preload = $status['preload_statistics']['scripts']; - sort($preload, SORT_STRING); - if ($overview) { - $overview['preload_memory'] = $status['preload_statistics']['memory_consumption']; - $overview['readable']['preload_memory'] = bsize($status['preload_statistics']['memory_consumption']); - } - } - - if (!empty($status['interned_strings_usage'])) { - $overview['readable']['interned'] = [ - 'buffer_size' => bsize($status['interned_strings_usage']['buffer_size']), - 'strings_used_memory' => bsize($status['interned_strings_usage']['used_memory']), - 'strings_free_memory' => bsize($status['interned_strings_usage']['free_memory']), - 'number_of_strings' => number_format($status['interned_strings_usage']['number_of_strings']) - ]; - } - - if ($overview && !empty($status['jit'])) { - $overview['jit_buffer_used_percentage'] = ($status['jit']['buffer_size'] - ? round(100 * (($status['jit']['buffer_size'] - $status['jit']['buffer_free']) / $status['jit']['buffer_size'])) - : 0 - ); - $overview['readable'] = array_merge($overview['readable'], [ - 'jit_buffer_size' => bsize($status['jit']['buffer_size']), - 'jit_buffer_free' => bsize($status['jit']['buffer_free']) - ]); - } - - $directives = []; - ksort($config['directives']); - foreach ($config['directives'] as $k => $v) { - if (in_array($k, ['opcache.max_file_size', 'opcache.memory_consumption', 'opcache.jit_buffer_size']) && $v) { - $v = bsize($v) . " ({$v})"; - } elseif ($k === 'opcache.optimization_level') { - $levels = []; - foreach ($optimizationLevels as $level => $info) { - if ($level & $v) { - $levels[] = "{$info} [{$level}]"; - } - } - $v = $levels ?: 'none'; - } elseif ($k === 'opcache.jit') { - if ($v === '1') { - $v = 'on'; - } - if (isset($jitModeMapping[$v]) || is_numeric($v)) { - $levels = []; - foreach (str_split((string)($jitModeMapping[$v] ?? $v)) as $type => $level) { - $levels[] = "{$level}: {$jitModes[$type]['value'][$level]} ({$jitModes[$type]['flag']})"; - } - $v = [$v, $levels]; - } elseif (empty($v) || strtolower($v) === 'off') { - $v = 'Off'; - } - } - $directives[] = [ - 'k' => $k, - 'v' => $v - ]; - } - - $version = array_merge( - $config['version'], - [ - 'php' => phpversion(), - 'server' => $_SERVER['SERVER_SOFTWARE'] ?: '', - 'host' => (function_exists('gethostname') - ? gethostname() - : (php_uname('n') - ?: (empty($_SERVER['SERVER_NAME']) - ? $_SERVER['HOST_NAME'] - : $_SERVER['SERVER_NAME'] - ) - ) - ) - ] - ); + $opcache = (new \Amnuts\Opcache\Service())->getData(); UI::view('settings/opcacheinfo.html.twig', [ 'opcacheinfo' => [ - 'version' => $version, - 'overview' => $overview, - 'files' => $files, - 'preload' => $preload, - 'directives' => $directives, - 'blacklist' => $config['blacklist'], - 'functions' => get_extension_funcs('Zend OPcache') + 'version' => $opcache['version'], + 'overview' => $opcache['overview'], + 'files' => $opcache['files'], + 'preload' => $opcache['preload'], + 'directives' => $opcache['directives'], + 'blacklist' => $opcache['blacklist'], + 'functions' => $opcache['functions'], ] ]); } - -function bsize($size) -{ - $i = 0; - $val = ['b', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - while (($size / 1024) > 1) { - $size /= 1024; - ++$i; - } - return sprintf( - '%.2f%s%s', - $size, - '', - $val[$i] - ); -} diff --git a/composer.json b/composer.json index aac3c0fd..cbc90494 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,8 @@ "twig/twig": "^3.3", "erusev/parsedown": "^1.7", "symfony/console": "^5.4", - "pear/net_dns2": "^1.5" + "pear/net_dns2": "^1.5", + "amnuts/opcache-gui": "^3.4" }, "require-dev": { "phpunit/phpunit": "^9", diff --git a/composer.lock b/composer.lock index 9cf44dfa..d34f97e9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,70 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2de39e6b85579ce1f0c2f7a16d57ede3", + "content-hash": "9ce9c044d979a2358438b876c3c73561", "packages": [ + { + "name": "amnuts/opcache-gui", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/amnuts/opcache-gui.git", + "reference": "a4af194185bcda734cf3e15e877b217153fffd2b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amnuts/opcache-gui/zipball/a4af194185bcda734cf3e15e877b217153fffd2b", + "reference": "a4af194185bcda734cf3e15e877b217153fffd2b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-zend-opcache": "*", + "php": ">=7.1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amnuts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrew Collington", + "email": "andy@amnuts.com", + "homepage": "https://blog.amnuts.com/", + "role": "Developer" + }, + { + "name": "Contributors", + "homepage": "https://github.com/amnuts/opcache-gui/graphs/contributors" + } + ], + "description": "A clean, effective and responsive interface for Zend OPcache, with real(ish)-time monitoring, filtering and the ability to invalidate files", + "keywords": [ + "Opcache", + "cache", + "gui", + "interface", + "opcodes" + ], + "support": { + "email": "andy@amnuts.com", + "issues": "https://github.com/amnuts/opcache-gui/issues", + "source": "https://github.com/amnuts/opcache-gui/tree/3.4.0" + }, + "funding": [ + { + "url": "https://github.com/amnuts", + "type": "github" + } + ], + "time": "2022-08-02T23:08:34+00:00" + }, { "name": "erusev/parsedown", "version": "1.7.4", diff --git a/lng/de.lng.php b/lng/de.lng.php index ce712eb4..4dfd7818 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -879,6 +879,9 @@ return [ 'moveofcustomerfailed' => 'Das Verschieben des Kunden ist fehlgeschlagen. Alle übrigen Änderungen wurden durchgeführt und gespeichert.

Fehlermeldung: %s', 'domain_import_error' => 'Der folgende Fehler trat beim Importieren der Domains auf: %s', 'fcgidandphpfpmnogoodtogether' => 'FCGID und PHP-FPM können nicht gleichzeitig aktiviert werden.', + 'no_apcuinfo' => 'Keine APCu Cache Informationen verfügbar. APCu scheint nicht installiert zu sein.', + 'no_opcacheinfo' => 'Keine OPCache Informationen verfügbar. OPCache scheint nicht installiert zu sein.', + 'inactive_opcacheinfo' => 'OPCache ist installiert, aber nicht aktiviert.', 'nowildcardwithletsencrypt' => 'Let\'s Encrypt kann mittels ACME Wildcard-Domains nur via DNS validieren, sorry. Bitte den ServerAlias auf WWW setzen oder deaktivieren', 'customized_version' => 'Es scheint als wäre die Froxlor Installation angepasst worden. Kein Support, sorry.', 'autoupdate_0' => 'Unbekannter Fehler', diff --git a/lng/en.lng.php b/lng/en.lng.php index 8994dbc0..a5e84bd5 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -950,7 +950,8 @@ return [ 'domain_import_error' => 'Following error occurred while importing domains: %s', 'fcgidandphpfpmnogoodtogether' => 'FCGID and PHP-FPM cannot be activated at the same time', 'no_apcuinfo' => 'No cache info available. APCu does not appear to be running.', - 'no_opcacheinfo' => 'No cache info available. OPCache does not appear to be running.', + 'no_opcacheinfo' => 'No OPCache info available. OPCache does not appear to be loaded.', + 'inactive_opcacheinfo' => 'OPCache seems to be installed but not activated.', 'nowildcardwithletsencrypt' => 'Let\'s Encrypt cannot handle wildcard-domains using ACME in froxlor (requires dns-challenge), sorry. Please set the ServerAlias to WWW or disable it completely', 'customized_version' => 'It looks like your Froxlor installation has been modified, no support sorry.', 'autoupdate_0' => 'Unknown error',