Failed Conditions
Push — psr2 ( e24a74...d8b492 )
by Andreas
03:19
created

inc/Cache/Cache.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace dokuwiki\Cache;
4
5
use \dokuwiki\Debug\PropertyDeprecationHelper;
6
7
/**
8
 * Generic handling of caching
9
 */
10
class Cache
11
{
12
    use PropertyDeprecationHelper;
13
14
    public $key = '';          // primary identifier for this item
15
    public $ext = '';          // file ext for cache data, secondary identifier for this item
16
    public $cache = '';        // cache file name
17
    public $depends = array(); // array containing cache dependency information,
18
    //   used by makeDefaultCacheDecision to determine cache validity
19
20
    // phpcs:disable
21
    /**
22
     * @deprecated since 2019-02-02 use the respective getters instead!
23
     */
24
    protected $_event = '';       // event to be triggered during useCache
25
    protected $_time;
26
    protected $_nocache = false;  // if set to true, cache will not be used or stored
27
    // phpcs:enable
28
29
    /**
30
     * @param string $key primary identifier
31
     * @param string $ext file extension
32
     */
33
    public function __construct($key, $ext)
34
    {
35
        $this->key = $key;
36
        $this->ext = $ext;
37
        $this->cache = getCacheName($key, $ext);
38
39
        /**
40
         * @deprecated since 2019-02-02 use the respective getters instead!
41
         */
42
        $this->deprecatePublicProperty('_event');
43
        $this->deprecatePublicProperty('_time');
44
        $this->deprecatePublicProperty('_nocache');
45
    }
46
47
    public function getTime()
48
    {
49
        return $this->_time;
50
    }
51
52
    public function getEvent()
53
    {
54
        return $this->_event;
0 ignored issues
show
Deprecated Code introduced by
The property dokuwiki\Cache\Cache::$_event has been deprecated with message: since 2019-02-02 use the respective getters instead!

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
55
    }
56
57
    public function setEvent($_event)
58
    {
59
        $this->_event = $_event;
0 ignored issues
show
Deprecated Code introduced by
The property dokuwiki\Cache\Cache::$_event has been deprecated with message: since 2019-02-02 use the respective getters instead!

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
60
    }
61
62
    /**
63
     * public method to determine whether the cache can be used
64
     *
65
     * to assist in centralisation of event triggering and calculation of cache statistics,
66
     * don't override this function override makeDefaultCacheDecision()
67
     *
68
     * @param  array $depends array of cache dependencies, support dependecies:
69
     *                            'age'   => max age of the cache in seconds
70
     *                            'files' => cache must be younger than mtime of each file
71
     *                                       (nb. dependency passes if file doesn't exist)
72
     *
73
     * @return bool    true if cache can be used, false otherwise
74
     */
75
    public function useCache($depends = array())
76
    {
77
        $this->depends = $depends;
78
        $this->addDependencies();
79
80
        if ($this->_event) {
0 ignored issues
show
Deprecated Code introduced by
The property dokuwiki\Cache\Cache::$_event has been deprecated with message: since 2019-02-02 use the respective getters instead!

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
81
            return $this->stats(trigger_event($this->_event, $this, array($this, 'makeDefaultCacheDecision')));
0 ignored issues
show
Deprecated Code introduced by
The property dokuwiki\Cache\Cache::$_event has been deprecated with message: since 2019-02-02 use the respective getters instead!

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

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