web/lib/Zend/Cache/Backend/ZendPlatform.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  * @subpackage Zend_Cache_Backend
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  * @version    $Id: ZendPlatform.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    21  */
       
    22 
       
    23 /**
       
    24  * @see Zend_Cache_Backend_Interface
       
    25  */
       
    26 require_once 'Zend/Cache/Backend.php';
       
    27 
       
    28 /**
       
    29  * @see Zend_Cache_Backend_Interface
       
    30  */
       
    31 require_once 'Zend/Cache/Backend/Interface.php';
       
    32 
       
    33 
       
    34 /**
       
    35  * Impementation of Zend Cache Backend using the Zend Platform (Output Content Caching)
       
    36  *
       
    37  * @package    Zend_Cache
       
    38  * @subpackage Zend_Cache_Backend
       
    39  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    40  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    41  */
       
    42 class Zend_Cache_Backend_ZendPlatform extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface
       
    43 {
       
    44     /**
       
    45      * internal ZP prefix
       
    46      */
       
    47     const TAGS_PREFIX = "internal_ZPtag:";
       
    48 
       
    49     /**
       
    50      * Constructor
       
    51      * Validate that the Zend Platform is loaded and licensed
       
    52      *
       
    53      * @param  array $options Associative array of options
       
    54      * @throws Zend_Cache_Exception
       
    55      * @return void
       
    56      */
       
    57     public function __construct(array $options = array())
       
    58     {
       
    59         if (!function_exists('accelerator_license_info')) {
       
    60             Zend_Cache::throwException('The Zend Platform extension must be loaded for using this backend !');
       
    61         }
       
    62         if (!function_exists('accelerator_get_configuration')) {
       
    63             $licenseInfo = accelerator_license_info();
       
    64             Zend_Cache::throwException('The Zend Platform extension is not loaded correctly: '.$licenseInfo['failure_reason']);
       
    65         }
       
    66         $accConf = accelerator_get_configuration();
       
    67         if (@!$accConf['output_cache_licensed']) {
       
    68             Zend_Cache::throwException('The Zend Platform extension does not have the proper license to use content caching features');
       
    69         }
       
    70         if (@!$accConf['output_cache_enabled']) {
       
    71             Zend_Cache::throwException('The Zend Platform content caching feature must be enabled for using this backend, set the \'zend_accelerator.output_cache_enabled\' directive to On !');
       
    72         }
       
    73         if (!is_writable($accConf['output_cache_dir'])) {
       
    74             Zend_Cache::throwException('The cache copies directory \''. ini_get('zend_accelerator.output_cache_dir') .'\' must be writable !');
       
    75         }
       
    76         parent:: __construct($options);
       
    77     }
       
    78 
       
    79     /**
       
    80      * Test if a cache is available for the given id and (if yes) return it (false else)
       
    81      *
       
    82      * @param  string  $id                     Cache id
       
    83      * @param  boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
       
    84      * @return string Cached data (or false)
       
    85      */
       
    86     public function load($id, $doNotTestCacheValidity = false)
       
    87     {
       
    88         // doNotTestCacheValidity implemented by giving zero lifetime to the cache
       
    89         if ($doNotTestCacheValidity) {
       
    90             $lifetime = 0;
       
    91         } else {
       
    92             $lifetime = $this->_directives['lifetime'];
       
    93         }
       
    94         $res = output_cache_get($id, $lifetime);
       
    95         if($res) {
       
    96             return $res[0];
       
    97         } else {
       
    98             return false;
       
    99         }
       
   100     }
       
   101 
       
   102 
       
   103     /**
       
   104      * Test if a cache is available or not (for the given id)
       
   105      *
       
   106      * @param  string $id Cache id
       
   107      * @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record
       
   108      */
       
   109     public function test($id)
       
   110     {
       
   111         $result = output_cache_get($id, $this->_directives['lifetime']);
       
   112         if ($result) {
       
   113             return $result[1];
       
   114         }
       
   115         return false;
       
   116     }
       
   117 
       
   118     /**
       
   119      * Save some string datas into a cache record
       
   120      *
       
   121      * Note : $data is always "string" (serialization is done by the
       
   122      * core not by the backend)
       
   123      *
       
   124      * @param  string $data             Data to cache
       
   125      * @param  string $id               Cache id
       
   126      * @param  array  $tags             Array of strings, the cache record will be tagged by each string entry
       
   127      * @param  int    $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
       
   128      * @return boolean true if no problem
       
   129      */
       
   130     public function save($data, $id, $tags = array(), $specificLifetime = false)
       
   131     {
       
   132         if (!($specificLifetime === false)) {
       
   133             $this->_log("Zend_Cache_Backend_ZendPlatform::save() : non false specifc lifetime is unsuported for this backend");
       
   134         }
       
   135 
       
   136         $lifetime = $this->_directives['lifetime'];
       
   137         $result1  = output_cache_put($id, array($data, time()));
       
   138         $result2  = (count($tags) == 0);
       
   139 
       
   140         foreach ($tags as $tag) {
       
   141             $tagid = self::TAGS_PREFIX.$tag;
       
   142             $old_tags = output_cache_get($tagid, $lifetime);
       
   143             if ($old_tags === false) {
       
   144                 $old_tags = array();
       
   145             }
       
   146             $old_tags[$id] = $id;
       
   147             output_cache_remove_key($tagid);
       
   148             $result2 = output_cache_put($tagid, $old_tags);
       
   149         }
       
   150 
       
   151         return $result1 && $result2;
       
   152     }
       
   153 
       
   154 
       
   155     /**
       
   156      * Remove a cache record
       
   157      *
       
   158      * @param  string $id Cache id
       
   159      * @return boolean True if no problem
       
   160      */
       
   161     public function remove($id)
       
   162     {
       
   163         return output_cache_remove_key($id);
       
   164     }
       
   165 
       
   166 
       
   167     /**
       
   168      * Clean some cache records
       
   169      *
       
   170      * Available modes are :
       
   171      * Zend_Cache::CLEANING_MODE_ALL (default)    => remove all cache entries ($tags is not used)
       
   172      * Zend_Cache::CLEANING_MODE_OLD              => remove too old cache entries ($tags is not used)
       
   173      *                                               This mode is not supported in this backend
       
   174      * Zend_Cache::CLEANING_MODE_MATCHING_TAG     => remove cache entries matching all given tags
       
   175      *                                               ($tags can be an array of strings or a single string)
       
   176      * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => unsupported
       
   177      * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
       
   178      *                                               ($tags can be an array of strings or a single string)
       
   179      *
       
   180      * @param  string $mode Clean mode
       
   181      * @param  array  $tags Array of tags
       
   182      * @throws Zend_Cache_Exception
       
   183      * @return boolean True if no problem
       
   184      */
       
   185     public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
       
   186     {
       
   187         switch ($mode) {
       
   188             case Zend_Cache::CLEANING_MODE_ALL:
       
   189             case Zend_Cache::CLEANING_MODE_OLD:
       
   190                 $cache_dir = ini_get('zend_accelerator.output_cache_dir');
       
   191                 if (!$cache_dir) {
       
   192                     return false;
       
   193                 }
       
   194                 $cache_dir .= '/.php_cache_api/';
       
   195                 return $this->_clean($cache_dir, $mode);
       
   196                 break;
       
   197             case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
       
   198                 $idlist = null;
       
   199                 foreach ($tags as $tag) {
       
   200                     $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']);
       
   201                     if ($idlist) {
       
   202                         $idlist = array_intersect_assoc($idlist, $next_idlist);
       
   203                     } else {
       
   204                         $idlist = $next_idlist;
       
   205                     }
       
   206                     if (count($idlist) == 0) {
       
   207                         // if ID list is already empty - we may skip checking other IDs
       
   208                         $idlist = null;
       
   209                         break;
       
   210                     }
       
   211                 }
       
   212                 if ($idlist) {
       
   213                     foreach ($idlist as $id) {
       
   214                         output_cache_remove_key($id);
       
   215                     }
       
   216                 }
       
   217                 return true;
       
   218                 break;
       
   219             case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
       
   220                 $this->_log("Zend_Cache_Backend_ZendPlatform::clean() : CLEANING_MODE_NOT_MATCHING_TAG is not supported by the Zend Platform backend");
       
   221                 return false;
       
   222                 break;
       
   223             case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
       
   224                 $idlist = null;
       
   225                 foreach ($tags as $tag) {
       
   226                     $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']);
       
   227                     if ($idlist) {
       
   228                         $idlist = array_merge_recursive($idlist, $next_idlist);
       
   229                     } else {
       
   230                         $idlist = $next_idlist;
       
   231                     }
       
   232                     if (count($idlist) == 0) {
       
   233                         // if ID list is already empty - we may skip checking other IDs
       
   234                         $idlist = null;
       
   235                         break;
       
   236                     }
       
   237                 }
       
   238                 if ($idlist) {
       
   239                     foreach ($idlist as $id) {
       
   240                         output_cache_remove_key($id);
       
   241                     }
       
   242                 }
       
   243                 return true;
       
   244                 break;
       
   245             default:
       
   246                 Zend_Cache::throwException('Invalid mode for clean() method');
       
   247                 break;
       
   248         }
       
   249     }
       
   250 
       
   251     /**
       
   252      * Clean a directory and recursivly go over it's subdirectories
       
   253      *
       
   254      * Remove all the cached files that need to be cleaned (according to mode and files mtime)
       
   255      *
       
   256      * @param  string $dir  Path of directory ot clean
       
   257      * @param  string $mode The same parameter as in Zend_Cache_Backend_ZendPlatform::clean()
       
   258      * @return boolean True if ok
       
   259      */
       
   260     private function _clean($dir, $mode)
       
   261     {
       
   262         $d = @dir($dir);
       
   263         if (!$d) {
       
   264             return false;
       
   265         }
       
   266         $result = true;
       
   267         while (false !== ($file = $d->read())) {
       
   268             if ($file == '.' || $file == '..') {
       
   269                 continue;
       
   270             }
       
   271             $file = $d->path . $file;
       
   272             if (is_dir($file)) {
       
   273                 $result = ($this->_clean($file .'/', $mode)) && ($result);
       
   274             } else {
       
   275                 if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
       
   276                     $result = ($this->_remove($file)) && ($result);
       
   277                 } else if ($mode == Zend_Cache::CLEANING_MODE_OLD) {
       
   278                     // Files older than lifetime get deleted from cache
       
   279                     if ($this->_directives['lifetime'] !== null) {
       
   280                         if ((time() - @filemtime($file)) > $this->_directives['lifetime']) {
       
   281                             $result = ($this->_remove($file)) && ($result);
       
   282                         }
       
   283                     }
       
   284                 }
       
   285             }
       
   286         }
       
   287         $d->close();
       
   288         return $result;
       
   289     }
       
   290 
       
   291     /**
       
   292      * Remove a file
       
   293      *
       
   294      * If we can't remove the file (because of locks or any problem), we will touch
       
   295      * the file to invalidate it
       
   296      *
       
   297      * @param  string $file Complete file path
       
   298      * @return boolean True if ok
       
   299      */
       
   300     private function _remove($file)
       
   301     {
       
   302         if (!@unlink($file)) {
       
   303             # If we can't remove the file (because of locks or any problem), we will touch
       
   304             # the file to invalidate it
       
   305             $this->_log("Zend_Cache_Backend_ZendPlatform::_remove() : we can't remove $file => we are going to try to invalidate it");
       
   306             if ($this->_directives['lifetime'] === null) {
       
   307                 return false;
       
   308             }
       
   309             if (!file_exists($file)) {
       
   310                 return false;
       
   311             }
       
   312             return @touch($file, time() - 2*abs($this->_directives['lifetime']));
       
   313         }
       
   314         return true;
       
   315     }
       
   316 
       
   317 }