| Current Path : /home/ereika83/public_html/wp-content/plugins/sfwd-lms/includes/loggers/ |
| Current File : /home/ereika83/public_html/wp-content/plugins/sfwd-lms/includes/loggers/class-learndash-logger.php |
<?php
/**
* This class provides an easy way to log everything.
*
* @since 4.5.0
*
* @package LearnDash
*/
use LearnDash\Core\Utilities\Cast;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'Learndash_Logger' ) ) {
/**
* Logger class.
*
* @since 4.5.0
*/
abstract class Learndash_Logger {
private const PATH_ID = 'learndash_logs';
private const PATH = 'learndash' . DIRECTORY_SEPARATOR . 'logs';
private const EXTENSION = '.log';
private const SUFFIXES_META_KEY = 'learndash_log_suffixes';
private const DEFAULT_MAX_SIZE_IN_BYTES = 10485760; // 10MB.
/**
* Instructions to protect the path against direct access.
*
* @since 4.5.0
*
* @var string
*/
private static $file_protection_instructions = '';
/**
* Log file stream.
*
* @since 4.5.0
*
* @var resource|null|false
*/
private $log_stream = null;
/**
* List on initialized loggers.
*
* @since 4.5.0
*
* @var Learndash_Logger[]
*/
private static $loggers = array();
/**
* Returns the logger instance if available.
*
* @since 4.5.0
*
* @param string $name Logger name.
*
* @return Learndash_Logger|null
*/
public static function get_instance( string $name ): ?self {
return self::$loggers[ $name ] ?? null;
}
/**
* Logger destructor.
*
* @since 4.5.0
*
* @return void
*/
public function __destruct() {
if ( is_resource( $this->log_stream ) ) {
fclose( $this->log_stream ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
}
}
/**
* Inits a logger.
*
* @since 4.5.0
*
* @return void
*/
final public function init(): void {
self::$loggers[ $this->get_name() ] = $this;
}
/**
* Returns the label.
*
* @since 4.5.0
*
* @return string
*/
abstract public function get_label(): string;
/**
* Returns the name.
*
* @since 4.5.0
*
* @return string
*/
abstract public function get_name(): string;
/**
* Creates the logger resource if needed.
*
* @since 4.5.0
*
* @return void
*/
private function maybe_create_resource() {
if ( is_resource( $this->log_stream ) ) {
return;
}
try {
$this->maybe_rotate_file();
$this->log_stream = fopen( // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
self::get_log_path( $this->get_name() ),
'a'
);
} catch ( Exception $e ) {
return;
}
}
/**
* Rotates the log file if needed.
*
* @return void
*/
private function maybe_rotate_file() {
$log_path = self::get_log_path( $this->get_name() );
if ( ! is_file( $log_path ) ) {
return;
}
$file_size = filesize( $log_path );
if ( ! $file_size ) {
return;
}
/**
* Filters the maximum log file size in bytes.
*
* @since 4.5.0
*
* @param int $max_size Maximum log file size in bytes.
* @param Learndash_Logger $learndash_logger Logger instance.
*/
$max_file_size = apply_filters( 'learndash_logger_max_file_size', self::DEFAULT_MAX_SIZE_IN_BYTES, $this );
if ( $file_size < $max_file_size ) {
return;
}
// calculate the new size.
$new_file_size = min( $max_file_size, $file_size * 0.9 ); // reduce the file size by 10%.
// create a temporary file to save the new data.
$temp_path = $log_path . '.tmp';
$temp_file = fopen( $temp_path, 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
if ( ! $temp_file ) {
return;
}
// copy the data from the log file to the temporary file skipping the first part.
$log_file = fopen( $log_path, 'r' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
if ( ! $log_file ) {
return;
}
fseek( $log_file, (int) ( $file_size - $new_file_size ) );
while ( ! feof( $log_file ) ) {
if ( $content = fgets( $log_file ) ) { // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found,Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
fwrite( $temp_file, $content ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
}
}
// move the temporary file to the log file.
rename( $temp_path, $log_path );
fclose( $temp_file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
fclose( $log_file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
}
/**
* Writes to the log file.
*
* @since 4.5.0
*
* @param string $formatted_message Formatted message.
* @param string $prefix Prefix. Default empty.
*
* @return void
*/
private function write( string $formatted_message, string $prefix = '' ): void {
try {
if ( ! $this->is_enabled() ) {
return;
}
} catch ( Exception $e ) {
return;
}
$this->maybe_create_resource();
if ( ! is_resource( $this->log_stream ) ) {
return;
}
if ( ! empty( $prefix ) ) {
$formatted_message = '[' . $prefix . '] ' . $formatted_message;
}
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
fwrite( $this->log_stream, current_time( 'Y-m-d H:i:s: ' ) . $formatted_message . PHP_EOL );
}
/**
* Writes an information to the log file.
*
* @since 4.5.0
*
* @param string $message Message.
* @param string $prefix Prefix. Optional.
*
* @return void
*/
public function info( string $message, string $prefix = '' ): void {
$this->write( $message, $prefix );
}
/**
* Writes an error to the log file.
*
* @since 4.5.0
*
* @param string $message Message.
* @param string $prefix Prefix. Optional.
*
* @return void
*/
public function error( string $message, string $prefix = '' ): void {
$this->write( 'Error: ' . $message, $prefix );
}
/**
* Returns the download URL.
*
* @since 4.5.0
*
* @return string
*/
public function get_download_url(): string {
return Learndash_Admin_File_Download_Handler::get_download_url(
self::PATH_ID,
basename( $this->get_log_path( $this->get_name() ) )
);
}
/**
* Checks if the logger file exists.
*
* @since 4.5.0
*
* @return bool True if the logger file exists, false otherwise.
*/
public function log_exists(): bool {
return file_exists( $this->get_log_path( $this->get_name() ) );
}
/**
* Returns the log content.
*
* @since 4.5.0
*
* @return string
*/
public function get_content(): string {
$log_path = $this->get_log_path( $this->get_name() );
if ( ! file_exists( $log_path ) ) {
return '';
}
$content = file_get_contents( $log_path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
if ( false === $content ) {
return '';
}
return $content;
}
/**
* Deletes the log content.
*
* @since 4.5.0
*
* @return bool
*/
public function delete_content(): bool {
$log_path = $this->get_log_path( $this->get_name() );
if ( ! file_exists( $log_path ) ) {
return true;
}
return unlink( $log_path );
}
/**
* Returns the path to the log file in the "uploads" directory.
*
* @param string $file_name Log file name. Default empty.
*
* @since 4.5.0
*
* @return string
*/
private static function get_log_path( string $file_name = '' ): string {
$log_path = trailingslashit( wp_upload_dir()['basedir'] ) . self::PATH;
if ( ! empty( $file_name ) ) {
$logs_suffixes = (array) get_option( self::SUFFIXES_META_KEY, array() );
$file_suffix = isset( $logs_suffixes[ $file_name ] )
? basename( Cast::to_string( $logs_suffixes[ $file_name ] ) )
: '';
if ( empty( $file_suffix ) ) {
$logs_suffixes[ $file_name ] = uniqid( '', true );
update_option( self::SUFFIXES_META_KEY, $logs_suffixes );
$file_suffix = $logs_suffixes[ $file_name ];
}
$log_path .= DIRECTORY_SEPARATOR . $file_name . $file_suffix . self::EXTENSION;
}
return $log_path;
}
/**
* Initialize the log directory
*
* @since 4.5.0
*
* @return void
*/
public static function init_log_directory() {
$log_dir = self::get_log_path();
if ( ! is_dir( $log_dir ) ) {
wp_mkdir_p( $log_dir );
}
learndash_put_directory_index_file( trailingslashit( $log_dir ) . 'index.php' );
Learndash_Admin_File_Download_Handler::register_file_path( self::PATH_ID, $log_dir );
self::$file_protection_instructions = Learndash_Admin_File_Download_Handler::try_to_protect_file_path( $log_dir );
}
/**
* Returns the file protection instructions.
*
* @since 4.5.0
*
* @return string
*/
public static function get_file_protection_instructions(): string {
return self::$file_protection_instructions;
}
/**
* Gets loggers select. Keys are logger names and values are logger labels.
*
* @since 4.5.0
*
* @return array<string,string>
*/
public static function get_select_list(): array {
$result = array();
foreach ( self::$loggers as $logger ) {
$result[ $logger->get_name() ] = $logger->get_label();
}
return $result;
}
/**
* Returns true if the logger is enabled, false otherwise.
*
* @since 4.5.0
*
* @throws Exception If the call is too early.
*
* @return bool
*/
public function is_enabled(): bool {
if ( empty( self::$loggers ) ) {
throw new Exception( 'The loggers are not initialized yet.' );
}
$enabled = LearnDash_Settings_Section::get_section_setting(
'LearnDash_Settings_Section_Logs',
$this->get_name()
);
return 'yes' === $enabled;
}
}
}