File indexing completed on 2025-01-19 05:20:56

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Cache
0017  * @subpackage Zend_Cache_Backend
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 
0024 /**
0025  * @see Zend_Cache_Backend_Interface
0026  */
0027 // require_once 'Zend/Cache/Backend/ExtendedInterface.php';
0028 
0029 /**
0030  * @see Zend_Cache_Backend
0031  */
0032 // require_once 'Zend/Cache/Backend.php';
0033 
0034 
0035 /**
0036  * @package    Zend_Cache
0037  * @subpackage Zend_Cache_Backend
0038  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0039  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0040  */
0041 class Zend_Cache_Backend_Apc extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
0042 {
0043     /**
0044      * Log message
0045      */
0046     const TAGS_UNSUPPORTED_BY_CLEAN_OF_APC_BACKEND = 'Zend_Cache_Backend_Apc::clean() : tags are unsupported by the Apc backend';
0047     const TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND =  'Zend_Cache_Backend_Apc::save() : tags are unsupported by the Apc backend';
0048 
0049     /**
0050      * Constructor
0051      *
0052      * @param  array $options associative array of options
0053      * @throws Zend_Cache_Exception
0054      * @return void
0055      */
0056     public function __construct(array $options = array())
0057     {
0058         if (!extension_loaded('apc')) {
0059             Zend_Cache::throwException('The apc extension must be loaded for using this backend !');
0060         }
0061         parent::__construct($options);
0062     }
0063 
0064     /**
0065      * Test if a cache is available for the given id and (if yes) return it (false else)
0066      *
0067      * WARNING $doNotTestCacheValidity=true is unsupported by the Apc backend
0068      *
0069      * @param  string  $id                     cache id
0070      * @param  boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
0071      * @return string cached datas (or false)
0072      */
0073     public function load($id, $doNotTestCacheValidity = false)
0074     {
0075         $tmp = apc_fetch($id);
0076         if (is_array($tmp)) {
0077             return $tmp[0];
0078         }
0079         return false;
0080     }
0081 
0082     /**
0083      * Test if a cache is available or not (for the given id)
0084      *
0085      * @param  string $id cache id
0086      * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
0087      */
0088     public function test($id)
0089     {
0090         $tmp = apc_fetch($id);
0091         if (is_array($tmp)) {
0092             return $tmp[1];
0093         }
0094         return false;
0095     }
0096 
0097     /**
0098      * Save some string datas into a cache record
0099      *
0100      * Note : $data is always "string" (serialization is done by the
0101      * core not by the backend)
0102      *
0103      * @param string $data datas to cache
0104      * @param string $id cache id
0105      * @param array $tags array of strings, the cache record will be tagged by each string entry
0106      * @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime)
0107      * @return boolean true if no problem
0108      */
0109     public function save($data, $id, $tags = array(), $specificLifetime = false)
0110     {
0111         $lifetime = $this->getLifetime($specificLifetime);
0112         $result = apc_store($id, array($data, time(), $lifetime), $lifetime);
0113         if (count($tags) > 0) {
0114             $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
0115         }
0116         return $result;
0117     }
0118 
0119     /**
0120      * Remove a cache record
0121      *
0122      * @param  string $id cache id
0123      * @return boolean true if no problem
0124      */
0125     public function remove($id)
0126     {
0127         return apc_delete($id);
0128     }
0129 
0130     /**
0131      * Clean some cache records
0132      *
0133      * Available modes are :
0134      * 'all' (default)  => remove all cache entries ($tags is not used)
0135      * 'old'            => unsupported
0136      * 'matchingTag'    => unsupported
0137      * 'notMatchingTag' => unsupported
0138      * 'matchingAnyTag' => unsupported
0139      *
0140      * @param  string $mode clean mode
0141      * @param  array  $tags array of tags
0142      * @throws Zend_Cache_Exception
0143      * @return boolean true if no problem
0144      */
0145     public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
0146     {
0147         switch ($mode) {
0148             case Zend_Cache::CLEANING_MODE_ALL:
0149                 return apc_clear_cache('user');
0150                 break;
0151             case Zend_Cache::CLEANING_MODE_OLD:
0152                 $this->_log("Zend_Cache_Backend_Apc::clean() : CLEANING_MODE_OLD is unsupported by the Apc backend");
0153                 break;
0154             case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
0155             case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
0156             case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
0157                 $this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_APC_BACKEND);
0158                 break;
0159             default:
0160                 Zend_Cache::throwException('Invalid mode for clean() method');
0161                 break;
0162         }
0163     }
0164 
0165     /**
0166      * Return true if the automatic cleaning is available for the backend
0167      *
0168      * DEPRECATED : use getCapabilities() instead
0169      *
0170      * @deprecated
0171      * @return boolean
0172      */
0173     public function isAutomaticCleaningAvailable()
0174     {
0175         return false;
0176     }
0177 
0178     /**
0179      * Return the filling percentage of the backend storage
0180      *
0181      * @throws Zend_Cache_Exception
0182      * @return int integer between 0 and 100
0183      */
0184     public function getFillingPercentage()
0185     {
0186         $mem = apc_sma_info(true);
0187         $memSize    = $mem['num_seg'] * $mem['seg_size'];
0188         $memAvailable= $mem['avail_mem'];
0189         $memUsed = $memSize - $memAvailable;
0190         if ($memSize == 0) {
0191             Zend_Cache::throwException('can\'t get apc memory size');
0192         }
0193         if ($memUsed > $memSize) {
0194             return 100;
0195         }
0196         return ((int) (100. * ($memUsed / $memSize)));
0197     }
0198 
0199     /**
0200      * Return an array of stored tags
0201      *
0202      * @return array array of stored tags (string)
0203      */
0204     public function getTags()
0205     {
0206         $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
0207         return array();
0208     }
0209 
0210     /**
0211      * Return an array of stored cache ids which match given tags
0212      *
0213      * In case of multiple tags, a logical AND is made between tags
0214      *
0215      * @param array $tags array of tags
0216      * @return array array of matching cache ids (string)
0217      */
0218     public function getIdsMatchingTags($tags = array())
0219     {
0220         $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
0221         return array();
0222     }
0223 
0224     /**
0225      * Return an array of stored cache ids which don't match given tags
0226      *
0227      * In case of multiple tags, a logical OR is made between tags
0228      *
0229      * @param array $tags array of tags
0230      * @return array array of not matching cache ids (string)
0231      */
0232     public function getIdsNotMatchingTags($tags = array())
0233     {
0234         $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
0235         return array();
0236     }
0237 
0238     /**
0239      * Return an array of stored cache ids which match any given tags
0240      *
0241      * In case of multiple tags, a logical AND is made between tags
0242      *
0243      * @param array $tags array of tags
0244      * @return array array of any matching cache ids (string)
0245      */
0246     public function getIdsMatchingAnyTags($tags = array())
0247     {
0248         $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_APC_BACKEND);
0249         return array();
0250     }
0251 
0252     /**
0253      * Return an array of stored cache ids
0254      *
0255      * @return array array of stored cache ids (string)
0256      */
0257     public function getIds()
0258     {
0259         $ids      = array();
0260         $iterator = new APCIterator('user', null, APC_ITER_KEY);
0261         foreach ($iterator as $item) {
0262             $ids[] = $item['key'];
0263         }
0264 
0265         return $ids;
0266     }
0267 
0268     /**
0269      * Return an array of metadatas for the given cache id
0270      *
0271      * The array must include these keys :
0272      * - expire : the expire timestamp
0273      * - tags : a string array of tags
0274      * - mtime : timestamp of last modification time
0275      *
0276      * @param string $id cache id
0277      * @return array array of metadatas (false if the cache id is not found)
0278      */
0279     public function getMetadatas($id)
0280     {
0281         $tmp = apc_fetch($id);
0282         if (is_array($tmp)) {
0283             $data = $tmp[0];
0284             $mtime = $tmp[1];
0285             if (!isset($tmp[2])) {
0286                 // because this record is only with 1.7 release
0287                 // if old cache records are still there...
0288                 return false;
0289             }
0290             $lifetime = $tmp[2];
0291             return array(
0292                 'expire' => $mtime + $lifetime,
0293                 'tags' => array(),
0294                 'mtime' => $mtime
0295             );
0296         }
0297         return false;
0298     }
0299 
0300     /**
0301      * Give (if possible) an extra lifetime to the given cache id
0302      *
0303      * @param string $id cache id
0304      * @param int $extraLifetime
0305      * @return boolean true if ok
0306      */
0307     public function touch($id, $extraLifetime)
0308     {
0309         $tmp = apc_fetch($id);
0310         if (is_array($tmp)) {
0311             $data = $tmp[0];
0312             $mtime = $tmp[1];
0313             if (!isset($tmp[2])) {
0314                 // because this record is only with 1.7 release
0315                 // if old cache records are still there...
0316                 return false;
0317             }
0318             $lifetime = $tmp[2];
0319             $newLifetime = $lifetime - (time() - $mtime) + $extraLifetime;
0320             if ($newLifetime <=0) {
0321                 return false;
0322             }
0323             apc_store($id, array($data, time(), $newLifetime), $newLifetime);
0324             return true;
0325         }
0326         return false;
0327     }
0328 
0329     /**
0330      * Return an associative array of capabilities (booleans) of the backend
0331      *
0332      * The array must include these keys :
0333      * - automatic_cleaning (is automating cleaning necessary)
0334      * - tags (are tags supported)
0335      * - expired_read (is it possible to read expired cache records
0336      *                 (for doNotTestCacheValidity option for example))
0337      * - priority does the backend deal with priority when saving
0338      * - infinite_lifetime (is infinite lifetime can work with this backend)
0339      * - get_list (is it possible to get the list of cache ids and the complete list of tags)
0340      *
0341      * @return array associative of with capabilities
0342      */
0343     public function getCapabilities()
0344     {
0345         return array(
0346             'automatic_cleaning' => false,
0347             'tags' => false,
0348             'expired_read' => false,
0349             'priority' => false,
0350             'infinite_lifetime' => false,
0351             'get_list' => true
0352         );
0353     }
0354 
0355 }