Initial commit
This commit is contained in:
		
							
								
								
									
										240
									
								
								content/inc/Cache/Cache.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								content/inc/Cache/Cache.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,240 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace dokuwiki\Cache;
 | 
			
		||||
 | 
			
		||||
use dokuwiki\Debug\PropertyDeprecationHelper;
 | 
			
		||||
use dokuwiki\Extension\Event;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Generic handling of caching
 | 
			
		||||
 */
 | 
			
		||||
class Cache
 | 
			
		||||
{
 | 
			
		||||
    use PropertyDeprecationHelper;
 | 
			
		||||
 | 
			
		||||
    public $key = '';          // primary identifier for this item
 | 
			
		||||
    public $ext = '';          // file ext for cache data, secondary identifier for this item
 | 
			
		||||
    public $cache = '';        // cache file name
 | 
			
		||||
    public $depends = array(); // array containing cache dependency information,
 | 
			
		||||
    //   used by makeDefaultCacheDecision to determine cache validity
 | 
			
		||||
 | 
			
		||||
    // phpcs:disable
 | 
			
		||||
    /**
 | 
			
		||||
     * @deprecated since 2019-02-02 use the respective getters instead!
 | 
			
		||||
     */
 | 
			
		||||
    protected $_event = '';       // event to be triggered during useCache
 | 
			
		||||
    protected $_time;
 | 
			
		||||
    protected $_nocache = false;  // if set to true, cache will not be used or stored
 | 
			
		||||
    // phpcs:enable
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param string $key primary identifier
 | 
			
		||||
     * @param string $ext file extension
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct($key, $ext)
 | 
			
		||||
    {
 | 
			
		||||
        $this->key = $key;
 | 
			
		||||
        $this->ext = $ext;
 | 
			
		||||
        $this->cache = getCacheName($key, $ext);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * @deprecated since 2019-02-02 use the respective getters instead!
 | 
			
		||||
         */
 | 
			
		||||
        $this->deprecatePublicProperty('_event');
 | 
			
		||||
        $this->deprecatePublicProperty('_time');
 | 
			
		||||
        $this->deprecatePublicProperty('_nocache');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getTime()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_time;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getEvent()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_event;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setEvent($event)
 | 
			
		||||
    {
 | 
			
		||||
        $this->_event = $event;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * public method to determine whether the cache can be used
 | 
			
		||||
     *
 | 
			
		||||
     * to assist in centralisation of event triggering and calculation of cache statistics,
 | 
			
		||||
     * don't override this function override makeDefaultCacheDecision()
 | 
			
		||||
     *
 | 
			
		||||
     * @param  array $depends array of cache dependencies, support dependecies:
 | 
			
		||||
     *                            'age'   => max age of the cache in seconds
 | 
			
		||||
     *                            'files' => cache must be younger than mtime of each file
 | 
			
		||||
     *                                       (nb. dependency passes if file doesn't exist)
 | 
			
		||||
     *
 | 
			
		||||
     * @return bool    true if cache can be used, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public function useCache($depends = array())
 | 
			
		||||
    {
 | 
			
		||||
        $this->depends = $depends;
 | 
			
		||||
        $this->addDependencies();
 | 
			
		||||
 | 
			
		||||
        if ($this->getEvent()) {
 | 
			
		||||
            return $this->stats(
 | 
			
		||||
                Event::createAndTrigger(
 | 
			
		||||
                    $this->getEvent(),
 | 
			
		||||
                    $this,
 | 
			
		||||
                    array($this, 'makeDefaultCacheDecision')
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->stats($this->makeDefaultCacheDecision());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * internal method containing cache use decision logic
 | 
			
		||||
     *
 | 
			
		||||
     * this function processes the following keys in the depends array
 | 
			
		||||
     *   purge - force a purge on any non empty value
 | 
			
		||||
     *   age   - expire cache if older than age (seconds)
 | 
			
		||||
     *   files - expire cache if any file in this array was updated more recently than the cache
 | 
			
		||||
     *
 | 
			
		||||
     * Note that this function needs to be public as it is used as callback for the event handler
 | 
			
		||||
     *
 | 
			
		||||
     * can be overridden
 | 
			
		||||
     *
 | 
			
		||||
     * @internal This method may only be called by the event handler! Call \dokuwiki\Cache\Cache::useCache instead!
 | 
			
		||||
     *
 | 
			
		||||
     * @return bool               see useCache()
 | 
			
		||||
     */
 | 
			
		||||
    public function makeDefaultCacheDecision()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->_nocache) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }                              // caching turned off
 | 
			
		||||
        if (!empty($this->depends['purge'])) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }              // purge requested?
 | 
			
		||||
        if (!($this->_time = @filemtime($this->cache))) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }   // cache exists?
 | 
			
		||||
 | 
			
		||||
        // cache too old?
 | 
			
		||||
        if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!empty($this->depends['files'])) {
 | 
			
		||||
            foreach ($this->depends['files'] as $file) {
 | 
			
		||||
                if ($this->_time <= @filemtime($file)) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }         // cache older than files it depends on?
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * add dependencies to the depends array
 | 
			
		||||
     *
 | 
			
		||||
     * this method should only add dependencies,
 | 
			
		||||
     * it should not remove any existing dependencies and
 | 
			
		||||
     * it should only overwrite a dependency when the new value is more stringent than the old
 | 
			
		||||
     */
 | 
			
		||||
    protected function addDependencies()
 | 
			
		||||
    {
 | 
			
		||||
        global $INPUT;
 | 
			
		||||
        if ($INPUT->has('purge')) {
 | 
			
		||||
            $this->depends['purge'] = true;
 | 
			
		||||
        }   // purge requested
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * retrieve the cached data
 | 
			
		||||
     *
 | 
			
		||||
     * @param   bool $clean true to clean line endings, false to leave line endings alone
 | 
			
		||||
     * @return  string          cache contents
 | 
			
		||||
     */
 | 
			
		||||
    public function retrieveCache($clean = true)
 | 
			
		||||
    {
 | 
			
		||||
        return io_readFile($this->cache, $clean);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * cache $data
 | 
			
		||||
     *
 | 
			
		||||
     * @param   string $data the data to be cached
 | 
			
		||||
     * @return  bool           true on success, false otherwise
 | 
			
		||||
     */
 | 
			
		||||
    public function storeCache($data)
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->_nocache) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return io_saveFile($this->cache, $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * remove any cached data associated with this cache instance
 | 
			
		||||
     */
 | 
			
		||||
    public function removeCache()
 | 
			
		||||
    {
 | 
			
		||||
        @unlink($this->cache);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Record cache hits statistics.
 | 
			
		||||
     * (Only when debugging allowed, to reduce overhead.)
 | 
			
		||||
     *
 | 
			
		||||
     * @param    bool $success result of this cache use attempt
 | 
			
		||||
     * @return   bool              pass-thru $success value
 | 
			
		||||
     */
 | 
			
		||||
    protected function stats($success)
 | 
			
		||||
    {
 | 
			
		||||
        global $conf;
 | 
			
		||||
        static $stats = null;
 | 
			
		||||
        static $file;
 | 
			
		||||
 | 
			
		||||
        if (!$conf['allowdebug']) {
 | 
			
		||||
            return $success;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (is_null($stats)) {
 | 
			
		||||
            $file = $conf['cachedir'] . '/cache_stats.txt';
 | 
			
		||||
            $lines = explode("\n", io_readFile($file));
 | 
			
		||||
 | 
			
		||||
            foreach ($lines as $line) {
 | 
			
		||||
                $i = strpos($line, ',');
 | 
			
		||||
                $stats[substr($line, 0, $i)] = $line;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isset($stats[$this->ext])) {
 | 
			
		||||
            list($ext, $count, $hits) = explode(',', $stats[$this->ext]);
 | 
			
		||||
        } else {
 | 
			
		||||
            $ext = $this->ext;
 | 
			
		||||
            $count = 0;
 | 
			
		||||
            $hits = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $count++;
 | 
			
		||||
        if ($success) {
 | 
			
		||||
            $hits++;
 | 
			
		||||
        }
 | 
			
		||||
        $stats[$this->ext] = "$ext,$count,$hits";
 | 
			
		||||
 | 
			
		||||
        io_saveFile($file, join("\n", $stats));
 | 
			
		||||
 | 
			
		||||
        return $success;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function isNoCache()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->_nocache;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user