+ */
+class IntrospectionProcessor implements ProcessorInterface
+{
+ private $level;
+
+ private $skipClassesPartials;
+
+ private $skipStackFramesCount;
+
+ private $skipFunctions = array(
+ 'call_user_func',
+ 'call_user_func_array',
+ );
+
+ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = array(), $skipStackFramesCount = 0)
+ {
+ $this->level = Logger::toMonologLevel($level);
+ $this->skipClassesPartials = array_merge(array('WP_Rocket\Dependencies\Monolog\\'), $skipClassesPartials);
+ $this->skipStackFramesCount = $skipStackFramesCount;
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ // return if the level is not high enough
+ if ($record['level'] < $this->level) {
+ return $record;
+ }
+
+ /*
+ * http://php.net/manual/en/function.debug-backtrace.php
+ * As of 5.3.6, DEBUG_BACKTRACE_IGNORE_ARGS option was added.
+ * Any version less than 5.3.6 must use the DEBUG_BACKTRACE_IGNORE_ARGS constant value '2'.
+ */
+ $trace = debug_backtrace((PHP_VERSION_ID < 50306) ? 2 : DEBUG_BACKTRACE_IGNORE_ARGS);
+
+ // skip first since it's always the current method
+ array_shift($trace);
+ // the call_user_func call is also skipped
+ array_shift($trace);
+
+ $i = 0;
+
+ while ($this->isTraceClassOrSkippedFunction($trace, $i)) {
+ if (isset($trace[$i]['class'])) {
+ foreach ($this->skipClassesPartials as $part) {
+ if (strpos($trace[$i]['class'], $part) !== false) {
+ $i++;
+ continue 2;
+ }
+ }
+ } elseif (in_array($trace[$i]['function'], $this->skipFunctions)) {
+ $i++;
+ continue;
+ }
+
+ break;
+ }
+
+ $i += $this->skipStackFramesCount;
+
+ // we should have the call source now
+ $record['extra'] = array_merge(
+ $record['extra'],
+ array(
+ 'file' => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null,
+ 'line' => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null,
+ 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null,
+ 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null,
+ )
+ );
+
+ return $record;
+ }
+
+ private function isTraceClassOrSkippedFunction(array $trace, $index)
+ {
+ if (!isset($trace[$index])) {
+ return false;
+ }
+
+ return isset($trace[$index]['class']) || in_array($trace[$index]['function'], $this->skipFunctions);
+ }
+}
diff --git a/inc/Dependencies/Monolog/Processor/ProcessorInterface.php b/inc/Dependencies/Monolog/Processor/ProcessorInterface.php
new file mode 100644
index 0000000000..597900c88a
--- /dev/null
+++ b/inc/Dependencies/Monolog/Processor/ProcessorInterface.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace WP_Rocket\Dependencies\Monolog\Processor;
+
+/**
+ * An optional interface to allow labelling WP_Rocket\Dependencies\Monolog processors.
+ *
+ * @author Nicolas Grekas
+ */
+interface ProcessorInterface
+{
+ /**
+ * @return array The processed records
+ */
+ public function __invoke(array $records);
+}
diff --git a/inc/Dependencies/Monolog/Registry.php b/inc/Dependencies/Monolog/Registry.php
new file mode 100644
index 0000000000..806ee114ac
--- /dev/null
+++ b/inc/Dependencies/Monolog/Registry.php
@@ -0,0 +1,134 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace WP_Rocket\Dependencies\Monolog;
+
+use InvalidArgumentException;
+
+/**
+ * WP_Rocket\Dependencies\Monolog log registry
+ *
+ * Allows to get `Logger` instances in the global scope
+ * via static method calls on this class.
+ *
+ *
+ * $application = new WP_Rocket\Dependencies\Monolog\Logger('application');
+ * $api = new WP_Rocket\Dependencies\Monolog\Logger('api');
+ *
+ * WP_Rocket\Dependencies\Monolog\Registry::addLogger($application);
+ * WP_Rocket\Dependencies\Monolog\Registry::addLogger($api);
+ *
+ * function testLogger()
+ * {
+ * WP_Rocket\Dependencies\Monolog\Registry::api()->addError('Sent to $api Logger instance');
+ * WP_Rocket\Dependencies\Monolog\Registry::application()->addError('Sent to $application Logger instance');
+ * }
+ *
+ *
+ * @author Tomas Tatarko
+ */
+class Registry
+{
+ /**
+ * List of all loggers in the registry (by named indexes)
+ *
+ * @var Logger[]
+ */
+ private static $loggers = array();
+
+ /**
+ * Adds new logging channel to the registry
+ *
+ * @param Logger $logger Instance of the logging channel
+ * @param string|null $name Name of the logging channel ($logger->getName() by default)
+ * @param bool $overwrite Overwrite instance in the registry if the given name already exists?
+ * @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists
+ */
+ public static function addLogger(Logger $logger, $name = null, $overwrite = false)
+ {
+ $name = $name ?: $logger->getName();
+
+ if (isset(self::$loggers[$name]) && !$overwrite) {
+ throw new InvalidArgumentException('Logger with the given name already exists');
+ }
+
+ self::$loggers[$name] = $logger;
+ }
+
+ /**
+ * Checks if such logging channel exists by name or instance
+ *
+ * @param string|Logger $logger Name or logger instance
+ */
+ public static function hasLogger($logger)
+ {
+ if ($logger instanceof Logger) {
+ $index = array_search($logger, self::$loggers, true);
+
+ return false !== $index;
+ } else {
+ return isset(self::$loggers[$logger]);
+ }
+ }
+
+ /**
+ * Removes instance from registry by name or instance
+ *
+ * @param string|Logger $logger Name or logger instance
+ */
+ public static function removeLogger($logger)
+ {
+ if ($logger instanceof Logger) {
+ if (false !== ($idx = array_search($logger, self::$loggers, true))) {
+ unset(self::$loggers[$idx]);
+ }
+ } else {
+ unset(self::$loggers[$logger]);
+ }
+ }
+
+ /**
+ * Clears the registry
+ */
+ public static function clear()
+ {
+ self::$loggers = array();
+ }
+
+ /**
+ * Gets Logger instance from the registry
+ *
+ * @param string $name Name of the requested Logger instance
+ * @throws \InvalidArgumentException If named Logger instance is not in the registry
+ * @return Logger Requested instance of Logger
+ */
+ public static function getInstance($name)
+ {
+ if (!isset(self::$loggers[$name])) {
+ throw new InvalidArgumentException(sprintf('Requested "%s" logger instance is not in the registry', $name));
+ }
+
+ return self::$loggers[$name];
+ }
+
+ /**
+ * Gets Logger instance from the registry via static method call
+ *
+ * @param string $name Name of the requested Logger instance
+ * @param array $arguments Arguments passed to static method call
+ * @throws \InvalidArgumentException If named Logger instance is not in the registry
+ * @return Logger Requested instance of Logger
+ */
+ public static function __callStatic($name, $arguments)
+ {
+ return self::getInstance($name);
+ }
+}
diff --git a/inc/Dependencies/Monolog/ResettableInterface.php b/inc/Dependencies/Monolog/ResettableInterface.php
new file mode 100644
index 0000000000..f91ee124b2
--- /dev/null
+++ b/inc/Dependencies/Monolog/ResettableInterface.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace WP_Rocket\Dependencies\Monolog;
+
+/**
+ * Handler or Processor implementing this interface will be reset when Logger::reset() is called.
+ *
+ * Resetting ends a log cycle gets them back to their initial state.
+ *
+ * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal
+ * state, and getting it back to a state in which it can receive log records again.
+ *
+ * This is useful in case you want to avoid logs leaking between two requests or jobs when you
+ * have a long running process like a worker or an application server serving multiple requests
+ * in one process.
+ *
+ * @author Grégoire Pineau
+ */
+interface ResettableInterface
+{
+ public function reset();
+}
diff --git a/inc/Dependencies/Monolog/SignalHandler.php b/inc/Dependencies/Monolog/SignalHandler.php
new file mode 100644
index 0000000000..8f62c7e990
--- /dev/null
+++ b/inc/Dependencies/Monolog/SignalHandler.php
@@ -0,0 +1,115 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace WP_Rocket\Dependencies\Monolog;
+
+use WP_Rocket\Dependencies\Psr\Log\LoggerInterface;
+use WP_Rocket\Dependencies\Psr\Log\LogLevel;
+use ReflectionExtension;
+
+/**
+ * WP_Rocket\Dependencies\Monolog POSIX signal handler
+ *
+ * @author Robert Gust-Bardon
+ */
+class SignalHandler
+{
+ private $logger;
+
+ private $previousSignalHandler = array();
+ private $signalLevelMap = array();
+ private $signalRestartSyscalls = array();
+
+ public function __construct(LoggerInterface $logger)
+ {
+ $this->logger = $logger;
+ }
+
+ public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, $callPrevious = true, $restartSyscalls = true, $async = true)
+ {
+ if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) {
+ return $this;
+ }
+
+ if ($callPrevious) {
+ if (function_exists('pcntl_signal_get_handler')) {
+ $handler = pcntl_signal_get_handler($signo);
+ if ($handler === false) {
+ return $this;
+ }
+ $this->previousSignalHandler[$signo] = $handler;
+ } else {
+ $this->previousSignalHandler[$signo] = true;
+ }
+ } else {
+ unset($this->previousSignalHandler[$signo]);
+ }
+ $this->signalLevelMap[$signo] = $level;
+ $this->signalRestartSyscalls[$signo] = $restartSyscalls;
+
+ if (function_exists('pcntl_async_signals') && $async !== null) {
+ pcntl_async_signals($async);
+ }
+
+ pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls);
+
+ return $this;
+ }
+
+ public function handleSignal($signo, array $siginfo = null)
+ {
+ static $signals = array();
+
+ if (!$signals && extension_loaded('pcntl')) {
+ $pcntl = new ReflectionExtension('pcntl');
+ $constants = $pcntl->getConstants();
+ if (!$constants) {
+ // HHVM 3.24.2 returns an empty array.
+ $constants = get_defined_constants(true);
+ $constants = $constants['Core'];
+ }
+ foreach ($constants as $name => $value) {
+ if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) {
+ $signals[$value] = $name;
+ }
+ }
+ unset($constants);
+ }
+
+ $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL;
+ $signal = isset($signals[$signo]) ? $signals[$signo] : $signo;
+ $context = isset($siginfo) ? $siginfo : array();
+ $this->logger->log($level, sprintf('Program received signal %s', $signal), $context);
+
+ if (!isset($this->previousSignalHandler[$signo])) {
+ return;
+ }
+
+ if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) {
+ if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch')
+ && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) {
+ $restartSyscalls = isset($this->signalRestartSyscalls[$signo]) ? $this->signalRestartSyscalls[$signo] : true;
+ pcntl_signal($signo, SIG_DFL, $restartSyscalls);
+ pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset);
+ posix_kill(posix_getpid(), $signo);
+ pcntl_signal_dispatch();
+ pcntl_sigprocmask(SIG_SETMASK, $oldset);
+ pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls);
+ }
+ } elseif (is_callable($this->previousSignalHandler[$signo])) {
+ if (PHP_VERSION_ID >= 70100) {
+ $this->previousSignalHandler[$signo]($signo, $siginfo);
+ } else {
+ $this->previousSignalHandler[$signo]($signo);
+ }
+ }
+ }
+}
diff --git a/inc/Dependencies/Monolog/Utils.php b/inc/Dependencies/Monolog/Utils.php
new file mode 100644
index 0000000000..2542e2ed19
--- /dev/null
+++ b/inc/Dependencies/Monolog/Utils.php
@@ -0,0 +1,189 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace WP_Rocket\Dependencies\Monolog;
+
+class Utils
+{
+ /**
+ * @internal
+ */
+ public static function getClass($object)
+ {
+ $class = \get_class($object);
+
+ return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
+ }
+
+ /**
+ * Makes sure if a relative path is passed in it is turned into an absolute path
+ *
+ * @param string $streamUrl stream URL or path without protocol
+ *
+ * @return string
+ */
+ public static function canonicalizePath($streamUrl)
+ {
+ $prefix = '';
+ if ('file://' === substr($streamUrl, 0, 7)) {
+ $streamUrl = substr($streamUrl, 7);
+ $prefix = 'file://';
+ }
+
+ // other type of stream, not supported
+ if (false !== strpos($streamUrl, '://')) {
+ return $streamUrl;
+ }
+
+ // already absolute
+ if (substr($streamUrl, 0, 1) === '/' || substr($streamUrl, 1, 1) === ':' || substr($streamUrl, 0, 2) === '\\\\') {
+ return $prefix.$streamUrl;
+ }
+
+ $streamUrl = getcwd() . '/' . $streamUrl;
+
+ return $prefix.$streamUrl;
+ }
+
+ /**
+ * Return the JSON representation of a value
+ *
+ * @param mixed $data
+ * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
+ * @param bool $ignoreErrors whether to ignore encoding errors or to throw on error, when ignored and the encoding fails, "null" is returned which is valid json for null
+ * @throws \RuntimeException if encoding fails and errors are not ignored
+ * @return string
+ */
+ public static function jsonEncode($data, $encodeFlags = null, $ignoreErrors = false)
+ {
+ if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
+ }
+
+ if ($ignoreErrors) {
+ $json = @json_encode($data, $encodeFlags);
+ if (false === $json) {
+ return 'null';
+ }
+
+ return $json;
+ }
+
+ $json = json_encode($data, $encodeFlags);
+ if (false === $json) {
+ $json = self::handleJsonError(json_last_error(), $data);
+ }
+
+ return $json;
+ }
+
+ /**
+ * Handle a json_encode failure.
+ *
+ * If the failure is due to invalid string encoding, try to clean the
+ * input and encode again. If the second encoding attempt fails, the
+ * inital error is not encoding related or the input can't be cleaned then
+ * raise a descriptive exception.
+ *
+ * @param int $code return code of json_last_error function
+ * @param mixed $data data that was meant to be encoded
+ * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
+ * @throws \RuntimeException if failure can't be corrected
+ * @return string JSON encoded data after error correction
+ */
+ public static function handleJsonError($code, $data, $encodeFlags = null)
+ {
+ if ($code !== JSON_ERROR_UTF8) {
+ self::throwEncodeError($code, $data);
+ }
+
+ if (is_string($data)) {
+ self::detectAndCleanUtf8($data);
+ } elseif (is_array($data)) {
+ array_walk_recursive($data, array('WP_Rocket\Dependencies\Monolog\Utils', 'detectAndCleanUtf8'));
+ } else {
+ self::throwEncodeError($code, $data);
+ }
+
+ if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
+ }
+
+ $json = json_encode($data, $encodeFlags);
+
+ if ($json === false) {
+ self::throwEncodeError(json_last_error(), $data);
+ }
+
+ return $json;
+ }
+
+ /**
+ * Throws an exception according to a given code with a customized message
+ *
+ * @param int $code return code of json_last_error function
+ * @param mixed $data data that was meant to be encoded
+ * @throws \RuntimeException
+ */
+ private static function throwEncodeError($code, $data)
+ {
+ switch ($code) {
+ case JSON_ERROR_DEPTH:
+ $msg = 'Maximum stack depth exceeded';
+ break;
+ case JSON_ERROR_STATE_MISMATCH:
+ $msg = 'Underflow or the modes mismatch';
+ break;
+ case JSON_ERROR_CTRL_CHAR:
+ $msg = 'Unexpected control character found';
+ break;
+ case JSON_ERROR_UTF8:
+ $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
+ break;
+ default:
+ $msg = 'Unknown error';
+ }
+
+ throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true));
+ }
+
+ /**
+ * Detect invalid UTF-8 string characters and convert to valid UTF-8.
+ *
+ * Valid UTF-8 input will be left unmodified, but strings containing
+ * invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed
+ * original encoding of ISO-8859-15. This conversion may result in
+ * incorrect output if the actual encoding was not ISO-8859-15, but it
+ * will be clean UTF-8 output and will not rely on expensive and fragile
+ * detection algorithms.
+ *
+ * Function converts the input in place in the passed variable so that it
+ * can be used as a callback for array_walk_recursive.
+ *
+ * @param mixed $data Input to check and convert if needed, passed by ref
+ * @private
+ */
+ public static function detectAndCleanUtf8(&$data)
+ {
+ if (is_string($data) && !preg_match('//u', $data)) {
+ $data = preg_replace_callback(
+ '/[\x80-\xFF]+/',
+ function ($m) { return utf8_encode($m[0]); },
+ $data
+ );
+ $data = str_replace(
+ array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'),
+ array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'),
+ $data
+ );
+ }
+ }
+}
diff --git a/inc/Dependencies/Psr/Log/AbstractLogger.php b/inc/Dependencies/Psr/Log/AbstractLogger.php
new file mode 100644
index 0000000000..ae46968633
--- /dev/null
+++ b/inc/Dependencies/Psr/Log/AbstractLogger.php
@@ -0,0 +1,128 @@
+log(LogLevel::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Action must be taken immediately.
+ *
+ * Example: Entire website down, database unavailable, etc. This should
+ * trigger the SMS alerts and wake you up.
+ *
+ * @param string $message
+ * @param mixed[] $context
+ *
+ * @return void
+ */
+ public function alert($message, array $context = array())
+ {
+ $this->log(LogLevel::ALERT, $message, $context);
+ }
+
+ /**
+ * Critical conditions.
+ *
+ * Example: Application component unavailable, unexpected exception.
+ *
+ * @param string $message
+ * @param mixed[] $context
+ *
+ * @return void
+ */
+ public function critical($message, array $context = array())
+ {
+ $this->log(LogLevel::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Runtime errors that do not require immediate action but should typically
+ * be logged and monitored.
+ *
+ * @param string $message
+ * @param mixed[] $context
+ *
+ * @return void
+ */
+ public function error($message, array $context = array())
+ {
+ $this->log(LogLevel::ERROR, $message, $context);
+ }
+
+ /**
+ * Exceptional occurrences that are not errors.
+ *
+ * Example: Use of deprecated APIs, poor use of an API, undesirable things
+ * that are not necessarily wrong.
+ *
+ * @param string $message
+ * @param mixed[] $context
+ *
+ * @return void
+ */
+ public function warning($message, array $context = array())
+ {
+ $this->log(LogLevel::WARNING, $message, $context);
+ }
+
+ /**
+ * Normal but significant events.
+ *
+ * @param string $message
+ * @param mixed[] $context
+ *
+ * @return void
+ */
+ public function notice($message, array $context = array())
+ {
+ $this->log(LogLevel::NOTICE, $message, $context);
+ }
+
+ /**
+ * Interesting events.
+ *
+ * Example: User logs in, SQL logs.
+ *
+ * @param string $message
+ * @param mixed[] $context
+ *
+ * @return void
+ */
+ public function info($message, array $context = array())
+ {
+ $this->log(LogLevel::INFO, $message, $context);
+ }
+
+ /**
+ * Detailed debug information.
+ *
+ * @param string $message
+ * @param mixed[] $context
+ *
+ * @return void
+ */
+ public function debug($message, array $context = array())
+ {
+ $this->log(LogLevel::DEBUG, $message, $context);
+ }
+}
diff --git a/inc/Dependencies/Psr/Log/InvalidArgumentException.php b/inc/Dependencies/Psr/Log/InvalidArgumentException.php
new file mode 100644
index 0000000000..559e424ca1
--- /dev/null
+++ b/inc/Dependencies/Psr/Log/InvalidArgumentException.php
@@ -0,0 +1,7 @@
+logger = $logger;
+ }
+}
diff --git a/inc/Dependencies/Psr/Log/LoggerInterface.php b/inc/Dependencies/Psr/Log/LoggerInterface.php
new file mode 100644
index 0000000000..f150312453
--- /dev/null
+++ b/inc/Dependencies/Psr/Log/LoggerInterface.php
@@ -0,0 +1,125 @@
+log(LogLevel::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Action must be taken immediately.
+ *
+ * Example: Entire website down, database unavailable, etc. This should
+ * trigger the SMS alerts and wake you up.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function alert($message, array $context = array())
+ {
+ $this->log(LogLevel::ALERT, $message, $context);
+ }
+
+ /**
+ * Critical conditions.
+ *
+ * Example: Application component unavailable, unexpected exception.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function critical($message, array $context = array())
+ {
+ $this->log(LogLevel::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Runtime errors that do not require immediate action but should typically
+ * be logged and monitored.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function error($message, array $context = array())
+ {
+ $this->log(LogLevel::ERROR, $message, $context);
+ }
+
+ /**
+ * Exceptional occurrences that are not errors.
+ *
+ * Example: Use of deprecated APIs, poor use of an API, undesirable things
+ * that are not necessarily wrong.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function warning($message, array $context = array())
+ {
+ $this->log(LogLevel::WARNING, $message, $context);
+ }
+
+ /**
+ * Normal but significant events.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function notice($message, array $context = array())
+ {
+ $this->log(LogLevel::NOTICE, $message, $context);
+ }
+
+ /**
+ * Interesting events.
+ *
+ * Example: User logs in, SQL logs.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function info($message, array $context = array())
+ {
+ $this->log(LogLevel::INFO, $message, $context);
+ }
+
+ /**
+ * Detailed debug information.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function debug($message, array $context = array())
+ {
+ $this->log(LogLevel::DEBUG, $message, $context);
+ }
+
+ /**
+ * Logs with an arbitrary level.
+ *
+ * @param mixed $level
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ *
+ * @throws \WP_Rocket\Dependencies\Psr\Log\InvalidArgumentException
+ */
+ abstract public function log($level, $message, array $context = array());
+}
diff --git a/inc/Dependencies/Psr/Log/NullLogger.php b/inc/Dependencies/Psr/Log/NullLogger.php
new file mode 100644
index 0000000000..bdea7eb158
--- /dev/null
+++ b/inc/Dependencies/Psr/Log/NullLogger.php
@@ -0,0 +1,30 @@
+logger) { }`
+ * blocks.
+ */
+class NullLogger extends AbstractLogger
+{
+ /**
+ * Logs with an arbitrary level.
+ *
+ * @param mixed $level
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ *
+ * @throws \WP_Rocket\Dependencies\Psr\Log\InvalidArgumentException
+ */
+ public function log($level, $message, array $context = array())
+ {
+ // noop
+ }
+}
diff --git a/inc/Engine/Cache/AdminSubscriber.php b/inc/Engine/Cache/AdminSubscriber.php
index ff7368e1ce..16feec5874 100644
--- a/inc/Engine/Cache/AdminSubscriber.php
+++ b/inc/Engine/Cache/AdminSubscriber.php
@@ -72,6 +72,7 @@ public static function get_subscribed_events() {
],
"update_option_{$slug}" => [ 'maybe_set_wp_cache', 12 ],
'site_status_tests' => 'add_wp_cache_status_test',
+ 'wp_rocket_upgrade' => [ 'on_update', 10, 2 ],
'rocket_domain_changed' => [
[ 'regenerate_configs' ],
[ 'delete_old_configs' ],
@@ -214,9 +215,9 @@ public function delete_old_configs() {
foreach ( $contents as $content ) {
$content = WP_ROCKET_CONFIG_PATH . $content['name'];
if ( ! preg_match( '#\.php$#', $content ) || ! $this->filesystem->is_file( $content ) || in_array(
- $content,
+ $content,
$configs,
- true
+ true
) ) {
continue;
}
@@ -251,4 +252,19 @@ protected function generate_config_path() {
public function clear_cache( string $current_url, string $old_url ) {
rocket_clean_files( [ $old_url, $current_url ], null, false );
}
+
+ /**
+ * Regenerate the advanced cache file on update
+ *
+ * @param string $new_version New plugin version.
+ * @param string $old_version Previous plugin version.
+ *
+ * @return void
+ */
+ public function on_update( $new_version, $old_version ) {
+ if ( version_compare( $old_version, '3.15', '>=' ) ) {
+ return;
+ }
+ rocket_generate_advanced_cache_file();
+ }
}
diff --git a/inc/Logger/HTMLFormatter.php b/inc/Logger/HTMLFormatter.php
new file mode 100644
index 0000000000..22ef7f9287
--- /dev/null
+++ b/inc/Logger/HTMLFormatter.php
@@ -0,0 +1,58 @@
+addTitle( $record['level_name'], $record['level'] );
+ $output .= '';
+
+ $output .= $this->addRow( 'Message', (string) $record['message'] );
+ $output .= $this->addRow( 'Time', $record['datetime']->format( $this->dateFormat ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+
+ if ( $record['context'] ) {
+ $embedded_table = '';
+
+ foreach ( $record['context'] as $key => $value ) {
+ $embedded_table .= $this->addRow( $key, $this->convertToString( $value ) );
+ }
+
+ $embedded_table .= '
';
+ $output .= $this->addRow( 'Context', $embedded_table, false );
+ }
+
+ if ( $record['extra'] ) {
+ $embedded_table = '';
+
+ foreach ( $record['extra'] as $key => $value ) {
+ $embedded_table .= $this->addRow( $key, $this->convertToString( $value ) );
+ }
+
+ $embedded_table .= '
';
+ $output .= $this->addRow( 'Extra', $embedded_table, false );
+ }
+
+ return $output . '
';
+ }
+}
diff --git a/inc/Logger/Logger.php b/inc/Logger/Logger.php
new file mode 100644
index 0000000000..ce3eef6848
--- /dev/null
+++ b/inc/Logger/Logger.php
@@ -0,0 +1,563 @@
+debug( $message, $context ) : null;
+ }
+
+ /**
+ * Adds a log record at the INFO level.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @param string $message The log message.
+ * @param array $context The log context.
+ * @return bool|null Whether the record has been processed.
+ */
+ public static function info( $message, array $context = [] ) {
+ return static::debug_enabled() ? static::get_logger()->info( $message, $context ) : null;
+ }
+
+ /**
+ * Adds a log record at the NOTICE level.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @param string $message The log message.
+ * @param array $context The log context.
+ * @return bool|null Whether the record has been processed.
+ */
+ public static function notice( $message, array $context = [] ) {
+ return static::debug_enabled() ? static::get_logger()->notice( $message, $context ) : null;
+ }
+
+ /**
+ * Adds a log record at the WARNING level.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @param string $message The log message.
+ * @param array $context The log context.
+ * @return bool|null Whether the record has been processed.
+ */
+ public static function warning( $message, array $context = [] ) {
+ return static::debug_enabled() ? static::get_logger()->warning( $message, $context ) : null;
+ }
+
+ /**
+ * Adds a log record at the ERROR level.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @param string $message The log message.
+ * @param array $context The log context.
+ * @return bool|null Whether the record has been processed.
+ */
+ public static function error( $message, array $context = [] ) {
+ return static::debug_enabled() ? static::get_logger()->error( $message, $context ) : null;
+ }
+
+ /**
+ * Adds a log record at the CRITICAL level.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @param string $message The log message.
+ * @param array $context The log context.
+ * @return bool|null Whether the record has been processed.
+ */
+ public static function critical( $message, array $context = [] ) {
+ return static::debug_enabled() ? static::get_logger()->critical( $message, $context ) : null;
+ }
+
+ /**
+ * Adds a log record at the ALERT level.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @param string $message The log message.
+ * @param array $context The log context.
+ * @return bool|null Whether the record has been processed.
+ */
+ public static function alert( $message, array $context = [] ) {
+ return static::debug_enabled() ? static::get_logger()->alert( $message, $context ) : null;
+ }
+
+ /**
+ * Adds a log record at the EMERGENCY level.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @param string $message The log message.
+ * @param array $context The log context.
+ * @return bool|null Whether the record has been processed.
+ */
+ public static function emergency( $message, array $context = [] ) {
+ return static::debug_enabled() ? static::get_logger()->emergency( $message, $context ) : null;
+ }
+
+ /**
+ * Get the logger instance.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return Logger A Logger instance.
+ */
+ public static function get_logger() {
+ $logger_name = static::LOGGER_NAME;
+ $log_level = Monologger::DEBUG;
+
+ if ( Registry::hasLogger( $logger_name ) ) {
+ return Registry::$logger_name();
+ }
+
+ /**
+ * File handler.
+ * HTML formatter is used.
+ */
+ $handler = new StreamHandler( static::get_log_file_path(), $log_level );
+ $formatter = new HtmlFormatter();
+
+ $handler->setFormatter( $formatter );
+
+ /**
+ * Thanks to the processors, add data to each log:
+ * - `debug_backtrace()` (exclude this class and Abstract_Buffer).
+ */
+ $trace_processor = new IntrospectionProcessor( $log_level, [ get_called_class(), 'Abstract_Buffer' ] );
+
+ // Create the logger.
+ $logger = new Monologger( $logger_name, [ $handler ], [ $trace_processor ] );
+
+ // Store the logger.
+ Registry::addLogger( $logger );
+
+ return $logger;
+ }
+
+
+ /** ----------------------------------------------------------------------------------------- */
+ /** LOG FILE ================================================================================ */
+ /** ----------------------------------------------------------------------------------------- */
+
+ /**
+ * Get the path to the log file.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return string
+ */
+ public static function get_log_file_path() {
+ if ( defined( 'WP_ROCKET_DEBUG_LOG_FILE' ) && WP_ROCKET_DEBUG_LOG_FILE && is_string( WP_ROCKET_DEBUG_LOG_FILE ) ) {
+ // Make sure the file uses a ".log" extension.
+ return preg_replace( '/\.[^.]*$/', '', WP_ROCKET_DEBUG_LOG_FILE ) . '.log';
+ }
+
+ if ( defined( 'WP_ROCKET_DEBUG_INTERVAL' ) ) {
+ // Adds an optional logs rotator depending on a constant value - WP_ROCKET_DEBUG_INTERVAL (interval by minutes).
+ $rotator = str_pad( round( ( strtotime( 'now' ) - strtotime( 'today midnight' ) ) / 60 / WP_ROCKET_DEBUG_INTERVAL ), 4, '0', STR_PAD_LEFT );
+ return WP_CONTENT_DIR . '/wp-rocket-config/' . $rotator . '-' . static::LOG_FILE_NAME;
+ } else {
+ return WP_CONTENT_DIR . '/wp-rocket-config/' . static::LOG_FILE_NAME;
+ }
+ }
+
+ /**
+ * Get the log file contents.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return string|object The file contents on success. A WP_Error object on failure.
+ */
+ public static function get_log_file_contents() {
+ $filesystem = \rocket_direct_filesystem();
+ $file_path = static::get_log_file_path();
+
+ if ( ! $filesystem->exists( $file_path ) ) {
+ return new \WP_Error( 'no_file', __( 'The log file does not exist.', 'rocket' ) );
+ }
+
+ $contents = $filesystem->get_contents( $file_path );
+
+ if ( false === $contents ) {
+ return new \WP_Error( 'file_not_read', __( 'The log file could not be read.', 'rocket' ) );
+ }
+
+ return $contents;
+ }
+
+ /**
+ * Get the log file size and number of entries.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return array|object An array of statistics on success. A WP_Error object on failure.
+ */
+ public static function get_log_file_stats() {
+ $formatter = static::get_stream_formatter();
+
+ if ( ! $formatter ) {
+ return new \WP_Error( 'no_stream_formatter', __( 'The logs are not saved into a file.', 'rocket' ) );
+ }
+
+ $filesystem = \rocket_direct_filesystem();
+ $file_path = static::get_log_file_path();
+
+ if ( ! $filesystem->exists( $file_path ) ) {
+ return new \WP_Error( 'no_file', __( 'The log file does not exist.', 'rocket' ) );
+ }
+
+ $contents = $filesystem->get_contents( $file_path );
+
+ if ( false === $contents ) {
+ return new \WP_Error( 'file_not_read', __( 'The log file could not be read.', 'rocket' ) );
+ }
+
+ if ( $formatter instanceof HtmlFormatter ) {
+ $entries = preg_split( '@size( $file_path );
+ $decimals = $bytes > pow( 1024, 3 ) ? 1 : 0;
+ $bytes = @size_format( $bytes, $decimals ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
+ $bytes = str_replace( ' ', ' ', $bytes ); // Non-breaking space character.
+
+ return compact( 'entries', 'bytes' );
+ }
+
+ /**
+ * Get the log file extension related to the formatter in use. This can be used when the file is downloaded.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return string The corresponding file extension with the heading dot.
+ */
+ public static function get_log_file_extension() {
+ $formatter = static::get_stream_formatter();
+
+ if ( ! $formatter ) {
+ return '.log';
+ }
+
+ if ( $formatter instanceof HtmlFormatter ) {
+ return '.html';
+ }
+
+ if ( $formatter instanceof LineFormatter ) {
+ return '.txt';
+ }
+
+ return '.log';
+ }
+
+ /**
+ * Delete the log file.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return bool True on success. False on failure.
+ */
+ public static function delete_log_file() {
+ $filesystem = \rocket_direct_filesystem();
+ $file_path = static::get_log_file_path();
+
+ if ( ! $filesystem->exists( $file_path ) ) {
+ return true;
+ }
+
+ $filesystem->put_contents( $file_path, '' );
+ $filesystem->delete( $file_path, false, 'f' );
+
+ return ! $filesystem->exists( $file_path );
+ }
+
+ /**
+ * Get the handler used for the log file.
+ *
+ * @since 3.2
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return object|bool The formatter object on success. False on failure.
+ */
+ public static function get_stream_handler() {
+ $handlers = static::get_logger()->getHandlers();
+
+ if ( ! $handlers ) {
+ return false;
+ }
+
+ foreach ( $handlers as $_handler ) {
+ if ( $_handler instanceof MonoStreamHandler ) {
+ $handler = $_handler;
+ break;
+ }
+ }
+
+ if ( empty( $handler ) ) {
+ return false;
+ }
+
+ return $handler;
+ }
+
+ /**
+ * Get the formatter used for the log file.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return object|bool The formatter object on success. False on failure.
+ */
+ public static function get_stream_formatter() {
+ $handler = static::get_stream_handler();
+
+ if ( empty( $handler ) ) {
+ return false;
+ }
+
+ return $handler->getFormatter();
+ }
+
+
+ /** ----------------------------------------------------------------------------------------- */
+ /** CONSTANT ================================================================================ */
+ /** ----------------------------------------------------------------------------------------- */
+
+ /**
+ * Tell if debug is enabled.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return bool
+ */
+ public static function debug_enabled() {
+ return defined( 'WP_ROCKET_DEBUG' ) && WP_ROCKET_DEBUG;
+ }
+
+ /**
+ * Enable debug mode by adding a constant in the `wp-config.php` file.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ */
+ public static function enable_debug() {
+ static::define_debug( true );
+ }
+
+ /**
+ * Disable debug mode by removing the constant in the `wp-config.php` file.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ */
+ public static function disable_debug() {
+ static::define_debug( false );
+ }
+
+ /**
+ * Enable or disable debug mode by adding or removing a constant in the `wp-config.php` file.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @param bool $enable True to enable debug, false to disable.
+ */
+ public static function define_debug( $enable ) {
+ if ( $enable && static::debug_enabled() ) {
+ // Debug is already enabled.
+ return;
+ }
+
+ if ( ! $enable && ! static::debug_enabled() ) {
+ // Debug is already disabled.
+ return;
+ }
+
+ // Get the path to the file.
+ $file_path = \rocket_find_wpconfig_path();
+
+ if ( ! $file_path ) {
+ // Couldn't get the path to the file.
+ return;
+ }
+
+ // Get the content of the file.
+ $filesystem = \rocket_direct_filesystem();
+ $content = $filesystem->get_contents( $file_path );
+
+ if ( false === $content ) {
+ // Cound't get the content of the file.
+ return;
+ }
+
+ // Remove previous value.
+ $placeholder = '## WP_ROCKET_DEBUG placeholder ##';
+ $content = preg_replace( '@^[\t ]*define\s*\(\s*["\']WP_ROCKET_DEBUG["\'].*$@miU', $placeholder, $content );
+ $content = preg_replace( "@\n$placeholder@", '', $content );
+
+ if ( $enable ) {
+ // Add the constant.
+ $define = "define( 'WP_ROCKET_DEBUG', true ); // Added by WP Rocket.\r\n";
+ $content = preg_replace( '@<\?php\s*@i', "put_contents( $file_path, $content, $chmod );
+ }
+
+
+ /** ----------------------------------------------------------------------------------------- */
+ /** TOOLS =================================================================================== */
+ /** ----------------------------------------------------------------------------------------- */
+
+ /**
+ * Get the thread identifier.
+ *
+ * @since 3.3
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @return string
+ */
+ public static function get_thread_id() {
+ if ( ! isset( self::$thread_id ) ) {
+ self::$thread_id = uniqid( '', true );
+ }
+
+ return self::$thread_id;
+ }
+
+ /**
+ * Remove cookies related to WP auth.
+ *
+ * @since 3.1.4
+ * @access public
+ * @author Grégory Viguier
+ *
+ * @param array $cookies An array of cookies.
+ * @return array
+ */
+ public static function remove_auth_cookies( $cookies = [] ) {
+ if ( ! $cookies || ! is_array( $cookies ) ) {
+ $cookies = $_COOKIE;
+ }
+
+ unset( $cookies['wordpress_test_cookie'] );
+
+ if ( ! $cookies ) {
+ return [];
+ }
+
+ $pattern = strtolower( '@^WordPress(?:user|pass|_sec|_logged_in)?_@' ); // Trolling PHPCS.
+
+ foreach ( $cookies as $cookie_name => $value ) {
+ if ( preg_match( $pattern, $cookie_name ) ) {
+ $cookies[ $cookie_name ] = 'Value removed by WP Rocket.';
+ }
+ }
+
+ return $cookies;
+ }
+}
diff --git a/inc/Logger/StreamHandler.php b/inc/Logger/StreamHandler.php
new file mode 100644
index 0000000000..1359a53ae8
--- /dev/null
+++ b/inc/Logger/StreamHandler.php
@@ -0,0 +1,147 @@
+create_htaccess_file();
+ }
+
+ /**
+ * Create a .htaccess file in the log folder, to prevent direct access and directory listing.
+ *
+ * @since 3.2
+ *
+ * @throws \UnexpectedValueException When the .htaccess file could not be created.
+ *
+ * @return bool True if the file exists or has been created. False on failure.
+ */
+ public function create_htaccess_file() {
+ if ( $this->htaccess_exists ) {
+ return true;
+ }
+
+ if ( $this->has_error ) {
+ return false;
+ }
+
+ $dir = $this->get_dir_from_stream( $this->url );
+
+ if ( ! $dir || ! is_dir( $dir ) ) {
+ $this->has_error = true;
+ return false;
+ }
+
+ $file_path = $dir . '/.htaccess';
+
+ if ( file_exists( $file_path ) ) {
+ $this->htaccess_exists = true;
+ return true;
+ }
+
+ $this->error_message = null;
+
+ set_error_handler( [ $this, 'custom_error_handler' ] ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
+
+ $file_resource = fopen( $file_path, 'a' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
+
+ restore_error_handler();
+
+ if ( ! is_resource( $file_resource ) ) {
+ $this->has_error = true;
+ throw new UnexpectedValueException( sprintf( 'The file "%s" could not be opened: ' . $this->error_message, $file_path ) );
+ }
+
+ $new_content = "\nOrder allow,deny\nDeny from all\n\nOptions -Indexes";
+
+ fwrite( $file_resource, $new_content ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
+ fclose( $file_resource ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
+ @chmod( $file_path, 0644 ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
+
+ $this->htaccess_exists = true;
+
+ return true;
+ }
+
+ /**
+ * Temporary error handler that "cleans" the error messages.
+ *
+ * @since 3.2
+ *
+ * @see parent::customErrorHandler()
+ *
+ * @param int $code Error code.
+ * @param string $msg Error message.
+ */
+ private function custom_error_handler( int $code, string $msg ) {
+ $this->error_message = preg_replace( '{^(fopen|mkdir)\(.*?\): }', '', $msg );
+ }
+
+ /**
+ * A dirname() that also works for streams, by removing the protocol.
+ *
+ * @since 3.2
+ *
+ * @see parent::getDirFromStream()
+ *
+ * @param string $stream Path to a file.
+ *
+ * @return null|string
+ */
+ private function get_dir_from_stream( string $stream ) {
+ $pos = strpos( $stream, '://' );
+
+ if ( false === $pos ) {
+ return dirname( $stream );
+ }
+
+ if ( 'file://' === substr( $stream, 0, 7 ) ) {
+ return dirname( substr( $stream, 7 ) );
+ }
+ }
+}
diff --git a/inc/classes/logger/class-html-formatter.php b/inc/classes/logger/class-html-formatter.php
index 8652c9cc40..250bd4c04d 100644
--- a/inc/classes/logger/class-html-formatter.php
+++ b/inc/classes/logger/class-html-formatter.php
@@ -1,58 +1,4 @@
addTitle( $record['level_name'], $record['level'] );
- $output .= '
';
-
- $output .= $this->addRow( 'Message', (string) $record['message'] );
- $output .= $this->addRow( 'Time', $record['datetime']->format( $this->dateFormat ) ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
-
- if ( $record['context'] ) {
- $embedded_table = '';
-
- foreach ( $record['context'] as $key => $value ) {
- $embedded_table .= $this->addRow( $key, $this->convertToString( $value ) );
- }
-
- $embedded_table .= '
';
- $output .= $this->addRow( 'Context', $embedded_table, false );
- }
-
- if ( $record['extra'] ) {
- $embedded_table = '';
-
- foreach ( $record['extra'] as $key => $value ) {
- $embedded_table .= $this->addRow( $key, $this->convertToString( $value ) );
- }
-
- $embedded_table .= '
';
- $output .= $this->addRow( 'Extra', $embedded_table, false );
- }
-
- return $output . '
';
- }
+if ( isset( $rocket_path ) ) {
+ require_once $rocket_path . 'inc/Logger/HTMLFormatter.php';
}
diff --git a/inc/classes/logger/class-logger.php b/inc/classes/logger/class-logger.php
index 3fc1f178d3..25cbd426fc 100644
--- a/inc/classes/logger/class-logger.php
+++ b/inc/classes/logger/class-logger.php
@@ -1,563 +1,4 @@
debug( $message, $context ) : null;
- }
-
- /**
- * Adds a log record at the INFO level.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @param string $message The log message.
- * @param array $context The log context.
- * @return bool|null Whether the record has been processed.
- */
- public static function info( $message, array $context = [] ) {
- return static::debug_enabled() ? static::get_logger()->info( $message, $context ) : null;
- }
-
- /**
- * Adds a log record at the NOTICE level.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @param string $message The log message.
- * @param array $context The log context.
- * @return bool|null Whether the record has been processed.
- */
- public static function notice( $message, array $context = [] ) {
- return static::debug_enabled() ? static::get_logger()->notice( $message, $context ) : null;
- }
-
- /**
- * Adds a log record at the WARNING level.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @param string $message The log message.
- * @param array $context The log context.
- * @return bool|null Whether the record has been processed.
- */
- public static function warning( $message, array $context = [] ) {
- return static::debug_enabled() ? static::get_logger()->warning( $message, $context ) : null;
- }
-
- /**
- * Adds a log record at the ERROR level.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @param string $message The log message.
- * @param array $context The log context.
- * @return bool|null Whether the record has been processed.
- */
- public static function error( $message, array $context = [] ) {
- return static::debug_enabled() ? static::get_logger()->error( $message, $context ) : null;
- }
-
- /**
- * Adds a log record at the CRITICAL level.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @param string $message The log message.
- * @param array $context The log context.
- * @return bool|null Whether the record has been processed.
- */
- public static function critical( $message, array $context = [] ) {
- return static::debug_enabled() ? static::get_logger()->critical( $message, $context ) : null;
- }
-
- /**
- * Adds a log record at the ALERT level.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @param string $message The log message.
- * @param array $context The log context.
- * @return bool|null Whether the record has been processed.
- */
- public static function alert( $message, array $context = [] ) {
- return static::debug_enabled() ? static::get_logger()->alert( $message, $context ) : null;
- }
-
- /**
- * Adds a log record at the EMERGENCY level.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @param string $message The log message.
- * @param array $context The log context.
- * @return bool|null Whether the record has been processed.
- */
- public static function emergency( $message, array $context = [] ) {
- return static::debug_enabled() ? static::get_logger()->emergency( $message, $context ) : null;
- }
-
- /**
- * Get the logger instance.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @return Logger A Logger instance.
- */
- public static function get_logger() {
- $logger_name = static::LOGGER_NAME;
- $log_level = Monologger::DEBUG;
-
- if ( Registry::hasLogger( $logger_name ) ) {
- return Registry::$logger_name();
- }
-
- /**
- * File handler.
- * HTML formatter is used.
- */
- $handler = new StreamHandler( static::get_log_file_path(), $log_level );
- $formatter = new HtmlFormatter();
-
- $handler->setFormatter( $formatter );
-
- /**
- * Thanks to the processors, add data to each log:
- * - `debug_backtrace()` (exclude this class and Abstract_Buffer).
- */
- $trace_processor = new IntrospectionProcessor( $log_level, [ get_called_class(), 'Abstract_Buffer' ] );
-
- // Create the logger.
- $logger = new Monologger( $logger_name, [ $handler ], [ $trace_processor ] );
-
- // Store the logger.
- Registry::addLogger( $logger );
-
- return $logger;
- }
-
-
- /** ----------------------------------------------------------------------------------------- */
- /** LOG FILE ================================================================================ */
- /** ----------------------------------------------------------------------------------------- */
-
- /**
- * Get the path to the log file.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @return string
- */
- public static function get_log_file_path() {
- if ( defined( 'WP_ROCKET_DEBUG_LOG_FILE' ) && WP_ROCKET_DEBUG_LOG_FILE && is_string( WP_ROCKET_DEBUG_LOG_FILE ) ) {
- // Make sure the file uses a ".log" extension.
- return preg_replace( '/\.[^.]*$/', '', WP_ROCKET_DEBUG_LOG_FILE ) . '.log';
- }
-
- if ( defined( 'WP_ROCKET_DEBUG_INTERVAL' ) ) {
- // Adds an optional logs rotator depending on a constant value - WP_ROCKET_DEBUG_INTERVAL (interval by minutes).
- $rotator = str_pad( round( ( strtotime( 'now' ) - strtotime( 'today midnight' ) ) / 60 / WP_ROCKET_DEBUG_INTERVAL ), 4, '0', STR_PAD_LEFT );
- return WP_CONTENT_DIR . '/wp-rocket-config/' . $rotator . '-' . static::LOG_FILE_NAME;
- } else {
- return WP_CONTENT_DIR . '/wp-rocket-config/' . static::LOG_FILE_NAME;
- }
- }
-
- /**
- * Get the log file contents.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @return string|object The file contents on success. A WP_Error object on failure.
- */
- public static function get_log_file_contents() {
- $filesystem = \rocket_direct_filesystem();
- $file_path = static::get_log_file_path();
-
- if ( ! $filesystem->exists( $file_path ) ) {
- return new \WP_Error( 'no_file', __( 'The log file does not exist.', 'rocket' ) );
- }
-
- $contents = $filesystem->get_contents( $file_path );
-
- if ( false === $contents ) {
- return new \WP_Error( 'file_not_read', __( 'The log file could not be read.', 'rocket' ) );
- }
-
- return $contents;
- }
-
- /**
- * Get the log file size and number of entries.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @return array|object An array of statistics on success. A WP_Error object on failure.
- */
- public static function get_log_file_stats() {
- $formatter = static::get_stream_formatter();
-
- if ( ! $formatter ) {
- return new \WP_Error( 'no_stream_formatter', __( 'The logs are not saved into a file.', 'rocket' ) );
- }
-
- $filesystem = \rocket_direct_filesystem();
- $file_path = static::get_log_file_path();
-
- if ( ! $filesystem->exists( $file_path ) ) {
- return new \WP_Error( 'no_file', __( 'The log file does not exist.', 'rocket' ) );
- }
-
- $contents = $filesystem->get_contents( $file_path );
-
- if ( false === $contents ) {
- return new \WP_Error( 'file_not_read', __( 'The log file could not be read.', 'rocket' ) );
- }
-
- if ( $formatter instanceof HtmlFormatter ) {
- $entries = preg_split( '@size( $file_path );
- $decimals = $bytes > pow( 1024, 3 ) ? 1 : 0;
- $bytes = @size_format( $bytes, $decimals );
- $bytes = str_replace( ' ', ' ', $bytes ); // Non-breaking space character.
-
- return compact( 'entries', 'bytes' );
- }
-
- /**
- * Get the log file extension related to the formatter in use. This can be used when the file is downloaded.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @return string The corresponding file extension with the heading dot.
- */
- public static function get_log_file_extension() {
- $formatter = static::get_stream_formatter();
-
- if ( ! $formatter ) {
- return '.log';
- }
-
- if ( $formatter instanceof HtmlFormatter ) {
- return '.html';
- }
-
- if ( $formatter instanceof LineFormatter ) {
- return '.txt';
- }
-
- return '.log';
- }
-
- /**
- * Delete the log file.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @return bool True on success. False on failure.
- */
- public static function delete_log_file() {
- $filesystem = \rocket_direct_filesystem();
- $file_path = static::get_log_file_path();
-
- if ( ! $filesystem->exists( $file_path ) ) {
- return true;
- }
-
- $filesystem->put_contents( $file_path, '' );
- $filesystem->delete( $file_path, false, 'f' );
-
- return ! $filesystem->exists( $file_path );
- }
-
- /**
- * Get the handler used for the log file.
- *
- * @since 3.2
- * @access public
- * @author Grégory Viguier
- *
- * @return object|bool The formatter object on success. False on failure.
- */
- public static function get_stream_handler() {
- $handlers = static::get_logger()->getHandlers();
-
- if ( ! $handlers ) {
- return false;
- }
-
- foreach ( $handlers as $_handler ) {
- if ( $_handler instanceof MonoStreamHandler ) {
- $handler = $_handler;
- break;
- }
- }
-
- if ( empty( $handler ) ) {
- return false;
- }
-
- return $handler;
- }
-
- /**
- * Get the formatter used for the log file.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @return object|bool The formatter object on success. False on failure.
- */
- public static function get_stream_formatter() {
- $handler = static::get_stream_handler();
-
- if ( empty( $handler ) ) {
- return false;
- }
-
- return $handler->getFormatter();
- }
-
-
- /** ----------------------------------------------------------------------------------------- */
- /** CONSTANT ================================================================================ */
- /** ----------------------------------------------------------------------------------------- */
-
- /**
- * Tell if debug is enabled.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @return bool
- */
- public static function debug_enabled() {
- return defined( 'WP_ROCKET_DEBUG' ) && WP_ROCKET_DEBUG;
- }
-
- /**
- * Enable debug mode by adding a constant in the `wp-config.php` file.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- */
- public static function enable_debug() {
- static::define_debug( true );
- }
-
- /**
- * Disable debug mode by removing the constant in the `wp-config.php` file.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- */
- public static function disable_debug() {
- static::define_debug( false );
- }
-
- /**
- * Enable or disable debug mode by adding or removing a constant in the `wp-config.php` file.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @param bool $enable True to enable debug, false to disable.
- */
- public static function define_debug( $enable ) {
- if ( $enable && static::debug_enabled() ) {
- // Debug is already enabled.
- return;
- }
-
- if ( ! $enable && ! static::debug_enabled() ) {
- // Debug is already disabled.
- return;
- }
-
- // Get the path to the file.
- $file_path = \rocket_find_wpconfig_path();
-
- if ( ! $file_path ) {
- // Couldn't get the path to the file.
- return;
- }
-
- // Get the content of the file.
- $filesystem = \rocket_direct_filesystem();
- $content = $filesystem->get_contents( $file_path );
-
- if ( false === $content ) {
- // Cound't get the content of the file.
- return;
- }
-
- // Remove previous value.
- $placeholder = '## WP_ROCKET_DEBUG placeholder ##';
- $content = preg_replace( '@^[\t ]*define\s*\(\s*["\']WP_ROCKET_DEBUG["\'].*$@miU', $placeholder, $content );
- $content = preg_replace( "@\n$placeholder@", '', $content );
-
- if ( $enable ) {
- // Add the constant.
- $define = "define( 'WP_ROCKET_DEBUG', true ); // Added by WP Rocket.\r\n";
- $content = preg_replace( '@<\?php\s*@i', "put_contents( $file_path, $content, $chmod );
- }
-
-
- /** ----------------------------------------------------------------------------------------- */
- /** TOOLS =================================================================================== */
- /** ----------------------------------------------------------------------------------------- */
-
- /**
- * Get the thread identifier.
- *
- * @since 3.3
- * @access public
- * @author Grégory Viguier
- *
- * @return string
- */
- public static function get_thread_id() {
- if ( ! isset( self::$thread_id ) ) {
- self::$thread_id = uniqid( '', true );
- }
-
- return self::$thread_id;
- }
-
- /**
- * Remove cookies related to WP auth.
- *
- * @since 3.1.4
- * @access public
- * @author Grégory Viguier
- *
- * @param array $cookies An array of cookies.
- * @return array
- */
- public static function remove_auth_cookies( $cookies = [] ) {
- if ( ! $cookies || ! is_array( $cookies ) ) {
- $cookies = $_COOKIE;
- }
-
- unset( $cookies['wordpress_test_cookie'] );
-
- if ( ! $cookies ) {
- return [];
- }
-
- $pattern = strtolower( '@^WordPress(?:user|pass|_sec|_logged_in)?_@' ); // Trolling PHPCS.
-
- foreach ( $cookies as $cookie_name => $value ) {
- if ( preg_match( $pattern, $cookie_name ) ) {
- $cookies[ $cookie_name ] = 'Value removed by WP Rocket.';
- }
- }
-
- return $cookies;
- }
+if ( isset( $rocket_path ) ) {
+ require_once $rocket_path . 'inc/Logger/Logger.php';
}
diff --git a/inc/classes/logger/class-stream-handler.php b/inc/classes/logger/class-stream-handler.php
index 7e80bd74e9..179267ed3c 100644
--- a/inc/classes/logger/class-stream-handler.php
+++ b/inc/classes/logger/class-stream-handler.php
@@ -1,147 +1,4 @@
create_htaccess_file();
- }
-
- /**
- * Create a .htaccess file in the log folder, to prevent direct access and directory listing.
- *
- * @since 3.2
- *
- * @throws \UnexpectedValueException When the .htaccess file could not be created.
- *
- * @return bool True if the file exists or has been created. False on failure.
- */
- public function create_htaccess_file() {
- if ( $this->htaccess_exists ) {
- return true;
- }
-
- if ( $this->has_error ) {
- return false;
- }
-
- $dir = $this->get_dir_from_stream( $this->url );
-
- if ( ! $dir || ! is_dir( $dir ) ) {
- $this->has_error = true;
- return false;
- }
-
- $file_path = $dir . '/.htaccess';
-
- if ( file_exists( $file_path ) ) {
- $this->htaccess_exists = true;
- return true;
- }
-
- $this->error_message = null;
-
- set_error_handler( [ $this, 'custom_error_handler' ] ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
-
- $file_resource = fopen( $file_path, 'a' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
-
- restore_error_handler();
-
- if ( ! is_resource( $file_resource ) ) {
- $this->has_error = true;
- throw new UnexpectedValueException( sprintf( 'The file "%s" could not be opened: ' . $this->error_message, $file_path ) );
- }
-
- $new_content = "\nOrder allow,deny\nDeny from all\n\nOptions -Indexes";
-
- fwrite( $file_resource, $new_content ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
- fclose( $file_resource ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
- @chmod( $file_path, 0644 );
-
- $this->htaccess_exists = true;
-
- return true;
- }
-
- /**
- * Temporary error handler that "cleans" the error messages.
- *
- * @since 3.2
- *
- * @see parent::customErrorHandler()
- *
- * @param int $code Error code.
- * @param string $msg Error message.
- */
- private function custom_error_handler( int $code, string $msg ) {
- $this->error_message = preg_replace( '{^(fopen|mkdir)\(.*?\): }', '', $msg );
- }
-
- /**
- * A dirname() that also works for streams, by removing the protocol.
- *
- * @since 3.2
- *
- * @see parent::getDirFromStream()
- *
- * @param string $stream Path to a file.
- *
- * @return null|string
- */
- private function get_dir_from_stream( string $stream ) {
- $pos = strpos( $stream, '://' );
-
- if ( false === $pos ) {
- return dirname( $stream );
- }
-
- if ( 'file://' === substr( $stream, 0, 7 ) ) {
- return dirname( substr( $stream, 7 ) );
- }
- }
+if ( isset( $rocket_path ) ) {
+ require_once $rocket_path . 'inc/Logger/StreamHandler.php';
}
diff --git a/tests/Fixtures/content/advancedCacheContent.php b/tests/Fixtures/content/advancedCacheContent.php
index 5e2e142de5..684db81f81 100644
--- a/tests/Fixtures/content/advancedCacheContent.php
+++ b/tests/Fixtures/content/advancedCacheContent.php
@@ -36,62 +36,7 @@
MOBILE_CONTENTS;
-$end = << \$rocket_path . 'inc/classes/Buffer/class-abstract-buffer.php',
- 'WP_Rocket\\\Buffer\\\Cache' => \$rocket_path . 'inc/classes/Buffer/class-cache.php',
- 'WP_Rocket\\\Buffer\\\Tests' => \$rocket_path . 'inc/classes/Buffer/class-tests.php',
- 'WP_Rocket\\\Buffer\\\Config' => \$rocket_path . 'inc/classes/Buffer/class-config.php',
- 'WP_Rocket\\\Logger\\\HTML_Formatter' => \$rocket_path . 'inc/classes/logger/class-html-formatter.php',
- 'WP_Rocket\\\Logger\\\Logger' => \$rocket_path . 'inc/classes/logger/class-logger.php',
- 'WP_Rocket\\\Logger\\\Stream_Handler' => \$rocket_path . 'inc/classes/logger/class-stream-handler.php',
- 'WP_Rocket\\\Traits\\\Memoize' => \$rocket_path . 'inc/classes/traits/trait-memoize.php',
- ];
-
- if ( isset( \$rocket_classes[ \$class ] ) ) {
- \$file = \$rocket_classes[ \$class ];
- } elseif ( strpos( \$class, 'Monolog\\\' ) === 0 ) {
- \$file = \$rocket_path . 'vendor/monolog/monolog/src/' . str_replace( '\\\', '/', \$class ) . '.php';
- } elseif ( strpos( \$class, 'Psr\\\Log\\\' ) === 0 ) {
- \$file = \$rocket_path . 'vendor/psr/log/' . str_replace( '\\\', '/', \$class ) . '.php';
- } else {
- return;
- }
-
- if ( file_exists( \$file ) ) {
- require \$file;
- }
- }
-);
-
-if ( ! class_exists( '\WP_Rocket\Buffer\Cache' ) ) {
- if ( ! defined( 'DONOTROCKETOPTIMIZE' ) ) {
- define( 'DONOTROCKETOPTIMIZE', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
- }
- return;
-}
-
-\$rocket_config_class = new Config(
- [
- 'config_dir_path' => \$rocket_config_path,
- ]
-);
-
-( new Cache(
- new Tests(
- \$rocket_config_class
- ),
- \$rocket_config_class,
- [
- 'cache_dir_path' => \$rocket_cache_path,
- ]
-) )->maybe_init_process();
-
-ENDING_CONTENTS;
+$end = file_get_contents(__DIR__ . '/endingContent.php');
return [
'non_mobile' => "{$start}{$end}",
diff --git a/tests/Fixtures/content/endingContent.php b/tests/Fixtures/content/endingContent.php
new file mode 100644
index 0000000000..682abb1203
--- /dev/null
+++ b/tests/Fixtures/content/endingContent.php
@@ -0,0 +1,76 @@
+
+
+spl_autoload_register(
+ function( $class ) use ( $rocket_path ) {
+ $rocket_classes = [
+ 'WP_Rocket\\Buffer\\Abstract_Buffer' => [ $rocket_path . 'inc/classes/Buffer/class-abstract-buffer.php' ],
+ 'WP_Rocket\\Buffer\\Cache' => [ $rocket_path . 'inc/classes/Buffer/class-cache.php' ],
+ 'WP_Rocket\\Buffer\\Tests' => [ $rocket_path . 'inc/classes/Buffer/class-tests.php' ],
+ 'WP_Rocket\\Buffer\\Config' => [ $rocket_path . 'inc/classes/Buffer/class-config.php' ],
+ 'WP_Rocket\\Logger\\HTMLFormatter' => [
+ $rocket_path . 'inc/Logger/HTMLFormatter.php',
+ $rocket_path . 'inc/classes/logger/class-html-formatter.php',
+ ],
+ 'WP_Rocket\\Logger\\Logger' => [
+ $rocket_path . 'inc/Logger/Logger.php',
+ $rocket_path . 'inc/classes/logger/class-logger.php',
+ ],
+ 'WP_Rocket\\Logger\\StreamHandler' => [
+ $rocket_path . 'inc/Logger/StreamHandler.php',
+ $rocket_path . 'inc/classes/logger/class-stream-handler.php',
+ ],
+ 'WP_Rocket\\Traits\\Memoize' => [ $rocket_path . 'inc/classes/traits/trait-memoize.php' ],
+ ];
+
+ if ( isset( $rocket_classes[ $class ] ) ) {
+ $file_options = $rocket_classes[ $class ];
+ $file = '';
+
+ foreach ( $file_options as $file_option ) {
+ if ( file_exists( $file_option ) ) {
+ $file = $file_option;
+ break;
+ }
+ }
+ } elseif ( strpos( $class, 'WP_Rocket\\Dependencies\\Monolog\\' ) === 0 ) {
+ $file = $rocket_path . 'inc/Dependencies/Monolog/' . str_replace( '\\', '/', $class ) . '.php';
+ if ( ! file_exists( $file ) ) {
+ $file = $rocket_path . 'vendor/monolog/monolog/src/' . str_replace( '\\', '/', $class ) . '.php';
+ }
+ } elseif ( strpos( $class, 'WP_Rocket\\Dependencies\\Psr\\Log\\' ) === 0 ) {
+ $file = $rocket_path . 'inc/Dependencies/Psr/Log/' . str_replace( '\\', '/', $class ) . '.php';
+ if ( ! file_exists( $file ) ) {
+ $file = $rocket_path . 'vendor/psr/log/' . str_replace( '\\', '/', $class ) . '.php';
+ }
+ } else {
+ return;
+ }
+
+ if ( file_exists( $file ) ) {
+ require $file;
+ }
+ }
+);
+
+if ( ! class_exists( '\WP_Rocket\Buffer\Cache' ) ) {
+ if ( ! defined( 'DONOTROCKETOPTIMIZE' ) ) {
+ define( 'DONOTROCKETOPTIMIZE', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
+ }
+ return;
+}
+
+$rocket_config_class = new Config(
+ [
+ 'config_dir_path' => $rocket_config_path,
+ ]
+);
+
+( new Cache(
+ new Tests(
+ $rocket_config_class
+ ),
+ $rocket_config_class,
+ [
+ 'cache_dir_path' => $rocket_cache_path,
+ ]
+) )->maybe_init_process();
diff --git a/tests/Fixtures/inc/Engine/Cache/AdminSubscriber/onUpdate.php b/tests/Fixtures/inc/Engine/Cache/AdminSubscriber/onUpdate.php
new file mode 100644
index 0000000000..9705c42cc7
--- /dev/null
+++ b/tests/Fixtures/inc/Engine/Cache/AdminSubscriber/onUpdate.php
@@ -0,0 +1,17 @@
+ [
+ 'config' => [
+ 'new_version' => '3.15',
+ 'old_version' => '3.14',
+ 'is_superior' => false
+ ],
+ ],
+ 'SuperiorShouldNotGenerate' => [
+ 'config' => [
+ 'new_version' => '3.17',
+ 'old_version' => '3.16',
+ 'is_superior' => true
+ ],
+ ],
+];
diff --git a/tests/Unit/inc/Engine/Cache/AdminSubscriber/onUpdate.php b/tests/Unit/inc/Engine/Cache/AdminSubscriber/onUpdate.php
new file mode 100644
index 0000000000..eec16920a3
--- /dev/null
+++ b/tests/Unit/inc/Engine/Cache/AdminSubscriber/onUpdate.php
@@ -0,0 +1,44 @@
+subscriber = new AdminSubscriber(
+ Mockery::mock( AdvancedCache::class ),
+ Mockery::mock( WPCache::class )
+ );
+ }
+
+ /**
+ * @dataProvider configTestData
+ */
+ public function testShouldDoAsExpected( $config )
+ {
+ if( $config['is_superior'] ) {
+ Functions\expect('rocket_generate_advanced_cache_file')->never();
+ } else {
+ Functions\expect('rocket_generate_advanced_cache_file');
+ }
+ $this->subscriber->on_update( $config['new_version'], $config['old_version'] );
+ }
+}
diff --git a/views/cache/advanced-cache.php b/views/cache/advanced-cache.php
index 018f69fd81..afdb524237 100644
--- a/views/cache/advanced-cache.php
+++ b/views/cache/advanced-cache.php
@@ -31,22 +31,45 @@
spl_autoload_register(
function( $class ) use ( $rocket_path ) {
$rocket_classes = [
- 'WP_Rocket\\Buffer\\Abstract_Buffer' => $rocket_path . 'inc/classes/Buffer/class-abstract-buffer.php',
- 'WP_Rocket\\Buffer\\Cache' => $rocket_path . 'inc/classes/Buffer/class-cache.php',
- 'WP_Rocket\\Buffer\\Tests' => $rocket_path . 'inc/classes/Buffer/class-tests.php',
- 'WP_Rocket\\Buffer\\Config' => $rocket_path . 'inc/classes/Buffer/class-config.php',
- 'WP_Rocket\\Logger\\HTML_Formatter' => $rocket_path . 'inc/classes/logger/class-html-formatter.php',
- 'WP_Rocket\\Logger\\Logger' => $rocket_path . 'inc/classes/logger/class-logger.php',
- 'WP_Rocket\\Logger\\Stream_Handler' => $rocket_path . 'inc/classes/logger/class-stream-handler.php',
- 'WP_Rocket\\Traits\\Memoize' => $rocket_path . 'inc/classes/traits/trait-memoize.php',
+ 'WP_Rocket\\Buffer\\Abstract_Buffer' => [ $rocket_path . 'inc/classes/Buffer/class-abstract-buffer.php' ],
+ 'WP_Rocket\\Buffer\\Cache' => [ $rocket_path . 'inc/classes/Buffer/class-cache.php' ],
+ 'WP_Rocket\\Buffer\\Tests' => [ $rocket_path . 'inc/classes/Buffer/class-tests.php' ],
+ 'WP_Rocket\\Buffer\\Config' => [ $rocket_path . 'inc/classes/Buffer/class-config.php' ],
+ 'WP_Rocket\\Logger\\HTMLFormatter' => [
+ $rocket_path . 'inc/Logger/HTMLFormatter.php',
+ $rocket_path . 'inc/classes/logger/class-html-formatter.php',
+ ],
+ 'WP_Rocket\\Logger\\Logger' => [
+ $rocket_path . 'inc/Logger/Logger.php',
+ $rocket_path . 'inc/classes/logger/class-logger.php',
+ ],
+ 'WP_Rocket\\Logger\\StreamHandler' => [
+ $rocket_path . 'inc/Logger/StreamHandler.php',
+ $rocket_path . 'inc/classes/logger/class-stream-handler.php',
+ ],
+ 'WP_Rocket\\Traits\\Memoize' => [ $rocket_path . 'inc/classes/traits/trait-memoize.php' ],
];
if ( isset( $rocket_classes[ $class ] ) ) {
- $file = $rocket_classes[ $class ];
- } elseif ( strpos( $class, 'Monolog\\' ) === 0 ) {
- $file = $rocket_path . 'vendor/monolog/monolog/src/' . str_replace( '\\', '/', $class ) . '.php';
- } elseif ( strpos( $class, 'Psr\\Log\\' ) === 0 ) {
- $file = $rocket_path . 'vendor/psr/log/' . str_replace( '\\', '/', $class ) . '.php';
+ $file_options = $rocket_classes[ $class ];
+ $file = '';
+
+ foreach ( $file_options as $file_option ) {
+ if ( file_exists( $file_option ) ) {
+ $file = $file_option;
+ break;
+ }
+ }
+ } elseif ( strpos( $class, 'WP_Rocket\\Dependencies\\Monolog\\' ) === 0 ) {
+ $file = $rocket_path . 'inc/Dependencies/Monolog/' . str_replace( '\\', '/', $class ) . '.php';
+ if ( ! file_exists( $file ) ) {
+ $file = $rocket_path . 'vendor/monolog/monolog/src/' . str_replace( '\\', '/', $class ) . '.php';
+ }
+ } elseif ( strpos( $class, 'WP_Rocket\\Dependencies\\Psr\\Log\\' ) === 0 ) {
+ $file = $rocket_path . 'inc/Dependencies/Psr/Log/' . str_replace( '\\', '/', $class ) . '.php';
+ if ( ! file_exists( $file ) ) {
+ $file = $rocket_path . 'vendor/psr/log/' . str_replace( '\\', '/', $class ) . '.php';
+ }
} else {
return;
}