<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog336280.html" frameborder="0" width="336" scrolling="no" height="280"></iframe>
MemCached的PHP客户端操作类一
<?php <br />//
//+---------------------------------------------------------------------------+
//|memcachedclient,PHP|
//+---------------------------------------------------------------------------+
//|Copyright(c)2003RyanT.Dean<rtdean>| <br>//|Allrightsreserved.| <br>//|| <br>//|Redistributionanduseinsourceandbinaryforms,withorwithout| <br>//|modification,arepermittedprovidedthatthefollowingconditions| <br>//|aremet:| <br>//|| <br>//|1.Redistributionsofsourcecodemustretaintheabovecopyright| <br>//|notice,thislistofconditionsandthefollowingdisclaimer.| <br>//|2.Redistributionsinbinaryformmustreproducetheabovecopyright| <br>//|notice,thislistofconditionsandthefollowingdisclaimerinthe| <br>//|documentationand/orothermaterialsprovidedwiththedistribution.| <br>//|| <br>//|THISSOFTWAREISPROVIDEDBYTHEAUTHOR``ASIS''ANDANYEXPRESSOR| <br>//|IMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THEIMPLIEDWARRANTIES| <br>//|OFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSEAREDISCLAIMED.| <br>//|INNOEVENTSHALLTHEAUTHORBELIABLEFORANYDIRECT,INDIRECT,| <br>//|INCIDENTAL,SPECIAL,EXEMPLARY,ORCONSEQUENTIALDAMAGES(INCLUDING,BUT| <br>//|NOTLIMITEDTO,PROCUREMENTOFSUBSTITUTEGOODSORSERVICES;LOSSOFUSE,| <br>//|DATA,ORPROFITS;ORBUSINESSINTERRUPTION)HOWEVERCAUSEDANDONANY| <br>//|THEORYOFLIABILITY,WHETHERINCONTRACT,STRICTLIABILITY,ORTORT| <br>//|(INCLUDINGNEGLIGENCEOROTHERWISE)ARISINGINANYWAYOUTOFTHEUSEOF| <br>//|THISSOFTWARE,EVENIFADVISEDOFTHEPOSSIBILITYOFSUCHDAMAGE.| <br>//+---------------------------------------------------------------------------+ <br>//|Author:RyanT.Dean<rtdean>| <br>//|HeavilyinfluencedbythePerlmemcachedclientbyBradFitzpatrick.| <br>//|PermissiongrantedbyBradFitzpatrickforrelicenseofportedPerl| <br>//|clientlogicunder2-clauseBSDlicense.| <br>//+---------------------------------------------------------------------------+ <br>// <br>//$TCAnet$ <br>// <br><br>/** <br>*ThisisthePHPclientformemcached-adistributedmemorycachedaemon. <br>*Moreinformationisavailableathttp://www.danga.com/memcached/ <br>* <br>*Usageexample: <br>* <br>*require_once'memcached.php'; <br>* <br>*$mc=newmemcached(array( <br>*'servers'=>array('127.0.0.1:10000', <br>*array('192.0.0.1:10010',2), <br>*'127.0.0.1:10020'), <br>*'debug'=>false, <br>*'compress_threshold'=>10240, <br>*'persistant'=>true)); <br>* <br>*$mc->add('key',array('some','array')); <br>*$mc->replace('key','somerandomstring'); <br>*$val=$mc->get('key'); <br>* <br>*@authorRyanT.Dean<rtdean><br>*@packagememcached-client <br>*@version0.1.2 <br>*/ <br><br>//{{{requirements <br>//}}} <br><br>//{{{constants <br>//{{{flags <br><br>/** <br>*Flag:indicatesdataisserialized <br>*/ <br></rtdean></rtdean></rtdean>define("MEMCACHE_SERIALIZED",10);
/**
*Flag:indicatesdataiscompressed
*/
define("MEMCACHE_COMPRESSED",11);
//}}}
/**
*Minimumsavingstostoredatacompressed
*/
define("COMPRESSION_SAVINGS",0.20);
//}}}
//{{{classmemcached
/**
*memcachedclientclassimplementedusing(p)fsockopen()
*
*@authorRyanT.Dean<rtdean><br>*@packagememcached-client <br>*/ <br></rtdean>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)
returnfalse;
$sock=$this->get_sock($key);
if(!is_resource($sock))
returnfalse;
$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);
returnfalse;
}
$res=trim(fgets($sock));
if($this->_debug)
printf("MemCache:delete%s(%s)/n",$key,$res);
if($res=="DELETED")
returntrue;
returnfalse;
}
//}}}
//{{{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)
returnfalse;
$sock=$this->get_sock($key);
if(!is_resource($sock))
returnfalse;
$this->stats['get']++;
$cmd="get$key/r/n";
if(!fwrite($sock,$cmd,strlen($cmd)))
{
$this->_dead_sock($sock);
returnfalse;
}
$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)
returnfalse;
$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)
returnfalse;
returntrue;
}
//}}}
//{{{_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)
returnfalse;
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;$tries20;$tries++)
{
$host=$this->_buckets[$hv%$this->_bucketcount];
$sock=$this->sock_to_host($host);
if(is_resource($sock))
return$sock;
$hv+=$this->_hashfunc($tries.$realkey);
}
returnfalse;
}
//}}}
//{{{_hashfunc()
/**
*Createsahashintergerbasedonthe$key
*
*@paramstring$keyKeytohash
*
*@returnintergerHashvalue
*@accessprivate
*/
function_hashfunc($key)
{
$hash=0;
for($i=0;$istrlen($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)
returnnull;
$sock=$this->get_sock($key);
if(!is_resource($sock))
returnnull;
$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))
returnnull;
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")
{
returntrue;
}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)
{
//Somethingisborked!
if($this->_debug)
printf("Somethingisborked!key%sexpecting%dgot%dlength/n",$rkey,$len+2,$offset);
unset($ret[$rkey]);
$this->_close_sock($sock);
returnfalse;
}
$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("Errorparsingmemcachedresponse/n");
return0;
}
}
}
//}}}
//{{{_set()
/**
*Performstherequestedstorageoperationtothememcacheserver
*
*@paramstring$cmdCommandtoperform
*@paramstring$keyKeytoacton
*@parammixed$valWhatweneedtostore
*@paraminterger$expWhenitshouldexpire
*
*@returnboolean
*@accessprivate
*/
function_set($cmd,$key,$val,$exp)
{
if(!$this->_active)
returnfalse;
$sock=$this->get_sock($key);
if(!is_resource($sock))
returnfalse;
$this->stats[$cmd]++;
$flags=0;
if(!is_scalar($val))
{
$val=serialize($val);
$flags|=MEMCACHE_SERIALIZED;
if($this->_debug)
printf("client:serializingdataasitisnotscalar/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:compressingdata;was%dbytesisnow%dbytes/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='compresseddata';
printf("MemCache:%s%s=>%s(%s)/n",$cmd,$key,$val,$line);
}
if($line=="STORED")
returntrue;
returnfalse;
}
//}}}
//{{{sock_to_host()
/**
*Returnsthesocketforthehost
*
*@paramstring$hostHost:IPtogetsocketfor
*
*@returnmixedIOStreamorfalse
*@accessprivate
*/
functionsock_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)
returnnull;
if(!$this->_connect_sock($sock,$host))
return$this->_dead_sock($host);
//Donotbufferwrites
stream_set_write_buffer($sock,0);
$this->_cache_sock[$host]=$sock;
return$this->_cache_sock[$host];
}
//}}}
//}}}
//}}}
}
//}}}
?>