diff --git a/other/cachetools/MemcacheAdmin/Config/Memcache.php b/other/cachetools/MemcacheAdmin/Config/Memcache.php new file mode 100644 index 000000000..14a4fa9cf --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Config/Memcache.php @@ -0,0 +1,28 @@ + 'Server', + 'slabs_api' => 'Server', + 'items_api' => 'Server', + 'get_api' => 'Server', + 'set_api' => 'Server', + 'delete_api' => 'Server', + 'flush_all_api' => 'Server', + 'connection_timeout' => '1', + 'max_item_dump' => '100', + 'refresh_rate' => 5, + 'memory_alert' => '80', + 'hit_rate_alert' => '90', + 'eviction_alert' => '0', + 'file_path' => 'Temp/', + 'servers' => + array ( + 'Default' => + array ( + '127.0.0.1:11211' => + array ( + 'hostname' => '127.0.0.1', + 'port' => '11211', + ), + ), + ), +); \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Analysis.php b/other/cachetools/MemcacheAdmin/Library/Analysis.php new file mode 100644 index 000000000..5d5689bcd --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Analysis.php @@ -0,0 +1,332 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Analysis of memcached command response + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +class Library_Analysis +{ + /** + * Merge two arrays of stats from MemCacheAdmin_ServerCommands::stats() + * + * @param $array Statistic from MemCacheAdmin_ServerCommands::stats() + * @param $stats Statistic from MemCacheAdmin_ServerCommands::stats() + * + * @return Array + */ + public static function merge($array, $stats) + { + # Checking input + if(!is_array($array)) + { + return $stats; + } + elseif(!is_array($stats)) + { + return $array; + } + + # Merging Stats + foreach($stats as $key => $value) + { + if(isset($array[$key]) && ($key != 'version') && ($key != 'uptime')) + { + $array[$key] += $value; + } + else + { + $array[$key] = $value; + } + } + return $array; + } + + /** + * Diff two arrays of stats from MemCacheAdmin_ServerCommands::stats() + * + * @param Array $array Statistic from MemCacheAdmin_ServerCommands::stats() + * @param Array $stats Statistic from MemCacheAdmin_ServerCommands::stats() + * + * @return Array + */ + public static function diff($array, $stats) + { + # Checking input + if(!is_array($array)) + { + return $stats; + } + elseif(!is_array($stats)) + { + return $array; + } + + # Diff for each key + foreach($stats as $key => $value) + { + if(isset($array[$key])) + { + $stats[$key] = $value - $array[$key]; + } + } + + return $stats; + } + + /** + * Analyse and return memcache stats command + * + * @param Array $stats Statistic from MemCacheAdmin_ServerCommands::stats() + * + * @return Array + */ + public static function stats($stats) + { + if(!is_array($stats) || (count($stats) == 0)) + { + return false; + } + + # Command set() + $stats['set_rate'] = ($stats['cmd_set'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_set'] / $stats['uptime'], 1); + + # Command get() + $stats['get_hits_percent'] = ($stats['cmd_get'] == 0) ? ' - ' : sprintf('%.1f', $stats['get_hits'] / $stats['cmd_get'] * 100, 1); + $stats['get_misses_percent'] = ($stats['cmd_get'] == 0) ? ' - ' : sprintf('%.1f', $stats['get_misses'] / $stats['cmd_get'] * 100, 1); + $stats['get_rate'] = ($stats['cmd_get'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_get'] / $stats['uptime'], 1); + + # Command delete(), version > 1.2.X + if(isset($stats['delete_hits'], $stats['delete_misses'])) + { + $stats['cmd_delete'] = $stats['delete_hits'] + $stats['delete_misses']; + $stats['delete_hits_percent'] = ($stats['cmd_delete'] == 0) ? ' - ' : sprintf('%.1f', $stats['delete_hits'] / $stats['cmd_delete'] * 100, 1); + $stats['delete_misses_percent'] = ($stats['cmd_delete'] == 0) ? ' - ' : sprintf('%.1f', $stats['delete_misses'] / $stats['cmd_delete'] * 100, 1); + } + else + { + $stats['cmd_delete'] = 0; + $stats['delete_hits_percent'] = ' - '; + $stats['delete_misses_percent'] = ' - '; + } + $stats['delete_rate'] = ($stats['cmd_delete'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_delete'] / $stats['uptime'], 1); + + # Command cas(), version > 1.2.X + if(isset($stats['cas_hits'], $stats['cas_misses'], $stats['cas_badval'])) + { + $stats['cmd_cas'] = $stats['cas_hits'] + $stats['cas_misses'] + $stats['cas_badval']; + $stats['cas_hits_percent'] = ($stats['cmd_cas'] == 0) ? ' - ' : sprintf('%.1f', $stats['cas_hits'] / $stats['cmd_cas'] * 100, 1); + $stats['cas_misses_percent'] = ($stats['cmd_cas'] == 0) ? ' - ' : sprintf('%.1f', $stats['cas_misses'] / $stats['cmd_cas'] * 100, 1); + $stats['cas_badval_percent'] = ($stats['cmd_cas'] == 0) ? ' - ' : sprintf('%.1f', $stats['cas_badval'] / $stats['cmd_cas'] * 100, 1); + } + else + { + $stats['cmd_cas'] = 0; + $stats['cas_hits_percent'] = ' - '; + $stats['cas_misses_percent'] = ' - '; + $stats['cas_badval_percent'] = ' - '; + } + $stats['cas_rate'] = ($stats['cmd_cas'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_cas'] / $stats['uptime'], 1); + + # Command increment(), version > 1.2.X + if(isset($stats['incr_hits'], $stats['incr_misses'])) + { + $stats['cmd_incr'] = $stats['incr_hits'] + $stats['incr_misses']; + $stats['incr_hits_percent'] = ($stats['cmd_incr'] == 0) ? ' - ' : sprintf('%.1f', $stats['incr_hits'] / $stats['cmd_incr'] * 100, 1); + $stats['incr_misses_percent'] = ($stats['cmd_incr'] == 0) ? ' - ' : sprintf('%.1f', $stats['incr_misses'] / $stats['cmd_incr'] * 100, 1); + } + else + { + $stats['cmd_incr'] = 0; + $stats['incr_hits_percent'] = ' - '; + $stats['incr_misses_percent'] = ' - '; + + } + $stats['incr_rate'] = ($stats['cmd_incr'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_incr'] / $stats['uptime'], 1); + + # Command decrement(), version > 1.2.X + if(isset($stats['decr_hits'], $stats['decr_misses'])) + { + $stats['cmd_decr'] = $stats['decr_hits'] + $stats['decr_misses']; + $stats['decr_hits_percent'] = ($stats['cmd_decr'] == 0) ? ' - ' : sprintf('%.1f', $stats['decr_hits'] / $stats['cmd_decr'] * 100, 1); + $stats['decr_misses_percent'] = ($stats['cmd_decr'] == 0) ? ' - ' : sprintf('%.1f', $stats['decr_misses'] / $stats['cmd_decr'] * 100, 1); + } + else + { + $stats['cmd_decr'] = 0; + $stats['decr_hits_percent'] = ' - '; + $stats['decr_misses_percent'] = ' - '; + } + $stats['decr_rate'] = ($stats['cmd_decr'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_decr'] / $stats['uptime'], 1); + + # Total hit & miss + #$stats['cmd_total'] = $stats['cmd_get'] + $stats['cmd_set'] + $stats['cmd_delete'] + $stats['cmd_cas'] + $stats['cmd_incr'] + $stats['cmd_decr']; + #$stats['hit_percent'] = ($stats['cmd_get'] == 0) ? '0.0' : sprintf('%.1f', ($stats['get_hits']) / ($stats['get_hits'] + $stats['get_misses']) * 100, 1); + #$stats['miss_percent'] = ($stats['cmd_get'] == 0) ? '0.0' : sprintf('%.1f', ($stats['get_misses']) / ($stats['get_hits'] + $stats['get_misses']) * 100, 1); + + # Command flush_all + if(isset($stats['cmd_flush'])) + { + $stats['flush_rate'] = ($stats['cmd_flush'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_flush'] / $stats['uptime'], 1); + } + else + { + $stats['flush_rate'] = '0.0'; + } + + # Cache size + $stats['bytes_percent'] = ($stats['limit_maxbytes'] == 0) ? '0.0' : sprintf('%.1f', $stats['bytes'] / $stats['limit_maxbytes'] * 100, 1); + + # Request rate + $stats['request_rate'] = sprintf('%.1f', ($stats['cmd_get'] + $stats['cmd_set'] + $stats['cmd_delete'] + $stats['cmd_cas'] + $stats['cmd_incr'] + $stats['cmd_decr']) / $stats['uptime'], 1); + $stats['hit_rate'] = sprintf('%.1f', ($stats['get_hits']) / $stats['uptime'], 1); + $stats['miss_rate'] = sprintf('%.1f', ($stats['get_misses']) / $stats['uptime'], 1); + + # Eviction & reclaimed rate + $stats['eviction_rate'] = ($stats['evictions'] == 0) ? '0.0' : sprintf('%.1f', $stats['evictions'] / $stats['uptime'], 1); + $stats['reclaimed_rate'] = (!isset($stats['reclaimed']) || ($stats['reclaimed'] == 0)) ? '0.0' : sprintf('%.1f', $stats['reclaimed'] / $stats['uptime'], 1); + + return $stats; + } + + /** + * Analyse and return memcache slabs command + * + * @param Array $slabs Statistic from MemCacheAdmin_ServerCommands::slabs() + * + * @return Array + */ + public static function slabs($slabs) + { + # Initializing Used Slabs + $slabs['used_slabs'] = 0; + $slabs['total_wasted'] = 0; + # Request Rate par Slabs + foreach($slabs as $id => $slab) + { + # Check if it's a Slab + if(is_numeric($id)) + { + # Check if Slab is used + if($slab['used_chunks'] > 0) + { + $slabs['used_slabs']++; + } + $slabs[$id]['request_rate'] = sprintf('%.1f', ($slab['get_hits'] + $slab['cmd_set'] + $slab['delete_hits'] + $slab['cas_hits'] + $slab['cas_badval'] + $slab['incr_hits'] + $slab['decr_hits']) / $slabs['uptime'], 1); + $slabs[$id]['mem_wasted'] = (($slab['total_chunks'] * $slab['chunk_size']) < $slab['mem_requested']) ?(($slab['total_chunks'] - $slab['used_chunks']) * $slab['chunk_size']):(($slab['total_chunks'] * $slab['chunk_size']) - $slab['mem_requested']); + $slabs['total_wasted'] += $slabs[$id]['mem_wasted']; + } + } + return $slabs; + } + + /** + * Calculate Uptime + * + * @param Integer $uptime Uptime timestamp + * + * @return String + */ + public static function uptime($uptime) + { + if($uptime > 0) + { + $days = floor($uptime/60/60/24); + $hours = $uptime/60/60%24; + $mins = $uptime/60%60; + if(($days + $hours + $mins) == 0) + { + return ' less than 1 min'; + } + return $days . ' days ' . $hours . ' hrs ' . $mins . ' min'; + } + return ' - '; + } + + /** + * Resize a byte value + * + * @param Integer $value Value to resize + * + * @return String + */ + public static function byteResize($value) + { + # Unit list + $units = array('', 'K', 'M', 'G', 'T'); + + # Resizing + foreach($units as $unit) + { + if($value < 1024) + { + break; + } + $value /= 1024; + } + return sprintf('%.1f %s', $value, $unit); + } + + /** + * Resize a value + * + * @param Integer $value Value to resize + * + * @return String + */ + public static function valueResize($value) + { + # Unit list + $units = array('', 'K', 'M', 'G', 'T'); + + # Resizing + foreach($units as $unit) + { + if($value < 1000) + { + break; + } + $value /= 1000; + } + return sprintf('%.1f%s', $value, $unit); + } + + /** + * Resize a hit value + * + * @param Integer $value Hit value to resize + * + * @return String + */ + public static function hitResize($value) + { + # Unit list + $units = array('', 'K', 'M', 'G', 'T'); + + # Resizing + foreach($units as $unit) + { + if($value < 10000000) + { + break; + } + $value /= 1000; + } + return sprintf('%.0f%s', $value, $unit); + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Factory.php b/other/cachetools/MemcacheAdmin/Library/Command/Factory.php new file mode 100644 index 000000000..a94d930d2 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Factory.php @@ -0,0 +1,111 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Factory for communication with Memcache Server + * + * @author c.mahieux@of2m.fr + * @since 30/03/2010 + */ +class Library_Command_Factory +{ + private static $_object = array(); + + # No explicit call of constructor + private function __construct() {} + + # No explicit call of clone() + private function __clone() {} + + /** + * Accessor to command class instance by command type + * + * @param String $command Type of command + * + * @return void + */ + public static function instance($command) + { + # Importing configuration + $_ini = Library_Configuration_Loader::singleton(); + + # Instance does not exists + if(!isset(self::$_object[$_ini->get($command)]) || ($_ini->get($command) != 'Server')) + { + # Switching by API + switch($_ini->get($command)) + { + case 'Memcache': + # PECL Memcache API + require_once 'Memcache.php'; + self::$_object['Memcache'] = new Library_Command_Memcache(); + break; + + case 'Memcached': + # PECL Memcached API + require_once 'Memcached.php'; + self::$_object['Memcached'] = new Library_Command_Memcached(); + break; + + case 'Server': + default: + # Server API (eg communicating directly with the memcache server) + require_once 'Server.php'; + self::$_object['Server'] = new Library_Command_Server(); + break; + } + } + return self::$_object[$_ini->get($command)]; + } + + /** + * Accessor to command class instance by type + * + * @param String $command Type of command + * + * @return void + */ + public static function api($api) + { + # Instance does not exists + if(!isset(self::$_object[$api]) || ($api != 'Server')) + { + # Switching by API + switch($api) + { + case 'Memcache': + # PECL Memcache API + require_once 'Memcache.php'; + self::$_object['Memcache'] = new Library_Command_Memcache(); + break; + + case 'Memcached': + # PECL Memcached API + require_once 'Memcached.php'; + self::$_object['Memcached'] = new Library_Command_Memcached(); + break; + + case 'Server': + default: + # Server API (eg communicating directly with the memcache server) + require_once 'Server.php'; + self::$_object['Server'] = new Library_Command_Server(); + break; + } + } + return self::$_object[$api]; + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Interface.php b/other/cachetools/MemcacheAdmin/Library/Command/Interface.php new file mode 100644 index 000000000..cf080c903 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Interface.php @@ -0,0 +1,139 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Interface of communication to MemCache Server + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +interface Library_Command_Interface +{ + /** + * Constructor + * + * @return void + */ + function __construct(); + + /** + * Send stats command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + function stats($server, $port); + + /** + * Retrieve slabs stats + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + function slabs($server, $port); + + /** + * Retrieve items from a slabs + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $slab Slab ID + * + * @return Array|Boolean + */ + function items($server, $port, $slab); + + /** + * Send get command to server to retrieve an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to retrieve + * + * @return String + */ + function get($server, $port, $key); + + /** + * Set an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to store + * @param Mixed $data Data to store + * @param Integer $duration Duration + * + * @return String + */ + function set($server, $port, $key, $data, $duration); + + /** + * Delete an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to delete + * + * @return String + */ + function delete($server, $port, $key); + + /** + * Flush all items on a server after delay + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $delay Delay before flushing server + * + * @return String + */ + function flush_all($server, $port, $delay); + + /** + * Search for item + * Return all the items matching parameters if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to search + * + * @return array + */ + function search($server, $port, $search); + + /** + * Execute a telnet command on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $command Command to execute + * + * @return String + */ + function telnet($server, $port, $command); +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Memcache.php b/other/cachetools/MemcacheAdmin/Library/Command/Memcache.php new file mode 100644 index 000000000..5808cb042 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Memcache.php @@ -0,0 +1,257 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Sending command to memcache server via PECL memcache API http://pecl.php.net/package/memcache + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +class Library_Command_Memcache implements Library_Command_Interface +{ + private static $_ini; + private static $_memcache; + + /** + * Constructor + * + * @param Array $ini Array from ini_parse + * + * @return void + */ + public function __construct() + { + # Importing configuration + self::$_ini = Library_Configuration_Loader::singleton(); + + # Initializing + self::$_memcache = new Memcache(); + } + + /** + * Send stats command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function stats($server, $port) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command + if(($return = self::$_memcache->getExtendedStats())) + { + # Delete server key based + $stats = $return[$server.':'.$port]; + return $stats; + } + return false; + } + + /** + * Send stats items command to server to retrieve slabs stats + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function slabs($server, $port) + { + # Initializing + $slabs = array(); + + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : slabs + if(($slabs = self::$_memcache->getStats('slabs'))) + { + # Finding uptime + $stats = $this->stats($server, $port); + $slabs['uptime'] = $stats['uptime']; + unset($stats); + + # Executing command : items + if(($result = self::$_memcache->getStats('items'))) + { + # Indexing by slabs + foreach($result['items'] as $id => $items) + { + foreach($items as $key => $value) + { + $slabs[$id]['items:' . $key] = $value; + } + } + return $slabs; + } + } + return false; + } + + /** + * Send stats cachedump command to server to retrieve slabs items + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Interger $slab Slab ID + * + * @return Array|Boolean + */ + public function items($server, $port, $slab) + { + # Initializing + $items = false; + + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : slabs stats + if(($items = self::$_memcache->getStats('cachedump', $slab, self::$_ini->get('max_item_dump')))) + { + return $items; + } + return false; + } + + /** + * Send get command to server to retrieve an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to retrieve + * + * @return String + */ + public function get($server, $port, $key) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : get + if($item = self::$_memcache->get($key)) + { + return print_r($item, true); + } + return 'NOT_FOUND'; + } + + /** + * Set an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to store + * @param Mixed $data Data to store + * @param Integer $duration Duration + * + * @return String + */ + function set($server, $port, $key, $data, $duration) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : set + if(self::$_memcache->set($key, $data, 0, $duration)) + { + return 'STORED'; + } + return 'ERROR'; + } + + /** + * Delete an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to delete + * + * @return String + */ + public function delete($server, $port, $key) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : delete + if(self::$_memcache->delete($key)) + { + return 'DELETED'; + } + return 'NOT_FOUND'; + } + + /** + * Flush all items on a server + * Warning, delay won't work with Memcache API + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $delay Delay before flushing server + * + * @return String + */ + function flush_all($server, $port, $delay) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : flush_all + self::$_memcache->flush(); + return 'OK'; + } + + /** + * Search for item + * Return all the items matching parameters if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to search + * + * @return array + */ + function search($server, $port, $search) + { + throw new Exception('PECL Memcache does not support search function, use Server instead'); + } + + /** + * Execute a telnet command on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $command Command to execute + * + * @return String + */ + function telnet($server, $port, $command) + { + throw new Exception('PECL Memcache does not support telnet, use Server instead'); + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Memcached.php b/other/cachetools/MemcacheAdmin/Library/Command/Memcached.php new file mode 100644 index 000000000..2493b1740 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Memcached.php @@ -0,0 +1,226 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Sending command to memcache server via PECL memcache API http://pecl.php.net/package/memcache + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +class Library_Command_Memcached implements Library_Command_Interface +{ + private static $_ini; + private static $_memcache; + + /** + * Constructor + * + * @param Array $ini Array from ini_parse + * + * @return void + */ + public function __construct() + { + # Importing configuration + self::$_ini = Library_Configuration_Loader::singleton(); + + # Initializing + self::$_memcache = new Memcached(); + } + + /** + * Send stats command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function stats($server, $port) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command + if(($return = self::$_memcache->getStats())) + { + # Delete server key based + $stats = $return[$server.':'.$port]; + + # Adding value that miss + $stats['delete_hits'] = ''; + $stats['delete_misses'] = ''; + $stats['incr_hits'] = ''; + $stats['incr_misses'] = ''; + $stats['decr_hits'] = ''; + $stats['decr_misses'] = ''; + $stats['cas_hits'] = ''; + $stats['cas_misses'] = ''; + $stats['cas_badval'] = ''; + + return $stats; + } + return false; + } + + /** + * Send stats items command to server to retrieve slabs stats + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function slabs($server, $port) + { + throw new Exception('PECL Memcache does not support slabs stats, use Server or Memcache instead'); + } + + /** + * Send stats cachedump command to server to retrieve slabs items + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Interger $slab Slab ID + * + * @return Array|Boolean + */ + public function items($server, $port, $slab) + { + throw new Exception('PECL Memcache does not support slabs items stats, use Server or Memcache instead'); + } + + /** + * Send get command to server to retrieve an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to retrieve + * + * @return String + */ + public function get($server, $port, $key) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : get + if($item = self::$_memcache->get($key)) + { + return print_r($item, true); + } + return self::$_memcache->getResultMessage(); + } + + /** + * Set an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to store + * @param Mixed $data Data to store + * @param Integer $duration Duration + * + * @return String + */ + function set($server, $port, $key, $data, $duration) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Checking duration + if($duration == '') { $duration = 0; } + + # Executing command : set + self::$_memcache->set($key, $data, $duration); + return self::$_memcache->getResultMessage(); + } + + /** + * Delete an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to delete + * + * @return String + */ + public function delete($server, $port, $key) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : delete + self::$_memcache->delete($key); + return self::$_memcache->getResultMessage(); + } + + /** + * Flush all items on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $delay Delay before flushing server + * + * @return String + */ + public function flush_all($server, $port, $delay) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : delete + self::$_memcache->flush($delay); + return self::$_memcache->getResultMessage(); + } + + /** + * Search for item + * Return all the items matching parameters if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to search + * + * @return array + */ + function search($server, $port, $search) + { + throw new Exception('PECL Memcached does not support search function, use Server instead'); + } + + /** + * Execute a telnet command on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $command Command to execute + * + * @return String + */ + function telnet($server, $port, $command) + { + throw new Exception('PECL Memcached does not support telnet, use Server instead'); + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Server.php b/other/cachetools/MemcacheAdmin/Library/Command/Server.php new file mode 100644 index 000000000..7d44f2076 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Server.php @@ -0,0 +1,443 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Sending command to memcache server + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +class Library_Command_Server implements Library_Command_Interface +{ + private static $_ini; + private static $_log; + + /** + * Constructor + * + * @param Array $ini Array from ini_parse + * + * @return void + */ + public function __construct() + { + # Importing configuration + self::$_ini = Library_Configuration_Loader::singleton(); + } + + /** + * Executing a Command on a MemCache Server + * With the help of http://github.com/memcached/memcached/blob/master/doc/protocol.txt + * Return the response, or false otherwise + * + * @param String $command Command + * @param String $server Server Hostname + * @param Integer $port Server Port + * + * @return String|Boolean + */ + public function exec($command, $server, $port) + { + # Variables + $buffer = ''; + $handle = null; + + # Socket Opening + if(!($handle = @fsockopen($server, $port, $errno, $errstr, self::$_ini->get('connection_timeout')))) + { + # Adding error to log + self::$_log = utf8_encode($errstr); + Library_Data_Error::add(utf8_encode($errstr)); + return false; + } + + # Sending Command ... + fwrite($handle, $command . "\r\n"); + + # Getting first line + $buffer = fgets($handle); + + # Checking if result is valid + if($this->end($buffer)) + { + # Closing socket + fclose($handle); + + # Adding error to log + self::$_log = $buffer; + + return false; + } + + # Reading Results + while((!feof($handle))) + { + # Getting line + $line = fgets($handle); + $buffer .= $line; + + # Checking for end of MemCache command + if($this->end($line)) + { + break; + } + } + # Closing socket + fclose($handle); + + return $buffer; + } + + /** + * Check if response is at the end from memcache server + * Return true if response end, true otherwise + * + * @param String $buffer Buffer received from memcache server + * + * @return Boolean + */ + private function end($buffer) + { + # Checking command response end + if(preg_match('/(END|DELETED|OK|ERROR|SERVER_ERROR|CLIENT_ERROR|NOT_FOUND|STORED|RESET)\r\n$/', $buffer)) + { + return true; + } + return false; + } + + /** + * Parse result to make an array + * + * @param String $string String to parse + * @param Boolean $string (optionnal) Parsing stats ? + * + * @return Array + */ + public function parse($string, $stats = true) + { + # Variable + $return = array(); + + # Exploding by \r\n + $lines = preg_split('/\r\n/', $string); + + # Stats + if($stats) + { + # Browsing each line + foreach($lines as $line) + { + $data = preg_split('/ /', $line); + if(isset($data[2])) + { + $return[$data[1]] = $data[2]; + } + } + } + # Items + else + { + # Browsing each line + foreach($lines as $line) + { + $data = preg_split('/ /', $line); + if(isset($data[1])) + { + $return[$data[1]] = array(substr($data[2], 1), $data[4]); + } + } + } + return $return; + } + + /** + * Send stats command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function stats($server, $port) + { + # Executing command + if(($return = $this->exec('stats', $server, $port))) + { + return $this->parse($return); + } + return false; + } + + /** + * Send stats settings command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function settings($server, $port) + { + # Executing command + if(($return = $this->exec('stats settings', $server, $port))) + { + return $this->parse($return); + } + return false; + } + + /** + * Send stats items command to server to retrieve slabs stats + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function slabs($server, $port) + { + # Initializing + $slabs = array(); + + # Finding uptime + $stats = $this->stats($server, $port); + $slabs['uptime'] = $stats['uptime']; + unset($stats); + + # Executing command : slabs stats + if(($result = $this->exec('stats slabs', $server, $port))) + { + # Parsing result + $result = $this->parse($result); + $slabs['active_slabs'] = $result['active_slabs']; + $slabs['total_malloced'] = $result['total_malloced']; + unset($result['active_slabs']); + unset($result['total_malloced']); + + # Indexing by slabs + foreach($result as $key => $value) + { + $key = preg_split('/:/', $key); + $slabs[$key[0]][$key[1]] = $value; + } + + # Executing command : items stats + if(($result = $this->exec('stats items', $server, $port))) + { + # Parsing result + $result = $this->parse($result); + + # Indexing by slabs + foreach($result as $key => $value) + { + $key = preg_split('/:/', $key); + $slabs[$key[1]]['items:' . $key[2]] = $value; + } + + return $slabs; + } + } + return false; + } + + /** + * Send stats cachedump command to server to retrieve slabs items + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Interger $slab Slab ID + * + * @return Array|Boolean + */ + public function items($server, $port, $slab) + { + # Initializing + $items = false; + + # Executing command : stats cachedump + if(($result = $this->exec('stats cachedump ' . $slab . ' ' . self::$_ini->get('max_item_dump'), $server, $port))) + { + # Parsing result + $items = $this->parse($result, false); + } + return $items; + } + + /** + * Send get command to server to retrieve an item + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to retrieve + * + * @return String + */ + public function get($server, $port, $key) + { + # Executing command : get + if(($string = $this->exec('get ' . $key, $server, $port))) + { + return preg_replace('/^VALUE ' . preg_quote($key, '/') . '[0-9 ]*\r\n/', '', $string); + } + return self::$_log; + } + + /** + * Set an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to store + * @param Mixed $data Data to store + * @param Integer $duration Duration + * + * @return String + */ + function set($server, $port, $key, $data, $duration) + { + # Formatting data + $data = preg_replace('/\r/', '', $data); + + # Executing command : set + if(($result = $this->exec('set ' . $key . ' 0 ' . $duration . ' ' . strlen($data) . "\r\n" . $data, $server, $port))) + { + return $result; + } + return self::$_log; + } + + /** + * Delete an item + * Return true if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to delete + * + * @return String + */ + public function delete($server, $port, $key) + { + # Executing command : delete + if(($result = $this->exec('delete ' . $key, $server, $port))) + { + return $result; + } + return self::$_log; + } + + /** + * Flush all items on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $delay Delay before flushing server + * + * @return String + */ + function flush_all($server, $port, $delay) + { + # Executing command : flush_all + if(($result = $this->exec('flush_all ' . $delay, $server, $port))) + { + return $result; + } + return self::$_log; + } + + /** + * Search for item + * Return all the items matching parameters if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to search + * + * @return array + */ + function search($server, $port, $search) + { + $slabs = array(); + $items = false; + + # Executing command : slabs stats + if(($result = $this->exec('stats slabs', $server, $port))) + { + # Parsing result + $result = $this->parse($result); + unset($result['active_slabs']); + unset($result['total_malloced']); + # Indexing by slabs + foreach($result as $key => $value) + { + $key = preg_split('/:/', $key); + $slabs[$key[0]] = true; + } + } + + # Exploring each slabs + foreach($slabs as $slab => $unused) + { + # Executing command : stats cachedump + if(($result = $this->exec('stats cachedump ' . $slab . ' 0', $server, $port))) + { + # Parsing result + preg_match_all('/^ITEM ((?:.*)' . preg_quote($search, '/') . '(?:.*)) \[(?:.*)\]\r\n/mU', $result, $matchs, PREG_SET_ORDER); + + foreach($matchs as $item) + { + $items[] = $item[1]; + } + } + unset($slabs[$slab]); + } + + if(is_array($items)) + { + sort($items); + } + + return $items; + } + + /** + * Execute a telnet command on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $command Command to execute + * + * @return String + */ + function telnet($server, $port, $command) + { + # Executing command + if(($result = $this->exec($command, $server, $port))) + { + return $result; + } + return self::$_log; + } +} diff --git a/other/cachetools/MemcacheAdmin/Library/Configuration/Loader.php b/other/cachetools/MemcacheAdmin/Library/Configuration/Loader.php new file mode 100644 index 000000000..9e2a91baf --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Configuration/Loader.php @@ -0,0 +1,187 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Configuration class for editing, saving, ... + * + * @author c.mahieux@of2m.fr + * @since 19/05/2010 + */ +class Library_Configuration_Loader +{ + # Singleton + protected static $_instance = null; + + # Configuration file + protected static $_iniPath = './Config/Memcache.php'; + + # Configuration needed keys + protected static $_iniKeys = array('stats_api', + 'slabs_api', + 'items_api', + 'get_api', + 'set_api', + 'delete_api', + 'flush_all_api', + 'connection_timeout', + 'max_item_dump', + 'refresh_rate', + 'memory_alert', + 'hit_rate_alert', + 'eviction_alert', + 'file_path', + 'servers'); + + # Storage + protected static $_ini = array(); + + /** + * Constructor, load configuration file and parse server list + * + * @return Void + */ + protected function __construct() + { + # Opening ini file + self::$_ini = require self::$_iniPath; + } + + /** + * Get Library_Configuration_Loader singleton + * + * @return Library_Configuration_Loader + */ + public static function singleton() + { + if(!isset(self::$_instance)) + { + self::$_instance = new self(); + } + return self::$_instance; + } + + /** + * Config key to retrieve + * Return the value, or false if does not exists + * + * @param String $key Key to get + * + * @return Mixed + */ + public function get($key) + { + if(isset(self::$_ini[$key])) + { + return self::$_ini[$key]; + } + return false; + } + + /** + * Servers to retrieve from cluster + * Return the value, or false if does not exists + * + * @param String $cluster Cluster to retreive + * + * @return Array + */ + public function cluster($cluster) + { + if(isset(self::$_ini['servers'][$cluster])) + { + return self::$_ini['servers'][$cluster]; + } + return array(); + } + + /** + * Check and return server data + * Return the value, or false if does not exists + * + * @param String $server Server to retreive + * + * @return Array + */ + public function server($server) + { + foreach(self::$_ini['servers'] as $cluster => $servers) + { + if(isset(self::$_ini['servers'][$cluster][$server])) + { + return self::$_ini['servers'][$cluster][$server]; + } + } + return array(); + } + + /** + * Config key to set + * + * @param String $key Key to set + * @param Mixed $value Value to set + * + * @return Boolean + */ + public function set($key, $value) + { + self::$_ini[$key] = $value; + } + + /** + * Return actual ini file path + * + * @return String + */ + public function path() + { + return self::$_iniPath; + } + + /** + * Check if every ini keys are set + * Return true if ini is correct, false otherwise + * + * @return Boolean + */ + public function check() + { + # Checking configuration keys + foreach(self::$_iniKeys as $iniKey) + { + # Ini file key not set + if(!isset(self::$_ini[$iniKey])) + { + return false; + } + } + return true; + } + + /** + * Write ini file + * Return true if written, false otherwise + * + * @return Boolean + */ + public function write() + { + if($this->check()) + { + return is_numeric(file_put_contents(self::$_iniPath, '<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Error container + * + * @author elijaa@free.fr + * @since 11/10/2010 + */ +class Library_Data_Error +{ + private static $_errors = array(); + + /** + * Add an error to the container + * Return true if successful, false otherwise + * + * @param String $error Error message + * + * @return Boolean + */ + public static function add($error) + { + return array_push(self::$_errors, $error); + } + + /** + * Return last Error message + * + * @return Mixed + */ + public static function last() + { + return (isset(self::$_errors[count(self::$_errors) - 1])) ? self::$_errors[count(self::$_errors) - 1] : null; + } + + /** + * Return errors count + * + * @return Integer + */ + public static function count() + { + return count(self::$_errors); + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/HTML/Components.php b/other/cachetools/MemcacheAdmin/Library/HTML/Components.php new file mode 100644 index 000000000..a94597aaf --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/HTML/Components.php @@ -0,0 +1,147 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Manipulation of HTML + * + * @author c.mahieux@of2m.fr + * @since 05/04/2010 + */ +class Library_HTML_Components +{ + /** + * Dump server list in an HTML select + * + * @return string + */ + public static function serverSelect($name, $selected = '', $class = '', $events = '') + { + # Loading ini file + $_ini = Library_Configuration_Loader::singleton(); + + # Select Name + $serverList = ''; + } + + /** + * Dump cluster list in an HTML select + * + * @return string + */ + public static function clusterSelect($name, $selected = '', $class = '', $events = '') + { + # Loading ini file + $_ini = Library_Configuration_Loader::singleton(); + + # Select Name + $clusterList = ''; + } + + /** + * Dump server response in proper formatting + * + * @param string $hostname Hostname + * @param string $port Port + * @param mixed $data Data (reponse) + * + * @return string + */ + public static function serverResponse($hostname, $port, $data) + { + $header = 'Server ' . $hostname . ':' . $port . "\r\n"; + $return = ''; + if(is_array($data)) + { + foreach($data as $string) + { + $return .= $string . "\r\n"; + } + return $header . htmlentities($return, ENT_NOQUOTES | ENT_IGNORE, "UTF-8") . "\r\n"; + } + return $header . $return . $data . "\r\n"; + } + + /** + * Dump api list un HTML select with select name + * + * @param String $iniAPI API Name from ini file + * @param String $id Select ID + * + * @return String + */ + public static function apiList($iniAPI = '', $id) + { + return ''; + } + + /** + * Used to see if an option is selected + * + * @param String $actual Actual value + * @param String $selected Selected value + * + * @return String + */ + private static function selected($actual, $selected) + { + if($actual == $selected) + { + return 'selected="selected"'; + } + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Loader.php b/other/cachetools/MemcacheAdmin/Library/Loader.php new file mode 100644 index 000000000..24b766374 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Loader.php @@ -0,0 +1,9 @@ +Cluster '+''+'
'+'Add New Server to Cluster Delete Cluster

';clusterDiv.setAttribute('id','cluster_'+cluster_id);document.getElementById('server_form').appendChild(clusterDiv);} +function addServer(current_cluster_id){var serverDiv=document.createElement('div');server_id++;serverDiv.innerHTML='
'+' '+' '+'Delete'+'
';serverDiv.setAttribute('id','server_'+server_id);document.getElementById('cluster_'+current_cluster_id).insertBefore(serverDiv,document.getElementById('cluster_'+current_cluster_id+'_commands'));} +function deleteServerOrCluster(divID){var div=document.getElementById(divID);div.parentNode.removeChild(div);} +function hostnameOnFocus(obj){if(obj.value=='hostname'){obj.value='';}} +function hostnameOnBlur(obj){if(obj.value==''){obj.value='hostname';}} +function portOnFocus(obj){if(obj.value=='port'){obj.value='';}} +function portOnBlur(obj){if(obj.value==''){obj.value='port';}} +function ajax(url,target){if(window.XMLHttpRequest){req=new XMLHttpRequest();req.onreadystatechange=function(){ajaxDone(target);};req.open("GET",url,true);req.send(null);}else if(window.ActiveXObject){req=new ActiveXObject('Microsoft.XMLHTTP');if(req){req.onreadystatechange=function(){ajaxDone(target);};req.open("GET",url,true);req.send();}} +setTimeout("ajax(page, 'stats')",timeout);} +function ajaxDone(target){if(req.readyState==4){if(req.status==200||req.status==304){results=req.responseText;document.getElementById(target).innerHTML=results;}else{document.getElementById(target).innerHTML="Loading stats error : " ++req.statusText;}}} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Public/Styles/Style.css b/other/cachetools/MemcacheAdmin/Public/Styles/Style.css new file mode 100644 index 000000000..bbfa49fef --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Public/Styles/Style.css @@ -0,0 +1 @@ +body{background-color:#FEFEFE;font-family:Verdana,Tahoma,Segoe UI,Arial;font-size:0.8em;margin-top:10px}a{ color:#EEE; text-decoration:none}a:hover{ color:#A00}input,select,textarea{ -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; border:solid 1px #AAA; width:298px; font-family:tahoma; font-size:1em}textarea{ width:494px; resize:none}select{ width:300px}input:focus,textarea:focus{ border:solid 1px #EEE}input:hover{ color:#A00}img{ border:none}/** hr */hr{ height:0; border:none; border-bottom:solid 1px #eee}.menu{ border:solid 1px #a0312a; color:#eee; width:198px}.item{ font-family:Bitstream Vera Sans Mono}#loading{ text-decoration:blink; width:680px; visibility:hidden}.full-size{width:980px}.size-0{width:494px}.size-1{width:696px}.size-2{width:398px}.size-4{width:290px}.size-5{width:226px}.padding{padding:3px 7px 3px 7px}.corner{-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px}.header{border:1px solid #9c3c36;background:url("../Images/b5463f.png") repeat-x scroll 50% 50% #B5463F;font-weight:bold;color:#fff;clear:both}.sub-header{border:1px solid #514845;background:url("../Images/635855.png") repeat-x scroll 50% 50% #635855;font-weight:bold;color:#fff;clear:both;margin-top:10px}.container{border:1px solid #d0d0d0;background:#ebebeb;font-weight:none;color:#000;margin-top:1px;clear:both}.list{border:1px solid #9c3c36;background:#B5463F;font-weight:bold;color:#fff}.button{padding:1px 20px;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px}.live{font-family:Bitstream Vera Sans Mono,Lucida Sans Typewriter,DejaVu Sans Mono;font-size:12px;overflow:visible;white-space:pre-wrap}.line{min-height:18px;padding-top:3px;padding-bottom:2px;clear:both}.left{float:left;min-width:126px;font-weight:bold}.right{float:right}.setting{min-width:180px}.slabs{min-width:104px}.container hr{height:0;border:none;border-bottom:solid 1px #fff}.grey{ color:#EEE}.green{color:#40aaba}.red{background:#b5463f;color:#fff;font-weight:bold} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Temp/live_stats.12857559947a1920d61156abc05a60135aefe8bc67 b/other/cachetools/MemcacheAdmin/Temp/live_stats.12857559947a1920d61156abc05a60135aefe8bc67 new file mode 100644 index 000000000..ed948be0d --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Temp/live_stats.12857559947a1920d61156abc05a60135aefe8bc67 @@ -0,0 +1 @@ +a:1:{s:15:"127.0.0.1:11211";a:38:{s:3:"pid";s:4:"2049";s:6:"uptime";s:6:"779472";s:4:"time";s:10:"1326282322";s:7:"version";s:5:"1.4.5";s:12:"pointer_size";s:2:"32";s:11:"rusage_user";s:9:"20.137258";s:13:"rusage_system";s:9:"33.862116";s:16:"curr_connections";s:1:"6";s:17:"total_connections";s:5:"13230";s:21:"connection_structures";s:2:"17";s:7:"cmd_get";s:5:"25856";s:7:"cmd_set";s:5:"21025";s:9:"cmd_flush";s:1:"0";s:8:"get_hits";s:5:"22412";s:10:"get_misses";s:4:"3444";s:13:"delete_misses";s:1:"2";s:11:"delete_hits";s:2:"85";s:11:"incr_misses";s:1:"0";s:9:"incr_hits";s:1:"0";s:11:"decr_misses";s:1:"0";s:9:"decr_hits";s:1:"0";s:10:"cas_misses";s:1:"0";s:8:"cas_hits";s:1:"0";s:10:"cas_badval";s:1:"0";s:9:"auth_cmds";s:1:"0";s:11:"auth_errors";s:1:"0";s:10:"bytes_read";s:8:"34784259";s:13:"bytes_written";s:8:"61237342";s:14:"limit_maxbytes";s:8:"67108864";s:15:"accepting_conns";s:1:"1";s:19:"listen_disabled_num";s:1:"0";s:7:"threads";s:1:"4";s:11:"conn_yields";s:1:"0";s:5:"bytes";s:6:"175257";s:10:"curr_items";s:2:"45";s:11:"total_items";s:5:"21025";s:9:"evictions";s:1:"0";s:9:"reclaimed";s:4:"1746";}} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/View/Commands/Commands.tpl b/other/cachetools/MemcacheAdmin/View/Commands/Commands.tpl new file mode 100644 index 000000000..044b48545 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/View/Commands/Commands.tpl @@ -0,0 +1,162 @@ +
+
Console
+
+

+        
+
+ + + + +
+ +
Execute predefined Command
+
+ + + + + +
+
+
+ Execute command on one or all memcached servers
+
+
+
+ Command + + + +
+ + + + +
+ Server + + + +
+
+ API + + get('get_api'), 'request_api'); ?> + +
+
+
+ +
+
+
+ +
+
+
+ +
Execute Telnet Commands
+
+ + + + + +
+
+ Execute telnet command on one or all memcached servers
+
+
+
+ +
+
+ Server + + + +
+
+
+ +
+
+ You can use this thing to execute any telnet command to any memcached server +
+ It will connect to the server, execute the command and return it in the console +
+
+
+
+ For more informations about memcached commands, see memcached protocol + here +
+
+ +
Search Key
+
+ + + + + +
+
+ Search for a key on one or all memcached servers
+
+
+
+ Key + + + +
+
+ Server + + + +
+
+
+ +
+
+ Warning !
This thing is only for debuging issue, do not use it in a production environment as it can lock + or impact your memcached servers performances. +
Also keep in mind that it does not list all keys. It lists keys up to a certain buffer size (1 or 2MB), and it list key that are expired. +
+
You can also use a PCRE regular expression +
+
+
\ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/View/Configure/Configure.tpl b/other/cachetools/MemcacheAdmin/View/Configure/Configure.tpl new file mode 100644 index 000000000..9da6d0c8a --- /dev/null +++ b/other/cachetools/MemcacheAdmin/View/Configure/Configure.tpl @@ -0,0 +1,161 @@ +
+
+ +
Commands Configuration
+
+
+
+ Memcached commands API used by phpMemCacheAdmin
+
+
+
+ Stats + get('stats_api'), 'stats_api'); ?> +
+
+ Slabs + get('slabs_api'), 'slabs_api'); ?> +
+
+ Items + get('items_api'), 'items_api'); ?> +
+
+ Get + get('get_api'), 'get_api'); ?> +
+
+ Set + get('set_api'), 'set_api'); ?> +
+
+ Delete + get('delete_api'), 'delete_api'); ?> +
+
+ Flush All + get('flush_all_api'), 'flush_all_api'); ?> +
+
+
+ +
+
+
+ +
Live Stats Configuration
+
+
+
+ Alert & refresh rate for Live Stats
+
+
+
+ Refresh Rate in sec + +
+
+ Memory Alert + +
+
+ Hit Rate Alert + +
+
+ Eviction Alert + +
+
+ Temp Path + +
+
+
+ +
+
+
+ +
Miscellaneous Configuration
+
+
+
+ Server connection timeout & miscellaneous
+
+
+
+ Timeout in sec + +
+
+ Max Items + +
+
+
+ +
+
+
+ +
+
+
Server List
+
+
+
+ Servers list used by phpMemCacheAdmin
+
+
+get('servers') as $cluster => $servers) + { + $cluster_id++; ?> +
+
+ Cluster + +
+
+ + + Delete +
+
+ + +
+
+ +
+
+
+ Add New Cluster + +
+
+
+ + +
+
+ For more information about configuring phpMemcachedAdmin, see installation guide + here +
+
+
+
\ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/View/Footer.tpl b/other/cachetools/MemcacheAdmin/View/Footer.tpl new file mode 100644 index 000000000..3ddfec358 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/View/Footer.tpl @@ -0,0 +1,7 @@ +
+ phpMemcachedAdmin on GoogleCode + - Memcached.org +
+ + + \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/View/Header.tpl b/other/cachetools/MemcacheAdmin/View/Header.tpl new file mode 100644 index 000000000..c52eededa --- /dev/null +++ b/other/cachetools/MemcacheAdmin/View/Header.tpl @@ -0,0 +1,62 @@ +'; ?> + + + + phpMemcachedAdmin <?php echo CURRENT_VERSION; ?> + + + + +
+
phpMemcachedAdmin
+
+ + Live Stats | + + See Live Stats | + + Actually seeing + + See Stats for + + | + + Executing Commands on Servers + + Execute Commands on Servers + + | + + Editing Configuration + + Edit Configuration + +
+ + diff --git a/other/cachetools/MemcacheAdmin/View/LiveStats/Frame.tpl b/other/cachetools/MemcacheAdmin/View/LiveStats/Frame.tpl new file mode 100644 index 000000000..bb0fbe5f8 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/View/LiveStats/Frame.tpl @@ -0,0 +1,70 @@ + + +
+
Live Stats
+ $_ini->get('refresh_rate')) + { ?> +
+ Connections errors were discovered, to prevent any problem, refresh rate was increased by + get('refresh_rate')); ?> seconds. +
+ + +
+
+ Actually looking at stats +
+
+        Loading live stats, please wait ~get('refresh_rate')); ?> seconds ...
+        
+
+
+
+ SIZE + Total cache size on this server +
+
+ %MEM + Percentage of total cache size used on this server +
+
+ %HIT + Global hit percent on this server : get_hits / (get_hits + get_misses) +
+
+ TIME + Time taken to connect to the server and proceed the request, high value can indicate a latency or server problem +
+
+ REQ/s + Total request per second (get, set, delete, incr, ...) issued to this server +
+
+ CONN + Current connections, monitor that this number doesn't come too close to the server max connection setting +
+
+ GET/s, SET/s, DEL/s + Get, set or delete commands per second issued to this server +
+
+ EVI/s + Number of times an item which had an explicit expire time set had to be evicted before it expired +
+
+ READ/s + Total number of bytes read by this server from network +
+
+ WRITE/s + Total number of bytes sent by this server to network +
+
+
diff --git a/other/cachetools/MemcacheAdmin/View/LiveStats/Stats.tpl b/other/cachetools/MemcacheAdmin/View/LiveStats/Stats.tpl new file mode 100644 index 000000000..14bc9dd6b --- /dev/null +++ b/other/cachetools/MemcacheAdmin/View/LiveStats/Stats.tpl @@ -0,0 +1,87 @@ +get('refresh_rate') . ' sec)' . EOL . EOL; + +# Table header +echo '' . sprintf('%-40s', 'SERVER:PORT') . sprintf('%10s', 'SIZE') . sprintf('%7s', '%MEM') . sprintf('%8s', 'TIME') . +sprintf('%6s', 'CONN') . sprintf('%7s', '%HIT') . sprintf('%8s', 'REQ/s') . sprintf('%8s', 'GET/s') . sprintf('%8s', 'SET/s') . +sprintf('%8s', 'DEL/s') . sprintf('%8s', 'EVI/s') . sprintf('%11s', 'READ/s') . sprintf('%10s', 'WRITE/s') . '' . EOL . '
'; + +# Showing stats for every server +foreach($stats as $server => $data) +{ + # Server name + echo sprintf('%-40.40s', $server); + + # Checking for stats validity + if((isset($data['time'], $data['bytes_percent'], $data['get_hits_percent'], $data['query_time'], $data['request_rate'], $data['curr_connections'], + $data['get_rate'], $data['set_rate'], $data['delete_rate'], $data['eviction_rate'], $data['bytes_read'], $data['bytes_written'])) && ($data['time'] > 0)) + { + # Total Memory + echo sprintf('%10s', Library_Analysis::byteResize($data['limit_maxbytes']) . 'b'); + + # Memory Occupation / Alert State + if($data['bytes_percent'] > $_ini->get('memory_alert')) + { + echo str_pad('', 7 - strlen($data['bytes_percent']), ' ') . '' . sprintf('%.1f', $data['bytes_percent']) . ''; + } + else + { + echo sprintf('%7.1f', $data['bytes_percent']); + } + + # Query Time + echo sprintf('%5.0f', Library_Analysis::valueResize($data['query_time'])) . ' ms'; + + # Current connection + echo sprintf('%6s', $data['curr_connections']); + + # Hit percent (get, delete, cas, incr & decr) + if($data['get_hits_percent'] < $_ini->get('hit_rate_alert')) + { + echo str_pad('', 7 - strlen($data['get_hits_percent']), ' ') . '' . sprintf('%.1f', $data['get_hits_percent']) . ''; + } + else + { + echo sprintf('%7.1f', $data['get_hits_percent']); + } + + # Request rate + echo sprintf('%8s', Library_Analysis::valueResize($data['request_rate'])); + + # Get rate + echo sprintf('%8s', Library_Analysis::valueResize($data['get_rate'])); + + # Set rate + echo sprintf('%8s', Library_Analysis::valueResize($data['set_rate'])); + + # Delete rate + echo sprintf('%8s', Library_Analysis::valueResize($data['delete_rate'])); + + # Eviction rate + if($data['eviction_rate'] > $_ini->get('eviction_alert')) + { + echo str_pad('', 8 - strlen(Library_Analysis::valueResize($data['eviction_rate'])), ' ') . '' . Library_Analysis::valueResize($data['eviction_rate']) . ''; + } + else + { + echo sprintf('%8s', Library_Analysis::valueResize($data['eviction_rate'])); + } + + # Bytes read + echo sprintf('%11s', Library_Analysis::byteResize($data['bytes_read'] / $data['time']) . 'b'); + + # Bytes written + echo sprintf('%10s', Library_Analysis::byteResize($data['bytes_written'] / $data['time']) . 'b'); + } + else + { + echo str_pad('', 20, ' ') . 'An error has occured when retreiving or calculating stats'; + } + + # End of Line + echo EOL . '
'; +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/View/Stats/Error.tpl b/other/cachetools/MemcacheAdmin/View/Stats/Error.tpl new file mode 100644 index 000000000..76aef8860 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/View/Stats/Error.tpl @@ -0,0 +1,58 @@ + +
+ cluster($_GET['server'])) ? 'All servers from Cluster ' . $_GET['server'] : 'Server ' . $_GET['server'], ' did not respond !'; + } + # All servers stats + else + { + echo 'Servers did not respond !'; + } ?> +
+
+ Error message +
+ +
+
+ Please check above error message, your configuration or your server status and retry +
+ +
+ No slabs used in this server ! +
+
+ Error message +
+ Maybe this server is not used, check your configuration or your server status and retry +
+ +
+ No item in this slab ! +
+
+ Error message +
+ This slab is allocated, but is empty +
+
+ Go back to Server Slabs +
+ +
Result
+
+ $result) + { ?> +
+ +
+ +
+ Items in Slab , only showing first get('max_item_dump'); ?> items + Back to Server Slabs +
+
+ $data) +{ + # Checking if first item + if($notFirst) { echo '
'; } + ?> + + 70) ? substr($key, 0, 70) . '[..]' : $key); ?> + + + Size : Bytes, + Expiration : + + + +
\ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/View/Stats/Slabs.tpl b/other/cachetools/MemcacheAdmin/View/Stats/Slabs.tpl new file mode 100644 index 000000000..f0ba9d2b0 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/View/Stats/Slabs.tpl @@ -0,0 +1,126 @@ +
+
Slabs Stats
+
+
+ Slabs Used + +
+
+ Memory Used + Bytes +
+
+ Wasted + Bytes +
+
+
+ +
+ +
+
+ +
+
+ For more informations about memcached slabs stats, see memcached protocol + here +
+
+ + + + $slab) +{ + # If Slab is Used + if(is_numeric($id)) + { + # Making a new line + if($actualSlab >= 4) + { +?> + + + + + +'; +} +?> + +
0) { echo 'style="padding-left:9px;"'; } ?> valign="top"> +
Slab Stats + See Slab Items +
+
+
+ Chunk Size + Bytes +
+
+ Used Chunk + + [ %] +
+
+ Total Chunk + +
+
+ Total Page + +
+
+ Wasted + Bytes +
+
+ Hits + Request/sec +
+ 0) +{ ?> +
+ Evicted + +
+ + +
+ Slab is allocated but empty +
+ +
+
\ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/View/Stats/Stats.tpl b/other/cachetools/MemcacheAdmin/View/Stats/Stats.tpl new file mode 100644 index 000000000..bfa79a6dc --- /dev/null +++ b/other/cachetools/MemcacheAdmin/View/Stats/Stats.tpl @@ -0,0 +1,356 @@ +
+
Get Stats
+
+
+ Hits + + [%] +
+
+ Miss + + [%] +
+
+ Rate + Request/sec +
+
+ +
Set Stats
+
+
+ Total + +
+
+ Rate + Request/sec +
+
+ +
Delete Stats
+
+
+ Hits + + [%] +
+
+ Miss + + [%] +
+
+ Rate + +
+
+ +
Cas Stats
+
+
+ Hits + + [%] +
+
+ Miss + + [%] +
+
+ Bad Value + + [%] +
+
+ Rate + +
+
+ +
Increment Stats
+
+
+ Hits + + [%] +
+
+ Miss + + [%] +
+
+ Rate + +
+
+ +
Decrement Stats
+
+
+ Hits + + [%] +
+
+ Miss + + [%] +
+
+ Rate + +
+
+ +
Flush Stats
+
+
+ Total + +
+
+ Rate + +
+
+
+ +
+server($_GET['server']))) +{ ?> + + +
server($_GET['server'])) ? 'Server' : 'Cluster'; ?> Stats
+
+server($_GET['server']))) +{ ?> +
+ Uptime + +
+
+ Memcached + Version +
+ +
+ Curr Connections + +
+
+ Total Connections + +
+
+ Max Connections Errors + +
+
+ Current Items + +
+
+ Total Items + +
+server($_GET['server']))) +{ ?> +
+ Oldest Item + +
+ +
+ +
Eviction & Reclaimed Stats
+
+
+ Items Eviction + +
+
+ Rate + Eviction/sec +
+
+ Reclaimed + +
+
+ Rate + +
+
+ +server($_GET['server']))) +{ ?> +
Server Configuration
+
+
+ Accepting Connections + +
+
+ Max Bytes + +
+
+ Max Connection + +
+
+ TCP/UDP Port + +
+
+ Listen Interface + +
+
+ Evictions + +
+
+ Path to Domain Socket + +
+
+ Domain Socket Umask + +
+
+ Chunk Size + +
+
+ Chunk Growth Factor + +
+
+ Max Threads + +
+
+ Detail Enabled + +
+
+ Max IO Ops/Event + +
+
+ CAS Enabled + +
+
+ TCP Listen Backlog + +
+
+ SASL Auth + +
+
+cluster($_GET['server']))) +{ ?> +
Cluster Servers List
+
+ +
+ + See Server Stats +
+ +
+
+ +
+ +
+ +
+
Cache Size Stats
+
+
+ Used + Bytes +
+
+ Total + Bytes +
+
+ Wasted + Bytes +
+ +
+ +
Cache Size Graphic
+
+
+ Cache Size by GoogleCharts +
+
+ +
Hit & Miss Rate Graphic
+
+
+ Cache Hit & Miss Rate by GoogleChart +
+
+ +
Network Stats
+
+
+ Bytes Read + Bytes +
+
+ Bytes Written + Bytes +
+
+
diff --git a/other/cachetools/MemcacheAdmin/commands.php b/other/cachetools/MemcacheAdmin/commands.php new file mode 100644 index 000000000..53a14a4f8 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/commands.php @@ -0,0 +1,276 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Executing commands + * + * @author c.mahieux@of2m.fr + * @since 06/04/2010 + */ + +# Headers +header('Content-type: text/html;'); +header('Cache-Control: no-cache, must-revalidate'); + +# Require +require_once 'Library/Loader.php'; + +# Date timezone +date_default_timezone_set('Europe/Paris'); + +# Loading ini file +$_ini = Library_Configuration_Loader::singleton(); + +# Initializing requests & response +$request = (isset($_GET['request_command'])) ? $_GET['request_command'] : null; + +# Starting +ob_start(); + +# Display by request rype +switch($request) +{ + # Memcache::get command + case 'get': + # Ask for get on a cluster + if(isset($_GET['request_server']) && ($cluster = $_ini->cluster($_GET['request_server']))) + { + foreach($cluster as $server) + { + # Dumping server get command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->get($server['hostname'], $server['port'], $_GET['request_key'])); + } + } + # Ask for get on one server + elseif(isset($_GET['request_server']) && ($server = $_ini->server($_GET['request_server']))) + { + # Dumping server get command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->get($server['hostname'], $server['port'], $_GET['request_key'])); + } + # Ask for get on all servers + else + { + foreach($_ini->get('servers') as $cluster => $servers) + { + # Asking for each server stats + foreach($servers as $server) + { + # Dumping server get command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->get($server['hostname'], $server['port'], $_GET['request_key'])); + } + } + } + break; + + # Memcache::set command + case 'set': + # Ask for set on a cluster + if(isset($_GET['request_server']) && ($cluster = $_ini->cluster($_GET['request_server']))) + { + foreach($cluster as $server) + { + # Dumping server get command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->set($server['hostname'], $server['port'], $_GET['request_key'], $_GET['request_data'], $_GET['request_duration'])); + } + } + # Ask for set on one server + elseif(isset($_GET['request_server']) && ($server = $_ini->server($_GET['request_server']))) + { + # Dumping server set command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->set($server['hostname'], $server['port'], $_GET['request_key'], $_GET['request_data'], $_GET['request_duration'])); + } + # Ask for set on all servers + else + { + foreach($_ini->get('servers') as $cluster => $servers) + { + # Asking for each server stats + foreach($servers as $server) + { + # Dumping server set command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->set($server['hostname'], $server['port'], $_GET['request_key'], $_GET['request_data'], $_GET['request_duration'])); + } + } + } + break; + + # Memcache::delete command + case 'delete': + # Ask for delete on a cluster + if(isset($_GET['request_server']) && ($cluster = $_ini->cluster($_GET['request_server']))) + { + foreach($cluster as $server) + { + # Dumping server get command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->delete($server['hostname'], $server['port'], $_GET['request_key'])); + } + } + # Ask for delete on one server + elseif(isset($_GET['request_server']) && ($server = $_ini->server($_GET['request_server']))) + { + # Dumping server delete command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->delete($server['hostname'], $server['port'], $_GET['request_key'])); + } + # Ask for delete on all servers + else + { + foreach($_ini->get('servers') as $cluster => $servers) + { + # Asking for each server stats + foreach($servers as $server) + { + # Dumping server delete command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->delete($server['hostname'], $server['port'], $_GET['request_key'])); + } + } + } + break; + + # Memcache::flush_all command + case 'flush_all': + # Checking delay + if(!isset($_GET['request_delay']) || !is_numeric($_GET['request_delay'])) + { + $_GET['request_delay'] = 0; + } + + # Ask for flush_all on a cluster + if(isset($_GET['request_server']) && ($cluster = $_ini->cluster($_GET['request_server']))) + { + foreach($cluster as $server) + { + # Dumping server get command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->flush_all($server['hostname'], $server['port'], $_GET['request_delay'])); + } + } + # Ask for flush_all on one server + elseif(isset($_GET['request_server']) && ($server = $_ini->server($_GET['request_server']))) + { + # Dumping server flush_all command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->flush_all($server['hostname'], $server['port'], $_GET['request_delay'])); + } + # Ask for flush_all on all servers + else + { + foreach($_ini->get('servers') as $cluster => $servers) + { + # Asking for each server stats + foreach($servers as $server) + { + # Dumping server flush_all command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api($_GET['request_api'])->flush_all($server['hostname'], $server['port'], $_GET['request_delay'])); + } + } + } + break; + + # Memcache::search command + case 'search': + # Ask for flush_all on a cluster + if(isset($_GET['request_server']) && ($cluster = $_ini->cluster($_GET['request_server']))) + { + foreach($cluster as $server) + { + # Dumping server get command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api('Server')->search($server['hostname'], $server['port'], $_GET['request_key'])); + } + } + # Ask for search on one server + elseif(isset($_GET['request_server']) && ($server = $_ini->server($_GET['request_server']))) + { + # Dumping server search command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api('Server')->search($server['hostname'], $server['port'], $_GET['request_key'])); + } + # Ask for search on all servers + else + { + # Looking into each cluster + foreach($_ini->get('servers') as $cluster => $servers) + { + # Asking for each server stats + foreach($servers as $server) + { + # Dumping server search command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api('Server')->search($server['hostname'], $server['port'], $_GET['request_key'])); + } + } + } + break; + + # Memcache::telnet command + case 'telnet': + # Ask for a telnet command on a cluster + if(isset($_GET['request_server']) && ($cluster = $_ini->cluster($_GET['request_server']))) + { + foreach($cluster as $server) + { + # Dumping server telnet command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api('Server')->telnet($server['hostname'], $server['port'], $_GET['request_telnet'])); + } + } + # Ask for a telnet command on one server + elseif(isset($_GET['request_server']) && ($server = $_ini->server($_GET['request_server']))) + { + # Dumping server telnet command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api('Server')->telnet($server['hostname'], $server['port'], $_GET['request_telnet'])); + } + # Ask for a telnet command on all servers + else + { + # Looking into each cluster + foreach($_ini->get('servers') as $cluster => $servers) + { + # Asking for each server stats + foreach($servers as $server) + { + # Dumping server telnet command response + echo Library_HTML_Components::serverResponse($server['hostname'], $server['port'], + Library_Command_Factory::api('Server')->telnet($server['hostname'], $server['port'], $_GET['request_telnet'])); + } + } + } + break; + # Default : No command + default : + # Showing header + include 'View/Header.tpl'; + + # Showing formulary + include 'View/Commands/Commands.tpl'; + + # Showing footer + include 'View/Footer.tpl'; + break; +} + +ob_end_flush(); \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/configure.php b/other/cachetools/MemcacheAdmin/configure.php new file mode 100644 index 000000000..b0f9f70f9 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/configure.php @@ -0,0 +1,127 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Configuration + * + * @author c.mahieux@of2m.fr + * @since 06/04/2010 + */ +# Headers +header('Content-type: text/html;'); +header('Cache-Control: no-cache, must-revalidate'); + +# Require +require_once 'Library/Loader.php'; + +# Date timezone +date_default_timezone_set('Europe/Paris'); + +# Loading ini file +$_ini = Library_Configuration_Loader::singleton(); + +# Initializing requests +$request = (isset($_GET['request_write'])) ? $_GET['request_write'] : null; +$write = null; + +# Display by request rype +switch($request) +{ + # Unlock configuration file & temp directory + case 'unlock': + # chmod 0755 + chmod(Library_Configuration_Loader::path(), 0755); + chmod($_ini->get('file_path'), 0755); + break; + + # Live stats configuration save + case 'live_stats': + # Updating configuration + $_ini->set('refresh_rate', round(max(2, $_POST['refresh_rate']))); + $_ini->set('memory_alert', $_POST['memory_alert']); + $_ini->set('hit_rate_alert', $_POST['hit_rate_alert']); + $_ini->set('eviction_alert', $_POST['eviction_alert']); + $_ini->set('file_path', $_POST['file_path']); + + # Writing configuration file + $write = Library_Configuration_Loader::singleton()->write(); + break; + + # Commands configuration save + case 'commands': + # Updating configuration + $_ini->set('stats_api', $_POST['stats_api']); + $_ini->set('slabs_api', $_POST['slabs_api']); + $_ini->set('items_api', $_POST['items_api']); + $_ini->set('get_api', $_POST['get_api']); + $_ini->set('set_api', $_POST['set_api']); + $_ini->set('delete_api', $_POST['delete_api']); + $_ini->set('flush_all_api', $_POST['flush_all_api']); + + # Writing configuration file + $write = Library_Configuration_Loader::singleton()->write(); + break; + + # Server configuration save + case 'servers': + $array = array(); + foreach($_POST['server'] as $cluster => $servers) + { + foreach($servers as $data) + { + $array[$_POST['cluster'][$cluster]][$data['hostname'] . ':' . $data['port']] = $data; + } + } + + # Sorting clusters + ksort($array); + foreach($array as $cluster => $servers) + { + # Sorting servers + ksort($servers); + $array[$cluster] = $servers; + } + + # Updating configuration + $_ini->set('servers', $array); + + # Writing configuration file + $write = Library_Configuration_Loader::singleton()->write(); + break; + + # Miscellaneous configuration save + case 'miscellaneous': + # Updating configuration + $_ini->set('connection_timeout', $_POST['connection_timeout']); + $_ini->set('max_item_dump', $_POST['max_item_dump']); + + # Writing configuration file + $write = Library_Configuration_Loader::singleton()->write(); + break; + + # Default : No command + default : + break; +} + +# Showing header +include 'View/Header.tpl'; + +# Showing formulary +include 'View/Configure/Configure.tpl'; + +# Showing footer +include 'View/Footer.tpl'; \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/index.php b/other/cachetools/MemcacheAdmin/index.php new file mode 100644 index 000000000..719fa8765 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/index.php @@ -0,0 +1,176 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Stats viewing + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +# Headers +header('Content-type: text/html; charset=UTF-8'); +header('Cache-Control: no-cache, must-revalidate'); + +# Require +require_once 'Library/Loader.php'; + +# Date timezone +date_default_timezone_set('Europe/Paris'); + +# Loading ini file +$_ini = Library_Configuration_Loader::singleton(); + +# Initializing requests +$request = (isset($_GET['show'])) ? $_GET['show'] : null; + +# Getting default cluster +if(!isset($_GET['server'])) +{ + $clusters = array_keys($_ini->get('servers')); + $cluster = isset($clusters[0]) ? $clusters[0] : null; + $_GET['server'] = $cluster; +} + +# Showing header +include 'View/Header.tpl'; + +# Display by request type +switch($request) +{ + # Items : Display of all items for a single slab for a single server + case 'items': + # Initializing items array + $server = null; + $items = false; + $response = array(); + + # Ask for one server and one slabs items + if(isset($_GET['server']) && ($server = $_ini->server($_GET['server']))) + { + $items = Library_Command_Factory::instance('items_api')->items($server['hostname'], $server['port'], $_GET['slab']); + } + + # Cheking if asking an item + if(isset($_GET['request_key'])) + { + $response[$server['hostname'] . ':' . $server['port']] = Library_Command_Factory::instance('get_api')->get($server['hostname'], $server['port'], $_GET['request_key']); + } + + # Getting stats to calculate server boot time + $stats = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']); + $infinite = (isset($stats['time'], $stats['uptime'])) ? ($stats['time'] - $stats['uptime']) : 0; + + # Items are well formed + if($items !== false) + { + # Showing items + include 'View/Stats/Items.tpl'; + } + # Items are not well formed + else + { + include 'View/Stats/Error.tpl'; + } + unset($items); + break; + + # Slabs : Display of all slabs for a single server + case 'slabs': + # Initializing slabs array + $slabs = false; + + # Ask for one server slabs + if(isset($_GET['server']) && ($server = $_ini->server($_GET['server']))) + { + # Spliting server in hostname:port + $slabs = Library_Command_Factory::instance('slabs_api')->slabs($server['hostname'], $server['port']); + } + + # Slabs are well formed + if($slabs !== false) + { + # Analysis + $slabs = Library_Analysis::slabs($slabs); + include 'View/Stats/Slabs.tpl'; + } + # Slabs are not well formed + else + { + include 'View/Stats/Error.tpl'; + } + unset($slabs); + break; + + # Default : Stats for all or specific single server + default : + # Initializing stats & settings array + $stats = array(); + $slabs = array(); + $slabs['total_malloced'] = 0; + $slabs['total_wasted'] = 0; + $settings = array(); + $status = array(); + + $cluster = null; + $server = null; + + # Ask for a particular cluster stats + if(isset($_GET['server']) && ($cluster = $_ini->cluster($_GET['server']))) + { + foreach($cluster as $server) + { + # Getting Stats & Slabs stats + $data = array(); + $data['stats'] = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']); + $data['slabs'] = Library_Analysis::slabs(Library_Command_Factory::instance('slabs_api')->slabs($server['hostname'], $server['port'])); + $stats = Library_Analysis::merge($stats, $data['stats']); + + # Computing stats + if(isset($data['slabs']['total_malloced'], $data['slabs']['total_wasted'])) + { + $slabs['total_malloced'] += $data['slabs']['total_malloced']; + $slabs['total_wasted'] += $data['slabs']['total_wasted']; + } + $status[$server['hostname'] . ':' . $server['port']] = ($data['stats'] != array()) ? $data['stats']['version'] : ''; + $uptime[$server['hostname'] . ':' . $server['port']] = ($data['stats'] != array()) ? $data['stats']['uptime'] : ''; + } + } + # Asking for a server stats + elseif(isset($_GET['server']) && ($server = $_ini->server($_GET['server']))) + { + # Getting Stats & Slabs stats + $stats = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']); + $slabs = Library_Analysis::slabs(Library_Command_Factory::instance('slabs_api')->slabs($server['hostname'], $server['port'])); + $settings = Library_Command_Factory::instance('stats_api')->settings($server['hostname'], $server['port']); + } + + # Stats are well formed + if(($stats !== false) && ($stats != array())) + { + # Analysis + $stats = Library_Analysis::stats($stats); + include 'View/Stats/Stats.tpl'; + } + # Stats are not well formed + else + { + include 'View/Stats/Error.tpl'; + } + unset($stats); + break; +} +# Showing footer +include 'View/Footer.tpl'; \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/stats.php b/other/cachetools/MemcacheAdmin/stats.php new file mode 100644 index 000000000..3ce90511a --- /dev/null +++ b/other/cachetools/MemcacheAdmin/stats.php @@ -0,0 +1,171 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Live Stats top style + * + * @author Cyrille Mahieux : elijaa(at)free.fr + * @since 12/04/2010 + */ + +# Headers +header('Content-type: text/html;'); +header('Cache-Control: no-cache, must-revalidate'); + +# Require +require_once 'Library/Loader.php'; + +# Date timezone +date_default_timezone_set('Europe/Paris'); + +# Loading ini file +$_ini = Library_Configuration_Loader::singleton(); + +# Initializing requests +$request = (isset($_GET['request_command'])) ? $_GET['request_command'] : null; + +# Stat of a particular cluster +if(isset($_GET['cluster']) && ($_GET['cluster'] != null)) +{ + $cluster = $_GET['cluster']; +} +# Getting default cluster +else +{ + $clusters = array_keys($_ini->get('servers')); + $cluster = isset($clusters[0]) ? $clusters[0] : null; + $_GET['cluster'] = $cluster; +} + +# Hashing cluster +$hash = md5($_GET['cluster']); + +# Cookie @FIXME not a perfect method +if(!isset($_COOKIE['live_stats_id' . $hash])) +{ + # Cleaning temporary directory + $files = glob($_ini->get('file_path') . '*', GLOB_NOSORT ); + foreach($files as $path) + { + $stats = @stat($path); + if(isset($stats[9]) && ($stats[9] < (time() - 60*60*24))) + { + @unlink($path); + } + } + + # Generating unique id + $live_stats_id = rand() . $hash; + + # Cookie + setcookie('live_stats_id' . $hash, $live_stats_id, time() + 60*60*24); +} +else +{ + # Backup from a previous request + $live_stats_id = $_COOKIE['live_stats_id' . $hash]; +} + +# Live stats dump file +$file_path = rtrim($_ini->get('file_path'), '/') . DIRECTORY_SEPARATOR . 'live_stats.' . $live_stats_id; + +# Display by request type +switch($request) +{ + # Ajax ask : stats + case 'live_stats': + # Opening old stats dump + $previous = @unserialize(file_get_contents($file_path)); + + # Initializing variables + $actual = array(); + $stats = array(); + $time = 0; + + # Requesting stats for each server + foreach($_ini->cluster($cluster) as $server) + { + # Start query time calculation + $time = microtime(true); + + # Asking server for stats + $actual[$server['hostname'] . ':' . $server['port']] = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']); + + # Calculating query time length + $actual[$server['hostname'] . ':' . $server['port']]['query_time'] = max((microtime(true) - $time) * 1000, 1); + } + + # Analysing stats + foreach($_ini->cluster($cluster) as $server) + { + # Making an alias + $server = $server['hostname'] . ':' . $server['port']; + + # Diff between old and new dump + $stats[$server] = Library_Analysis::diff($previous[$server], $actual[$server]); + } + + # Making stats for each server + foreach($stats as $server => $array) + { + # Analysing request + if((isset($stats[$server]['uptime'])) && ($stats[$server]['uptime'] > 0)) + { + # Computing stats + $stats[$server] = Library_Analysis::stats($stats[$server]); + + # Because we make a diff on every key, we must reasign some values + $stats[$server]['bytes_percent'] = sprintf('%.1f', $actual[$server]['bytes'] / $actual[$server]['limit_maxbytes'] * 100); + $stats[$server]['bytes'] = $actual[$server]['bytes']; + $stats[$server]['limit_maxbytes'] = $actual[$server]['limit_maxbytes']; + $stats[$server]['curr_connections'] = $actual[$server]['curr_connections']; + $stats[$server]['query_time'] = $actual[$server]['query_time']; + } + } + + # Saving new stats dump + file_put_contents($file_path, serialize($actual)); + + # Showing stats + include 'View/LiveStats/Stats.tpl'; + break; + + # Default : No command + default : + # Initializing : making stats dump + $stats = array(); + foreach($_ini->cluster($cluster) as $server) + { + $stats[$server['hostname'] . ':' . $server['port']] = Library_Command_Factory::instance('stats_api')->stats($server['hostname'], $server['port']); + } + + # Saving first stats dump + file_put_contents($file_path, serialize($stats)); + + # Searching for connection error, adding some time to refresh rate to prevent error + $refresh_rate = max($_ini->get('refresh_rate'), count($_ini->cluster($cluster)) * 0.25 + (Library_Data_Error::count() * (0.5 + $_ini->get('connection_timeout')))); + + # Showing header + include 'View/Header.tpl'; + + # Showing live stats frame + include 'View/LiveStats/Frame.tpl'; + + # Showing footer + include 'View/Footer.tpl'; + + break; +} diff --git a/other/cachetools/phpRedisAdmin/README.markdown b/other/cachetools/phpRedisAdmin/README.markdown new file mode 100644 index 000000000..daec73c04 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/README.markdown @@ -0,0 +1,39 @@ +phpRedisAdmin +============= + +phpRedisAdmin is a simple web interface to manage [Redis](http://redis.io/) databases. It is released under the [Creative Commons Attribution 3.0 license](http://creativecommons.org/licenses/by/3.0/). This code is being developed and maintained by [Erik Dubbelboer](https://github.com/ErikDubbelboer/). + +You can send comments, patches, questions [here on github](https://github.com/ErikDubbelboer/phpRedisAdmin/issues) or to erik@dubbelboer.com. + + +Example +======= + +You can find an example database at [http://dubbelboer.com/phpRedisAdmin/](http://dubbelboer.com/phpRedisAdmin/?view&key=example:hash) + + +Installing/Configuring +====================== + +You will need [phpredis](https://github.com/nicolasff/phpredis). See phpredis for install instructions. + +You will need to edit config.inc.php with your redis information. You might also want to uncomment and change the login information in config.inc.php. + + +TODO +==== + +* Javascript sorting of tables +* Better error handling +* Move or Copy key to different server +* Importing JSON +* JSON export with seperate objects based on your seperator + + +Credits +======= + +Icons by [http://p.yusukekamiyamane.com/](http://p.yusukekamiyamane.com/) ([https://github.com/yusukekamiyamane/fugue-icons/tree/master/icons-shadowless](https://github.com/yusukekamiyamane/fugue-icons/tree/master/icons-shadowless)) + +Favicon from [https://github.com/antirez/redis-io/blob/master/public/images/favicon.png](https://github.com/antirez/redis-io/blob/master/public/images/favicon.png) + diff --git a/other/cachetools/phpRedisAdmin/common.inc.php b/other/cachetools/phpRedisAdmin/common.inc.php new file mode 100644 index 000000000..80f47bb0d --- /dev/null +++ b/other/cachetools/phpRedisAdmin/common.inc.php @@ -0,0 +1,115 @@ +https://github.com/nicolasff/phpredis'); +} + + + + +// Undo magic quotes (both in keys and values) +if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) { + $process = array(&$_GET, &$_POST); + + while (list($key, $val) = each($process)) { + foreach ($val as $k => $v) { + unset($process[$key][$k]); + + if (is_array($v)) { + $process[$key][stripslashes($k)] = $v; + $process[] = &$process[$key][stripslashes($k)]; + } else { + $process[$key][stripslashes($k)] = stripslashes($v); + } + } + } + + unset($process); +} + + + + +// These includes are needed by each script. +require_once 'config.inc.php'; +require_once 'functions.inc.php'; +require_once 'page.inc.php'; + + +if (isset($config['login'])) { + require_once 'login.inc.php'; +} + + + + +// phpredis types to string conversion array. +$redistypes = array( + Redis::REDIS_STRING => 'string', + Redis::REDIS_SET => 'set', + Redis::REDIS_LIST => 'list', + Redis::REDIS_ZSET => 'zset', + Redis::REDIS_HASH => 'hash', +); + + + + + +if (isset($login['servers'])) { + $i = current($login['servers']); +} else { + $i = 0; +} + + +if (isset($_GET['s']) && is_numeric($_GET['s']) && ($_GET['s'] < count($config['servers']))) { + $i = $_GET['s']; +} + +$server = $config['servers'][$i]; +$server['id'] = $i; + + +if (isset($login, $login['servers'])) { + if (array_search($i, $login['servers']) === false) { + die('You are not allowed to access this database.'); + } + + foreach ($config['servers'] as $key => $ignore) { + if (array_search($key, $login['servers']) === false) { + unset($config['servers'][$key]); + } + } +} + + +if (!isset($server['db'])) { + $server['db'] = 0; +} + + +// Setup a connection to Redis. +$redis = new Redis(); + +try { + $redis->connect($server['host'], $server['port']); +} catch (Exception $e) { + die('ERROR: Could not connect to Redis ('.$server['host'].':'.$server['port'].')'); +} + + +if (isset($server['auth'])) { + if (!$redis->auth($server['auth'])) { + die('ERROR: Authentication failed ('.$server['host'].':'.$server['port'].')'); + } +} + + +if ($server['db'] != 0) { + if (!$redis->select($server['db'])) { + die('ERROR: Selecting database failed ('.$server['host'].':'.$server['port'].','.$server['db'].')'); + } +} + +?> diff --git a/other/cachetools/phpRedisAdmin/config.inc.php b/other/cachetools/phpRedisAdmin/config.inc.php new file mode 100644 index 000000000..a0fdf4d0a --- /dev/null +++ b/other/cachetools/phpRedisAdmin/config.inc.php @@ -0,0 +1,56 @@ + array( + 0 => array( + 'name' => 'local server', // Optional name. + 'host' => '127.0.0.1', + 'port' => 6379, + + // Optional Redis authentication. + //'auth' => 'redispasswordhere' // Warning: The password is sent in plain-text to the Redis server. + ), + + /*1 => array( + 'host' => 'localhost', + 'port' => 6380 + ),*/ + + /*2 => array( + 'name' => 'local db 2', + 'host' => 'localhost', + 'port' => 6379, + 'db' => 1 // Optional database number, see http://redis.io/commands/select + )*/ + ), + + + 'seperator' => ':', + + + // Uncomment to show less information and make phpRedisAdmin fire less commands to the Redis server. Recommended for a really busy Redis server. + //'faster' => true, + + + // Uncomment to enable HTTP authentication + /*'login' => array( + // Username => Password + // Multiple combinations can be used + 'admin' => array( + 'password' => 'adminpassword', + ), + 'guest' => array( + 'password' => '', + 'servers' => array(1) // Optional list of servers this user can access. + ) + ),*/ + + + + + // You can ignore settings below this point. + + 'maxkeylen' => 100 +); + +?> diff --git a/other/cachetools/phpRedisAdmin/css/common.css b/other/cachetools/phpRedisAdmin/css/common.css new file mode 100644 index 000000000..942c49a35 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/css/common.css @@ -0,0 +1,53 @@ + +html { +font-size: x-small; /* Wikipedia font-size scaling method */ +} + +body { +font: 116%/1.4em Verdana, sans-serif; +color: #000; +margin: 0; +padding: 0; +border: 0; +height: 100%; +max-height: 100%; +background-color: #fff; +} + +h1 { +font: bold 190% "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +h2 { +font: bold 160% "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +h3 { +font: bold 130% "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +abbr { +border-bottom: 1px dotted #666; +} + +img { +border: 0; +} + + +.clear { +clear: left; +} + + +.info { +color: #aaa; +font-weight: normal; +} + + +.add { +padding: 3px 0 1px 20px; +background: url(../images/add.png) left center no-repeat; +} + diff --git a/other/cachetools/phpRedisAdmin/css/frame.css b/other/cachetools/phpRedisAdmin/css/frame.css new file mode 100644 index 000000000..c467b85cf --- /dev/null +++ b/other/cachetools/phpRedisAdmin/css/frame.css @@ -0,0 +1,56 @@ + +form { +margin: 0; +} + +form p { +padding-left: 8em; +margin: 1em 0; +} + +form label { +float: left; +width: 7em; +margin-left: -8em; +} + +form .button { +margin-left: -7em; +} + + +#hkeyp, #indexp, #scorep { +display: none; +} + + +table { +border-spacing: 0; +border-collapse: collapse; +} + +td { +background-color: #eee; +border: 2px solid #fff; +} + +.alt td { +background-color: #ccc; +} + +td div, th div { +padding: .5em; +} + + +.imgbut { +vertical-align: middle; +margin-top: -4px; +} + + +.server { +float: left; +margin: 1em; +} + diff --git a/other/cachetools/phpRedisAdmin/css/index.css b/other/cachetools/phpRedisAdmin/css/index.css new file mode 100644 index 000000000..b562ccf47 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/css/index.css @@ -0,0 +1,122 @@ + +#sidebar { +position: absolute; +top: 0; +bottom: 0; +left: 0; +width: 24em; +height: 100%; +padding-left: 1em; +border-right: 1px solid #000; +overflow: hidden; +} + +#sidebar a, #sidebar a:visited { +color: #000; +} + +#sidebar a { +text-decoration: none; +} + +#sidebar a:hover { +text-decoration: underline; +} + + +#keys { +position: fixed; +top: 15.5em; +bottom: 0; +width: 24em; +padding-bottom: 1em; +overflow: auto; +} + +#keys ul { +list-style-type: none; +margin: 0; +padding: 0; +} + +#keys li { +font-weight: normal; +} + +#keys li.folder { +font-weight: bold; +margin-top: .05em; +} + +#keys li.current a { +background-color: #eee; +} + +#keys li.hidden { +display: none; +} + +#keys .icon { +padding: 1px 0 1px 20px; +background: url(../images/folder-open.png) left center no-repeat; +white-space: nowrap; +} + +#keys li.collapsed ul { +display: none; +} + +#keys ul ul { +margin-left: 6px; +background: url(../images/tree-vline.gif) repeat-y; +} + +#keys ul ul li { +padding-left: 16px; +background: url(../images/tree-node.gif) no-repeat; +} + +#keys ul ul li.folder { +background-image: url(../images/tree-folder-expanded.gif); +} + +#keys ul ul li.folder.collapsed { +background-image: url(../images/tree-folder-collapsed.gif); +} + +#keys ul ul li.last { /* Hard-coded substitute for :last-child */ +margin-bottom: .3em; +background: #fff url(../images/tree-lastnode.gif) no-repeat; +} + +#keys ul ul li.last.folder { +background-image: url(../images/tree-lastnode-expanded.gif); +} + +#keys ul ul li.last.folder.collapsed { +background-image: url(../images/tree-lastnode-collapsed.gif); +} + +#keys .deltree { +display: none; +} + +#keys .icon:hover .deltree { +display: inline; +} + + +#frame { +position: fixed; +top: 0; +left: 25em; +right: 0; +bottom: 0; +padding-left: 1em; +} + +#frame iframe { +width: 100%; +height: 100%; +} + diff --git a/other/cachetools/phpRedisAdmin/delete.php b/other/cachetools/phpRedisAdmin/delete.php new file mode 100644 index 000000000..e7a96caba --- /dev/null +++ b/other/cachetools/phpRedisAdmin/delete.php @@ -0,0 +1,63 @@ +delete($_GET['key']); + } + + // Hash + else if (($_GET['type'] == 'hash') && isset($_GET['hkey'])) { + // Delete only the field in the hash. + $redis->hDel($_GET['key'], $_GET['hkey']); + } + + // List + else if (($_GET['type'] == 'list') && isset($_GET['index'])) { + // Lists don't have simple delete operations. + // You can only remove something based on a value so we set the value at the index to some random value we hope doesn't occur elsewhere in the list. + $value = str_rand(69); + + // This code assumes $value is not present in the list. To make sure of this we would need to check the whole list and place a Watch on it to make sure the list isn't modified in between. + $redis->lSet($_GET['key'], $_GET['index'], $value); + $redis->lRem($_GET['key'], $value, 1); + } + + // Set + else if (($_GET['type'] == 'set') && isset($_GET['value'])) { + // Removing members from a set can only be done by supplying the member. + $redis->sRem($_GET['key'], $_GET['value']); + } + + // ZSet + else if (($_GET['type'] == 'zset') && isset($_GET['value'])) { + // Removing members from a zset can only be done by supplying the value. + $redis->zDelete($_GET['key'], $_GET['value']); + } + + + die('?view&s='.$server['id'].'&key='.urlencode($_GET['key'])); +} + + +if (isset($_GET['tree'])) { + $keys = $redis->keys($_GET['tree'].'*'); + + foreach ($keys as $key) { + $redis->delete($key); + } + + die; +} + +?> diff --git a/other/cachetools/phpRedisAdmin/edit.php b/other/cachetools/phpRedisAdmin/edit.php new file mode 100644 index 000000000..dbc331574 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/edit.php @@ -0,0 +1,186 @@ + $config['maxkeylen']) { + die('ERROR: Your key is to long (max length is '.$config['maxkeylen'].')'); + } + + // String + if ($_POST['type'] == 'string') { + $redis->set($_POST['key'], $_POST['value']); + } + + // Hash + else if (($_POST['type'] == 'hash') && isset($_POST['hkey'])) { + if (strlen($_POST['hkey']) > $config['maxkeylen']) { + die('ERROR: Your hash key is to long (max length is '.$config['maxkeylen'].')'); + } + + if ($edit && !$redis->hExists($_POST['key'], $_POST['hkey'])) { + $redis->hDel($_POST['key'], $_GET['hkey']); + } + + $redis->hSet($_POST['key'], $_POST['hkey'], $_POST['value']); + } + + // List + else if (($_POST['type'] == 'list') && isset($_POST['index'])) { + $size = $redis->lSize($_POST['key']); + + if (($_POST['index'] == '') || + ($_POST['index'] == $size) || + ($_POST['index'] == -1)) { + // Push it at the end + $redis->rPush($_POST['key'], $_POST['value']); + } else if (($_POST['index'] >= 0) && + ($_POST['index'] < $size)) { + // Overwrite an index + $redis->lSet($_POST['key'], $_POST['index'], $_POST['value']); + } else { + die('ERROR: Out of bounds index'); + } + } + + // Set + else if ($_POST['type'] == 'set') { + if ($_POST['value'] != $_POST['oldvalue']) { + // The only way to edit a Set value is to add it and remove the old value. + $redis->sRem($_POST['key'], $_POST['oldvalue']); + $redis->sAdd($_POST['key'], $_POST['value']); + } + } + + // ZSet + else if (($_POST['type'] == 'zset') && isset($_POST['score'])) { + if ($_POST['value'] != $_POST['oldvalue']) { + // The only way to edit a ZSet value is to add it and remove the old value. + $redis->zDelete($_POST['key'], $_POST['oldvalue']); + $redis->zAdd($_POST['key'], $_POST['score'], $_POST['value']); + } + } + + + + // Refresh the top so the key tree is updated. + require 'header.inc.php'; + + ?> + + get($_GET['key']); + } + + // Hash + else if (($_GET['type'] == 'hash') && isset($_GET['hkey'])) { + $value = $redis->hGet($_GET['key'], $_GET['hkey']); + } + + // List + else if (($_GET['type'] == 'list') && isset($_GET['index'])) { + $value = $redis->lGet($_GET['key'], $_GET['index']); + } + + // Set, ZSet + else if ((($_GET['type'] == 'set') || ($_GET['type'] == 'zset')) && isset($_GET['value'])) { + $value = $_GET['value']; + } +} + + + + +$page['css'][] = 'frame'; +$page['js'][] = 'frame'; + +require 'header.inc.php'; + +?> +

+
+ +

+ + +

+ +

+ +> +

+ +

+ +> +

+ +

+ +> empty to append, -1 to prepend +

+ +

+ +> +

+ +

+ + +

+ + + +

+ +

+ +
+ diff --git a/other/cachetools/phpRedisAdmin/export.php b/other/cachetools/phpRedisAdmin/export.php new file mode 100644 index 000000000..01f8541c8 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/export.php @@ -0,0 +1,197 @@ +type($key); + + if (!isset($redistypes[$type])) { + return; + } + + $type = $redistypes[$type]; + + + // String + if ($type == 'string') { + echo 'SET "',addslashes($key),'" "',addslashes($redis->get($key)),'"',PHP_EOL; + } + + // Hash + else if ($type == 'hash') { + $values = $redis->hGetAll($key); + + foreach ($values as $k => $v) { + echo 'HSET "',addslashes($key),'" "',addslashes($k),'" "',addslashes($v),'"',PHP_EOL; + } + } + + // List + else if ($type == 'list') { + $size = $redis->lSize($key); + + for ($i = 0; $i < $size; ++$i) { + echo 'RPUSH "',addslashes($key),'" "',addslashes($redis->lGet($key, $i)),'"',PHP_EOL; + } + } + + // Set + else if ($type == 'set') { + $values = $redis->sMembers($key); + + foreach ($values as $v) { + echo 'SADD "',addslashes($key),'" "',addslashes($v),'"',PHP_EOL; + } + } + + // ZSet + else if ($type == 'zset') { + $values = $redis->zRange($key, 0, -1); + + foreach ($values as $v) { + $s = $redis->zScore($key, $v); + + echo 'ZADD "',addslashes($key),'" ',$s,' "',addslashes($v),'"',PHP_EOL; + } + } +} + + + +// Return the JSON for this key +function export_json($key) { + global $redistypes, $redis; + + $type = $redis->type($key); + + if (!isset($redistypes[$type])) { + return 'undefined'; + } + + $type = $redistypes[$type]; + + + // String + if ($type == 'string') { + $value = $redis->get($key); + } + + // Hash + else if ($type == 'hash') { + $value = $redis->hGetAll($key); + } + + // List + else if ($type == 'list') { + $size = $redis->lSize($key); + $value = array(); + + for ($i = 0; $i < $size; ++$i) { + $value[] = $redis->lGet($key, $i); + } + } + + // Set + else if ($type == 'set') { + $value = $redis->sMembers($key); + } + + // ZSet + else if ($type == 'zset') { + $value = $redis->zRange($key, 0, -1); + } + + + return $value; +} + + + + +// Export +if (isset($_POST['type'])) { + if ($_POST['type'] == 'json') { + $ext = 'js'; + $ct = 'application/json'; + } else { + $ext = 'redis'; + $ct = 'text/plain'; + } + + + header('Content-type: '.$ct.'; charset=utf-8'); + header('Content-Disposition: inline; filename="export.'.$ext.'"'); + + + // JSON + if ($_POST['type'] == 'json') { + // Single key + if (isset($_GET['key'])) { + echo json_encode(export_json($_GET['key'])); + } else { // All keys + $keys = $redis->keys('*'); + $vals = array(); + + foreach ($keys as $key) { + $vals[$key] = export_json($key); + } + + echo json_encode($vals); + } + } + + // Redis Commands + else { + // Single key + if (isset($_GET['key'])) { + export_redis($_GET['key']); + } else { // All keys + $keys = $redis->keys('*'); + + foreach ($keys as $key) { + export_redis($key); + } + } + } + + + die; +} + + + + +$page['css'][] = 'frame'; +$page['js'][] = 'frame'; + +require 'header.inc.php'; + +?> +

Export

+ +
+ +

+ + +

+ +

+ +

+ +
+ diff --git a/other/cachetools/phpRedisAdmin/footer.inc.php b/other/cachetools/phpRedisAdmin/footer.inc.php new file mode 100644 index 000000000..11a09caf8 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/footer.inc.php @@ -0,0 +1,3 @@ + + + diff --git a/other/cachetools/phpRedisAdmin/functions.inc.php b/other/cachetools/phpRedisAdmin/functions.inc.php new file mode 100644 index 000000000..388f535db --- /dev/null +++ b/other/cachetools/phpRedisAdmin/functions.inc.php @@ -0,0 +1,66 @@ += 0) + $suffix = 'ago'; + else { + $when = -$when; + $suffix = 'in the future'; + } + + if ($when > $day) { + $when = round($when / $day); + $what = 'day'; + } else if ($when > $hour) { + $when = round($when / $hour); + $what = 'hour'; + } else if ($when > $minute) { + $when = round($when / $minute); + $what = 'minute'; + } else { + $what = 'second'; + } + + if ($when != 1) $what .= 's'; + + if ($ago) { + return "$when $what $suffix"; + } else { + return "$when $what"; + } +} + + +function format_size($size) { + $sizes = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); + + if ($size == 0) { + return '0 B'; + } else { + return round($size / pow(1024, ($i = floor(log($size, 1024)))), 1).' '.$sizes[$i]; + } +} + + +function str_rand($length) { + $r = ''; + + for (; $length > 0; --$length) { + $r .= chr(rand(32, 126)); // 32 - 126 is the printable ascii range + } + + return $r; +} + diff --git a/other/cachetools/phpRedisAdmin/header.inc.php b/other/cachetools/phpRedisAdmin/header.inc.php new file mode 100644 index 000000000..1d09a8889 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/header.inc.php @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + +<?php echo format_html($server['host'])?> - phpRedisAdmin + + + + + + + + + + + + + + + diff --git a/other/cachetools/phpRedisAdmin/images/add.png b/other/cachetools/phpRedisAdmin/images/add.png new file mode 100644 index 000000000..db594c821 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/add.png differ diff --git a/other/cachetools/phpRedisAdmin/images/delete.png b/other/cachetools/phpRedisAdmin/images/delete.png new file mode 100644 index 000000000..2d669c0ce Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/delete.png differ diff --git a/other/cachetools/phpRedisAdmin/images/edit.png b/other/cachetools/phpRedisAdmin/images/edit.png new file mode 100644 index 000000000..0f2f227e9 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/edit.png differ diff --git a/other/cachetools/phpRedisAdmin/images/export.png b/other/cachetools/phpRedisAdmin/images/export.png new file mode 100644 index 000000000..79a7ce538 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/export.png differ diff --git a/other/cachetools/phpRedisAdmin/images/favicon.png b/other/cachetools/phpRedisAdmin/images/favicon.png new file mode 100644 index 000000000..d38c145ee Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/favicon.png differ diff --git a/other/cachetools/phpRedisAdmin/images/folder-open.png b/other/cachetools/phpRedisAdmin/images/folder-open.png new file mode 100644 index 000000000..b8ff2ac78 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/folder-open.png differ diff --git a/other/cachetools/phpRedisAdmin/images/import.png b/other/cachetools/phpRedisAdmin/images/import.png new file mode 100644 index 000000000..17ac67b1b Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/import.png differ diff --git a/other/cachetools/phpRedisAdmin/images/info.png b/other/cachetools/phpRedisAdmin/images/info.png new file mode 100644 index 000000000..a23992539 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/info.png differ diff --git a/other/cachetools/phpRedisAdmin/images/logout.png b/other/cachetools/phpRedisAdmin/images/logout.png new file mode 100644 index 000000000..76e246dbb Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/logout.png differ diff --git a/other/cachetools/phpRedisAdmin/images/reset.png b/other/cachetools/phpRedisAdmin/images/reset.png new file mode 100644 index 000000000..063f5116a Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/reset.png differ diff --git a/other/cachetools/phpRedisAdmin/images/save.png b/other/cachetools/phpRedisAdmin/images/save.png new file mode 100644 index 000000000..75f9e6288 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/save.png differ diff --git a/other/cachetools/phpRedisAdmin/images/tree-folder-collapsed.gif b/other/cachetools/phpRedisAdmin/images/tree-folder-collapsed.gif new file mode 100644 index 000000000..8ee76a386 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/tree-folder-collapsed.gif differ diff --git a/other/cachetools/phpRedisAdmin/images/tree-folder-expanded.gif b/other/cachetools/phpRedisAdmin/images/tree-folder-expanded.gif new file mode 100644 index 000000000..682130a40 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/tree-folder-expanded.gif differ diff --git a/other/cachetools/phpRedisAdmin/images/tree-lastnode-collapsed.gif b/other/cachetools/phpRedisAdmin/images/tree-lastnode-collapsed.gif new file mode 100644 index 000000000..0d4e21d36 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/tree-lastnode-collapsed.gif differ diff --git a/other/cachetools/phpRedisAdmin/images/tree-lastnode-expanded.gif b/other/cachetools/phpRedisAdmin/images/tree-lastnode-expanded.gif new file mode 100644 index 000000000..f1cd23d60 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/tree-lastnode-expanded.gif differ diff --git a/other/cachetools/phpRedisAdmin/images/tree-lastnode.gif b/other/cachetools/phpRedisAdmin/images/tree-lastnode.gif new file mode 100644 index 000000000..238e38291 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/tree-lastnode.gif differ diff --git a/other/cachetools/phpRedisAdmin/images/tree-node.gif b/other/cachetools/phpRedisAdmin/images/tree-node.gif new file mode 100644 index 000000000..2bfed48d2 Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/tree-node.gif differ diff --git a/other/cachetools/phpRedisAdmin/images/tree-vline.gif b/other/cachetools/phpRedisAdmin/images/tree-vline.gif new file mode 100644 index 000000000..9793ee3af Binary files /dev/null and b/other/cachetools/phpRedisAdmin/images/tree-vline.gif differ diff --git a/other/cachetools/phpRedisAdmin/import.php b/other/cachetools/phpRedisAdmin/import.php new file mode 100644 index 000000000..dc8bebccb --- /dev/null +++ b/other/cachetools/phpRedisAdmin/import.php @@ -0,0 +1,122 @@ +set($commands[$i+1], $commands[$i+2]); + $i += 2; + break; + } + + case 'HSET': { + $redis->hSet($commands[$i+1], $commands[$i+2], $commands[$i+3]); + $i += 3; + break; + } + + case 'LPUSH': { + $redis->lPush($commands[$i+1], $commands[$i+2]); + $i += 2; + break; + } + + case 'RPUSH': { + $redis->rPush($commands[$i+1], $commands[$i+2]); + $i += 2; + break; + } + + case 'LSET': { + $redis->lSet($commands[$i+1], $commands[$i+2], $commands[$i+3]); + $i += 3; + break; + } + + case 'SADD': { + $redis->sAdd($commands[$i+1], $commands[$i+2]); + $i += 2; + break; + } + + case 'ZADD': { + $redis->zAdd($commands[$i+1], $commands[$i+2], $commands[$i+3]); + $i += 3; + break; + } + } + } + + + // Refresh the top so the key tree is updated. + require 'header.inc.php'; + + ?> + + +

Import

+
+ +

+ + +

+ +

+ +

+ +
+ diff --git a/other/cachetools/phpRedisAdmin/index.php b/other/cachetools/phpRedisAdmin/index.php new file mode 100644 index 000000000..001b0d306 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/index.php @@ -0,0 +1,205 @@ +keys('*'); + +sort($keys); + +$namespaces = array(); // Array to hold our top namespaces. + +// Build an array of nested arrays containing all our namespaces and containing keys. +foreach ($keys as $key) { + // Ignore keys that are to long (Redis supports keys that can be way to long to put in an url). + if (strlen($key) > $config['maxkeylen']) { + continue; + } + + $key = explode($config['seperator'], $key); + + // $d will be a reference to the current namespace. + $d = &$namespaces; + + // We loop though all the namespaces for this key creating the array for each. + // Each time updating $d to be a reference to the last namespace so we can create the next one in it. + for ($i = 0; $i < (count($key) - 1); ++$i) { + if (!isset($d[$key[$i]])) { + $d[$key[$i]] = array(); + } + + $d = &$d[$key[$i]]; + } + + // Containing an item named __phpredisadmin__ means it's also a key. + // This means that creating an actual key named __phpredisadmin__ will make this bug. + $d[$key[count($key) - 1]] = array('__phpredisadmin__' => true); + + // Unset $d so we don't accidentally overwrite it somewhere else. + unset($d); +} + + + +// This is basically the same as the click code in index.js. +// Just build the url for the frame based on our own url. +if (count($_GET) == 0) { + $iframe = 'overview.php'; +} else { + $iframe = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], '?') + 1); + + if (strpos($iframe, '&') !== false) { + $iframe = substr_replace($iframe, '.php?', strpos($iframe, '&'), 1); + } else { + $iframe .= '.php'; + } +} + + + + + + +// Recursive function used to print the namespaces. +function print_namespace($item, $name, $fullkey, $islast) { + global $config, $redistypes, $server, $redis; + + // Is this also a key and not just a namespace? + if (isset($item['__phpredisadmin__'])) { + // Unset it so we won't loop over it when printing this namespace. + unset($item['__phpredisadmin__']); + + $type = $redis->type($fullkey); + + if (!isset($redistypes[$type])) { + return; + } + + $type = $redistypes[$type]; + $class = array(); + $len = false; + + if (isset($_GET['key']) && ($fullkey == $_GET['key'])) { + $class[] = 'current'; + } + if ($islast) { + $class[] = 'last'; + } + + // Get the number of items in the key. + if (!isset($config['faster']) || !$config['faster']) { + switch ($type) { + case 'hash': + $len = $redis->hLen($fullkey); + break; + + case 'list': + $len = $redis->lSize($fullkey); + break; + + case 'set': + // This is currently the only way to do this, this can be slow since we need to retrieve all keys + $len = count($redis->sMembers($fullkey)); + break; + + case 'zset': + // This is currently the only way to do this, this can be slow since we need to retrieve all keys + $len = count($redis->zRange($fullkey, 0, -1)); + break; + } + } + + + ?> + > + () + + 0) { + ?> +
  • +
     () + [X] +
      + $childitem) { + // $fullkey will be empty on the first call. + if (empty($fullkey)) { + $childfullkey = $childname; + } else { + $childfullkey = $fullkey.$config['seperator'].$childname; + } + + print_namespace($childitem, $childname, $childfullkey, (--$l == 0)); + } + + ?> +
    +
  • + + + diff --git a/other/cachetools/phpRedisAdmin/info.php b/other/cachetools/phpRedisAdmin/info.php new file mode 100644 index 000000000..69c5338f9 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/info.php @@ -0,0 +1,60 @@ +resetStat(); + + header('Location: info.php'); + die; +} + + + +// Fetch the info +$info = $redis->info(); +$alt = false; + + + + +$page['css'][] = 'frame'; +$page['js'][] = 'frame'; + +require 'header.inc.php'; + +?> +

    Info

    + + +

    +Reset usage statistics +

    + + + + + $value) { + if ($key == 'allocation_stats') { // This key is very long to split it into multiple lines + $value = str_replace(',', ",\n", $value); + } + + ?> + > + +
    Key
    Value
    + diff --git a/other/cachetools/phpRedisAdmin/js/frame.js b/other/cachetools/phpRedisAdmin/js/frame.js new file mode 100644 index 000000000..2fb031dac --- /dev/null +++ b/other/cachetools/phpRedisAdmin/js/frame.js @@ -0,0 +1,30 @@ + +$(function() { + if (history.replaceState) { + window.parent.history.replaceState({}, '', document.location.href.replace('?', '&').replace(/([a-z]*)\.php/, '?$1')); + } + + + $('#type').change(function(e) { + $('#hkeyp' ).css('display', e.target.value == 'hash' ? 'block' : 'none'); + $('#indexp').css('display', e.target.value == 'list' ? 'block' : 'none'); + $('#scorep').css('display', e.target.value == 'zset' ? 'block' : 'none'); + }).change(); + + + $('.delkey, .delval').click(function(e) { + e.preventDefault(); + + if (confirm($(this).hasClass('delkey') ? 'Are you sure you want to delete this key and all it\'s values?' : 'Are you sure you want to delete this value?')) { + $.ajax({ + type: "POST", + url: this.href, + data: 'post=1', + success: function(url) { + top.location.href = top.location.pathname+url; + } + }); + } + }); +}); + diff --git a/other/cachetools/phpRedisAdmin/js/index.js b/other/cachetools/phpRedisAdmin/js/index.js new file mode 100644 index 000000000..e2fb7e8d3 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/js/index.js @@ -0,0 +1,103 @@ + +$(function() { + $('#sidebar a').click(function(e) { + if (e.currentTarget.href.indexOf('/?') == -1) { + return; + } + + e.preventDefault(); + + var href; + + if ((e.currentTarget.href.indexOf('?') == -1) || + (e.currentTarget.href.indexOf('?') == (e.currentTarget.href.length - 1))) { + href = 'overview.php'; + } else { + href = e.currentTarget.href.substr(e.currentTarget.href.indexOf('?') + 1); + + if (href.indexOf('&') != -1) { + href = href.replace('&', '.php?'); + } else { + href += '.php'; + } + } + + $('#iframe').attr('src', href); + }); + + + $('#server').change(function(e) { + if (location.href.indexOf('?') == -1) { + location.href = location.href+'?s='+e.target.value; + } else if (location.href.indexOf('&s=') == -1) { + location.href = location.href+'&s='+e.target.value; + } else { + location.href = location.href.replace(/s=[0-9]*/, 's='+e.target.value); + } + }); + + + $('li.current').parents('li.folder').removeClass('collapsed'); + + $('li.folder').click(function(e) { + var t = $(this); + + if ((e.pageY >= t.offset().top) && + (e.pageY <= t.offset().top + t.children('div').height())) { + e.stopPropagation(); + t.toggleClass('collapsed'); + } + }); + + $('a').click(function() { + $('li.current').removeClass('current'); + }); + + $('li a').click(function() { + $(this).parent().addClass('current'); + }); + + + $('#filter').focus(function() { + if ($(this).hasClass('info')) { + $(this).removeClass('info').val(''); + } + }).keyup(function() { + var val = $(this).val(); + + $('li:not(.folder)').each(function(i, el) { + var key = $('a', el).get(0); + var key = unescape(key.href.substr(key.href.indexOf('key=') + 4)); + + if (key.indexOf(val) == -1) { + $(el).addClass('hidden'); + } else { + $(el).removeClass('hidden'); + } + }); + + $('li.folder').each(function(i, el) { + if ($('li:not(.hidden, .folder)', el).length == 0) { + $(el).addClass('hidden'); + } else { + $(el).removeClass('hidden'); + } + }); + }); + + $('.deltree').click(function(e) { + e.preventDefault(); + + if (confirm('Are you sure you want to delete this whole tree and all it\'s keys?')) { + $.ajax({ + type: "POST", + url: this.href, + data: 'post=1', + success: function(url) { + top.location.href = top.location.pathname; + } + }); + } + }); +}); + diff --git a/other/cachetools/phpRedisAdmin/login.inc.php b/other/cachetools/phpRedisAdmin/login.inc.php new file mode 100644 index 000000000..633bd9460 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/login.inc.php @@ -0,0 +1,63 @@ + 1, + 'nc' => 1, + 'cnonce' => 1, + 'qop' => 1, + 'username' => 1, + 'uri' => 1, + 'response' => 1 + ); + +$data = array(); +$keys = implode('|', array_keys($needed_parts)); + +preg_match_all('/('.$keys.')=(?:([\'"])([^\2]+?)\2|([^\s,]+))/', $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER); + +foreach ($matches as $m) { + $data[$m[1]] = $m[3] ? $m[3] : $m[4]; + unset($needed_parts[$m[1]]); +} + +if (!empty($needed_parts)) { + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Digest realm="'.$realm.'",qop="auth",nonce="'.uniqid().'",opaque="'.$opaque.'"'); + die; +} + +if (!isset($config['login'][$data['username']])) { + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Digest realm="'.$realm.'",qop="auth",nonce="'.uniqid().'",opaque="'.$opaque.'"'); + die('Invalid username and/or password combination.'); +} + +$login = $config['login'][$data['username']]; +$login['name'] = $data['username']; + +$password = md5($login['name'].':'.$realm.':'.$login['password']); + +$response = md5($password.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.md5($_SERVER['REQUEST_METHOD'].':'.$data['uri'])); + +if ($data['response'] != $response) { + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Digest realm="'.$realm.'",qop="auth",nonce="'.uniqid().'",opaque="'.$opaque.'"'); + die('Invalid username and/or password combination.'); +} + +?> diff --git a/other/cachetools/phpRedisAdmin/logout.php b/other/cachetools/phpRedisAdmin/logout.php new file mode 100644 index 000000000..502d33959 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/logout.php @@ -0,0 +1,40 @@ + 1, + 'nc' => 1, + 'cnonce' => 1, + 'qop' => 1, + 'username' => 1, + 'uri' => 1, + 'response' => 1 + ); + +$data = array(); +$keys = implode('|', array_keys($needed_parts)); + +preg_match_all('/('.$keys.')=(?:([\'"])([^\2]+?)\2|([^\s,]+))/', $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER); + +foreach ($matches as $m) { + $data[$m[1]] = $m[3] ? $m[3] : $m[4]; + unset($needed_parts[$m[1]]); +} + + +if (!isset($_GET['nonce'])) { + header('Location: logout.php?nonce='.$data['nonce']); + die; +} + + +if ($data['nonce'] == $_GET['nonce']) { + unset($_SERVER['PHP_AUTH_DIGEST']); + + require 'login.inc.php'; +} + + +header('Location: '.substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], 'logout.php'))); + +?> diff --git a/other/cachetools/phpRedisAdmin/overview.php b/other/cachetools/phpRedisAdmin/overview.php new file mode 100644 index 000000000..3d73bc0d4 --- /dev/null +++ b/other/cachetools/phpRedisAdmin/overview.php @@ -0,0 +1,84 @@ + $server) { + if (!isset($server['db'])) { + $server['db'] = 0; + } + + // Setup a connection to this Redis server. + $redis->close(); + + try { + $redis->connect($server['host'], $server['port']); + } catch (Exception $e) { + die('ERROR: Could not connect to Redis ('.$server['host'].':'.$server['port'].')'); + } + + + if (isset($server['auth'])) { + if (!$redis->auth($server['auth'])) { + die('ERROR: Authentication failed ('.$server['host'].':'.$server['port'].')'); + } + } + + + if ($server['db'] != 0) { + if (!$redis->select($server['db'])) { + die('ERROR: Selecting database failed ('.$server['host'].':'.$server['port'].','.$server['db'].')'); + } + } + + + $info[$i] = $redis->info(); + $info[$i]['size'] = $redis->dbSize(); +} + + + + +$page['css'][] = 'frame'; +$page['js'][] = 'frame'; + +require 'header.inc.php'; + +?> + + $server) { ?> +
    +

    + + + + + + + + + + + + + +
    Redis version:
    Keys:
    Memory used:
    Uptime:
    Last save:
    [S]
    +
    + + +

    +phpRedisAdmin on GitHub +

    + +

    +Redis Documentation +

    + diff --git a/other/cachetools/phpRedisAdmin/page.inc.php b/other/cachetools/phpRedisAdmin/page.inc.php new file mode 100644 index 000000000..474a8c80f --- /dev/null +++ b/other/cachetools/phpRedisAdmin/page.inc.php @@ -0,0 +1,22 @@ + array('common'), + 'js' => array() +); + +?> \ No newline at end of file diff --git a/other/cachetools/phpRedisAdmin/rename.php b/other/cachetools/phpRedisAdmin/rename.php new file mode 100644 index 000000000..8264f1bed --- /dev/null +++ b/other/cachetools/phpRedisAdmin/rename.php @@ -0,0 +1,56 @@ + $config['maxkeylen']) { + die('ERROR: Your key is to long (max length is '.$config['maxkeylen'].')'); + } + + $redis->rename($_POST['old'], $_POST['key']); + + + // Refresh the top so the key tree is updated. + require 'header.inc.php'; + + ?> + + +

    Edit Name of

    +
    + + + +

    + +> +

    + +

    + +

    + +
    + diff --git a/other/cachetools/phpRedisAdmin/save.php b/other/cachetools/phpRedisAdmin/save.php new file mode 100644 index 000000000..56214a9ff --- /dev/null +++ b/other/cachetools/phpRedisAdmin/save.php @@ -0,0 +1,30 @@ + +

    Saving

    + +... +save(); + +?> + done. + \ No newline at end of file diff --git a/other/cachetools/phpRedisAdmin/ttl.php b/other/cachetools/phpRedisAdmin/ttl.php new file mode 100644 index 000000000..fd9752d7e --- /dev/null +++ b/other/cachetools/phpRedisAdmin/ttl.php @@ -0,0 +1,50 @@ +persist($_POST['key']); + } else { + $redis->setTimeout($_POST['key'], $_POST['ttl']); + } + + header('Location: view.php?key='.urlencode($_POST['key'])); + die; +} + + + + +$page['css'][] = 'frame'; +$page['js'][] = 'frame'; + +require 'header.inc.php'; + +?> +

    Edit TTL

    +
    + +

    + +> +

    + +

    + +> (-1 to remove the TTL) +

    + +

    + +

    + +
    + diff --git a/other/cachetools/phpRedisAdmin/view.php b/other/cachetools/phpRedisAdmin/view.php new file mode 100644 index 000000000..6f55f38de --- /dev/null +++ b/other/cachetools/phpRedisAdmin/view.php @@ -0,0 +1,207 @@ + + Invalid key + type($_GET['key']); +$exists = $redis->exists($_GET['key']); + + +?> +

    + + [R] + [X] + [E] + +

    + + This key does not exist. + ttl($_GET['key']); +$encoding = $redis->object('encoding', $_GET['key']); + + +switch ($type) { + case 'string': + $value = $redis->get($_GET['key']); + $size = strlen($value); + break; + + case 'hash': + $values = $redis->hGetAll($_GET['key']); + $size = count($values); + break; + + case 'list': + $size = $redis->lSize($_GET['key']); + break; + + case 'set': + $values = $redis->sMembers($_GET['key']); + $size = count($values); + break; + + case 'zset': + $values = $redis->zRange($_GET['key'], 0, -1); + $size = count($values); + break; +} + + +?> + + + + + + + + + + +
    Type:
    TTL:
    [E]
    Encoding:
    Size:
    + +

    + + + + +
    + [E] +
    + [X] +
    + + + + + + + $value) { ?> + > + + + + +
    Key
    Value
     
     
    + [E] +
    + [X] +
    + + +lGet($_GET['key'], $i); +?> + > + + + +
    Index
    Value
     
     
    + [E] +
    + [X] +
    + + +exists($value) ? ''.nl2br(format_html($value)).'' : nl2br(format_html($value)); +?> + > + + + + +
    Value
     
     
    + [E] +
    + [X] +
    + + +zScore($_GET['key'], $value); + $display_value = $redis->exists($value) ? ''.nl2br(format_html($value)).'' : nl2br(format_html($value)); +?> + > + + + +
    Score
    Value
     
     
    + [E] + [X] +
    + +

    + Add another value +

    +