首页 > 开发 > PHP > 正文

MemCached的PHP客户端操作类二

2024-05-04 22:59:05
字体:
来源:转载
供稿:网友

memcached的php客户端操作类二


<?php
/*
 * memcached php client
 * copyright (c) 2003
 * ryan gilfether <[email protected]>
 * http://www.gilfether.com
 *
 * originally translated from brad fitzpatrick's <[email protected]> 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 <[email protected]>
 * @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_sock as $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([email protected]_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->servers as $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);
&nbs, p;   }

    /**
     * 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";
    }
}
?>

 

 

  • 本文来源于网页设计爱好者web开发社区http://www.html.org.cn收集整理,欢迎访问。
  • 发表评论 共有条评论
    用户名: 密码:
    验证码: 匿名发表