[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/Cache/ -> Cache.php (source)

   1  <?php
   2  
   3  namespace dokuwiki\Cache;
   4  
   5  use \dokuwiki\Debug\PropertyDeprecationHelper;
   6  use dokuwiki\Extension\Event;
   7  
   8  /**
   9   * Generic handling of caching
  10   */
  11  class Cache
  12  {
  13      use PropertyDeprecationHelper;
  14  
  15      public $key = '';          // primary identifier for this item
  16      public $ext = '';          // file ext for cache data, secondary identifier for this item
  17      public $cache = '';        // cache file name
  18      public $depends = array(); // array containing cache dependency information,
  19      //   used by makeDefaultCacheDecision to determine cache validity
  20  
  21      // phpcs:disable
  22      /**
  23       * @deprecated since 2019-02-02 use the respective getters instead!
  24       */
  25      protected $_event = '';       // event to be triggered during useCache
  26      protected $_time;
  27      protected $_nocache = false;  // if set to true, cache will not be used or stored
  28      // phpcs:enable
  29  
  30      /**
  31       * @param string $key primary identifier
  32       * @param string $ext file extension
  33       */
  34      public function __construct($key, $ext)
  35      {
  36          $this->key = $key;
  37          $this->ext = $ext;
  38          $this->cache = getCacheName($key, $ext);
  39  
  40          /**
  41           * @deprecated since 2019-02-02 use the respective getters instead!
  42           */
  43          $this->deprecatePublicProperty('_event');
  44          $this->deprecatePublicProperty('_time');
  45          $this->deprecatePublicProperty('_nocache');
  46      }
  47  
  48      public function getTime()
  49      {
  50          return $this->_time;
  51      }
  52  
  53      public function getEvent()
  54      {
  55          return $this->_event;
  56      }
  57  
  58      public function setEvent($event)
  59      {
  60          $this->_event = $event;
  61      }
  62  
  63      /**
  64       * public method to determine whether the cache can be used
  65       *
  66       * to assist in centralisation of event triggering and calculation of cache statistics,
  67       * don't override this function override makeDefaultCacheDecision()
  68       *
  69       * @param  array $depends array of cache dependencies, support dependecies:
  70       *                            'age'   => max age of the cache in seconds
  71       *                            'files' => cache must be younger than mtime of each file
  72       *                                       (nb. dependency passes if file doesn't exist)
  73       *
  74       * @return bool    true if cache can be used, false otherwise
  75       */
  76      public function useCache($depends = array())
  77      {
  78          $this->depends = $depends;
  79          $this->addDependencies();
  80  
  81          if ($this->_event) {
  82              return $this->stats(Event::createAndTrigger(
  83                  $this->_event, $this, array($this, 'makeDefaultCacheDecision'))
  84              );
  85          }
  86  
  87          return $this->stats($this->makeDefaultCacheDecision());
  88      }
  89  
  90      /**
  91       * internal method containing cache use decision logic
  92       *
  93       * this function processes the following keys in the depends array
  94       *   purge - force a purge on any non empty value
  95       *   age   - expire cache if older than age (seconds)
  96       *   files - expire cache if any file in this array was updated more recently than the cache
  97       *
  98       * Note that this function needs to be public as it is used as callback for the event handler
  99       *
 100       * can be overridden
 101       *
 102       * @internal This method may only be called by the event handler! Call \dokuwiki\Cache\Cache::useCache instead!
 103       *
 104       * @return bool               see useCache()
 105       */
 106      public function makeDefaultCacheDecision()
 107      {
 108  
 109          if ($this->_nocache) {
 110              return false;
 111          }                              // caching turned off
 112          if (!empty($this->depends['purge'])) {
 113              return false;
 114          }              // purge requested?
 115          if (!($this->_time = @filemtime($this->cache))) {
 116              return false;
 117          }   // cache exists?
 118  
 119          // cache too old?
 120          if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) {
 121              return false;
 122          }
 123  
 124          if (!empty($this->depends['files'])) {
 125              foreach ($this->depends['files'] as $file) {
 126                  if ($this->_time <= @filemtime($file)) {
 127                      return false;
 128                  }         // cache older than files it depends on?
 129              }
 130          }
 131  
 132          return true;
 133      }
 134  
 135      /**
 136       * add dependencies to the depends array
 137       *
 138       * this method should only add dependencies,
 139       * it should not remove any existing dependencies and
 140       * it should only overwrite a dependency when the new value is more stringent than the old
 141       */
 142      protected function addDependencies()
 143      {
 144          global $INPUT;
 145          if ($INPUT->has('purge')) {
 146              $this->depends['purge'] = true;
 147          }   // purge requested
 148      }
 149  
 150      /**
 151       * retrieve the cached data
 152       *
 153       * @param   bool $clean true to clean line endings, false to leave line endings alone
 154       * @return  string          cache contents
 155       */
 156      public function retrieveCache($clean = true)
 157      {
 158          return io_readFile($this->cache, $clean);
 159      }
 160  
 161      /**
 162       * cache $data
 163       *
 164       * @param   string $data the data to be cached
 165       * @return  bool           true on success, false otherwise
 166       */
 167      public function storeCache($data)
 168      {
 169          if ($this->_nocache) {
 170              return false;
 171          }
 172  
 173          return io_savefile($this->cache, $data);
 174      }
 175  
 176      /**
 177       * remove any cached data associated with this cache instance
 178       */
 179      public function removeCache()
 180      {
 181          @unlink($this->cache);
 182      }
 183  
 184      /**
 185       * Record cache hits statistics.
 186       * (Only when debugging allowed, to reduce overhead.)
 187       *
 188       * @param    bool $success result of this cache use attempt
 189       * @return   bool              pass-thru $success value
 190       */
 191      protected function stats($success)
 192      {
 193          global $conf;
 194          static $stats = null;
 195          static $file;
 196  
 197          if (!$conf['allowdebug']) {
 198              return $success;
 199          }
 200  
 201          if (is_null($stats)) {
 202              $file = $conf['cachedir'] . '/cache_stats.txt';
 203              $lines = explode("\n", io_readFile($file));
 204  
 205              foreach ($lines as $line) {
 206                  $i = strpos($line, ',');
 207                  $stats[substr($line, 0, $i)] = $line;
 208              }
 209          }
 210  
 211          if (isset($stats[$this->ext])) {
 212              list($ext, $count, $hits) = explode(',', $stats[$this->ext]);
 213          } else {
 214              $ext = $this->ext;
 215              $count = 0;
 216              $hits = 0;
 217          }
 218  
 219          $count++;
 220          if ($success) {
 221              $hits++;
 222          }
 223          $stats[$this->ext] = "$ext,$count,$hits";
 224  
 225          io_saveFile($file, join("\n", $stats));
 226  
 227          return $success;
 228      }
 229  
 230      /**
 231       * @return bool
 232       */
 233      public function isNoCache()
 234      {
 235          return $this->_nocache;
 236      }
 237  }