设为首页 收藏本站
查看: 704|回复: 0

[经验分享] [转]MemCached的PHP客户端操作类一

[复制链接]

尚未签到

发表于 2017-4-10 10:54:51 | 显示全部楼层 |阅读模式
  

MemCached的PHP客户端操作类一


  <?php
//
//+---------------------------------------------------------------------------+
//|memcachedclient,PHP|
//+---------------------------------------------------------------------------+
//|Copyright(c)2003RyanT.Dean<rtdean@cytherianage.net>|
//|Allrightsreserved.|
//||
//|Redistributionanduseinsourceandbinaryforms,withorwithout|
//|modification,arepermittedprovidedthatthefollowingconditions|
//|aremet:|
//||
//|1.Redistributionsofsourcecodemustretaintheabovecopyright|
//|notice,thislistofconditionsandthefollowingdisclaimer.|
//|2.Redistributionsinbinaryformmustreproducetheabovecopyright|
//|notice,thislistofconditionsandthefollowingdisclaimerinthe|
//|documentationand/orothermaterialsprovidedwiththedistribution.|
//||
//|THISSOFTWAREISPROVIDEDBYTHEAUTHOR``ASIS''ANDANYEXPRESSOR|
//|IMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THEIMPLIEDWARRANTIES|
//|OFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSEAREDISCLAIMED.|
//|INNOEVENTSHALLTHEAUTHORBELIABLEFORANYDIRECT,INDIRECT,|
//|INCIDENTAL,SPECIAL,EXEMPLARY,ORCONSEQUENTIALDAMAGES(INCLUDING,BUT|
//|NOTLIMITEDTO,PROCUREMENTOFSUBSTITUTEGOODSORSERVICES;LOSSOFUSE,|
//|DATA,ORPROFITS;ORBUSINESSINTERRUPTION)HOWEVERCAUSEDANDONANY|
//|THEORYOFLIABILITY,WHETHERINCONTRACT,STRICTLIABILITY,ORTORT|
//|(INCLUDINGNEGLIGENCEOROTHERWISE)ARISINGINANYWAYOUTOFTHEUSEOF|
//|THISSOFTWARE,EVENIFADVISEDOFTHEPOSSIBILITYOFSUCHDAMAGE.|
//+---------------------------------------------------------------------------+
//|Author:RyanT.Dean<rtdean@cytherianage.net>|
//|HeavilyinfluencedbythePerlmemcachedclientbyBradFitzpatrick.|
//|PermissiongrantedbyBradFitzpatrickforrelicenseofportedPerl|
//|clientlogicunder2-clauseBSDlicense.|
//+---------------------------------------------------------------------------+
//
//$TCAnet$
//

/**
*ThisisthePHPclientformemcached-adistributedmemorycachedaemon.
*Moreinformationisavailableathttp://www.danga.com/memcached/
*
*Usageexample:
*
*require_once'memcached.php';
*
*$mc=newmemcached(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','somerandomstring');
*$val=$mc->get('key');
*
*@authorRyanT.Dean<rtdean@cytherianage.net>
*@packagememcached-client
*@version0.1.2
*/

//{{{requirements
//}}}

//{{{constants
//{{{flags

/**
*Flag:indicatesdataisserialized
*/
define("MEMCACHE_SERIALIZED",1<<0);

/**
*Flag:indicatesdataiscompressed
*/
define("MEMCACHE_COMPRESSED",1<<1);

//}}}

/**
*Minimumsavingstostoredatacompressed
*/
define("COMPRESSION_SAVINGS",0.20);

//}}}

//{{{classmemcached
/**
*memcachedclientclassimplementedusing(p)fsockopen()
*
*@authorRyanT.Dean<rtdean@cytherianage.net>
*@packagememcached-client
*/
classmemcached
{
//{{{properties
//{{{public

/**
*Commandstatistics
*
*@vararray
*@accesspublic
*/
var$stats;

//}}}
//{{{private

/**
*CachedSocketsthatareconnected
*
*@vararray
*@accessprivate
*/
var$_cache_sock;

/**
*Currentdebugstatus;0-noneto9-profiling
*
*@varboolean
*@accessprivate
*/
var$_debug;

/**
*Deadhosts,assocarray,'host'=>'unixtimewhenoktocheckagain'
*
*@vararray
*@accessprivate
*/
var$_host_dead;

/**
*Iscompressionavailable?
*
*@varboolean
*@accessprivate
*/
var$_have_zlib;

/**
*Dowewanttousecompression?
*
*@varboolean
*@accessprivate
*/
var$_compress_enable;

/**
*Athowmanybytesshouldwecompress?
*
*@varinterger
*@accessprivate
*/
var$_compress_threshold;

/**
*Areweusingpersistantlinks?
*
*@varboolean
*@accessprivate
*/
var$_persistant;

/**
*Ifonlyusingoneserver;containsip:porttoconnectto
*
*@varstring
*@accessprivate
*/
var$_single_sock;

/**
*Arraycontainingip:portorarray(ip:port,weight)
*
*@vararray
*@accessprivate
*/
var$_servers;

/**
*Ourbitbuckets
*
*@vararray
*@accessprivate
*/
var$_buckets;

/**
*Total#ofbitbucketswehave
*
*@varinterger
*@accessprivate
*/
var$_bucketcount;

/**
*#oftotalserverswehave
*
*@varinterger
*@accessprivate
*/
var$_active;

//}}}
//}}}
//{{{methods
//{{{publicfunctions
//{{{memcached()

/**
*Memcacheinitializer
*
*@paramarray$argsAssociativearrayofsettings
*
*@returnmixed
*@accesspublic
*/
functionmemcached($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()

/**
*Addsakey/valuetothememcacheserverifoneisn'talreadysetwith
*thatkey
*
*@paramstring$keyKeytosetwithdata
*@parammixed$valValuetostore
*@paraminterger$exp(optional)Timetoexpiredataat
*
*@returnboolean
*@accesspublic
*/
functionadd($key,$val,$exp=0)
{
return
$this->_set('add',$key,$val,$exp);
}

//}}}
//{{{decr()

/**
*Decrimentavaluestoredonthememcacheserver
*
*@paramstring$keyKeytodecriment
*@paraminterger$amt(optional)Amounttodecriment
*
*@returnmixedFALSEonfailure,valueonsuccess
*@accesspublic
*/
functiondecr($key,$amt=1)
{
return
$this->_incrdecr('decr',$key,$amt);
}

//}}}
//{{{delete()

/**
*Deletesakeyfromtheserver,optionallyafter$time
*
*@paramstring$keyKeytodelete
*@paraminterger$time(optional)Howlongtowaitbeforedeleting
*
*@returnbooleanTRUEonsuccess,FALSEonfailure
*@accesspublic
*/
functiondelete($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()

/**
*Disconnectsallconnectedsockets
*
*@accesspublic
*/
functiondisconnect_all()
{
foreach(
$this->_cache_sockas$sock)
fclose($sock);

$this->_cache_sock=array();
}

//}}}
//{{{enable_compress()

/**
*Enable/Disablecompression
*
*@paramboolean$enableTRUEtoenable,FALSEtodisable
*
*@accesspublic
*/
functionenable_compress($enable)
{
$this->_compress_enable=$enable;
}

//}}}
//{{{forget_dead_hosts()

/**
*Forgetaboutallofthedeadhosts
*
*@accesspublic
*/
functionforget_dead_hosts()
{
$this->_host_dead=array();
}

//}}}
//{{{get()

/**
*Retrievesthevalueassociatedwiththekeyfromthememcacheserver
*
*@paramstring$keyKeytoretrieve
*
*@returnmixed
*@accesspublic
*/
functionget($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(
$valas$k=>$v)
printf("MemCache:sock%sgot%s=>%s\r\n",$sock,$k,$v);

return
$val[$key];
}

//}}}
//{{{get_multi()

/**
*Getmultiplekeysfromtheserver(s)
*
*@paramarray$keysKeystoretrieve
*
*@returnarray
*@accesspublic
*/
functionget_multi($keys)
{
if(!
$this->_active)
return
false;

$this->stats['get_multi']++;

foreach(
$keysas$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;
}

//Sendouttherequests
foreach($socksas$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);
}
}

//Parseresponses
$val=array();
foreach(
$gatheras$sock)
{
$this->_load_items($sock,$val);
}

if(
$this->_debug)
foreach(
$valas$k=>$v)
printf("MemCache:got%s=>%s\r\n",$k,$v);

return
$val;
}

//}}}
//{{{incr()

/**
*Increments$key(optionally)by$amt
*
*@paramstring$keyKeytoincrement
*@paraminterger$amt(optional)amounttoincrement
*
*@returnintergerNewkeyvalue?
*@accesspublic
*/
functionincr($key,$amt=1)
{
return
$this->_incrdecr('incr',$key,$amt);
}

//}}}
//{{{replace()

/**
*Overwritesanexistingvalueforkey;onlyworksifkeyisalreadyset
*
*@paramstring$keyKeytosetvalueas
*@parammixed$valueValuetostore
*@paraminterger$exp(optional)Experiationtime
*
*@returnboolean
*@accesspublic
*/
functionreplace($key,$value,$exp=0)
{
return
$this->_set('replace',$key,$value,$exp);
}

//}}}
//{{{run_command()

/**
*Passesthrough$cmdtothememcacheserverconnectedby$sock;returns
*outputasanarray(nullarrayifnooutput)
*
*NOTE:duetoapossiblebuginhowPHPreadswhileusingfgets(),each
*linemaynotbeterminatedbya\r\n.Morespecifically,mytesting
*hasshownthat,onFreeBSDatleast,eachlineisterminatedonly
*witha\n.ThisiswiththePHPflagauto_detect_line_endingsset
*tofalase(thedefault).
*
*@paramresource$sockSockettosendcommandon
*@paramstring$cmdCommandtorun
*
*@returnarrayOutputarray
*@accesspublic
*/
functionrun_command($sock,$cmd)
{
if(!
is_resource($sock))
returnarray();

if(!
fwrite($sock,$cmd,strlen($cmd)))
returnarray();

while(
true)
{
$res=fgets($sock);
$ret[]=$res;
if(
preg_match('/^END/',$res))
break;
if(
strlen($res)==0)
break;
}
return
$ret;
}

//}}}
//{{{set()

/**
*Unconditionallysetsakeytoagivenvalueinthememcache.Returnstrue
*ifsetsuccessfully.
*
*@paramstring$keyKeytosetvalueas
*@parammixed$valueValuetoset
*@paraminterger$exp(optional)Experiationtime
*
*@returnbooleanTRUEonsuccess
*@accesspublic
*/
functionset($key,$value,$exp=0)
{
return
$this->_set('set',$key,$value,$exp);
}

//}}}
//{{{set_compress_threshold()

/**
*Setsthecompressionthreshold
*
*@paraminterger$threshThresholdtocompressiflargerthan
*
*@accesspublic
*/
functionset_compress_threshold($thresh)
{
$this->_compress_threshold=$thresh;
}

//}}}
//{{{set_debug()

/**
*Setsthedebugflag
*
*@paramboolean$dbgTRUEfordebugging,FALSEotherwise
*
*@accesspublic
*
*@seememcahced::memcached
*/
functionset_debug($dbg)
{
$this->_debug=$dbg;
}

//}}}
//{{{set_servers()

/**
*Setstheserverlisttodistributekeygetsandputsbetween
*
*@paramarray$listArrayofserverstoconnectto
*
*@accesspublic
*
*@seememcached::memcached()
*/
functionset_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];
}

//}}}
//}}}
//{{{privatemethods
//{{{_close_sock()

/**
*Closethespecifiedsocket
*
*@paramstring$sockSockettoclose
*
*@accessprivate
*/
function_close_sock($sock)
{
$host=array_search($sock,$this->_cache_sock);
fclose($this->_cache_sock[$host]);
unset(
$this->_cache_sock[$host]);
}

//}}}
//{{{_connect_sock()

/**
*Connects$sockto$host,timingoutafter$timeout
*
*@paraminterger$sockSockettoconnect
*@paramstring$hostHost:IPtoconnectto
*@paramfloat$timeout(optional)Timeoutvalue,defaultsto0.25s
*
*@returnboolean
*@accessprivate
*/
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()

/**
*Marksahostasdeaduntil30-40secondsinthefuture
*
*@paramstring$sockSockettomarkasdead
*
*@accessprivate
*/
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
*
*@paramstring$keyKeytoretrievevaluefor;
*
*@returnmixedresourceonsuccess,falseonfailure
*@accessprivate
*/
functionget_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->_serversas$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()

/**
*Createsahashintergerbasedonthe$key
*
*@paramstring$keyKeytohash
*
*@returnintergerHashvalue
*@accessprivate
*/
function_hashfunc($key)
{
$hash=0;
for(
$i=0;$i<strlen($key);$i++)
{
$hash=$hash*33+ord($key[$i]);
}

return
$hash;
}

//}}}
//{{{_incrdecr()

/**
*Performincrement/decrimenton$key
*
*@paramstring$cmdCommandtoperform
*@paramstring$keyKeytoperformiton
*@paraminterger$amtAmounttoadjust
*
*@returnintergerNewvalueof$key
*@accessprivate
*/
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()

/**
*Loaditemsinto$retfrom$sock
*
*@paramresource$sockSockettoreadfrom
*@paramarray$retReturnedvalues
*
*@accessprivate
*/
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,</spa

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-362826-1-1.html 上篇帖子: php高性能的缓存存储引擎secache 源代码 下篇帖子: php中高并发状态下文件读写
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表