index.php 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297
  1. <?php
  2. namespace OpcacheGui;
  3. /**
  4. * OPcache GUI
  5. *
  6. * A simple but effective single-file GUI for the OPcache PHP extension.
  7. *
  8. * @author Andrew Collington, andy@amnuts.com
  9. * @version 2.4.0
  10. * @link https://github.com/amnuts/opcache-gui
  11. * @license MIT, http://acollington.mit-license.org/
  12. */
  13. /*
  14. * User configuration
  15. */
  16. $options = [
  17. 'allow_filelist' => true, // show/hide the files tab
  18. 'allow_invalidate' => true, // give a link to invalidate files
  19. 'allow_reset' => true, // give option to reset the whole cache
  20. 'allow_realtime' => true, // give option to enable/disable real-time updates
  21. 'refresh_time' => 5, // how often the data will refresh, in seconds
  22. 'size_precision' => 2, // Digits after decimal point
  23. 'size_space' => false, // have '1MB' or '1 MB' when showing sizes
  24. 'charts' => true, // show gauge chart or just big numbers
  25. 'debounce_rate' => 250, // milliseconds after key press to send keyup event when filtering
  26. 'cookie_name' => 'opcachegui', // name of cookie
  27. 'cookie_ttl' => 365 // days to store cookie
  28. ];
  29. /*
  30. * Shouldn't need to alter anything else below here
  31. */
  32. if (!extension_loaded('Zend OPcache')) {
  33. die('The Zend OPcache extension does not appear to be installed');
  34. }
  35. $ocEnabled = ini_get('opcache.enable');
  36. if (empty($ocEnabled)) {
  37. die('The Zend OPcache extension is installed but not turned on');
  38. }
  39. class OpCacheService
  40. {
  41. protected $data;
  42. protected $options;
  43. protected $defaults = [
  44. 'allow_filelist' => true,
  45. 'allow_invalidate' => true,
  46. 'allow_reset' => true,
  47. 'allow_realtime' => true,
  48. 'refresh_time' => 5,
  49. 'size_precision' => 2,
  50. 'size_space' => false,
  51. 'charts' => true,
  52. 'debounce_rate' => 250,
  53. 'cookie_name' => 'opcachegui',
  54. 'cookie_ttl' => 365
  55. ];
  56. private function __construct($options = [])
  57. {
  58. $this->options = array_merge($this->defaults, $options);
  59. $this->data = $this->compileState();
  60. }
  61. public static function init($options = [])
  62. {
  63. $self = new self($options);
  64. if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])
  65. && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'
  66. ) {
  67. if (isset($_GET['reset']) && $self->getOption('allow_reset')) {
  68. echo '{ "success": "' . ($self->resetCache() ? 'yes' : 'no') . '" }';
  69. } else if (isset($_GET['invalidate']) && $self->getOption('allow_invalidate')) {
  70. echo '{ "success": "' . ($self->resetCache($_GET['invalidate']) ? 'yes' : 'no') . '" }';
  71. } else {
  72. echo json_encode($self->getData((empty($_GET['section']) ? null : $_GET['section'])));
  73. }
  74. exit;
  75. } else if (isset($_GET['reset']) && $self->getOption('allow_reset')) {
  76. $self->resetCache();
  77. header('Location: ?');
  78. exit;
  79. } else if (isset($_GET['invalidate']) && $self->getOption('allow_invalidate')) {
  80. $self->resetCache($_GET['invalidate']);
  81. header('Location: ?');
  82. exit;
  83. }
  84. return $self;
  85. }
  86. public function getOption($name = null)
  87. {
  88. if ($name === null) {
  89. return $this->options;
  90. }
  91. return (isset($this->options[$name])
  92. ? $this->options[$name]
  93. : null
  94. );
  95. }
  96. public function getData($section = null, $property = null)
  97. {
  98. if ($section === null) {
  99. return $this->data;
  100. }
  101. $section = strtolower($section);
  102. if (isset($this->data[$section])) {
  103. if ($property === null || !isset($this->data[$section][$property])) {
  104. return $this->data[$section];
  105. }
  106. return $this->data[$section][$property];
  107. }
  108. return null;
  109. }
  110. public function canInvalidate()
  111. {
  112. return ($this->getOption('allow_invalidate') && function_exists('opcache_invalidate'));
  113. }
  114. public function resetCache($file = null)
  115. {
  116. $success = false;
  117. if ($file === null) {
  118. $success = opcache_reset();
  119. } else if (function_exists('opcache_invalidate')) {
  120. $success = opcache_invalidate(urldecode($file), true);
  121. }
  122. if ($success) {
  123. $this->compileState();
  124. }
  125. return $success;
  126. }
  127. protected function size($size)
  128. {
  129. $i = 0;
  130. $val = array('b', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
  131. while (($size / 1024) > 1) {
  132. $size /= 1024;
  133. ++$i;
  134. }
  135. return sprintf('%.'.$this->getOption('size_precision').'f%s%s',
  136. $size, ($this->getOption('size_space') ? ' ' : ''), $val[$i]
  137. );
  138. }
  139. protected function compileState()
  140. {
  141. $status = opcache_get_status();
  142. $config = opcache_get_configuration();
  143. $missingConfig = array_diff_key(ini_get_all('zend opcache', false), $config['directives']);
  144. if (!empty($missingConfig)) {
  145. $config['directives'] = array_merge($config['directives'], $missingConfig);
  146. }
  147. $files = [];
  148. if (!empty($status['scripts']) && $this->getOption('allow_filelist')) {
  149. uasort($status['scripts'], function($a, $b) {
  150. return $a['hits'] < $b['hits'];
  151. });
  152. foreach ($status['scripts'] as &$file) {
  153. $file['full_path'] = str_replace('\\', '/', $file['full_path']);
  154. $file['readable'] = [
  155. 'hits' => number_format($file['hits']),
  156. 'memory_consumption' => $this->size($file['memory_consumption'])
  157. ];
  158. }
  159. $files = array_values($status['scripts']);
  160. }
  161. if ($config['directives']['opcache.file_cache_only']) {
  162. $overview = false;
  163. } else {
  164. $overview = array_merge(
  165. $status['memory_usage'], $status['opcache_statistics'], [
  166. 'used_memory_percentage' => round(100 * (
  167. ($status['memory_usage']['used_memory'] + $status['memory_usage']['wasted_memory'])
  168. / $config['directives']['opcache.memory_consumption'])),
  169. 'hit_rate_percentage' => round($status['opcache_statistics']['opcache_hit_rate']),
  170. 'wasted_percentage' => round($status['memory_usage']['current_wasted_percentage'], 2),
  171. 'readable' => [
  172. 'total_memory' => $this->size($config['directives']['opcache.memory_consumption']),
  173. 'used_memory' => $this->size($status['memory_usage']['used_memory']),
  174. 'free_memory' => $this->size($status['memory_usage']['free_memory']),
  175. 'wasted_memory' => $this->size($status['memory_usage']['wasted_memory']),
  176. 'num_cached_scripts' => number_format($status['opcache_statistics']['num_cached_scripts']),
  177. 'hits' => number_format($status['opcache_statistics']['hits']),
  178. 'misses' => number_format($status['opcache_statistics']['misses']),
  179. 'blacklist_miss' => number_format($status['opcache_statistics']['blacklist_misses']),
  180. 'num_cached_keys' => number_format($status['opcache_statistics']['num_cached_keys']),
  181. 'max_cached_keys' => number_format($status['opcache_statistics']['max_cached_keys']),
  182. 'interned' => null,
  183. 'start_time' => date('Y-m-d H:i:s', $status['opcache_statistics']['start_time']),
  184. 'last_restart_time' => ($status['opcache_statistics']['last_restart_time'] == 0
  185. ? 'never'
  186. : date('Y-m-d H:i:s', $status['opcache_statistics']['last_restart_time'])
  187. )
  188. ]
  189. ]
  190. );
  191. }
  192. if (!empty($status['interned_strings_usage'])) {
  193. $overview['readable']['interned'] = [
  194. 'buffer_size' => $this->size($status['interned_strings_usage']['buffer_size']),
  195. 'strings_used_memory' => $this->size($status['interned_strings_usage']['used_memory']),
  196. 'strings_free_memory' => $this->size($status['interned_strings_usage']['free_memory']),
  197. 'number_of_strings' => number_format($status['interned_strings_usage']['number_of_strings'])
  198. ];
  199. }
  200. $directives = [];
  201. ksort($config['directives']);
  202. foreach ($config['directives'] as $k => $v) {
  203. if (in_array($k, ['opcache.max_file_size', 'opcache.memory_consumption']) && $v) {
  204. $v = $this->size($v) . " ({$v})";
  205. }
  206. $directives[] = [
  207. 'k' => $k,
  208. 'v' => $v
  209. ];
  210. }
  211. $version = array_merge(
  212. $config['version'],
  213. [
  214. 'php' => phpversion(),
  215. 'server' => empty($_SERVER['SERVER_SOFTWARE']) ? '' : $_SERVER['SERVER_SOFTWARE'],
  216. 'host' => (function_exists('gethostname')
  217. ? gethostname()
  218. : (php_uname('n')
  219. ?: (empty($_SERVER['SERVER_NAME'])
  220. ? $_SERVER['HOST_NAME']
  221. : $_SERVER['SERVER_NAME']
  222. )
  223. )
  224. )
  225. ]
  226. );
  227. return [
  228. 'version' => $version,
  229. 'overview' => $overview,
  230. 'files' => $files,
  231. 'directives' => $directives,
  232. 'blacklist' => $config['blacklist'],
  233. 'functions' => get_extension_funcs('Zend OPcache')
  234. ];
  235. }
  236. }
  237. $opcache = OpCacheService::init($options);
  238. ?>
  239. <!DOCTYPE html>
  240. <html>
  241. <head>
  242. <meta charset="UTF-8">
  243. <meta name="viewport" content="width=device-width,initial-scale=1.0">
  244. <title>OPcache statistics on <?php echo $opcache->getData('version', 'host'); ?></title>
  245. <script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>
  246. <script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script>
  247. <script src="//cdn.jsdelivr.net/jquery/3.1.1/jquery.min.js"></script>
  248. <style type="text/css">
  249. body { font-family:sans-serif; font-size:90%; padding: 0; margin: 0 }
  250. nav { padding-top: 20px; }
  251. nav > ul { list-style-type: none; padding-left: 8px; margin: 0; border-bottom: 1px solid #ccc; }
  252. nav > ul > li { display: inline-block; padding: 0; margin: 0 0 -1px 0; }
  253. nav > ul > li > a { display: block; margin: 0 10px; padding: 15px 30px; border: 1px solid transparent; border-bottom-color: #ccc; text-decoration: none; }
  254. nav > ul > li > a:hover { background-color: #f4f4f4; text-decoration: underline; }
  255. nav > ul > li > a.active:hover { background-color: initial; }
  256. nav > ul > li > a[data-for].active { border: 1px solid #ccc; border-bottom-color: #ffffff; border-top: 3px solid #6ca6ef; }
  257. table { margin: 0 0 1em 0; border-collapse: collapse; border-color: #fff; width: 100%; table-layout: fixed; }
  258. table caption { text-align: left; font-size: 1.5em; }
  259. table tr { background-color: #99D0DF; border-color: #fff; }
  260. table th { text-align: left; padding: 6px; background-color: #6ca6ef; color: #fff; border-color: #fff; font-weight: normal; }
  261. table td { padding: 4px 6px; line-height: 1.4em; vertical-align: top; border-color: #fff; overflow: hidden; overflow-wrap: break-word; text-overflow: ellipsis;}
  262. table tr:nth-child(odd) { background-color: #EFFEFF; }
  263. table tr:nth-child(even) { background-color: #E0ECEF; }
  264. #filelist table tr { background-color: #EFFEFF; }
  265. #filelist table tr.alternate { background-color: #E0ECEF; }
  266. td.pathname { width: 70%; }
  267. footer { border-top: 1px solid #ccc; padding: 1em 2em; }
  268. footer a { padding: 2em; text-decoration: none; opacity: 0.7; }
  269. footer a:hover { opacity: 1; }
  270. canvas { display: block; max-width: 100%; height: auto; margin: 0 auto; }
  271. #tabs { padding: 2em; }
  272. #tabs > div { display: none; }
  273. #tabs > div#overview { display:block; }
  274. #resetCache, #toggleRealtime, footer > a { background-position: 5px 50%; background-repeat: no-repeat; background-color: transparent; }
  275. footer > a { background-position: 0 50%; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjE2MENCRkExNzVBQjExRTQ5NDBGRTUzMzQyMDVDNzFFIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjE2MENCRkEyNzVBQjExRTQ5NDBGRTUzMzQyMDVDNzFFIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MTYwQ0JGOUY3NUFCMTFFNDk0MEZFNTMzNDIwNUM3MUUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MTYwQ0JGQTA3NUFCMTFFNDk0MEZFNTMzNDIwNUM3MUUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7HtUU1AAABN0lEQVR42qyUvWoCQRSF77hCLLKC+FOlCKTyIbYQUuhbWPkSFnZ2NpabUvANLGyz5CkkYGMlFtFAUmiSM8lZOVkWsgm58K079+fMnTusZl92BXbgDrTtZ2szd8fas/XBOzmBKaiCEFyTkL4pc9L8vgpNJJDyWtDna61EoXpO+xcFfXUVqtrf7Vx7m9Pub/EatvgHoYXD4ylztC14BBVwydvydgDPHPgNaErN3jLKIxAUmEvAXK21I18SJpXBGAxyBAaMlblOWOs1bMXFkMGeBFsi0pJNe/QNuV7563+gs8LfhrRfE6GaHLuRqfnUiKi6lJ034B44EXL0baTTJWujNGkG3kBX5uRyZuRkPl3WzDTBtzjnxxiDDq83yNxUk7GYuXM53jeLuMNavvAXkv4zrJkTaeGHAAMAIal3icPMsyQAAAAASUVORK5CYII='); font-size: 80%; }
  276. #resetCache { background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NjBFMUMyMjI3NDlGMTFFNEE3QzNGNjQ0OEFDQzQ1MkMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NjBFMUMyMjM3NDlGMTFFNEE3QzNGNjQ0OEFDQzQ1MkMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MEUxQzIyMDc0OUYxMUU0QTdDM0Y2NDQ4QUNDNDUyQyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo2MEUxQzIyMTc0OUYxMUU0QTdDM0Y2NDQ4QUNDNDUyQyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PplZ+ZkAAAD1SURBVHjazFPtDYJADIUJZAMZ4UbACWQENjBO4Ao6AW5AnODcADZQJwAnwJ55NbWhB/6zycsdpX39uDZNpsURtjgzwkDoCBecs5ITPGGMwCNAkIrQw+8ri36GhBHsavFdpILEo4wEpZxRigy009EhG760gr0VhFoyZfvJKPwsheIWIeGejBZRIxRVhMRFevbuUXBew/iE/lhlBduV0j8Jx+TvJEWPphq8n5li9utgaw6cW/h6NSt/JcnVBhQxotIgKTBrbNvIHo2G0x1rwlKqTDusxiAz6hHNL1zayTVqVKRKpa/LPljPH1sJh6l/oNSrZfwSYABtq3tFdZA5BAAAAABJRU5ErkJggg=='); }
  277. #toggleRealtime { position: relative; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAUCAYAAACAl21KAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODE5RUU4NUE3NDlGMTFFNDkyMzA4QzY1RjRBQkIzQjUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODE5RUU4NUI3NDlGMTFFNDkyMzA4QzY1RjRBQkIzQjUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4MTlFRTg1ODc0OUYxMUU0OTIzMDhDNjVGNEFCQjNCNSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4MTlFRTg1OTc0OUYxMUU0OTIzMDhDNjVGNEFCQjNCNSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PpXjpvMAAAD2SURBVHjarFQBEcMgDKR3E1AJldA5wMEqAQmTgINqmILdFCChdUAdMAeMcukuSwnQbbnLlZLwJPkQIcrSiT/IGNQHNb8CGQDyRw+2QWUBqC+luzo4OKQZIAVrB+ssyKp3Bkijf0+ijzIh4wQppoBauMSjyDZfMSCDxYZMsfHF120T36AqWZMkgyguQ3GOfottJ5TKnHC+wfeRsC2oDVayPgr3bbN2tHBH3tWuJCPa0JUgKtFzMQrcZH3FNHAc0yOp1cCASALyngoN6lhDopkJWxdifwY9A3u7l29ImpxOFSWIOVsGwHKENIWxss2eBVKdOeeXAAMAk/Z9h4QhXmUAAAAASUVORK5CYII='); }
  278. #counts { width: 270px; float: right; }
  279. #counts > div > div { background-color: #ededed; margin-bottom: 10px; }
  280. #counts > div > div > h3 { background-color: #cdcdcd; padding: 4px 6px; margin: 0; text-align: center; }
  281. #counts > div > div > p { margin: 0; text-align: center; }
  282. #counts > div > div > p span.large + span { font-size: 20pt; margin: 0; color: #6ca6ef; }
  283. #counts > div > div > p span.large { color: #6ca6ef; font-size: 80pt; margin: 0; padding: 0; text-align: center; }
  284. #info { margin-right: 280px; }
  285. #frmFilter { width: 520px; }
  286. #fileCacheOnly { margin-top: 0; }
  287. .moreinfo > div { padding: 10px; }
  288. .moreinfo > div > p { margin: 0; line-height: 1.75em; }
  289. .metainfo { font-size: 80%; }
  290. .hide { display: none; }
  291. #toggleRealtime.pulse::before {
  292. content: ""; position: absolute;
  293. top: 13px; left: 3px; width: 18px; height: 18px;
  294. z-index: 10; opacity: 0; background-color: transparent;
  295. border: 2px solid rgb(255, 116, 0); border-radius: 100%;
  296. -webkit-animation: pulse 1s linear 2;
  297. -moz-animation: pulse 1s linear 2;
  298. animation: pulse 1s linear 2;
  299. }
  300. @media screen and (max-width: 750px) {
  301. #info { margin-right:auto; clear:both; }
  302. nav > ul { border-bottom: 0; }
  303. nav > ul > li { display: block; margin: 0; }
  304. nav > ul > li > a { display: block; margin: 0 10px; padding: 10px 0 10px 30px; border: 0; }
  305. nav > ul > li > a[data-for].active { border-bottom-color: #ccc; }
  306. #counts { position:relative; display:block; width:100%; }
  307. #toggleRealtime.pulse::before { top: 8px; }
  308. }
  309. @media screen and (max-width: 550px) {
  310. #frmFilter { width: 100%; }
  311. }
  312. @keyframes pulse {
  313. 0% {transform: scale(1); opacity: 0;}
  314. 50% {transform: scale(1.3); opacity: 0.7;}
  315. 100% {transform: scale(1.6); opacity: 1;}
  316. }
  317. @-webkit-keyframes pulse {
  318. 0% {-webkit-transform: scale(1); opacity: 0;}
  319. 50% {-webkit-transform: scale(1.3); opacity: 0.7;}
  320. 100% {-webkit-transform: scale(1.6); opacity: 0;}
  321. }
  322. @-moz-keyframes pulse {
  323. 0% {-moz-transform: scale(1); opacity: 0;}
  324. 50% {-moz-transform: scale(1.3); opacity: 0.7;}
  325. 100% {-moz-transform: scale(1.6); opacity: 0;}
  326. }
  327. </style>
  328. </head>
  329. <body>
  330. <header>
  331. <nav>
  332. <ul>
  333. <li><a data-for="overview" href="#overview" class="active">Overview</a></li>
  334. <?php if ($opcache->getOption('allow_filelist')): ?>
  335. <li><a data-for="files" href="#files">File usage</a></li>
  336. <?php endif; ?>
  337. <?php if ($opcache->getOption('allow_reset')): ?>
  338. <li><a href="?reset=1" id="resetCache" onclick="return confirm('Are you sure you want to reset the cache?');">Reset cache</a></li>
  339. <?php endif; ?>
  340. <?php if ($opcache->getOption('allow_realtime')): ?>
  341. <li><a href="#" id="toggleRealtime">Enable real-time update</a></li>
  342. <?php endif; ?>
  343. </ul>
  344. </nav>
  345. </header>
  346. <div id="tabs">
  347. <div id="overview">
  348. <div class="container">
  349. <div id="counts"></div>
  350. <div id="info">
  351. <div id="generalInfo"></div>
  352. <div id="directives"></div>
  353. <div id="functions">
  354. <table>
  355. <thead>
  356. <tr><th>Available functions</th></tr>
  357. </thead>
  358. <tbody>
  359. <?php foreach ($opcache->getData('functions') as $func): ?>
  360. <tr><td><a href="http://php.net/<?php echo $func; ?>" title="View manual page" target="_blank"><?php echo $func; ?></a></td></tr>
  361. <?php endforeach; ?>
  362. </tbody>
  363. </table>
  364. </div>
  365. <br style="clear:both;" />
  366. </div>
  367. </div>
  368. </div>
  369. <div id="files">
  370. <?php if ($opcache->getOption('allow_filelist')): ?>
  371. <form action="#">
  372. <label for="frmFilter">Start typing to filter on script path</label><br>
  373. <input type="text" name="filter" id="frmFilter">
  374. </form>
  375. <?php endif; ?>
  376. <div class="container" id="filelist"></div>
  377. </div>
  378. </div>
  379. <footer>
  380. <a href="https://github.com/amnuts/opcache-gui" target="_blank">https://github.com/amnuts/opcache-gui</a>
  381. </footer>
  382. <script type="text/javascript">
  383. var realtime = false;
  384. var opstate = <?php echo json_encode($opcache->getData()); ?>;
  385. var canInvalidate = <?php echo json_encode($opcache->canInvalidate()); ?>;
  386. var useCharts = <?php echo json_encode($opcache->getOption('charts')); ?>;
  387. var allowFiles = <?php echo json_encode($opcache->getOption('allow_filelist')); ?>;
  388. var debounce = function(func, wait, immediate) {
  389. var timeout;
  390. wait = wait || 250;
  391. return function() {
  392. var context = this, args = arguments;
  393. var later = function() {
  394. timeout = null;
  395. if (!immediate) {
  396. func.apply(context, args);
  397. }
  398. };
  399. var callNow = immediate && !timeout;
  400. clearTimeout(timeout);
  401. timeout = setTimeout(later, wait);
  402. if (callNow) {
  403. func.apply(context, args);
  404. }
  405. };
  406. };
  407. function keyUp(event){
  408. var compare = $('#frmFilter').val().toLowerCase();
  409. $('#filelist').find('table tbody tr').each(function(index){
  410. if ($(this).data('path').indexOf(compare) == -1) {
  411. $(this).addClass('hide');
  412. } else {
  413. $(this).removeClass('hide');
  414. }
  415. });
  416. $('#filelist table tbody').trigger('paint');
  417. };
  418. <?php if ($opcache->getOption('charts')): ?>
  419. var Gauge = function(el, colour) {
  420. this.canvas = $(el).get(0);
  421. this.ctx = this.canvas.getContext('2d');
  422. this.width = this.canvas.width;
  423. this.height = this.canvas.height;
  424. this.colour = colour || '#6ca6ef';
  425. this.loop = null;
  426. this.degrees = 0;
  427. this.newdegs = 0;
  428. this.text = '';
  429. this.init = function() {
  430. this.ctx.clearRect(0, 0, this.width, this.height);
  431. this.ctx.beginPath();
  432. this.ctx.strokeStyle = '#e2e2e2';
  433. this.ctx.lineWidth = 30;
  434. this.ctx.arc(this.width/2, this.height/2, 100, 0, Math.PI*2, false);
  435. this.ctx.stroke();
  436. this.ctx.beginPath();
  437. this.ctx.strokeStyle = this.colour;
  438. this.ctx.lineWidth = 30;
  439. this.ctx.arc(this.width/2, this.height/2, 100, 0 - (90 * Math.PI / 180), (this.degrees * Math.PI / 180) - (90 * Math.PI / 180), false);
  440. this.ctx.stroke();
  441. this.ctx.fillStyle = this.colour;
  442. this.ctx.font = '60px sans-serif';
  443. this.text = Math.round((this.degrees/360)*100) + '%';
  444. this.ctx.fillText(this.text, (this.width/2) - (this.ctx.measureText(this.text).width/2), (this.height/2) + 20);
  445. };
  446. this.draw = function() {
  447. if (typeof this.loop != 'undefined') {
  448. clearInterval(this.loop);
  449. }
  450. var self = this;
  451. self.loop = setInterval(function(){ self.animate(); }, 1000/(this.newdegs - this.degrees));
  452. };
  453. this.animate = function() {
  454. if (this.degrees == this.newdegs) {
  455. clearInterval(this.loop);
  456. }
  457. if (this.degrees < this.newdegs) {
  458. ++this.degrees;
  459. } else {
  460. --this.degrees;
  461. }
  462. this.init();
  463. };
  464. this.setValue = function(val) {
  465. this.newdegs = Math.round(3.6 * val);
  466. this.draw();
  467. };
  468. }
  469. <?php endif; ?>
  470. $(function(){
  471. <?php if ($opcache->getOption('allow_realtime')): ?>
  472. function setCookie() {
  473. var d = new Date();
  474. var secure = (window.location.protocol === 'https:' ? ';secure' : '');
  475. d.setTime(d.getTime() + (<?php echo ($opcache->getOption('cookie_ttl')); ?> * 86400000));
  476. var expires = "expires="+d.toUTCString();
  477. document.cookie = "<?php echo ($opcache->getOption('cookie_name')); ?>=true;" + expires + ";path=/" + secure;
  478. };
  479. function removeCookie() {
  480. var secure = (window.location.protocol === 'https:' ? ';secure' : '');
  481. document.cookie = "<?php echo ($opcache->getOption('cookie_name')); ?>=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/" + secure;
  482. };
  483. function getCookie() {
  484. var v = document.cookie.match('(^|;) ?<?php echo ($opcache->getOption('cookie_name')); ?>=([^;]*)(;|$)');
  485. return v ? v[2] : null;
  486. };
  487. function updateStatus() {
  488. $('#toggleRealtime').removeClass('pulse');
  489. $.ajax({
  490. url: "#",
  491. dataType: "json",
  492. cache: false,
  493. success: function(data) {
  494. $('#toggleRealtime').addClass('pulse');
  495. opstate = data;
  496. overviewCountsObj.setState({
  497. data : opstate.overview
  498. });
  499. generalInfoObj.setState({
  500. version : opstate.version,
  501. start : opstate.overview.readable.start_time,
  502. reset : opstate.overview.readable.last_restart_time
  503. });
  504. filesObj.setState({
  505. data : opstate.files,
  506. count_formatted : opstate.overview.readable.num_cached_scripts,
  507. count : opstate.overview.num_cached_scripts
  508. });
  509. keyUp();
  510. }
  511. });
  512. }
  513. $('#toggleRealtime').click(function(){
  514. if (realtime === false) {
  515. realtime = setInterval(function(){updateStatus()}, <?php echo (int)$opcache->getOption('refresh_time') * 1000; ?>);
  516. $(this).text('Disable real-time update');
  517. setCookie();
  518. } else {
  519. clearInterval(realtime);
  520. realtime = false;
  521. $(this).text('Enable real-time update').removeClass('pulse');
  522. removeCookie();
  523. }
  524. });
  525. if (getCookie() == 'true') {
  526. realtime = setInterval(function(){updateStatus()}, <?php echo (int)$opcache->getOption('refresh_time') * 1000; ?>);
  527. $('#toggleRealtime').text('Disable real-time update');
  528. }
  529. <?php endif; ?>
  530. $('nav a[data-for]').click(function(){
  531. $('#tabs > div').hide();
  532. $('#' + $(this).data('for')).show();
  533. $('nav a[data-for]').removeClass('active');
  534. $(this).addClass('active');
  535. return false;
  536. });
  537. $(document).on('paint', '#filelist table tbody', function(event, params) {
  538. var trs = $('#filelist').find('tbody tr');
  539. trs.removeClass('alternate');
  540. trs.filter(':not(.hide):odd').addClass('alternate');
  541. filesObj.setState({showing: trs.filter(':not(.hide)').length});
  542. });
  543. $('#frmFilter').bind('keyup', debounce(keyUp, <?php echo $opcache->getOption('debounce_rate'); ?>));
  544. });
  545. var MemoryUsageGraph = React.createClass({
  546. getInitialState: function () {
  547. return {
  548. memoryUsageGauge: null
  549. };
  550. },
  551. componentDidMount: function () {
  552. if (this.props.chart) {
  553. this.state.memoryUsageGauge = new Gauge('#memoryUsageCanvas');
  554. this.state.memoryUsageGauge.setValue(this.props.value);
  555. }
  556. },
  557. componentDidUpdate: function () {
  558. if (this.state.memoryUsageGauge != null) {
  559. this.state.memoryUsageGauge.setValue(this.props.value);
  560. }
  561. },
  562. render: function () {
  563. if (this.props.chart == true) {
  564. return React.createElement("canvas", { id: "memoryUsageCanvas", width: "250", height: "250", "data-value": this.props.value });
  565. }
  566. return React.createElement(
  567. "p",
  568. null,
  569. React.createElement(
  570. "span",
  571. { className: "large" },
  572. this.props.value
  573. ),
  574. React.createElement(
  575. "span",
  576. null,
  577. "%"
  578. )
  579. );
  580. }
  581. });
  582. var HitRateGraph = React.createClass({
  583. getInitialState: function () {
  584. return {
  585. hitRateGauge: null
  586. };
  587. },
  588. componentDidMount: function () {
  589. if (this.props.chart) {
  590. this.state.hitRateGauge = new Gauge('#hitRateCanvas');
  591. this.state.hitRateGauge.setValue(this.props.value);
  592. }
  593. },
  594. componentDidUpdate: function () {
  595. if (this.state.hitRateGauge != null) {
  596. this.state.hitRateGauge.setValue(this.props.value);
  597. }
  598. },
  599. render: function () {
  600. if (this.props.chart == true) {
  601. return React.createElement("canvas", { id: "hitRateCanvas", width: "250", height: "250", "data-value": this.props.value });
  602. }
  603. return React.createElement(
  604. "p",
  605. null,
  606. React.createElement(
  607. "span",
  608. { className: "large" },
  609. this.props.value
  610. ),
  611. React.createElement(
  612. "span",
  613. null,
  614. "%"
  615. )
  616. );
  617. }
  618. });
  619. var MemoryUsagePanel = React.createClass({
  620. render: function () {
  621. return React.createElement(
  622. "div",
  623. { className: "moreinfo" },
  624. React.createElement(
  625. "h3",
  626. null,
  627. "memory usage"
  628. ),
  629. React.createElement(
  630. "div",
  631. null,
  632. React.createElement(
  633. "p",
  634. null,
  635. React.createElement(
  636. "b",
  637. null,
  638. "total memory:"
  639. ),
  640. " ",
  641. this.props.total
  642. ),
  643. React.createElement(
  644. "p",
  645. null,
  646. React.createElement(
  647. "b",
  648. null,
  649. "used memory:"
  650. ),
  651. " ",
  652. this.props.used
  653. ),
  654. React.createElement(
  655. "p",
  656. null,
  657. React.createElement(
  658. "b",
  659. null,
  660. "free memory:"
  661. ),
  662. " ",
  663. this.props.free
  664. ),
  665. React.createElement(
  666. "p",
  667. null,
  668. React.createElement(
  669. "b",
  670. null,
  671. "wasted memory:"
  672. ),
  673. " ",
  674. this.props.wasted,
  675. " (",
  676. this.props.wastedPercent,
  677. "%)"
  678. )
  679. )
  680. );
  681. }
  682. });
  683. var StatisticsPanel = React.createClass({
  684. render: function () {
  685. return React.createElement(
  686. "div",
  687. { className: "moreinfo" },
  688. React.createElement(
  689. "h3",
  690. null,
  691. "opcache statistics"
  692. ),
  693. React.createElement(
  694. "div",
  695. null,
  696. React.createElement(
  697. "p",
  698. null,
  699. React.createElement(
  700. "b",
  701. null,
  702. "number of cached files:"
  703. ),
  704. " ",
  705. this.props.num_cached_scripts
  706. ),
  707. React.createElement(
  708. "p",
  709. null,
  710. React.createElement(
  711. "b",
  712. null,
  713. "number of hits:"
  714. ),
  715. " ",
  716. this.props.hits
  717. ),
  718. React.createElement(
  719. "p",
  720. null,
  721. React.createElement(
  722. "b",
  723. null,
  724. "number of misses:"
  725. ),
  726. " ",
  727. this.props.misses
  728. ),
  729. React.createElement(
  730. "p",
  731. null,
  732. React.createElement(
  733. "b",
  734. null,
  735. "blacklist misses:"
  736. ),
  737. " ",
  738. this.props.blacklist_miss
  739. ),
  740. React.createElement(
  741. "p",
  742. null,
  743. React.createElement(
  744. "b",
  745. null,
  746. "number of cached keys:"
  747. ),
  748. " ",
  749. this.props.num_cached_keys
  750. ),
  751. React.createElement(
  752. "p",
  753. null,
  754. React.createElement(
  755. "b",
  756. null,
  757. "max cached keys:"
  758. ),
  759. " ",
  760. this.props.max_cached_keys
  761. )
  762. )
  763. );
  764. }
  765. });
  766. var InternedStringsPanel = React.createClass({
  767. render: function () {
  768. return React.createElement(
  769. "div",
  770. { className: "moreinfo" },
  771. React.createElement(
  772. "h3",
  773. null,
  774. "interned strings usage"
  775. ),
  776. React.createElement(
  777. "div",
  778. null,
  779. React.createElement(
  780. "p",
  781. null,
  782. React.createElement(
  783. "b",
  784. null,
  785. "buffer size:"
  786. ),
  787. " ",
  788. this.props.buffer_size
  789. ),
  790. React.createElement(
  791. "p",
  792. null,
  793. React.createElement(
  794. "b",
  795. null,
  796. "used memory:"
  797. ),
  798. " ",
  799. this.props.strings_used_memory
  800. ),
  801. React.createElement(
  802. "p",
  803. null,
  804. React.createElement(
  805. "b",
  806. null,
  807. "free memory:"
  808. ),
  809. " ",
  810. this.props.strings_free_memory
  811. ),
  812. React.createElement(
  813. "p",
  814. null,
  815. React.createElement(
  816. "b",
  817. null,
  818. "number of strings:"
  819. ),
  820. " ",
  821. this.props.number_of_strings
  822. )
  823. )
  824. );
  825. }
  826. });
  827. var OverviewCounts = React.createClass({
  828. getInitialState: function () {
  829. return {
  830. data: opstate.overview,
  831. chart: useCharts
  832. };
  833. },
  834. render: function () {
  835. if (this.state.data == false) {
  836. return React.createElement(
  837. "p",
  838. { id: "fileCacheOnly" },
  839. "You have ",
  840. React.createElement(
  841. "i",
  842. null,
  843. "opcache.file_cache_only"
  844. ),
  845. " turned on. As a result, the memory information is not available. Statistics and file list may also not be returned by ",
  846. React.createElement(
  847. "i",
  848. null,
  849. "opcache_get_statistics()"
  850. ),
  851. "."
  852. );
  853. }
  854. var interned = this.state.data.readable.interned != null ? React.createElement(InternedStringsPanel, {
  855. buffer_size: this.state.data.readable.interned.buffer_size,
  856. strings_used_memory: this.state.data.readable.interned.strings_used_memory,
  857. strings_free_memory: this.state.data.readable.interned.strings_free_memory,
  858. number_of_strings: this.state.data.readable.interned.number_of_strings
  859. }) : '';
  860. return React.createElement(
  861. "div",
  862. null,
  863. React.createElement(
  864. "div",
  865. null,
  866. React.createElement(
  867. "h3",
  868. null,
  869. "memory"
  870. ),
  871. React.createElement(
  872. "p",
  873. null,
  874. React.createElement(MemoryUsageGraph, { chart: this.state.chart, value: this.state.data.used_memory_percentage })
  875. )
  876. ),
  877. React.createElement(
  878. "div",
  879. null,
  880. React.createElement(
  881. "h3",
  882. null,
  883. "hit rate"
  884. ),
  885. React.createElement(
  886. "p",
  887. null,
  888. React.createElement(HitRateGraph, { chart: this.state.chart, value: this.state.data.hit_rate_percentage })
  889. )
  890. ),
  891. React.createElement(MemoryUsagePanel, {
  892. total: this.state.data.readable.total_memory,
  893. used: this.state.data.readable.used_memory,
  894. free: this.state.data.readable.free_memory,
  895. wasted: this.state.data.readable.wasted_memory,
  896. wastedPercent: this.state.data.wasted_percentage
  897. }),
  898. React.createElement(StatisticsPanel, {
  899. num_cached_scripts: this.state.data.readable.num_cached_scripts,
  900. hits: this.state.data.readable.hits,
  901. misses: this.state.data.readable.misses,
  902. blacklist_miss: this.state.data.readable.blacklist_miss,
  903. num_cached_keys: this.state.data.readable.num_cached_keys,
  904. max_cached_keys: this.state.data.readable.max_cached_keys
  905. }),
  906. interned
  907. );
  908. }
  909. });
  910. var GeneralInfo = React.createClass({
  911. getInitialState: function () {
  912. return {
  913. version: opstate.version,
  914. start: opstate.overview ? opstate.overview.readable.start_time : null,
  915. reset: opstate.overview ? opstate.overview.readable.last_restart_time : null
  916. };
  917. },
  918. render: function () {
  919. var startTime = this.state.start ? React.createElement(
  920. "tr",
  921. null,
  922. React.createElement(
  923. "td",
  924. null,
  925. "Start time"
  926. ),
  927. React.createElement(
  928. "td",
  929. null,
  930. this.state.start
  931. )
  932. ) : '';
  933. var lastReset = this.state.reset ? React.createElement(
  934. "tr",
  935. null,
  936. React.createElement(
  937. "td",
  938. null,
  939. "Last reset"
  940. ),
  941. React.createElement(
  942. "td",
  943. null,
  944. this.state.reset
  945. )
  946. ) : '';
  947. return React.createElement(
  948. "table",
  949. null,
  950. React.createElement(
  951. "thead",
  952. null,
  953. React.createElement(
  954. "tr",
  955. null,
  956. React.createElement(
  957. "th",
  958. { colSpan: "2" },
  959. "General info"
  960. )
  961. )
  962. ),
  963. React.createElement(
  964. "tbody",
  965. null,
  966. React.createElement(
  967. "tr",
  968. null,
  969. React.createElement(
  970. "td",
  971. null,
  972. "Zend OPcache"
  973. ),
  974. React.createElement(
  975. "td",
  976. null,
  977. this.state.version.version
  978. )
  979. ),
  980. React.createElement(
  981. "tr",
  982. null,
  983. React.createElement(
  984. "td",
  985. null,
  986. "PHP"
  987. ),
  988. React.createElement(
  989. "td",
  990. null,
  991. this.state.version.php
  992. )
  993. ),
  994. React.createElement(
  995. "tr",
  996. null,
  997. React.createElement(
  998. "td",
  999. null,
  1000. "Host"
  1001. ),
  1002. React.createElement(
  1003. "td",
  1004. null,
  1005. this.state.version.host
  1006. )
  1007. ),
  1008. React.createElement(
  1009. "tr",
  1010. null,
  1011. React.createElement(
  1012. "td",
  1013. null,
  1014. "Server Software"
  1015. ),
  1016. React.createElement(
  1017. "td",
  1018. null,
  1019. this.state.version.server
  1020. )
  1021. ),
  1022. startTime,
  1023. lastReset
  1024. )
  1025. );
  1026. }
  1027. });
  1028. var Directives = React.createClass({
  1029. getInitialState: function () {
  1030. return { data: opstate.directives };
  1031. },
  1032. render: function () {
  1033. var directiveNodes = this.state.data.map(function (directive) {
  1034. var map = { 'opcache.': '', '_': ' ' };
  1035. var dShow = directive.k.replace(/opcache\.|_/gi, function (matched) {
  1036. return map[matched];
  1037. });
  1038. var vShow;
  1039. if (directive.v === true || directive.v === false) {
  1040. vShow = React.createElement('i', {}, directive.v.toString());
  1041. } else if (directive.v === '') {
  1042. vShow = React.createElement('i', {}, 'no value');
  1043. } else {
  1044. vShow = directive.v;
  1045. }
  1046. return React.createElement(
  1047. "tr",
  1048. { key: directive.k },
  1049. React.createElement(
  1050. "td",
  1051. { title: 'View ' + directive.k + ' manual entry' },
  1052. React.createElement(
  1053. "a",
  1054. { href: 'http://php.net/manual/en/opcache.configuration.php#ini.' + directive.k.replace(/_/g, '-'), target: "_blank" },
  1055. dShow
  1056. )
  1057. ),
  1058. React.createElement(
  1059. "td",
  1060. null,
  1061. vShow
  1062. )
  1063. );
  1064. });
  1065. return React.createElement(
  1066. "table",
  1067. null,
  1068. React.createElement(
  1069. "thead",
  1070. null,
  1071. React.createElement(
  1072. "tr",
  1073. null,
  1074. React.createElement(
  1075. "th",
  1076. { colSpan: "2" },
  1077. "Directives"
  1078. )
  1079. )
  1080. ),
  1081. React.createElement(
  1082. "tbody",
  1083. null,
  1084. directiveNodes
  1085. )
  1086. );
  1087. }
  1088. });
  1089. var Files = React.createClass({
  1090. getInitialState: function () {
  1091. return {
  1092. data: opstate.files,
  1093. showing: null,
  1094. allowFiles: allowFiles
  1095. };
  1096. },
  1097. handleInvalidate: function (e) {
  1098. e.preventDefault();
  1099. if (realtime) {
  1100. $.get('#', { invalidate: e.currentTarget.getAttribute('data-file') }, function (data) {
  1101. console.log('success: ' + data.success);
  1102. }, 'json');
  1103. } else {
  1104. window.location.href = e.currentTarget.href;
  1105. }
  1106. },
  1107. render: function () {
  1108. if (this.state.allowFiles) {
  1109. var fileNodes = this.state.data.map(function (file, i) {
  1110. var invalidate, invalidated;
  1111. if (file.timestamp == 0) {
  1112. invalidated = React.createElement(
  1113. "span",
  1114. null,
  1115. React.createElement(
  1116. "i",
  1117. { className: "invalid metainfo" },
  1118. " - has been invalidated"
  1119. )
  1120. );
  1121. }
  1122. if (canInvalidate) {
  1123. invalidate = React.createElement(
  1124. "span",
  1125. null,
  1126. ",\xA0",
  1127. React.createElement(
  1128. "a",
  1129. { className: "metainfo", href: '?invalidate=' + file.full_path, "data-file": file.full_path, onClick: this.handleInvalidate },
  1130. "force file invalidation"
  1131. )
  1132. );
  1133. }
  1134. return React.createElement(
  1135. "tr",
  1136. { key: file.full_path, "data-path": file.full_path.toLowerCase(), className: i % 2 ? 'alternate' : '' },
  1137. React.createElement(
  1138. "td",
  1139. null,
  1140. React.createElement(
  1141. "div",
  1142. null,
  1143. React.createElement(
  1144. "span",
  1145. { className: "pathname" },
  1146. file.full_path
  1147. ),
  1148. React.createElement("br", null),
  1149. React.createElement(FilesMeta, { data: [file.readable.hits, file.readable.memory_consumption, file.last_used] }),
  1150. invalidate,
  1151. invalidated
  1152. )
  1153. )
  1154. );
  1155. }.bind(this));
  1156. return React.createElement(
  1157. "div",
  1158. null,
  1159. React.createElement(FilesListed, { showing: this.state.showing }),
  1160. React.createElement(
  1161. "table",
  1162. null,
  1163. React.createElement(
  1164. "thead",
  1165. null,
  1166. React.createElement(
  1167. "tr",
  1168. null,
  1169. React.createElement(
  1170. "th",
  1171. null,
  1172. "Script"
  1173. )
  1174. )
  1175. ),
  1176. React.createElement(
  1177. "tbody",
  1178. null,
  1179. fileNodes
  1180. )
  1181. )
  1182. );
  1183. } else {
  1184. return React.createElement("span", null);
  1185. }
  1186. }
  1187. });
  1188. var FilesMeta = React.createClass({
  1189. render: function () {
  1190. return React.createElement(
  1191. "span",
  1192. { className: "metainfo" },
  1193. React.createElement(
  1194. "b",
  1195. null,
  1196. "hits: "
  1197. ),
  1198. React.createElement(
  1199. "span",
  1200. null,
  1201. this.props.data[0],
  1202. ", "
  1203. ),
  1204. React.createElement(
  1205. "b",
  1206. null,
  1207. "memory: "
  1208. ),
  1209. React.createElement(
  1210. "span",
  1211. null,
  1212. this.props.data[1],
  1213. ", "
  1214. ),
  1215. React.createElement(
  1216. "b",
  1217. null,
  1218. "last used: "
  1219. ),
  1220. React.createElement(
  1221. "span",
  1222. null,
  1223. this.props.data[2]
  1224. )
  1225. );
  1226. }
  1227. });
  1228. var FilesListed = React.createClass({
  1229. getInitialState: function () {
  1230. return {
  1231. formatted: opstate.overview ? opstate.overview.readable.num_cached_scripts : 0,
  1232. total: opstate.overview ? opstate.overview.num_cached_scripts : 0
  1233. };
  1234. },
  1235. render: function () {
  1236. var display = this.state.formatted + ' file' + (this.state.total == 1 ? '' : 's') + ' cached';
  1237. if (this.props.showing !== null && this.props.showing != this.state.total) {
  1238. display += ', ' + this.props.showing + ' showing due to filter';
  1239. }
  1240. return React.createElement(
  1241. "h3",
  1242. null,
  1243. display
  1244. );
  1245. }
  1246. });
  1247. var overviewCountsObj = ReactDOM.render(React.createElement(OverviewCounts, null), document.getElementById('counts'));
  1248. var generalInfoObj = ReactDOM.render(React.createElement(GeneralInfo, null), document.getElementById('generalInfo'));
  1249. var filesObj = ReactDOM.render(React.createElement(Files, null), document.getElementById('filelist'));
  1250. ReactDOM.render(React.createElement(Directives, null), document.getElementById('directives'));
  1251. </script>
  1252. </body>
  1253. </html>