From 4b40a3170cb3bae9310af23a84997a4f957455ee Mon Sep 17 00:00:00 2001 From: Corey McKrill <916023+coreymckrill@users.noreply.github.com> Date: Wed, 12 Jun 2024 10:14:55 -0700 Subject: [PATCH] Logging: Handle multibyte characters and slashes in context data (#48341) The json_encode function encodes multibyte characters literally by default, which makes them unreadable in the log files. This change ensures those characters remain intact, rather than encoded. It also adds better handling for characters that get escaped with slashes. Fixes #44743 --- .../changelog/fix-44743-log-multibyte-context | 4 ++++ .../src/Internal/Admin/Logging/LogHandlerFileV2.php | 4 ++-- .../src/Internal/Admin/Logging/PageController.php | 11 ++++++++--- .../Internal/Admin/Logging/LogHandlerFileV2Test.php | 7 +++++++ 4 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-44743-log-multibyte-context diff --git a/plugins/woocommerce/changelog/fix-44743-log-multibyte-context b/plugins/woocommerce/changelog/fix-44743-log-multibyte-context new file mode 100644 index 00000000000..1e79019301f --- /dev/null +++ b/plugins/woocommerce/changelog/fix-44743-log-multibyte-context @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Ensure that data containing multibyte characters and/or slashes that is appended to log entries gets encoded and rendered correctly diff --git a/plugins/woocommerce/src/Internal/Admin/Logging/LogHandlerFileV2.php b/plugins/woocommerce/src/Internal/Admin/Logging/LogHandlerFileV2.php index 19c551c672d..c169ef4c1a9 100644 --- a/plugins/woocommerce/src/Internal/Admin/Logging/LogHandlerFileV2.php +++ b/plugins/woocommerce/src/Internal/Admin/Logging/LogHandlerFileV2.php @@ -88,8 +88,8 @@ class LogHandlerFileV2 extends WC_Log_Handler { unset( $context_for_entry['source'] ); if ( ! empty( $context_for_entry ) ) { - $formatted_context = wp_json_encode( $context_for_entry ); - $message .= " CONTEXT: $formatted_context"; + $formatted_context = wp_json_encode( $context_for_entry, JSON_UNESCAPED_UNICODE ); + $message .= stripslashes( " CONTEXT: $formatted_context" ); } $entry = "$time_string $level_string $message"; diff --git a/plugins/woocommerce/src/Internal/Admin/Logging/PageController.php b/plugins/woocommerce/src/Internal/Admin/Logging/PageController.php index 0162c1ec44b..9e14b1d34e3 100644 --- a/plugins/woocommerce/src/Internal/Admin/Logging/PageController.php +++ b/plugins/woocommerce/src/Internal/Admin/Logging/PageController.php @@ -715,13 +715,18 @@ class PageController { $message_chunks = explode( 'CONTEXT:', $segments[2], 2 ); if ( isset( $message_chunks[1] ) ) { try { - $maybe_json = stripslashes( html_entity_decode( trim( $message_chunks[1] ) ) ); - $context = json_decode( $maybe_json, false, 512, JSON_THROW_ON_ERROR ); + $maybe_json = html_entity_decode( addslashes( trim( $message_chunks[1] ) ) ); + + // Decode for validation. + $context = json_decode( $maybe_json, false, 512, JSON_THROW_ON_ERROR ); + + // Re-encode to make it pretty. + $context = wp_json_encode( $context, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE ); $message_chunks[1] = sprintf( '
%1$s%2$s
', esc_html__( 'Additional context', 'woocommerce' ), - wp_json_encode( $context, JSON_PRETTY_PRINT ) + stripslashes( $context ) ); $segments[2] = implode( ' ', $message_chunks ); diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/Logging/LogHandlerFileV2Test.php b/plugins/woocommerce/tests/php/src/Internal/Admin/Logging/LogHandlerFileV2Test.php index 4975344653c..ed320366cf9 100644 --- a/plugins/woocommerce/tests/php/src/Internal/Admin/Logging/LogHandlerFileV2Test.php +++ b/plugins/woocommerce/tests/php/src/Internal/Admin/Logging/LogHandlerFileV2Test.php @@ -187,6 +187,13 @@ MESSAGE; ), $context_delineator . '{"yin":"yang","apple":"orange"}', ); + yield 'custom keys with multibyte and slashed values' => array( + array( + 'multibyte' => '中文字', + 'backslashes' => 'C:\MS-DOS\\', + ), + $context_delineator . '{"multibyte":"中文字","backslashes":"C:\MS-DOS\"}', + ); yield 'backtrace boolean only' => array( array( 'backtrace' => true ), $context_delineator . wp_json_encode( array( 'backtrace' => $this->get_mock_backtrace() ) ),