add wp-rocket
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Logger;
|
||||
|
||||
use Monolog\Formatter\HtmlFormatter;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class used to format log records as HTML.
|
||||
*
|
||||
* @since 3.2
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class HTML_Formatter extends HtmlFormatter {
|
||||
|
||||
/**
|
||||
* Formats a log record.
|
||||
* Compared to the parent method, it removes the "channel" row.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param array $record A record to format.
|
||||
* @return mixed The formatted record.
|
||||
*/
|
||||
public function format( array $record ) {
|
||||
$output = $this->addTitle( $record['level_name'], $record['level'] );
|
||||
$output .= '<table cellspacing="1" width="100%" class="monolog-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 = '<table cellspacing="1" width="100%">';
|
||||
|
||||
foreach ( $record['context'] as $key => $value ) {
|
||||
$embedded_table .= $this->addRow( $key, $this->convertToString( $value ) );
|
||||
}
|
||||
|
||||
$embedded_table .= '</table>';
|
||||
$output .= $this->addRow( 'Context', $embedded_table, false );
|
||||
}
|
||||
|
||||
if ( $record['extra'] ) {
|
||||
$embedded_table = '<table cellspacing="1" width="100%">';
|
||||
|
||||
foreach ( $record['extra'] as $key => $value ) {
|
||||
$embedded_table .= $this->addRow( $key, $this->convertToString( $value ) );
|
||||
}
|
||||
|
||||
$embedded_table .= '</table>';
|
||||
$output .= $this->addRow( 'Extra', $embedded_table, false );
|
||||
}
|
||||
|
||||
return $output . '</table>';
|
||||
}
|
||||
}
|
557
wp-content/plugins/wp-rocket/inc/classes/logger/class-logger.php
Normal file
557
wp-content/plugins/wp-rocket/inc/classes/logger/class-logger.php
Normal file
@@ -0,0 +1,557 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Logger;
|
||||
|
||||
use Monolog\Logger as Monologger;
|
||||
use Monolog\Registry;
|
||||
use Monolog\Processor\IntrospectionProcessor;
|
||||
use Monolog\Handler\StreamHandler as MonoStreamHandler;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
use WP_Rocket\Logger\HTML_Formatter as HtmlFormatter;
|
||||
use WP_Rocket\Logger\Stream_Handler as StreamHandler;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class used to log events.
|
||||
*
|
||||
* @since 3.1.4
|
||||
* @since 3.2 Changed namespace from \WP_Rocket to \WP_Rocket\Logger.
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class Logger {
|
||||
|
||||
/**
|
||||
* Logger name.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.1.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
const LOGGER_NAME = 'wp_rocket';
|
||||
|
||||
/**
|
||||
* Name of the logs file.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.1.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
const LOG_FILE_NAME = 'wp-rocket-debug.log.html';
|
||||
|
||||
/**
|
||||
* A unique ID given to the current thread.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.3
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private static $thread_id;
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** LOG ===================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Adds a log record at the DEBUG 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 debug( $message, array $context = [] ) {
|
||||
return static::debug_enabled() ? static::get_logger()->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';
|
||||
}
|
||||
|
||||
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( '@<h1 @', $contents );
|
||||
} elseif ( $formatter instanceof LineFormatter ) {
|
||||
$entries = preg_split( '@^\[\d{4,}-\d{2,}-\d{2,} \d{2,}:\d{2,}:\d{2,}] @m', $contents );
|
||||
} else {
|
||||
$entries = 0;
|
||||
}
|
||||
|
||||
$entries = $entries ? number_format_i18n( count( $entries ) ) : '0';
|
||||
$bytes = $filesystem->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', "<?php\n$define", $content, 1 );
|
||||
}
|
||||
|
||||
// Save the file.
|
||||
$chmod = rocket_get_filesystem_perms( 'file' );
|
||||
$filesystem->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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Logger;
|
||||
|
||||
use Monolog\Handler\StreamHandler;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class used to log records into a local file.
|
||||
*
|
||||
* @since 3.2
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class Stream_Handler extends StreamHandler {
|
||||
|
||||
/**
|
||||
* Tell if the .htaccess file exists.
|
||||
*
|
||||
* @var bool
|
||||
* @since 3.2
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $htaccess_exists;
|
||||
|
||||
/**
|
||||
* Tell if there is an error.
|
||||
*
|
||||
* @var bool
|
||||
* @since 3.2
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $has_error;
|
||||
|
||||
/**
|
||||
* Contains an error message.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $error_message;
|
||||
|
||||
/**
|
||||
* Writes the record down to the log of the implementing handler.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param array $record Log contents.
|
||||
*/
|
||||
protected function write( array $record ) {
|
||||
parent::write( $record );
|
||||
$this->create_htaccess_file();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a .htaccess file in the log folder, to prevent direct access and directory listing.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access protected
|
||||
* @throws \UnexpectedValueException When the .htaccess file could not be created.
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @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 = "<Files ~ \"\.log$\">\nOrder allow,deny\nDeny from all\n</Files>\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
|
||||
* @access private
|
||||
* @see parent::customErrorHandler()
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param int $code Error code.
|
||||
* @param string $msg Error message.
|
||||
*/
|
||||
private function custom_error_handler( $code, $msg ) {
|
||||
$this->error_message = preg_replace( '{^(fopen|mkdir)\(.*?\): }', '', $msg );
|
||||
}
|
||||
|
||||
/**
|
||||
* A dirname() that also works for streams, by removing the protocol.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access private
|
||||
* @see parent::getDirFromStream()
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $stream Path to a file.
|
||||
* @return null|string
|
||||
*/
|
||||
private function get_dir_from_stream( $stream ) {
|
||||
$pos = strpos( $stream, '://' );
|
||||
|
||||
if ( false === $pos ) {
|
||||
return dirname( $stream );
|
||||
}
|
||||
|
||||
if ( 'file://' === substr( $stream, 0, 7 ) ) {
|
||||
return dirname( substr( $stream, 7 ) );
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user