array( // 'enabled' => true, // 'username' => 'ocp', // 'password' => 'password', // ), // 'test' => true, ); $app = new OCP\App($config); $app->run(); } namespace OCP { class Opcache { protected $extension = ''; protected $iniPrefix = ''; protected $functionPrefix = ''; protected $status; protected $isTest = false; public function __construct() { foreach (array('zend opcache', 'zend optimizer+') as $name) { if (extension_loaded($name)) { $this->extension = $name; switch ($name) { case 'zend opcache': $this->functionPrefix = 'opcache_'; $this->iniPrefix = 'opcache.'; break; case 'zend optimizer+': $this->functionPrefix = 'accelerator_'; $this->iniPrefix = 'zend_optimizerplus.'; break; } break; } } } public function setIsTest($value) { $this->isTest = (bool)$value; return $this; } public function getIniPrefix() { return $this->iniPrefix; } public function getFunctionPrefix() { return $this->functionPrefix; } public function getExtension() { return $this->extension; } public function isAvailable() { return !empty($this->extension); } public function reset() { if ($this->isTest) { return true; } return call_user_func($this->functionPrefix . 'reset'); } public function canRecheck() { return function_exists($this->functionPrefix . 'invalidate'); } public function invalidate($file) { if ($this->isTest) { return true; } return call_user_func($this->functionPrefix . 'invalidate', $file); } public function invalidatePath($path) { $files = array_keys($this->getCachedScripts($path)); foreach ($files as $file) { $this->invalidate($file); } } public function getStatus() { if (empty($this->status)) { $this->status = call_user_func($this->functionPrefix . 'get_status'); } return $this->status; } public function getStatistics() { $status = $this->getStatus(); return $status[$this->functionPrefix . 'statistics']; } public function getCachedScripts($path, $asTree = true) { $status = $this->getStatus(); if (!isset($status['scripts'])) { return array(); } $files = $status['scripts']; $result = array(); if (!empty($path)) { foreach ($files as $file => $info) { if (strpos($file, $path) === 0) { $result[$file] = $info; } } $files = $result; $result = array(); } if (!$asTree) { return $files; } foreach ($files as $file => $info) { $dirs = explode(DIRECTORY_SEPARATOR, rtrim($file, DIRECTORY_SEPARATOR)); $file = array_pop($dirs); $resultPos =& $result; $fullPath = ''; foreach ($dirs as $dir) { $fullPath .= $dir . DIRECTORY_SEPARATOR; if (empty($dir)) { continue; } if (!isset($resultPos[$dir])) { $resultPos[$dir] = array( 'full_path' => $fullPath, 'hits' => $info['hits'], 'memory_consumption' => $info['memory_consumption'], 'last_used' => $info['last_used'], 'last_used_timestamp' => $info['last_used_timestamp'], 'timestamp' => $info['timestamp'], 'directory' => true, 'children' => array(), ); } else { $resultPos[$dir]['hits'] += $info['hits']; $resultPos[$dir]['memory_consumption'] += $info['memory_consumption']; if ($resultPos[$dir]['last_used_timestamp'] < $info['last_used_timestamp']) { $resultPos[$dir]['last_used_timestamp'] = $info['last_used_timestamp']; $resultPos[$dir]['last_used'] = $info['last_used']; } if (empty($resultPos[$dir]['timestamp']) || !empty($info['timestamp']) && $resultPos[$dir]['timestamp'] > $info['timestamp']) { $resultPos[$dir]['timestamp'] = $info['timestamp']; } } $tempRef =& $resultPos[$dir]['children']; unset($resultPos); $resultPos =& $tempRef; unset($tempRef); } $resultPos[$file] = $info; } // return the requested path if (!empty($path)) { $dirs = explode(DIRECTORY_SEPARATOR, rtrim($path, DIRECTORY_SEPARATOR)); foreach ($dirs as $dir) { if (empty($dir)) { continue; } if (!isset($result[$dir])) { $result = array(); break; } else { $result = $result[$dir]['children']; } } } return $result; } public function getConfiguration() { if (function_exists($this->functionPrefix . 'get_configuration')) { return call_user_func($this->functionPrefix . 'get_configuration'); } return false; } public function getAllIni() { return ini_get_all($this->extension); } public function getFunctions() { return get_extension_funcs($this->extension); } } class Url { public function getUrl($urlParts = array(), $absolute = false) { $url = ''; if (empty($urlParts['path'])) { $urlParts['path'] = $_SERVER['PHP_SELF']; } if (!empty($urlParts['query'])) { if (is_array($urlParts['query'])) { $urlParts['query'] = http_build_query($urlParts['query']); } } if ($absolute) { if (!empty($_SERVER['HTTPS'])) { $urlParts['scheme'] = 'https'; } else { $urlParts['scheme'] = 'http'; } if (!empty($_SERVER['HTTP_HOST'])) { $hostParts = explode(':', $_SERVER['HTTP_HOST'], 2); $urlParts['host'] = $hostParts[0]; if (isset($hostParts[1])) { $urlParts['port'] = $hostParts[1]; } } else { $urlParts['host'] = $_SERVER['SERVER_ADDR']; $serverPort = $_SERVER['SERVER_PORT']; if (($urlParts['scheme'] === 'http' && $serverPort != 80) || ($urlParts['scheme' === 'https' && $serverPort != 443])) { $urlParts['port'] = $serverPort; } } $url = $urlParts['scheme'] . '://' . $urlParts['host']; } $url .= $urlParts['path']; if (!empty($urlParts['query'])) { $url .= '?' . $urlParts['query']; } if (!empty($urlParts['fragment'])) { $url .= '#' . $urlParts['fragment']; } return $url; } } abstract class View { protected $time = null; protected $viewParams = array(); protected $urlModel = null; public function getPathDirs($path) { return explode(DIRECTORY_SEPARATOR, rtrim($path, DIRECTORY_SEPARATOR)); } public function getParentDirs($path) { $dirs = $this->getPathDirs($path); } public function getDisplayPercent($value, $total) { if (!$total) { return ''; } $percent = round($value / $total * 100, 1); if ($percent < 1) { return ''; } return $percent . '%'; } public function getFormattedValue($value, $base2 = false, $precision = 0) { $suffix = ''; if ($base2) { $exp = floor(log($value, 2)); if ($exp >= 20) { $exp = 20; $suffix = ' MiB'; } elseif ($exp >= 13) { $exp = 10; $suffix = ' KiB'; } else { $exp = 0; } $value = round($value / pow(2, $exp), $precision) . $suffix; } else { $exp = floor(log($value, 10)); if ($exp >= 6) { $exp = 6; $suffix = ' M'; } elseif ($exp >= 4) { $exp = 3; $suffix = ' k'; } else { $exp = 0; } $value = round($value / pow(10, $exp), $precision) . $suffix; } return $value; } public function escapeHtml($html) { return htmlspecialchars($html, ENT_COMPAT, 'UTF-8'); } public function getTimeSince($since, $short = false, $limit = false) { if ($this->time === null) { $this->time = time(); } $ret = array(); $secs = $this->time - $since; $bit = array( 'year' => $secs / 31556926 % 12, 'week' => $secs / 604800 % 52, 'day' => $secs / 86400 % 7, 'hour' => $secs / 3600 % 24, 'minute' => $secs / 60 % 60, 'second' => $secs % 60, ); foreach ($bit as $k => $v){ if ($short) { $k = $k[0]; } if ($v) { if ($short) { $vk = $v . $k; } else { $vk = $v . ' ' . $k . ($v > 1 ? 's' : ''); } $ret[] = $vk; } } if ($limit) { $ret = array_slice($ret, 0, $limit); } if (!$short && count($ret) > 1) { array_splice($ret, count($ret) - 1, 0, 'and'); } return implode(' ', $ret); } public function getUrl($urlParts = array(), $absolute = false) { if ($this->urlModel === null) { $this->urlModel = new Url(); } return $this->urlModel->getUrl($urlParts, $absolute); } public function getViewUrl($addons = array()) { $params = array_merge($this->viewParams, $addons); return $this->getUrl(array('query' => $params)); } } class Graphs extends View { protected $opcache; public function __construct(Opcache $opcache) { $this->opcache = $opcache; } public function __toString() { $config = $this->opcache->getConfiguration(); $status = $this->opcache->getStatus(); $stats = $this->opcache->getStatistics(); $labelColors = array( 'free' => 'green', 'used' => 'brown', 'wasted' => 'red', 'scripts' => 'brown', 'hits' => 'green', 'misses' => 'brown', 'blacklist' => 'red', 'manual' => 'green', 'keys' => 'brown', 'memory' => 'red', ); $graphs = array( 'memory' => array( '1free' => $status['memory_usage']['free_memory'], '2used' => $status['memory_usage']['used_memory'], '3wasted' => $status['memory_usage']['wasted_memory'], ), 'keys' => array( '0total' => isset($stats['max_cached_keys']) ? $stats['max_cached_keys'] : $stats['max_cached_scripts'], '2scripts' => $stats['num_cached_scripts'], ), 'hits' => array( '1hits' => $stats['hits'], '2misses' => $stats['misses'], '3blacklist' => $stats['blacklist_misses'], ), ); $graphs['hits']['0total'] = array_sum($graphs['hits']); if (!empty($config)) { $graphs['memory']['0total'] = $config['directives'][$this->opcache->getIniPrefix() . 'memory_consumption']; } else { $graphs['memory']['0total'] = array_sum($graphs['memory']); } if (isset($stats['num_cached_keys'])) { $graphs['keys']['1free'] = $graphs['keys']['0total'] - $stats['num_cached_keys']; $graphs['keys']['3wasted'] = $stats['num_cached_keys'] - $graphs['keys']['2scripts']; } else { $graphs['keys']['1free'] = $graphs['keys']['0total'] - $graphs['keys']['2scripts']; } if (isset($stats['manual_restarts'])) { $graphs['restarts'] = array( '1manual' => $stats['manual_restarts'], '2keys' => $stats['hash_restarts'], '3memory' => $stats['oom_restarts'], ); $graphs['restarts']['0total'] = array_sum($graphs['restarts']); } foreach ($graphs as $title => $graph) { ksort($graph); $sortedGraph = array(); foreach ($graph as $label => $value) { if (is_numeric($label[0])) { $label = substr($label, 1); } $sortedGraph[$label] = $value; } $graphs[$title] = $sortedGraph; unset($sortedGraph); } ob_start(); ?>
$graph): ?>

$value): ?> getDisplayPercent($value, $graph['total']); ?>
getFormattedValue($graph['total'], $title == 'memory'); ?> title="">
getFormattedValue($value, $title == 'memory'); ?> title=""> style="height: ">
opcache = $opcache; } public function __toString() { $config = $this->opcache->getConfiguration(); $status = $this->opcache->getStatus(); $stats = $this->opcache->getStatistics(); $funcPrefix = $this->opcache->getFunctionPrefix(); $iniPrefix = $this->opcache->getIniPrefix(); ob_start(); ?>

General

General Host Information
Host escapeHtml($_SERVER[$hostVar]); break; } } ?>
PHP Version escapeHtml(constant($versionConst) . ' '); } } ?>
OPcache Version escapeHtml($config['version'][$funcPrefix . 'product_name'] . ' ' . $config['version']['version']) ?>
Opcode Caching
Optimization
Uptime getTimeSince($stats[$uptimeVar]); break; } } ?>
opcache = $opcache; } public function __toString() { $config = $this->opcache->getConfiguration(); $status = $this->opcache->getStatus(); $stats = $this->opcache->getStatistics(); ob_start(); ?>

Memory

$value): ?>
OPcache Memory Utilization
Cache Full
getFormattedValue($value, true, 1); } else { echo round($value, 1); } ?>
$value): ?>
OPcache Interned Strings Utilization
getFormattedValue($value, true, 1); } else { $fValue = round($value, 1); } ?> title="">

Statistics

$value): ?>
Raw OPcache Statistics Data
escapeHtml($title) ?> escapeHtml($value) ?>
opcache = $opcache; } public function __toString() { $config = $this->opcache->getConfiguration(); $ini = $this->opcache->getAllIni(); $iniPrefix = $this->opcache->getIniPrefix(); $directives = array(); if ($config) { $directives = $config['directives']; $opLevel = $directives[$iniPrefix . 'optimization_level']; } else { $opLevel = intval($ini[$iniPrefix . 'optimization_level']['local_value'], 0); } $functions = $this->opcache->getFunctions(); ob_start(); ?>

Blacklist Entries

opcache = $opcache; $this->viewParams = $viewParams; $this->treeView = $treeView; } protected function getParentPath($path) { $dirs = $this->getPathDirs($path); $parentPath = ''; if (empty($dirs[0])) { $parentPath = DIRECTORY_SEPARATOR; array_shift($dirs); } $dirDepth = count($dirs); if ($dirDepth) { if ($dirDepth > 1) { array_pop($dirs); return $parentPath . implode(DIRECTORY_SEPARATOR, $dirs) . DIRECTORY_SEPARATOR; } else { return null; } } return false; } protected function getPathHtml($path) { $dirs = $this->getPathDirs($path); $parentPath = ''; if (!empty($dirs[0])) { $root = 'Computer'; } else { $root = $parentPath = DIRECTORY_SEPARATOR; array_shift($dirs); } $count = count($dirs); if (!$count) { return ''; } ob_start(); ?> Current Path: $dir): ?>escapeHtml($dir) ?> viewParams['p'])) { $path = $this->viewParams['p']; $parent = $this->getParentPath($path); } $files = $this->opcache->getCachedScripts($path, $this->treeView); ob_start(); ?>

treeView ? ' class="active"' : '' ?>>Tree View / treeView ? '' : ' class="active"' ?>>List View

Cached Scripts

getPathHtml($path) ?> $info): ?>
Path Size Hits Last Used Created
..
opcache->canRecheck()): ?>
treeView && isset($info['directory']) && $info['directory']; if ($isDir): ?> escapeHtml($file) ?>
getFormattedValue($info['memory_consumption'], true) ?> getTimeSince($info['last_used_timestamp'], true); if ($ago) { echo $ago; } else { echo 'now'; } ?> getTimeSince($info['timestamp'], true) : '' ?>
opcache = $opcache; $this->view = $view; $this->viewParams = $viewParams; } public function addMessage($msg) { $this->messages[] = $msg; return $this; } public function addContent($content) { $this->content[] = $content; } public function getTitle($withSuffix = false) { $title = $this->title; if ($withSuffix) { $title .= ' - OPcache Control Panel'; } return $title; } public function setTitle($title) { $this->title = $title; return $this; } public function __toString() { ob_start() ?> <?php echo $this->getTitle(true) ?>
messages as $msg): ?>
escapeHtml($msg) ?>

getTitle() ?>

content as $content) { echo $content; } ?>
'The OPcache has been successfully reset.', 'ERROR_INVALID_VERSION' => 'Sorry, this function requires a newer version of OPcache.', 'SUCCESS_RECHECK' => 'The OPcache has been successfully invalidated.', 'SUCCESS_RECHECK_PATH' => 'The requested path has successfully been invalidated in the OPcache', ); protected $views = array( 'GRAPHS', 'ALL', 'FILES', ); protected $view = ''; protected $opcache; protected $status; protected $authOptions = array( 'enabled' => false, 'username' => 'ocp', 'password' => self::DEFAULT_PASSWORD, 'realm' => 'OCP Login', ); public function __construct($config = array()) { $this->opcache = new Opcache(); if (isset($config['test'])) { $this->opcache->setIsTest($config['test']); } if (isset($config['auth']) && is_array($config['auth'])) { $this->authOptions = array_merge($this->authOptions, $config['auth']); } } protected function route() { if (!$this->opcache->isAvailable()) { $this->view = 'UNAVAILABLE'; } elseif (!empty($_GET['view']) && in_array($_GET['view'], $this->views)) { $this->view = $_GET['view']; } } public function getViewParams() { $params = array(); if ($this->view) { $params['view'] = $this->view; switch ($this->view) { case 'FILES': if (isset($_GET['p'])) { $params['p'] = $_GET['p']; } if (isset($_GET['md'])) { $params['md'] = $_GET['md']; } break; } } return $params; } protected function postRedirectGet($urlParts) { $urlModel = new Url(); if ($_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1') { $url = $urlModel->getUrl($urlParts, true); header("Location: ${url}", true, 303); } else { $url = $urlModel->getUrl($urlParts); header("Location: ${url}", true, 302); } } protected function preDispatch() { $msgs = array(); if ($this->authOptions['enabled']) { if ($this->authOptions['password'] !== self::DEFAULT_PASSWORD) { $user = $pass = ''; if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { $user = $_SERVER['PHP_AUTH_USER']; $pass = $_SERVER['PHP_AUTH_PW']; } elseif (!empty($_SERVER['HTTP_AUTHORIZATION'])) { $auth = $_SERVER['HTTP_AUTHORIZATION']; list($user, $pass) = explode(':', base64_decode(substr($auth, strpos($auth, " ") + 1))); } elseif (!empty($_SERVER['Authorization'])) { $auth = $_SERVER['Authorization']; list($user, $pass) = explode(':', base64_decode(substr($auth, strpos($auth, " ") + 1))); } if (!$user || !$pass || $user !== $this->authOptions['username'] || $pass !== $this->authOptions['password']) { header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Basic realm="' . $this->authOptions['realm'] . '"'); echo '

401 Unauthorized

Wrong username or password.

'; exit; } } else { header('HTTP/1.1 500 Application Configuration Error'); echo '

Application Configuration Error

Use a non-default password.

'; exit; } } if (!empty($_POST['action'])) { switch ($_POST['action']) { case 'RESET': $this->opcache->reset(); $msgs[] = 'SUCCESS_RESET'; break; case 'RECHECK': if ($this->opcache->canRecheck()) { $recheck = false; if (!empty($_POST['rp'])) { $recheck = $_POST['rp']; } $this->opcache->invalidatePath($recheck); if ($recheck) { $msgs[] = 'SUCCESS_RECHECK_PATH'; } else { $msgs[] = 'SUCCESS_RECHECK'; } } else { $msgs[] = 'INVALID_VERSION'; } break; } $params = array(); if (!empty($msgs)) { $params['m'] = $msgs; } $params = array_merge($this->getViewParams(), $params); $this->postRedirectGet(array('query' => $params)); exit; } } protected function loadMessages(Page $page) { if (!empty($_GET['m'])) { foreach ($_GET['m'] as $msg) { if (isset($this->msgs[$msg])) { $page->addMessage($this->msgs[$msg]); } } } } protected function indexAction() { $page = new Page($this->opcache, $this->view, $this->getViewParams()); $this->loadMessages($page); $page->setTitle('Statistics/Configuration'); $page->addContent(new Graphs($this->opcache)); if ($this->view == 'GRAPHS') { echo $page; return; } $page->addContent(new Info($this->opcache)); if ($this->view == '') { echo $page; return; } $page->setTitle($page->getTitle() . ' (Full)'); $page->addContent(new Stats($this->opcache)); $page->addContent(new Config($this->opcache)); echo $page; } protected function filesAction() { $treeView = true; $path = isset($_GET['p']) ? $_GET['p'] : ''; if (isset($_GET['md']) && $_GET['md'] == 'list') { $treeView = false; } if (isset($_GET['format']) && $_GET['format'] == 'json') { header('Content-Type: application/json'); echo json_encode($this->opcache->getCachedScripts($path, $treeView)); return; } $viewParams = $this->getViewParams(); $page = new Page($this->opcache, $this->view, $viewParams); $this->loadMessages($page); $page->setTitle('Cached Scripts'); $page->addContent(new Files($this->opcache, $viewParams, $treeView)); echo $page; } protected function invalidAction() { $page = new Page($this->opcache, $this->view, $this->getViewParams()); $page->setTitle('OPcache not detected'); echo $page; } public function dispatch() { switch ($this->view) { case '': case 'GRAPHS': case 'ALL': $this->indexAction(); break; case 'FILES': $this->filesAction(); break; default: $this->invalidAction(); } } public function run() { // weak block against indirect access if (count(get_included_files())>1 || php_sapi_name()=='cli' || empty($_SERVER['REMOTE_ADDR'])) { die; } $this->route(); $this->preDispatch(); $this->dispatch(); } } }