File: /dom877180/wp-content/mu-plugins/object-cache-pro/src/Plugin/Lifecycle.php
<?php
/**
* Copyright © 2019-2026 Rhubarb Tech Inc. All Rights Reserved.
*
* The Object Cache Pro Software and its related materials are property and confidential
* information of Rhubarb Tech Inc. Any reproduction, use, distribution, or exploitation
* of the Object Cache Pro Software and its related materials, in whole or in part,
* is strictly forbidden unless prior permission is obtained from Rhubarb Tech Inc.
*
* In addition, any reproduction, use, distribution, or exploitation of the Object Cache Pro
* Software and its related materials, in whole or in part, is subject to the End-User License
* Agreement accessible in the included `LICENSE` file, or at: https://objectcache.pro/eula
*/
declare(strict_types=1);
namespace RedisCachePro\Plugin;
use Exception;
/**
* @mixin \RedisCachePro\Plugin
*/
trait Lifecycle
{
/**
* Boot lifecycle component and register hooks.
*
* @return void
*/
public function bootLifecycle()
{
add_action('init', [$this, 'run']);
add_action("deactivate_{$this->basename}", [$this, 'deactivate']);
add_action("uninstall_{$this->basename}", [$this, 'uninstall']);
add_action('pre_uninstall_plugin', [$this, 'beforeUninstall']);
add_filter('pre_objectcache_flush', [$this, 'maybeLogFlush'], PHP_INT_MAX);
add_filter('pre_objectcache_flush_group', [$this, 'maybeLogGroupFlush'], PHP_INT_MAX, 2);
}
/**
* Called when initializing WordPress.
*
* @return void
*/
public function run()
{
$this->maybeLogEarlyFlushes();
if (is_admin() && ! wp_doing_ajax()) {
$this->killSwitch($this->license(true));
}
}
/**
* Called by `deactivate_{$plugin}` hook.
*
* @return void
*/
public function deactivate()
{
delete_site_option('objectcache_license');
$this->disableDropin();
}
/**
* Called by `uninstall_{$plugin}` hook.
*
* @return void
*/
public function uninstall()
{
delete_site_option('objectcache_options');
delete_site_option('objectcache_license');
delete_site_option('objectcache_relay_license');
delete_site_option('objectcache_flushlog');
delete_site_option('objectcache_flushlog_groups');
$this->unschedule();
}
/**
* Called by `pre_uninstall_plugin` hook.
*
* @return void
*/
public function beforeUninstall()
{
$this->config->setAnalytics(false);
}
/**
* Attempt to wipe the cache on a standalone connection.
* Exceptions are caught and converted to error log messages.
*
* @param bool $write_metadata
* @return bool
*/
public function resetCache($write_metadata = true)
{
try {
$connection = $this->config->connector::connect($this->config);
$result = $connection->flushdb();
$this->logFlush(null, null, 2);
if ($write_metadata) {
$cache = new $this->config->cache($connection, $this->config);
$cache->writeMetadata(); // @phpstan-ignore-line
}
return $result;
} catch (Exception $exception) {
$this->config->logger->error($exception->getMessage());
return false;
}
}
/**
* Maybe log cache flush. Called by `pre_objectcache_flush` hook.
*
* @param bool $should_flush
* @return bool
*/
public function maybeLogFlush($should_flush)
{
if ($should_flush) {
$this->logFlush();
}
return $should_flush;
}
/**
* Maybe log cache flush. Called by `pre_objectcache_flush_group` hook.
*
* @param bool $should_flush
* @param string $group
* @return bool
*/
public function maybeLogGroupFlush($should_flush, $group)
{
if ($should_flush) {
$this->logGroupFlush($group);
}
return $should_flush;
}
/**
* Log early cache and cache group flushes, if any occurred.
*
* @return void
*/
protected function maybeLogEarlyFlushes()
{
global $wp_object_cache_flushlog;
if (! is_array($wp_object_cache_flushlog)) {
return;
}
foreach ($wp_object_cache_flushlog as $flush) {
if (! is_array($flush)) {
continue;
}
if ($flush['type'] === 'flush') {
$this->logFlush($flush['reason'] ?? null, $flush['backtrace']);
}
if ($flush['type'] === 'group-flush') {
$this->logGroupFlush($flush['group'], $flush['backtrace']);
}
}
}
/**
* Log cache flush.
*
* @param ?string $reason
* @param ?array<int, array<string, mixed>> $backtrace
* @param int $skip_frames
* @return void
*/
public function logFlush($reason = null, $backtrace = null, int $skip_frames = 1)
{
/** @var string $traceSummary */
$traceSummary = $backtrace
? $this->flushBacktraceSummary($backtrace, $skip_frames)
: wp_debug_backtrace_summary(null, $skip_frames);
if ($this->config->debug || (WP_DEBUG && WP_DEBUG_LOG)) {
$this->config->logger->debug("Flushing object cache... {$traceSummary}");
}
if (
$this->config->debug ||
$this->config->save_commands ||
WP_DEBUG ||
$this->option('flushlog')
) {
$log = (array) get_site_option('objectcache_flushlog', []);
array_unshift($log, [
'time' => time(),
'user' => get_current_user_id() ?: null,
'site' => $backtrace ? get_current_blog_id() : null,
'cron' => wp_doing_cron(),
'cli' => defined('WP_CLI') && WP_CLI,
'reason' => $reason,
'trace' => $traceSummary,
]);
/**
* Filter how many flush log entries are stored.
*
* @param int $limit Number of entries to store.
*/
$entries = (int) apply_filters('objectcache_flushlog_limit', 10);
update_site_option('objectcache_flushlog', array_slice($log, 0, $entries));
}
}
/**
* Log cache group flush.
*
* @param string $group
* @param ?array<int, array<string, mixed>> $backtrace
* @return void
*/
public function logGroupFlush($group, $backtrace = null)
{
/** @var string $traceSummary */
$traceSummary = $backtrace
? $this->flushBacktraceSummary($backtrace, 1)
: wp_debug_backtrace_summary(null, 1);
if ($this->config->debug || (WP_DEBUG && WP_DEBUG_LOG)) {
$this->config->logger->debug("Flushing object cache group `{$group}`... {$traceSummary}");
}
if (
$this->config->debug ||
$this->config->save_commands ||
WP_DEBUG ||
$this->option('groupflushlog')
) {
$log = (array) get_site_option('objectcache_flushlog_groups', []);
array_unshift($log, [
'group' => $group,
'time' => time(),
'user' => get_current_user_id() ?: null,
'site' => $backtrace ? null : get_current_blog_id(),
'cron' => wp_doing_cron(),
'cli' => defined('WP_CLI') && WP_CLI,
'trace' => $traceSummary,
]);
/**
* Filter how many flush log entries are stored.
*
* @param int $limit Number of entries to store.
*/
$entries = (int) apply_filters('objectcache_flushlog_limit', 10);
update_site_option('objectcache_flushlog_groups', array_slice($log, 0, $entries));
}
}
/**
* Simplified version of `wp_debug_backtrace_summary()`
* that supports passing in the stacktrace.
*
* @param array<int, array<string, mixed>> $trace
* @param int $skip_frames
* @return string
*/
protected function flushBacktraceSummary($trace, $skip_frames)
{
static $truncate_paths;
$caller = [];
if (! isset($truncate_paths)) {
$truncate_paths = [
wp_normalize_path(WP_CONTENT_DIR),
wp_normalize_path(ABSPATH),
];
}
foreach ($trace as $call) {
if ($skip_frames > 0) {
$skip_frames--;
} elseif (isset($call['class'])) {
$caller[] = "{$call['class']}{$call['type']}{$call['function']}";
} else {
if (in_array($call['function'], ['do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array'], true)) {
$name = $call['args'][0] ?? '';
$caller[] = "{$call['function']}('{$name}')";
} elseif (in_array($call['function'], ['include', 'include_once', 'require', 'require_once'], true)) {
$filename = $call['args'][0] ?? '';
$caller[] = $call['function'] . "('" . str_replace($truncate_paths, '', wp_normalize_path($filename)) . "')";
} else {
$caller[] = $call['function'];
}
}
}
return implode(', ', array_reverse($caller));
}
}