Cache
[ class tree: Cache ] [ index: Cache ] [ all elements ]

Source for file Container.php

Documentation is available at Container.php

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

Documentation generated on Mon, 11 Mar 2019 15:25:49 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.