~ubuntu-branches/ubuntu/karmic/dokuwiki/karmic

« back to all changes in this revision

Viewing changes to inc/cache.php

  • Committer: Bazaar Package Importer
  • Author(s): Mohammed Adnène Trojette
  • Date: 2007-03-29 19:44:52 UTC
  • mfrom: (2.1.6 feisty)
  • Revision ID: james.westby@ubuntu.com-20070329194452-8r2w798oo21ago6l
Tags: 0.0.20061106-6
* High-urgency upload for fixing RC bug.
* Make fr.po's translation of "global" consistent. (Closes: #416509)
* Remove /etc/apache*/conf.d/ on purge. (Closes: #387974)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Generic class to handle caching
 
4
 *
 
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 
6
 * @author     Chris Smith <chris@jalakai.co.uk>
 
7
 */
 
8
 
 
9
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
 
10
 
 
11
require_once(DOKU_INC.'inc/io.php');
 
12
require_once(DOKU_INC.'inc/pageutils.php');
 
13
require_once(DOKU_INC.'inc/parserutils.php');
 
14
 
 
15
class cache {
 
16
  var $key = '';          // primary identifier for this item
 
17
  var $ext = '';          // file ext for cache data, secondary identifier for this item
 
18
  var $cache = '';        // cache file name
 
19
  var $depends = array(); // array containing cache dependency information,
 
20
                          //   used by _useCache to determine cache validity
 
21
 
 
22
  var $_event = '';       // event to be triggered during useCache
 
23
 
 
24
  function cache($key,$ext) {
 
25
    $this->key = $key;
 
26
    $this->ext = $ext;
 
27
    $this->cache = getCacheName($key,$ext);
 
28
  }
 
29
 
 
30
  /**
 
31
   * public method to determine whether the cache can be used
 
32
   *
 
33
   * to assist in cetralisation of event triggering and calculation of cache statistics, 
 
34
   * don't override this function override _useCache()
 
35
   *
 
36
   * @param  array   $depends   array of cache dependencies, support dependecies:
 
37
   *                            'age'   => max age of the cache in seconds
 
38
   *                            'files' => cache must be younger than mtime of each file
 
39
   *                                       (nb. dependency passes if file doesn't exist)
 
40
   *
 
41
   * @return bool    true if cache can be used, false otherwise
 
42
   */
 
43
  function useCache($depends=array()) {
 
44
    $this->depends = $depends;
 
45
    $this->_addDependencies();
 
46
 
 
47
    if ($this->_event) {
 
48
      return $this->_stats(trigger_event($this->_event,$this,array($this,'_useCache')));
 
49
    } else {
 
50
      return $this->_stats($this->_useCache());
 
51
    }
 
52
  }
 
53
 
 
54
  /**
 
55
   * private method containing cache use decision logic
 
56
   *
 
57
   * this function processes the following keys in the depends array
 
58
   *   purge - force a purge on any non empty value
 
59
   *   age   - expire cache if older than age (seconds)
 
60
   *   files - expire cache if any file in this array was updated more recently than the cache
 
61
   *
 
62
   * can be overridden
 
63
   *
 
64
   * @return bool               see useCache()
 
65
   */
 
66
  function _useCache() {
 
67
 
 
68
    if (!empty($this->depends['purge'])) return false;              // purge requested?
 
69
    if (!($this->_time = @filemtime($this->cache))) return false;   // cache exists?
 
70
 
 
71
    // cache too old?
 
72
    if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) return false;
 
73
 
 
74
    if (!empty($this->depends['files'])) {
 
75
      foreach ($this->depends['files'] as $file) {
 
76
        if ($this->_time < @filemtime($file)) return false;         // cache older than files it depends on?
 
77
      }
 
78
    }
 
79
 
 
80
    return true;
 
81
  }
 
82
 
 
83
  /**
 
84
   * add dependencies to the depends array
 
85
   *
 
86
   * this method should only add dependencies,
 
87
   * it should not remove any existing dependencies and
 
88
   * it should only overwrite a dependency when the new value is more stringent than the old
 
89
   */
 
90
  function _addDependencies() {
 
91
    if (isset($_REQUEST['purge'])) $this->depends['purge'] = true;   // purge requested
 
92
  }
 
93
 
 
94
  /**
 
95
   * retrieve the cached data
 
96
   *
 
97
   * @param   bool   $clean   true to clean line endings, false to leave line endings alone
 
98
   * @return  string          cache contents
 
99
   */
 
100
  function retrieveCache($clean=true) {
 
101
    return io_readFile($this->cache, $clean);
 
102
  }
 
103
 
 
104
  /**
 
105
   * cache $data
 
106
   *
 
107
   * @param   string $data   the data to be cached
 
108
   * @return  none
 
109
   */
 
110
  function storeCache($data) {
 
111
    io_savefile($this->cache, $data);
 
112
  }
 
113
 
 
114
  /**
 
115
   * remove any cached data associated with this cache instance
 
116
   */
 
117
  function removeCache() {
 
118
    @unlink($this->cache);
 
119
  }
 
120
 
 
121
  /**
 
122
   * Record cache hits statistics.
 
123
   * (Only when debugging allowed, to reduce overhead.)
 
124
   *
 
125
   * @param    bool   $success   result of this cache use attempt
 
126
   * @return   bool              pass-thru $success value
 
127
   */
 
128
  function _stats($success) {
 
129
    global $conf;
 
130
    static $stats = NULL;
 
131
    static $file;
 
132
 
 
133
    if (!$conf['allowdebug']) { return $success; }
 
134
 
 
135
    if (is_null($stats)) {
 
136
      $file = $conf['cachedir'].'/cache_stats.txt';
 
137
      $lines = explode("\n",io_readFile($file));
 
138
 
 
139
      foreach ($lines as $line) {
 
140
        $i = strpos($line,',');
 
141
        $stats[substr($line,0,$i)] = $line;
 
142
      }
 
143
    }
 
144
 
 
145
    if (isset($stats[$this->ext])) {
 
146
      list($ext,$count,$hits) = explode(',',$stats[$this->ext]);
 
147
    } else {
 
148
      $ext = $this->ext;
 
149
      $count = 0;
 
150
      $hits = 0;
 
151
    }
 
152
 
 
153
    $count++;
 
154
    if ($success) $hits++;
 
155
    $stats[$this->ext] = "$ext,$count,$hits";
 
156
 
 
157
    io_saveFile($file,join("\n",$stats));
 
158
 
 
159
    return $success;
 
160
  }
 
161
}
 
162
 
 
163
class cache_parser extends cache {
 
164
 
 
165
  var $file = '';       // source file for cache
 
166
  var $mode = '';       // input mode (represents the processing the input file will undergo)
 
167
 
 
168
  var $_event = 'PARSER_CACHE_USE';
 
169
 
 
170
  function cache_parser($id, $file, $mode) {
 
171
    if ($id) $this->page = $id;
 
172
    $this->file = $file;
 
173
    $this->mode = $mode;
 
174
 
 
175
    parent::cache($file.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.'.$mode);
 
176
  }
 
177
 
 
178
  function _useCache() {
 
179
 
 
180
    if (!@file_exists($this->file)) return false;                   // source exists?
 
181
    return parent::_useCache();
 
182
  }
 
183
 
 
184
  function _addDependencies() {
 
185
    global $conf;
 
186
 
 
187
    $this->depends['age'] = isset($this->depends['age']) ? 
 
188
                   min($this->depends['age'],$conf['cachetime']) : $conf['cachetime'];
 
189
 
 
190
    // parser cache file dependencies ...
 
191
    $files = array($this->file,                                     // ... source
 
192
                   DOKU_CONF.'dokuwiki.php',                        // ... config
 
193
                   DOKU_CONF.'local.php',                           // ... local config
 
194
                   DOKU_INC.'inc/parser/parser.php',                // ... parser
 
195
                   DOKU_INC.'inc/parser/handler.php',               // ... handler
 
196
             );
 
197
 
 
198
    $this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files;
 
199
    parent::_addDependencies();
 
200
  }
 
201
 
 
202
}
 
203
 
 
204
class cache_renderer extends cache_parser {
 
205
 
 
206
  function useCache($depends=array()) {
 
207
    $use = parent::useCache($depends);
 
208
 
 
209
    // meta data needs to be kept in step with the cache
 
210
    if (!$use && isset($this->page)) {
 
211
      p_set_metadata($this->page,array(),true);
 
212
    }
 
213
 
 
214
    return $use;
 
215
  }
 
216
 
 
217
  function _useCache() {
 
218
    global $conf;
 
219
 
 
220
    if (!parent::_useCache()) return false;
 
221
 
 
222
    // for wiki pages, check metadata dependencies
 
223
    if (isset($this->page)) {
 
224
      $metadata = p_get_metadata($this->page);
 
225
 
 
226
      // check currnent link existence is consistent with cache version
 
227
      // first check the purgefile
 
228
      // - if the cache is more recent that the purgefile we know no links can have been updated
 
229
      if ($this->_time < @filemtime($conf['cachedir'].'/purgefile')) {
 
230
 
 
231
#       $links = p_get_metadata($this->page,"relation references");
 
232
        $links = $metadata['relation']['references'];
 
233
 
 
234
        if (!empty($links)) {
 
235
          foreach ($links as $id => $exists) {
 
236
            if ($exists != @file_exists(wikiFN($id,'',false))) return false;
 
237
          }
 
238
        }
 
239
      }
 
240
    }
 
241
 
 
242
    return true;
 
243
  }
 
244
 
 
245
  function _addDependencies() {
 
246
 
 
247
    // renderer cache file dependencies ...
 
248
    $files = array(
 
249
                   DOKU_INC.'inc/parser/'.$this->mode.'.php',       // ... the renderer
 
250
             );
 
251
 
 
252
    // page implies metadata and possibly some other dependencies
 
253
    if (isset($this->page)) {
 
254
 
 
255
      $metafile = metaFN($this->page,'.meta');
 
256
      if (@file_exists($metafile)) {
 
257
        $files[] = $metafile;                                       // ... the page's own metadata
 
258
        $files[] = DOKU_INC.'inc/parser/metadata.php';              // ... the metadata renderer
 
259
 
 
260
        $valid = p_get_metadata($this->page, 'date valid');
 
261
        if (!empty($valid['age'])) {
 
262
          $this->depends['age'] = isset($this->depends['age']) ?
 
263
                   min($this->depends['age'],$valid['age']) : $valid['age'];
 
264
        }
 
265
 
 
266
      } else {
 
267
        $this->depends['purge'] = true;                             // ... purging cache will generate metadata
 
268
        return;
 
269
      }
 
270
    }
 
271
 
 
272
    $this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files;
 
273
    parent::_addDependencies();
 
274
  }
 
275
}
 
276
 
 
277
class cache_instructions extends cache_parser {
 
278
 
 
279
  function cache_instructions($id, $file) {
 
280
    parent::cache_parser($id, $file, 'i');
 
281
  }
 
282
 
 
283
  function retrieveCache() {
 
284
    $contents = io_readFile($this->cache, false);
 
285
    return !empty($contents) ? unserialize($contents) : array();
 
286
  }
 
287
 
 
288
  function storeCache($instructions) {
 
289
    io_savefile($this->cache,serialize($instructions));
 
290
  }
 
291
}