Skip to content

Commit 9f08594

Browse files
committed
Add dashboard
1 parent f307183 commit 9f08594

File tree

1 file changed

+289
-0
lines changed

1 file changed

+289
-0
lines changed

cache.php

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
<?php
2+
$opcache = opcache_get_status(true);
3+
$apc = array(
4+
'cache' => apc_cache_info('user'),
5+
'sma' => apc_sma_info(true)
6+
);
7+
8+
function percentage( $a, $b ) {
9+
return ( $a / $b ) * 100;
10+
}
11+
12+
function opcache_mem( $key ) {
13+
global $opcache;
14+
15+
if( $key == 'total' )
16+
return opcache_mem('free') + opcache_mem('used') + opcache_mem('wasted');
17+
18+
if( in_array( $key, array( 'used', 'free', 'wasted' ) ) )
19+
$key = $key . '_memory';
20+
21+
return $opcache['memory_usage'][$key];
22+
}
23+
24+
function opcache_stat( $stat ) {
25+
global $opcache;
26+
27+
return $opcache['opcache_statistics'][$stat];
28+
}
29+
30+
function apc_mem( $key ) {
31+
global $apc;
32+
33+
if( $key == 'total' )
34+
return $apc['sma']['seg_size'];
35+
36+
if( $key == 'free' )
37+
return $apc['sma']['avail_mem'];
38+
39+
if( $key == 'used' )
40+
return apc_mem('total') - apc_mem('free');
41+
42+
return 0;
43+
44+
}
45+
46+
function human_size( $s ) {
47+
$size = 'B';
48+
$sizes = array( 'KB', 'MB', 'GB' );
49+
50+
while( $s > 1024 ) {
51+
$size = array_shift( $sizes );
52+
$s /= 1024;
53+
}
54+
55+
$s = round( $s, 2 );
56+
return $s . ' ' . $size;
57+
}
58+
59+
function redirect($url) {
60+
header('Status: 302 Moved Temporarily');
61+
header('Location: '. $url);
62+
exit();
63+
}
64+
65+
function get_selector() {
66+
return '#' . str_replace( '#', '\#', urldecode($_GET['selector']) ) . '#';
67+
}
68+
69+
function sort_url($on) {
70+
$query = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
71+
if( empty( $query ) )
72+
$query = '';
73+
else
74+
$query .= '&';
75+
76+
$query = preg_replace( '#sort=[^&]+&?#', '', $query );
77+
$query = preg_replace( '#order=[^&]+&?#', '', $query );
78+
79+
if( !isset( $_GET['order'] ) )
80+
$_GET['order'] = '';
81+
82+
$query .= 'sort=' . urlencode($on);
83+
$query .= '&order=' . ( $_GET['order'] == 'asc' ? 'desc' : 'asc' );
84+
85+
return '?' . $query;
86+
}
87+
88+
function sort_list(&$list) {
89+
if( !isset( $_GET['sort'] ) )
90+
return $list;
91+
92+
$key = urldecode($_GET['sort']);
93+
$reverse = isset($_GET['order']) ? ( urldecode($_GET['order']) == 'desc' ) : false;
94+
usort($list, function( $item1, $item2 ) use ( $key, $reverse ) {
95+
if( $reverse ) {
96+
$tmp = $item1;
97+
$item1 = $item2;
98+
$item2 = $tmp;
99+
unset($tmp);
100+
}
101+
if( is_string( $item1[$key] ) || is_string( $item2[$key] ) )
102+
return strcmp( $item1[$key], $item2[$key] );
103+
104+
return $item1[$key] - $item2[$key];
105+
});
106+
107+
return $list;
108+
}
109+
110+
// Opcache
111+
112+
if( isset( $_GET['action'] ) && $_GET['action'] == 'op_restart' ) {
113+
opcache_reset();
114+
redirect('?');
115+
}
116+
117+
if( isset( $_GET['action'] ) && $_GET['action'] == 'op_delete' ) {
118+
$selector = get_selector();
119+
foreach( $opcache['scripts'] as $key => $value ) {
120+
if( !preg_match( $selector, $key) ) continue;
121+
122+
opcache_invalidate( $key );
123+
}
124+
redirect('?action=op_select&selector=' . $_GET['selector'] );
125+
}
126+
127+
// APC
128+
if( isset( $_GET['action'] ) && $_GET['action'] == 'apc_restart' ) {
129+
apc_delete( new ApcIterator('#.*#') );
130+
redirect('?');
131+
}
132+
133+
if( isset( $_GET['action'] ) && $_GET['action'] == 'apc_delete' ) {
134+
apc_delete( new ApcIterator('user',get_selector()) );
135+
redirect( '?action=apc_select&selector=' . $_GET['selector'] );
136+
}
137+
?><html>
138+
<head>
139+
<title>Cache Status</title>
140+
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1" />
141+
<style>
142+
html, body { font-family: Arial, sans-serif;}
143+
.wrap { max-width: 960px; margin: 0 auto;}
144+
.full { width: 100%; }
145+
.green { background: green; }
146+
.red { background: red; }
147+
.orange { background: orange; }
148+
.bar { height: 20px; overflow: hidden; border-radius: 4px 4px; }
149+
.bar div { height: 20px; float: left; }
150+
.bar, .bar div { background-image: repeating-linear-gradient(45deg, transparent 0, rgba( 255,255,255,0.3) 1px, rgba(255,255,255,0.3) 10px, transparent 11px, transparent 18px); background-repeat: repeat-x; }
151+
label { font-weight: bold; }
152+
table { border-spacing: 0; }
153+
table td { padding: 0.2em 1em; }
154+
table th { background: #686868; color: white; padding: 0.5em 1em 0.2em 1em; font-weight: normal; }
155+
table th a { text-decoration: none; color: white; cursor: pointer; }
156+
table tr:nth-child(2n+1) { background: #efefef; }
157+
@media screen and (max-width: 480px) {
158+
input { width: 40%; }
159+
}
160+
</style>
161+
</head>
162+
163+
<body>
164+
<div class="wrap">
165+
<div>
166+
Goto: <a href="#opcache">PHP Opcache</a> or <a href="#apcu">APCu</a>
167+
</div>
168+
<h2 id="opcache">PHP Opcache</h2>
169+
<div>
170+
<h3>Memory <?=human_size(opcache_mem('used')+opcache_mem('wasted'))?> of <?=human_size(opcache_mem('total'))?></h3>
171+
<div class="full bar green">
172+
<div class="orange" style="width: <?=percentage(opcache_mem('used'), opcache_mem('total'))?>%"></div>
173+
<div class="red" style="width: <?=percentage(opcache_mem('wasted'), opcache_mem('total'))?>%"></div>
174+
</div>
175+
</div>
176+
<div>
177+
<h3>Keys <?=opcache_stat('num_cached_keys')?> of <?=opcache_stat('max_cached_keys')?></h3>
178+
<div class="full bar green">
179+
<div class="orange" style="width: <?=percentage(opcache_stat('num_cached_keys'), opcache_stat('max_cached_keys'))?>%"></div>
180+
</div>
181+
</div>
182+
<div>
183+
<h3>Cache hit <?=round(opcache_stat('opcache_hit_rate'),2)?>%</h3>
184+
<div class="full bar green">
185+
<div class="red" style="width: <?=100-opcache_stat('opcache_hit_rate')?>%"></div>
186+
</div>
187+
</div>
188+
<div>
189+
<h3>Actions</h3>
190+
<form action="?" method="GET">
191+
<label>Cache:
192+
<button name="action" value="op_restart">Restart</button>
193+
</label>
194+
</form>
195+
<form action="?" method="GET">
196+
<label>Key(s):
197+
<input name="selector" type="text" value="" placeholder=".*" />
198+
</label>
199+
<button type="submit" name="action" value="op_select">Select</button>
200+
<button type="submit" name="action" value="op_delete">Delete</button>
201+
</form>
202+
</div>
203+
<?php if( isset( $_GET['action'] ) && $_GET['action'] == 'op_select' ): ?>
204+
<div>
205+
<h3>Keys matching <?=htmlentities('"'.$_GET['selector'].'"')?></h3>
206+
<table>
207+
<thead>
208+
<tr>
209+
<th><a href="<?=sort_url('full_path')?>">Key</a></th>
210+
<th><a href="<?=sort_url('hits')?>">Hits</a></th>
211+
<th><a href="<?=sort_url('memory_consumption')?>">Size</a></th>
212+
<th>Action</th>
213+
</tr>
214+
</thead>
215+
216+
<tfoot></tfoot>
217+
218+
<tbody>
219+
<?php foreach( sort_list($opcache['scripts']) as $item ):
220+
if( !preg_match(get_selector(), $item['full_path']) ) continue;?>
221+
<tr>
222+
<td><?=$item['full_path']?></td>
223+
<td><?=$item['hits']?></td>
224+
<td><?=human_size($item['memory_consumption'])?></td>
225+
<td><a href="?action=op_delete&selector=<?=urlencode('^'.$item['full_path'].'$')?>">Delete</a>
226+
</tr>
227+
<?php endforeach; ?>
228+
</tbody>
229+
</table>
230+
</div>
231+
<?php endif; ?>
232+
233+
<h2 id="apcu">APCu</h2>
234+
<div>
235+
<h3>Memory <?=human_size(apc_mem('used'))?> of <?=human_size(apc_mem('total'))?></h3>
236+
<div class="full bar green">
237+
<div class="orange" style="width: <?=percentage(apc_mem('used'), apc_mem('total'))?>%"></div>
238+
</div>
239+
</div>
240+
<div>
241+
<h3>Actions</h3>
242+
<form action="?" method="GET">
243+
<label>Cache:
244+
<button name="action" value="apc_restart">Restart</button>
245+
</label>
246+
</form>
247+
<form action="?" method="GET">
248+
<label>Key(s):</label>
249+
<input name="selector" type="text" value="" placeholder=".*" />
250+
<button type="submit" name="action" value="apc_select">Select</button>
251+
<button type="submit" name="action" value="apc_delete">Delete</button>
252+
</form>
253+
</div>
254+
<?php if( isset( $_GET['action'] ) && $_GET['action'] == 'apc_select' ): ?>
255+
<div>
256+
<h3>Keys matching <?=htmlentities('"'.$_GET['selector'].'"')?></h3>
257+
<table>
258+
<thead>
259+
<tr>
260+
<th><a href="<?=sort_url('key')?>">Key</a></th>
261+
<th><a href="<?=sort_url('nhits')?>">Hits</a></th>
262+
<th><a href="<?=sort_url('mem_size')?>">Size</a></th>
263+
<th><a href="<?=sort_url('ttl')?>">TTL</a></th>
264+
<th>Expires</th>
265+
<th>Action</th>
266+
</tr>
267+
</thead>
268+
269+
<tfoot></tfoot>
270+
271+
<tbody>
272+
<?php foreach( sort_list($apc['cache']['cache_list']) as $item ):
273+
if( !preg_match(get_selector(), $item['key']) ) continue;?>
274+
<tr>
275+
<td><?=$item['key']?></td>
276+
<td><?=$item['nhits']?></td>
277+
<td><?=human_size($item['mem_size'])?></td>
278+
<td><?=$item['ttl']?></td>
279+
<td><?=date('Y-m-d H:i', $item['mtime'] + $item['ttl'] )?></td>
280+
<td><a href="?action=apc_delete&selector=<?=urlencode('^'.$item['key'].'$')?>">Delete</a>
281+
</tr>
282+
<?php endforeach; ?>
283+
</tbody>
284+
</table>
285+
</div>
286+
<?php endif; ?>
287+
</div>
288+
</body>
289+
</html>

0 commit comments

Comments
 (0)