[ 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 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 = [])
  77      {
  78          $this->depends = $depends;
  79          $this->addDependencies();
  80  
  81          if ($this->getEvent()) {
  82              return $this->stats(
  83                  Event::createAndTrigger(
  84                      $this->getEvent(),
  85                      $this,
  86                      [$this, 'makeDefaultCacheDecision']
  87                  )
  88              );
  89          }
  90  
  91          return $this->stats($this->makeDefaultCacheDecision());
  92      }
  93  
  94      /**
  95       * internal method containing cache use decision logic
  96       *
  97       * this function processes the following keys in the depends array
  98       *   purge - force a purge on any non empty value
  99       *   age   - expire cache if older than age (seconds)
 100       *   files - expire cache if any file in this array was updated more recently than the cache
 101       *
 102       * Note that this function needs to be public as it is used as callback for the event handler
 103       *
 104       * can be overridden
 105       *
 106       * @internal This method may only be called by the event handler! Call \dokuwiki\Cache\Cache::useCache instead!
 107       *
 108       * @return bool               see useCache()
 109       */
 110      public function makeDefaultCacheDecision()
 111      {
 112          if ($this->_nocache) {
 113              return false;
 114          }                              // caching turned off
 115          if (!empty($this->depends['purge'])) {
 116              return false;
 117          }              // purge requested?
 118          if (!($this->_time = @filemtime($this->cache))) {
 119              return false;
 120          }   // cache exists?
 121  
 122          // cache too old?
 123          if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) {
 124              return false;
 125          }
 126  
 127          if (!empty($this->depends['files'])) {
 128              foreach ($this->depends['files'] as $file) {
 129                  if ($this->_time <= @filemtime($file)) {
 130                      return false;
 131                  }         // cache older than files it depends on?
 132              }
 133          }
 134  
 135          return true;
 136      }
 137  
 138      /**
 139       * add dependencies to the depends array
 140       *
 141       * this method should only add dependencies,
 142       * it should not remove any existing dependencies and
 143       * it should only overwrite a dependency when the new value is more stringent than the old
 144       */
 145      protected function addDependencies()
 146      {
 147          global $INPUT;
 148          if ($INPUT->has('purge')) {
 149              $this->depends['purge'] = true;
 150          }   // purge requested
 151      }
 152  
 153      /**
 154       * retrieve the cached data
 155       *
 156       * @param   bool $clean true to clean line endings, false to leave line endings alone
 157       * @return  string          cache contents
 158       */
 159      public function retrieveCache($clean = true)
 160      {
 161          return io_readFile($this->cache, $clean);
 162      }
 163  
 164      /**
 165       * cache $data
 166       *
 167       * @param   string $data the data to be cached
 168       * @return  bool           true on success, false otherwise
 169       */
 170      public function storeCache($data)
 171      {
 172          if ($this->_nocache) {
 173              return false;
 174          }
 175  
 176          return io_saveFile($this->cache, $data);
 177      }
 178  
 179      /**
 180       * remove any cached data associated with this cache instance
 181       */
 182      public function removeCache()
 183      {
 184          @unlink($this->cache);
 185      }
 186  
 187      /**
 188       * Record cache hits statistics.
 189       * (Only when debugging allowed, to reduce overhead.)
 190       *
 191       * @param    bool $success result of this cache use attempt
 192       * @return   bool              pass-thru $success value
 193       */
 194      protected function stats($success)
 195      {
 196          global $conf;
 197          static $stats = null;
 198          static $file;
 199  
 200          if (!$conf['allowdebug']) {
 201              return $success;
 202          }
 203  
 204          if (is_null($stats)) {
 205              $file = $conf['cachedir'] . '/cache_stats.txt';
 206              $lines = explode("\n", io_readFile($file));
 207  
 208              foreach ($lines as $line) {
 209                  $i = strpos($line, ',');
 210                  $stats[substr($line, 0, $i)] = $line;
 211              }
 212          }
 213  
 214          if (isset($stats[$this->ext])) {
 215              [$ext, $count, $hits] = explode(',', $stats[$this->ext]);
 216          } else {
 217              $ext = $this->ext;
 218              $count = 0;
 219              $hits = 0;
 220          }
 221  
 222          $count++;
 223          if ($success) {
 224              $hits++;
 225          }
 226          $stats[$this->ext] = "$ext,$count,$hits";
 227  
 228          io_saveFile($file, implode("\n", $stats));
 229  
 230          return $success;
 231      }
 232  
 233      /**
 234       * @return bool
 235       */
 236      public function isNoCache()
 237      {
 238          return $this->_nocache;
 239      }
 240  }