News:

Please note these forums are mostly a testing ground for my SMF work and I don't really use them otherwise.

Main Menu

Paste-1259125268:v:use_geshi-1:v:type-php

Started by Guest, Nov 25, 2009, 05:01 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Guest

<?php
/*
** The settings in Settings.php should look like this:
// Select a system. Probably want to leave this up to the installer or admin panel.
$cache = array(
   // memcache, eaccelerator, mmcache, output_cache, xcache, apc, file, or false.
   'system' => '',
   // The level of caching. The higher the number, the more gets cached. An integer between 0 and 3 (0 turns caching off).
   'level' => 0,
   // This is generally only used for memcache. Should be a string of 'server:port, server:port'.
   'servers' => '',
   // Persistent connection (only of use to memcache).
   'persist' => false,
   // The directory where you want to store your cache files (if you are using the 'file' system).
   'dir' => '',
   // Boolean value. If true, it logs how many hits/misses and how long they took.
   'debug' => false,
);
*/

$cache = new cache($cache);
class cache
{
   public $hits = 0;
   public $count = 0;
   protected $settings = array();

   // Check all of the variables and setup what functions to use.
   function __construct ($settings = false)
   {
      $this->settings = $settings;

      if ($this->cache == false)
         return;

      $this->settings['level'] = !empty($this->settings['level']) ? (int) $this->settings['level'] : false;
      $this->settings['system'] = !empty($this->settings['system']) ? $this->settings['system'] : false;
      $this->settings['dir'] = !empty($this->settings['dir']) && file_exists($this->settings['dir']) ? $this->settings['dir'] : false;

      if (!$this->settings['system'] || !$this->settings['level'])
         $this->settings = false;
   
      // Define the Get, Set, and sometimes Remove functions.
      // Just added: remove, increment, decrement, status.
      switch ($this->settings['system'])
      {
         case 'apc':
            $this->get = 'apc_fetch';
            $this->set = 'apc_store';
            $this->rm = 'apc_delete';
            $this->clear = 'apc_clear_cache';
            break;
         case 'memcache':
            $this->get = 'memcache_get';
            $this->set = 'memcache_set';
            $this->rm = 'memcache_delete';
            $this->clear = 'memcache_flush';
            break;
         case 'eaccelerator':
            $this->get = 'eaccelerator_get';
            $this->set = 'eaccelerator_put';
            $this->rm = 'eaccelerator_rm';
            $this->gc = 'eaccelerator_gc';
            // Might have to use eaccelerator_list_keys() and rm all of them.
            //$this->clear = 'eaccelerator_gc';
            break;
         case 'mmcache':
            $this->get = 'mmcache_get';
            $this->set = 'mmcache_put';
            $this->rm = 'mmcache_rm';
            $this->gc = 'mmcache_gc';
            break;
         case 'output_cache':
            $this->get = 'output_cache_get';
            $this->set = 'output_cache_put';
            // Always one that has to be different. We must find those that check for TTL in get.
            $this->settings['req_ttl'] = true;
            $this->rm = 'output_cache_remove_key';
            // No idea how to implement clear() in this one.
            break;
         case 'xcache':
            $this->get = 'xcache_get';
            $this->set = 'xcache_set';
            $this->rm = 'xcache_unset';
            $this->clear = 'xcache_clear_cache';
            break;
         case: 'file':
            $this->get = array($this, 'get');
            $this->set = array($this, 'set');
            $this->rm = array($this, 'rm');
            $this->clear = array($this, 'clear');
            //$this->version = array($this, 'version'),
         default:
            $this->settings = false;
      }
   
      // Do we need to connect to the memcached server?
      if ($this->settings['system'] == 'memcache')
      {
         if (!empty($this->settings['servers']))
         {   
            // Not connected yet?
            if (empty($this->res))
            {
               $this->settings['servers'] = explode(',', $this->settings['servers']);
               get_memcached_server();
            }
            if (!$this->res)
               $this->settings = false;
         }
         else
            $this->settings = false;
      }
   
      // Do we need to do garbage collection?
      if (isset($this->gc) && mt_rand(0, 10) == 1)
         call_user_func($this->gc);
   
      // Let someone know that caching isn't working.
      if ($this->settings === false)
         trigger_error('Invalid cache type: ' . $this->settings['system'], E_USER_NOTICE);
   
      if (!is_callable($this->get) || !is_callable($this->set))
         trigger_error($this->get .' or ' . $this->set . ' functions not found', E_USER_NOTICE);
   }

   // Connect to a memcached server.
   private function get_memcached_server($level = 3)
   {   
      $server = explode(':', trim($this->settings['servers'][array_rand($this->settings['servers'])]));
   
      // Don't try more times than we have servers!
      $level = min(count($this->settings['servers']), $level);
   
      // Don't wait too long. It might be faster to just run without caching.
      if ($this->settings['persist'])
         $this->res = memcache_connect($server[0], empty($server[1]) ? 11211 : $server[1]);
      else
         $this->res = memcache_pconnect($server[0], empty($server[1]) ? 11211 : $server[1]);
   
      if (!$this->res && $level > 0)
         get_memcached_server($level - 1);
   }

   // Put an item in the cache.
   function put($key, $value, $ttl = 120, $level = 0)
   {   
      if (!$this->settings)
         return;
   
      if ($this->settings['debug'])
      {
         $this->count++;
         $this->hits[$this->count] = array('k' => $key, 'd' => 'put', 's' => $value === null ? 0 : strlen(serialize($value)));
         $st = microtime();
      }
   
      $key = $this->get_key($key);
      $value = $value === null ? null : serialize($value);
   
      if ($value === null)
         $this->rm($key);
   
      if ($this->settings['system'] == 'file')
      {
         // Create a PHP file with the info.
         if ($value !== null)
            file_put_contents($this->settings['dir'] . '/data_' . $key . '.php', '<?php if (' . (time() + $ttl) . ' < time()) $expired = true; else{$expired = false; $value = \'' . addcslashes($value, '\\\'') . '\';}?>', LOCK_EX);
         else
            $this->rm($this->settings['dir'] . '/data_' . $key . '.php');
      }
      // Some caches are accessed through a resource.
      elseif (isset($this->res))
         $cache['put']($this->res, $key, $value, 0, $ttl);
      else
         $cache['put']($key, $value, $ttl);
   
      if ($this->settings['debug'])
         $this->hits[$this->count]['t'] = array_sum(explode(' ', microtime())) - array_sum(explode(' ', $st));
   }

   // Return a cached item.
   function get($key, $ttl = 120, $level = 0)
   {   
      if (!$this->settings)
         return;
   
      if ($this->settings['debug'])
      {
         $this->count++;
         $this->hits[$this->count] = array('k' => $key, 'd' => 'get');
         $st = microtime();
      }
   
      $key = $this->get_key($key);
   
      if ($this->settings['system'] == 'file' && file_exists($this->settings['dir'] . '/data_' . $key . '.php') && filesize($this->settings['dir'] . '/data_' . $key . '.php') > 10)
      {
         require($this->settings['dir'] . '/data_' . $key . '.php');
         if (!empty($expired) && isset($value))
         {
            $this->rm($this->settings['dir'] . '/data_' . $key . '.php');
            unset($value);
         }
      }
      elseif (isset($this->res))
         $value = $this->get($this->res, $key);
      elseif ($this->settings['req_ttl'])
         $value = $this->get($key, $ttl);
      else
         $value = $this->get($key);
   
      if ($this->settings['debug'])
      {
         $this->hits[$this->count]['t'] = array_sum(explode(' ', microtime())) - array_sum(explode(' ', $st));
         $this->hits[$this->count]['s'] = isset($value) ? strlen($value) : 0;
      }
   
      if (!empty($value))
         return unserialize($value);
   }

   // Increment.
   function increment($key, $value = 1, $ttl = 120)
   {
      if (!$this->settings)
         return;

      if (!isset($this->inc))
      {
         $cached_value = call_user_func(array($this, 'get'), $key);
         if (is_int($cached_value))
         {
            call_user_func(array($this, 'put'), $cached_value + $value);
            return $cached_value + $value;
         }
      }
      elseif ($this->settings['req_ttl'])
         return call_user_func($this->inc, $value, $ttl);
      else
         return call_user_func($this->inc, $value);
   }

   // Decrement.
   function decrement($key, $value = 1, $ttl = 120)
   {
      if (!$this->settings)
         return;

      if (!isset($this->dec))
      {
         $cached_value = call_user_func(array($this, 'get'), $key);
         if (is_int($cached_value))
         {
            call_user_func(array($this, 'put'), $cached_value - $value);
            return $cached_value + $value;
         }
      }
      elseif ($this->settings['req_ttl'])
         return call_user_func($this->dec, $value, $ttl);
      else
         return call_user_func($this->dec, $value);
   }

   // Remove a cached item.
   function rm($key)
   {
      if (!$this->settings)
         return;

      if ($this->settings['system'] == 'file' && file_exists($this->settings['dir'] . '/data_' . $key . '.php'))
         unlink($this->settings['dir'] . '/data_' . $key . '.php');
      else
         call_user_func($this->rm);
   }

   // Clears the entire cache. Nothing will be left!
   function clear()
   {
      if (!$this->settings)
         return;

      if ($this->settings['system'] == 'file')
      {
         $files = scandir($this->settings['dir']);
         foreach ($files as $file)
            unlink($this->settings . '/' . $file);
      }

      // If there is no clear function defined, try to find all of the keys and delete those?
      // If we can't delete all of them, try dropping everything and then restarting?
   }

   // Return the version of the current cache.
   function version()
   {
      if (!$this->settings)
         return;

      switch($this->settings['system'])
      {
         case 'apc':
            $version = array('title' => 'Alternative PHP Cache', 'version' => phpversion('apc'));
            break;
         case 'memcache':
            $version = array('title' => 'Memcached', 'version' => memcache_get_version($this->resource));
            break;
         case 'eaccelerator':
            $version = array('title' => 'eAccelerator', 'version' => EACCELERATOR_VERSION);
            break;
         case 'mmcache':
            $version = array('title' => 'Turck MMCache', 'version' => MMCACHE_VERSION);
            break;
         case 'output_cache':
            global $_PHPA;
            $version = array('title' => 'Zend', 'version' => $_PHPA['VERSION']);
            break;
         case 'xcache':
            $version = array('title' => 'XCache', 'version' => XCACHE_VERSION);
            break;
         default:
            $version = array('title' => 'file', 'version' => 1);
      }
      return $version;
   }

   // One function to get the key so we can change how the keys are formatted easily.
   private function get_key($key)
   {
      //return md5(__DIR__ . filemtime(__FILE__) . __FILE__ . strtr($key, ':', '-'));
      return strtr($key, ':', '-');
   }
}

/*   Development Notes:
   *   I removed the @ operator from unlink because if we can't remove a file, we don't want to fill up our filesystem with cached files.
      I'd rather have it fill up an error log and let someone know about it.
   *   Webpages for support:
         MMCache:      http://turck-mmcache.sourceforge.net/index_old.html#api
         Xcache:         http://xcache.lighttpd.net/wiki/XcacheApi
         memcache:      http://www.php.net/memcache
         APC:         http://www.php.net/apc
         eAccelerator:   http://bart.eaccelerator.net/doc/phpdoc/
         Zend:         http://files.zend.com/help/Zend-Platform/partial_and_preemptive_page_caching.htm
*/
?>