root/tags/2.3.1/wp-includes/cache.php

Revision 5870, 10.3 kB (checked in by ryan, 1 year ago)

Space before slash to properly close br tag. Props tmountjr. fixes #4717

  • Property svn:eol-style set to native
Line 
1 <?php
2 function wp_cache_add($key, $data, $flag = '', $expire = 0) {
3     global $wp_object_cache;
4     $data = unserialize(serialize($data));
5
6     return $wp_object_cache->add($key, $data, $flag, $expire);
7 }
8
9 function wp_cache_close() {
10     global $wp_object_cache;
11
12     if ( ! isset($wp_object_cache) )
13         return;
14     return $wp_object_cache->save();
15 }
16
17 function wp_cache_delete($id, $flag = '') {
18     global $wp_object_cache;
19
20     return $wp_object_cache->delete($id, $flag);
21 }
22
23 function wp_cache_flush() {
24     global $wp_object_cache;
25
26     return $wp_object_cache->flush();
27 }
28
29 function wp_cache_get($id, $flag = '') {
30     global $wp_object_cache;
31
32     return $wp_object_cache->get($id, $flag);
33 }
34
35 function wp_cache_init() {
36     $GLOBALS['wp_object_cache'] =& new WP_Object_Cache();
37 }
38
39 function wp_cache_replace($key, $data, $flag = '', $expire = 0) {
40     global $wp_object_cache;
41     $data = unserialize(serialize($data));
42
43     return $wp_object_cache->replace($key, $data, $flag, $expire);
44 }
45
46 function wp_cache_set($key, $data, $flag = '', $expire = 0) {
47     global $wp_object_cache;
48     $data = unserialize(serialize($data));
49
50     return $wp_object_cache->set($key, $data, $flag, $expire);
51 }
52
53 define('CACHE_SERIAL_HEADER', "<?php\n/*");
54 define('CACHE_SERIAL_FOOTER', "*/\n?".">");
55
56 class WP_Object_Cache {
57     var $cache_dir;
58     var $cache_enabled = false;
59     var $expiration_time = 900;
60     var $flock_filename = 'wp_object_cache.lock';
61     var $mutex;
62     var $cache = array ();
63     var $dirty_objects = array ();
64     var $non_existant_objects = array ();
65     var $global_groups = array ('users', 'userlogins', 'usermeta');
66     var $non_persistent_groups = array('comment');
67     var $blog_id;
68     var $cold_cache_hits = 0;
69     var $warm_cache_hits = 0;
70     var $cache_misses = 0;
71     var $secret = '';
72
73     function acquire_lock() {
74         // Acquire a write lock.
75         $this->mutex = @fopen($this->cache_dir.$this->flock_filename, 'w');
76         if ( false == $this->mutex)
77             return false;
78         flock($this->mutex, LOCK_EX);
79         return true;
80     }
81
82     function add($id, $data, $group = 'default', $expire = '') {
83         if (empty ($group))
84             $group = 'default';
85
86         if (false !== $this->get($id, $group, false))
87             return false;
88
89         return $this->set($id, $data, $group, $expire);
90     }
91
92     function delete($id, $group = 'default', $force = false) {
93         if (empty ($group))
94             $group = 'default';
95
96         if (!$force && false === $this->get($id, $group, false))
97             return false;
98
99         unset ($this->cache[$group][$id]);
100         $this->non_existant_objects[$group][$id] = true;
101         $this->dirty_objects[$group][] = $id;
102         return true;
103     }
104
105     function flush() {
106         if ( !$this->cache_enabled )
107             return true;
108
109         if ( ! $this->acquire_lock() )
110             return false;
111
112         $this->rm_cache_dir();
113         $this->cache = array ();
114         $this->dirty_objects = array ();
115         $this->non_existant_objects = array ();
116
117         $this->release_lock();
118
119         return true;
120     }
121
122     function get($id, $group = 'default', $count_hits = true) {
123         if (empty ($group))
124             $group = 'default';
125
126         if (isset ($this->cache[$group][$id])) {
127             if ($count_hits)
128                 $this->warm_cache_hits += 1;
129             return $this->cache[$group][$id];
130         }
131
132         if (isset ($this->non_existant_objects[$group][$id]))
133             return false;
134
135         //  If caching is not enabled, we have to fall back to pulling from the DB.
136         if (!$this->cache_enabled) {
137             if (!isset ($this->cache[$group]))
138                 $this->load_group_from_db($group);
139
140             if (isset ($this->cache[$group][$id])) {
141                 $this->cold_cache_hits += 1;
142                 return $this->cache[$group][$id];
143             }
144
145             $this->non_existant_objects[$group][$id] = true;
146             $this->cache_misses += 1;
147             return false;
148         }
149
150         $cache_file = $this->cache_dir.$this->get_group_dir($group)."/".$this->hash($id).'.php';
151         if (!file_exists($cache_file)) {
152             $this->non_existant_objects[$group][$id] = true;
153             $this->cache_misses += 1;
154             return false;
155         }
156
157         // If the object has expired, remove it from the cache and return false to force
158         // a refresh.
159         $now = time();
160         if ((filemtime($cache_file) + $this->expiration_time) <= $now) {
161             $this->cache_misses += 1;
162             $this->delete($id, $group, true);
163             return false;
164         }
165
166         $this->cache[$group][$id] = unserialize(base64_decode(substr(@ file_get_contents($cache_file), strlen(CACHE_SERIAL_HEADER), -strlen(CACHE_SERIAL_FOOTER))));
167         if (false === $this->cache[$group][$id])
168             $this->cache[$group][$id] = '';
169
170         $this->cold_cache_hits += 1;
171         return $this->cache[$group][$id];
172     }
173
174     function get_group_dir($group) {
175         if (false !== array_search($group, $this->global_groups))
176             return $group;
177
178         return "{$this->blog_id}/$group";
179     }
180
181     function hash($data) {
182         if ( function_exists('hash_hmac') ) {
183             return hash_hmac('md5', $data, $this->secret);
184         } else {
185             return md5($data . $this->secret);
186         }
187     }
188
189     function load_group_from_db($group) {
190         return;
191     }
192
193     function make_group_dir($group, $perms) {
194         $group_dir = $this->get_group_dir($group);
195         $make_dir = '';
196         foreach (split('/', $group_dir) as $subdir) {
197             $make_dir .= "$subdir/";
198             if (!file_exists($this->cache_dir.$make_dir)) {
199                 if (! @ mkdir($this->cache_dir.$make_dir))
200                     break;
201                 @ chmod($this->cache_dir.$make_dir, $perms);
202             }
203
204             if (!file_exists($this->cache_dir.$make_dir."index.php")) {
205                 $file_perms = $perms & 0000666;
206                 @ touch($this->cache_dir.$make_dir."index.php");
207                 @ chmod($this->cache_dir.$make_dir."index.php", $file_perms);
208             }
209         }
210
211         return $this->cache_dir."$group_dir/";
212     }
213
214     function rm_cache_dir() {
215         $dir = $this->cache_dir;
216         $dir = rtrim($dir, DIRECTORY_SEPARATOR);
217         $top_dir = $dir;
218         $stack = array($dir);
219         $index = 0;
220
221         while ($index < count($stack)) {
222             # Get indexed directory from stack
223             $dir = $stack[$index];
224
225             $dh = @ opendir($dir);
226             if (!$dh)
227                 return false;
228
229             while (($file = @ readdir($dh)) !== false) {
230                 if ($file == '.' or $file == '..')
231                     continue;
232
233                 if (@ is_dir($dir . DIRECTORY_SEPARATOR . $file))
234                     $stack[] = $dir . DIRECTORY_SEPARATOR . $file;
235                 else if (@ is_file($dir . DIRECTORY_SEPARATOR . $file))
236                     @ unlink($dir . DIRECTORY_SEPARATOR . $file);
237             }
238
239             $index++;
240         }
241
242         $stack = array_reverse($stack);  // Last added dirs are deepest
243         foreach($stack as $dir) {
244             if ( $dir != $top_dir)
245                 @ rmdir($dir);
246         }
247
248     }
249
250     function release_lock() {
251         // Release write lock.
252         flock($this->mutex, LOCK_UN);
253         fclose($this->mutex);
254     }
255
256     function replace($id, $data, $group = 'default', $expire = '') {
257         if (empty ($group))
258             $group = 'default';
259
260         if (false === $this->get($id, $group, false))
261             return false;
262
263         return $this->set($id, $data, $group, $expire);
264     }
265
266     function set($id, $data, $group = 'default', $expire = '') {
267         if (empty ($group))
268             $group = 'default';
269
270         if (NULL == $data)
271             $data = '';
272
273         $this->cache[$group][$id] = $data;
274         unset ($this->non_existant_objects[$group][$id]);
275         $this->dirty_objects[$group][] = $id;
276
277         return true;
278     }
279
280     function save() {
281         //$this->stats();
282
283         if (!$this->cache_enabled)
284             return true;
285
286         if (empty ($this->dirty_objects))
287             return true;
288
289         // Give the new dirs the same perms as wp-content.
290         $stat = stat(ABSPATH.'wp-content');
291         $dir_perms = $stat['mode'] & 0007777; // Get the permission bits.
292         $file_perms = $dir_perms & 0000666; // Remove execute bits for files.
293
294         // Make the base cache dir.
295         if (!file_exists($this->cache_dir)) {
296             if (! @ mkdir($this->cache_dir))
297                 return false;
298             @ chmod($this->cache_dir, $dir_perms);
299         }
300
301         if (!file_exists($this->cache_dir."index.php")) {
302             @ touch($this->cache_dir."index.php");
303             @ chmod($this->cache_dir."index.php", $file_perms);
304         }
305
306         if ( ! $this->acquire_lock() )
307             return false;
308
309         // Loop over dirty objects and save them.
310         $errors = 0;
311         foreach ($this->dirty_objects as $group => $ids) {
312             if ( in_array($group, $this->non_persistent_groups) )
313                 continue;
314
315             $group_dir = $this->make_group_dir($group, $dir_perms);
316
317             $ids = array_unique($ids);
318             foreach ($ids as $id) {
319                 $cache_file = $group_dir.$this->hash($id).'.php';
320
321                 // Remove the cache file if the key is not set.
322                 if (!isset ($this->cache[$group][$id])) {
323                     if (file_exists($cache_file))
324                         @ unlink($cache_file);
325                     continue;
326                 }
327
328                 $temp_file = tempnam($group_dir, 'tmp');
329                 $serial = CACHE_SERIAL_HEADER.base64_encode(serialize($this->cache[$group][$id])).CACHE_SERIAL_FOOTER;
330                 $fd = @fopen($temp_file, 'w');
331                 if ( false === $fd ) {
332                     $errors++;
333                     continue;
334                 }
335                 fputs($fd, $serial);
336                 fclose($fd);
337                 if (!@ rename($temp_file, $cache_file)) {
338                     if (!@ copy($temp_file, $cache_file))
339                         $errors++;
340                     @ unlink($temp_file);
341                 }
342                 @ chmod($cache_file, $file_perms);
343             }
344         }
345
346         $this->dirty_objects = array();
347
348         $this->release_lock();
349
350         if ( $errors )
351             return false;
352
353         return true;
354     }
355
356     function stats() {
357         echo "<p>";
358         echo "<strong>Cold Cache Hits:</strong> {$this->cold_cache_hits}<br />";
359         echo "<strong>Warm Cache Hits:</strong> {$this->warm_cache_hits}<br />";
360         echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
361         echo "</p>";
362
363         foreach ($this->cache as $group => $cache) {
364             echo "<p>";
365             echo "<strong>Group:</strong> $group<br />";
366             echo "<strong>Cache:</strong>";
367             echo "<pre>";
368             print_r($cache);
369             echo "</pre>";
370             if (isset ($this->dirty_objects[$group])) {
371                 echo "<strong>Dirty Objects:</strong>";
372                 echo "<pre>";
373                 print_r(array_unique($this->dirty_objects[$group]));
374                 echo "</pre>";
375                 echo "</p>";
376             }
377         }
378     }
379
380     function WP_Object_Cache() {
381         return $this->__construct();
382     }
383
384     function __construct() {
385         global $blog_id;
386
387         register_shutdown_function(array(&$this, "__destruct"));
388
389         if (defined('DISABLE_CACHE'))
390             return;
391
392         if ( ! defined('ENABLE_CACHE') )
393             return;
394
395         // Disable the persistent cache if safe_mode is on.
396         if ( ini_get('safe_mode') && ! defined('ENABLE_CACHE') )
397             return;
398
399         if (defined('CACHE_PATH'))
400             $this->cache_dir = CACHE_PATH;
401         else
402             // Using the correct separator eliminates some cache flush errors on Windows
403             $this->cache_dir = ABSPATH.'wp-content'.DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR;
404
405         if (is_writable($this->cache_dir) && is_dir($this->cache_dir)) {
406                 $this->cache_enabled = true;
407         } else {
408             if (is_writable(ABSPATH.'wp-content')) {
409                 $this->cache_enabled = true;
410             }
411         }
412
413         if (defined('CACHE_EXPIRATION_TIME'))
414             $this->expiration_time = CACHE_EXPIRATION_TIME;
415
416         if ( defined('WP_SECRET') )
417             $this->secret = WP_SECRET;
418         else
419             $this->secret = DB_PASSWORD . DB_USER . DB_NAME . DB_HOST . ABSPATH;
420
421         $this->blog_id = $this->hash($blog_id);
422     }
423
424     function __destruct() {
425         $this->save();
426         return true;
427     }
428 }
429 ?>
430
Note: See TracBrowser for help on using the browser.