PluginProbe
Docket Cache – Object Cache Accelerator / trunk
Docket Cache – Object Cache Accelerator vtrunk
26.04.05 trunk 22.07.01 22.07.02 22.07.03 22.07.04 22.07.05 23.08.01 23.08.02 24.07.01 24.07.02 24.07.03 24.07.04 24.07.05 24.07.06 24.07.07 26.04.03 26.04.04
docket-cache / includes / cache.php

cache.php in Docket Cache – Object Cache Accelerator trunk, at includes/cache.php

2,447 lines 69.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Docket Cache.
4 *
5 * @author Nawawi Jamili
6 * @license MIT
7 *
8 * @see https://github.com/nawawi/docket-cache
9 */
10 \defined('ABSPATH') || exit;
11
12 /*
13 * Reference:
14 * wp-includes/class-wp-object-cache.php
15 * wp-includes/cache.php
16 */
17
18 /**
19 * Core class that implements an object cache.
20 */
21 #[AllowDynamicProperties]
22 class WP_Object_Cache
23 {
24 /**
25 * Holds the cached objects.
26 *
27 * @var array
28 */
29 private $cache = [];
30
31 /**
32 * The amount of times the cache data was already stored in the cache.
33 *
34 * @var int
35 */
36 public $cache_hits = 0;
37
38 /**
39 * Amount of times the cache did not have the request in cache.
40 *
41 * @var int
42 */
43 public $cache_misses = 0;
44
45 /**
46 * The amount of times the cached data was fetched from the cache file.
47 *
48 * @var int
49 */
50 public $persistent_cache_hits = 0;
51
52 /**
53 * List of global cache groups.
54 *
55 * @var array
56 */
57 protected $global_groups = [];
58
59 /**
60 * List of non persistent groups.
61 *
62 * @var array
63 */
64 protected $non_persistent_groups = [];
65
66 /**
67 * List of non persistent keys.
68 *
69 * @var array
70 */
71 protected $non_persistent_keys = [];
72
73 /**
74 * List of non persistent group:key.
75 *
76 * @var array
77 */
78 protected $non_persistent_groupkey = [];
79
80 /**
81 * List of group:key exclude from pecaching.
82 *
83 * @var array
84 */
85 private $bypass_precache = [];
86
87 /**
88 * The blog prefix to prepend to keys in non-global groups.
89 *
90 * @var string
91 */
92 private $blog_prefix;
93
94 /**
95 * Holds the value of is_multisite().
96 *
97 * @var bool
98 */
99 private $multisite;
100
101 /**
102 * Holds the value of Network Id.
103 *
104 * @var bool
105 */
106 private $network_id = 1;
107
108 /**
109 * The cache path.
110 *
111 * @var string
112 */
113 private $cache_path;
114
115 /**
116 * The cache maximum size of cache file.
117 *
118 * @var int
119 */
120 private $cache_maxsize = 3145728;
121
122 /**
123 * The cache file lifespan.
124 *
125 * @var int
126 */
127 private $cache_maxttl = 345600;
128
129 /**
130 * List of filtered groups.
131 *
132 * @var array
133 */
134 private $filtered_groups = false;
135
136 /**
137 * Show signature.
138 *
139 * @var bool
140 */
141 private $add_signature;
142
143 /**
144 * List of caches to preload.
145 *
146 * @var array
147 */
148 public $precache = [];
149
150 /**
151 * List of loaded keys.
152 *
153 * @var array
154 */
155 public $precache_loaded = [];
156
157 /**
158 * Precache status.
159 *
160 * @var bool
161 */
162 private $is_precache = false;
163
164 /**
165 * Precache key.
166 *
167 * @var string
168 */
169 private $precache_hashkey = '';
170
171 /**
172 * Precache max keys.
173 *
174 * @var int
175 */
176 private $precache_maxkey = 20;
177
178 /**
179 * Precache max groups.
180 *
181 * @var int
182 */
183 private $precache_maxgroup = 20;
184
185 /**
186 * Precache max cache file (url).
187 *
188 * @var int
189 */
190 private $precache_maxfile = 100;
191
192 /**
193 * Maximum cache file.
194 *
195 * @var int
196 */
197 private $maxfile = 50000;
198
199 /**
200 * Check cache file limit in real-time.
201 *
202 * @var bool
203 */
204 private $maxfile_livecheck = true;
205
206 /**
207 * The maximum time in seconds a script is allowed to run.
208 *
209 * @var int
210 */
211 private $max_execution_time = 0;
212
213 /**
214 * Start of run timestamp.
215 *
216 * @var int
217 */
218 private $wp_start_timestamp = 0;
219
220 /**
221 * Dev mode.
222 *
223 * @var bool
224 */
225 private $is_dev = false;
226
227 /**
228 * Ignore stale cache.
229 *
230 * @var bool
231 */
232 private $ignore_stalecache = false;
233
234 /**
235 * Ignore empty cache.
236 *
237 * @var bool
238 */
239 private $ignore_emptycache = false;
240
241 /**
242 * Store Transients in DB.
243 *
244 * @var bool
245 */
246 private $use_transientdb = false;
247
248 /**
249 * List of transient exclude from store in DB.
250 *
251 * @var array
252 */
253 private $bypass_transientdb = [];
254
255 /**
256 * Sets up object properties.
257 */
258 public function __construct()
259 {
260 $this->multisite = \function_exists('is_multisite') && is_multisite();
261 $this->blog_prefix = $this->switch_to_blog(get_current_blog_id());
262 $this->network_id = (int) nwdcx_network_id();
263 $this->dc_init();
264 }
265
266 /**
267 * Makes private properties readable for backward compatibility.
268 *
269 * @since 4.0.0
270 *
271 * @param string $name property to get
272 *
273 * @return mixed property
274 */
275 public function __get($name)
276 {
277 return $this->$name;
278 }
279
280 /**
281 * Makes private properties settable for backward compatibility.
282 *
283 * @since 4.0.0
284 *
285 * @param string $name property to set
286 * @param mixed $value property value
287 *
288 * @return mixed newly-set property
289 */
290 public function __set($name, $value)
291 {
292 return $this->$name = $value;
293 }
294
295 /**
296 * Makes private properties checkable for backward compatibility.
297 *
298 * @since 4.0.0
299 *
300 * @param string $name property to check if set
301 *
302 * @return bool whether the property is set
303 */
304 public function __isset($name)
305 {
306 return isset($this->$name);
307 }
308
309 /**
310 * Makes private properties un-settable for backward compatibility.
311 *
312 * @since 4.0.0
313 *
314 * @param string $name property to unset
315 */
316 public function __unset($name)
317 {
318 unset($this->$name);
319 }
320
321 /**
322 * Serves as a utility function to determine whether a key exists in the cache.
323 *
324 * @param int|string $key cache key to check for existence
325 * @param string $group cache group for the key existence check
326 *
327 * @return bool whether the key exists in the cache for the given group
328 */
329 protected function _exists($key, $group, $force = false)
330 {
331 // check key
332 if (!$this->is_valid_key($key)) {
333 return false;
334 }
335
336 // check group
337 if (!\is_string($group)) {
338 // unset junk
339 unset($this->cache[$group]);
340 unset($this->precache[$group]);
341
342 return false;
343 }
344
345 $is_exists = !$force && !empty($this->cache) && isset($this->cache[$group]) && (isset($this->cache[$group][$key]) || \array_key_exists($key, $this->cache[$group]));
346
347 if (!$is_exists && !$this->is_non_persistent_groups($group) && !$this->is_non_persistent_keys($key) && !$this->is_non_persistent_groupkey($group, $key) && !$this->is_stalecache_ignored($key, $group)) {
348 $data = $this->dc_get($key, $group, false, $codestub_false);
349 if (false !== $data) {
350 $is_exists = true;
351 $this->cache[$group][$key] = $data;
352
353 if ($this->is_precache && !$codestub_false && !$this->fs()->suspend_cache_write() && !$this->is_bypass_precache($group, $key)) {
354 if (empty($this->precache[$group])) {
355 $this->precache[$group][$key] = 1;
356 } elseif (\count($this->precache[$group]) < $this->precache_maxkey && \count($this->precache) < $this->precache_maxgroup) {
357 $this->precache[$group][$key] = 1;
358 }
359 }
360 }
361 }
362
363 return $is_exists;
364 }
365
366 /**
367 * Adds data to the cache if it doesn't already exist.
368 *
369 * @uses WP_Object_Cache::_exists() Checks to see if the cache already has data.
370 * @uses WP_Object_Cache::set() Sets the data after the checking the cache
371 * contents existence.
372 *
373 * @param int|string $key what to call the contents in the cache
374 * @param mixed $data the contents to store in the cache
375 * @param string $group Optional. Where to group the cache contents. Default 'default'.
376 * @param int $expire Optional. When to expire the cache contents. Default 0 (no expiration).
377 *
378 * @return bool true on success, false if cache key and group already exist
379 */
380 public function add($key, $data, $group = 'default', $expire = 0)
381 {
382 if (wp_suspend_cache_addition()) {
383 return false;
384 }
385
386 if (!$this->is_valid_key($key)) {
387 return false;
388 }
389
390 if (empty($group)) {
391 $group = 'default';
392 }
393
394 $cache_key = $this->dc_key($key, $group);
395 if ($this->_exists($cache_key, $group)) {
396 return false;
397 }
398
399 return $this->set($key, $data, $group, (int) $expire);
400 }
401
402 /**
403 * Adds multiple values to the cache in one call.
404 *
405 * @param array $data array of keys and values to be added
406 * @param string $group Optional. Where the cache contents are grouped. Default empty.
407 * @param int $expire Optional. When to expire the cache contents, in seconds.
408 * Default 0 (no expiration).
409 *
410 * @return bool[] Array of return values, grouped by key. Each value is either
411 * true on success, or false if cache key and group already exist.
412 */
413 public function add_multiple(array $data, $group = '', $expire = 0)
414 {
415 $values = [];
416
417 foreach ($data as $key => $value) {
418 $values[$key] = $this->add($key, $value, $group, $expire);
419 }
420
421 return $values;
422 }
423
424 /**
425 * Replaces the contents in the cache, if contents already exist.
426 *
427 * @see WP_Object_Cache::set()
428 *
429 * @param int|string $key what to call the contents in the cache
430 * @param mixed $data the contents to store in the cache
431 * @param string $group Optional. Where to group the cache contents. Default 'default'.
432 * @param int $expire Optional. When to expire the cache contents. Default 0 (no expiration).
433 *
434 * @return bool false if not exists, true if contents were replaced
435 */
436 public function replace($key, $data, $group = 'default', $expire = 0)
437 {
438 if (!$this->is_valid_key($key)) {
439 return false;
440 }
441
442 if (empty($group)) {
443 $group = 'default';
444 }
445
446 $cache_key = $this->dc_key($key, $group);
447
448 if (!$this->_exists($cache_key, $group)) {
449 return false;
450 }
451
452 return $this->set($key, $data, $group, (int) $expire);
453 }
454
455 /**
456 * Sets the data contents into the cache.
457 *
458 * The cache contents are grouped by the $group parameter followed by the
459 * $key. This allows for duplicate ids in unique groups. Therefore, naming of
460 * the group should be used with care and should follow normal function
461 * naming guidelines outside of core WordPress usage.
462 *
463 * @param int|string $key what to call the contents in the cache
464 * @param mixed $data the contents to store in the cache
465 * @param string $group Optional. Where to group the cache contents. Default 'default'.
466 * @param int $expire the expiration time, defaults to 0
467 *
468 * @return true always returns true
469 */
470 public function set($key, $data, $group = 'default', $expire = 0)
471 {
472 if (!$this->is_valid_key($key)) {
473 return false;
474 }
475
476 if (empty($group)) {
477 $group = 'default';
478 }
479
480 $cache_key = $this->dc_key($key, $group);
481
482 if (\is_object($data)) {
483 $data = clone $data;
484 }
485
486 $this->cache[$group][$cache_key] = $data;
487
488 // suspend new cache
489 if ($this->fs()->suspend_cache_write() && !is_file($this->get_file_path($cache_key, $group))) {
490 return true;
491 }
492
493 if ((!$this->is_non_persistent_groups($group) && !$this->is_non_persistent_keys($key) && !$this->is_non_persistent_groupkey($group, $key) && !$this->is_stalecache_ignored($key, $group)) || $this->is_filtered_groups($group, $key)) {
494 $expire = $this->maybe_expire($group, $expire, $key);
495 $this->dc_save($cache_key, $this->cache[$group][$cache_key], $group, $expire, $key);
496 }
497
498 return true;
499 }
500
501 /**
502 * Sets multiple values to the cache in one call.
503 *
504 * @param array $data array of key and value to be set
505 * @param string $group Optional. Where the cache contents are grouped. Default empty.
506 * @param int $expire Optional. When to expire the cache contents, in seconds.
507 * Default 0 (no expiration).
508 *
509 * @return bool[] Array of return values, grouped by key. Each value is always true.
510 */
511 public function set_multiple(array $data, $group = '', $expire = 0)
512 {
513 $values = [];
514
515 foreach ($data as $key => $value) {
516 $values[$key] = $this->set($key, $value, $group, $expire);
517 }
518
519 return $values;
520 }
521
522 /**
523 * Retrieves the cache contents, if it exists.
524 *
525 * The contents will be first attempted to be retrieved by searching by the
526 * key in the cache group. If the cache is hit (success) then the contents
527 * are returned.
528 *
529 * On failure, the number of cache misses will be incremented.
530 *
531 * @param int|string $key what the contents in the cache are called
532 * @param string $group Optional. Where the cache contents are grouped. Default 'default'.
533 * @param bool $force Optional. Unused. Whether to force a refetch rather than relying on the local
534 * cache. Default false.
535 * @param bool $found Optional. Whether the key was found in the cache (passed by reference).
536 * Disambiguates a return of false, a storable value. Default null.
537 *
538 * @return mixed|false the cache contents on success, false on failure to retrieve contents
539 */
540 public function get($key, $group = 'default', $force = false, &$found = null, $doing_precache = false)
541 {
542 if (!$this->is_valid_key($key)) {
543 return false;
544 }
545
546 if (empty($group)) {
547 $group = 'default';
548 }
549
550 $cache_key = $this->dc_key($key, $group);
551
552 if ($this->_exists($cache_key, $group, $force)) {
553 if (!$doing_precache) {
554 ++$this->cache_hits;
555 }
556 $found = true;
557 if (\is_object($this->cache[$group][$cache_key])) {
558 return clone $this->cache[$group][$cache_key];
559 }
560
561 return $this->cache[$group][$cache_key];
562 }
563
564 $found = false;
565 if (!$doing_precache) {
566 ++$this->cache_misses;
567 }
568
569 return false;
570 }
571
572 /**
573 * Retrieves multiple values from the cache in one call.
574 *
575 * @param array $keys array of keys under which the cache contents are stored
576 * @param string $group Optional. Where the cache contents are grouped. Default 'default'.
577 * @param bool $force Optional. Whether to force an update of the local cache
578 * from the persistent cache. Default false.
579 *
580 * @return array array of values organized into groups
581 */
582 public function get_multiple($keys, $group = 'default', $force = false)
583 {
584 $values = [];
585 if (!empty($keys) && \is_array($keys)) {
586 foreach ($keys as $key) {
587 $values[$key] = $this->get($key, $group, $force);
588 }
589 }
590
591 return $values;
592 }
593
594 /**
595 * Removes the contents of the cache key in the group.
596 *
597 * If the cache key does not exist in the group, then nothing will happen.
598 *
599 * @param int|string $key what the contents in the cache are called
600 * @param string $group Optional. Where the cache contents are grouped. Default 'default'.
601 * @param bool $deprecated Optional. Unused. Default false.
602 *
603 * @return bool false if the contents weren't deleted and true on success
604 */
605 public function delete($key, $group = 'default', $deprecated = false)
606 {
607 if (!$this->is_valid_key($key)) {
608 return false;
609 }
610
611 if (empty($group)) {
612 $group = 'default';
613 }
614
615 $key = $this->dc_key($key, $group);
616
617 unset($this->cache[$group][$key]);
618 unset($this->precache[$group][$key]);
619
620 return $this->dc_remove($key, $group);
621 }
622
623 /**
624 * Deletes multiple values from the cache in one call.
625 *
626 * @param array $keys array of keys to be deleted
627 * @param string $group Optional. Where the cache contents are grouped. Default empty.
628 *
629 * @return bool[] Array of return values, grouped by key. Each value is either
630 * true on success, or false if the contents were not deleted.
631 */
632 public function delete_multiple(array $keys, $group = '')
633 {
634 $values = [];
635
636 foreach ($keys as $key) {
637 $values[$key] = $this->delete($key, $group);
638 }
639
640 return $values;
641 }
642
643 /**
644 * Increments numeric cache item's value.
645 *
646 * @param int|string $key The cache key to increment
647 * @param int $offset Optional. The amount by which to increment the item's value. Default 1.
648 * @param string $group Optional. The group the key is in. Default 'default'.
649 *
650 * @return int|false the item's new value on success, false on failure
651 */
652 public function incr($key, $offset = 1, $group = 'default')
653 {
654 if (!$this->is_valid_key($key)) {
655 return false;
656 }
657
658 if (empty($group)) {
659 $group = 'default';
660 }
661
662 $cache_key = $this->dc_key($key, $group);
663
664 if (!$this->_exists($cache_key, $group)) {
665 return false;
666 }
667
668 if (!is_numeric($this->cache[$group][$cache_key])) {
669 $this->cache[$group][$cache_key] = 0;
670 }
671
672 $offset = (int) $offset;
673
674 $this->cache[$group][$cache_key] += $offset;
675
676 if ($this->cache[$group][$cache_key] < 0) {
677 $this->cache[$group][$cache_key] = 0;
678 }
679
680 $this->dc_update($cache_key, $this->cache[$group][$cache_key], $group);
681
682 return $this->cache[$group][$cache_key];
683 }
684
685 /**
686 * Decrements numeric cache item's value.
687 *
688 * @param int|string $key the cache key to decrement
689 * @param int $offset Optional. The amount by which to decrement the item's value. Default 1.
690 * @param string $group Optional. The group the key is in. Default 'default'.
691 *
692 * @return int|false the item's new value on success, false on failure
693 */
694 public function decr($key, $offset = 1, $group = 'default')
695 {
696 if (!$this->is_valid_key($key)) {
697 return false;
698 }
699
700 if (empty($group)) {
701 $group = 'default';
702 }
703
704 $cache_key = $this->dc_key($key, $group);
705
706 if (!$this->_exists($cache_key, $group)) {
707 return false;
708 }
709
710 if (!is_numeric($this->cache[$group][$cache_key])) {
711 $this->cache[$group][$cache_key] = 0;
712 }
713
714 $offset = (int) $offset;
715
716 $this->cache[$group][$cache_key] -= $offset;
717
718 if ($this->cache[$group][$cache_key] < 0) {
719 $this->cache[$group][$cache_key] = 0;
720 }
721
722 $this->dc_update($cache_key, $this->cache[$group][$cache_key], $group);
723
724 return $this->cache[$group][$cache_key];
725 }
726
727 /**
728 * Clears the object cache of all data.
729 *
730 * @param bool $is_runtime Optional. Only removes cache items from the in-memory runtime cache.
731 *
732 * @return bool true on success, false on failure
733 */
734 public function flush($is_runtime = false)
735 {
736 $this->cache = [];
737 $this->precache = [];
738 $this->precache_loaded = [];
739
740 return $is_runtime ? true : $this->dc_flush();
741 }
742
743 /**
744 * Sets the list of global cache groups.
745 *
746 * @param array $groups list of groups that are global
747 */
748 public function add_global_groups($groups)
749 {
750 $groups = (array) $groups;
751
752 $groups = array_fill_keys($groups, true);
753 $this->global_groups = array_merge($this->global_groups, $groups);
754 }
755
756 /**
757 * Switches the internal blog ID.
758 *
759 * This changes the blog ID used to create keys in blog specific groups.
760 *
761 * @param int $blog_id blog ID
762 */
763 public function switch_to_blog($blog_id)
764 {
765 $blog_id = (int) $blog_id;
766 $this->blog_prefix = $this->multisite ? $blog_id.':' : '';
767 }
768
769 /**
770 * Echoes the stats of the caching.
771 *
772 * Gives the cache hits, and cache misses. Also prints every cached group,
773 * key and the data.
774 */
775 public function stats()
776 {
777 $ret = '';
778 $ret .= '<p>';
779 $ret .= "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
780 $ret .= "<strong>Persistent Cache Hits:</strong> {$this->persistent_cache_hits}<br />";
781 $ret .= "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
782 $ret .= '</p>';
783 $ret .= '<ul>';
784 $total = 0;
785
786 foreach ($this->cache as $group => $cache) {
787 $ret .= '<li><strong>Group:</strong> '.esc_html($group).' - ( '.number_format(\strlen(serialize($cache)) / KB_IN_BYTES, 2).'K )</li>';
788 $total += \strlen(serialize($cache));
789 }
790
791 $ret .= '</ul>';
792 $ret .= '<p>total: '.number_format($total / KB_IN_BYTES).'</p>';
793 echo $ret;
794 }
795
796 /**
797 * Sets the list of non persistent groups.
798 *
799 * @param array $groups list of groups that are to be ignored
800 */
801 public function add_non_persistent_groups($groups)
802 {
803 $groups = (array) $groups;
804
805 $groups = array_fill_keys($groups, true);
806 $this->non_persistent_groups = array_merge($this->non_persistent_groups, $groups);
807 }
808
809 /**
810 * Check if group in non persistent groups.
811 *
812 * @param bool $group cache group
813 */
814 protected function is_non_persistent_groups($group)
815 {
816 return !empty($this->non_persistent_groups) && \array_key_exists($group, $this->non_persistent_groups);
817 }
818
819 /**
820 * Sets the list of non persistent keys.
821 *
822 * @param array $keys list of keys that are to be ignored
823 */
824 public function add_non_persistent_keys($keys)
825 {
826 $keys = (array) $keys;
827
828 $keys = array_fill_keys($keys, true);
829 $this->non_persistent_keys = array_merge($this->non_persistent_keys, $keys);
830 }
831
832 /**
833 * Check if key in non persistent keys.
834 *
835 * @param bool $key cache key
836 */
837 protected function is_non_persistent_keys($key)
838 {
839 return !empty($this->non_persistent_keys) && \array_key_exists($key, $this->non_persistent_keys);
840 }
841
842 /**
843 * Check if key in non persistent index.
844 *
845 * @param bool $group cache group
846 * @param bool $key cache key
847 */
848 protected function is_non_persistent_groupkey($group, $key)
849 {
850 if (!empty($this->non_persistent_groupkey) && !empty($this->non_persistent_groupkey[$group])) {
851 $bypass_data = $this->non_persistent_groupkey[$group];
852
853 if (\is_array($bypass_data)) {
854 return false !== array_search($key, $bypass_data);
855 }
856
857 if ($key === $bypass_data) {
858 return true;
859 }
860 }
861
862 return false;
863 }
864
865 /**
866 * Bypass preache.
867 *
868 * @param bool $group cache group
869 * @param bool $key cache key
870 */
871 private function is_bypass_precache($group, $key)
872 {
873 if ($this->fs()->is_docketcachegroup($group, $key) || $this->fs()->is_transient($group) || $this->has_stalecache($key, $group)) {
874 return true;
875 }
876
877 if ('gbmedia-cpttables' === $group || 'doing_cron' === $key || preg_match('@^(\d+|[0-9a-f]{32})$@', $key)) {
878 return true;
879 }
880
881 if (!empty($this->bypass_precache) && !empty($this->bypass_precache[$group])) {
882 $bypass_data = $this->bypass_precache[$group];
883
884 if (\is_array($bypass_data)) {
885 return false !== array_search($key, $bypass_data);
886 }
887
888 if ($key === $bypass_data) {
889 return true;
890 }
891 }
892
893 return false;
894 }
895
896 /**
897 * is_valid_key.
898 */
899 private function is_valid_key($key)
900 {
901 if (\is_int($key)) {
902 return true;
903 }
904
905 if (\is_string($key) && '' !== trim($key)) {
906 return true;
907 }
908
909 if (!\function_exists('__') && \function_exists('wp_load_translations_early')) {
910 wp_load_translations_early();
911 }
912
913 return false;
914 }
915
916 /**
917 * is_user_logged_in.
918 */
919 private function is_user_logged_in()
920 {
921 return \function_exists('is_user_logged_in') && is_user_logged_in();
922 }
923
924 /**
925 * is_filtered_groups.
926 */
927 protected function is_filtered_groups($group, $key)
928 {
929 if (!\is_array($this->filtered_groups) || !isset($this->filtered_groups[$group])) {
930 return false;
931 }
932
933 if (false === $this->filtered_groups[$group]) {
934 $this->filtered_groups[$group][] = $key;
935 $this->filtered_groups[$group] = array_unique($this->filtered_groups[$group]);
936
937 return true;
938 }
939
940 if (\in_array($key, $this->filtered_groups[$group])) {
941 return true;
942 }
943
944 return false;
945 }
946
947 /**
948 * flush_filtered_groups.
949 */
950 private function flush_filtered_groups($hook, $args)
951 {
952 if (!\is_array($this->filtered_groups)) {
953 return false;
954 }
955
956 foreach ($this->filtered_groups as $group => $keys) {
957 if (empty($keys) || !\is_array($keys)) {
958 continue;
959 }
960
961 $keys = array_unique($keys);
962 foreach ($keys as $key) {
963 $this->delete($key, $group);
964 $this->dc_log('flush', '000000000000-'.$this->item_hash(__FUNCTION__), $group.':'.$key);
965 }
966 }
967
968 return true;
969 }
970
971 /**
972 * maybe_expire.
973 */
974 private function maybe_expire($group, $expire = 0, $key = '')
975 {
976 if (empty($expire)) {
977 $expire = 0;
978 }
979
980 $expire = $this->fs()->sanitize_timestamp($expire);
981 $maxttl = $this->cache_maxttl;
982
983 if (0 === $expire && $maxttl < 2419200) {
984 if ($this->fs()->is_transient($group)) {
985 if ('site-transient' === $group && \in_array($key, ['update_plugins', 'update_themes', 'update_core', '_woocommerce_helper_updates'])) {
986 $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d
987 } else {
988 // $expire = $maxttl < 604800 ? 604800 : $maxttl; // 7d
989 $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d
990 }
991 } elseif ($this->fs()->is_wp_options($group)) {
992 $expire = $maxttl < 1209600 ? 1209600 : $maxttl; // 14d
993 } elseif (\in_array($group, ['terms', 'posts', 'post_meta', 'comments', 'comment_feed', 'sites', 'networks'])) {
994 $expire = $maxttl < 1209600 ? 1209600 : $maxttl; // 14d
995 }
996
997 // wp stale cache
998 // group-queries: wp >= 6.3
999 elseif ($this->fs()->is_wp_cache_group_queries($group)) {
1000 $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d
1001 }
1002
1003 // wp stale cache
1004 // prefix:md5hash:microtime
1005 // wp_query|get_terms|get_comments|comment_feed|get_sites|get_network_ids|get_page_by_path|other?
1006 elseif (false !== strpos($key, ':') && @preg_match('@^([a-zA-Z0-9\._-]+):([0-9a-f]{32}):([0-9\. ]+)$@', $key)) {
1007 $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d
1008 }
1009
1010 // wp stale cache
1011 // cache timestamp
1012 elseif ('last_changed' === $key) {
1013 $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d
1014 }
1015
1016 // advcpost
1017 // docketcache-post-(found|media|timestamp)
1018 elseif (false !== strpos($group, 'docketcache-post-')) {
1019 $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d
1020 }
1021
1022 // advcpost
1023 // docketcache-post-media
1024 elseif ('docketcache-post-media' === $group) {
1025 $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d
1026 }
1027
1028 // advcpost
1029 // cache timestamp
1030 elseif ('docketcache-post' === $group && 'cache_incr' === $key) {
1031 $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d
1032 }
1033
1034 // woocommerce stale cache
1035 // cache prefix
1036 elseif (false !== strpos($key, '_cache_prefix') && @preg_match('@^wc_(.*?)_cache_prefix$@', $key)) {
1037 $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d
1038 }
1039
1040 // woocommerce stale cache
1041 // wc_cache_0.72953700 1651592702
1042 elseif (false !== strpos($key, 'wc_cache_') && @preg_match('@^wc_cache_([0-9\. ]+)_@', $key)) {
1043 $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d
1044 } elseif (false !== strpos($group, 'wc_cache_') && @preg_match('@^wc_cache_([0-9\. ]+)_@', $group)) {
1045 $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d
1046 }
1047
1048 // common cache
1049 elseif (preg_match('@[0-9a-f]{32}@', $key)) {
1050 $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d
1051 }
1052
1053 // else
1054 else {
1055 $expire = $maxttl;
1056 }
1057 }
1058
1059 return $expire;
1060 }
1061
1062 /**
1063 * get_item_hash.
1064 */
1065 private function get_item_hash($file)
1066 {
1067 return basename($file, '.php');
1068 }
1069
1070 /**
1071 * item_hash.
1072 */
1073 private function item_hash($str, $length = 12)
1074 {
1075 if (!$this->is_valid_key($str)) {
1076 $str = serialize($str);
1077 }
1078
1079 if (empty($length)) {
1080 return md5($str);
1081 }
1082
1083 return substr(md5($str), 0, $length);
1084 }
1085
1086 /**
1087 * get_file_path.
1088 */
1089 private function get_file_path($key, $group)
1090 {
1091 $hash_group = $this->item_hash($group);
1092 $hash_key = $this->item_hash($key);
1093
1094 $index = $hash_group.'-'.$hash_key;
1095
1096 if ($this->cf()->is_dcfalse('CHUNKCACHEDIR', true)) {
1097 return $this->cache_path.$index.'.php';
1098 }
1099
1100 $chunk_path = $this->fs()->get_chunk_path($hash_group, $hash_key);
1101
1102 return $this->cache_path.$chunk_path.$index.'.php';
1103 }
1104
1105 /**
1106 * skip_stats.
1107 */
1108 private function skip_stats($group, $key = '')
1109 {
1110 if ($this->is_non_persistent_groups($group) || (!empty($keys) && $this->is_non_persistent_keys($key))) {
1111 return true;
1112 }
1113
1114 return $this->cf()->is_dcfalse('LOG_ALL') && $this->fs()->is_docketcachegroup($group);
1115 }
1116
1117 /**
1118 * has_stalecache.
1119 */
1120 private function has_stalecache($key, $group = '')
1121 {
1122 if ($this->fs()->is_wp_cache_group_queries($group)) {
1123 return true;
1124 }
1125
1126 if ('wc_' === substr($key, 0, 3) && '_cache_prefix' === substr($key, -13)) {
1127 return true;
1128 }
1129
1130 if ('wc_cache_' === substr($key, 0, 9) || 'wc_cache_' === substr($group, 0, 9)) {
1131 return true;
1132 }
1133
1134 if (false !== strpos($key, ':') && @preg_match('@^([a-zA-Z0-9\._-]+):([0-9a-f]{32}):([0-9\. ]+)$@', $key)) {
1135 return true;
1136 }
1137
1138 if (false !== strpos($group, 'docketcache-post-') && preg_match('@^docketcache-post-\d+$@', $group)) {
1139 return true;
1140 }
1141
1142 return false;
1143 }
1144
1145 /**
1146 * is_stalecache_ignored.
1147 */
1148 private function is_stalecache_ignored($key, $group = '')
1149 {
1150 if ($this->ignore_stalecache) {
1151 return $this->has_stalecache($key, $group);
1152 }
1153
1154 return false;
1155 }
1156
1157 /**
1158 * fs.
1159 */
1160 private function fs()
1161 {
1162 static $inst;
1163 if (!\is_object($inst)) {
1164 $inst = new Nawawi\DocketCache\Filesystem();
1165 }
1166
1167 return $inst;
1168 }
1169
1170 /**
1171 * cf.
1172 */
1173 private function cf()
1174 {
1175 static $inst;
1176 if (!\is_object($inst)) {
1177 $inst = new Nawawi\DocketCache\Constans();
1178 }
1179
1180 return $inst;
1181 }
1182
1183 /**
1184 * transientdb.
1185 */
1186 private function transient_db()
1187 {
1188 static $inst;
1189 if (!\is_object($inst)) {
1190 $inst = new Nawawi\DocketCache\TransientDb();
1191 }
1192
1193 return $inst;
1194 }
1195
1196 /**
1197 * dc_key.
1198 */
1199 private function dc_key($key, $group)
1200 {
1201 if ($this->multisite && !\array_key_exists($group, $this->global_groups)) {
1202 $key = $this->blog_prefix.$key;
1203 }
1204
1205 return $key;
1206 }
1207
1208 /**
1209 * dc_log.
1210 */
1211 private function dc_log($tag, $id, $data)
1212 {
1213 if ($this->cf()->is_dcfalse('LOG')) {
1214 return false;
1215 }
1216
1217 if ($this->skip_stats($data)) {
1218 return false;
1219 }
1220
1221 if ($this->cf()->is_dcfalse('LOG_ALL')) {
1222 if (!\in_array($tag, ['hit', 'miss'])) {
1223 return false;
1224 }
1225
1226 if (false !== strpos($data, 'user') && @preg_match('@^user(s|email|logins|_meta)\:.*@', $data)) {
1227 return false;
1228 }
1229 }
1230
1231 $caller = '';
1232 if (!empty($_SERVER['REQUEST_URI'])) {
1233 $caller = $_SERVER['REQUEST_URI'];
1234 } elseif ($this->cf()->is_dctrue('WPCLI')) {
1235 $caller = 'wp-cli';
1236 }
1237
1238 if (false !== strpos($caller, '?page=docket-cache')) {
1239 return false;
1240 }
1241
1242 static $duplicate = [];
1243
1244 $buff = $this->item_hash($tag.$id.$data.$caller);
1245 if (isset($duplicate[$buff])) {
1246 return false;
1247 }
1248
1249 $duplicate[$buff] = 1;
1250
1251 return $this->fs()->log($tag, $id, $data, $caller);
1252 }
1253
1254 /**
1255 * dc_flush.
1256 */
1257 private function dc_flush()
1258 {
1259 $dir = $this->cache_path;
1260 $is_timeout = false;
1261 $cnt = $this->fs()->cachedir_flush($dir, false, $is_timeout);
1262 $logkey = '000000000000-'.$this->item_hash(__FUNCTION__);
1263
1264 if ($is_timeout) {
1265 $this->dc_log('err', $logkey, 'Process aborted. Reached maximum execution time. Total cache flushed: '.$cnt);
1266
1267 return false;
1268 }
1269
1270 if (false === $cnt) {
1271 $this->dc_log('err', $logkey, 'Cache could not be flushed');
1272
1273 return false;
1274 }
1275
1276 if ($cnt > 0) {
1277 $this->dc_log('flush', $logkey, 'Total cache flushed: '.$cnt);
1278 }
1279
1280 return true;
1281 }
1282
1283 /**
1284 * dc_remove.
1285 */
1286 private function dc_remove($key, $group)
1287 {
1288 $result = true;
1289 if ($this->use_transientdb && $this->fs()->is_transient($group)) {
1290 $result = $this->transient_db()->delete($key, $group);
1291 }
1292
1293 $file = $this->get_file_path($key, $group);
1294 $this->fs()->unlink($file, false);
1295 $this->dc_log('del', $this->get_item_hash($file), $group.':'.$key);
1296
1297 return $result;
1298 }
1299
1300 /**
1301 * dc_remove_group.
1302 */
1303 public function dc_remove_group($group)
1304 {
1305 $total = 0;
1306 if (!$this->fs()->is_docketcachedir($this->cache_path)) {
1307 return $total;
1308 }
1309
1310 $pattern = '@^'.$this->item_hash($group).'\-([a-z0-9]{12})\.php$@';
1311
1312 if (\is_array($group) && !empty($group)) {
1313 $groups = array_map(function ($name) {
1314 return $this->item_hash($name);
1315 }, $group);
1316
1317 $pattern = '@^('.implode('|', $groups).")\-([a-z0-9]{12})\.php$@";
1318 $group = implode(',', $group);
1319 }
1320
1321 $this->fs()->suspend_cache_write(true);
1322 $max_execution_time = $this->fs()->get_max_execution_time(180);
1323
1324 $slowdown = 0;
1325 foreach ($this->fs()->scanfiles($this->cache_path, null, $pattern) as $object) {
1326 if ($object->isFile()) {
1327 $fx = $object->getPathName();
1328 $fn = $object->getFileName();
1329 $this->fs()->unlink($fx, true);
1330 ++$total;
1331
1332 array_map(function ($grp) use ($fx) {
1333 unset($this->cache[$grp]);
1334 $this->dc_log('flush', $this->get_item_hash($fx), $grp.':*');
1335 }, explode(',', $group));
1336 }
1337
1338 if ($slowdown > 10) {
1339 $slowdown = 0;
1340 usleep(5000);
1341 }
1342
1343 ++$slowdown;
1344
1345 if ($max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $max_execution_time) {
1346 break;
1347 }
1348 }
1349
1350 $this->fs()->suspend_cache_write(false);
1351
1352 if ($this->use_transientdb && $this->fs()->is_transient(explode(',', $group)) && \function_exists('nwdcx_cleanuptransient')) {
1353 $total += nwdcx_cleanuptransient();
1354 }
1355
1356 return $total;
1357 }
1358
1359 /**
1360 * dc_remove_group_match.
1361 */
1362 public function dc_remove_group_match($group)
1363 {
1364 $total = 0;
1365 if (!$this->fs()->is_docketcachedir($this->cache_path)) {
1366 return $total;
1367 }
1368
1369 $this->fs()->suspend_cache_write(true);
1370 $max_execution_time = $this->fs()->get_max_execution_time(180);
1371
1372 $slowdown = 0;
1373 $pattern = '@^([a-z0-9]{12})\-([a-z0-9]{12})\.php$@';
1374 foreach ($this->fs()->scanfiles($this->cache_path, null, $pattern) as $object) {
1375 if ($object->isFile()) {
1376 $fx = $object->getPathName();
1377 $data = $this->fs()->cache_get($fx);
1378 if (!empty($data) && !empty($data['group'])) {
1379 $match = $data['group'];
1380
1381 if (\is_array($group) && !empty($group)) {
1382 foreach ($group as $grp) {
1383 if ($grp === substr($match, 0, \strlen($grp))) {
1384 $this->fs()->unlink($fx, true);
1385 $this->dc_log('flush', $this->get_item_hash($fx), $match.':*');
1386 unset($this->cache[$match]);
1387
1388 ++$total;
1389 }
1390 }
1391 } else {
1392 if ($group === substr($match, 0, \strlen($group))) {
1393 $this->fs()->unlink($fx, true);
1394 $this->dc_log('flush', $this->get_item_hash($fx), $match.':*');
1395 unset($this->cache[$match]);
1396
1397 ++$total;
1398 }
1399 }
1400 }
1401 unset($data);
1402 }
1403
1404 if ($slowdown > 10) {
1405 $slowdown = 0;
1406 usleep(5000);
1407 }
1408
1409 ++$slowdown;
1410
1411 if ($max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $max_execution_time) {
1412 break;
1413 }
1414 }
1415
1416 $this->fs()->suspend_cache_write(false);
1417
1418 return $total;
1419 }
1420
1421 /**
1422 * dc_get.
1423 */
1424 private function dc_get($key, $group, $is_raw = false, &$codestub_false = false)
1425 {
1426 $file = $this->get_file_path($key, $group);
1427 $logkey = $this->get_item_hash($file);
1428
1429 if ($this->use_transientdb && !\in_array($key, $this->bypass_transientdb)) {
1430 if ($this->fs()->is_transient($group)) {
1431 return $this->transient_db()->get($key, $group);
1432 }
1433
1434 if ($this->fs()->is_wp_options($group) && $this->transient_db()->match_key($key)) {
1435 return false;
1436 }
1437 }
1438
1439 $data = $this->fs()->cache_get($file);
1440 if (false === $data) {
1441 if (!$this->skip_stats($group) && !$this->fs()->is_transient($group)) {
1442 $this->dc_log('miss', $logkey, $group.':'.$key);
1443 }
1444
1445 /*if (!$this->skip_stats($group) && !$this->fs()->is_transient($group)) {
1446 ++$this->cache_misses;
1447
1448 $this->dc_log('miss', $logkey, $group.':'.$key);
1449 }*/
1450
1451 return false;
1452 }
1453
1454 $is_timeout = false;
1455 if (!empty($data['timeout']) && $this->fs()->valid_timestamp($data['timeout']) && time() >= $data['timeout']) {
1456 $this->dc_log('exp', $logkey, $group.':'.$key);
1457 $this->fs()->unlink($file, false);
1458 $is_timeout = true;
1459 }
1460
1461 // incase gc not run
1462 if (!$is_timeout && !empty($data['timestamp']) && $this->fs()->valid_timestamp($data['timestamp'])) {
1463 $maxttl = time() - $this->cache_maxttl;
1464 if ($maxttl > $data['timestamp']) {
1465 $this->dc_log('exp', $logkey, $group.':'.$key);
1466 $this->fs()->unlink($file, true); // true = delete it instead of truncate
1467 }
1468 }
1469
1470 if (!$this->skip_stats($group)) {
1471 ++$this->persistent_cache_hits;
1472 $this->dc_log('hit', $logkey, $group.':'.$key);
1473 }
1474
1475 // If the transient does not exist, does not have a value, or has expired, then the return value will be false.
1476 if (!empty($data['group']) && $this->fs()->is_transient($data['group']) && ('' === $data['data'] || $is_timeout)) {
1477 $data['data'] = false;
1478 }
1479
1480 // nwdcx_unserialize failed to convert serialize object.
1481 // we unserialize it here to get the object.
1482 if (!empty($data['data'])) {
1483 // *_serialize set at dc_save, to load it faster
1484 if (false !== strpos($data['type'], '_serialize')) {
1485 $data['data'] = unserialize($data['data']);
1486 } elseif ('string' === $data['type'] && \function_exists('maybe_unserialize')) {
1487 // old cache data
1488 $data['data'] = maybe_unserialize($data['data']);
1489 }
1490 }
1491 clearstatcache();
1492
1493 // skip precache.
1494 if (isset($GLOBALS['DOCKET_CACHE_CODESTUB_FALSE']) && isset($GLOBALS['DOCKET_CACHE_CODESTUB_FALSE'][$file])) {
1495 $codestub_false = true;
1496 }
1497
1498 return $is_raw ? $data : $data['data'];
1499 }
1500
1501 /**
1502 * dc_code.
1503 */
1504 private function dc_code($file, $arr)
1505 {
1506 $logkey = $this->get_item_hash($file);
1507 $logpref = __FUNCTION__.'():';
1508
1509 $data = $this->fs()->export_var($arr, $error);
1510
1511 if (false === $data) {
1512 $this->dc_log('err', $logkey, $logpref.' Failed to export var -> '.$error);
1513
1514 return false;
1515 }
1516
1517 $code = $this->fs()->code_stub($data);
1518 $stat = $this->fs()->dump($file, $code, false); // 3rd param = validate
1519
1520 if (false === $stat) {
1521 return false;
1522 }
1523
1524 if (-1 === $stat) {
1525 $this->dc_log('err', $logkey, $logpref.' Failed to write');
1526
1527 return false;
1528 }
1529
1530 // remove lock
1531 $this->fs()->validate_fatal_error_file($file);
1532
1533 return $stat;
1534 }
1535
1536 /**
1537 * dc_save.
1538 */
1539 private function dc_save($cache_key, $data, $group = 'default', $expire = 0, $key = '')
1540 {
1541 if (wp_suspend_cache_addition()) {
1542 return false;
1543 }
1544
1545 $logkey = $this->item_hash($group).'-'.$this->item_hash($cache_key);
1546 $logpref = __FUNCTION__.'():';
1547
1548 if ($this->use_transientdb && !\in_array($cache_key, $this->bypass_transientdb)) {
1549 if ($this->fs()->is_transient($group)) {
1550 if (!$expire) {
1551 $expire = 86400;
1552 }
1553
1554 return $this->transient_db()->set($cache_key, $data, $group, time() + $expire);
1555 }
1556
1557 if ($this->fs()->is_wp_options($group) && $this->transient_db()->match_key($cache_key)) {
1558 return false;
1559 }
1560
1561 if (\in_array($cache_key, ['notoptions', 'alloptions']) && \is_array($data) && !empty($data)) {
1562 foreach ($data as $m => $n) {
1563 if ($this->transient_db()->match_key($m)) {
1564 unset($data[$m]);
1565 }
1566 }
1567 }
1568 }
1569
1570 if (!$this->fs()->mkdir_p($this->cache_path)) {
1571 return false;
1572 }
1573
1574 @$this->fs()->placeholder($this->cache_path);
1575
1576 $file = $this->get_file_path($cache_key, $group);
1577
1578 // Skip save to disk, return true.
1579 if (('' === $data || (\is_array($data) && empty($data))) && ($this->fs()->is_transient($group) || $this->ignore_emptycache)) {
1580 nwdcx_debuglog(__FUNCTION__.': '.$logkey.': Process aborted. No data availale.');
1581 $this->fs()->unlink($file, false);
1582 unset($this->precache[$group][$cache_key]);
1583
1584 return true;
1585 }
1586
1587 // Chunk dir.
1588 if ($this->cf()->is_dctrue('CHUNKCACHEDIR', true) && !$this->fs()->mkdir_p(\dirname($file))) {
1589 return false;
1590 }
1591
1592 // If $expire is larger than 0, convert it to timestamp.
1593 $timeout = ($expire > 0 ? time() + $expire : 0);
1594
1595 $type = \gettype($data);
1596 if ('unknown type' === $type) {
1597 return false;
1598 }
1599
1600 if ('NULL' === $type && null === $data) {
1601 $data = '';
1602 }
1603
1604 if (!empty($data)) {
1605 if (!\in_array($type, ['boolean', 'integer', 'double', 'NULL'])) {
1606 // Abort if object too large.
1607 $len = 0;
1608 $nwdcx_suppresserrors = nwdcx_suppresserrors(true);
1609 if (\function_exists('maybe_serialize')) {
1610 $len = \strlen(@maybe_serialize($data));
1611 } else {
1612 $len = \strlen(@serialize($data));
1613 }
1614 nwdcx_suppresserrors($nwdcx_suppresserrors);
1615
1616 if ($len >= $this->cache_maxsize) {
1617 $this->dc_log('err', $logkey, $group.':'.$cache_key.' '.$logpref.' The size of object has breached '.$len.' of '.$this->cache_maxsize.' bytes.');
1618
1619 nwdcx_debuglog(__FUNCTION__.': '.$logkey.': Process aborted. The size of object has breached '.$len.' of '.$this->cache_maxsize.' bytes.');
1620 $this->fs()->unlink($file, false);
1621 unset($this->precache[$group][$cache_key]);
1622
1623 return false;
1624 }
1625 }
1626
1627 // Unserialize content first.
1628 if ('string' === $type) {
1629 $data = nwdcx_unserialize($data);
1630 } elseif ('array' === $type) {
1631 $data_r = nwdcx_arraymap('nwdcx_unserialize', $data);
1632
1633 if (!empty($data_r)) {
1634 $data = $data_r;
1635 }
1636 unset($data_r);
1637 }
1638 }
1639
1640 $meta = [];
1641 $meta['timestamp'] = time();
1642
1643 if ($this->multisite) {
1644 $meta['network_id'] = $this->network_id;
1645 }
1646
1647 $final_type = \gettype($data);
1648 if ('string' === $final_type && nwdcx_serialized($data)) {
1649 $final_type = 'string_serialize';
1650 } elseif ('array' === $final_type) {
1651 // The Data needs to be serialized.
1652 // The cache always returns false if the object has a class instance
1653 // other than stdClass since the class has not been loaded yet.
1654 $nwdcx_suppresserrors = nwdcx_suppresserrors(true);
1655 $export_data = @var_export($data, 1);
1656 if (!empty($export_data)) {
1657 // 1st priority. If has the "Request" instance.
1658 if (false !== strpos($export_data, 'Requests_Utility_CaseInsensitiveDictionary::__set_state')) {
1659 $data = @serialize($data);
1660 if (nwdcx_serialized($data)) {
1661 $final_type = 'array_serialize';
1662 }
1663 }
1664
1665 // 2nd priority. If Transients and has class instance.
1666 if ('array' === $final_type && $this->fs()->is_transient($group) && false !== strpos($export_data, '::__set_state')) {
1667 $data = @serialize($data);
1668 if (nwdcx_serialized($data)) {
1669 $final_type = 'array_serialize';
1670 }
1671 }
1672 }
1673 unset($export_data);
1674 nwdcx_suppresserrors($nwdcx_suppresserrors);
1675 // Pass to code_stub.
1676 }
1677
1678 $meta['site_id'] = get_current_blog_id();
1679 $meta['group'] = $group;
1680 $meta['key'] = $cache_key;
1681 $meta['type'] = $final_type;
1682
1683 // If 0 let gc handle it by comparing file mtime
1684 // and maxttl constants.
1685 $meta['timeout'] = $timeout;
1686
1687 // Before code_stub.
1688 $meta['data'] = $data;
1689
1690 // Only count new file.
1691 clearstatcache(true, $file);
1692 $has_cache_file = is_file($file);
1693 if (true === $this->dc_code($file, $meta)) {
1694 nwdcx_debuglog(__FUNCTION__.': '.$this->get_item_hash($file).': Storing to disk.');
1695
1696 if (!$has_cache_file && $this->maxfile_livecheck) {
1697 $count_file = (int) $this->get('count_file', 'docketcache-gc');
1698 if ($this->maxfile > $count_file) {
1699 ++$count_file;
1700 $this->set('count_file', $count_file, 'docketcache-gc', 86400); // 1d
1701 }
1702 }
1703
1704 return true;
1705 }
1706
1707 return false;
1708 }
1709
1710 /**
1711 * dc_update.
1712 */
1713 private function dc_update($cache_key, $data, $group)
1714 {
1715 $meta = $this->dc_get($cache_key, $group, true);
1716 if (false === $meta || !\is_array($meta) || !isset($meta['data'])) {
1717 return false;
1718 }
1719
1720 $file = $this->get_file_path($cache_key, $group);
1721 $meta['data'] = $data;
1722
1723 if (true === $this->dc_code($file, $meta)) {
1724 return true;
1725 }
1726
1727 return false;
1728 }
1729
1730 /**
1731 * dc_precache_load.
1732 */
1733 private function dc_precache_load($hash)
1734 {
1735 static $is_done = false;
1736
1737 if ($is_done) {
1738 return;
1739 }
1740
1741 $cached = [];
1742 $group = 'docketcache-precache';
1743 $keys = $this->get($hash, $group);
1744
1745 if (empty($keys) || !\is_array($keys)) {
1746 return;
1747 }
1748
1749 nwdcx_debuglog(__FUNCTION__.': Process started.');
1750
1751 $this->precache_loaded[$hash] = $keys;
1752
1753 $slowdown = 0;
1754 $cnt_max = 0;
1755
1756 foreach ($keys as $cache_group => $arr) {
1757 foreach ($arr as $cache_key) {
1758 if ($cnt_max >= $this->precache_maxkey) {
1759 break 2;
1760 }
1761
1762 $force = false;
1763 $found = false;
1764 $doing_precache = true;
1765 if (!isset($cached[$cache_key.$cache_group]) && false !== $this->get($cache_key, $cache_group, $force, $found, $doing_precache)) {
1766 $cached[$cache_key.$cache_group] = 1;
1767 }
1768
1769 ++$cnt_max;
1770
1771 if ($slowdown > 10) {
1772 $slowdown = 0;
1773 usleep(1000);
1774 }
1775
1776 ++$slowdown;
1777
1778 if ($this->max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $this->max_execution_time) {
1779 break 2;
1780 }
1781 }
1782 }
1783
1784 nwdcx_debuglog(__FUNCTION__.': Process ended. Loaded '.\count($cached));
1785
1786 unset($keys, $cached);
1787 $is_done = true;
1788 }
1789
1790 /**
1791 * dc_precache_set.
1792 */
1793 private function dc_precache_set($hash)
1794 {
1795 $group = 'docketcache-precache';
1796 $file = $this->get_file_path($hash, $group);
1797
1798 if (empty($this->precache) || !\is_array($this->precache)) {
1799 $this->fs()->unlink($file, true);
1800
1801 return;
1802 }
1803
1804 $file_hash = $this->get_item_hash($file);
1805 $data = [];
1806 $slowdown = 0;
1807 $cnt_max = 0;
1808
1809 nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process started.');
1810
1811 // docketcache-precache-gc
1812 $count_file = (int) $this->get('count_file', $group.'-gc');
1813 if ($count_file >= $this->precache_maxfile) {
1814 nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process aborted. Reached maximum file limit ('.$count_file.'/'.$this->precache_maxfile.')');
1815
1816 return;
1817 }
1818
1819 foreach ($this->precache as $cache_group => $cache_keys) {
1820 if ($cnt_max >= $this->precache_maxkey) {
1821 break;
1822 }
1823
1824 if ($cache_group !== $group) {
1825 $data[$cache_group] = array_keys($cache_keys);
1826 }
1827
1828 ++$cnt_max;
1829
1830 if ($slowdown > 10) {
1831 $slowdown = 0;
1832 usleep(100);
1833 }
1834
1835 ++$slowdown;
1836
1837 if ($this->max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $this->max_execution_time) {
1838 nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process aborted. Reached maximum execution time.');
1839 break;
1840 }
1841 }
1842
1843 if (!empty($data)) {
1844 nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Total items = '.\count($data, 1));
1845
1846 if (!empty($this->precache_loaded) && \function_exists('nwdcx_arraysimilar') && nwdcx_arraysimilar($this->precache_loaded[$hash], $data)) {
1847 nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process ended. No data changes.');
1848
1849 return;
1850 }
1851
1852 // docketcache-precache-gc
1853 if ($this->precache_maxfile > $count_file) {
1854 clearstatcache(true, $file);
1855
1856 // only count new file.
1857 $has_precache_file = is_file($file);
1858
1859 if ($this->set($hash, $data, $group, 86400)) { // 1d
1860 nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process ended. Storing cache to disk.');
1861
1862 if (!$has_precache_file) {
1863 ++$count_file;
1864 $this->set('count_file', $count_file, $group.'-gc', 86400); // 1d
1865 }
1866
1867 return;
1868 }
1869 }
1870 nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process aborted. Reached maximum file limit ('.$count_file.'/'.$this->precache_maxfile.')');
1871
1872 return;
1873 }
1874
1875 nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process ended. No data available.');
1876 unset($data, $hash);
1877 }
1878
1879 /**
1880 * dc_precache.
1881 */
1882 private function dc_precache_init()
1883 {
1884 if (!empty($_POST) || empty($_SERVER['REQUEST_URI']) || $this->cf()->is_dctrue('WPCLI')) {
1885 return;
1886 }
1887
1888 $req_uri = $_SERVER['REQUEST_URI'];
1889 $dostrip = !empty($_SERVER['QUERY_STRING']);
1890
1891 $intersect_key = [
1892 'docketcache_ping' => 1,
1893 'doing_wp_cron' => 1,
1894 'wc-ajax' => 1,
1895 '_fs_blog_admin' => 1,
1896 'action' => 1,
1897 'message' => 1,
1898 ];
1899
1900 if ($dostrip && !empty($_GET) && array_intersect_key($intersect_key, $_GET)) {
1901 return;
1902 }
1903
1904 if (false !== strpos($req_uri, '/wp-json/') || false !== strpos($req_uri, '/wp-admin/admin-ajax.php') || false !== strpos($req_uri, '/xmlrpc.php') || false !== strpos($req_uri, '/wp-cron.php') || false !== strpos($req_uri, '/robots.txt') || false !== strpos($req_uri, '/favicon.ico')) {
1905 return;
1906 }
1907
1908 $req_host = !empty($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
1909 if ('localhost' !== $req_host) {
1910 $req_host = nwdcx_fixhost($req_host);
1911 }
1912
1913 if ($dostrip && $this->is_user_logged_in() && false !== strpos($req_uri, '.php?') && false !== strpos($req_uri, '/wp-admin/') && @preg_match('@/wp-admin/(network/)?.*?\.php\?.*?@', $req_uri)) {
1914 $dostrip = false;
1915 }
1916
1917 // without pretty permalink
1918 if ($dostrip && !empty($_GET) && empty($_GET['s']) && empty($_GET['q']) && (false !== strpos($req_uri, '/?p=') || false !== strpos($req_uri, '/?cat=') || false !== strpos($req_uri, '/?m=') || false !== strpos($req_uri, '/?page_id=') || false !== strpos($req_uri, '/index.php/')) && !@nwdcx_optget('permalink_structure')) {
1919 $dostrip = false;
1920 }
1921
1922 if ($dostrip) {
1923 $req_uri = strtok($req_uri, '?#');
1924 }
1925
1926 if (empty($req_host) || empty($req_uri)) {
1927 return;
1928 }
1929
1930 // $this->precache_hashkey = $this->item_hash($req_host.$req_uri);
1931 $this->precache_hashkey = md5($req_host.$req_uri);
1932
1933 $this->dc_precache_load($this->precache_hashkey);
1934 }
1935
1936 /**
1937 * dc_close.
1938 * reference:
1939 * wp_cache_close()
1940 * wp-includes/load.php -> shutdown_action_hook().
1941 */
1942 public function dc_close()
1943 {
1944 static $is_done = false;
1945
1946 if (!$is_done) {
1947 if ($this->is_precache && !empty($this->precache_hashkey) && !$this->fs()->suspend_cache_write()) {
1948 $this->dc_precache_set($this->precache_hashkey);
1949 }
1950
1951 $is_done = true;
1952 }
1953 }
1954
1955 /**
1956 * dc_init.
1957 */
1958 private function dc_init()
1959 {
1960 $this->wp_start_timestamp = \defined('WP_START_TIMESTAMP') ? WP_START_TIMESTAMP : microtime(true);
1961 $this->max_execution_time = $this->fs()->get_max_execution_time();
1962 $this->is_dev = $this->cf()->is_dctrue('DEV');
1963
1964 if ($this->cf()->is_dcint('MAXSIZE', $dcvalue)) {
1965 if (!empty($dcvalue)) {
1966 $this->cache_maxsize = $this->fs()->sanitize_maxsize($dcvalue);
1967 }
1968 }
1969
1970 if ($this->cf()->is_dcint('MAXTTL', $dcvalue)) {
1971 if (!empty($dcvalue)) {
1972 $this->cache_maxttl = $this->fs()->sanitize_maxttl($dcvalue);
1973 }
1974 }
1975
1976 if ($this->cf()->is_dcarray('GLOBAL_GROUPS', $dcvalue)) {
1977 $this->add_global_groups($dcvalue);
1978 }
1979
1980 if ($this->cf()->is_dcarray('IGNORED_GROUPS', $dcvalue)) {
1981 $this->add_non_persistent_groups($dcvalue);
1982 }
1983
1984 if ($this->cf()->is_dcarray('IGNORED_KEYS', $dcvalue)) {
1985 $this->add_non_persistent_keys($dcvalue);
1986 }
1987
1988 if ($this->cf()->is_dcarray('FILTERED_GROUPS', $dcvalue)) {
1989 $this->filtered_groups = $dcvalue;
1990 }
1991
1992 if ($this->cf()->is_dcarray('IGNORED_GROUPKEY', $dcvalue)) {
1993 $this->non_persistent_groupkey = $dcvalue;
1994 }
1995
1996 if ($this->cf()->is_dcarray('IGNORED_PRECACHE', $dcvalue)) {
1997 $this->bypass_precache = $dcvalue;
1998 }
1999
2000 if (class_exists('Nawawi\\DocketCache\\TransientDb')) {
2001 $this->use_transientdb = $this->cf()->is_dctrue('TRANSIENTDB');
2002 if ($this->cf()->is_dcarray('IGNORED_TRANSIENTDB', $dcvalue)) {
2003 $this->bypass_transientdb = $dcvalue;
2004 }
2005 }
2006
2007 $this->cache_path = $this->fs()->define_cache_path($this->cf()->dcvalue('PATH'));
2008 if ($this->multisite) {
2009 $this->cache_path = nwdcx_network_dirpath($this->cache_path);
2010 }
2011
2012 if ($this->cf()->is_dctrue('WPOPTALOAD')) {
2013 $this->fs()->optimize_alloptions();
2014 }
2015
2016 add_filter(
2017 'pre_cache_alloptions',
2018 function ($alloptions) {
2019 if (isset($alloptions['cron'])) {
2020 unset($alloptions['cron']);
2021 }
2022
2023 if (isset($alloptions['litespeed_messages'])) {
2024 unset($alloptions['litespeed_messages']);
2025 }
2026
2027 if (isset($alloptions['litespeed.admin_display.messages'])) {
2028 unset($alloptions['litespeed.admin_display.messages']);
2029 }
2030
2031 return $alloptions;
2032 },
2033 \PHP_INT_MAX
2034 );
2035
2036 // litespeed admin notice
2037 add_action(
2038 'litespeed_purged_all',
2039 function () {
2040 $this->delete('alloptions', 'options');
2041 $this->delete('litespeed_messages', 'options');
2042 $this->delete('litespeed.admin_display.messages', 'options');
2043 },
2044 \PHP_INT_MAX
2045 );
2046
2047 add_action(
2048 'all_admin_notices',
2049 function () {
2050 if (\function_exists('run_litespeed_cache')) {
2051 $this->delete('litespeed_messages', 'options');
2052 $this->delete('litespeed.admin_display.messages', 'options');
2053 }
2054 },
2055 \PHP_INT_MAX
2056 );
2057
2058 foreach (['added', 'updated', 'deleted'] as $prefix) {
2059 add_action(
2060 $prefix.'_option',
2061 function ($option) {
2062 if (!wp_installing()) {
2063 $alloptions = wp_load_alloptions();
2064 if (isset($alloptions[$option])) {
2065 add_action(
2066 'shutdown',
2067 function () {
2068 $this->delete('alloptions', 'options');
2069 },
2070 \PHP_INT_MAX - 1
2071 );
2072 }
2073 unset($alloptions);
2074 }
2075 },
2076 \PHP_INT_MAX
2077 );
2078 }
2079
2080 foreach (['activate', 'deactivate'] as $prefix) {
2081 add_action(
2082 $prefix.'_plugin',
2083 function ($plugin, $network) {
2084 add_action(
2085 'shutdown',
2086 function () {
2087 if ($this->multisite) {
2088 $this->delete($this->network_id.':active_sitewide_plugins', 'site-options');
2089 $this->delete($this->network_id.':auto_update_plugins', 'site-options');
2090 }
2091
2092 $this->delete('uninstall_plugins', 'options');
2093 $this->delete('auto_update_plugins', 'options');
2094 },
2095 \PHP_INT_MAX - 1
2096 );
2097 },
2098 \PHP_INT_MAX,
2099 2
2100 );
2101 }
2102
2103 // filtered groups hooks
2104 if (\is_array($this->filtered_groups)) {
2105 add_action(
2106 'save_post',
2107 function ($post_id, $post, $update) {
2108 $this->flush_filtered_groups('save_post', [$post_id, $post, $update]);
2109 },
2110 \PHP_INT_MIN,
2111 3
2112 );
2113
2114 add_action(
2115 'edit_post',
2116 function ($post_id, $post) {
2117 $this->flush_filtered_groups('edit_post', [$post_id, $post]);
2118 },
2119 \PHP_INT_MIN,
2120 2
2121 );
2122
2123 add_action(
2124 'delete_post',
2125 function ($post_id) {
2126 $this->flush_filtered_groups('delete_post', [$post_id]);
2127 },
2128 \PHP_INT_MIN
2129 );
2130 }
2131
2132 // html comment
2133 $this->add_signature = false;
2134 if ($this->cf()->is_dctrue('SIGNATURE')) {
2135 add_action(
2136 'wp_head',
2137 function () {
2138 if (!$this->is_user_logged_in()) {
2139 $this->add_signature = true;
2140 }
2141 },
2142 \PHP_INT_MIN
2143 );
2144
2145 add_action(
2146 'shutdown',
2147 function () {
2148 if ($this->add_signature && !$this->is_user_logged_in()) {
2149 echo apply_filters('docketcache/filter/signature/htmlfooter', "\n<!-- Performance optimized by Docket Cache: https://wordpress.org/plugins/docket-cache -->\n");
2150 }
2151 },
2152 \PHP_INT_MAX
2153 );
2154 }
2155
2156 // bypass stalecache
2157 $this->ignore_stalecache = $this->cf()->is_dctrue('STALECACHE_IGNORE', true);
2158
2159 // bypass emptyache
2160 $this->ignore_emptycache = $this->cf()->is_dctrue('EMPTYCACHE_IGNORE', true);
2161
2162 // maxfile check
2163 // true = count file at dc_save, false = will handle by GC.
2164 $this->maxfile_livecheck = $this->cf()->is_dctrue('MAXFILE_LIVECHECK', true);
2165
2166 // maxfile
2167 $this->maxfile = (int) $this->fs()->sanitize_maxfile($this->cf()->dcvalue('MAXFILE', true));
2168 $count_file = (int) $this->get('count_file', 'docketcache-gc');
2169 if ($count_file >= $this->maxfile) {
2170 $this->fs()->suspend_cache_write(true);
2171 }
2172
2173 // load precache
2174 $this->is_precache = $this->cf()->is_dctrue('PRECACHE', true);
2175 if ($this->is_precache) {
2176 if ($this->cf()->is_dcint('PRECACHE_MAXGROUP', $dcvalue)) {
2177 if (!empty($dcvalue)) {
2178 $this->precache_maxgroup = $dcvalue;
2179 }
2180 }
2181
2182 if ($this->cf()->is_dcint('PRECACHE_MAXKEY', $dcvalue)) {
2183 if (!empty($dcvalue)) {
2184 $this->precache_maxkey = $dcvalue;
2185 }
2186 }
2187
2188 if ($this->cf()->is_dcint('PRECACHE_MAXFILE', $dcvalue)) {
2189 if (!empty($dcvalue)) {
2190 $this->precache_maxfile = $this->fs()->sanitize_precache_maxfile($dcvalue);
2191 }
2192 }
2193
2194 $this->dc_precache_init();
2195 }
2196 }
2197 }
2198
2199 /**
2200 * Sets up Object Cache Global and assigns it.
2201 *
2202 * @global WP_Object_Cache $wp_object_cache
2203 */
2204 function wp_cache_init()
2205 {
2206 global $wp_object_cache;
2207 if (!($wp_object_cache instanceof WP_Object_Cache)) {
2208 $wp_object_cache = new WP_Object_Cache();
2209 }
2210 }
2211
2212 /**
2213 * @see WP_Object_Cache::add()
2214 */
2215 function wp_cache_add($key, $data, $group = '', $expire = 0)
2216 {
2217 global $wp_object_cache;
2218
2219 return $wp_object_cache->add($key, $data, $group, (int) $expire);
2220 }
2221
2222 /**
2223 * @see WP_Object_Cache::add_multiple()
2224 */
2225 function wp_cache_add_multiple(array $data, $group = '', $expire = 0)
2226 {
2227 global $wp_object_cache;
2228
2229 return $wp_object_cache->add_multiple($data, $group, $expire);
2230 }
2231
2232 /**
2233 * @see WP_Object_Cache::replace()
2234 */
2235 function wp_cache_replace($key, $data, $group = '', $expire = 0)
2236 {
2237 global $wp_object_cache;
2238
2239 return $wp_object_cache->replace($key, $data, $group, (int) $expire);
2240 }
2241
2242 /**
2243 * @see WP_Object_Cache::set()
2244 */
2245 function wp_cache_set($key, $data, $group = '', $expire = 0)
2246 {
2247 global $wp_object_cache;
2248
2249 return $wp_object_cache->set($key, $data, $group, (int) $expire);
2250 }
2251
2252 /**
2253 * @see WP_Object_Cache::set_multiple()
2254 */
2255 function wp_cache_set_multiple(array $data, $group = '', $expire = 0)
2256 {
2257 global $wp_object_cache;
2258
2259 return $wp_object_cache->set_multiple($data, $group, $expire);
2260 }
2261
2262 /**
2263 * @see WP_Object_Cache::get()
2264 */
2265 function wp_cache_get($key, $group = '', $force = false, &$found = null)
2266 {
2267 global $wp_object_cache;
2268
2269 return $wp_object_cache->get($key, $group, $force, $found);
2270 }
2271
2272 /**
2273 * @see WP_Object_Cache::get_multiple()
2274 */
2275 function wp_cache_get_multiple(array $keys, $group = '', $force = false)
2276 {
2277 global $wp_object_cache;
2278
2279 return $wp_object_cache->get_multiple($keys, $group, $force);
2280 }
2281
2282 /**
2283 * @see WP_Object_Cache::delete()
2284 */
2285 function wp_cache_delete($key, $group = '')
2286 {
2287 global $wp_object_cache;
2288
2289 return $wp_object_cache->delete($key, $group);
2290 }
2291
2292 /**
2293 * @see WP_Object_Cache::delete_multiple()
2294 */
2295 function wp_cache_delete_multiple(array $keys, $group = '')
2296 {
2297 global $wp_object_cache;
2298
2299 return $wp_object_cache->delete_multiple($keys, $group);
2300 }
2301
2302 /**
2303 * @see WP_Object_Cache::incr()
2304 */
2305 function wp_cache_incr($key, $offset = 1, $group = '')
2306 {
2307 global $wp_object_cache;
2308
2309 return $wp_object_cache->incr($key, $offset, $group);
2310 }
2311
2312 /**
2313 * @see WP_Object_Cache::decr()
2314 */
2315 function wp_cache_decr($key, $offset = 1, $group = '')
2316 {
2317 global $wp_object_cache;
2318
2319 return $wp_object_cache->decr($key, $offset, $group);
2320 }
2321
2322 /**
2323 * @see WP_Object_Cache::flush()
2324 */
2325 function wp_cache_flush()
2326 {
2327 global $wp_object_cache;
2328
2329 return $wp_object_cache->flush();
2330 }
2331
2332 /**
2333 * @see WP_Object_Cache::flush()
2334 */
2335 function wp_cache_flush_runtime()
2336 {
2337 global $wp_object_cache;
2338
2339 return $wp_object_cache->flush(true);
2340 }
2341
2342 /**
2343 * Determines whether the object cache implementation supports a particular feature.
2344 *
2345 * @since 6.1.0
2346 *
2347 * @param string $feature Name of the feature to check for. Possible values include:
2348 * 'add_multiple', 'set_multiple', 'get_multiple', 'delete_multiple',
2349 * 'flush_runtime', 'flush_group'.
2350 *
2351 * @return bool true if the feature is supported, false otherwise
2352 */
2353 function wp_cache_supports($feature)
2354 {
2355 switch ($feature) {
2356 case 'add_multiple':
2357 case 'set_multiple':
2358 case 'get_multiple':
2359 case 'delete_multiple':
2360 case 'flush_runtime':
2361 case 'flush_group':
2362 return true;
2363
2364 default:
2365 return false;
2366 }
2367 }
2368
2369 /**
2370 * @see WP_Object_Cache::dc_close()
2371 */
2372 function wp_cache_close()
2373 {
2374 global $wp_object_cache;
2375
2376 $wp_object_cache->dc_close();
2377
2378 return true;
2379 }
2380
2381 /**
2382 * @see WP_Object_Cache::add_non_persistent_groups()
2383 */
2384 function wp_cache_add_non_persistent_groups($groups)
2385 {
2386 global $wp_object_cache;
2387 $wp_object_cache->add_non_persistent_groups($groups);
2388 }
2389
2390 /**
2391 * @see WP_Object_Cache::add_non_persistent_keys()
2392 */
2393 function wp_cache_add_non_persistent_keys($keys)
2394 {
2395 global $wp_object_cache;
2396 $wp_object_cache->add_non_persistent_keys($keys);
2397 }
2398
2399 /**
2400 * @see WP_Object_Cache::switch_to_blog()
2401 */
2402 function wp_cache_switch_to_blog($blog_id)
2403 {
2404 global $wp_object_cache;
2405
2406 $wp_object_cache->switch_to_blog($blog_id);
2407 }
2408
2409 /**
2410 * @see WP_Object_Cache::add_global_groups()
2411 */
2412 function wp_cache_add_global_groups($groups)
2413 {
2414 global $wp_object_cache;
2415
2416 $wp_object_cache->add_global_groups($groups);
2417 }
2418
2419 /**
2420 * @see WP_Object_Cache::stats()
2421 */
2422 function wp_cache_stats()
2423 {
2424 global $wp_object_cache;
2425 $wp_object_cache->stats();
2426 }
2427
2428 /**
2429 * @see WP_Object_Cache::dc_remove_group()
2430 */
2431 function wp_cache_flush_group($group = 'default')
2432 {
2433 global $wp_object_cache;
2434
2435 return $wp_object_cache->dc_remove_group($group);
2436 }
2437
2438 /**
2439 * @see WP_Object_Cache::dc_remove_group_match()
2440 */
2441 function wp_cache_flush_group_match($group = 'default')
2442 {
2443 global $wp_object_cache;
2444
2445 return $wp_object_cache->dc_remove_group_match($group);
2446 }
2447