gments, -1 )[0]; } else { $parsed['source'] = implode( '-', $segments ); } $rotation_marker = strrpos( $parsed['source'], '.', -1 ); if ( false !== $rotation_marker ) { $rotation = substr( $parsed['source'], -1 ); if ( is_numeric( $rotation ) ) { $parsed['rotation'] = intval( $rotation ); } $parsed['source'] = substr( $parsed['source'], 0, $rotation_marker ); } $parsed['file_id'] = static::generate_file_id( $parsed['source'], $parsed['rotation'], $parsed['created'] ); return $parsed; } /** * Generate a public ID for a log file based on its properties. * * The file ID is the basename of the file without the hash part. It allows us to identify a file without revealing * its full name in the filesystem, so that it's difficult to access the file directly with an HTTP request. * * @param string $source The source of the log entries contained in the file. * @param int|null $rotation Optional. The 0-based incremental rotation marker, if the file has been rotated. * Should only be a single digit. * @param int $created Optional. The date the file was created, as a Unix timestamp. * * @return string */ public static function generate_file_id( string $source, ?int $rotation = null, int $created = 0 ): string { $file_id = static::sanitize_source( $source ); if ( ! is_null( $rotation ) ) { $file_id .= '.' . $rotation; } if ( $created > 0 ) { $file_id .= '-' . gmdate( 'Y-m-d', $created ); } return $file_id; } /** * Generate a hash to use as the suffix on a log filename. * * @param string $file_id A file ID (file basename without the hash). * * @return string */ public static function generate_hash( string $file_id ): string { $key = Constants::get_constant( 'AUTH_SALT' ) ?? 'wc-logs'; return hash_hmac( 'md5', $file_id, $key ); } /** * Sanitize the source property of a log file. * * @param string $source The source of the log entries contained in the file. * * @return string */ public static function sanitize_source( string $source ): string { return sanitize_file_name( $source ); } /** * Parse the log file path and assign various properties to this class instance. * * @return void */ protected function ingest_path(): void { $parsed_path = static::parse_path( $this->path ); $this->source = $parsed_path['source']; $this->rotation = $parsed_path['rotation']; $this->created = $parsed_path['created']; $this->hash = $parsed_path['hash']; } /** * Check if the filename structure is in the expected format. * * @see parse_path(). * * @return bool */ public function has_standard_filename(): bool { return ! ! $this->get_hash(); } /** * Check if the file represented by the class instance is a file and is readable. * * @return bool */ public function is_readable(): bool { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $is_readable = $filesystem->is_file( $this->path ) && $filesystem->is_readable( $this->path ); } catch ( Exception $exception ) { return false; } return $is_readable; } /** * Check if the file represented by the class instance is a file and is writable. * * @return bool */ public function is_writable(): bool { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $is_writable = $filesystem->is_file( $this->path ) && $filesystem->is_writable( $this->path ); } catch ( Exception $exception ) { return false; } return $is_writable; } /** * Open a read-only stream for this file. * * @return resource|false */ public function get_stream() { if ( ! $this->is_readable() ) { return false; } if ( ! is_resource( $this->stream ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen -- No suitable alternative. $this->stream = fopen( $this->path, 'rb' ); } return $this->stream; } /** * Close the stream for this file. * * The stream will also close automatically when the class instance destructs, but this can be useful for * avoiding having a large number of streams open simultaneously. * * @return bool */ public function close_stream(): bool { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose -- No suitable alternative. return fclose( $this->stream ); } /** * Get the full absolute path of the file. * * @return string */ public function get_path(): string { return $this->path; } /** * Get the name of the file, with extension, but without full path. * * @return string */ public function get_basename(): string { return basename( $this->path ); } /** * Get the file's source property. * * @return string */ public function get_source(): string { return $this->source; } /** * Get the file's rotation property. * * @return int|null */ public function get_rotation(): ?int { return $this->rotation; } /** * Get the file's hash property. * * @return string */ public function get_hash(): string { return $this->hash; } /** * Get the file's public ID. * * @return string */ public function get_file_id(): string { $created = 0; if ( $this->has_standard_filename() ) { $created = $this->get_created_timestamp(); } $file_id = static::generate_file_id( $this->get_source(), $this->get_rotation(), $created ); return $file_id; } /** * Get the file's created property. * * @return int */ public function get_created_timestamp(): int { if ( ! $this->created && $this->is_readable() ) { $this->created = filectime( $this->path ); } return $this->created; } /** * Get the time of the last modification of the file, as a Unix timestamp. Or false if the file isn't readable. * * @return int|false */ public function get_modified_timestamp() { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $timestamp = $filesystem->mtime( $this->path ); } catch ( Exception $exception ) { return false; } return $timestamp; } /** * Get the size of the file in bytes. Or false if the file isn't readable. * * @return int|false */ public function get_file_size() { try { $filesystem = FilesystemUtil::get_wp_filesystem(); if ( ! $filesystem->is_readable( $this->path ) ) { return false; } $size = $filesystem->size( $this->path ); } catch ( Exception $exception ) { return false; } return $size; } /** * Create and set permissions on the file. * * @return bool */ protected function create(): bool { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $created = $filesystem->touch( $this->path ); $modded = $filesystem->chmod( $this->path ); } catch ( Exception $exception ) { return false; } return $created && $modded; } /** * Write content to the file, appending it to the end. * * @param string $text The content to add to the file. * * @return bool */ public function write( string $text ): bool { if ( '' === $text ) { return false; } if ( ! $this->is_writable() ) { $created = $this->create(); if ( ! $created || ! $this->is_writable() ) { return false; } } // Ensure content ends with a line ending. $eol_pos = strrpos( $text, PHP_EOL ); if ( false === $eol_pos || strlen( $text ) !== $eol_pos + 1 ) { $text .= PHP_EOL; } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen -- No suitable alternative. $resource = fopen( $this->path, 'ab' ); mbstring_binary_safe_encoding(); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite -- No suitable alternative. $bytes_written = fwrite( $resource, $text ); reset_mbstring_encoding(); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose -- No suitable alternative. fclose( $resource ); if ( strlen( $text ) !== $bytes_written ) { return false; } return true; } /** * Rename this file with an incremented rotation number. * * @return bool True if the file was successfully rotated. */ public function rotate(): bool { if ( ! $this->is_writable() ) { return false; } $created = 0; if ( $this->has_standard_filename() ) { $created = $this->get_created_timestamp(); } if ( is_null( $this->get_rotation() ) ) { $new_rotation = 0; } else { $new_rotation = $this->get_rotation() + 1; } $new_file_id = static::generate_file_id( $this->get_source(), $new_rotation, $created ); $search = array( $this->get_file_id() ); $replace = array( $new_file_id ); if ( $this->has_standard_filename() ) { $search[] = $this->get_hash(); $replace[] = static::generate_hash( $new_file_id ); } $old_filename = $this->get_basename(); $new_filename = str_replace( $search, $replace, $old_filename ); $new_path = str_replace( $old_filename, $new_filename, $this->path ); try { $filesystem = FilesystemUtil::get_wp_filesystem(); $moved = $filesystem->move( $this->path, $new_path, true ); } catch ( Exception $exception ) { return false; } if ( ! $moved ) { return false; } $this->path = $new_path; $this->ingest_path(); return $this->is_readable(); } /** * Delete the file from the filesystem. * * @return bool True on success, false on failure. */ public function delete(): bool { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $deleted = $filesystem->delete( $this->path, false, 'f' ); } catch ( Exception $exception ) { return false; } return $deleted; } }
Fatal error: Uncaught Error: Class "Automattic\WooCommerce\Internal\Admin\Logging\FileV2\File" not found in /htdocs/wp-content/plugins/woocommerce/src/Utilities/LoggingUtil.php:72 Stack trace: #0 /htdocs/wp-content/plugins/woocommerce/includes/wc-deprecated-functions.php(1160): Automattic\WooCommerce\Utilities\LoggingUtil::generate_log_file_id('social_login_hy...', NULL, 1719676111) #1 /htdocs/wp-content/plugins/woocommerce-social-login/includes/class-wc-social-login-hybridauth.php(81): wc_get_log_file_path('social_login_hy...') #2 /htdocs/wp-includes/class-wp-hook.php(324): WC_Social_Login_HybridAuth->init_config('') #3 /htdocs/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters(NULL, Array) #4 /htdocs/wp-includes/plugin.php(517): WP_Hook->do_action(Array) #5 /htdocs/wp-settings.php(643): do_action('init') #6 /htdocs/wp-config.php(178): require_once('/htdocs/wp-sett...') #7 /htdocs/wp-load.php(50): require_once('/htdocs/wp-conf...') #8 /htdocs/wp-blog-header.php(13): require_once('/htdocs/wp-load...') #9 /htdocs/index.php(17): require('/htdocs/wp-blog...') #10 {main} thrown in /htdocs/wp-content/plugins/woocommerce/src/Utilities/LoggingUtil.php on line 72
gments, -1 )[0]; } else { $parsed['source'] = implode( '-', $segments ); } $rotation_marker = strrpos( $parsed['source'], '.', -1 ); if ( false !== $rotation_marker ) { $rotation = substr( $parsed['source'], -1 ); if ( is_numeric( $rotation ) ) { $parsed['rotation'] = intval( $rotation ); } $parsed['source'] = substr( $parsed['source'], 0, $rotation_marker ); } $parsed['file_id'] = static::generate_file_id( $parsed['source'], $parsed['rotation'], $parsed['created'] ); return $parsed; } /** * Generate a public ID for a log file based on its properties. * * The file ID is the basename of the file without the hash part. It allows us to identify a file without revealing * its full name in the filesystem, so that it's difficult to access the file directly with an HTTP request. * * @param string $source The source of the log entries contained in the file. * @param int|null $rotation Optional. The 0-based incremental rotation marker, if the file has been rotated. * Should only be a single digit. * @param int $created Optional. The date the file was created, as a Unix timestamp. * * @return string */ public static function generate_file_id( string $source, ?int $rotation = null, int $created = 0 ): string { $file_id = static::sanitize_source( $source ); if ( ! is_null( $rotation ) ) { $file_id .= '.' . $rotation; } if ( $created > 0 ) { $file_id .= '-' . gmdate( 'Y-m-d', $created ); } return $file_id; } /** * Generate a hash to use as the suffix on a log filename. * * @param string $file_id A file ID (file basename without the hash). * * @return string */ public static function generate_hash( string $file_id ): string { $key = Constants::get_constant( 'AUTH_SALT' ) ?? 'wc-logs'; return hash_hmac( 'md5', $file_id, $key ); } /** * Sanitize the source property of a log file. * * @param string $source The source of the log entries contained in the file. * * @return string */ public static function sanitize_source( string $source ): string { return sanitize_file_name( $source ); } /** * Parse the log file path and assign various properties to this class instance. * * @return void */ protected function ingest_path(): void { $parsed_path = static::parse_path( $this->path ); $this->source = $parsed_path['source']; $this->rotation = $parsed_path['rotation']; $this->created = $parsed_path['created']; $this->hash = $parsed_path['hash']; } /** * Check if the filename structure is in the expected format. * * @see parse_path(). * * @return bool */ public function has_standard_filename(): bool { return ! ! $this->get_hash(); } /** * Check if the file represented by the class instance is a file and is readable. * * @return bool */ public function is_readable(): bool { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $is_readable = $filesystem->is_file( $this->path ) && $filesystem->is_readable( $this->path ); } catch ( Exception $exception ) { return false; } return $is_readable; } /** * Check if the file represented by the class instance is a file and is writable. * * @return bool */ public function is_writable(): bool { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $is_writable = $filesystem->is_file( $this->path ) && $filesystem->is_writable( $this->path ); } catch ( Exception $exception ) { return false; } return $is_writable; } /** * Open a read-only stream for this file. * * @return resource|false */ public function get_stream() { if ( ! $this->is_readable() ) { return false; } if ( ! is_resource( $this->stream ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen -- No suitable alternative. $this->stream = fopen( $this->path, 'rb' ); } return $this->stream; } /** * Close the stream for this file. * * The stream will also close automatically when the class instance destructs, but this can be useful for * avoiding having a large number of streams open simultaneously. * * @return bool */ public function close_stream(): bool { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose -- No suitable alternative. return fclose( $this->stream ); } /** * Get the full absolute path of the file. * * @return string */ public function get_path(): string { return $this->path; } /** * Get the name of the file, with extension, but without full path. * * @return string */ public function get_basename(): string { return basename( $this->path ); } /** * Get the file's source property. * * @return string */ public function get_source(): string { return $this->source; } /** * Get the file's rotation property. * * @return int|null */ public function get_rotation(): ?int { return $this->rotation; } /** * Get the file's hash property. * * @return string */ public function get_hash(): string { return $this->hash; } /** * Get the file's public ID. * * @return string */ public function get_file_id(): string { $created = 0; if ( $this->has_standard_filename() ) { $created = $this->get_created_timestamp(); } $file_id = static::generate_file_id( $this->get_source(), $this->get_rotation(), $created ); return $file_id; } /** * Get the file's created property. * * @return int */ public function get_created_timestamp(): int { if ( ! $this->created && $this->is_readable() ) { $this->created = filectime( $this->path ); } return $this->created; } /** * Get the time of the last modification of the file, as a Unix timestamp. Or false if the file isn't readable. * * @return int|false */ public function get_modified_timestamp() { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $timestamp = $filesystem->mtime( $this->path ); } catch ( Exception $exception ) { return false; } return $timestamp; } /** * Get the size of the file in bytes. Or false if the file isn't readable. * * @return int|false */ public function get_file_size() { try { $filesystem = FilesystemUtil::get_wp_filesystem(); if ( ! $filesystem->is_readable( $this->path ) ) { return false; } $size = $filesystem->size( $this->path ); } catch ( Exception $exception ) { return false; } return $size; } /** * Create and set permissions on the file. * * @return bool */ protected function create(): bool { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $created = $filesystem->touch( $this->path ); $modded = $filesystem->chmod( $this->path ); } catch ( Exception $exception ) { return false; } return $created && $modded; } /** * Write content to the file, appending it to the end. * * @param string $text The content to add to the file. * * @return bool */ public function write( string $text ): bool { if ( '' === $text ) { return false; } if ( ! $this->is_writable() ) { $created = $this->create(); if ( ! $created || ! $this->is_writable() ) { return false; } } // Ensure content ends with a line ending. $eol_pos = strrpos( $text, PHP_EOL ); if ( false === $eol_pos || strlen( $text ) !== $eol_pos + 1 ) { $text .= PHP_EOL; } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen -- No suitable alternative. $resource = fopen( $this->path, 'ab' ); mbstring_binary_safe_encoding(); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite -- No suitable alternative. $bytes_written = fwrite( $resource, $text ); reset_mbstring_encoding(); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose -- No suitable alternative. fclose( $resource ); if ( strlen( $text ) !== $bytes_written ) { return false; } return true; } /** * Rename this file with an incremented rotation number. * * @return bool True if the file was successfully rotated. */ public function rotate(): bool { if ( ! $this->is_writable() ) { return false; } $created = 0; if ( $this->has_standard_filename() ) { $created = $this->get_created_timestamp(); } if ( is_null( $this->get_rotation() ) ) { $new_rotation = 0; } else { $new_rotation = $this->get_rotation() + 1; } $new_file_id = static::generate_file_id( $this->get_source(), $new_rotation, $created ); $search = array( $this->get_file_id() ); $replace = array( $new_file_id ); if ( $this->has_standard_filename() ) { $search[] = $this->get_hash(); $replace[] = static::generate_hash( $new_file_id ); } $old_filename = $this->get_basename(); $new_filename = str_replace( $search, $replace, $old_filename ); $new_path = str_replace( $old_filename, $new_filename, $this->path ); try { $filesystem = FilesystemUtil::get_wp_filesystem(); $moved = $filesystem->move( $this->path, $new_path, true ); } catch ( Exception $exception ) { return false; } if ( ! $moved ) { return false; } $this->path = $new_path; $this->ingest_path(); return $this->is_readable(); } /** * Delete the file from the filesystem. * * @return bool True on success, false on failure. */ public function delete(): bool { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $deleted = $filesystem->delete( $this->path, false, 'f' ); } catch ( Exception $exception ) { return false; } return $deleted; } }
Fatal error: Uncaught Error: Class "Automattic\WooCommerce\Internal\Admin\Logging\FileV2\File" not found in /htdocs/wp-content/plugins/woocommerce/src/Internal/Admin/Logging/FileV2/FileController.php:117 Stack trace: #0 /htdocs/wp-content/plugins/woocommerce/src/Internal/Admin/Logging/LogHandlerFileV2.php(60): Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController->write_to_file('fatal-errors', '2024-06-29T15:4...', 1719676111) #1 /htdocs/wp-content/plugins/woocommerce/includes/class-wc-logger.php(189): Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2->handle(1719676111, 'critical', 'Uncaught Error:...', Array) #2 /htdocs/wp-content/plugins/woocommerce/includes/class-wc-logger.php(236): WC_Logger->log('critical', 'Uncaught Error:...', Array) #3 /htdocs/wp-content/plugins/woocommerce/includes/class-woocommerce.php(359): WC_Logger->critical('Uncaught Error:...', Array) #4 [internal function]: WooCommerce->log_errors() #5 {main} thrown in /htdocs/wp-content/plugins/woocommerce/src/Internal/Admin/Logging/FileV2/FileController.php on line 117