Skip to content

Commit 9e4dbac

Browse files
committed
[memcache] add Memcached and partial Memcache support
The `memcache` extension should be consiered legacy since it has not had a new release since 2013 and is not supported in recent version of PHP. For this reason some functionality might not work without the newer `memcached` extension
1 parent bfa327c commit 9e4dbac

File tree

3 files changed

+200
-3
lines changed

3 files changed

+200
-3
lines changed

cache.php

Lines changed: 183 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
<?php
2+
3+
// Hides error when no default timezone has been set
4+
$TZ = @date_default_timezone_get();
5+
date_default_timezone_set($TZ);
6+
27
define('ENABLE_APC', extension_loaded('apcu') || extension_loaded('apc'));
38
define('ENABLE_OPCACHE', extension_loaded('Zend OPcache'));
49
define('ENABLE_REALPATH', function_exists('realpath_cache_size'));
10+
define('ENABLE_MEMCACHE', extension_loaded('memcache') || extension_loaded('memcached'));
511

612
if (ENABLE_APC) {
713
if (!extension_loaded('apcu')) {
@@ -34,6 +40,46 @@ function __construct($search = null) { parent::__construct('user', $search); }
3440
$realpathCacheTotal = machine_size(ini_get('realpath_cache_size'));
3541
}
3642

43+
if (ENABLE_MEMCACHE) {
44+
if (extension_loaded('memcached')) {
45+
$memcache = new \Memcached();
46+
$memcacheVersion = 'memcached';
47+
$memcache->addServer('127.0.0.1', 11211);
48+
$memcache_stats = $memcache->getStats();
49+
} else if (extension_loaded('memcache')) {
50+
$memcache = new \Memcache();
51+
$memcacheVersion = 'memcache';
52+
$memcache->addServer('127.0.0.1', 11211);
53+
$memcache_stats = $memcache->getExtendedStats();
54+
}
55+
56+
if( is_action('memcache_clear') ) {
57+
$memcache->flush();
58+
redirect('?');
59+
}
60+
61+
if( is_action('memcache_delete') && $memcacheVersion == 'memcached' ) {
62+
$list = memcache_ref();
63+
$selector = get_selector();
64+
65+
foreach ($list as $key => $item)
66+
if (preg_match($selector, $key))
67+
$memcache->delete($key);
68+
69+
redirect( '?action=memcache_select&selector=' . $_GET['selector'] );
70+
}
71+
72+
if( is_action('memcache_delete') && $memcacheVersion != 'memcached' ) {
73+
$memcache->delete($_GET['selector']);
74+
75+
redirect( '?action=memcache_view&selector=' . $_GET['selector'] );
76+
}
77+
}
78+
79+
function val_to_str($value) {
80+
return htmlentities(var_export($value, true));
81+
}
82+
3783
function is_action($action) {
3884
return isset( $_GET['action'] ) && $_GET['action'] == $action;
3985
}
@@ -104,6 +150,66 @@ function apcu_ref() {
104150
return array();
105151
}
106152

153+
function memcache_mem( $key ) {
154+
global $memcache_stats;
155+
156+
if( $key == 'free' )
157+
return memcache_mem('total') - memcache_mem('used');
158+
159+
if( $key == 'total')
160+
$key = 'limit_maxbytes';
161+
162+
if( $key == 'used' )
163+
$key = 'bytes';
164+
165+
if( $key == 'hash' )
166+
$key = 'hash_bytes';
167+
168+
$result = 0;
169+
foreach( $memcache_stats as $server )
170+
$result += empty($server[$key]) ? 0 : $server[$key];
171+
172+
return $result;
173+
}
174+
175+
function memcache_get_key($key, &$found = false) {
176+
global $memcache;
177+
global $memcacheVersion;
178+
179+
if (empty($key)) {
180+
$found = false;
181+
return false;
182+
}
183+
184+
if ($memcacheVersion == 'memcache') {
185+
$val = $memcache->get(array($key));
186+
$found = count($val) > 0;
187+
return $found ? array_pop($val) : false;
188+
}
189+
190+
$val = $memcache->get($key, null, Memcached::GET_EXTENDED);
191+
$found = $val !== false;
192+
return $val['value'];
193+
}
194+
195+
function memcache_ref() {
196+
global $memcache;
197+
198+
// Listing keys is not supported using the legacy Memcache module
199+
// PHP 7 and newer do not support this extension anymore
200+
if (!extension_loaded('memcached'))
201+
return array();
202+
203+
$items = $memcache->getAllKeys();
204+
205+
$keys = array();
206+
foreach( $items as $item ) {
207+
$keys[$item] = memcache_get_key($item);
208+
}
209+
210+
return $keys;
211+
}
212+
107213
function human_size( $s ) {
108214
$size = 'B';
109215
$sizes = array( 'KB', 'MB', 'GB' );
@@ -383,7 +489,7 @@ function sort_list(&$list) {
383489
<?php if( is_action('apcu_view') ): ?>
384490
<div>
385491
<h3>Value for <?=htmlentities('"'.$_GET['selector'].'"')?></h3>
386-
<pre><?=htmlentities(var_export(apcu_fetch(urldecode($_GET['selector'])), true)); ?></pre>
492+
<pre><?=val_to_str(apcu_fetch(urldecode($_GET['selector']))); ?></pre>
387493
</div>
388494
<?php endif; ?>
389495
<?php if( is_action('apcu_select') ): ?>
@@ -477,6 +583,82 @@ function sort_list(&$list) {
477583
<?php endif; ?>
478584
</div>
479585
<?php endif; ?>
586+
587+
<?php if(ENABLE_MEMCACHE): ?>
588+
<?php $list = memcache_ref(); ?>
589+
<h2 id="memcached">Memcached</h2>
590+
<div>
591+
<h3>Memory <?=human_size(memcache_mem('used') + memcache_mem('hash'))?> of <?=human_size(memcache_mem('total'))?></h3>
592+
<div class="full bar green">
593+
<div class="orange" style="width: <?=percentage(memcache_mem('used'), memcache_mem('total'))?>%"></div>
594+
<div class="red" style="width: <?=percentage(memcache_mem('hash'), memcache_mem('total'))?>%"></div>
595+
</div>
596+
<div>
597+
<h3>Actions</h3>
598+
<form action="?" method="GET">
599+
<label>Cache:
600+
<button name="action" value="memcache_clear">Restart</button>
601+
</label>
602+
</form>
603+
<form action="?" method="GET">
604+
<label>Key(s):
605+
<input name="selector" type="text" value="" placeholder=".*" />
606+
</label>
607+
<?php if ($memcacheVersion == 'memcached'): ?>
608+
<button type="submit" name="action" value="memcache_select">Select</button>
609+
<?php else: ?>
610+
<button type="submit" name="action" value="memcache_view">View</button>
611+
<?php endif ?>
612+
<button type="submit" name="action" value="memcache_delete">Delete</button>
613+
</form>
614+
</div>
615+
616+
<?php if( is_action('memcache_view') ): ?>
617+
<?php $value = memcache_get_key($_GET['selector'], $found); ?>
618+
<div>
619+
<h3>Value for <?=htmlentities('"'.$_GET['selector'].'"')?></h3>
620+
<?php if ($found): ?>
621+
<pre><?=val_to_str($value); ?></pre>
622+
<?php else: ?>
623+
<p>Key not found</p>
624+
<?php endif ?>
625+
</div>
626+
<?php endif ?>
627+
628+
<?php if ($memcacheVersion == 'memcached'): ?>
629+
<?php if( is_action('memcache_select') ): ?>
630+
<div>
631+
<table>
632+
<thead>
633+
<tr>
634+
<th><a href="<?=sort_url('key')?>">Key</a></th>
635+
<th>Action</th>
636+
</tr>
637+
</thead>
638+
<tbody>
639+
<?php foreach( sort_list($list) as $key => $value ):
640+
if( !preg_match(get_selector(), $key) ) continue;?>
641+
<tr>
642+
<td><?=$key?></td>
643+
<td>
644+
<a href="?action=memcache_delete&selector=<?=urlencode('^'.$key.'$')?>">Delete</a>
645+
<a href="?action=memcache_view&selector=<?=urlencode($key)?>">View</a>
646+
</td>
647+
</tr>
648+
<?php endforeach; ?>
649+
</tbody>
650+
</table>
651+
</div>
652+
<?php endif; ?>
653+
<?php else: ?>
654+
<p style="text-align: center">
655+
Legacy <a href="https://pecl.php.net/package/memcache">memcache extension</a> does not support listing keys
656+
<br />
657+
Please install the newer <a href="https://pecl.php.net/package/memcached">memcached extension</a>
658+
</p>
659+
<?php endif; ?>
660+
</div>
661+
<?php endif; ?>
480662
</div>
481663
</body>
482664
</html>

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,8 @@
1313
"name": "Jorgen Evens",
1414
"email": "jorgen@evens.eu"
1515
}
16-
]
16+
],
17+
"scripts": {
18+
"dev": "php -S 127.0.0.1:8181"
19+
}
1720
}

demo/index.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
* DEMO PAGE
44
*
55
* This page is only use to load the demo on Heroku!
6+
* This page requires PHP >= 7
67
*
78
* Please use the `cache.php` file directly for your own deployments.
89
*/
910
class CacheDemoClass {
1011
public $hello = 'world';
1112
}
1213

13-
if (!preg_match('#herokuapp.com#', $_SERVER['HTTP_REFERER'] ?? '')) {
14+
define('INIT', !preg_match('#herokuapp.com|localhost|127.0.0.1#', $_SERVER['HTTP_REFERER'] ?? ''));
15+
16+
if (INIT) {
1417
apcu_store('type.bool.true', true);
1518
apcu_store('type.bool.false', true);
1619
apcu_store('type.numeric.10', 10);
@@ -25,4 +28,13 @@ class CacheDemoClass {
2528
apcu_store('type.class-instance', new CacheDemoClass(), 3600);
2629
}
2730

31+
if (INIT) {
32+
$memcache = new \Memcached();
33+
$memcache->addServer('127.0.0.1', 11211);
34+
35+
$memcache->add('type.array', ['abc', 'def']);
36+
$memcache->add('type.string', 'hello-world');
37+
$memcache->add('type.ttl.string', 'hello-world', time() + 3600);
38+
}
39+
2840
require_once('../cache.php');

0 commit comments

Comments
 (0)