• 技术文章 >php教程 >php手册

    MemCached的PHP客户端操作类

    2016-06-06 19:57:53原创485

    原贴:http://blog.csdn.net/heiyeshuwu/archive/2006/07/07/890078.aspx MemCached的PHP客户端操作类一 ?php // //+---------------------------------------------------------------------------+ //|memcachedclient,PHP| //+---------------------------

    原贴:http://blog.csdn.net/heiyeshuwu/archive/2006/07/07/890078.aspx


    MemCached的PHP客户端操作类一

    //
    // +---------------------------------------------------------------------------+
    // | memcached client, PHP |
    // +---------------------------------------------------------------------------+
    // | Copyright (c) 2003 Ryan T. Dean |
    // | All rights reserved. |
    // | |
    // | Redistribution and use in source and binary forms, with or without |
    // | modification, are permitted provided that the following conditions |
    // | are met: |
    // | |
    // | 1. Redistributions of source code must retain the above copyright |
    // | notice, this list of conditions and the following disclaimer. |
    // | 2. Redistributions in binary form must reproduce the above copyright |
    // | notice, this list of conditions and the following disclaimer in the |
    // | documentation and/or other materials provided with the distribution. |
    // | |
    // | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
    // | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
    // | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
    // | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
    // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
    // | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
    // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
    // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
    // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
    // | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
    // +---------------------------------------------------------------------------+
    // | Author: Ryan T. Dean |
    // | Heavily influenced by the Perl memcached client by Brad Fitzpatrick. |
    // | Permission granted by Brad Fitzpatrick for relicense of ported Perl |
    // | client logic under 2-clause BSD license. |
    // +---------------------------------------------------------------------------+
    //
    // $TCAnet$
    //

    /**
    * This is the PHP client for memcached - a distributed memory cache daemon.
    * More information is available at http://www.danga.com/memcached/
    *
    * Usage example:
    *
    * require_once 'memcached.php';
    *
    * $mc = new memcached(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', 'some random string');
    * $val = $mc->get('key');
    *
    * @author Ryan T. Dean
    * @package memcached-client
    * @version 0.1.2
    */

    // {{{ requirements
    // }}}

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

    /**
    * Flag: indicates data is serialized
    */
    define("MEMCACHE_SERIALIZED", 1<<0
    );

    /**
    * Flag: indicates data is compressed
    */
    define("MEMCACHE_COMPRESSED", 1<<1
    );

    // }}}

    /**
    * Minimum savings to store data compressed
    */
    define("COMPRESSION_SAVINGS", 0.20
    );

    // }}}

    // {{{ class memcached
    /**
    * memcached client class implemented using (p)fsockopen()
    *
    * @author Ryan T. Dean
    * @package memcached-client
    */
    class
    memcached
    {
    // {{{ properties
    // {{{ public

    /**
    * Command statistics
    *
    * @var array
    * @access public
    */
    var $stats
    ;

    // }}}
    // {{{ private

    /**
    * Cached Sockets that are connected
    *
    * @var array
    * @access private
    */
    var $_cache_sock
    ;

    /**
    * Current debug status; 0 - none to 9 - profiling
    *
    * @var boolean
    * @access private
    */
    var $_debug
    ;

    /**
    * Dead hosts, assoc array, 'host'=>'unixtime when ok to check again'
    *
    * @var array
    * @access private
    */
    var $_host_dead
    ;

    /**
    * Is compression available?
    *
    * @var boolean
    * @access private
    */
    var $_have_zlib
    ;

    /**
    * Do we want to use compression?
    *
    * @var boolean
    * @access private
    */
    var $_compress_enable
    ;

    /**
    * At how many bytes should we compress?
    *
    * @var interger
    * @access private
    */
    var $_compress_threshold
    ;

    /**
    * Are we using persistant links?
    *
    * @var boolean
    * @access private
    */
    var $_persistant
    ;

    /**
    * If only using one server; contains ip:port to connect to
    *
    * @var string
    * @access private
    */
    var $_single_sock
    ;

    /**
    * Array containing ip:port or array(ip:port, weight)
    *
    * @var array
    * @access private
    */
    var $_servers
    ;

    /**
    * Our bit buckets
    *
    * @var array
    * @access private
    */
    var $_buckets
    ;

    /**
    * Total # of bit buckets we have
    *
    * @var interger
    * @access private
    */
    var $_bucketcount
    ;

    /**
    * # of total servers we have
    *
    * @var interger
    * @access private
    */
    var $_active
    ;

    // }}}
    // }}}
    // {{{ methods
    // {{{ public functions
    // {{{ memcached()

    /**
    * Memcache initializer
    *
    * @param array $args Associative array of settings
    *
    * @return mixed
    * @access public
    */
    function memcached ($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()

    /**
    * Adds a key/value to the memcache server if one isn't already set with
    * that key
    *
    * @param string $key Key to set with data
    * @param mixed $val Value to store
    * @param interger $exp (optional) Time to expire data at
    *
    * @return boolean
    * @access public
    */
    function add ($key, $val, $exp = 0
    )
    {
    return
    $this->_set('add', $key, $val, $exp
    );
    }

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

    /**
    * Decriment a value stored on the memcache server
    *
    * @param string $key Key to decriment
    * @param interger $amt (optional) Amount to decriment
    *
    * @return mixed FALSE on failure, value on success
    * @access public
    */
    function decr ($key, $amt=1
    )
    {
    return
    $this->_incrdecr('decr', $key, $amt
    );
    }

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

    /**
    * Deletes a key from the server, optionally after $time
    *
    * @param string $key Key to delete
    * @param interger $time (optional) How long to wait before deleting
    *
    * @return boolean TRUE on success, FALSE on failure
    * @access public
    */
    function delete ($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()

    /**
    * Disconnects all connected sockets
    *
    * @access public
    */
    function disconnect_all
    ()
    {
    foreach (
    $this->_cache_sock as $sock
    )
    fclose($sock
    );

    $this->_cache_sock
    = array();
    }

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

    /**
    * Enable / Disable compression
    *
    * @param boolean $enable TRUE to enable, FALSE to disable
    *
    * @access public
    */
    function enable_compress ($enable
    )
    {
    $this->_compress_enable = $enable
    ;
    }

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

    /**
    * Forget about all of the dead hosts
    *
    * @access public
    */
    function forget_dead_hosts
    ()
    {
    $this->_host_dead
    = array();
    }

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

    /**
    * Retrieves the value associated with the key from the memcache server
    *
    * @param string $key Key to retrieve
    *
    * @return mixed
    * @access public
    */
    function get ($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 (
    $val as $k => $v
    )
    printf("MemCache: sock %s got %s => %s/r/n", $sock, $k, $v
    );

    return
    $val[$key
    ];
    }

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

    /**
    * Get multiple keys from the server(s)
    *
    * @param array $keys Keys to retrieve
    *
    * @return array
    * @access public
    */
    function get_multi ($keys
    )
    {
    if (!
    $this->_active
    )
    return
    false
    ;

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

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

    // Send out the requests
    foreach ($socks as $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
    );
    }
    }

    // Parse responses
    $val
    = array();
    foreach (
    $gather as $sock
    )
    {
    $this->_load_items($sock, $val
    );
    }

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

    return
    $val
    ;
    }

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

    /**
    * Increments $key (optionally) by $amt
    *
    * @param string $key Key to increment
    * @param interger $amt (optional) amount to increment
    *
    * @return interger New key value?
    * @access public
    */
    function incr ($key, $amt=1
    )
    {
    return
    $this->_incrdecr('incr', $key, $amt
    );
    }

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

    /**
    * Overwrites an existing value for key; only works if key is already set
    *
    * @param string $key Key to set value as
    * @param mixed $value Value to store
    * @param interger $exp (optional) Experiation time
    *
    * @return boolean
    * @access public
    */
    function replace ($key, $value, $exp=0
    )
    {
    return
    $this->_set('replace', $key, $value, $exp
    );
    }

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

    /**
    * Passes through $cmd to the memcache server connected by $sock; returns
    * output as an array (null array if no output)
    *
    * NOTE: due to a possible bug in how PHP reads while using fgets(), each
    * line may not be terminated by a /r/n. More specifically, my testing
    * has shown that, on FreeBSD at least, each line is terminated only
    * with a /n. This is with the PHP flag auto_detect_line_endings set
    * to falase (the default).
    *
    * @param resource $sock Socket to send command on
    * @param string $cmd Command to run
    *
    * @return array Output array
    * @access public
    */
    function run_command ($sock, $cmd
    )
    {
    if (!
    is_resource($sock
    ))
    return array();

    if (!
    fwrite($sock, $cmd, strlen($cmd
    )))
    return array();

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

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

    /**
    * Unconditionally sets a key to a given value in the memcache. Returns true
    * if set successfully.
    *
    * @param string $key Key to set value as
    * @param mixed $value Value to set
    * @param interger $exp (optional) Experiation time
    *
    * @return boolean TRUE on success
    * @access public
    */
    function set ($key, $value, $exp=0
    )
    {
    return
    $this->_set('set', $key, $value, $exp
    );
    }

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

    /**
    * Sets the compression threshold
    *
    * @param interger $thresh Threshold to compress if larger than
    *
    * @access public
    */
    function set_compress_threshold ($thresh
    )
    {
    $this->_compress_threshold = $thresh
    ;
    }

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

    /**
    * Sets the debug flag
    *
    * @param boolean $dbg TRUE for debugging, FALSE otherwise
    *
    * @access public
    *
    * @see memcahced::memcached
    */
    function set_debug ($dbg
    )
    {
    $this->_debug = $dbg
    ;
    }

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

    /**
    * Sets the server list to distribute key gets and puts between
    *
    * @param array $list Array of servers to connect to
    *
    * @access public
    *
    * @see memcached::memcached()
    */
    function set_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
    ];
    }

    // }}}
    // }}}
    // {{{ private methods
    // {{{ _close_sock()

    /**
    * Close the specified socket
    *
    * @param string $sock Socket to close
    *
    * @access private
    */
    function _close_sock ($sock
    )
    {
    $host = array_search($sock, $this->_cache_sock
    );
    fclose($this->_cache_sock[$host
    ]);
    unset(
    $this->_cache_sock[$host
    ]);
    }

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

    /**
    * Connects $sock to $host, timing out after $timeout
    *
    * @param interger $sock Socket to connect
    * @param string $host Host:IP to connect to
    * @param float $timeout (optional) Timeout value, defaults to 0.25s
    *
    * @return boolean
    * @access private
    */
    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()

    /**
    * Marks a host as dead until 30-40 seconds in the future
    *
    * @param string $sock Socket to mark as dead
    *
    * @access private
    */
    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
    *
    * @param string $key Key to retrieve value for;
    *
    * @return mixed resource on success, false on failure
    * @access private
    */
    function get_sock ($key
    )
    {
    if (!
    $this->_active
    )
    return
    false
    ;

    if (
    $this->_single_sock !== null

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:php运算符以及运算符短路 下一篇:phalcon PHP基础知识(一)
    VIP课程(WEB全栈开发)

    相关文章推荐

    • 【腾讯云】年中优惠,「专享618元」优惠券!• PHP数组排序函数使用方法• 论坛显示顺序的问题• PHP跳转页面的三种方式• phpcms v9 模板标签说明整理系列• Sajax融合服务器端的PHP和JS
    1/1

    PHP中文网