From d804bb1fdb863a7b04239241bebcc1d7f0012e0d Mon Sep 17 00:00:00 2001 From: rjchow Date: Wed, 18 Sep 2024 12:44:59 +1000 Subject: [PATCH] lint --- .../src/Internal/Logging/RemoteLogger.php | 17 ++- .../Logging/SafeGlobalExecutionProxy.php | 126 ------------------ .../Logging/SafeGlobalFunctionProxy.php | 115 ++++++++++++++++ 3 files changed, 128 insertions(+), 130 deletions(-) delete mode 100644 plugins/woocommerce/src/Internal/Logging/SafeGlobalExecutionProxy.php create mode 100644 plugins/woocommerce/src/Internal/Logging/SafeGlobalFunctionProxy.php diff --git a/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php b/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php index 8581efbe6e6..5ab1e28ab20 100644 --- a/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php +++ b/plugins/woocommerce/src/Internal/Logging/RemoteLogger.php @@ -77,7 +77,7 @@ class RemoteLogger extends \WC_Log_Handler { 'host' => SafeGlobalFunctionProxy::wp_parse_url( SafeGlobalFunctionProxy::home_url(), PHP_URL_HOST ) ?? 'Unable to retrieve host', 'tags' => array( 'woocommerce', 'php' ), 'properties' => array( - 'wc_version' => $this->get_wc_version(), // TODO check this + 'wc_version' => $this->get_wc_version(), 'php_version' => phpversion(), 'wp_version' => SafeGlobalFunctionProxy::get_bloginfo( 'version' ) ?? 'Unable to retrieve wp version', 'request_uri' => $this->sanitize_request_uri( filter_input( INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL ) ), @@ -250,7 +250,7 @@ class RemoteLogger extends \WC_Log_Handler { ) ); - if ( SafeGlobalFunctionProxy::is_wp_error( $response ) ) { // TODO: check this because the proxy doesn't return a WP_Error + if ( SafeGlobalFunctionProxy::is_wp_error( $response ) ) { SafeGlobalFunctionProxy::wc_get_logger()->error( 'Failed to send the log to the remote logging service: ' . $response->get_error_message(), array( 'source' => 'remote-logging' ) ); return false; } @@ -288,7 +288,16 @@ class RemoteLogger extends \WC_Log_Handler { } // If the current version is the latest, we don't want to log errors. - return version_compare( $this->get_wc_version(), $new_version, '>=' ); // TODO check this + return version_compare( $this->get_wc_version(), $new_version, '>=' ); + } + + /** + * Get the current WooCommerce version. + * + * @return string The current WooCommerce version. + */ + private function get_wc_version() { + return WC()->version; } /** @@ -475,7 +484,7 @@ class RemoteLogger extends \WC_Log_Handler { $whitelist = apply_filters( 'woocommerce_remote_logger_request_uri_whitelist', $default_whitelist ); $parsed_url = SafeGlobalFunctionProxy::wp_parse_url( $request_uri ); - if ( ! isset( $parsed_url['query'] ) ) { // TODO: make sure this is failsafe + if ( ! is_array( $parsed_url ) || ! isset( $parsed_url['query'] ) ) { return $request_uri; } diff --git a/plugins/woocommerce/src/Internal/Logging/SafeGlobalExecutionProxy.php b/plugins/woocommerce/src/Internal/Logging/SafeGlobalExecutionProxy.php deleted file mode 100644 index 2994af06e79..00000000000 --- a/plugins/woocommerce/src/Internal/Logging/SafeGlobalExecutionProxy.php +++ /dev/null @@ -1,126 +0,0 @@ - ABSPATH . WPINC . '/http.php', - 'home_url' => ABSPATH . WPINC . '/link-template.php', - 'get_bloginfo' => ABSPATH . WPINC . '/general-template.php', - 'get_option' => ABSPATH . WPINC . '/option.php', - 'get_site_transient' => ABSPATH . WPINC . '/option.php', - 'set_site_transient' => ABSPATH . WPINC . '/option.php', - 'wp_safe_remote_post' => ABSPATH . WPINC . '/http.php', - 'is_wp_error' => ABSPATH . WPINC . '/load.php', - 'get_plugin_updates' => array( ABSPATH . 'wp-admin/includes/update.php', ABSPATH . 'wp-admin/includes/plugin.php' ), - 'wp_get_environment_type' => ABSPATH . WPINC . '/load.php', - 'wp_json_encode' => ABSPATH . WPINC . '/functions.php', - 'wc_get_logger' => WC_ABSPATH . 'includes/class-wc-logger.php', - 'wc_print_r' => WC_ABSPATH . 'includes/wc-core-functions.php', - ); - - if ( ! function_exists( $name ) ) { - if ( isset( $function_map[ $name ] ) ) { - $files = (array) $function_map[ $name ]; - foreach ($files as $file) { - require_once $file; - } - } else { - throw new Exception("Function $name does not exist and could not be loaded."); - } - } - } - - /** - * Proxy for trapping all calls on SafeGlobalFunctionProxy. - * Use this for calling WP and WC global functions safely. - * Example usage: - * - * SafeGlobalFunctionProxy::wp_parse_url('https://example.com', PHP_URL_PATH); - * - * @since 9.4.0 - * @param string $name The name of the function to call. - * @param array $arguments The arguments to pass to the function. - * @return mixed The result of the function call, or null if an error occurs. - */ - public static function __callStatic($name, $arguments) { - set_error_handler(static function (int $type, string $message, string $file, int $line) { - if (__FILE__ === $file) { - $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); - $file = $trace[2]['file'] ?? $file; - $line = $trace[2]['line'] ?? $line; - } - throw new ErrorException($message, 0, $type, $file, $line); - }); - - try { - self::maybe_load_missing_function($name); - $results = call_user_func_array($name, $arguments); - } catch (Throwable $e) { - self::log_wrapper_error($name, $e->getMessage(), $arguments); - $results = null; - } finally { - restore_error_handler(); - } - - return $results; - } - - /** - * Get_wc_version wrapper. - * - * @return string The WooCommerce version. - * - * @throws \Exception If get_wc_version function does not exist. - */ - protected function get_wc_version() { - try { - return Constants::get_constant( 'WC_VERSION' ) ?? 'unknown'; - } catch ( \Throwable $e ) { - self::log_wrapper_error( - __FUNCTION__, - $e->getMessage(), - array() - ); - - return 'Unable to retrieve'; - } - } - - /** - * Log wrapper function errors to "local logging" for debugging. - * - * @param string $function_name The name of the wrapped function. - * @param string $error_message The error message. - * @param array $context Additional context for the error. - */ - protected function log_wrapper_error( $function_name, $error_message, $context = array() ) { - self::maybe_load_missing_function('wc_get_logger'); - - wc_get_logger()->error( - '[Wrapper function error] ' . sprintf( 'Error in %s: %s', $function_name, $error_message ), - array_merge( - array( - 'function' => $function_name, - 'source' => 'remote-logging', - ), - $context - ) - ); - } -} diff --git a/plugins/woocommerce/src/Internal/Logging/SafeGlobalFunctionProxy.php b/plugins/woocommerce/src/Internal/Logging/SafeGlobalFunctionProxy.php new file mode 100644 index 00000000000..bc43f1e3e14 --- /dev/null +++ b/plugins/woocommerce/src/Internal/Logging/SafeGlobalFunctionProxy.php @@ -0,0 +1,115 @@ + ABSPATH . WPINC . '/http.php', + 'home_url' => ABSPATH . WPINC . '/link-template.php', + 'get_bloginfo' => ABSPATH . WPINC . '/general-template.php', + 'get_option' => ABSPATH . WPINC . '/option.php', + 'get_site_transient' => ABSPATH . WPINC . '/option.php', + 'set_site_transient' => ABSPATH . WPINC . '/option.php', + 'wp_safe_remote_post' => ABSPATH . WPINC . '/http.php', + 'is_wp_error' => ABSPATH . WPINC . '/load.php', + 'get_plugin_updates' => array( ABSPATH . 'wp-admin/includes/update.php', ABSPATH . 'wp-admin/includes/plugin.php' ), + 'wp_get_environment_type' => ABSPATH . WPINC . '/load.php', + 'wp_json_encode' => ABSPATH . WPINC . '/functions.php', + 'wc_get_logger' => WC_ABSPATH . 'includes/class-wc-logger.php', + 'wc_print_r' => WC_ABSPATH . 'includes/wc-core-functions.php', + ); + + if ( ! function_exists( $name ) ) { + if ( isset( $function_map[ $name ] ) ) { + $files = (array) $function_map[ $name ]; + foreach ( $files as $file ) { + require_once $file; + } + } else { + throw new \Exception( sprintf( 'Function %s does not exist and could not be loaded.', esc_html( $name ) ) ); + } + } + } + + /** + * Proxy for trapping all calls on SafeGlobalFunctionProxy. + * Use this for calling WP and WC global functions safely. + * Example usage: + * + * SafeGlobalFunctionProxy::wp_parse_url('https://example.com', PHP_URL_PATH); + * + * @since 9.4.0 + * @param string $name The name of the function to call. + * @param array $arguments The arguments to pass to the function. + * @return mixed The result of the function call, or null if an error occurs. + */ + public static function __callStatic( $name, $arguments ) { + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler -- Custom error handler is necessary to convert errors to exceptions + set_error_handler( + static function ( int $type, string $message, string $file, int $line ) { + if ( __FILE__ === $file ) { + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace -- Used to adjust file and line number for accurate error reporting + $trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 3 ); + $file = $trace[2]['file'] ?? $file; + $line = $trace[2]['line'] ?? $line; + } + // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception is thrown here but handled securely elsewhere + throw new \ErrorException( $message, 0, $type, $file, $line ); + } + ); + + try { + self::maybe_load_missing_function( $name ); + $results = call_user_func_array( $name, $arguments ); + } catch ( \Throwable $e ) { + self::log_wrapper_error( $name, $e->getMessage(), $arguments ); + $results = null; + } finally { + restore_error_handler(); + } + + return $results; + } + + /** + * Log wrapper function errors to "local logging" for debugging. + * + * @param string $function_name The name of the wrapped function. + * @param string $error_message The error message. + * @param array $context Additional context for the error. + */ + protected static function log_wrapper_error( $function_name, $error_message, $context = array() ) { + self::maybe_load_missing_function( 'wc_get_logger' ); + + wc_get_logger()->error( + '[Wrapper function error] ' . sprintf( 'Error in %s: %s', $function_name, $error_message ), + array_merge( + array( + 'function' => $function_name, + 'source' => 'remote-logging', + ), + $context + ) + ); + } +}