Instantly share code, notes, and snippets.

@ck-on /ocp.php
Last active Nov 24, 2018

What would you like to do?
OCP - Opcache Control Panel (aka Zend Optimizer+ Control Panel for PHP)#ocp #php #opcache #opcode #cache #zend #optimizerplus #optimizer+
OCP - Opcache Control Panel (aka Zend Optimizer+ Control Panel for PHP)
Author: _ck_ (with contributions by GK, stasilok)
Version: 0.1.7
Free for any kind of use or modification, I am not responsible for anything, please share your improvements
* revision history
0.1.7 2015-09-01 regex fix for PHP7 phpinfo
0.1.6 2013-04-12 moved meta to footer so graphs can be higher and reduce clutter
0.1.5 2013-04-12 added graphs to visualize cache state, please report any browser/style bugs
0.1.4 2013-04-09 added "recheck" to update files when using large revalidate_freq (or validate_timestamps=Off)
0.1.3 2013-03-30 show host and php version, can bookmark with hashtag ie. #statistics - needs new layout asap
0.1.2 2013-03-25 show optimization levels, number formatting, support for start_time in 7.0.2
0.1.1 2013-03-18 today Zend completely renamed Optimizer+ to OPcache, adjusted OCP to keep working
0.1.0 2013-03-17 added group/sort indicators, replaced "accelerator_" functions with "opcache_"
0.0.6 2013-03-16 transition support as Zend renames product and functions for PHP 5.5 (stasilok)
0.0.5 2013-03-10 added refresh button (GK)
0.0.4 2013-02-18 added file grouping and sorting (click on headers) - code needs cleanup but gets the job done
0.0.2 2013-02-14 first public release
* known problems/limitations:
Unlike APC, the Zend OPcache API
- cannot determine when a file was put into the cache
- cannot change settings on the fly
- cannot protect opcache functions by restricting execution to only specific scripts/paths
* todo:
Extract variables for prefered ordering and better layout instead of just dumping into tables
File list filter
// ini_set('display_errors',1); error_reporting(-1);
if ( count(get_included_files())>1 || php_sapi_name()=='cli' || empty($_SERVER['REMOTE_ADDR']) ) { die; } // weak block against indirect access
if ( !empty($_GET['RESET']) ) {
if ( function_exists(CACHEPREFIX.'reset') ) { call_user_func(CACHEPREFIX.'reset'); }
header( 'Location: '.str_replace('?'.$_SERVER['QUERY_STRING'],'',$_SERVER['REQUEST_URI']) );
if ( !empty($_GET['RECHECK']) ) {
if ( function_exists(CACHEPREFIX.'invalidate') ) {
$recheck=trim($_GET['RECHECK']); $files=call_user_func(CACHEPREFIX.'get_status');
if (!empty($files['scripts'])) {
foreach ($files['scripts'] as $file=>$value) {
if ( $recheck==='1' || strpos($file,$recheck)===0 ) call_user_func(CACHEPREFIX.'invalidate',$file);
header( 'Location: '.str_replace('?'.$_SERVER['QUERY_STRING'],'',$_SERVER['REQUEST_URI']) );
} else { echo 'Sorry, this feature requires Zend Opcache newer than April 8th 2013'; }
?><!DOCTYPE html>
<title>OCP - Opcache Control Panel</title>
<style type="text/css">
body {background-color: #fff; color: #000;}
body, td, th, h1, h2 {font-family: sans-serif;}
pre {margin: 0px; font-family: monospace;}
a:link,a:visited {color: #000099; text-decoration: none;}
a:hover {text-decoration: underline;}
table {border-collapse: collapse; width: 600px; }
.center {text-align: center;}
.center table { margin-left: auto; margin-right: auto; text-align: left;}
.center th { text-align: center !important; }
.middle {vertical-align:middle;}
td, th { border: 1px solid #000; font-size: 75%; vertical-align: baseline; padding: 3px; }
h1 {font-size: 150%;}
h2 {font-size: 125%;}
.p {text-align: left;}
.e {background-color: #ccccff; font-weight: bold; color: #000; width:50%; white-space:nowrap;}
.h {background-color: #9999cc; font-weight: bold; color: #000;}
.v {background-color: #cccccc; color: #000;}
.vr {background-color: #cccccc; text-align: right; color: #000; white-space: nowrap;}
.b {font-weight:bold;}
.white, .white a {color:#fff;}
img {float: right; border: 0px;}
hr {width: 600px; background-color: #cccccc; border: 0px; height: 1px; color: #000;}
.meta, .small {font-size: 75%; }
.meta {margin: 2em 0;}
.meta a, th a {padding: 10px; white-space:nowrap; }
.buttons {margin:0 0 1em;}
.buttons a {margin:0 15px; background-color: #9999cc; color:#fff; text-decoration:none; padding:1px; border:1px solid #000; display:inline-block; width:5em; text-align:center;}
#files td.v a {font-weight:bold; color:#9999cc; margin:0 10px 0 5px; text-decoration:none; font-size:120%;}
#files td.v a:hover {font-weight:bold; color:#ee0000;}
.graph {display:inline-block; width:145px; margin:1em 0 1em 1px; border:0; vertical-align:top;}
.graph table {width:100%; height:150px; border:0; padding:0; margin:5px 0 0 0; position:relative;}
.graph td {vertical-align:middle; border:0; padding:0 0 0 5px;}
.graph .bar {width:25px; text-align:right; padding:0 2px; color:#fff;}
.graph .total {width:34px; text-align:center; padding:0 5px 0 0;}
.graph .total div {border:1px dashed #888; border-right:0; height:99%; width:12px; position:absolute; bottom:0; left:17px; z-index:-1;}
.graph .total span {background:#fff; font-weight:bold;}
.graph .actual {text-align:right; font-weight:bold; padding:0 5px 0 0;}
.graph .red {background:#ee0000;}
.graph .green {background:#00cc00;}
.graph .brown {background:#8B4513;}
<!--[if lt IE 9]><script type="text/javascript" defer="defer">
window.onload=function(){var i,t=document.getElementsByTagName('table');for(i=0;i<t.length;i++){if(t[i].parentNode.className=='graph')t[i].style.height=150-(t[i].clientHeight-150)+'px';}}
<div class="center">
<h1><a href="?">Opcache Control Panel</a></h1>
<div class="buttons">
<a href="?ALL=1">Details</a>
<a href="?FILES=1&GROUP=2&SORT=3">Files</a>
<a href="?RESET=1" onclick="return confirm('RESET cache ?')">Reset</a>
<?php if ( function_exists(CACHEPREFIX.'invalidate') ) { ?>
<a href="?RECHECK=1" onclick="return confirm('Recheck all files in the cache ?')">Recheck</a>
<?php } ?>
<a href="?" onclick="window.location.reload(true); return false">Refresh</a>
if ( !function_exists(CACHEPREFIX.'get_status') ) { echo '<h2>Opcache not detected?</h2>'; die; }
if ( !empty($_GET['FILES']) ) { echo '<h2>files cached</h2>'; files_display(); echo '</div></body></html>'; exit; }
if ( !(isset($_REQUEST['GRAPHS']) && !$_REQUEST['GRAPHS']) && CACHEPREFIX=='opcache_') { graphs_display(); if ( !empty($_REQUEST['GRAPHS']) ) { exit; } }
ob_start(); phpinfo(8); $phpinfo = ob_get_contents(); ob_end_clean(); // some info is only available via phpinfo? sadly buffering capture has to be used
if ( !preg_match( '/module\_Zend.(Optimizer\+|OPcache).+?(\<table[^>]*\>.+?\<\/table\>).+?(\<table[^>]*\>.+?\<\/table\>)/is', $phpinfo, $opcache) ) { } // todo
if ( function_exists(CACHEPREFIX.'get_configuration') ) { echo '<h2>general</h2>'; $configuration=call_user_func(CACHEPREFIX.'get_configuration'); }
$host=function_exists('gethostname')?@gethostname():@php_uname('n'); if (empty($host)) { $host=empty($_SERVER['SERVER_NAME'])?$_SERVER['HOST_NAME']:$_SERVER['SERVER_NAME']; }
$version['PHP Version']='PHP '.(defined('PHP_VERSION')?PHP_VERSION:'???').' '.(defined('PHP_SAPI')?PHP_SAPI:'').' '.(defined('PHP_OS')?' '.PHP_OS:'');
$version['Opcache Version']=empty($configuration['version']['version'])?'???':$configuration['version'][CACHEPREFIX.'product_name'].' '.$configuration['version']['version'];
if ( !empty($opcache[2]) ) { echo preg_replace('/\<tr\>\<td class\="e"\>[^>]+\<\/td\>\<td class\="v"\>[0-9\,\. ]+\<\/td\>\<\/tr\>/','',$opcache[2]); }
if ( function_exists(CACHEPREFIX.'get_status') && $status=call_user_func(CACHEPREFIX.'get_status') ) {
if ( !empty($status[CACHEPREFIX.'statistics']['start_time']) ) {
if ( !empty($status[CACHEPREFIX.'statistics']['last_restart_time']) ) {
if (!empty($uptime)) {print_table($uptime);}
if ( !empty($status['cache_full']) ) { $status['memory_usage']['cache_full']=$status['cache_full']; }
echo '<h2 id="memory">memory</h2>';
echo '<h2 id="statistics">statistics</h2>';
if ( empty($_GET['ALL']) ) { meta_display(); exit; }
if ( !empty($configuration['blacklist']) ) { echo '<h2 id="blacklist">blacklist</h2>'; print_table($configuration['blacklist']); }
if ( !empty($opcache[3]) ) { echo '<h2 id="runtime">runtime</h2>'; echo $opcache[3]; }
$name='zend opcache'; $functions=get_extension_funcs($name);
if (!$functions) { $name='zend optimizer+'; $functions=get_extension_funcs($name); }
if ($functions) { echo '<h2 id="functions">functions</h2>'; print_table($functions); } else { $name=''; }
if (isset($configuration['directives'][$level])) {
echo '<h2 id="optimization">optimization levels</h2>';
$levelset=strrev(base_convert($configuration['directives'][$level], 10, 2));
1=>'<a href="">Constants subexpressions elimination</a> (CSE) true, false, null, etc.<br />Optimize series of ADD_STRING / ADD_CHAR<br />Convert CAST(IS_BOOL,x) into BOOL(x)<br />Convert <a href="">INIT_FCALL_BY_NAME</a> + <a href="">DO_FCALL_BY_NAME</a> into <a href="">DO_FCALL</a>',
2=>'Convert constant operands to expected types<br />Convert conditional <a href="">JMP</a> with constant operands<br />Optimize static <a href="">BRK</a> and <a href="<a href="">CONT</a>',
3=>'Convert $a = $a + expr into $a += expr<br />Convert $a++ into ++$a<br />Optimize series of <a href="">JMP</a>',
4=>'PRINT and ECHO optimization (<a href="">defunct</a>)',
5=>'Block Optimization - most expensive pass<br />Performs many different optimization patterns based on <a href="">control flow graph</a> (CFG)',
9=>'Optimize <a href="">register allocation</a> (allows re-usage of temporary variables)',
10=>'Remove NOPs'
echo '<table width="600" border="0" cellpadding="3"><tbody><tr class="h"><th>Pass</th><th>Description</th></tr>';
foreach ($levels as $pass=>$description) {
$disabled=substr($levelset,$pass-1,1)!=='1' || $pass==4 ? ' white':'';
echo '<tr><td class="v center middle'.$disabled.'">'.$pass.'</td><td class="v'.$disabled.'">'.$description.'</td></tr>';
echo '</table>';
if ( isset($_GET['DUMP']) ) {
if ($name) { echo '<h2 id="ini">ini</h2>'; print_table(ini_get_all($name,true)); }
foreach ($configuration as $key=>$value) { echo '<h2>',$key,'</h2>'; print_table($configuration[$key]); }
echo '</div></body></html>';
function time_since($time,$original,$extended=0,$text='ago') {
$time = $time - $original;
$day = $extended? floor($time/86400) : round($time/86400,0);
$amount=0; $unit='';
if ( $time < 86400) {
if ( $time < 60) { $amount=$time; $unit='second'; }
elseif ( $time < 3600) { $amount=floor($time/60); $unit='minute'; }
else { $amount=floor($time/3600); $unit='hour'; }
elseif ( $day < 14) { $amount=$day; $unit='day'; }
elseif ( $day < 56) { $amount=floor($day/7); $unit='week'; }
elseif ( $day < 672) { $amount=floor($day/30); $unit='month'; }
else { $amount=intval(2*($day/365))/2; $unit='year'; }
if ( $amount!=1) {$unit.='s';}
if ($extended && $time>60) { $text=' and '.time_since($time,$time<86400?($time<3600?$amount*60:$amount*3600):$day*86400,0,'').$text; }
return $amount.' '.$unit.' '.$text;
function print_table($array,$headers=false) {
if ( empty($array) || !is_array($array) ) {return;}
echo '<table border="0" cellpadding="3" width="600">';
if (!empty($headers)) {
if (!is_array($headers)) {$headers=array_keys(reset($array));}
echo '<tr class="h">';
foreach ($headers as $value) { echo '<th>',$value,'</th>'; }
echo '</tr>';
foreach ($array as $key=>$value) {
echo '<tr>';
if ( !is_numeric($key) ) {
$key=ucwords(str_replace('_',' ',$key));
echo '<td class="e">',$key,'</td>';
if ( is_numeric($value) ) {
if ( $value>1048576) { $value=round($value/1048576,1).'M'; }
elseif ( is_float($value) ) { $value=round($value,1); }
if ( is_array($value) ) {
foreach ($value as $column) {
echo '<td class="v">',$column,'</td>';
echo '</tr>';
else { echo '<td class="v">',$value,'</td></tr>'; }
echo '</table>';
function files_display() {
if ( empty($status['scripts']) ) {return;}
if ( isset($_GET['DUMP']) ) { print_table($status['scripts']); exit;}
$time=time(); $sort=0;
$group=empty($_GET['GROUP'])?0:intval($_GET['GROUP']); if ( $group<0 || $group>9) { $group=1;}
$groupset=array_fill(0,9,''); $groupset[$group]=' class="b" ';
echo '<div class="meta">
<a ',$groupset[0],'href="',$nogroup,'">ungroup</a> |
<a ',$groupset[1],'href="',$nogroup,'&GROUP=1">1</a> |
<a ',$groupset[2],'href="',$nogroup,'&GROUP=2">2</a> |
<a ',$groupset[3],'href="',$nogroup,'&GROUP=3">3</a> |
<a ',$groupset[4],'href="',$nogroup,'&GROUP=4">4</a> |
<a ',$groupset[5],'href="',$nogroup,'&GROUP=5">5</a>
if ( !$group ) { $files =& $status['scripts']; }
else {
foreach ($status['scripts'] as $data) {
if ( preg_match('@^[/]([^/]+[/]){'.$group.'}@',$data['full_path'],$path) ) {
if ( empty($files[$path[0]])) { $files[$path[0]]=array('full_path'=>'','files'=>0,'hits'=>0,'memory_consumption'=>0,'last_used_timestamp'=>'','timestamp'=>''); }
if ( $data['last_used_timestamp']>$files[$path[0]]['last_used_timestamp']) {$files[$path[0]]['last_used_timestamp']=$data['last_used_timestamp'];}
if ( $data['timestamp']>$files[$path[0]]['timestamp']) {$files[$path[0]]['timestamp']=$data['timestamp'];}
if ( !empty($_GET['SORT']) ) {
$titles=array('','path',$group?'files':'','size','hits','last used','created');
$sortflip=range(0,7); $sortflip[$sort]=-$direction*$sort;
if ( $keys[$key]==SORT_STRING) {$direction=-$direction; }
$arrow=array_fill(0,7,''); $arrow[$sort]=$direction>0?' &#x25BC;':' &#x25B2;';
$column=array(); foreach ($files as $data) { $column[]=$data[$key]; }
array_multisort($column, $keys[$key], $direction, $files);
echo '<table border="0" cellpadding="3" width="960" id="files">
<tr class="h">';
foreach ($titles as $column=>$title) {
if ($title) echo '<th><a href="',$nosort,'&SORT=',$sortflip[$column],'">',$title,$arrow[$column],'</a></th>';
echo ' </tr>';
foreach ($files as $data) {
echo '<tr>
<td class="v" nowrap><a title="recheck" href="?RECHECK=',rawurlencode($data['full_path']),'">x</a>',$data['full_path'],'</td>',
($group?'<td class="vr">'.number_format($data['files']).'</td>':''),
'<td class="vr">',number_format(round($data['memory_consumption']/1024)),'K</td>',
'<td class="vr">',number_format($data['hits']),'</td>',
'<td class="vr">',time_since($time,$data['last_used_timestamp']),'</td>',
'<td class="vr">',empty($data['timestamp'])?'':time_since($time,$data['timestamp']),'</td>
echo '</table>';
function graphs_display() {
$primes=array(223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987);
foreach ($primes as $prime) { if ($prime>=$graphs['keys']['total']) { $graphs['keys']['total']=$prime; break;} }
foreach ( $graphs as $caption=>$graph) {
echo '<div class="graph"><div class="h">',$caption,'</div><table border="0" cellpadding="0" cellspacing="0">';
foreach ($graph as $label=>$value) {
if ($label=='total') { $key=0; $total=$value; $totaldisplay='<td rowspan="3" class="total"><span>'.($total>999999?round($total/1024/1024).'M':($total>9999?round($total/1024).'K':$total)).'</span><div></div></td>'; continue;}
$percent=$total?floor($value*100/$total):''; $percent=!$percent||$percent>99?'':$percent.'%';
echo '<tr>',$totaldisplay,'<td class="actual">', ($value>999999?round($value/1024/1024).'M':($value>9999?round($value/1024).'K':$value)),'</td><td class="bar ',$colors[$key],'" height="',$percent,'">',$percent,'</td><td>',$label,'</td></tr>';
$key++; $totaldisplay='';
echo '</table></div>',"\n";
function meta_display() {
<div class="meta">
<a href="">directives guide</a> |
<a href="">functions guide</a> |
<a href=""></a> |
<a href="">pecl</a> |
<a href="">Zend source</a> |
<a href="">OCP latest</a>

This comment has been minimized.

tvlooy commented Mar 1, 2013

Why not put this in a regular repository so people can open pull requests on it?


This comment has been minimized.

tvlooy commented Mar 16, 2013

accelerator_get_status was renamed to opcache_get_status


This comment has been minimized.


ck-on commented Mar 17, 2013

Version 0.1.0 now replaces all "accelerator_" functions to "opcache_" to match newest Optimizer+ code.

Also added group/sort indicators.

Zend API has many limitations compared to APC but hopefully they will address this sooner than later.


This comment has been minimized.


ck-on commented Mar 19, 2013

today Zend completely renamed Zend Optimizer+ to Zend OPcache


OCP version 0.1.1 tries to work with all the differences between the three different Zend code sets

But people with previous versions will have to report if it's broken or not.


This comment has been minimized.


ck-on commented Mar 25, 2013

OCP version 0.1.2 now shows show optimization levels (not well tested but I thought I'd document them)

Also added number formatting (commas) to large numbers to make them easier to read.

Zend was nice enough to add "start_time" in 7.0.2 based on my request so I can now show uptime in addition to last reset time - enhanced my "time_since" function to show extended fractions of time for uptime.

But Zend refuses to add the ability to change settings on the fly:
zendtech/ZendOptimizerPlus#67 (comment)

My last hope is Zend at least gives us the ability to manually delete individual files via the api,
ie. opcache_delete( $fullpath )


This comment has been minimized.


ck-on commented Apr 9, 2013

OCP version 0.1.4 ( 2013-April-09 )

Added a "recheck" feature to update files when using a large opcache.revalidate_freq
(or opcache.validate_timestamps=Off)

Also an "X" now appears next to each file/group in the Files listing to allow you to recheck just those files.

This feature is only now possible thanks to Zend adding the ability to delete individual files as per my request:

zendtech/ZendOptimizerPlus#26 (comment)

To use this feature you must be using a version of Zend Opcache newer than April 8th 2013
which has the opcache_invalidate function.

I also added a weak security check to make sure OCP is running from your browser and not included or running from the command-line. Obviously you should be password protecting the OCP directory on your server.


This comment has been minimized.


ck-on commented Apr 12, 2013

OCP version 0.1.5 ( 2013-April-12 )

Finally added some graphs to visualize cache state.

This took quite a bit of trial and error to display as much info as possible but keep it easy enough to read.

Please report any browser/style bugs (it also required a javascript hack to fix compatibility with IE8).

There is an undocumented trick to just show the graphs with ?GRAPHS=1
or you can turn off the graphs with ?GRAPHS=0

also, 0.1.6 moved the meta to the footer


This comment has been minimized.

ylluminate commented Apr 14, 2013

Absolutely wonderful work. Are you expecting to add a function that will allow some form of authentication and be able to make actual changes to the php.ini? Or always leave this as more of a "monitor" to review settings? I am suspecting the latter, but I'm just curious. Very useful.


This comment has been minimized.


ck-on commented Apr 14, 2013

@ylluminate if I understand your questions correctly, unfortunately security doesn't exist right now because Zend doesn't have any kind of security control on their opcache functions as far as what user, or what path, can execute them.

So even if this script was password protected on your server, if it was a shared hosting server, someone else could just run these functions elsewhere on the server to do whatever.

The only defense in that case would be to disable the opcache functions entirely in the php.ini and override it somehow for the control panel for server admin. Tricky but maybe possible.

ie. everyone else runs one php.ini that disabled opcache functions but you have a special php.ini that enables the functions

But the good news is that the most malicious thing anyone could do is repeatedly delete a file from the cache, which would then regenerate. It would cause a little load and eventually exhaust the cache and reset the cache. But they could not do any permanent damage, only annoy the server admin.

Oh I see now what you are saying, my request to be able to adjust ini settings, like the revalidate_freq

Well I put in a request for them to allow api path restriction: zendtech/ZendOptimizerPlus#89

If they did that, problem solved.


This comment has been minimized.

ache commented Jun 25, 2013

Apache 2.2.24 apache2handler PHP 5.4.16 Zend OPcache 7.0.2.

  1. PHP Notice: Undefined index: timestamp in ocp.php on line 289. Can be fixed using if ( isset($data['timestamp']) && ...
  2. 'created' column in the Files tab is always empty, it seems related to 1)
  3. Segmentation fault in few Apache children after pressing Recheck button and apparently no effect.

This comment has been minimized.


ck-on commented Jun 26, 2013

@ache, Thanks for the report - I guess you have file stat turned completely off?
ie. opcache.validate_timestamps=0 ?

I forgot to test that situation. And in theory "recheck" is impossible if so.

An alternative you can try is to just push the opcache.revalidate_freq really high
opcache.validate_timestamps=1 opcache.revalidate_freq=999999999

Unfortunately Zend doesn't store the timestamps if the file stat is turned off.


This comment has been minimized.


ck-on commented Jul 31, 2013

Zend has now thoughtfully added my api path restriction idea:


So admin on shared servers can now do things in php.ini like
opcache.restrict_api = "/home/admin/ocp/"


This comment has been minimized.

NewEraCracker commented Aug 23, 2013

Hello, I was only seeing a white page in my server and only could see the page when I commented this line

if ( count(get_included_files())>1 || php_sapi_name()=='cli' || empty($_SERVER['REMOTE_ADDR']) ) { die; }  // weak block against indirect access

This is as I use the auto_prepend_file to include a file to disable timezone errors.

Now I've changed that code to

$max_included_files = 1;
if( ini_get('auto_prepend_file') ) ++$max_included_files;
if ( count(get_included_files())>$max_included_files || php_sapi_name()=='cli' || empty($_SERVER['REMOTE_ADDR']) ) { die; }  // weak block against indirect access

And seems to work.


This comment has been minimized.


ck-on commented Aug 26, 2013

@tk1 - you are welcome to use it any way you wish

@NewEraCracker - I am shocked I didn't know about auto_prepend_file in PHP after all these years.
I wonder how commonly it is used. Interesting that it's not counted as "included".


This comment has been minimized.

n1xim commented Aug 29, 2013

@ck-on I've forked an update that scales "hits" as base 10 and not base 2.


This comment has been minimized.


ck-on commented Sep 5, 2013

@n1xim - I see what you did but instead of repeating all the lines in the if/else you could have just used a variable to equal 1000 instead of 1024 ?


This comment has been minimized.

NewEraCracker commented Sep 23, 2013

@ck-on As far as I've noticed in PHP 5.4 and in PHP 5.5 auto_prepend_file is counted towards get_included_files() count.

I've been using auto_prepend_file to "counter-attack" timezone warnings in the scripts I run (forums and blogs mostly), for portability reasons I have an algorithm to auto detect those on runtime as I deploy servers in several locations and use the same php.ini for all of them.

This is, for example, the script I usually use as auto_prepend_file

 Fix for PHP Warning about system's timezone settings
 @author NewEraCracker

ini_set('date.timezone', @date_default_timezone_get());

And that is why I have to use the 'fix' I mentioned in the previous comment.


This comment has been minimized.

NewEraCracker commented Sep 23, 2013

I also made a simple patch file that also adds ocp_function_exists and ocp_call_user_func. Those functions check if CACHEPREFIX is set, if that is not the case it won't execute the function and will allow returning the 'opcache not installed' error.

This fixes an issue when you access 'Reset' option when OPcache is not installed. PHP has a 'reset' function and it will be executed.


This comment has been minimized.

ylluminate commented Sep 26, 2013

Thanks @NewEraCracker, can you just fork this and create a completed version gist with your patches?


This comment has been minimized.

leisegang commented Nov 6, 2013

Could you add a login part to this script?
As the APC.php files has. It is a bit bad i think to have this kind of script open to the world!


This comment has been minimized.

ksarnelli commented Nov 18, 2013

The 'Files' tab is broken on Windows. To make it support both Unix and Windows style paths the regex in line 282 can be changed to:



This comment has been minimized.

durasj commented Jan 28, 2014

@leisegang you can write your own login page. I think it's better to do so.


This comment has been minimized.

szepeviktor commented Feb 15, 2014

Please add at line 35:


" phpinfo(): It is not safe to rely on the system's timezone settings. You are required to use the date.timezone setting or the date_default_timezone_set() function."


This comment has been minimized.

kabel commented May 7, 2014

I created a fork that includes a code restructure along with some of the latest contributions from other forks. Feel free to use as you see fit.


This comment has been minimized.

winkexp commented Jul 4, 2014

Hi, my edit tool reminds me that there is a tag missing at line 112:


This comment has been minimized.

jimmyyem commented Apr 1, 2015



This comment has been minimized.

Nirjonadda commented Jul 5, 2015

Can using both Opcache and Xcache? Does have any issue?


This comment has been minimized.

purpl commented Jul 31, 2015

This is offers a phenomenal insight, great tool, love it


This comment has been minimized.

tomolimo commented Aug 18, 2015

View my revision to be able to group files up to 8 directories/sub-directories
And to be able to use groups when hosted by Windows.


This comment has been minimized.

Zorlin commented Nov 20, 2015

Thank you very much! This helped me discover some huge bottlenecks.


This comment has been minimized.

Philzen commented Feb 8, 2016

There is an issue that leads to infinite redirects when including the script in an environment where all requests are routed through an index.php via mod_redirect. Problem root is that in such cases $_SERVER['QUERY_STRING'] contains the full query string that is assembled via the rewrite in the main .htaccess file - while $_SERVER['REQUEST_URI'] will always hold the "pretty" URL.

My workaround for now is as follows:

Replace line 42 with:

header( 'Location: ' . str_replace(substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], 'RESET=') - 1, 1) . 'RESET=' . $_GET['RESET'], '', $_SERVER['REQUEST_URI']) );

Replace line 54 with:

header( 'Location: '.str_replace(substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], 'RECHECK=') - 1, 1) . 'RECHECK=' . $_GET['RECHECK'], '', $_SERVER['REQUEST_URI']) );

This comment has been minimized.

TrurlMcByte commented Sep 15, 2016

also better to add

header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate');

before ?><!DOCTYPE html>


This comment has been minimized.

futureweb commented Nov 23, 2016

getting thousands of those Errors when calling ocp.php:

[Wed Nov 23 15:39:03.615290 2016] [:error] [pid 7777] [client] PHP Notice: Undefined index: timestamp in /var/myPath/ocp.php on line 296, referer:
[Wed Nov 23 15:39:22.810754 2016] [:error] [pid 9901] [client] PHP Notice: Undefined index: timestamp in /var/myPath/ocp.php on line 296, referer:

Env: PHP 7.0.13


This comment has been minimized.

justechn commented May 24, 2017

Just tried out this page and it still works great
screen shot 2017-05-24 at 10 14 27 am

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment