5. 用 PHP 源码操作 memcache(2)
如何使用PHP源码来操作memcached服务
如果管理员不让我们去加载 memcache.dll 文件,我们可以直接通过源码操作.先关闭扩展.
mem3.php
<?phprequire_once './memcached.php';$mc = new memcached(array('servers' => array('127.0.0.1:11211'),//连接memcache 的 ip 和端口'debug' => false, //是否debug'compress_threshold' => 10240, //最大压缩'persistant' => true));//是否是持久连接$mc->add('key2','hello');
// $mc->replace('key', 'some random string');$val = $mc->get('key2');
echo $val;
//修改
$mc->set('key1','北京');
$val1 = $mc->get('key1');
var_dump($val1);//删除
$mc->delete('key1');
$val2 = $mc->get('key1');
var_dump($val2);
memcached.php 源码
<?php
//
// +---------------------------------------------------------------------------+
// | memcached client, PHP |
// +---------------------------------------------------------------------------+
// | Copyright (c) 2003 Ryan T. Dean <rtdean@cytherianage.net> |
// | All rights reserved. |
// | |
// | Redistribution and use in source and binary forms, with or without |
// | modification, are permitted provided that the following conditions |
// | are met: |
// | |
// | 1. Redistributions of source code must retain the above copyright |
// | notice, this list of conditions and the following disclaimer. |
// | 2. Redistributions in binary form must reproduce the above copyright |
// | notice, this list of conditions and the following disclaimer in the |
// | documentation and/or other materials provided with the distribution. |
// | |
// | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
// | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
// | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
// | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
// | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
// | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// +---------------------------------------------------------------------------+
// | Author: Ryan T. Dean <rtdean@cytherianage.net> |
// | Heavily influenced by the Perl memcached client by Brad Fitzpatrick. |
// | Permission granted by Brad Fitzpatrick for relicense of ported Perl |
// | client logic under 2-clause BSD license. |
// +---------------------------------------------------------------------------+
//
// $TCAnet$
///*** This is the PHP client for memcached - a distributed memory cache daemon.* More information is available at http://www.danga.com/memcached/** Usage example:** require_once 'memcached.php';* * $mc = new memcached(array(* 'servers' => array('127.0.0.1:10000', * array('192.0.0.1:10010', 2),* '127.0.0.1:10020'),* 'debug' => false,* 'compress_threshold' => 10240,* 'persistant' => true));** $mc->add('key', array('some', 'array'));* $mc->replace('key', 'some random string');* $val = $mc->get('key');** @author Ryan T. Dean <rtdean@cytherianage.net>* @package memcached-client* @version 0.1.2*/// {{{ requirements
// }}}// {{{ constants
// {{{ flags/*** Flag: indicates data is serialized*/
define("MEMCACHE_SERIALIZED", 1<<0);/*** Flag: indicates data is compressed*/
define("MEMCACHE_COMPRESSED", 1<<1);// }}}/*** Minimum savings to store data compressed*/
define("COMPRESSION_SAVINGS", 0.20);// }}}// {{{ class memcached
/*** memcached client class implemented using (p)fsockopen()** @author Ryan T. Dean <rtdean@cytherianage.net>* @package memcached-client*/
class memcached
{// {{{ properties// {{{ public/*** Command statistics** @var array* @access public*/var $stats;// }}}// {{{ private/*** Cached Sockets that are connected** @var array* @access private*/var $_cache_sock;/*** Current debug status; 0 - none to 9 - profiling** @var boolean* @access private*/var $_debug;/*** Dead hosts, assoc array, 'host'=>'unixtime when ok to check again'** @var array* @access private*/var $_host_dead;/*** Is compression available?** @var boolean* @access private*/var $_have_zlib;/*** Do we want to use compression?** @var boolean* @access private*/var $_compress_enable;/*** At how many bytes should we compress?** @var interger* @access private*/var $_compress_threshold;/*** Are we using persistant links?** @var boolean* @access private*/var $_persistant;/*** If only using one server; contains ip:port to connect to** @var string* @access private*/var $_single_sock;/*** Array containing ip:port or array(ip:port, weight)** @var array* @access private*/var $_servers;/*** Our bit buckets** @var array* @access private*/var $_buckets;/*** Total # of bit buckets we have** @var interger* @access private*/var $_bucketcount;/*** # of total servers we have** @var interger* @access private*/var $_active;// }}}// }}}// {{{ methods// {{{ public functions// {{{ memcached()/*** Memcache initializer** @param array $args Associative array of settings** @return mixed* @access public*/public function __construct ($args){$this->set_servers($args['servers']);$this->_debug = $args['debug'];$this->stats = array();$this->_compress_threshold = $args['compress_threshold'];$this->_persistant = isset($args['persistant']) ? $args['persistant'] : false;$this->_compress_enable = true;$this->_have_zlib = function_exists("gzcompress");$this->_cache_sock = array();$this->_host_dead = array();}// }}}// {{{ add()/*** Adds a key/value to the memcache server if one isn't already set with * that key** @param string $key Key to set with data* @param mixed $val Value to store* @param interger $exp (optional) Time to expire data at** @return boolean* @access public*/function add ($key, $val, $exp = 0){return $this->_set('add', $key, $val, $exp);}// }}}// {{{ decr()/*** Decriment a value stored on the memcache server** @param string $key Key to decriment* @param interger $amt (optional) Amount to decriment** @return mixed FALSE on failure, value on success* @access public*/function decr ($key, $amt=1){return $this->_incrdecr('decr', $key, $amt);}// }}}// {{{ delete()/*** Deletes a key from the server, optionally after $time** @param string $key Key to delete* @param interger $time (optional) How long to wait before deleting** @return boolean TRUE on success, FALSE on failure* @access public*/function delete ($key, $time = 0){if (!$this->_active)return false;$sock = $this->get_sock($key);if (!is_resource($sock))return false;$key = is_array($key) ? $key[1] : $key;$this->stats['delete']++;$cmd = "delete $key $time\r\n";if(!fwrite($sock, $cmd, strlen($cmd))){$this->_dead_sock($sock);return false;}$res = trim(fgets($sock));if ($this->_debug)printf("MemCache: delete %s (%s)\n", $key, $res);if ($res == "DELETED")return true;return false;}// }}}// {{{ disconnect_all()/*** Disconnects all connected sockets** @access public*/function disconnect_all (){foreach ($this->_cache_sock as $sock)fclose($sock);$this->_cache_sock = array();}// }}}// {{{ enable_compress()/*** Enable / Disable compression** @param boolean $enable TRUE to enable, FALSE to disable** @access public*/function enable_compress ($enable){$this->_compress_enable = $enable;}// }}}// {{{ forget_dead_hosts()/*** Forget about all of the dead hosts** @access public*/function forget_dead_hosts (){$this->_host_dead = array();}// }}}// {{{ get()/*** Retrieves the value associated with the key from the memcache server** @param string $key Key to retrieve** @return mixed* @access public*/function get ($key){if (!$this->_active)return false;$sock = $this->get_sock($key);if (!is_resource($sock))return false;$this->stats['get']++;$cmd = "get $key\r\n";if (!fwrite($sock, $cmd, strlen($cmd))){$this->_dead_sock($sock);return false;}$val = array();$this->_load_items($sock, $val);if ($this->_debug)foreach ($val as $k => $v)printf("MemCache: sock %s got %s => %s\r\n", $sock, $k, $v);return $val[$key];}// }}}// {{{ get_multi()/*** Get multiple keys from the server(s)** @param array $keys Keys to retrieve** @return array* @access public* get('key1') keys=array('key1','key2');*/function get_multi ($keys){if (!$this->_active)return false;$this->stats['get_multi']++;foreach ($keys as $key){$sock = $this->get_sock($key);if (!is_resource($sock)) continue;$key = is_array($key) ? $key[1] : $key;if (!isset($sock_keys[$sock])){$sock_keys[$sock] = array();$socks[] = $sock;}$sock_keys[$sock][] = $key;}// Send out the requestsforeach ($socks as $sock){$cmd = "get";foreach ($sock_keys[$sock] as $key){$cmd .= " ". $key;}$cmd .= "\r\n";if (fwrite($sock, $cmd, strlen($cmd))){$gather[] = $sock;} else{$this->_dead_sock($sock);}}// Parse responses$val = array();foreach ($gather as $sock){$this->_load_items($sock, $val);}if ($this->_debug)foreach ($val as $k => $v)printf("MemCache: got %s => %s\r\n", $k, $v);return $val;}// }}}// {{{ incr()/*** Increments $key (optionally) by $amt** @param string $key Key to increment* @param interger $amt (optional) amount to increment** @return interger New key value?* @access public*/function incr ($key, $amt=1){return $this->_incrdecr('incr', $key, $amt);}// }}}// {{{ replace()/*** Overwrites an existing value for key; only works if key is already set** @param string $key Key to set value as* @param mixed $value Value to store* @param interger $exp (optional) Experiation time** @return boolean* @access public*/function replace ($key, $value, $exp=0){return $this->_set('replace', $key, $value, $exp);}// }}}// {{{ run_command()/*** Passes through $cmd to the memcache server connected by $sock; returns * output as an array (null array if no output)** NOTE: due to a possible bug in how PHP reads while using fgets(), each* line may not be terminated by a \r\n. More specifically, my testing* has shown that, on FreeBSD at least, each line is terminated only* with a \n. This is with the PHP flag auto_detect_line_endings set* to falase (the default).** @param resource $sock Socket to send command on* @param string $cmd Command to run** @return array Output array* @access public*/function run_command ($sock, $cmd){if (!is_resource($sock))return array();if (!fwrite($sock, $cmd, strlen($cmd)))return array();while (true){$res = fgets($sock);$ret[] = $res;if (preg_match('/^END/', $res))break;if (strlen($res) == 0)break;}return $ret;}// }}}// {{{ set()/*** Unconditionally sets a key to a given value in the memcache. Returns true* if set successfully.** @param string $key Key to set value as* @param mixed $value Value to set* @param interger $exp (optional) Experiation time** @return boolean TRUE on success* @access public*/function set ($key, $value, $exp=0){return $this->_set('set', $key, $value, $exp);}// }}}// {{{ set_compress_threshold()/*** Sets the compression threshold** @param interger $thresh Threshold to compress if larger than** @access public*/function set_compress_threshold ($thresh){$this->_compress_threshold = $thresh;}// }}}// {{{ set_debug()/*** Sets the debug flag** @param boolean $dbg TRUE for debugging, FALSE otherwise** @access public** @see memcahced::memcached*/function set_debug ($dbg){$this->_debug = $dbg;}// }}}// {{{ set_servers()/*** Sets the server list to distribute key gets and puts between** @param array $list Array of servers to connect to** @access public** @see memcached::memcached()*/function set_servers ($list){$this->_servers = $list;$this->_active = count($list);$this->_buckets = null;$this->_bucketcount = 0;$this->_single_sock = null;if ($this->_active == 1)$this->_single_sock = $this->_servers[0];}// }}}// }}}// {{{ private methods// {{{ _close_sock()/*** Close the specified socket** @param string $sock Socket to close** @access private*/function _close_sock ($sock){$host = array_search($sock, $this->_cache_sock);fclose($this->_cache_sock[$host]);unset($this->_cache_sock[$host]);}// }}}// {{{ _connect_sock()/*** Connects $sock to $host, timing out after $timeout** @param interger $sock Socket to connect* @param string $host Host:IP to connect to* @param float $timeout (optional) Timeout value, defaults to 0.25s** @return boolean* @access private*/function _connect_sock (&$sock, $host, $timeout = 0.25){list ($ip, $port) = explode(":", $host);if ($this->_persistant == 1){$sock = @pfsockopen($ip, $port, $errno, $errstr, $timeout);} else{$sock = @fsockopen($ip, $port, $errno, $errstr, $timeout);}if (!$sock)return false;return true;}// }}}// {{{ _dead_sock()/*** Marks a host as dead until 30-40 seconds in the future** @param string $sock Socket to mark as dead** @access private*/function _dead_sock ($sock){$host = array_search($sock, $this->_cache_sock);list ($ip, $port) = explode(":", $host);$this->_host_dead[$ip] = time() + 30 + intval(rand(0, 10));$this->_host_dead[$host] = $this->_host_dead[$ip];unset($this->_cache_sock[$host]);}// }}}// {{{ get_sock()/*** get_sock** @param string $key Key to retrieve value for;** @return mixed resource on success, false on failure* @access private*/function get_sock ($key){if (!$this->_active)return false;if ($this->_single_sock !== null)return $this->sock_to_host($this->_single_sock);$hv = is_array($key) ? intval($key[0]) : $this->_hashfunc($key);if ($this->_buckets === null){foreach ($this->_servers as $v){if (is_array($v)){for ($i=0; $i<$v[1]; $i++)$bu[] = $v[0];} else{$bu[] = $v;}}$this->_buckets = $bu;$this->_bucketcount = count($bu);}$realkey = is_array($key) ? $key[1] : $key;for ($tries = 0; $tries<20; $tries++){$host = $this->_buckets[$hv % $this->_bucketcount];$sock = $this->sock_to_host($host);if (is_resource($sock))return $sock;$hv += $this->_hashfunc($tries . $realkey);}return false;}// }}}// {{{ _hashfunc()/*** Creates a hash interger based on the $key** @param string $key Key to hash** @return interger Hash value* @access private*/function _hashfunc ($key){$hash = 0;for ($i=0; $i<strlen($key); $i++){$hash = $hash*33 + ord($key[$i]);}return $hash;}// }}}// {{{ _incrdecr()/*** Perform increment/decriment on $key** @param string $cmd Command to perform* @param string $key Key to perform it on* @param interger $amt Amount to adjust** @return interger New value of $key* @access private*/function _incrdecr ($cmd, $key, $amt=1){if (!$this->_active)return null;$sock = $this->get_sock($key);if (!is_resource($sock))return null;$key = is_array($key) ? $key[1] : $key;$this->stats[$cmd]++;if (!fwrite($sock, "$cmd $key $amt\r\n"))return $this->_dead_sock($sock);stream_set_timeout($sock, 1, 0);$line = fgets($sock);if (!preg_match('/^(\d+)/', $line, $match))return null;return $match[1];}// }}}// {{{ _load_items()/*** Load items into $ret from $sock** @param resource $sock Socket to read from* @param array $ret Returned values** @access private*/function _load_items ($sock, &$ret){while (1){$decl = fgets($sock);if ($decl == "END\r\n"){return true;} elseif (preg_match('/^VALUE (\S+) (\d+) (\d+)\r\n$/', $decl, $match)){list($rkey, $flags, $len) = array($match[1], $match[2], $match[3]);$bneed = $len+2;$offset = 0;while ($bneed > 0){$data = fread($sock, $bneed);$n = strlen($data);if ($n == 0)break;$offset += $n;$bneed -= $n;$ret[$rkey] .= $data;}if ($offset != $len+2){// Something is borked!if ($this->_debug)printf("Something is borked! key %s expecting %d got %d length\n", $rkey, $len+2, $offset);unset($ret[$rkey]);$this->_close_sock($sock);return false;}$ret[$rkey] = rtrim($ret[$rkey]);if ($this->_have_zlib && $flags & MEMCACHE_COMPRESSED)$ret[$rkey] = gzuncompress($ret[$rkey]);if ($flags & MEMCACHE_SERIALIZED)$ret[$rkey] = unserialize($ret[$rkey]);} else {if ($this->_debug)print("Error parsing memcached response\n");return 0;}}}// }}}// {{{ _set()/*** Performs the requested storage operation to the memcache server** @param string $cmd Command to perform* @param string $key Key to act on* @param mixed $val What we need to store* @param interger $exp When it should expire** @return boolean* @access private*/function _set ($cmd, $key, $val, $exp){if (!$this->_active)return false;//get_sock就是去获取到memcached服务器连接$sock = $this->get_sock($key);if (!is_resource($sock))return false;$this->stats[$cmd]++;$flags = 0;if (!is_scalar($val)){$val = serialize($val);$flags |= MEMCACHE_SERIALIZED;if ($this->_debug)printf("client: serializing data as it is not scalar\n");}$len = strlen($val);if ($this->_have_zlib && $this->_compress_enable && $this->_compress_threshold && $len >= $this->_compress_threshold){$c_val = gzcompress($val, 9);$c_len = strlen($c_val);if ($c_len < $len*(1 - COMPRESS_SAVINGS)){if ($this->_debug)printf("client: compressing data; was %d bytes is now %d bytes\n", $len, $c_len);$val = $c_val;$len = $c_len;$flags |= MEMCACHE_COMPRESSED;}}if (!fwrite($sock, "$cmd $key $flags $exp $len\r\n$val\r\n"))return $this->_dead_sock($sock);$line = trim(fgets($sock));if ($this->_debug){if ($flags & MEMCACHE_COMPRESSED)$val = 'compressed data';printf("MemCache: %s %s => %s (%s)\n", $cmd, $key, $val, $line);}if ($line == "STORED")return true;return false;}// }}}// {{{ sock_to_host()/*** Returns the socket for the host** @param string $host Host:IP to get socket for** @return mixed IO Stream or false* @access private*/function sock_to_host ($host){if (isset($this->_cache_sock[$host]))return $this->_cache_sock[$host];$now = time();list ($ip, $port) = explode (":", $host);if (isset($this->_host_dead[$host]) && $this->_host_dead[$host] > $now ||isset($this->_host_dead[$ip]) && $this->_host_dead[$ip] > $now)return null;if (!$this->_connect_sock($sock, $host))return $this->_dead_sock($host);// Do not buffer writesstream_set_write_buffer($sock, 0);$this->_cache_sock[$host] = $sock;return $this->_cache_sock[$host];}// }}}// }}}// }}}
}// }}}
?>
5. 用 PHP 源码操作 memcache(2)相关推荐
- 在Windows和Linux上编译gRPC源码操作步骤(C++)
gRPC最新发布版本为v1.23.0,下面以此版本为例说明在Windows和Linux下编译过程. Windows7/10 vs2103编译gRPC源码操作步骤: 1. 需要本机已安装Git.CMak ...
- java 留言板源码,JSP留言板的JSP源码操作实施
JSP留言板的JSP源码操作实施 很多JSP编程的爱好者都是出于要做网站的目的,那么网站的PR值就很重要网站的PR值全称为PageRank),是google搜索排名算法中的一个组成部分,级别从1到10 ...
- [转]php与memcached服务器交互的分布式实现源码分析[memcache版]
原文链接:http://www.cnblogs.com/luckcs/articles/2619846.html 前段时间,因为一个项目的关系,研究了php通过调用memcache和memcached ...
- Ubuntu 14.04上使用CMake编译MXNet源码操作步骤(Python)
MXNet源码版本号为1.3.0,其它依赖库的版本号可参考:https://blog.csdn.net/fengbingchun/article/details/84997490 . 为了通过编译源码 ...
- Windows10上使用VS2017编译MXNet源码操作步骤(C++)
MXNet是一种开源的深度学习框架,核心代码是由C++实现.MXNet官网推荐使用VS2015或VS2017编译,因为源码中使用了一些C++14的特性,VS2013是不支持的.这里通过VS2017编译 ...
- Ubuntu下安装Cppcheck源码操作步骤
Cppcheck是用在C.C++中对code进行静态检查的工具.它的源码在 https://github.com/danmar/cppcheck .它的License是GPL-3.0. Cppche ...
- Ubuntu14.04上编译指定版本的protobuf源码操作步骤
Google Protobuf的介绍可以参考 http://blog.csdn.net/fengbingchun/article/details/49977903 ,这里介绍在Ubuntu14.04上 ...
- java调用caffe_Caffe中master与windows分支差异对比及通过命令提示符编译Caffe源码操作步骤...
目前GitHub https://github.com/fengbingchun/Caffe_Test 中的caffe还是依赖较老的版本,更新于2015.08.15,commit为09868ac,近 ...
- 海思3559A上编译Valgrind源码操作步骤
注:按照以下步骤可以在海思板子上正常编译valgrind源码并生成valgrind可执行文件,但可能还不能在海思板子上正常使用. 1. 从http://valgrind.org/downloads/? ...
- 海思3559A上编译OpenCV4.1.0源码操作步骤
1. 从https://github.com/opencv/opencv/releases 下载opencv源码opencv-4.1.0.zip并解压缩: 2. 修改最顶层的CMakeLists.tx ...
最新文章
- AI会完美的执行我们设定的目标,但这不是一个好消息
- rlm sql mysql.so_UBUUTU7.10上安装配置freeradius+mysql+rp-pppoe手记
- linux oracle脚本编写,Linux 脚本编写基础(一)--语法
- 【求知探新】Unity中ShaderLab内存优化
- 响应式Web设计 viewport 移动端页面自适应
- span标签的鼠标滑入提示_彻底搞懂拖拽——基于鼠标事件的拖拽以及基于HTML5 API的拖拽...
- Arduino M0 的一个坑(2015-12-25)
- JavaScript声明变量详解
- 在Ubuntu上安装Drone持续集成环境
- 存储器和 I/O 端口有哪两种编址方式?简要说明各自特点
- php ajax 同时验证 用户名 密码
- ElasticSearch(十二):Spring Data ElasticSearch 的使用(二)
- 离线安装docker
- 适合64位系统的c语言编辑器,wintc 32/64位软件下载
- hibernate HQL 使用from (select ……)子查询的方法
- 数字音视频知识点汇总(一)
- 【SQL管理】-Flyway数据库版本管理利器从入门到入味
- 下载b站外挂字幕,用 potplayer 播放视频也能看字幕了
- 有利可图网_公布有利可图的辅助项目手册
- 记录linux的内网穿透frp操作
热门文章
- webuploader横向按钮样式
- Qt配置使用VS2010进行开发
- R语言实现常用的5种分析方法(主成分+因子+多维标度+判别+聚类
- SpringBoot 集成Netty实现UDP Server
- Struct1中 Form表单提交的几种方式以及无刷新提交的方式
- sqlserver 获取当前操作的数据库名称
- 虚拟机下给Ubuntu挂载新硬盘
- 68、secureCRT,vim中输入中文
- [BuildRelease]Mozilla Build Tools - Autoconf + GNU Make
- javascript常用函数集