[转]MemCached的PHP客户端操作类二

MemCached的PHP客户端操作类二

<?php
/*
*MemCachedPHPclient
*Copyright(c)2003
*RyanGilfether<hotrodder@rocketmail.com>
*http://www.gilfether.com
*
*OriginallytranslatedfromBradFitzpatrick's<brad@danga.com>MemCachedPerlclient
*Seethememcachedwebsite:
*http://www.danga.com/memcached/
*
*ThismoduleisCopyright(c)2003RyanGilfether.
*Allrightsreserved.
*YoumaydistributeunderthetermsoftheGNUGeneralPublicLicense
*Thisisfreesoftware.ITCOMESWITHOUTWARRANTYOFANYKIND.
*
*/

/**
*versionstring
*/
define("MC_VERSION","1.0.10");
/**
*int,buffersizeusedforsendingandreceiving
*datafromsockets
*/
define("MC_BUFFER_SZ",1024);
/**
*MemCachederrornumbers
*/
define("MC_ERR_NOT_ACTIVE",1001);//noactiveservers
define("MC_ERR_SOCKET_WRITE",1002);//socket_write()failed
define("MC_ERR_SOCKET_READ",1003);//socket_read()failed
define("MC_ERR_SOCKET_CONNECT",1004);//failedtoconnecttohost
define("MC_ERR_DELETE",1005);//delete()didnotrecieveDELETEDcommand
define("MC_ERR_HOST_FORMAT",1006);//sock_to_host()invalidhostformat
define("MC_ERR_HOST_DEAD",1007);//sock_to_host()hostisdead
define("MC_ERR_GET_SOCK",1008);//get_sock()failedtofindavalidsocket
define("MC_ERR_SET",1009);//_set()failedtoreceivetheSTOREDresponse
define("MC_ERR_GET_KEY",1010);//_load_itemsnovaluesreturnedforkey(s)
define("MC_ERR_LOADITEM_END",1011);//_load_itemsfailedtoreceiveENDresponse
define("MC_ERR_LOADITEM_BYTES",1012);//_load_itemsbytesreadlargerthanbytesavailable


/**
*MemCachedPHPclientClass.
*
*CommunicateswiththeMemCachedserver,andexecutestheMemCachedprotocol
*MemCachedavailableathttp://www.danga.com/memcached
*
*@authorRyanGilfether<ryan@gilfether.com>
*@packageMemCachedClient
*@accesspublic
*@version1.0.10
*/
classMemCachedClient
{
/**
*arrayofserversnolongavailable
*@vararray
*/
var$host_dead;
/**
*arrayofopensockets
*@vararray
*/
var$cache_sock;
/**
*determineifdebuggingiseitheronoroff
*@varbool
*/
var$debug;
/**
*arrayofserverstoattempttouse,"host:port"stringformat
*@vararray
*/
var$servers;
/**
*countofcurrentlyactiveconnectionstoservers
*@varint
*/
var$active;
/**
*errorcodeifoneisset
*@varint
*/
var$errno;
/**
*stringdescribingerror
*@varstring
*/
var$errstr;
/**
*sizeofvaltoforcecompression;0turnsoff;defaults1
*@varint
*/
var$compress=1;
/**
*tempflagtoturncompressionon/off;defaultson
*@varint
*/
var$comp_active=1;

/**
*arraythatcontainsparsedoutbuckets
*@vararray
*/
var$bucket;


/**
*Constructor
*
*CreatesanewMemCachedClientobject
*Takesoneparameter,aarrayofoptions.Themostimportantkeyis
*$options["servers"],butthatcanalsobesetlaterwiththeset_servers()
*method.Theserversmustbeanarrayofhosts,eachofwhichis
*eitherascalaroftheform<10.0.0.10:11211>oranarrayofthe
*formerandanintegerweightvalue.(thedefaultweightif
*unspecifiedis1.)It'srecommendedthatweightvaluesbekeptaslow
*aspossible,asthismodulecurrentlyallocatesmemoryforbucket
*distributionproportionaltothetotalhostweights.
*$options["debug"]turnsthedebuggingonifsettotrue
*
*@accesspublic
*@paramarray$optionanarrayofserversanddebugstatus
*@returnobjectMemCachedClientthenewMemCachedClientobject
*/
functionMemCachedClient($options=0)
{
if(
is_array($options))
{
$this->set_servers($options["servers"]);
$this->debug=$options["debug"];
$this->compress=$options["compress"];
$this->cache_sock=array();
}

$this->errno=0;
$this->errstr="";
}


/**
*setsupthelistofserversandtheportstoconnectto
*takesanarrayofserversinthesameformatasintheconstructor
*
*@accesspublic
*@paramarray$serversarrayofserversintheformatdescribedintheconstructor
*/
functionset_servers($servers)
{
$this->servers=$servers;
$this->active=count($this->servers);
}


/**
*if$do_debugissettotrue,willprintout
*debugginginfo,elsedebugisturnedoff
*
*@accesspublic
*@parambool$do_debugsettotruetoturndebuggingon,falsetoturnoff
*/
functionset_debug($do_debug)
{
$this->debug=$do_debug;
}


/**
*removeallcachedhoststhatarenolongergood
*
*@accesspublic
*/
functionforget_dead_hosts()
{
unset(
$this->host_dead);
}


/**
*disconnectsfromallservers
*
*@accesspublic
*/
functiondisconnect_all()
{
foreach(
$this->cache_sockas$sock)
socket_close($sock);

unset(
$this->cache_sock);
$this->active=0;
}


/**
*removesthekeyfromtheMemCache
*$timeistheamountoftimeinseconds(orUnixtime)untilwhich
*theclientwishestheservertorefuse"add"and"replace"commands
*withthiskey.Forthisamountofitem,theitemisputintoa
*deletequeue,whichmeansthatitwon'tpossibletoretrieveitby
*the"get"command,but"add"and"replace"commandwiththiskey
*willalsofail(the"set"commandwillsucceed,however).Afterthe
*timepasses,theitemisfinallydeletedfromservermemory.
*Theparameter$timeisoptional,and,ifabsent,defaultsto0
*(whichmeansthattheitemwillbedeletedimmediatelyandfurther
*storagecommandswiththiskeywillsucceed).
*Possibleerrorssetare:
*MC_ERR_NOT_ACTIVE
*MC_ERR_GET_SOCK
*MC_ERR_SOCKET_WRITE
*MC_ERR_SOCKET_READ
*MC_ERR_DELETE
*
*@accesspublic
*@paramstring$keythekeytodelete
*@paramtimestamp$timeoptional,theamountoftimeserverwillrefusecommandsonkey
*@returnboolTRUEonsuccess,FALSEifkeydoesnotexist
*/
functiondelete($key,$time=0)
{
if(!
$this->active)
{
$this->errno=MC_ERR_NOT_ACTIVE;
$this->errstr="Noactiveserversareavailable";

if(
$this->debug)
$this->_debug("delete():Therearenoactiveserversavailable.");

return
FALSE;
}

$sock=$this->get_sock($key);

if(!
is_resource($sock))
{
$this->errno=MC_ERR_GET_SOCK;
$this->errstr="Unabletoretrieveavalidsocket.";

if(
$this->debug)
$this->_debug("delete():get_sock()returnedaninvalidsocket.");

return
FALSE;
}

if(
is_array($key))
$key=$key[1];

$cmd="delete$key$time\r\n";
$cmd_len=strlen($cmd);
$offset=0;

//nowsendthecommand
while($offset<$cmd_len)
{
$result=socket_write($sock,substr($cmd,$offset,MC_BUFFER_SZ),MC_BUFFER_SZ);

if(
$result!==FALSE)
$offset+=$result;
elseif(
$offset<$cmd_len)
{
$this->errno=MC_ERR_SOCKET_WRITE;
$this->errstr="Failedtowritetosocket.";

if(
$this->debug)
{
$sockerr=socket_last_error($sock);
$this->_debug("delete():socket_write()returnedFALSE.SocketError$sockerr:".socket_strerror($sockerr));
}

return
FALSE;
}
}

//nowreadtheserver'sresponse
if(($retval=socket_read($sock,MC_BUFFER_SZ,PHP_NORMAL_READ))===FALSE)
{
$this->errno=MC_ERR_SOCKET_READ;
$this->errstr="Failedtoreadfromsocket.";

if(
$this->debug)
{
$sockerr=socket_last_error($sock);
$this->_debug("delete():socket_read()returnedFALSE.SocketError$sockerr:".socket_strerror($sockerr));
}

return
FALSE;
}

//removethe\r\nfromtheend
$retval=rtrim($retval);

//nowreadtheserver'sresponse
if($retval=="DELETED")
return
TRUE;
else
{
//somethingwentwrong,createtheerror
$this->errno=MC_ERR_DELETE;
$this->errstr="FailedtoreceiveDELETEDresponsefromserver.";

if(
$this->debug)
$this->_debug("delete():FailedtoreceiveDELETEDresponsefromserver.Received$retvalinstead.");

return
FALSE;
}
}


/**
*Likeset(),butonlystoresinmemcacheifthekeydoesn'talreadyexist.
*Possibleerrorssetare:
*MC_ERR_NOT_ACTIVE
*MC_ERR_GET_SOCK
*MC_ERR_SOCKET_WRITE
*MC_ERR_SOCKET_READ
*MC_ERR_SET
*
*@accesspublic
*@paramstring$keythekeytoset
*@parammixed$valthevalueofthekey
*@paramtimestamp$exptimeoptional,thetotoliveofthekey
*@returnboolTRUEonsuccess,elseFALSE
*/
functionadd($key,$val,$exptime=0)
{
return
$this->_set("add",$key,$val,$exptime);
}


/**
*Likeset(),butonlystoresinmemcacheifthekeyalreadyexists.
*returnsTRUEonsuccesselseFALSE
*Possibleerrorssetare:
*MC_ERR_NOT_ACTIVE
*MC_ERR_GET_SOCK
*MC_ERR_SOCKET_WRITE
*MC_ERR_SOCKET_READ
*MC_ERR_SET
*
*@accesspublic
*@paramstring$keythekeytoset
*@parammixed$valthevalueofthekey
*@paramtimestamp$exptimeoptional,thetotoliveofthekey
*@returnboolTRUEonsuccess,elseFALSE
*/
functionreplace($key,$val,$exptime=0)
{
return
$this->_set("replace",$key,$val,$exptime);
}


/**
*Unconditionallysetsakeytoagivenvalueinthememcache.Returnstrue
*ifitwasstoredsuccessfully.
*The$keycanoptionallybeanarrayref,withthefirstelementbeingthe
*hashvalue,asdescribedabove.
*Possibleerrorssetare:
*MC_ERR_NOT_ACTIVE
*MC_ERR_GET_SOCK
*MC_ERR_SOCKET_WRITE
*MC_ERR_SOCKET_READ
*MC_ERR_SET
*
*@accesspublic
*@paramstring$keythekeytoset
*@parammixed$valthevalueofthekey
*@paramtimestamp$exptimeoptional,thetotoliveofthekey
*@returnboolTRUEonsuccess,elseFALSE
*/
functionset($key,$val,$exptime=0)
{
return
$this->_set("set",$key,$val,$exptime);
}


/**
*Retrievesakeyfromthememcache.Returnsthevalue(automatically
*unserialized,ifnecessary)orFALSEifitfails.
*The$keycanoptionallybeanarray,withthefirstelementbeingthe
*hashvalue,ifyouwanttoavoidmakingthismodulecalculateahash
*value.Youmayprefer,forexample,tokeepallofagivenuser's
*objectsonthesamememcacheserver,soyoucouldusetheuser's
*uniqueidasthehashvalue.
*Possibleerrorssetare:
*MC_ERR_GET_KEY
*
*@accesspublic
*@paramstring$keythekeytoretrieve
*@returnmixedthevalueofthekey,FALSEonerror
*/
functionget($key)
{
$val=&$this->get_multi($key);

if(!
$val)
{
$this->errno=MC_ERR_GET_KEY;
$this->errstr="Novaluefoundforkey$key";

if(
$this->debug)
$this->_debug("get():Novaluefoundforkey$key");

return
FALSE;
}

return
$val[$key];
}


/**
*justlikeget(),buttakesanarrayofkeys,returnsFALSEonerror
*Possibleerrorssetare:
*MC_ERR_NOT_ACTIVE
*
*@accesspublic
*@paramarray$keysthekeystoretrieve
*@returnarraythevalueofeachkey,FALSEonerror
*/
functionget_multi($keys)
{
$sock_keys=array();
$socks=array();
$val=0;

if(!
$this->active)
{
$this->errno=MC_ERR_NOT_ACTIVE;
$this->errstr="Noactiveserversareavailable";

if(
$this->debug)
$this->_debug("get_multi():Therearenoactiveserversavailable.");

return
FALSE;
}

if(!
is_array($keys))
{
$arr[]=$keys;
$keys=$arr;
}

foreach(
$keysas$k)
{
$sock=$this->get_sock($k);

if(
$sock)
{
$k=is_array($k)?$k[1]:$k;

if(@!
is_array($sock_keys[$sock]))
$sock_keys[$sock]=array();

//if$sock_keys[$sock]doesn'texist,createit
if(!$sock_keys[$sock])
$socks[]=$sock;

$sock_keys[$sock][]=$k;
}
}

if(!
is_array($socks))
{
$arr[]=$socks;
$socks=$arr;
}

foreach(
$socksas$s)
{
$this->_load_items($s,$val,$sock_keys[$sock]);
}

if(
$this->debug)
{
while(list(
$k,$v)=@each($val))
$this->_debug("MemCache:got$k=$v\n");
}

return
$val;
}


/**
*Sendsacommandtotheservertoatomicallyincrementthevaluefor
*$keyby$value,orby1if$valueisundefined.ReturnsFALSEif$key
*doesn'texistonserver,otherwiseitreturnsthenewvalueafter
*incrementing.Valueshouldbezeroorgreater.Overflowonserver
*isnotchecked.Beawareofvaluesapproaching2**32.Seedecr.
*ONLYWORKSWITHNUMERICVALUES
*Possibleerrorssetare:
*MC_ERR_NOT_ACTIVE
*MC_ERR_GET_SOCK
*MC_ERR_SOCKET_WRITE
*MC_ERR_SOCKET_READ
*
*@accesspublic
*@paramstring$keythekeystoincrement
*@paramint$valuetheamounttoincrementthekeybye
*@returnintthenewvalueofthekey,elseFALSE
*/
functionincr($key,$value=1)
{
return
$this->_incrdecr("incr",$key,$value);
}


/**
*Likeincr,butdecrements.Unlikeincr,underflowischeckedandnew
*valuesarecappedat0.Ifservervalueis1,adecrementof2
*returns0,not-1.
*ONLYWORKSWITHNUMERICVALUES
*Possibleerrorssetare:
*MC_ERR_NOT_ACTIVE
*MC_ERR_GET_SOCK
*MC_ERR_SOCKET_WRITE
*MC_ERR_SOCKET_READ
*
*@accesspublic
*@paramstring$keythekeystoincrement
*@paramint$valuetheamounttoincrementthekeybye
*@returnintthenewvalueofthekey,elseFALSE
*/
functiondecr($key,$value=1)
{
return
$this->_incrdecr("decr",$key,$value);
}


/**
*WhenafunctionreturnsFALSE,anerrorcodeisset.
*Thisfuntionwillreturntheerrorcode.
*Seeerror_string()
*
*@accesspublic
*@returnintthevalueofthelasterrorcode
*/
functionerror()
{
return
$this->errno;
}


/**
*Returnsastringdescribingtheerrorsetinerror()
*Seeerror()
*
*@accesspublic
*@returnintastringdescribingtheerrorcodegiven
*/
functionerror_string()
{
return
$this->errstr;
}


/**
*Resetstheerrornumberanderrorstring
*
*@accesspublic
*/
functionerror_clear()
{
//resettonoerror
$this->errno=0;
$this->errstr="";
}


/**
*temporarilysetscompressiononoroff
*turningitoff,andthenbackonwillresultinthecompressionthresholdgoing
*backtotheoriginalsettingfrom$options
*@paramint$settingsettingofcompression(0=off|1=on)
*/

functionset_compression($setting=1){
if(
$setting!=0){
$this->comp_active=1;
}else{
$this->comp_active=0;
}
}



/*
*PRIVATEFUNCTIONS
*/


/**
*connectstoaserver
*The$hostmayeitherastringinttheformofhost:portoranarrayofthe
*formerandanintegerweightvalue.(thedefaultweightif
*unspecifiedis1.)Seetheconstructorfordetails
*Possibleerrorssetare:
*MC_ERR_HOST_FORMAT
*MC_ERR_HOST_DEAD
*MC_ERR_SOCKET_CONNECT
*
*@accessprivate
*@parammixed$hosteitheranarrayorastring
*@returnresourcethesocketofthenewconnection,elseFALSE
*/
functionsock_to_host($host)
{
if(
is_array($host))
$host=array_shift($host);

$now=time();

//seperatetheipfromtheport,index0=ip,index1=port
$conn=explode(":",$host);
if(
count($conn)!=2)
{
$this->errno=MC_ERR_HOST_FORMAT;
$this->errstr="Hostaddresswasnotintheformatofhost:port";

if(
$this->debug)
$this->_debug("sock_to_host():Hostaddresswasnotintheformatofhost:port");

return
FALSE;
}

if(@(
$this->host_dead[$host]&&$this->host_dead[$host]>$now)||
@(
$this->host_dead[$conn[0]]&&$this->host_dead[$conn[0]]>$now))
{
$this->errno=MC_ERR_HOST_DEAD;
$this->errstr="Host$hostisnotavailable.";

if(
$this->debug)
$this->_debug("sock_to_host():Host$hostisnotavailable.");

return
FALSE;
}

//connecttotheserver,ifitfails,addittothehost_deadbelow
$sock=socket_create(AF_INET,SOCK_STREAM,getprotobyname("TCP"));

//weneedsurpresstheerrormessageifaconnectionfails
if(!@socket_connect($sock,$conn[0],$conn[1]))
{
$this->host_dead[$host]=$this->host_dead[$conn[0]]=$now+60+intval(rand(0,10));

$this->errno=MC_ERR_SOCKET_CONNECT;
$this->errstr="Failedtoconnectto".$conn[0].":".$conn[1];

if(
$this->debug)
$this->_debug("sock_to_host():Failedtoconnectto".$conn[0].":".$conn[1]);

return
FALSE;
}

//success,addtothelistofsockets
$cache_sock[$host]=$sock;

return
$sock;
}


/**
*retrievesthesocketassociatedwithakey
*Possibleerrorssetare:
*MC_ERR_NOT_ACTIVE
*MC_ERR_GET_SOCK
*
*@accessprivate
*@paramstring$keythekeytoretrievethesocketfrom
*@returnresourcethesocketoftheconnection,elseFALSE
*/
functionget_sock($key)
{
if(!
$this->active)
{
$this->errno=MC_ERR_NOT_ACTIVE;
$this->errstr="Noactiveserversareavailable";

if(
$this->debug)
$this->_debug("get_sock():Therearenoactiveserversavailable.");

return
FALSE;
}

$hv=is_array($key)?intval($key[0]):$this->_hashfunc($key);

if(!
$this->buckets)
{
$bu=$this->buckets=array();

foreach(
$this->serversas$v)
{
if(
is_array($v))
{
for(
$i=1;$i<=$v[1];++$i)
$bu[]=$v[0];
}
else
$bu[]=$v;
}

$this->buckets=$bu;
}

$real_key=is_array($key)?$key[1]:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值