|
8 | 8 | define('ENABLE_OPCACHE', extension_loaded('Zend OPcache'));
|
9 | 9 | define('ENABLE_REALPATH', function_exists('realpath_cache_size'));
|
10 | 10 | define('ENABLE_MEMCACHE', extension_loaded('memcache') || extension_loaded('memcached'));
|
| 11 | + define('ENABLE_REDIS', extension_loaded('redis')); |
11 | 12 |
|
12 | 13 | // Memcache configuration
|
13 | 14 | define('MEMCACHE_HOST', getenv('MEMCACHE_HOST') ?: '127.0.0.1');
|
14 | 15 | define('MEMCACHE_PORT', getenv('MEMCACHE_PORT') ?: 11211);
|
15 | 16 | define('MEMCACHE_USER', getenv('MEMCACHE_USER') ?: null);
|
16 | 17 | define('MEMCACHE_PASSWORD', getenv('MEMCACHE_PASSWORD') ?: null);
|
17 | 18 |
|
| 19 | + // Redis configuration |
| 20 | + define('REDIS_HOST', getenv('REDIS_HOST') ?: '127.0.0.1'); |
| 21 | + define('REDIS_PORT', getenv('REDIS_PORT') ?: 6379); |
| 22 | + define('REDIS_PASSWORD', getenv('REDIS_PASSWORD') ?: null); |
| 23 | + define('REDIS_DATABASE', getenv('REDIS_DATABASE') ?: null); |
| 24 | + define('REDIS_SIZE', getenv('REDIS_SIZE') ?: null); |
| 25 | + |
18 | 26 | if (ENABLE_APC) {
|
19 | 27 | if (!extension_loaded('apcu')) {
|
20 | 28 | function apcu_cache_info($limited = false) { return apc_cache_info('user', $limited); }
|
@@ -88,6 +96,45 @@ function __construct($search = null) { parent::__construct('user', $search); }
|
88 | 96 | }
|
89 | 97 | }
|
90 | 98 |
|
| 99 | + if (ENABLE_REDIS) { |
| 100 | + $redis = new Redis(); |
| 101 | + |
| 102 | + try { |
| 103 | + $redis->connect(REDIS_HOST, REDIS_PORT); |
| 104 | + |
| 105 | + if (!empty(REDIS_PASSWORD)) |
| 106 | + $redis->auth(REDIS_PASSWORD); |
| 107 | + |
| 108 | + $redis_db = 0; |
| 109 | + $redis_dbs = $redis->config('GET', 'databases'); |
| 110 | + $redis_db_select = !is_numeric(REDIS_DATABASE) && !empty($redis_dbs); |
| 111 | + $redis_memory = $redis->info('memory'); |
| 112 | + |
| 113 | + if (!$redis_db_select) |
| 114 | + $redis_db = REDIS_DATABASE; |
| 115 | + else if (!empty($_COOKIE['redis_db'])) |
| 116 | + $redis_db = (int)$_COOKIE['redis_db']; |
| 117 | + |
| 118 | + $redis->select($redis_db); |
| 119 | + } catch(RedisException $ex) { |
| 120 | + // Failed to connect |
| 121 | + } |
| 122 | + |
| 123 | + if( $redis->isConnected() && is_action('redis_clear') ) { |
| 124 | + $redis->flushDb(); |
| 125 | + redirect('?'); |
| 126 | + } |
| 127 | + |
| 128 | + if( $redis->isConnected() && is_action('redis_delete') ) { |
| 129 | + $list = redis_keys(get_selector()); |
| 130 | + |
| 131 | + foreach ($list as $key => $item) |
| 132 | + $redis->del($key); |
| 133 | + |
| 134 | + redirect( '?action=redis_select&selector=' . $_GET['selector'] ); |
| 135 | + } |
| 136 | + } |
| 137 | + |
91 | 138 | function val_to_str($value) {
|
92 | 139 | return htmlentities(var_export($value, true));
|
93 | 140 | }
|
@@ -223,6 +270,104 @@ function memcache_ref() {
|
223 | 270 | return $keys;
|
224 | 271 | }
|
225 | 272 |
|
| 273 | + function redis_mem( $key ) { |
| 274 | + global $redis_memory; |
| 275 | + |
| 276 | + if( $key == 'free' ) |
| 277 | + return max(redis_mem('total') - redis_mem('used'), 0); |
| 278 | + |
| 279 | + if( $key == 'total' && !empty($redis_memory['maxmemory']) ) |
| 280 | + return $redis_memory['maxmemory']; |
| 281 | + |
| 282 | + if( $key == 'total' && !empty($redis_memory['total_system_memory']) ) |
| 283 | + return $redis_memory['total_system_memory']; |
| 284 | + |
| 285 | + if( $key == 'total' && !empty(REDIS_SIZE)) |
| 286 | + return (int)REDIS_SIZE; |
| 287 | + |
| 288 | + if( $key == 'total') |
| 289 | + return redis_mem('used'); |
| 290 | + |
| 291 | + if ($key == 'used') |
| 292 | + return $redis_memory['used_memory']; |
| 293 | + |
| 294 | + if ($key == 'overhead' && !empty($redis_memory['used_memory_overhead'])) |
| 295 | + return $redis_memory['used_memory_overhead']; |
| 296 | + |
| 297 | + return 0; |
| 298 | + } |
| 299 | + |
| 300 | + function redis_get_key($key, &$found = false) { |
| 301 | + global $redis; |
| 302 | + |
| 303 | + $type = $redis->type($key); |
| 304 | + $found = $redis->exists($key); |
| 305 | + $value = null; |
| 306 | + |
| 307 | + if ($type == Redis::REDIS_STRING || $type == Redis::REDIS_NOT_FOUND) |
| 308 | + $value = $redis->get($key); |
| 309 | + else if ($type == Redis::REDIS_HASH) |
| 310 | + $value == $redis->hgetall($key); |
| 311 | + else if ($type == Redis::REDIS_LIST) |
| 312 | + $value = $redis->lrange(0, -1); |
| 313 | + else if ($type == Redis::REDIS_SET || $type == Redis::REDIS_ZSET) { |
| 314 | + $it = null; |
| 315 | + $value = array(); |
| 316 | + |
| 317 | + do { |
| 318 | + $res = $redis->sscan($key, $it); |
| 319 | + |
| 320 | + if (!is_array($res)) |
| 321 | + continue; |
| 322 | + |
| 323 | + $value = array_merge($value, $res); |
| 324 | + } while ($it > 0); |
| 325 | + } |
| 326 | + else if ($type == Redis::REDIS_ZSET) { |
| 327 | + $len = $redis->zcard($key); |
| 328 | + $start = 0; |
| 329 | + $value = array(); |
| 330 | + |
| 331 | + while($start < $len) { |
| 332 | + $stop = $start + 99; |
| 333 | + |
| 334 | + $res = $redis->zrange($key, $start, $stop, true); |
| 335 | + |
| 336 | + $start += 100; |
| 337 | + } |
| 338 | + } |
| 339 | + |
| 340 | + return $value; |
| 341 | + } |
| 342 | + |
| 343 | + function redis_keys($selector) { |
| 344 | + global $redis; |
| 345 | + $keys = array(); |
| 346 | + |
| 347 | + $it = null; |
| 348 | + do { |
| 349 | + $res = $redis->scan($it); |
| 350 | + |
| 351 | + if (!is_array($res)) |
| 352 | + continue; |
| 353 | + |
| 354 | + foreach ($res as $key) { |
| 355 | + if (!preg_match($selector, $key)) |
| 356 | + continue; |
| 357 | + |
| 358 | + $keys[$key] = array( |
| 359 | + 'key' => $key, |
| 360 | + 'ttl' => $redis->ttl($key), |
| 361 | + 'type' => $redis->type($key), |
| 362 | + 'size' => $redis->rawCommand('memory', 'usage', $key) |
| 363 | + ); |
| 364 | + } |
| 365 | + |
| 366 | + } while($it > 0); |
| 367 | + |
| 368 | + return $keys; |
| 369 | + } |
| 370 | + |
226 | 371 | function human_size( $s ) {
|
227 | 372 | $size = 'B';
|
228 | 373 | $sizes = array( 'KB', 'MB', 'GB' );
|
@@ -285,7 +430,7 @@ function sort_url($on) {
|
285 | 430 | return '?' . $query;
|
286 | 431 | }
|
287 | 432 |
|
288 |
| - function sort_list(&$list) { |
| 433 | + function sort_list($list) { |
289 | 434 | if( !isset( $_GET['sort'] ) )
|
290 | 435 | return $list;
|
291 | 436 |
|
@@ -676,6 +821,74 @@ function sort_list(&$list) {
|
676 | 821 | <?php endif; ?>
|
677 | 822 | </div>
|
678 | 823 | <?php endif; ?>
|
| 824 | + |
| 825 | + <?php if(ENABLE_REDIS && $redis->isConnected()): ?> |
| 826 | + <h2 id="redis">Redis</h2> |
| 827 | + <div> |
| 828 | + <h3>Memory <?=human_size(redis_mem('used') + redis_mem('hash'))?> of <?=human_size(redis_mem('total'))?></h3> |
| 829 | + <div class="full bar green"> |
| 830 | + <div class="orange" style="width: <?=percentage(redis_mem('used'), redis_mem('total'))?>%"></div> |
| 831 | + <div class="red" style="width: <?=percentage(redis_mem('overhead'), redis_mem('total'))?>%"></div> |
| 832 | + </div> |
| 833 | + <div> |
| 834 | + <h3>Actions</h3> |
| 835 | + <form action="?" method="GET"> |
| 836 | + <label>Cache: |
| 837 | + <button name="action" value="redis_clear">Restart</button> |
| 838 | + </label> |
| 839 | + </form> |
| 840 | + <form action="?" method="GET"> |
| 841 | + <label>Key(s): |
| 842 | + <input name="selector" type="text" value="" placeholder=".*" /> |
| 843 | + </label> |
| 844 | + <button type="submit" name="action" value="redis_select">Select</button> |
| 845 | + <button type="submit" name="action" value="redis_delete">Delete</button> |
| 846 | + </form> |
| 847 | + </div> |
| 848 | + |
| 849 | + <?php if( is_action('redis_view') ): ?> |
| 850 | + <?php $value = redis_get_key(urldecode($_GET['selector']), $found); ?> |
| 851 | + <div> |
| 852 | + <h3>Value for <?=htmlentities('"'.urldecode($_GET['selector']).'"')?></h3> |
| 853 | + <?php if ($found): ?> |
| 854 | + <pre><?=val_to_str($value); ?></pre> |
| 855 | + <?php else: ?> |
| 856 | + <p>Key not found</p> |
| 857 | + <?php endif ?> |
| 858 | + </div> |
| 859 | + <?php endif ?> |
| 860 | + |
| 861 | + <?php if( is_action('redis_select') ): ?> |
| 862 | + <div> |
| 863 | + <table> |
| 864 | + <thead> |
| 865 | + <tr> |
| 866 | + <th><a href="<?=sort_url('key')?>">Key</a></th> |
| 867 | + <th><a href="<?=sort_url('size')?>">Size</a></th> |
| 868 | + <th><a href="<?=sort_url('ttl')?>">TTL</a></th> |
| 869 | + <th>Expires</th> |
| 870 | + <th>Action</th> |
| 871 | + </tr> |
| 872 | + </thead> |
| 873 | + <tbody> |
| 874 | + <?php foreach( sort_list(redis_keys(get_selector())) as $key => $item ):?> |
| 875 | + <tr> |
| 876 | + <td><?=$item['key']?></td> |
| 877 | + <td><?=$item['size']?></td> |
| 878 | + <td><?=$item['ttl']?></td> |
| 879 | + <td><?=($item['ttl'] < 0 ? 'indefinite' : date('Y-m-d H:i', time() + $item['ttl'] ))?></td> |
| 880 | + <td> |
| 881 | + <a href="?action=redis_delete&selector=<?=urlencode('^'.$key.'$')?>">Delete</a> |
| 882 | + <a href="?action=redis_view&selector=<?=urlencode($key)?>">View</a> |
| 883 | + </td> |
| 884 | + </tr> |
| 885 | + <?php endforeach; ?> |
| 886 | + </tbody> |
| 887 | + </table> |
| 888 | + </div> |
| 889 | + <?php endif; ?> |
| 890 | + </div> |
| 891 | + <?php endif; ?> |
679 | 892 | </div>
|
680 | 893 | </body>
|
681 | 894 | </html>
|
0 commit comments