home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 August / PCWorld_2001-08_cd.bin / Komunikace / phptriad / phptriadsetup2-11.exe / php / pear / Cache / Container.php next >
PHP Script  |  2001-03-08  |  13KB  |  425 lines

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP version 4.0                                                      |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to version 2.0 of the PHP license,       |
  8. // | that is bundled with this package in the file LICENSE, and is        |
  9. // | available at through the world-wide-web at                           |
  10. // | http://www.php.net/license/2_02.txt.                                 |
  11. // | If you did not receive a copy of the PHP license and are unable to   |
  12. // | obtain it through the world-wide-web, please send a note to          |
  13. // | license@php.net so we can mail you a copy immediately.               |
  14. // +----------------------------------------------------------------------+
  15. // | Authors: Ulf Wendel <ulf.wendel@phpdoc.de>                           |
  16. // |          Sebastian Bergmann <sb@sebastian-bergmann.de>               |
  17. // |          Christian Stocker <chregu@nomad.ch>                         |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: Container.php,v 1.9 2001/03/08 20:41:39 uw Exp $
  21.  
  22. require_once "Cache/Error.php";
  23.  
  24. /**
  25. * Common base class of all cache storage container.
  26. * To speed up things we do a preload you should know about, otherwise it might 
  27. * play you a trick. The Cache controller classes (Cache/Cache, Cache/Output, ...)
  28. * usually do something like is (isCached($id) && !isExpired($id)) return $container->load($id).
  29. * if you implement isCached(), isExpired() and load() straight ahead, each of this 
  30. * functions will result in a storage medium (db, file,...) access. This generates too much load. 
  31. * Now, a simple speculative preload should saves time in most cases. Whenever 
  32. * one of the mentioned methods is invoked we preload the cached dataset into class variables.
  33. * That means that we have only one storage medium access for the sequence
  34. *  (isCached($id) && !isExpired($id)) return $container->load($id).
  35. * The bad thing is that the preloaded data might be outdated meanwhile, which is 
  36. * unlikely but for you power users, be warned. If you do not want the preload 
  37. * you should switch it off by setting the class variable $preload to false. Anyway, this is 
  38. * not recommended!
  39. * @author   Ulf Wendel <ulf.wendel@phpdoc.de>
  40. * @version  $Id: Container.php,v 1.9 2001/03/08 20:41:39 uw Exp $
  41. * @package  Cache
  42. * @access   public
  43. * @abstract
  44. */
  45. class Cache_Container {
  46.  
  47.     /**
  48.     * Flag indicating wheter to preload datasets.
  49.     *
  50.     * See the class description for more details.
  51.     *
  52.     * @var  boolean
  53.     */
  54.     var $preload = true;
  55.  
  56.     /**
  57.     * ID of a preloaded dataset
  58.     *
  59.     * @var  string
  60.     */
  61.     var $id = "";
  62.  
  63.     /**
  64.     * Cache group of a preloaded dataset
  65.     *
  66.     * @var  string
  67.     */
  68.     var $group = "";
  69.  
  70.     /**
  71.     * Expiration timestamp of a preloaded dataset.
  72.     * 
  73.     * @var  integer 0 means never, endless
  74.     */
  75.     var $expires = 0;
  76.  
  77.     /**
  78.     * Value of a preloaded dataset.
  79.     * 
  80.     * @var  string
  81.     */
  82.     var $cachedata = "";
  83.  
  84.     /**
  85.     * Preloaded userdata field.
  86.     * 
  87.     * @var  string
  88.     */
  89.     var $userdata = "";
  90.  
  91.     /**
  92.     * Flag indicating that the dataset requested for preloading is unknown.
  93.     *  
  94.     * @var  boolean
  95.     */
  96.     var $unknown = true;
  97.  
  98.     /**
  99.     * Encoding mode for cache data: base64 or addslashes() (slash).
  100.     *
  101.     * @var  string  base64 or slash
  102.     */
  103.     var $encoding_mode = "base64";
  104.  
  105.     /**
  106.     * Loads a dataset from the cache.
  107.     * 
  108.     * @param    string  dataset ID
  109.     * @param    string  cache group
  110.     * @return   mixed   dataset value or NULL on failure
  111.     * @access   public
  112.     */
  113.     function load($id, $group) {
  114.         if ($this->preload) {
  115.             if ($this->id != $id || $this->group != $group)
  116.                 $this->preload($id, $group);
  117.  
  118.             return $this->cachedata;
  119.         } else {
  120.             list( , $data, ) = $this->fetch($id, $group);
  121.             return $data;
  122.         }
  123.     } // end func load
  124.  
  125.     /**
  126.     * Returns the userdata field of a cached data set.
  127.     *
  128.     * @param    string  dataset ID
  129.     * @param    string  cache group
  130.     * @return   string  userdata
  131.     * @access   public
  132.     */
  133.     function getUserdata($id, $group) {
  134.         if ($this->preload) {
  135.             if ($this->id != $id || $this->group != $group)
  136.                 $this->preload($id, $group);
  137.                 
  138.             return $this->userdata;
  139.         } else {
  140.             list( , , $userdata) = $this->fetch($id, $group);
  141.             return $userdata;
  142.         }
  143.     } // end func getUserdata
  144.  
  145.     /**
  146.     * Checks if a dataset is expired.
  147.     * 
  148.     * @param    string  dataset ID
  149.     * @param    string  cache group
  150.     * @param    integer maximum age timestamp
  151.     * @return   boolean 
  152.     * @access   public
  153.     */
  154.     function isExpired($id, $group, $max_age) {
  155.         if ($this->preload) {
  156.           if ($this->id != $id || $this->group != $group)
  157.             $this->preload($id, $group);
  158.           
  159.           if ($this->unknown)
  160.             return false;
  161.         } else {
  162.             // check if at all it is cached
  163.             if (!$this->isCached($id, $group))
  164.                 return false;
  165.                 
  166.             // I'm lazy...
  167.             list($this->expires, , ) = $this->fetch($id, $group);
  168.         }
  169.  
  170.         // endless
  171.         if (0 == $this->expires)
  172.             return false;
  173.  
  174.         // you feel fine, Ulf?
  175.         if ($expired  = ($this->expires <= time() || ($max_age && ($this->expires <= $max_age))) ) {
  176.  
  177.            $this->delete($id, $group);
  178.            $this->flushPreload();
  179.         }
  180.         return $expired;
  181.     } // end func isExpired
  182.  
  183.     /**
  184.     * Checks if a dataset is cached.
  185.     *
  186.     * @param    string  dataset ID
  187.     * @param    string  cache group
  188.     * @return   boolean
  189.     */
  190.     function isCached($id, $group) {
  191.         if ($this->preload) {
  192.             if ($this->id != $id || $this->group != $group)
  193.                 $this->preload($id, $group);
  194.  
  195.             return !($this->unknown);
  196.         } else {
  197.             return $this->idExists($id, $group);
  198.         }
  199.     } // end func isCached
  200.  
  201.     //
  202.     // abstract methods
  203.     //
  204.  
  205.     /**
  206.     * Fetches a dataset from the storage medium.
  207.     *
  208.     * @param    string  dataset ID
  209.     * @param    string  cache group
  210.     * @return   array   format: [expire date, cached data, user data]
  211.     * @throws   Cache_Error
  212.     * @abstract
  213.     */
  214.     function fetch($id, $group) {
  215.         return array(NULL, NULL, NULL);
  216.     } // end func fetch
  217.  
  218.     /**
  219.     * Stores a dataset.
  220.     * 
  221.     * @param    string  dataset ID
  222.     * @param    mixed   data to store
  223.     * @param    mixed   userdefined expire date
  224.     * @param    string  cache group
  225.     * @param    string  additional userdefined data
  226.     * @return   boolean
  227.     * @throws   Cache_Error
  228.     * @access   public
  229.     * @abstract
  230.     */
  231.     function save($id, $data, $expire, $group, $userdata) {
  232.         // QUESTION: Should we update the preload buffer instead?
  233.         // Don't think so as the sequence save()/load() is unlikely.
  234.         $this->flushPreload($id, $group);
  235.  
  236.         return NULL;
  237.     } // end func save
  238.  
  239.     /**
  240.     * Deletes a dataset.
  241.     * 
  242.     * @param    string  dataset ID
  243.     * @param    string  cache group
  244.     * @return   boolean  
  245.     * @access   public
  246.     * @abstract
  247.     */     
  248.     function delete($id, $group) {
  249.         $this->flushPreload($id, $group);
  250.         return NULL;
  251.     } // end func delete
  252.  
  253.     /**
  254.     * Flushes the cache - removes all caches datasets from the cache.
  255.     * 
  256.     * @param    string      If a cache group is given only the group will be flushed
  257.     * @return   integer     Number of removed datasets, -1 on failure
  258.     * @access   public
  259.     * @abstract
  260.     */
  261.     function flush($group) {
  262.         $this->flushPreload();
  263.         return NULL;
  264.     } // end func flush
  265.  
  266.     /**
  267.     * Checks if a dataset exists.
  268.     * 
  269.     * @param    string  dataset ID
  270.     * @param    string  cache group
  271.     * @return   boolean 
  272.     * @access   public
  273.     * @abstract
  274.     */
  275.     function idExists($id, $group) {
  276.         return NULL;
  277.     } // end func idExists
  278.  
  279.     /**
  280.     * Starts the garbage collection.
  281.     * 
  282.     * @access   public
  283.     * @abstract
  284.     */
  285.     function garbageCollection() {
  286.         $this->flushPreload();
  287.     } // end func garbageCollection
  288.  
  289.     /**
  290.     * Does a speculative preload of a dataset
  291.     *
  292.     * @param    string  dataset ID
  293.     * @param    string  cache group
  294.     * @return   boolean
  295.     */ 
  296.     function preload($id, $group) {
  297.         // whatever happens, remember the preloaded ID
  298.         $this->id = $id;
  299.         $this->group = $group;        
  300.  
  301.         list($this->expires, $this->cachedata, $this->userdata) = $this->fetch($id, $group);
  302.  
  303.         if (NULL === $this->expires) {
  304.             // Uuups, unknown ID
  305.             $this->flushPreload();
  306.  
  307.             return false;
  308.         }
  309.  
  310.         $this->unknown = false;
  311.  
  312.         return true;
  313.     } // end func preload
  314.  
  315.     /**
  316.     * Flushes the internal preload buffer.
  317.     *
  318.     * save(), delete() and flush() must call this method
  319.     * to preevent differences between the preloaded values and 
  320.     * the real cache contents.
  321.     *
  322.     * @param    string  dataset ID, if left out the preloaded values will be flushed. 
  323.     *                   If given the preloaded values will only be flushed if they are
  324.     *                   equal to the given id and group
  325.     * @param    string  cache group
  326.     * @see  preload()
  327.     */
  328.     function flushPreload($id = "", $group = "default") {
  329.         if (!$id || ($this->id == $id && $this->group == $group)) {
  330.             // clear the internal preload values
  331.             $this->id = "";
  332.             $this->group = "";
  333.             $this->cachedata = "";
  334.             $this->userdata = "";
  335.             $this->expires = -1;
  336.             $this->unknown = true;
  337.         }
  338.     } // end func flushPreload
  339.  
  340.     /**
  341.     * Imports the requested datafields as object variables if allowed
  342.     * 
  343.     * @param    array   List of fields to be imported as object variables
  344.     * @param    array   List of allowed datafields
  345.     */
  346.     function setOptions($requested, $allowed) {
  347.         foreach ($allowed as $k => $field)
  348.             if (isset($requested[$field]))
  349.                 $this->$field = $requested[$field];
  350.                 
  351.     } // end func setOptions
  352.  
  353.     /**
  354.     * Encodes the data for the storage container.
  355.     * 
  356.     * @var  mixed data to encode
  357.     */
  358.     function encode($data) {
  359.         if ("base64" == $this->encoding_mode) 
  360.             return base64_encode(serialize($data));
  361.         else 
  362.             return serialize($data);
  363.     } // end func encode
  364.  
  365.     
  366.     /**
  367.     * Decodes the data from the storage container.
  368.     * 
  369.     * @var  mixed
  370.     */
  371.     function decode($data) {
  372.         if ("base64" == $this->encoding_mode)
  373.             return unserialize(base64_decode($data));
  374.         else
  375.             return unserialize($data);
  376.     } // end func decode
  377.  
  378.     
  379.     /**
  380.     * Translates human readable/relative times in unixtime
  381.     *
  382.     * @param  mixed   can be in the following formats:
  383.     *               human readable          : yyyymmddhhmm[ss]] eg: 20010308095100
  384.     *               relative in seconds (1) : +xx              eg: +10
  385.     *               relative in seconds (2) : x <  946681200   eg: 10
  386.     *               absolute unixtime       : x < 2147483648   eg: 2147483648
  387.     *               see comments in code for details
  388.     * @return integer unix timestamp
  389.     */
  390.     function getExpiresAbsolute($expires)
  391.     {
  392.         if (!$expires)
  393.             return 0;
  394.         //for api-compatibility, one has not to provide a "+",
  395.         // if integer is < 946681200 (= Jan 01 2000 00:00:00)
  396.         if ('+' == $expires[0] || $expires < 946681200)
  397.         {
  398.             return(time() + $expires);
  399.         }
  400.         //if integer is < 100000000000 (= in 3140 years),
  401.         // it must be an absolut unixtime
  402.         // (since the "human readable" definition asks for a higher number)
  403.         elseif ($expires < 100000000000)
  404.         {
  405.             return $expires;
  406.         }
  407.         // else it's "human readable";
  408.         else
  409.         {
  410.             $year = substr($expires, 0, 4);
  411.             $month = substr($expires, 4, 2);
  412.             $day = substr($expires, 6, 2);
  413.             $hour = substr($expires, 8, 2);
  414.             $minute = substr($expires, 10, 2);
  415.             $second = substr($expires, 12, 2);
  416.             return mktime($hour, $minute, $second, $month, $day, $year);
  417.         }
  418.         
  419.     } // end func getExpireAbsolute
  420.     
  421. } // end class Container
  422. ?>
  423.