web/lib/Zend/Cache/Core.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Cache
       
    17  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  * @version    $Id: Core.php 22651 2010-07-21 04:19:44Z ramon $
       
    20  */
       
    21 
       
    22 
       
    23 /**
       
    24  * @package    Zend_Cache
       
    25  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    26  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    27  */
       
    28 class Zend_Cache_Core
       
    29 {
       
    30     /**
       
    31      * Messages
       
    32      */
       
    33     const BACKEND_NOT_SUPPORTS_TAG = 'tags are not supported by the current backend';
       
    34     const BACKEND_NOT_IMPLEMENTS_EXTENDED_IF = 'Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available';
       
    35 
       
    36     /**
       
    37      * Backend Object
       
    38      *
       
    39      * @var Zend_Cache_Backend_Interface $_backend
       
    40      */
       
    41     protected $_backend = null;
       
    42 
       
    43     /**
       
    44      * Available options
       
    45      *
       
    46      * ====> (boolean) write_control :
       
    47      * - Enable / disable write control (the cache is read just after writing to detect corrupt entries)
       
    48      * - Enable write control will lightly slow the cache writing but not the cache reading
       
    49      * Write control can detect some corrupt cache files but maybe it's not a perfect control
       
    50      *
       
    51      * ====> (boolean) caching :
       
    52      * - Enable / disable caching
       
    53      * (can be very useful for the debug of cached scripts)
       
    54      *
       
    55      * =====> (string) cache_id_prefix :
       
    56      * - prefix for cache ids (namespace)
       
    57      *
       
    58      * ====> (boolean) automatic_serialization :
       
    59      * - Enable / disable automatic serialization
       
    60      * - It can be used to save directly datas which aren't strings (but it's slower)
       
    61      *
       
    62      * ====> (int) automatic_cleaning_factor :
       
    63      * - Disable / Tune the automatic cleaning process
       
    64      * - The automatic cleaning process destroy too old (for the given life time)
       
    65      *   cache files when a new cache file is written :
       
    66      *     0               => no automatic cache cleaning
       
    67      *     1               => systematic cache cleaning
       
    68      *     x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
       
    69      *
       
    70      * ====> (int) lifetime :
       
    71      * - Cache lifetime (in seconds)
       
    72      * - If null, the cache is valid forever.
       
    73      *
       
    74      * ====> (boolean) logging :
       
    75      * - If set to true, logging is activated (but the system is slower)
       
    76      *
       
    77      * ====> (boolean) ignore_user_abort
       
    78      * - If set to true, the core will set the ignore_user_abort PHP flag inside the
       
    79      *   save() method to avoid cache corruptions in some cases (default false)
       
    80      *
       
    81      * @var array $_options available options
       
    82      */
       
    83     protected $_options = array(
       
    84         'write_control'             => true,
       
    85         'caching'                   => true,
       
    86         'cache_id_prefix'           => null,
       
    87         'automatic_serialization'   => false,
       
    88         'automatic_cleaning_factor' => 10,
       
    89         'lifetime'                  => 3600,
       
    90         'logging'                   => false,
       
    91         'logger'                    => null,
       
    92         'ignore_user_abort'         => false
       
    93     );
       
    94 
       
    95     /**
       
    96      * Array of options which have to be transfered to backend
       
    97      *
       
    98      * @var array $_directivesList
       
    99      */
       
   100     protected static $_directivesList = array('lifetime', 'logging', 'logger');
       
   101 
       
   102     /**
       
   103      * Not used for the core, just a sort a hint to get a common setOption() method (for the core and for frontends)
       
   104      *
       
   105      * @var array $_specificOptions
       
   106      */
       
   107     protected $_specificOptions = array();
       
   108 
       
   109     /**
       
   110      * Last used cache id
       
   111      *
       
   112      * @var string $_lastId
       
   113      */
       
   114     private $_lastId = null;
       
   115 
       
   116     /**
       
   117      * True if the backend implements Zend_Cache_Backend_ExtendedInterface
       
   118      *
       
   119      * @var boolean $_extendedBackend
       
   120      */
       
   121     protected $_extendedBackend = false;
       
   122 
       
   123     /**
       
   124      * Array of capabilities of the backend (only if it implements Zend_Cache_Backend_ExtendedInterface)
       
   125      *
       
   126      * @var array
       
   127      */
       
   128     protected $_backendCapabilities = array();
       
   129 
       
   130     /**
       
   131      * Constructor
       
   132      *
       
   133      * @param  array|Zend_Config $options Associative array of options or Zend_Config instance
       
   134      * @throws Zend_Cache_Exception
       
   135      * @return void
       
   136      */
       
   137     public function __construct($options = array())
       
   138     {
       
   139         if ($options instanceof Zend_Config) {
       
   140             $options = $options->toArray();
       
   141         }
       
   142         if (!is_array($options)) {
       
   143             Zend_Cache::throwException("Options passed were not an array"
       
   144             . " or Zend_Config instance.");
       
   145         }
       
   146         while (list($name, $value) = each($options)) {
       
   147             $this->setOption($name, $value);
       
   148         }
       
   149         $this->_loggerSanity();
       
   150     }
       
   151 
       
   152     /**
       
   153      * Set options using an instance of type Zend_Config
       
   154      *
       
   155      * @param Zend_Config $config
       
   156      * @return Zend_Cache_Core
       
   157      */
       
   158     public function setConfig(Zend_Config $config)
       
   159     {
       
   160         $options = $config->toArray();
       
   161         while (list($name, $value) = each($options)) {
       
   162             $this->setOption($name, $value);
       
   163         }
       
   164         return $this;
       
   165     }
       
   166 
       
   167     /**
       
   168      * Set the backend
       
   169      *
       
   170      * @param  Zend_Cache_Backend $backendObject
       
   171      * @throws Zend_Cache_Exception
       
   172      * @return void
       
   173      */
       
   174     public function setBackend(Zend_Cache_Backend $backendObject)
       
   175     {
       
   176         $this->_backend= $backendObject;
       
   177         // some options (listed in $_directivesList) have to be given
       
   178         // to the backend too (even if they are not "backend specific")
       
   179         $directives = array();
       
   180         foreach (Zend_Cache_Core::$_directivesList as $directive) {
       
   181             $directives[$directive] = $this->_options[$directive];
       
   182         }
       
   183         $this->_backend->setDirectives($directives);
       
   184         if (in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_backend))) {
       
   185             $this->_extendedBackend = true;
       
   186             $this->_backendCapabilities = $this->_backend->getCapabilities();
       
   187         }
       
   188 
       
   189     }
       
   190 
       
   191     /**
       
   192      * Returns the backend
       
   193      *
       
   194      * @return Zend_Cache_Backend backend object
       
   195      */
       
   196     public function getBackend()
       
   197     {
       
   198         return $this->_backend;
       
   199     }
       
   200 
       
   201     /**
       
   202      * Public frontend to set an option
       
   203      *
       
   204      * There is an additional validation (relatively to the protected _setOption method)
       
   205      *
       
   206      * @param  string $name  Name of the option
       
   207      * @param  mixed  $value Value of the option
       
   208      * @throws Zend_Cache_Exception
       
   209      * @return void
       
   210      */
       
   211     public function setOption($name, $value)
       
   212     {
       
   213         if (!is_string($name)) {
       
   214             Zend_Cache::throwException("Incorrect option name : $name");
       
   215         }
       
   216         $name = strtolower($name);
       
   217         if (array_key_exists($name, $this->_options)) {
       
   218             // This is a Core option
       
   219             $this->_setOption($name, $value);
       
   220             return;
       
   221         }
       
   222         if (array_key_exists($name, $this->_specificOptions)) {
       
   223             // This a specic option of this frontend
       
   224             $this->_specificOptions[$name] = $value;
       
   225             return;
       
   226         }
       
   227     }
       
   228 
       
   229     /**
       
   230      * Public frontend to get an option value
       
   231      *
       
   232      * @param  string $name  Name of the option
       
   233      * @throws Zend_Cache_Exception
       
   234      * @return mixed option value
       
   235      */
       
   236     public function getOption($name)
       
   237     {
       
   238         if (is_string($name)) {
       
   239             $name = strtolower($name);
       
   240             if (array_key_exists($name, $this->_options)) {
       
   241                 // This is a Core option
       
   242                 return $this->_options[$name];
       
   243             }
       
   244             if (array_key_exists($name, $this->_specificOptions)) {
       
   245                 // This a specic option of this frontend
       
   246                 return $this->_specificOptions[$name];
       
   247             }
       
   248         }
       
   249         Zend_Cache::throwException("Incorrect option name : $name");
       
   250     }
       
   251 
       
   252     /**
       
   253      * Set an option
       
   254      *
       
   255      * @param  string $name  Name of the option
       
   256      * @param  mixed  $value Value of the option
       
   257      * @throws Zend_Cache_Exception
       
   258      * @return void
       
   259      */
       
   260     private function _setOption($name, $value)
       
   261     {
       
   262         if (!is_string($name) || !array_key_exists($name, $this->_options)) {
       
   263             Zend_Cache::throwException("Incorrect option name : $name");
       
   264         }
       
   265         if ($name == 'lifetime' && empty($value)) {
       
   266             $value = null;
       
   267         }
       
   268         $this->_options[$name] = $value;
       
   269     }
       
   270 
       
   271     /**
       
   272      * Force a new lifetime
       
   273      *
       
   274      * The new value is set for the core/frontend but for the backend too (directive)
       
   275      *
       
   276      * @param  int $newLifetime New lifetime (in seconds)
       
   277      * @return void
       
   278      */
       
   279     public function setLifetime($newLifetime)
       
   280     {
       
   281         $this->_options['lifetime'] = $newLifetime;
       
   282         $this->_backend->setDirectives(array(
       
   283             'lifetime' => $newLifetime
       
   284         ));
       
   285     }
       
   286 
       
   287     /**
       
   288      * Test if a cache is available for the given id and (if yes) return it (false else)
       
   289      *
       
   290      * @param  string  $id                     Cache id
       
   291      * @param  boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
       
   292      * @param  boolean $doNotUnserialize       Do not serialize (even if automatic_serialization is true) => for internal use
       
   293      * @return mixed|false Cached datas
       
   294      */
       
   295     public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false)
       
   296     {
       
   297         if (!$this->_options['caching']) {
       
   298             return false;
       
   299         }
       
   300         $id = $this->_id($id); // cache id may need prefix
       
   301         $this->_lastId = $id;
       
   302         self::_validateIdOrTag($id);
       
   303         $data = $this->_backend->load($id, $doNotTestCacheValidity);
       
   304         if ($data===false) {
       
   305             // no cache available
       
   306             return false;
       
   307         }
       
   308         if ((!$doNotUnserialize) && $this->_options['automatic_serialization']) {
       
   309             // we need to unserialize before sending the result
       
   310             return unserialize($data);
       
   311         }
       
   312         return $data;
       
   313     }
       
   314 
       
   315     /**
       
   316      * Test if a cache is available for the given id
       
   317      *
       
   318      * @param  string $id Cache id
       
   319      * @return int|false Last modified time of cache entry if it is available, false otherwise
       
   320      */
       
   321     public function test($id)
       
   322     {
       
   323         if (!$this->_options['caching']) {
       
   324             return false;
       
   325         }
       
   326         $id = $this->_id($id); // cache id may need prefix
       
   327         self::_validateIdOrTag($id);
       
   328         $this->_lastId = $id;
       
   329         return $this->_backend->test($id);
       
   330     }
       
   331 
       
   332     /**
       
   333      * Save some data in a cache
       
   334      *
       
   335      * @param  mixed $data           Data to put in cache (can be another type than string if automatic_serialization is on)
       
   336      * @param  string $id             Cache id (if not set, the last cache id will be used)
       
   337      * @param  array $tags           Cache tags
       
   338      * @param  int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
       
   339      * @param  int   $priority         integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends
       
   340      * @throws Zend_Cache_Exception
       
   341      * @return boolean True if no problem
       
   342      */
       
   343     public function save($data, $id = null, $tags = array(), $specificLifetime = false, $priority = 8)
       
   344     {
       
   345         if (!$this->_options['caching']) {
       
   346             return true;
       
   347         }
       
   348         if ($id === null) {
       
   349             $id = $this->_lastId;
       
   350         } else {
       
   351             $id = $this->_id($id);
       
   352         }
       
   353         self::_validateIdOrTag($id);
       
   354         self::_validateTagsArray($tags);
       
   355         if ($this->_options['automatic_serialization']) {
       
   356             // we need to serialize datas before storing them
       
   357             $data = serialize($data);
       
   358         } else {
       
   359             if (!is_string($data)) {
       
   360                 Zend_Cache::throwException("Datas must be string or set automatic_serialization = true");
       
   361             }
       
   362         }
       
   363         // automatic cleaning
       
   364         if ($this->_options['automatic_cleaning_factor'] > 0) {
       
   365             $rand = rand(1, $this->_options['automatic_cleaning_factor']);
       
   366             if ($rand==1) {
       
   367                 if ($this->_extendedBackend) {
       
   368                     // New way
       
   369                     if ($this->_backendCapabilities['automatic_cleaning']) {
       
   370                         $this->clean(Zend_Cache::CLEANING_MODE_OLD);
       
   371                     } else {
       
   372                         $this->_log('Zend_Cache_Core::save() / automatic cleaning is not available/necessary with this backend');
       
   373                     }
       
   374                 } else {
       
   375                     // Deprecated way (will be removed in next major version)
       
   376                     if (method_exists($this->_backend, 'isAutomaticCleaningAvailable') && ($this->_backend->isAutomaticCleaningAvailable())) {
       
   377                         $this->clean(Zend_Cache::CLEANING_MODE_OLD);
       
   378                     } else {
       
   379                         $this->_log('Zend_Cache_Core::save() / automatic cleaning is not available/necessary with this backend');
       
   380                     }
       
   381                 }
       
   382             }
       
   383         }
       
   384         if ($this->_options['ignore_user_abort']) {
       
   385             $abort = ignore_user_abort(true);
       
   386         }
       
   387         if (($this->_extendedBackend) && ($this->_backendCapabilities['priority'])) {
       
   388             $result = $this->_backend->save($data, $id, $tags, $specificLifetime, $priority);
       
   389         } else {
       
   390             $result = $this->_backend->save($data, $id, $tags, $specificLifetime);
       
   391         }
       
   392         if ($this->_options['ignore_user_abort']) {
       
   393             ignore_user_abort($abort);
       
   394         }
       
   395         if (!$result) {
       
   396             // maybe the cache is corrupted, so we remove it !
       
   397             if ($this->_options['logging']) {
       
   398                 $this->_log("Zend_Cache_Core::save() : impossible to save cache (id=$id)");
       
   399             }
       
   400             $this->remove($id);
       
   401             return false;
       
   402         }
       
   403         if ($this->_options['write_control']) {
       
   404             $data2 = $this->_backend->load($id, true);
       
   405             if ($data!=$data2) {
       
   406                 $this->_log('Zend_Cache_Core::save() / write_control : written and read data do not match');
       
   407                 $this->_backend->remove($id);
       
   408                 return false;
       
   409             }
       
   410         }
       
   411         return true;
       
   412     }
       
   413 
       
   414     /**
       
   415      * Remove a cache
       
   416      *
       
   417      * @param  string $id Cache id to remove
       
   418      * @return boolean True if ok
       
   419      */
       
   420     public function remove($id)
       
   421     {
       
   422         if (!$this->_options['caching']) {
       
   423             return true;
       
   424         }
       
   425         $id = $this->_id($id); // cache id may need prefix
       
   426         self::_validateIdOrTag($id);
       
   427         return $this->_backend->remove($id);
       
   428     }
       
   429 
       
   430     /**
       
   431      * Clean cache entries
       
   432      *
       
   433      * Available modes are :
       
   434      * 'all' (default)  => remove all cache entries ($tags is not used)
       
   435      * 'old'            => remove too old cache entries ($tags is not used)
       
   436      * 'matchingTag'    => remove cache entries matching all given tags
       
   437      *                     ($tags can be an array of strings or a single string)
       
   438      * 'notMatchingTag' => remove cache entries not matching one of the given tags
       
   439      *                     ($tags can be an array of strings or a single string)
       
   440      * 'matchingAnyTag' => remove cache entries matching any given tags
       
   441      *                     ($tags can be an array of strings or a single string)
       
   442      *
       
   443      * @param  string       $mode
       
   444      * @param  array|string $tags
       
   445      * @throws Zend_Cache_Exception
       
   446      * @return boolean True if ok
       
   447      */
       
   448     public function clean($mode = 'all', $tags = array())
       
   449     {
       
   450         if (!$this->_options['caching']) {
       
   451             return true;
       
   452         }
       
   453         if (!in_array($mode, array(Zend_Cache::CLEANING_MODE_ALL,
       
   454                                    Zend_Cache::CLEANING_MODE_OLD,
       
   455                                    Zend_Cache::CLEANING_MODE_MATCHING_TAG,
       
   456                                    Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG,
       
   457                                    Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG))) {
       
   458             Zend_Cache::throwException('Invalid cleaning mode');
       
   459         }
       
   460         self::_validateTagsArray($tags);
       
   461         return $this->_backend->clean($mode, $tags);
       
   462     }
       
   463 
       
   464     /**
       
   465      * Return an array of stored cache ids which match given tags
       
   466      *
       
   467      * In case of multiple tags, a logical AND is made between tags
       
   468      *
       
   469      * @param array $tags array of tags
       
   470      * @return array array of matching cache ids (string)
       
   471      */
       
   472     public function getIdsMatchingTags($tags = array())
       
   473     {
       
   474         if (!$this->_extendedBackend) {
       
   475             Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
       
   476         }
       
   477         if (!($this->_backendCapabilities['tags'])) {
       
   478             Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
       
   479         }
       
   480 
       
   481         $ids = $this->_backend->getIdsMatchingTags($tags);
       
   482 
       
   483         // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
       
   484         if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
       
   485             $prefix    = & $this->_options['cache_id_prefix'];
       
   486             $prefixLen = strlen($prefix);
       
   487             foreach ($ids as &$id) {
       
   488                 if (strpos($id, $prefix) === 0) {
       
   489                     $id = substr($id, $prefixLen);
       
   490                 }
       
   491             }
       
   492         }
       
   493 
       
   494         return $ids;
       
   495     }
       
   496 
       
   497     /**
       
   498      * Return an array of stored cache ids which don't match given tags
       
   499      *
       
   500      * In case of multiple tags, a logical OR is made between tags
       
   501      *
       
   502      * @param array $tags array of tags
       
   503      * @return array array of not matching cache ids (string)
       
   504      */
       
   505     public function getIdsNotMatchingTags($tags = array())
       
   506     {
       
   507         if (!$this->_extendedBackend) {
       
   508             Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
       
   509         }
       
   510         if (!($this->_backendCapabilities['tags'])) {
       
   511             Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
       
   512         }
       
   513 
       
   514         $ids = $this->_backend->getIdsNotMatchingTags($tags);
       
   515 
       
   516         // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
       
   517         if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
       
   518             $prefix    = & $this->_options['cache_id_prefix'];
       
   519             $prefixLen = strlen($prefix);
       
   520             foreach ($ids as &$id) {
       
   521                 if (strpos($id, $prefix) === 0) {
       
   522                     $id = substr($id, $prefixLen);
       
   523                 }
       
   524             }
       
   525         }
       
   526 
       
   527         return $ids;
       
   528     }
       
   529 
       
   530     /**
       
   531      * Return an array of stored cache ids which match any given tags
       
   532      *
       
   533      * In case of multiple tags, a logical OR is made between tags
       
   534      *
       
   535      * @param array $tags array of tags
       
   536      * @return array array of matching any cache ids (string)
       
   537      */
       
   538     public function getIdsMatchingAnyTags($tags = array())
       
   539     {
       
   540         if (!$this->_extendedBackend) {
       
   541             Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
       
   542         }
       
   543         if (!($this->_backendCapabilities['tags'])) {
       
   544             Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
       
   545         }
       
   546 
       
   547         $ids = $this->_backend->getIdsMatchingAnyTags($tags);
       
   548 
       
   549         // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
       
   550         if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
       
   551             $prefix    = & $this->_options['cache_id_prefix'];
       
   552             $prefixLen = strlen($prefix);
       
   553             foreach ($ids as &$id) {
       
   554                 if (strpos($id, $prefix) === 0) {
       
   555                     $id = substr($id, $prefixLen);
       
   556                 }
       
   557             }
       
   558         }
       
   559 
       
   560         return $ids;
       
   561     }
       
   562 
       
   563     /**
       
   564      * Return an array of stored cache ids
       
   565      *
       
   566      * @return array array of stored cache ids (string)
       
   567      */
       
   568     public function getIds()
       
   569     {
       
   570         if (!$this->_extendedBackend) {
       
   571             Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
       
   572         }
       
   573 
       
   574         $ids = $this->_backend->getIds();
       
   575 
       
   576         // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
       
   577         if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
       
   578             $prefix    = & $this->_options['cache_id_prefix'];
       
   579             $prefixLen = strlen($prefix);
       
   580             foreach ($ids as &$id) {
       
   581                 if (strpos($id, $prefix) === 0) {
       
   582                     $id = substr($id, $prefixLen);
       
   583                 }
       
   584             }
       
   585         }
       
   586 
       
   587         return $ids;
       
   588     }
       
   589 
       
   590     /**
       
   591      * Return an array of stored tags
       
   592      *
       
   593      * @return array array of stored tags (string)
       
   594      */
       
   595     public function getTags()
       
   596     {
       
   597         if (!$this->_extendedBackend) {
       
   598             Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
       
   599         }
       
   600         if (!($this->_backendCapabilities['tags'])) {
       
   601             Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
       
   602         }
       
   603         return $this->_backend->getTags();
       
   604     }
       
   605 
       
   606     /**
       
   607      * Return the filling percentage of the backend storage
       
   608      *
       
   609      * @return int integer between 0 and 100
       
   610      */
       
   611     public function getFillingPercentage()
       
   612     {
       
   613         if (!$this->_extendedBackend) {
       
   614             Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
       
   615         }
       
   616         return $this->_backend->getFillingPercentage();
       
   617     }
       
   618 
       
   619     /**
       
   620      * Return an array of metadatas for the given cache id
       
   621      *
       
   622      * The array will include these keys :
       
   623      * - expire : the expire timestamp
       
   624      * - tags : a string array of tags
       
   625      * - mtime : timestamp of last modification time
       
   626      *
       
   627      * @param string $id cache id
       
   628      * @return array array of metadatas (false if the cache id is not found)
       
   629      */
       
   630     public function getMetadatas($id)
       
   631     {
       
   632         if (!$this->_extendedBackend) {
       
   633             Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
       
   634         }
       
   635         $id = $this->_id($id); // cache id may need prefix
       
   636         return $this->_backend->getMetadatas($id);
       
   637     }
       
   638 
       
   639     /**
       
   640      * Give (if possible) an extra lifetime to the given cache id
       
   641      *
       
   642      * @param string $id cache id
       
   643      * @param int $extraLifetime
       
   644      * @return boolean true if ok
       
   645      */
       
   646     public function touch($id, $extraLifetime)
       
   647     {
       
   648         if (!$this->_extendedBackend) {
       
   649             Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
       
   650         }
       
   651         $id = $this->_id($id); // cache id may need prefix
       
   652         return $this->_backend->touch($id, $extraLifetime);
       
   653     }
       
   654 
       
   655     /**
       
   656      * Validate a cache id or a tag (security, reliable filenames, reserved prefixes...)
       
   657      *
       
   658      * Throw an exception if a problem is found
       
   659      *
       
   660      * @param  string $string Cache id or tag
       
   661      * @throws Zend_Cache_Exception
       
   662      * @return void
       
   663      */
       
   664     protected static function _validateIdOrTag($string)
       
   665     {
       
   666         if (!is_string($string)) {
       
   667             Zend_Cache::throwException('Invalid id or tag : must be a string');
       
   668         }
       
   669         if (substr($string, 0, 9) == 'internal-') {
       
   670             Zend_Cache::throwException('"internal-*" ids or tags are reserved');
       
   671         }
       
   672         if (!preg_match('~^[a-zA-Z0-9_]+$~D', $string)) {
       
   673             Zend_Cache::throwException("Invalid id or tag '$string' : must use only [a-zA-Z0-9_]");
       
   674         }
       
   675     }
       
   676 
       
   677     /**
       
   678      * Validate a tags array (security, reliable filenames, reserved prefixes...)
       
   679      *
       
   680      * Throw an exception if a problem is found
       
   681      *
       
   682      * @param  array $tags Array of tags
       
   683      * @throws Zend_Cache_Exception
       
   684      * @return void
       
   685      */
       
   686     protected static function _validateTagsArray($tags)
       
   687     {
       
   688         if (!is_array($tags)) {
       
   689             Zend_Cache::throwException('Invalid tags array : must be an array');
       
   690         }
       
   691         foreach($tags as $tag) {
       
   692             self::_validateIdOrTag($tag);
       
   693         }
       
   694         reset($tags);
       
   695     }
       
   696 
       
   697     /**
       
   698      * Make sure if we enable logging that the Zend_Log class
       
   699      * is available.
       
   700      * Create a default log object if none is set.
       
   701      *
       
   702      * @throws Zend_Cache_Exception
       
   703      * @return void
       
   704      */
       
   705     protected function _loggerSanity()
       
   706     {
       
   707         if (!isset($this->_options['logging']) || !$this->_options['logging']) {
       
   708             return;
       
   709         }
       
   710 
       
   711         if (isset($this->_options['logger']) && $this->_options['logger'] instanceof Zend_Log) {
       
   712             return;
       
   713         }
       
   714 
       
   715         // Create a default logger to the standard output stream
       
   716         require_once 'Zend/Log/Writer/Stream.php';
       
   717         require_once 'Zend/Log.php';
       
   718         $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
       
   719         $this->_options['logger'] = $logger;
       
   720     }
       
   721 
       
   722     /**
       
   723      * Log a message at the WARN (4) priority.
       
   724      *
       
   725      * @param string $message
       
   726      * @throws Zend_Cache_Exception
       
   727      * @return void
       
   728      */
       
   729     protected function _log($message, $priority = 4)
       
   730     {
       
   731         if (!$this->_options['logging']) {
       
   732             return;
       
   733         }
       
   734         if (!(isset($this->_options['logger']) || $this->_options['logger'] instanceof Zend_Log)) {
       
   735             Zend_Cache::throwException('Logging is enabled but logger is not set');
       
   736         }
       
   737         $logger = $this->_options['logger'];
       
   738         $logger->log($message, $priority);
       
   739     }
       
   740 
       
   741     /**
       
   742      * Make and return a cache id
       
   743      *
       
   744      * Checks 'cache_id_prefix' and returns new id with prefix or simply the id if null
       
   745      *
       
   746      * @param  string $id Cache id
       
   747      * @return string Cache id (with or without prefix)
       
   748      */
       
   749     protected function _id($id)
       
   750     {
       
   751         if (($id !== null) && isset($this->_options['cache_id_prefix'])) {
       
   752             return $this->_options['cache_id_prefix'] . $id; // return with prefix
       
   753         }
       
   754         return $id; // no prefix, just return the $id passed
       
   755     }
       
   756 
       
   757 }