/home/arranoyd/energyclinic/wp-content/plugins/docket-cache/includes/src/Event.php
<?php
/**
* Docket Cache.
*
* @author Nawawi Jamili
* @license MIT
*
* @see https://github.com/nawawi/docket-cache
*/
namespace Nawawi\DocketCache;
\defined('ABSPATH') || exit;
final class Event
{
private $pt;
private $is_optimizedb;
private $max_execution_time = 0;
private $wp_start_timestamp = 0;
public function __construct(Plugin $pt)
{
$this->pt = $pt;
$this->is_optimizedb = false;
$this->wp_start_timestamp = \defined('WP_START_TIMESTAMP') ? WP_START_TIMESTAMP : microtime(true);
$this->max_execution_time = $this->pt->get_max_execution_time();
}
/**
* register.
*/
public function register()
{
// global
add_filter('docketcache/filter/garbagecollector', [$this, 'garbage_collector']);
add_filter(
'cron_schedules',
function ($schedules) {
$schedules['halfhour'] = [
'interval' => 30 * MINUTE_IN_SECONDS,
'display' => esc_html__('Every 30 Minutes', 'docket-cache'),
];
if (empty($schedules['hourly'])) {
$schedules['hourly'] = [
'interval' => HOUR_IN_SECONDS,
'display' => esc_html__('Once Hourly', 'docket-cache'),
];
}
if (empty($schedules['monthly'])) {
$schedules['monthly'] = [
'interval' => MONTH_IN_SECONDS,
'display' => esc_html__('Once Monthly', 'docket-cache'),
];
}
$schedules['docketcache_gc_schedule'] = [
'interval' => 5 * MINUTE_IN_SECONDS,
'display' => esc_html__('Every 5 Minutes', 'docket-cache'),
];
$schedules['docketcache_checkversion_schedule'] = [
'interval' => 15 * DAY_IN_SECONDS,
'display' => esc_html__('Every 15 Days', 'docket-cache'),
];
return $schedules;
},
\PHP_INT_MAX
);
add_action(
'plugins_loaded',
function () {
// 19092020: standardize. rename hooks.
// 19012023: remove docketcache_watchproc.
foreach (['docket_cache_gc', 'docket_cache_optimizedb', 'docket_cache_monitor', 'docketcache_watchproc'] as $hx) {
if (false !== wp_get_scheduled_event($hx)) {
wp_clear_scheduled_hook($hx);
}
}
// garbage collector
// 27012023: added disable constant
if ($this->pt->cf()->is_dcfalse('GCRON_DISABLED')) {
add_action('docketcache_gc', [$this, 'garbage_collector']);
if (!wp_next_scheduled('docketcache_gc')) {
wp_schedule_event(time(), 'docketcache_gc_schedule', 'docketcache_gc');
}
} else {
if (wp_get_schedule('docketcache_gc')) {
wp_clear_scheduled_hook('docketcache_gc');
}
}
// optimize db
$cronoptmzdb = $this->pt->cf()->dcvalue('CRONOPTMZDB');
if (!empty($cronoptmzdb) && 'never' !== $cronoptmzdb && is_main_site()) {
$recurrence = '';
switch ($cronoptmzdb) {
case 'daily':
$recurrence = 'daily';
break;
case 'weekly':
$recurrence = 'weekly';
break;
case 'monthly':
$recurrence = 'monthly';
break;
}
if (empty($recurrence)) {
wp_clear_scheduled_hook('docketcache_optimizedb');
} else {
$this->is_optimizedb = true;
add_action('docketcache_optimizedb', [$this, 'optimizedb']);
if (!wp_next_scheduled('docketcache_optimizedb')) {
wp_schedule_event(time(), $recurrence, 'docketcache_optimizedb');
}
}
} else {
if (wp_get_schedule('docketcache_optimizedb')) {
wp_clear_scheduled_hook('docketcache_optimizedb');
}
}
// check version
if ($this->pt->cf()->is_dctrue('CHECKVERSION', true)) {
// 06102020: reset old schedule
$check = wp_get_scheduled_event('docketcache_checkversion');
if (\is_object($check) && 'docketcache_checkversion_schedule' !== $check->schedule) {
wp_clear_scheduled_hook('docketcache_checkversion');
}
if (is_main_site() && is_main_network()) {
add_action('docketcache_checkversion', [$this, 'checkversion']);
if (!wp_next_scheduled('docketcache_checkversion')) {
wp_schedule_event(time(), 'docketcache_checkversion_schedule', 'docketcache_checkversion');
}
}
} else {
if (wp_get_schedule('docketcache_checkversion')) {
wp_clear_scheduled_hook('docketcache_checkversion');
}
}
// expired transient in DB
if (has_action('delete_expired_transients') && wp_using_ext_object_cache()) {
add_action('delete_expired_transients', [$this, 'delete_expired_transients_db']);
}
}
);
}
/**
* unregister.
*/
public function unregister()
{
foreach (['docketcache_gc', 'docketcache_optimizedb', 'docketcache_watchproc', 'docketcache_checkversion'] as $hx) {
wp_clear_scheduled_hook($hx);
}
}
/**
* reset.
*/
public function reset()
{
$this->unregister();
$this->register();
}
/**
* garbage_collector.
*/
public function garbage_collector($force = false)
{
static $is_done = false;
$maxfile_default = (int) $this->pt->get_cache_maxfile();
$maxfile = $maxfile_default;
if ($maxfile_default > 10000) {
$maxfile = $maxfile_default - 1000;
}
$maxfile_precache_default = (int) $this->pt->get_precache_maxfile();
$maxfile_precache = $maxfile_precache_default;
if ($maxfile_precache_default > 10000) {
$maxfile_precache = $maxfile_precache_default - 1000;
}
$maxttl_default = (int) $this->pt->get_cache_maxttl();
$maxttl = $maxttl_default;
if (!empty($maxttl)) {
$maxttl = time() - $maxttl;
}
$chkmaxdisk = false;
$maxsizedisk_default = (int) $this->pt->get_cache_maxsize_disk();
$maxsizedisk = $maxsizedisk_default;
if (!empty($maxsizedisk)) {
$maxsizedisk = $maxsizedisk - 1048576;
if ($maxsizedisk > 1048576) {
$chkmaxdisk = true;
}
}
$collect = (object) [
'is_locked' => false,
'cache_maxttl' => $maxttl_default,
'cache_maxfile' => $maxfile_default,
'cache_maxdisk' => $maxsizedisk_default,
'cleanup_maxfile' => 0,
'cleanup_precache_maxfile' => 0,
'cleanup_maxttl' => 0,
'cleanup_expire' => 0,
'cleanup_maxdisk' => 0,
'cache_file' => 0,
'cache_cleanup' => 0,
'cache_ignore' => 0,
'cleanup_failed' => 0,
'cleanup_stalecache' => 0,
];
clearstatcache();
if (!$this->pt->is_docketcachedir($this->pt->cache_path) || @is_file(DOCKET_CACHE_CONTENT_PATH.'/.object-cache-flush.txt')) {
$collect->is_locked = true;
return $collect;
}
// try to set max execution time to 3 minutes if not 0 or lower than 180 seconds.
$max_execution_time = $this->pt->get_max_execution_time(180);
// lock process.
$lock_expiry = $max_execution_time > 0 ? $max_execution_time : 180;
$lock_expiry = time() + $lock_expiry;
if ($is_done || $this->pt->co()->lockproc('garbage_collector', $lock_expiry)) {
$collect->is_locked = true;
return $collect;
}
// Stalecache
$is_flush_stalecache = $this->pt->cf()->is_dctrue('FLUSH_STALECACHE', true);
$is_ignore_stalecache = $this->pt->cf()->is_dctrue('STALECACHE_IGNORE', true);
$wp_cache_last_changed = [];
$wp_cache_last_changed_match = [
'posts' => 'wp_query',
'terms' => 'get_terms',
'comment' => 'get_comments',
'sites' => 'get_sites',
'networks' => 'get_network_ids',
];
foreach ($wp_cache_last_changed_match as $grp => $kk) {
$wp_cache_last_changed[$grp] = wp_cache_get_last_changed($grp);
// wp >= 6.3
// remove ending 's' -> posts = post-queries.
$grpq = strtok($grp, 's').'-queries';
$wp_cache_last_changed[$grpq] = $wp_cache_last_changed[$grp];
}
$wp_cache_last_changed['advpost'] = wp_cache_get('cache_incr', 'docketcache-post');
$wc_has_cache_helper = method_exists('WC_Cache_Helper', 'get_cache_prefix');
$wc_session_cache_group = \defined('WC_SESSION_CACHE_GROUP') ? WC_SESSION_CACHE_GROUP : 'wc_session_id';
$delay = $force ? 650 : 5000;
if ('cli' === \PHP_SAPI) {
$delay = 100;
}
// hold cache write
$this->pt->suspend_cache_write(true);
$filesize_total = 0;
$file_cache_count = 0;
$file_precache_count = 0;
$bytes_total = 0;
$slowdown = 0;
$gcisrun_lock = $this->pt->cache_path.'/.gc-is-run.txt';
$this->pt->touch($gcisrun_lock);
foreach ($this->pt->scanfiles($this->pt->cache_path) as $object) {
if ($max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $max_execution_time) {
break;
}
if ($slowdown > 10) {
$slowdown = 0;
usleep($delay);
}
++$slowdown;
try {
if (!$object->isFile()) {
++$collect->cache_ignore;
continue;
}
$fx = $object->getPathName();
$fn = $object->getFileName();
$fs = $object->getSize();
$fm = time() + 300;
$ft = filemtime($fx);
$this->pt->remove_non_chunk_cache($this->pt->cache_path, $fx);
} catch (\Throwable $e) {
nwdcx_throwable(__METHOD__, $e);
continue;
}
nwdcx_cliverbose('run-gc: '.$fx."\n");
if ($fm >= $ft && (0 === $fs || 'dump_' === substr($fn, 0, 5))) {
$this->pt->unlink($fx, true);
if ($force && @is_file($fx)) {
++$collect->cleanup_failed;
}
continue;
}
// 03022023: timeout 0 was set to maxtll, see WP_Object_Cache::maybe_expire
// cleanup first to reduce memory usage
if ($maxttl > 0 && $maxttl > $ft) {
$this->pt->unlink($fx, true);
if ($force && @is_file($fx)) {
++$collect->cleanup_failed;
}
++$collect->cleanup_maxttl;
continue;
}
// 032e9f2c5b60- = docketcache-precache-
if ($maxfile_precache > 0 && '032e9f2c5b60-' === substr($fn, 0, 13)) {
++$file_precache_count;
if ($file_precache_count > $maxfile_precache) {
$this->pt->unlink($fx, true);
if ($force && @is_file($fx)) {
++$collect->cleanup_failed;
}
++$collect->cleanup_precache_maxfile;
continue;
}
}
if ($file_cache_count >= $maxfile) {
$this->pt->unlink($fx, true);
if ($force && @is_file($fx)) {
++$collect->cleanup_failed;
}
++$collect->cleanup_maxfile;
continue;
}
if ($chkmaxdisk && $filesize_total > $maxsizedisk) {
$this->pt->unlink($fx, true);
if ($force && @is_file($fx)) {
++$collect->cleanup_failed;
}
++$collect->cleanup_maxdisk;
continue;
}
$data = $this->pt->cache_get($fx);
$is_timeout = false;
if (false !== $data) {
unset($data['data']);
$is_timeout = !empty($data['timeout']) && $this->pt->valid_timestamp($data['timeout']) ? true : false;
if ($is_timeout) {
if ($fm >= (int) $data['timeout']) {
$this->pt->unlink($fx, true);
if ($force && @is_file($fx)) {
++$collect->cleanup_failed;
}
unset($data);
++$collect->cleanup_expire;
continue;
}
} else {
if (!empty($data['timestamp']) && $this->pt->valid_timestamp($data['timestamp']) && $maxttl > $data['timestamp']) {
$this->pt->unlink($fx, true);
if ($force && @is_file($fx)) {
++$collect->cleanup_failed;
}
unset($data);
++$collect->cleanup_maxttl;
continue;
}
}
if ($is_flush_stalecache) {
// wp stale cache
// wp >= 6.3
if ($is_ignore_stalecache && $this->pt->is_wp_cache_group_queries($data['group'])) {
if (@unlink($fx)) {
clearstatcache(true, $fx);
nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n");
++$collect->cleanup_stalecache;
continue;
}
}
// wp stale cache
// prefix:hash:timestamp timestamp
if (!empty($wp_cache_last_changed_match[$data['group']]) && preg_match('@^(wp_query|get_terms|get_comments|comment_feed|get_sites|get_network_ids|get_page_by_path|adjacent_post|wp_get_archives):([0-9a-f]{32}):([0-9\. ]{21})([0-9\. ]+)?$@', $data['key'], $mm)) {
// main type
switch ($mm[1]) {
case 'get_page_by_path':
case 'adjacent_post':
$mm[1] = 'wp_query';
break;
case 'comment_feed':
$mm[1] = 'get_comments';
break;
}
$km = $wp_cache_last_changed_match[$data['group']];
if (($km === $mm[1] && $wp_cache_last_changed[$data['group']] !== $mm[3]) || $is_ignore_stalecache) {
if (@unlink($fx)) {
clearstatcache(true, $fx);
nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n");
++$collect->cleanup_stalecache;
continue;
}
}
}
// wp stale cache
// get_comment_child_ids:int:hash:timestamp timestamp
// get_comment_child_ids:1654:5247020d1a40e3b2e9a40de1139bc5c9:0.48761900 1678553206
if (!empty($wp_cache_last_changed_match[$data['group']]) && preg_match('@^(get_comment_child_ids):(\d+):([0-9a-f]{32}):([0-9\. ]{21})([0-9\. ]+)?$@', $data['key'], $mm)) {
$mm[1] = 'get_comments';
$km = $wp_cache_last_changed_match[$data['group']];
if (($km === $mm[1] && $wp_cache_last_changed[$data['group']] !== $mm[4]) || $is_ignore_stalecache) {
if (@unlink($fx)) {
clearstatcache(true, $fx);
nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n");
++$collect->cleanup_stalecache;
continue;
}
}
}
// advpost stale cache
if (false !== strpos($data['group'], 'docketcache-post-') && preg_match('@^docketcache-post-(\d+)$@', $data['group'], $mm)) {
if ((int) $wp_cache_last_changed['advpost'] !== (int) $mm[1] || $is_ignore_stalecache) {
if (@unlink($fx)) {
clearstatcache(true, $fx);
nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n");
++$collect->cleanup_stalecache;
continue;
}
}
}
// wc stale cache
if (false !== strpos($data['key'], 'wc_cache_') && preg_match('@^(wc_cache_[0-9\. ]+_)@', $data['key'], $mm)) {
if (!$wc_has_cache_helper || $is_ignore_stalecache) {
if (@unlink($fx)) {
clearstatcache(true, $fx);
nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n");
++$collect->cleanup_stalecache;
}
continue;
}
$current_prefix = $mm[1];
static $cache_prefix_cached = [];
// wc product
if ('products' === $data['group'] && preg_match('@.*?_type_(\d+)$@', $data['key'], $nn)) {
$grp = 'product_'.$nn[1];
if (!empty($cache_prefix_cached[$grp])) {
$cache_prefix = $cache_prefix_cached;
} else {
$cache_prefix = \WC_Cache_Helper::get_cache_prefix($grp);
$cache_prefix_cached[$grp] = $cache_prefix;
}
if ($cache_prefix !== $current_prefix) {
if (@unlink($fx)) {
clearstatcache(true, $fx);
nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n");
++$collect->cleanup_stalecache;
continue;
}
}
}
if (\in_array($data['group'],
[
'products', 'coupons', 'orders', 'webhooks', 'taxes', 'shipping_zones',
'woocommerce-attributes', 'store_api_rate_limit', $wc_session_cache_group,
])) {
$grp = $data['group'];
if (!empty($cache_prefix_cached[$grp])) {
$cache_prefix = $cache_prefix_cached;
} else {
$cache_prefix = \WC_Cache_Helper::get_cache_prefix($grp);
$cache_prefix_cached[$grp] = $cache_prefix;
}
if ($cache_prefix !== $current_prefix) {
if (@unlink($fx)) {
clearstatcache(true, $fx);
nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n");
++$collect->cleanup_stalecache;
continue;
}
}
}
if ('wc_rate_limit' === $data['group'] && 'rate_limit' === substr($data['key'], 0, 10)) {
$grp = $data['group'];
if (!empty($cache_prefix_cached[$grp])) {
$cache_prefix = $cache_prefix_cached;
} else {
$cache_prefix = \WC_Cache_Helper::get_cache_prefix($grp);
$cache_prefix_cached[$grp] = $cache_prefix;
}
if ($cache_prefix !== $current_prefix) {
if (@unlink($fx)) {
clearstatcache(true, $fx);
nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n");
++$collect->cleanup_stalecache;
continue;
}
}
}
}
}
$bytes_total += \strlen(serialize($data));
} // data
// no timeout data or 0
// 03022023: timeout 0 was set to maxtll, see WP_Object_Cache::maybe_expire
/*if (false === $is_timeout && $maxttl > 0 && $maxttl > $ft) {
$this->pt->unlink($fx, true);
if ($force && @is_file($fx)) {
++$collect->cleanup_failed;
}
++$collect->cleanup_maxttl;
continue;
}*/
unset($data);
$filesize_total += $fs;
++$file_cache_count;
} // foreach1
@unlink($gcisrun_lock);
$collect->cache_file = $file_cache_count;
$collect->cache_cleanup = $collect->cleanup_maxttl + $collect->cleanup_expire + $collect->cleanup_maxfile + $collect->cleanup_maxdisk + $collect->cleanup_precache_maxfile + $collect->cleanup_stalecache;
// release
$this->pt->suspend_cache_write(false);
if ($this->pt->cf()->is_dcfalse('TRANSIENTDB') && \function_exists('nwdcx_cleanuptransient')) {
nwdcx_cliverbose("run-gc: cleanup expired transients in DB\n");
nwdcx_cleanuptransient();
}
// reset gc
$count_file = $collect->cache_file;
$count_file = $count_file < 0 ? 0 : $count_file;
wp_cache_set('count_file', $count_file, 'docketcache-gc', 86400);
// reset precache
$count_file = $file_precache_count - $collect->cleanup_precache_maxfile;
$count_file = $count_file < 0 ? 0 : $count_file;
wp_cache_set('count_file', $count_file, 'docketcache-precache-gc', 86400);
// stats
$this->pt->co()->save_part([
'timestamp' => time(),
'size' => $bytes_total,
'filesize' => $filesize_total,
'files' => $collect->cache_file,
], 'cachestats');
// done
$this->pt->co()->lockreset('garbage_collector');
$this->pt->cx()->delay_expire();
$is_done = true;
return $collect;
}
/**
* optimizedb.
*/
public function optimizedb()
{
if (!nwdcx_wpdb($wpdb)) {
return false;
}
if ($this->pt->co()->lockproc('optimizedb', time() + 3600)) {
return false;
}
$suppress = $wpdb->suppress_errors(true);
@set_time_limit(300);
$max_execution_time = $this->pt->get_max_execution_time();
$this->delete_expired_transients_db();
if (is_main_site() && is_main_network()) {
$dbname = $wpdb->dbname;
$tables = $wpdb->get_results('SHOW TABLES FROM '.$dbname, ARRAY_A);
if (!empty($tables) && \is_array($tables)) {
foreach ($tables as $table) {
$tbl = $table['Tables_in_'.$dbname];
$sql = 'OPTIMIZE TABLE `'.$tbl.'`';
$ret = $wpdb->query($sql);
nwdcx_cliverbose(str_replace('`', '', $sql)."\n");
if ($max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $max_execution_time) {
break;
}
}
}
unset($tables);
}
$wpdb->suppress_errors($suppress);
$this->pt->co()->lockreset('optimizedb');
return true;
}
/**
* delete_expired_transients_db.
*/
public function delete_expired_transients_db()
{
if (!nwdcx_wpdb($wpdb)) {
return false;
}
if ($this->pt->cf()->is_dcfalse('TRANSIENTDB') && \function_exists('nwdcx_cleanuptransient')) {
nwdcx_cleanuptransient();
} elseif (\function_exists('delete_expired_transients')) {
delete_expired_transients(true);
}
return true;
}
/**
* checkversion.
*/
public function checkversion()
{
if (!is_main_site()) {
return false;
}
$part = 'checkversion';
if ($this->pt->co()->lockproc($part, time() + 3600)) {
return false;
}
$checkdata = $this->pt->co()->get_part($part, true);
if (!empty($checkdata) && \is_array($checkdata) && !empty($checkdata['selfcheck'])) {
$selfcheck = $checkdata['selfcheck'];
if (0 === $this->pt->sanitize_timestamp($selfcheck)) {
return false;
}
if ($selfcheck > 0 && $selfcheck > time()) {
return false;
}
}
$main_site_url = $this->pt->site_url();
$site_url = $this->pt->site_url(true);
$home_url = $this->pt->site_url(true, true);
$stmp = time() + 120;
$api_endpoint = $this->pt->api_endpoint.'/'.$part.'?v='.$stmp;
$args = [
'blocking' => true,
'body' => [
'timestamp' => date('Y-m-d H:i:s T'),
'timezone' => wp_timezone_string(),
'site' => $site_url,
'token' => $this->pt->nw_encrypt($main_site_url, md5($site_url)),
'meta' => $this->pt->site_meta(),
],
'headers' => [
'REFERER' => $home_url,
'Cache-Control' => 'no-cache',
],
];
$results = Crawler::post($api_endpoint, $args);
$output = [
'timestamp' => time(),
'endpoint' => $api_endpoint,
'request' => [
'headers' => $args['headers'],
'content' => $args['body'],
],
'selfcheck' => time() + 86400,
];
if (is_wp_error($results)) {
$output['error'] = $results->get_error_message();
$this->pt->co()->save_part($output, $part);
return false;
}
$output['response'] = wp_remote_retrieve_body($results);
if (!empty($output['response'])) {
$output['response'] = json_decode($output['response'], true);
if (\JSON_ERROR_NONE === json_last_error()) {
if (!empty($output['response']['error'])) {
$output['error'] = $output['response']['error'];
$this->pt->co()->save_part($output, $part);
return false;
}
}
}
$code = (int) wp_remote_retrieve_response_code($results);
if ($code > 400) {
$output['error'] = $code;
$this->pt->co()->save_part($output, $part);
return false;
}
$this->pt->co()->save_part($output, $part);
$this->pt->co()->lockreset($part);
return true;
}
}