Add analytics
[bus.git] / busui / owa / includes / memcached-client.php
blob:a/busui/owa/includes/memcached-client.php -> blob:b/busui/owa/includes/memcached-client.php
  <?php
  //
  // +---------------------------------------------------------------------------+
  // | memcached client, PHP |
  // +---------------------------------------------------------------------------+
  // | Copyright (c) 2003 Ryan T. Dean <rtdean@cytherianage.net> |
  // | 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 <rtdean@cytherianage.net> |
  // | 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 <rtdean@cytherianage.net>
  * @version 0.1.2
  */
   
  // {{{ requirements
  // }}}
   
  // {{{ class memcached
  /**
  * memcached client class implemented using (p)fsockopen()
  *
  * @author Ryan T. Dean <rtdean@cytherianage.net>
  * @ingroup Cache
  */
  class memcached
  {
  // {{{ properties
  // {{{ public
   
  // {{{ constants
  // {{{ flags
   
  /**
  * Flag: indicates data is serialized
  */
  const SERIALIZED = 1;
   
  /**
  * Flag: indicates data is compressed
  */
  const COMPRESSED = 2;
   
  // }}}
   
  /**
  * Minimum savings to store data compressed
  */
  const COMPRESSION_SAVINGS = 0.20;
   
  // }}}
   
   
  /**
  * 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 integer
  * @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 integer
  * @access private
  */
  var $_bucketcount;
   
  /**
  * # of total servers we have
  *
  * @var integer
  * @access private
  */
  var $_active;
   
  /**
  * Stream timeout in seconds. Applies for example to fread()
  *
  * @var integer
  * @access private
  */
  var $_timeout_seconds;
   
  /**
  * Stream timeout in microseconds
  *
  * @var integer
  * @access private
  */
  var $_timeout_microseconds;
   
  /**
  * Connect timeout in seconds
  */
  var $_connect_timeout;
   
  /**
  * Number of connection attempts for each server
  */
  var $_connect_attempts;
   
  // }}}
  // }}}
  // {{{ 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 = array_key_exists('persistant', $args) ? (@$args['persistant']) : false;
  $this->_compress_enable = true;
  $this->_have_zlib = function_exists("gzcompress");
   
  $this->_cache_sock = array();
  $this->_host_dead = array();
   
  $this->_timeout_seconds = 1;
  $this->_timeout_microseconds = 0;
   
  $this->_connect_timeout = 0.01;
  $this->_connect_attempts = 3;
  }
   
  // }}}
  // {{{ 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 integer $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 integer $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 integer $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(!$this->_safe_fwrite($sock, $cmd, strlen($cmd)))
  {
  $this->_dead_sock($sock);
  return false;
  }
  $res = trim(fgets($sock));
   
  if ($this->_debug)
  $this->_debugprint(sprintf("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)
 </