PluginProbe
Docket Cache – Object Cache Accelerator / 26.04.03
Docket Cache – Object Cache Accelerator v26.04.03
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 / src / Canopt.php

Canopt.php in Docket Cache – Object Cache Accelerator 26.04.03, at includes/src/Canopt.php

621 lines 18.3 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
11 namespace Nawawi\DocketCache;
12
13 \defined('ABSPATH') || exit;
14
15 final class Canopt extends Bepart
16 {
17 public $file;
18 public $path;
19 public $path_lock;
20
21 private static $inst;
22
23 public function __construct()
24 {
25 $this->define_path();
26 }
27
28 private function define_path()
29 {
30 $path = '';
31 $constfx = nwdcx_constfx('DATA_PATH');
32 if (\defined($constfx)) {
33 $path = \constant($constfx);
34 }
35
36 if (!empty($path)) {
37 if ('docket-cache-data' !== basename($path)) {
38 $path = rtrim($path, '/\\').'/docket-cache-data';
39 }
40 } else {
41 $path = rtrim(DOCKET_CACHE_CONTENT_PATH, '/\\').'/docket-cache-data';
42 }
43
44 $path = wp_normalize_path($path);
45
46 if (is_multisite()) {
47 $path = nwdcx_network_dirpath($path);
48 }
49
50 $this->path = rtrim($path, '/\\');
51
52 $this->file = $this->path.'/options.php';
53 $this->path_lock = $this->path.'/lock';
54 }
55
56 public static function init()
57 {
58 if (!isset(self::$inst)) {
59 self::$inst = new self();
60 }
61
62 return self::$inst;
63 }
64
65 public function is_options_writable()
66 {
67 if (@is_file($this->file)) {
68 return @is_writable($this->file);
69 }
70
71 if (@is_dir($this->path)) {
72 return @is_writable($this->path);
73 }
74
75 return @is_writable(\dirname($this->path));
76 }
77
78 private function key_names()
79 {
80 $names = [
81 'log',
82 'log_time',
83 'log_all',
84 'preload',
85 'menucache',
86 'optermcount',
87 'precache',
88 'mocache',
89 'misc_tweaks',
90 'postmissedschedule',
91 'wootweaks',
92 'wooadminoff',
93 'woowidgetoff',
94 'woowpdashboardoff',
95 'wooextensionpageoff',
96 'woocartfragsoff',
97 'wooaddtochartcrawling',
98 'pageloader',
99 'wpoptaload',
100 'cronoptmzdb',
101 'cronbot',
102 'opcviewer',
103 'stats',
104 'gcaction',
105 'flushaction',
106 'configaction',
107 'autoupdate_toggle',
108 'checkversion',
109 'optwpquery',
110 'limitbulkedit',
111 'pingback',
112 'headerjunk',
113 'wpemoji',
114 'wpembed',
115 'wpfeed',
116 'wplazyload',
117 'wpsitemap',
118 'wpapppassword',
119 'wpdashboardnews',
120 'wpbrowsehappy',
121 'wpservehappy',
122 'postviaemail',
123 'objectcacheoff',
124 'flush_shutdown',
125 'opcshutdown',
126 'maxsize_disk',
127 'maxfile',
128 'maxfile_livecheck',
129 'chunkcachedir',
130 'flush_stalecache',
131 'stalecache_ignore',
132 'emptycache_ignore',
133 'transientdb',
134 'limithttprequest',
135 'rtpostautosave',
136 'rtpostrevision',
137 'rtpostemptytrash',
138 'rtpluginthemeeditor',
139 'rtpluginthemeinstall',
140 'rtimageoverwrite',
141 'rtwpdebug',
142 'rtwpdebugdisplay',
143 'rtwpdebuglog',
144 'rtwpcoreupdate',
145 'rtconcatenatescripts',
146 'rtdisablewpcron',
147 ];
148
149 if (version_compare($GLOBALS['wp_version'], '6.1', '<')) {
150 $names[] = 'advcpost';
151 $names[] = 'advpost_posttype_all';
152 }
153
154 if (version_compare($GLOBALS['wp_version'], '5.8', '<')) {
155 $names[] = 'httpheadersexpect';
156 }
157
158 return $names;
159 }
160
161 public function keys($key = false)
162 {
163 // key = title
164 $data = [
165 'log' => esc_html__('Cache Log', 'docket-cache'),
166 'log_time' => esc_html__('Log Timestamp', 'docket-cache'),
167 'log_all' => esc_html__('Log All', 'docket-cache'),
168 'preload' => esc_html__('Admin Page Cache Preloading', 'docket-cache'),
169 'menucache' => esc_html__('WordPress Menu Caching', 'docket-cache'),
170 'optermcount' => esc_html__('Optimize Term Count Queries', 'docket-cache'),
171 'precache' => esc_html__('Object Cache Precaching', 'docket-cache'),
172 'mocache' => esc_html__('WordPress Translation Caching', 'docket-cache'),
173 'misc_tweaks' => esc_html__('Misc Performance Tweaks', 'docket-cache'),
174 'postmissedschedule' => esc_html__('Post Missed Schedule Tweaks', 'docket-cache'),
175 'wootweaks' => esc_html__('Misc WooCommerce Tweaks', 'docket-cache'),
176 'wooadminoff' => esc_html__('Deactivate WooCommerce Admin', 'docket-cache'),
177 'woowidgetoff' => esc_html__('Deactivate WooCommerce Classic Widget', 'docket-cache'),
178 'woowpdashboardoff' => esc_html__('Deactivate WooCommerce WP Dashboard', 'docket-cache'),
179 'wooextensionpageoff' => esc_html__('Deactivate WooCommerce Extensions Page', 'docket-cache'),
180 'woocartfragsoff' => esc_html__('Deactivate WooCommerce Cart Fragments', 'docket-cache'),
181 'wooaddtochartcrawling' => esc_html__('Prevent robots crawling add-to-cart links', 'docket-cache'),
182 'pageloader' => esc_html__('Admin Page Loader', 'docket-cache'),
183 'wpoptaload' => esc_html__('Suspend WP Options Autoload', 'docket-cache'),
184 'cronoptmzdb' => esc_html__('Optimize Database Tables', 'docket-cache'),
185 'cronbot' => esc_html__('Cronbot Service', 'docket-cache'),
186 'opcviewer' => esc_html__('OPcache Viewer', 'docket-cache'),
187 'stats' => esc_html__('Object Cache Data Stats', 'docket-cache'),
188 'gcaction' => esc_html__('Garbage Collector Action Button', 'docket-cache'),
189 'flushaction' => esc_html__('Additional Flush Cache Action Button', 'docket-cache'),
190 'configaction' => esc_html__('Export/Import Settings Action Button', 'docket-cache'),
191 'autoupdate_toggle' => esc_html__('Docket Cache Auto Update', 'docket-cache'),
192 'checkversion' => esc_html__('Critical Version Checking', 'docket-cache'),
193 'optwpquery' => esc_html__('Optimize WP Query', 'docket-cache'),
194 'limitbulkedit' => esc_html__('Limit Bulk Edit Actions', 'docket-cache'),
195 'pingback' => esc_html__('Deactivate XML-RPC / Pingbacks', 'docket-cache'),
196 'headerjunk' => esc_html__('Deactivate WP Header Junk', 'docket-cache'),
197 'wpemoji' => esc_html__('Deactivate WP Emoji', 'docket-cache'),
198 'wpembed' => esc_html__('Deactivate WP Embed', 'docket-cache'),
199 'wpfeed' => esc_html__('Deactivate WP Feed', 'docket-cache'),
200 'wplazyload' => esc_html__('Deactivate WP Lazy Load', 'docket-cache'),
201 'wpsitemap' => esc_html__('Deactivate WP Sitemap', 'docket-cache'),
202 'wpapppassword' => esc_html__('Deactivate WP Application Passwords', 'docket-cache'),
203 'wpdashboardnews' => esc_html__('Deactivate WP Events & News Feed Dashboard', 'docket-cache'),
204 'wpbrowsehappy' => esc_html__('Deactivate Browse Happy Checking', 'docket-cache'),
205 'wpservehappy' => esc_html__('Deactivate Serve Happy Checking', 'docket-cache'),
206 'postviaemail' => esc_html__('Deactivate Post Via Email', 'docket-cache'),
207 'objectcacheoff' => esc_html__('Suspend Object Cache', 'docket-cache'),
208 'flush_shutdown' => esc_html__('Flush Object Cache During Deactivation', 'docket-cache'),
209 'opcshutdown' => esc_html__('Flush OPcache During Deactivation', 'docket-cache'),
210 'maxsize_disk' => esc_html__('Cache Disk Limit', 'docket-cache'),
211 'maxfile' => esc_html__('Cache Files Limit', 'docket-cache'),
212 'maxfile_livecheck' => esc_html__('Real-time File Limit Checking', 'docket-cache'),
213 'chunkcachedir' => esc_html__('Chunk Cache Directory', 'docket-cache'),
214 'flush_stalecache' => esc_html__('Auto Remove Stale Cache', 'docket-cache'),
215 'stalecache_ignore' => esc_html__('Exclude Stale Cache', 'docket-cache'),
216 'emptycache_ignore' => esc_html__('Exclude Empty Object Data', 'docket-cache'),
217 'transientdb' => esc_html__('Retain Transients in Db', 'docket-cache'),
218 'limithttprequest' => esc_html__('Limit WP-Admin HTTP requests', 'docket-cache'),
219 'rtpostautosave' => esc_html__('Auto Save Interval', 'docket-cache'),
220 'rtpostrevision' => esc_html__('Post Revisions', 'docket-cache'),
221 'rtpostemptytrash' => esc_html__('Trash Bin', 'docket-cache'),
222 'rtpluginthemeeditor' => esc_html__('Disallows Plugin / Theme Editor', 'docket-cache'),
223 'rtpluginthemeinstall' => esc_html__('Disallows Plugin / Theme Update and Installation', 'docket-cache'),
224 'rtimageoverwrite' => esc_html__('Cleanup Image Edits', 'docket-cache'),
225 'rtwpdebug' => esc_html__('WP Debug', 'docket-cache'),
226 'rtwpdebugdisplay' => esc_html__('WP Debug Display', 'docket-cache'),
227 'rtwpdebuglog' => esc_html__('WP Debug Log', 'docket-cache'),
228 'rtwpcoreupdate' => esc_html__('Disallows WP Auto Update Core', 'docket-cache'),
229 'rtconcatenatescripts' => esc_html__('Deactivate Concatenate WP-Admin Scripts', 'docket-cache'),
230 'rtdisablewpcron' => esc_html__('Deactivate WP Cron', 'docket-cache'),
231 ];
232
233 if (version_compare($GLOBALS['wp_version'], '6.1', '<')) {
234 $data['advcpost'] = esc_html__('Advanced Post Caching', 'docket-cache');
235 $data['advpost_posttype_all'] = esc_html__('Post Caching Any Post Type', 'docket-cache');
236 }
237
238 if (version_compare($GLOBALS['wp_version'], '5.8', '<')) {
239 $data['httpheadersexpect'] = esc_html__('HTTP Request Expect header tweaks', 'docket-cache');
240 }
241
242 $data = apply_filters('docketcache/filter/optionkeys', $data);
243
244 if (false !== $key) {
245 if (!empty($data[$key])) {
246 return $data[$key];
247 }
248
249 return false;
250 }
251
252 return array_keys($data);
253 }
254
255 public function read_config($file = '', $force = false)
256 {
257 $file = empty($file) ? $this->file : $file;
258 $config = [];
259 if (@is_file($file) && is_readable($file)) {
260 // fresh
261 if ($force) {
262 $this->opcache_flush($file);
263 }
264
265 try {
266 $config = @include $file;
267 } catch (\Throwable $e) {
268 nwdcx_throwable(__METHOD__, $e);
269 }
270 }
271
272 return $config;
273 }
274
275 public function put_config($config, $file = '')
276 {
277 $file = empty($file) ? $this->file : $file;
278 if (empty($config) || !\is_array($config)) {
279 if (@is_file($file) && @is_writable($file)) {
280 @unlink($file);
281 }
282
283 clearstatcache();
284
285 return false;
286 }
287
288 $data = $this->export_var($config);
289 $code = $this->code_stub($data);
290
291 return $this->dump($file, $code);
292 }
293
294 public function config_cleanup($config)
295 {
296 if (!empty($config) && \is_array($config)) {
297 $names = $this->key_names();
298 foreach ($config as $name => $value) {
299 $nx = strtolower(nwdcx_constfx($name, true));
300 if (!\in_array($nx, $names) || (\is_string($value) && 'default' === $value)) {
301 unset($config[$name]);
302 }
303 }
304 }
305
306 return $config;
307 }
308
309 public function get($name)
310 {
311 $config = $this->read_config();
312
313 if (!empty($config) && !empty($config[$name])) {
314 return $config[$name];
315 }
316
317 return false;
318 }
319
320 public function save($name, $value, $do_action = true)
321 {
322 if (!$this->mkdir_p($this->path)) {
323 return false;
324 }
325
326 $this->placeholder($this->path);
327
328 $config = $this->read_config();
329 $config = $this->config_cleanup($config);
330
331 if (\in_array($name, $this->key_names())) {
332 $nx = nwdcx_constfx($name);
333
334 if ('default' === $value) {
335 unset($config[$nx]);
336 } else {
337 $config[$nx] = $value;
338 }
339 }
340
341 $ret = $this->put_config($config);
342
343 if ($do_action) {
344 do_action('docketcache/action/saveoption', $name, $value, $ret);
345 }
346
347 return $ret;
348 }
349
350 public function save_part($data, $file = 'part')
351 {
352 $file = $this->path.'/'.$file.'.php';
353
354 return $this->put_config($data, $file);
355 }
356
357 public function get_part($file = 'part', $force = false)
358 {
359 $file = $this->path.'/'.$file.'.php';
360
361 return $this->read_config($file, $force);
362 }
363
364 public function clear_part($file)
365 {
366 $file = $this->path.'/'.$file.'.php';
367 if (!@is_file($file)) {
368 return true;
369 }
370
371 $ret = @unlink($file);
372 clearstatcache();
373
374 return $ret;
375 }
376
377 public function clear_lock()
378 {
379 $path = $this->path_lock;
380 if (!@is_dir($path)) {
381 return false;
382 }
383
384 $files = @glob($path.'/lock-*.txt', \GLOB_MARK | \GLOB_NOSORT);
385 if (!empty($files) && \is_array($files)) {
386 foreach ($files as $file) {
387 if (@is_file($file) && @is_writable($file)) {
388 nwdcx_cliverbose(basename($file)."\n");
389 @unlink($file);
390 }
391 }
392 }
393
394 $files = @glob($path.'/dump_*.txt', \GLOB_MARK | \GLOB_NOSORT);
395 if (!empty($files) && \is_array($files)) {
396 foreach ($files as $file) {
397 if (@is_file($file) && @is_writable($file)) {
398 @unlink($file);
399 }
400 }
401 }
402
403 clearstatcache();
404
405 return true;
406 }
407
408 private function lock_file($key)
409 {
410 $key = substr(md5($key), 0, 12);
411 $path = $this->path_lock;
412 if (!$this->mkdir_p($path.'/')) {
413 return false;
414 }
415 $this->placeholder($path);
416
417 return $path.'/lock-'.$key.'.txt';
418 }
419
420 public function setlock($key, $value)
421 {
422 $file = $this->lock_file($key);
423 if (!$file) {
424 return false;
425 }
426
427 if (true === $this->dump($file, $value)) {
428 return true;
429 }
430
431 return false;
432 }
433
434 public function unlock($key)
435 {
436 $file = $this->lock_file($key);
437 if (!$file || !@is_file($file)) {
438 return true;
439 }
440
441 $ret = @unlink($file);
442 clearstatcache();
443
444 return $ret;
445 }
446
447 public function locked($key, &$value = '')
448 {
449 clearstatcache();
450
451 $file = $this->lock_file($key);
452 if (!$file || !@is_file($file)) {
453 return false;
454 }
455
456 $value = @file_get_contents($file);
457
458 return true;
459 }
460
461 // locked and not expire
462 public function lockexp($key)
463 {
464 if ($this->locked($key, $locked)) {
465 if (!empty($locked) && (int) $locked > time()) {
466 return true;
467 }
468 }
469
470 return false;
471 }
472
473 // lock process
474 public function lockproc($key, $value)
475 {
476 // if locked and not expire
477 if ($this->lockexp($key)) {
478 return true;
479 }
480
481 // if expire set new lock
482 $this->setlock($key, $value);
483
484 return false;
485 }
486
487 public function lockreset($key)
488 {
489 return $this->setlock($key, 0);
490 }
491
492 // lookup
493 public function lookup_set($key, $value)
494 {
495 $fkey = 'lockup-'.$key;
496
497 return $this->setlock($fkey, maybe_serialize($value));
498 }
499
500 public function lookup_get($key, $forget = false)
501 {
502 $fkey = 'lockup-'.$key;
503 if ($this->locked($fkey, $value)) {
504 if (!empty($value)) {
505 if ($forget) {
506 $this->lookup_delete($key);
507 }
508
509 return maybe_unserialize($value);
510 }
511 }
512
513 if ($forget) {
514 $this->lookup_delete($key);
515 }
516
517 return false;
518 }
519
520 public function lookup_delete($key)
521 {
522 $fkey = 'lockup-'.$key;
523
524 return $this->unlock($fkey);
525 }
526
527 public function export_config()
528 {
529 $config = $this->read_config();
530 $config = $this->config_cleanup($config);
531
532 if (empty($config) || !\is_array($config)) {
533 return false;
534 }
535
536 // Strip DOCKET_CACHE_ prefix for cleaner export.
537 $export = [];
538 foreach ($config as $name => $value) {
539 $key = strtolower(nwdcx_constfx($name, true));
540 $export[$key] = $value;
541 }
542
543 return $export;
544 }
545
546 public function import_config($data)
547 {
548 if (empty($data) || !\is_array($data)) {
549 return false;
550 }
551
552 if (!$this->mkdir_p($this->path)) {
553 return false;
554 }
555
556 $this->placeholder($this->path);
557
558 $valid_keys = $this->key_names();
559 $config = [];
560
561 foreach ($data as $name => $value) {
562 $name = strtolower($name);
563 if (!\in_array($name, $valid_keys)) {
564 continue;
565 }
566
567 // Only accept scalar values.
568 if (!\is_scalar($value)) {
569 continue;
570 }
571
572 $value = (string) $value;
573
574 // Cap value length to prevent abuse.
575 if (\strlen($value) > 256) {
576 continue;
577 }
578
579 if ('default' !== $value) {
580 $nx = nwdcx_constfx($name);
581 $config[$nx] = $value;
582 }
583 }
584
585 if (empty($config)) {
586 return false;
587 }
588
589 return $this->put_config($config);
590 }
591
592 public function reset()
593 {
594 $this->clear_lock();
595
596 $parts = [
597 'options',
598 'runtime',
599 'pings',
600 'cronbot',
601 'checkversion',
602 'cachestats',
603 'gc',
604 ];
605
606 $ok = true;
607 foreach ($parts as $part) {
608 $file = $this->path.'/'.$part.'.php';
609 if (@is_file($file) && is_writable($file)) {
610 if (!@unlink($file)) {
611 $ok = false;
612 }
613 }
614 }
615
616 clearstatcache(true);
617
618 return $ok;
619 }
620 }
621