MemCached的PHP客户端操作类二

本文介绍了一个用于 MemCached 的 PHP 客户端类的实现细节,包括类的构造方法、设置服务器列表、删除缓存项、设置及获取缓存等功能,并详细解释了错误处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


MemCached的PHP客户端操作类二

<?php
/*
* MemCached PHP client
* Copyright (c) 2003
* Ryan Gilfether <hotrodder@rocketmail.com>
* http://www.gilfether.com
*
* Originally translated from Brad Fitzpatrick's <brad@danga.com> MemCached Perl client
* See the memcached website:
* http://www.danga.com/memcached/
*
* This module is Copyright (c) 2003 Ryan Gilfether.
* All rights reserved.
* You may distribute under the terms of the GNU General Public License
* This is free software. IT COMES WITHOUT WARRANTY OF ANY KIND.
*
*/

/**
* version string
*/
define("MC_VERSION","1.0.10"
);
/**
* int, buffer size used for sending and receiving
* data from sockets
*/
define("MC_BUFFER_SZ",1024
);
/**
* MemCached error numbers
*/
define("MC_ERR_NOT_ACTIVE",1001);
// no active servers
define("MC_ERR_SOCKET_WRITE",1002);
// socket_write() failed
define("MC_ERR_SOCKET_READ",1003);
// socket_read() failed
define("MC_ERR_SOCKET_CONNECT",1004);
// failed to connect to host
define("MC_ERR_DELETE",1005);
// delete() did not recieve DELETED command
define("MC_ERR_HOST_FORMAT",1006);
// sock_to_host() invalid host format
define("MC_ERR_HOST_DEAD",1007);
// sock_to_host() host is dead
define("MC_ERR_GET_SOCK",1008);
// get_sock() failed to find a valid socket
define("MC_ERR_SET",1009);
// _set() failed to receive the STORED response
define("MC_ERR_GET_KEY",1010);
// _load_items no values returned for key(s)
define("MC_ERR_LOADITEM_END",1011);
// _load_items failed to receive END response
define("MC_ERR_LOADITEM_BYTES",1012);
// _load_items bytes read larger than bytes available


/**
* MemCached PHP client Class.
*
* Communicates with the MemCached server, and executes the MemCached protocol
* MemCached available at http://www.danga.com/memcached
*
* @author Ryan Gilfether <ryan@gilfether.com>
* @package MemCachedClient
* @access public
* @version 1.0.10
*/
class
MemCachedClient
{
/**
* array of servers no long available
* @var array
*/
var $host_dead
;
/**
* array of open sockets
* @var array
*/
var $cache_sock
;
/**
* determine if debugging is either on or off
* @var bool
*/
var $debug
;
/**
* array of servers to attempt to use, "host:port" string format
* @var array
*/
var $servers
;
/**
* count of currently active connections to servers
* @var int
*/
var $active
;
/**
* error code if one is set
* @var int
*/
var $errno
;
/**
* string describing error
* @var string
*/
var $errstr
;
/**
* size of val to force compression; 0 turns off; defaults 1
* @ var int
*/
var $compress= 1
;
/**
* temp flag to turn compression on/off; defaults on
* @ var int
*/
var $comp_active= 1
;

/**
* array that contains parsed out buckets
* @ var array
*/
var $bucket
;


/**
* Constructor
*
* Creates a new MemCachedClient object
* Takes one parameter, a array of options. The most important key is
* $options["servers"], but that can also be set later with the set_servers()
* method. The servers must be an array of hosts, each of which is
* either a scalar of the form <10.0.0.10:11211> or an array of the
* former and an integer weight value. (the default weight if
* unspecified is 1.) It's recommended that weight values be kept as low
* as possible, as this module currently allocates memory for bucket
* distribution proportional to the total host weights.
* $options["debug"] turns the debugging on if set to true
*
* @access public
* @param array $option an array of servers and debug status
* @return object MemCachedClient the new MemCachedClient object
*/
function MemCachedClient($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= ""
;
}


/**
* sets up the list of servers and the ports to connect to
* takes an array of servers in the same format as in the constructor
*
* @access public
* @param array $servers array of servers in the format described in the constructor
*/
function set_servers($servers
)
{
$this->servers= $servers
;
$this->active= count($this->servers
);
}


/**
* if $do_debug is set to true, will print out
* debugging info, else debug is turned off
*
* @access public
* @param bool $do_debug set to true to turn debugging on, false to turn off
*/
function set_debug($do_debug
)
{
$this->debug= $do_debug
;
}


/**
* remove all cached hosts that are no longer good
*
* @access public
*/
function forget_dead_hosts
()
{
unset(
$this->host_dead
);
}


/**
* disconnects from all servers
*
* @access public
*/
function disconnect_all
()
{
foreach(
$this->cache_sockas $sock
)
socket_close($sock
);

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


/**
* removes the key from the MemCache
* $time is the amount of time in seconds (or Unix time) until which
* the client wishes the server to refuse "add" and "replace" commands
* with this key. For this amount of item, the item is put into a
* delete queue, which means that it won't possible to retrieve it by
* the "get" command, but "add" and "replace" command with this key
* will also fail (the "set" command will succeed, however). After the
* time passes, the item is finally deleted from server memory.
* The parameter $time is optional, and, if absent, defaults to 0
* (which means that the item will be deleted immediately and further
* storage commands with this key will succeed).
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
* MC_ERR_GET_SOCK
* MC_ERR_SOCKET_WRITE
* MC_ERR_SOCKET_READ
* MC_ERR_DELETE
*
* @access public
* @param string $key the key to delete
* @param timestamp $time optional, the amount of time server will refuse commands on key
* @return bool TRUE on success, FALSE if key does not exist
*/
function delete($key,$time =0
)
{
if(!
$this->active
)
{
$this->errno= MC_ERR_NOT_ACTIVE
;
$this->errstr= "No active servers are available"
;

if(
$this->debug
)
$this->_debug("delete(): There are no active servers available."
);

return
FALSE
;
}

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

if(!
is_resource($sock
))
{
$this->errno= MC_ERR_GET_SOCK
;
$this->errstr= "Unable to retrieve a valid socket."
;

if(
$this->debug
)
$this->_debug("delete(): get_sock() returned an invalid socket."
);

return
FALSE
;
}

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

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

// now send the command
while($offset< $cmd_len
)
{
$result =socket_write($sock,substr($cmd,$offset,MC_BUFFER_SZ),MC_BUFFER_SZ
);

if(
$result !==FALSE
)
$offset +=$result
;
else if(
$offset <$cmd_len
)
{
$this->errno= MC_ERR_SOCKET_WRITE
;
$this->errstr= "Failed to write to socket."
;

if(
$this->debug
)
{
$sockerr =socket_last_error($sock
);
$this->_debug("delete(): socket_write() returned FALSE. Socket Error $sockerr: ".socket_strerror($sockerr
));
}

return
FALSE
;
}
}

// now read the server's response
if(($retval= socket_read($sock,MC_BUFFER_SZ,PHP_NORMAL_READ)) ===FALSE
)
{
$this->errno= MC_ERR_SOCKET_READ
;
$this->errstr= "Failed to read from socket."
;

if(
$this->debug
)
{
$sockerr =socket_last_error($sock
);
$this->_debug("delete(): socket_read() returned FALSE. Socket Error $sockerr: ".socket_strerror($sockerr
));
}

return
FALSE
;
}

// remove the /r/n from the end
$retval =rtrim($retval
);

// now read the server's response
if($retval== "DELETED"
)
return
TRUE
;
else
{
// something went wrong, create the error
$this->errno= MC_ERR_DELETE
;
$this->errstr= "Failed to receive DELETED response from server."
;

if(
$this->debug
)
$this->_debug("delete(): Failed to receive DELETED response from server. Received $retval instead."
);

return
FALSE
;
}
}


/**
* Like set(), but only stores in memcache if the key doesn't already exist.
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
* MC_ERR_GET_SOCK
* MC_ERR_SOCKET_WRITE
* MC_ERR_SOCKET_READ
* MC_ERR_SET
*
* @access public
* @param string $key the key to set
* @param mixed $val the value of the key
* @param timestamp $exptime optional, the to to live of the key
* @return bool TRUE on success, else FALSE
*/
function add($key,$val,$exptime =0
)
{
return
$this->_set("add",$key,$val,$exptime
);
}


/**
* Like set(), but only stores in memcache if the key already exists.
* returns TRUE on success else FALSE
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
* MC_ERR_GET_SOCK
* MC_ERR_SOCKET_WRITE
* MC_ERR_SOCKET_READ
* MC_ERR_SET
*
* @access public
* @param string $key the key to set
* @param mixed $val the value of the key
* @param timestamp $exptime optional, the to to live of the key
* @return bool TRUE on success, else FALSE
*/
function replace($key,$val,$exptime =0
)
{
return
$this->_set("replace",$key,$val,$exptime
);
}


/**
* Unconditionally sets a key to a given value in the memcache. Returns true
* if it was stored successfully.
* The $key can optionally be an arrayref, with the first element being the
* hash value, as described above.
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
* MC_ERR_GET_SOCK
* MC_ERR_SOCKET_WRITE
* MC_ERR_SOCKET_READ
* MC_ERR_SET
*
* @access public
* @param string $key the key to set
* @param mixed $val the value of the key
* @param timestamp $exptime optional, the to to live of the key
* @return bool TRUE on success, else FALSE
*/
function set($key,$val,$exptime =0
)
{
return
$this->_set("set",$key,$val,$exptime
);
}


/**
* Retrieves a key from the memcache. Returns the value (automatically
* unserialized, if necessary) or FALSE if it fails.
* The $key can optionally be an array, with the first element being the
* hash value, if you want to avoid making this module calculate a hash
* value. You may prefer, for example, to keep all of a given user's
* objects on the same memcache server, so you could use the user's
* unique id as the hash value.
* Possible errors set are:
* MC_ERR_GET_KEY
*
* @access public
* @param string $key the key to retrieve
* @return mixed the value of the key, FALSE on error
*/
function get($key
)
{
$val =&$this->get_multi($key
);

if(!
$val
)
{
$this->errno= MC_ERR_GET_KEY
;
$this->errstr= "No value found for key $key"
;

if(
$this->debug
)
$this->_debug("get(): No value found for key $key"
);

return
FALSE
;
}

return
$val[$key
];
}


/**
* just like get(), but takes an array of keys, returns FALSE on error
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
*
* @access public
* @param array $keys the keys to retrieve
* @return array the value of each key, FALSE on error
*/
function get_multi($keys
)
{
$sock_keys
= array();
$socks
= array();
$val =0
;

if(!
$this->active
)
{
$this->errno= MC_ERR_NOT_ACTIVE
;
$this->errstr= "No active servers are available"
;

if(
$this->debug
)
$this->_debug("get_multi(): There are no active servers available."
);

return
FALSE
;
}

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

foreach(
$keys as$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't exist, create it
if(!$sock_keys[$sock
])
$socks[] =$sock
;

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

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

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


/**
* Sends a command to the server to atomically increment the value for
* $key by $value, or by 1 if $value is undefined. Returns FALSE if $key
* doesn't exist on server, otherwise it returns the new value after
* incrementing. Value should be zero or greater. Overflow on server
* is not checked. Be aware of values approaching 2**32. See decr.
* ONLY WORKS WITH NUMERIC VALUES
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
* MC_ERR_GET_SOCK
* MC_ERR_SOCKET_WRITE
* MC_ERR_SOCKET_READ
*
* @access public
* @param string $key the keys to increment
* @param int $value the amount to increment the key bye
* @return int the new value of the key, else FALSE
*/
function incr($key,$value =1
)
{
return
$this->_incrdecr("incr",$key,$value
);
}


/**
* Like incr, but decrements. Unlike incr, underflow is checked and new
* values are capped at 0. If server value is 1, a decrement of 2
* returns 0, not -1.
* ONLY WORKS WITH NUMERIC VALUES
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
* MC_ERR_GET_SOCK
* MC_ERR_SOCKET_WRITE
* MC_ERR_SOCKET_READ
*
* @access public
* @param string $key the keys to increment
* @param int $value the amount to increment the key bye
* @return int the new value of the key, else FALSE
*/
function decr($key,$value =1
)
{
return
$this->_incrdecr("decr",$key,$value
);
}


/**
* When a function returns FALSE, an error code is set.
* This funtion will return the error code.
* See error_string()
*
* @access public
* @return int the value of the last error code
*/
function error
()
{
return
$this->errno
;
}


/**
* Returns a string describing the error set in error()
* See error()
*
* @access public
* @return int a string describing the error code given
*/
function error_string
()
{
return
$this->errstr
;
}


/**
* Resets the error number and error string
*
* @access public
*/
function error_clear
()
{
// reset to no error
$this->errno= 0
;
$this->errstr= ""
;
}


/**
* temporarily sets compression on or off
* turning it off, and then back on will result in the compression threshold going
* back to the original setting from $options
* @param int $setting setting of compression (0=off|1=on)
*/

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



/*
* PRIVATE FUNCTIONS
*/


/**
* connects to a server
* The $host may either a string int the form of host:port or an array of the
* former and an integer weight value. (the default weight if
* unspecified is 1.) See the constructor for details
* Possible errors set are:
* MC_ERR_HOST_FORMAT
* MC_ERR_HOST_DEAD
* MC_ERR_SOCKET_CONNECT
*
* @access private
* @param mixed $host either an array or a string
* @return resource the socket of the new connection, else FALSE
*/
function sock_to_host($host
)
{
if(
is_array($host
))
$host =array_shift($host
);

$now =time
();

// seperate the ip from the port, index 0 = ip, index 1 = port
$conn =explode(":",$host
);
if(
count($conn) !=2
)
{
$this->errno= MC_ERR_HOST_FORMAT
;
$this->errstr= "Host address was not in the format of host:port"
;

if(
$this->debug
)
$this->_debug("sock_to_host(): Host address was not in the format of host: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 $host is not available."
;

if(
$this->debug
)
$this->_debug("sock_to_host(): Host $host is not available."
);

return
FALSE
;
}

// connect to the server, if it fails, add it to the host_dead below
$sock =socket_create (AF_INET,SOCK_STREAM,getprotobyname("TCP"
));

// we need surpress the error message if a connection fails
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= "Failed to connect to ".$conn[0].":".$conn[1
];

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

return
FALSE
;
}

// success, add to the list of sockets
$cache_sock[$host] =$sock
;

return
$sock
;
}


/**
* retrieves the socket associated with a key
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
* MC_ERR_GET_SOCK
*
* @access private
* @param string $key the key to retrieve the socket from
* @return resource the socket of the connection, else FALSE
*/
function get_sock($key
)
{
if(!
$this->active
)
{
$this->errno= MC_ERR_NOT_ACTIVE
;
$this->errstr= "No active servers are available"
;

if(
$this->debug
)
$this->_debug("get_sock(): There are no active servers available."
);

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] :$key
;
$tries =0
;
while(
$tries <20
)
{
$host = @$this->buckets[$hv% count($this->buckets
)];
$sock =$this->sock_to_host($host
);

if(
is_resource($sock
))
return
$sock
;

$hv +=$this->_hashfunc($tries.$real_key
);
++
$tries
;
}

$this->errno= MC_ERR_GET_SOCK
;
$this->errstr= "Unable to retrieve a valid socket."
;

if(
$this->debug
)
$this->_debug("get_sock(): Unable to retrieve a valid socket."
);

return
FALSE
;
}


/**
* increments or decrements a numerical value in memcached. this function is
* called from incr() and decr()
* ONLY WORKS WITH NUMERIC VALUES
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
* MC_ERR_GET_SOCK
* MC_ERR_SOCKET_WRITE
* MC_ERR_SOCKET_READ
*
* @access private
* @param string $cmdname the command to send, either incr or decr
* @param string $key the key to perform the command on
* @param mixed $value the value to incr or decr the key value by
* @return int the new value of the key, FALSE if something went wrong
*/
function _incrdecr($cmdname,$key,$value
)
{
if(!
$this->active
)
{
$this->errno= MC_ERR_NOT_ACTIVE
;
$this->errstr= "No active servers are available"
;

if(
$this->debug
)
$this->_debug("_incrdecr(): There are no active servers available."
);

return
FALSE
;
}

$sock =$this->get_sock($key
);
if(!
is_resource($sock
))
{
$this->errno= MC_ERR_GET_SOCK
;
$this->errstr= "Unable to retrieve a valid socket."
;

if(
$this->debug
)
$this->_debug("_incrdecr(): Invalid socket returned by get_sock()."
);

return
FALSE
;
}

if(
$value ==""
)
$value =1
;

$cmd ="$cmdname $key $value/r/n"
;
$cmd_len =strlen($cmd
);
$offset =0
;

// write the command to the server
while($offset< $cmd_len
)
{
$result =socket_write($sock,substr($cmd,$offset,MC_BUFFER_SZ),MC_BUFFER_SZ
);

if(
$result !==FALSE
)
$offset +=$result
;
else if(
$offset <$cmd_len
)
{
$this->errno= MC_ERR_SOCKET_WRITE
;
$this->errstr= "Failed to write to socket."
;

if(
$this->debug
)
{
$sockerr =socket_last_error($sock
);
$this->_debug("_incrdecr(): socket_write() returned FALSE. Error $errno: ".socket_strerror($sockerr
));
}

return
FALSE
;
}
}

// now read the server's response
if(($retval= socket_read($sock,MC_BUFFER_SZ,PHP_NORMAL_READ)) ===FALSE
)
{
$this->errno= MC_ERR_SOCKET_READ
;
$this->errstr= "Failed to read from socket."
;

if(
$this->debug
)
{
$sockerr =socket_last_error($sock
);
$this->_debug("_incrdecr(): socket_read() returned FALSE. Socket Error $errno: ".socket_strerror($sockerr
));
}

return
FALSE
;
}

// strip the /r/n from the end and return value
return trim($retval
);
}

/**
* sends the command to the server
* Possible errors set are:
* MC_ERR_NOT_ACTIVE
* MC_ERR_GET_SOCK
* MC_ERR_SOCKET_WRITE
* MC_ERR_SOCKET_READ
* MC_ERR_SET
*
* @access private
* @param string $cmdname the command to send, either incr or decr
* @param string $key the key to perform the command on
* @param mixed $value the value to set the key to
* @param timestamp $exptime expiration time of the key
* @return bool TRUE on success, else FALSE
*/
function _set($cmdname,$key,$val,$exptime =0
)
{
if(!
$this->active
)
{
$this->errno= MC_ERR_NOT_ACTIVE
;
$this->errstr= "No active servers are available"
;

if(
$this->debug
)
$this->_debug("_set(): No active servers are available."
);

return
FALSE
;
}

$sock =$this->get_sock($key
);
if(!
is_resource($sock
))
{
$this->errno= MC_ERR_GET_SOCK
;
$this->errstr= "Unable to retrieve a valid socket."
;

if(
$this->debug
)
$this->_debug("_set(): Invalid socket returned by get_sock()."
);

return
FALSE
;
}

$flags =0
;
$key =is_array($key) ?$key[1] :$key
;

$raw_val =$val
;

// if the value is not scalar, we need to serialize it
if(!is_scalar($val
))
{
$val =serialize($val
);
$flags |=1
;
}

if ((
$this->compress_active) && ($this->compress> 0) && (strlen($val) > $this->compress
)) {
$this->_debug("_set(): compressing data. size in:".strlen($val
));
$cval=gzcompress($val
);
$this->_debug("_set(): done compressing data. size out:".strlen($cval
));
if ((
strlen($cval) <strlen($val)) && (strlen($val) - strlen($cval) >2048
)){
$flags |=2
;
$val=$cval
;
}
unset(
$cval
);
}

$len =strlen($val
);
if (!
is_int($exptime
))
$exptime =0
;

// send off the request
$cmd ="$cmdname $key $flags $exptime $len/r/n$val/r/n"
;
$cmd_len =strlen($cmd
);
$offset =0
;

// write the command to the server
while($offset< $cmd_len
)
{
$result =socket_write($sock,substr($cmd,$offset,MC_BUFFER_SZ),MC_BUFFER_SZ
);

if(
$result !==FALSE
)
$offset +=$result
;
else if(
$offset <$cmd_len
)
{
$this->errno= MC_ERR_SOCKET_WRITE
;
$this->errstr= "Failed to write to socket."
;

if(
$this->debug
)
{
$errno =socket_last_error($sock
);
$this->_debug("_set(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno
));
}

return
FALSE
;
}
}

// now read the server's response
if(($l_szResponse= socket_read($sock,6,PHP_NORMAL_READ)) ===FALSE
)
{
$this->errno= MC_ERR_SOCKET_READ
;
$this->errstr= "Failed to read from socket."
;

if(
$this->debug
)
{
$errno =socket_last_error($sock
);
$this->_debug("_set(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno
));
}

return
FALSE
;
}

if(
$l_szResponse =="STORED"
)
{
if(
$this->debug
)
$this->_debug("MemCache: $cmdname $key = $raw_val"
);

return
TRUE
;
}

$this->errno= MC_ERR_SET
;
$this->errstr= "Failed to receive the STORED response from the server."
;

if(
$this->debug
)
$this->_debug("_set(): Did not receive STORED as the server response! Received $l_szResponse instead."
);

return
FALSE
;
}


/**
* retrieves the value, and returns it unserialized
* Possible errors set are:
* MC_ERR_SOCKET_WRITE
* MC_ERR_SOCKET_READ
* MC_ERR_GET_KEY
* MC_ERR_LOADITEM_END
* MC_ERR_LOADITEM_BYTES
*
* @access private
* @param resource $sock the socket to connection we are retriving from
* @param array $val reference to the values retrieved
* @param mixed $sock_keys either a string or an array of keys to retrieve
* @return array TRUE on success, else FALSE
*/
function _load_items($sock, &$val,$sock_keys
)
{
$val
= array();
$cmd ="get "
;

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

foreach(
$sock_keys as$sk
)
$cmd .=$sk." "
;

$cmd .="/r/n"
;
$cmd_len =strlen($cmd
);
$offset =0
;

// write the command to the server
while($offset< $cmd_len
)
{
$result =socket_write($sock,substr($cmd,$offset,MC_BUFFER_SZ),MC_BUFFER_SZ
);

if(
$result !==FALSE
)
$offset +=$result
;
else if(
$offset <$cmd_len
)
{
$this->errno= MC_ERR_SOCKET_WRITE
;
$this->errstr= "Failed to write to socket."
;

if(
$this->debug
)
{
$errno =socket_last_error($sock
);
$this->_debug("_load_items(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno
));
}

return
FALSE
;
}
}

$len =0
;
$buf =""
;
$flags_array
= array();

// now read the response from the server
while($line= socket_read($sock,MC_BUFFER_SZ,PHP_BINARY_READ
))
{
// check for a socket_read error
if($line=== FALSE
)
{
$this->errno= MC_ERR_SOCKET_READ
;
$this->errstr= "Failed to read from socket."
;

if(
$this->debug
)
{
$errno =socket_last_error($sock
);
$this->_debug("_load_items(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno
));
}

return
FALSE
;
}

if(
$len ==0
)
{
$header =substr($line,0,strpos($line,"/r/n"
));
$matches =explode(" ",$header
);

if(
is_string($matches[1]) && is_numeric($matches[2]) && is_numeric($matches[3
]))
{
$rk =$matches[1
];
$flags =$matches[2
];
$len =$matches[3
];

if(
$flags
)
$flags_array[$rk] =$flags
;

$len_array[$rk] =$len
;
$bytes_read =0
;

// get the left over data after the header is read
$line =substr($line,strpos($line,"/r/n")+2,strlen($line
));
}
else
{
$this->errno= MC_ERR_GET_KEY
;
$this->errstr= "Requested key(s) returned no values."
;

// something went wrong, we never recieved the header
if($this->debug
)
$this->_debug("_load_items(): Requested key(s) returned no values."
);

return
FALSE
;
}
}

// skip over the extra return or newline
if($line== "/r"|| $line== "/n"
)
continue;

$bytes_read +=strlen($line
);
$buf .=$line
;

// we read the all of the data, take in account
// for the /r/nEND/r/n
if($bytes_read== ($len+ 7
))
{
$end =substr($buf,$len+2,3
);
if(
$end =="END"
)
{
$val[$rk] =substr($buf,0,$len
);

foreach(
$sock_keys as$sk
)
{
if(!isset(
$val[$sk
]))
continue;

if(
strlen($val[$sk]) != $len_array[$sk
])
continue;
if(@
$flags_array[$sk] &2
)
$val[$sk] =gzuncompress($val[$sk
]);

if(@
$flags_array[$sk] &1
)
$val[$sk] =unserialize($val[$sk
]);
}

return
TRUE
;
}
else
{
$this->errno= MC_ERR_LOADITEM_END
;
$this->errstr= "Failed to receive END response from server."
;

if(
$this->debug
)
$this->_debug("_load_items(): Failed to receive END. Received $end instead."
);

return
FALSE
;
}
}

// take in consideration for the "/r/nEND/r/n"
if($bytes_read> ($len+ 7
))
{
$this->errno= MC_ERR_LOADITEM_BYTES
;
$this->errstr= "Bytes read from server greater than size of data."
;

if(
$this->debug
)
$this->_debug("_load_items(): Bytes read is greater than requested data size."
);

return
FALSE
;
}

}
}


/**
* creates our hash
*
* @access private
* @param int $num
* @return hash
*/
function _hashfunc($num
)
{
$hash =sprintf("%u",crc32($num
));

return
$hash
;
}

/**
* function that can be overridden to handle debug output
* by default debug info is print to the screen
*
* @access private
* @param $text string to output debug info
*/
function _debug($text
)
{
print
$text ."/r/n"
;
}
}
?>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值