From 557b43eb86835e6ab24ed6e5ca4fe2a8d75ecc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 17 Sep 2023 10:46:13 +0200 Subject: [PATCH 01/15] Lowercase checks against the passed parameters to helper traits for custom properties Printing, escaping and sanitization trait helpers. --- WordPress/Helpers/EscapingFunctionsTrait.php | 20 +++++++++++++++---- WordPress/Helpers/PrintingFunctionsTrait.php | 10 ++++++++-- WordPress/Helpers/SanitizationHelperTrait.php | 20 +++++++++++++++---- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/WordPress/Helpers/EscapingFunctionsTrait.php b/WordPress/Helpers/EscapingFunctionsTrait.php index 4ebff51396..cdef43119b 100644 --- a/WordPress/Helpers/EscapingFunctionsTrait.php +++ b/WordPress/Helpers/EscapingFunctionsTrait.php @@ -218,9 +218,15 @@ final public function is_escaping_function( $functionName ) { if ( array() === $this->allEscapingFunctions || $this->customEscapingFunctions !== $this->addedCustomEscapingFunctions['escape'] ) { + /* + * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. + */ + $custom_escaping_functions = array_map( 'strtolower', $this->customEscapingFunctions ); + $escaping_functions = array_change_key_case( $this->escapingFunctions, \CASE_LOWER ); + $this->allEscapingFunctions = RulesetPropertyHelper::merge_custom_array( - $this->customEscapingFunctions, - $this->escapingFunctions + $custom_escaping_functions, + $escaping_functions ); $this->addedCustomEscapingFunctions['escape'] = $this->customEscapingFunctions; @@ -242,9 +248,15 @@ final public function is_auto_escaped_function( $functionName ) { if ( array() === $this->allAutoEscapedFunctions || $this->customAutoEscapedFunctions !== $this->addedCustomEscapingFunctions['autoescape'] ) { + /* + * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. + */ + $custom_auto_escaped_functions = array_map( 'strtolower', $this->customAutoEscapedFunctions ); + $auto_escaped_functions = array_change_key_case( $this->autoEscapedFunctions, \CASE_LOWER ); + $this->allAutoEscapedFunctions = RulesetPropertyHelper::merge_custom_array( - $this->customAutoEscapedFunctions, - $this->autoEscapedFunctions + $custom_auto_escaped_functions, + $auto_escaped_functions ); $this->addedCustomEscapingFunctions['autoescape'] = $this->customAutoEscapedFunctions; diff --git a/WordPress/Helpers/PrintingFunctionsTrait.php b/WordPress/Helpers/PrintingFunctionsTrait.php index edd6dbe211..330b811241 100644 --- a/WordPress/Helpers/PrintingFunctionsTrait.php +++ b/WordPress/Helpers/PrintingFunctionsTrait.php @@ -96,9 +96,15 @@ final public function get_printing_functions() { if ( array() === $this->allPrintingFunctions || $this->customPrintingFunctions !== $this->addedCustomPrintingFunctions ) { + /* + * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. + */ + $custom_printing_functions = array_map( 'strtolower', $this->customPrintingFunctions ); + $printing_functions = array_change_key_case( $this->printingFunctions, \CASE_LOWER ); + $this->allPrintingFunctions = RulesetPropertyHelper::merge_custom_array( - $this->customPrintingFunctions, - $this->printingFunctions + $custom_printing_functions, + $printing_functions ); $this->addedCustomPrintingFunctions = $this->customPrintingFunctions; diff --git a/WordPress/Helpers/SanitizationHelperTrait.php b/WordPress/Helpers/SanitizationHelperTrait.php index c041dfe5c1..df49ebd1f9 100644 --- a/WordPress/Helpers/SanitizationHelperTrait.php +++ b/WordPress/Helpers/SanitizationHelperTrait.php @@ -194,9 +194,15 @@ final public function get_sanitizing_functions() { if ( array() === $this->allSanitizingFunctions || $this->customSanitizingFunctions !== $this->addedCustomSanitizingFunctions['sanitize'] ) { + /* + * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. + */ + $custom_sanitizing_functions = array_map( 'strtolower', $this->customSanitizingFunctions ); + $sanitizing_functions = array_change_key_case( $this->sanitizingFunctions, \CASE_LOWER ); + $this->allSanitizingFunctions = RulesetPropertyHelper::merge_custom_array( - $this->customSanitizingFunctions, - $this->sanitizingFunctions + $custom_sanitizing_functions, + $sanitizing_functions ); $this->addedCustomSanitizingFunctions['sanitize'] = $this->customSanitizingFunctions; @@ -216,9 +222,15 @@ final public function get_sanitizing_and_unslashing_functions() { if ( array() === $this->allUnslashingSanitizingFunctions || $this->customUnslashingSanitizingFunctions !== $this->addedCustomSanitizingFunctions['unslashsanitize'] ) { + /* + * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. + */ + $custom_unslashing_sanitizing_functions = array_map( 'strtolower', $this->customUnslashingSanitizingFunctions ); + $unslashing_sanitizing_functions = array_change_key_case( $this->unslashingSanitizingFunctions, \CASE_LOWER ); + $this->allUnslashingSanitizingFunctions = RulesetPropertyHelper::merge_custom_array( - $this->customUnslashingSanitizingFunctions, - $this->unslashingSanitizingFunctions + $custom_unslashing_sanitizing_functions, + $unslashing_sanitizing_functions ); $this->addedCustomSanitizingFunctions['unslashsanitize'] = $this->customUnslashingSanitizingFunctions; From 2952d93704d2b574a267a8cc7d94e942a454dc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 17 Sep 2023 10:46:53 +0200 Subject: [PATCH 02/15] Lowercase checks for the added custom propery in the DirectDBQuerySniff --- .../Sniffs/DB/DirectDatabaseQuerySniff.php | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php index 590f6478ea..8cba52fab8 100644 --- a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php +++ b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php @@ -230,17 +230,17 @@ public function process_token( $stackPtr ) { for ( $i = ( $scopeStart + 1 ); $i < $scopeEnd; $i++ ) { if ( \T_STRING === $this->tokens[ $i ]['code'] ) { - if ( isset( $this->cacheDeleteFunctions[ $this->tokens[ $i ]['content'] ] ) ) { + if ( isset( $this->cacheDeleteFunctions[ strtolower( $this->tokens[ $i ]['content'] ) ] ) ) { if ( \in_array( $method, array( 'query', 'update', 'replace', 'delete' ), true ) ) { $cached = true; break; } - } elseif ( isset( $this->cacheGetFunctions[ $this->tokens[ $i ]['content'] ] ) ) { + } elseif ( isset( $this->cacheGetFunctions[ strtolower( $this->tokens[ $i ]['content'] ) ] ) ) { $wp_cache_get = true; - } elseif ( isset( $this->cacheSetFunctions[ $this->tokens[ $i ]['content'] ] ) ) { + } elseif ( isset( $this->cacheSetFunctions[ strtolower( $this->tokens[ $i ]['content'] ) ] ) ) { if ( $wp_cache_get ) { $cached = true; @@ -272,27 +272,45 @@ protected function mergeFunctionLists() { } if ( $this->customCacheGetFunctions !== $this->addedCustomFunctions['cacheget'] ) { + /* + * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. + */ + $custom_cache_get_functions = array_map( 'strtolower', $this->customCacheGetFunctions ); + $cache_get_functions = array_change_key_case( $this->cacheGetFunctions, \CASE_LOWER ); + $this->cacheGetFunctions = RulesetPropertyHelper::merge_custom_array( - $this->customCacheGetFunctions, - $this->cacheGetFunctions + $custom_cache_get_functions, + $cache_get_functions ); $this->addedCustomFunctions['cacheget'] = $this->customCacheGetFunctions; } if ( $this->customCacheSetFunctions !== $this->addedCustomFunctions['cacheset'] ) { + /* + * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. + */ + $custom_cache_set_functions = array_map( 'strtolower', $this->customCacheSetFunctions ); + $cache_set_functions = array_change_key_case( $this->cacheSetFunctions, \CASE_LOWER ); + $this->cacheSetFunctions = RulesetPropertyHelper::merge_custom_array( - $this->customCacheSetFunctions, - $this->cacheSetFunctions + $custom_cache_set_functions, + $cache_set_functions ); $this->addedCustomFunctions['cacheset'] = $this->customCacheSetFunctions; } if ( $this->customCacheDeleteFunctions !== $this->addedCustomFunctions['cachedelete'] ) { + /* + * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. + */ + $custom_cache_delete_functions = array_map( 'strtolower', $this->customCacheDeleteFunctions ); + $cache_delete_functions = array_change_key_case( $this->cacheDeleteFunctions, \CASE_LOWER ); + $this->cacheDeleteFunctions = RulesetPropertyHelper::merge_custom_array( - $this->customCacheDeleteFunctions, - $this->cacheDeleteFunctions + $custom_cache_delete_functions, + $cache_delete_functions ); $this->addedCustomFunctions['cachedelete'] = $this->customCacheDeleteFunctions; From 8e654663f65c3c46fa7f014b42006e122fda8e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 17 Sep 2023 10:47:11 +0200 Subject: [PATCH 03/15] Lowercase checks for the added custom propery in the NonceVerificationSniff --- WordPress/Sniffs/Security/NonceVerificationSniff.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/Security/NonceVerificationSniff.php b/WordPress/Sniffs/Security/NonceVerificationSniff.php index 0241147327..5c893d88c0 100644 --- a/WordPress/Sniffs/Security/NonceVerificationSniff.php +++ b/WordPress/Sniffs/Security/NonceVerificationSniff.php @@ -310,7 +310,7 @@ private function has_nonce_check( $stackPtr, array $cache_keys, $allow_nonce_aft } // If this is one of the nonce verification functions, we can bail out. - if ( isset( $this->nonceVerificationFunctions[ $this->tokens[ $i ]['content'] ] ) ) { + if ( isset( $this->nonceVerificationFunctions[ strtolower( $this->tokens[ $i ]['content'] ) ] ) ) { /* * Now, make sure it is a call to a global function. */ @@ -411,9 +411,15 @@ private function set_cache( $filename, $start, $end, $nonce ) { */ protected function mergeFunctionLists() { if ( $this->customNonceVerificationFunctions !== $this->addedCustomNonceFunctions ) { + /* + * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. + */ + $custom_nonce_verification_functions = array_map( 'strtolower', $this->customNonceVerificationFunctions ); + $nonce_verification_functions = array_change_key_case( $this->nonceVerificationFunctions, \CASE_LOWER ); + $this->nonceVerificationFunctions = RulesetPropertyHelper::merge_custom_array( - $this->customNonceVerificationFunctions, - $this->nonceVerificationFunctions + $custom_nonce_verification_functions, + $nonce_verification_functions ); $this->addedCustomNonceFunctions = $this->customNonceVerificationFunctions; From 03519cf5f015f4dc002493c610d20e348452dd25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sun, 17 Sep 2023 10:47:50 +0200 Subject: [PATCH 04/15] Added tests that will check if the mixed-cased custom function name won't trigger errors if allowed --- .../Tests/DB/DirectDatabaseQueryUnitTest.inc | 60 +++++++++++++++++++ .../Tests/DB/DirectDatabaseQueryUnitTest.php | 6 ++ .../Tests/Security/EscapeOutputUnitTest.1.inc | 6 ++ .../Tests/Security/EscapeOutputUnitTest.php | 2 + .../Security/NonceVerificationUnitTest.1.inc | 9 ++- .../ValidatedSanitizedInputUnitTest.1.inc | 29 +++++++++ .../ValidatedSanitizedInputUnitTest.php | 4 ++ 7 files changed, 115 insertions(+), 1 deletion(-) diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc index eb2d0e7473..6fe7f16b09 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc @@ -333,6 +333,66 @@ function method_names_are_caseinsensitive() { $autoload = $wpdb->Get_Var( $wpdb->Prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option_name ) ); // Warning x 2. } +/* + * Test using custom properties, setting & unsetting (resetting). + */ +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheGetFunctions[] my_cacheget +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] my_cacheset,my_other_cacheset +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] my_cachedel +function cache_customA() { + global $wpdb; + $quux = MY_cacheget( 'quux' ); + if ( false !== $quux ) { + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. + my_cacheSet( 'key', 'group' ); + } +} + +function cache_customB() { + global $wpdb; + $quux = my_cacheget( 'quux' ); + if ( false !== $quux ) { + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. + my_other_CacheSet( 'key', 'group' ); + } +} + +function cache_customC() { + global $wpdb; + $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. + my_cacheDEL( 'key', 'group' ); +} + +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] my_cacheset +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] + +function cache_customD() { + global $wpdb; + $quux = my_cacheget( 'quux' ); + if ( false !== $quux ) { + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. + my_cacHeset( 'key', 'group' ); + } +} + +function cache_customE() { + global $wpdb; + $quux = my_cacheget( 'quux' ); + if ( false !== $quux ) { + $wpdb->get_results( 'SELECT X FROM Y' ); // Warning x 2. + my_other_cacheset( 'key', 'group' ); + } +} + +function cache_customF() { + global $wpdb; + $wpdb->query( 'SELECT X FROM Y' ); // Warning x 2. + my_cachedel( 'key', 'group' ); +} + +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheGetFunctions[] +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] + // Live coding/parse error test. // This must be the last test in the file. $wpdb->get_col( ' diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php index e12828a1aa..6c7b8fc1fd 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.php @@ -91,6 +91,12 @@ public function getWarningList() { 300 => 1, 306 => 2, 333 => 2, + 346 => 1, + 355 => 1, + 362 => 1, + 373 => 1, + 382 => 2, + 389 => 2, ); } } diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index cfe20caeee..84f0604db4 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -655,3 +655,9 @@ echo ''; // Bad. echo ''; // Bad. echo ''; // OK, well not really, typo in param name, but that's not our concern. echo ''; // Bad. + +// phpcs:set WordPress.Security.EscapeOutput customPrintingFunctions[] to_screen,my_print +to_scReen( $var1, esc_attr( $var2 ) ); // Bad x 1. +my_prinT( $var1, $var2 ); // Bad x 2. + +// phpcs:set WordPress.Security.EscapeOutput customEscapingFunctions[] diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.php b/WordPress/Tests/Security/EscapeOutputUnitTest.php index 6150a4eeb4..abf966e04c 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.php +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.php @@ -159,6 +159,8 @@ public function getErrorList( $testFile = '' ) { 654 => 1, 655 => 1, 657 => 1, + 660 => 1, + 661 => 2, ); case 'EscapeOutputUnitTest.6.inc': diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc index cb8348b4ad..e277a73b21 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc @@ -466,7 +466,7 @@ function function_containing_nested_enum_with_nonce_check() { wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['my_nonce'] ) ), 'the_nonce' ); } } - + echo $_POST['foo']; // Bad. } @@ -486,3 +486,10 @@ enum MyEnum { echo $_POST['foo']; // OK. } } +// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] my_nonce_check +// phpcs:set WordPress.Security.NonceVerification customUnslashingSanitizingFunctions[] do_something +function foo_6() { + my_noncE_cheCk( do_soMeThinG( $_POST['tweet'] ) ); // OK. +} +// phpcs:set WordPress.Security.NonceVerification customUnslashingSanitizingFunctions[] +// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc index cc4edc147a..382dde0046 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc @@ -500,3 +500,32 @@ function test_in_match_condition_is_regarded_as_comparison() { }; } } + +/* + * Test using custom properties, setting & unsetting (resetting). + */ +function test_this() { + if ( ! isset( $_POST['abc_field'] ) ) { + return; + } + + $abc = sanitize_color( wp_unslash( $_POST['abc_field'] ) ); // Bad x1 - sanitize. + + // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] sanitize_color,sanitize_twitter_handle + + $abc = sanitize_cOlor( wp_unslash( $_POST['abc_field'] ) ); // OK. + $abc = sanitize_facebook_ID( wp_unslash( $_POST['abc_field'] ) ); // Bad x1 - sanitize. + $abc = sanitize_twitteR_handle( $_POST['abc_field'] ); // Bad x1 - unslash. + + // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] sanitize_color,sanitize_facebook_id + // phpcs:set WordPress.Security.ValidatedSanitizedInput customUnslashingSanitizingFunctions[] sanitize_twitter_handle + + $abc = sanitizE_coLor( wp_unslash( $_POST['abc_field'] ) ); // OK. + $abc = sanitize_facebook_ID( wp_unslash( $_POST['abc_field'] ) ); // OK. + $abc = sanitize_TWITTER_haNdle( $_POST['abc_field'] ); // OK. + + // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] + // phpcs:set WordPress.Security.ValidatedSanitizedInput customUnslashingSanitizingFunctions[] + + $abc = sanitize_twitter_handle( $_POST['abc_field'] ); // Bad x2, sanitize + unslash. +} diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php index 065162c2a8..c35086a1ca 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php @@ -114,6 +114,10 @@ public function getErrorList( $testFile = '' ) { 497 => 1, 498 => 1, 499 => 3, + 512 => 1, + 517 => 1, + 518 => 1, + 530 => 2, ); case 'ValidatedSanitizedInputUnitTest.2.inc': From d6ac1b518a7f14fdf796fe7644da6772d0a2b25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Mon, 18 Sep 2023 11:50:04 +0200 Subject: [PATCH 05/15] Add a new parameter for lowecasing array keys and values when arrays are merged --- WordPress/Helpers/RulesetPropertyHelper.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/WordPress/Helpers/RulesetPropertyHelper.php b/WordPress/Helpers/RulesetPropertyHelper.php index b20c6ed3bf..303c026e83 100644 --- a/WordPress/Helpers/RulesetPropertyHelper.php +++ b/WordPress/Helpers/RulesetPropertyHelper.php @@ -43,15 +43,17 @@ final class RulesetPropertyHelper { * @since 2.0.0 No longer supports custom array properties which were incorrectly * passed as a string. * @since 3.0.0 Moved from the Sniff class to this class. + * @since 3.1.0 Added a new parameter to lowercase array keys and values. * - * @param array $custom Custom list as provided via a ruleset. - * @param array $base Optional. Base list. Defaults to an empty array. - * Expects `value => true` format when `$flip` is true. - * @param bool $flip Optional. Whether or not to flip the custom list. - * Defaults to true. + * @param array $custom Custom list as provided via a ruleset. + * @param array $base Optional. Base list. Defaults to an empty array. + * Expects `value => true` format when `$flip` is true. + * @param bool $flip Optional. Whether or not to flip the custom list. + * @param bool $lowercaseKeyValues Optional. Whether to lowercase keys and values in the resulting array. + * Defaults to false. * @return array */ - public static function merge_custom_array( $custom, array $base = array(), $flip = true ) { + public static function merge_custom_array( $custom, array $base = array(), $flip = true, $lowercaseKeyValues = false ) { if ( true === $flip ) { $base = array_filter( $base ); } @@ -68,6 +70,13 @@ public static function merge_custom_array( $custom, array $base = array(), $flip return $custom; } + if ( $lowercaseKeyValues ) { + $base = array_map( 'strtolower', $base ); + $custom = array_map( 'strtolower', $custom ); + $base = array_change_key_case( $base ); + $custom = array_change_key_case( $custom ); + } + return array_merge( $base, $custom ); } } From 976c1c5440aa4129e27964ad69d78f5dbeeac22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Mon, 18 Sep 2023 11:50:45 +0200 Subject: [PATCH 06/15] Extract the lowercased content for the caching functions --- WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php index 8cba52fab8..fe99e6a6f3 100644 --- a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php +++ b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php @@ -229,18 +229,19 @@ public function process_token( $stackPtr ) { for ( $i = ( $scopeStart + 1 ); $i < $scopeEnd; $i++ ) { if ( \T_STRING === $this->tokens[ $i ]['code'] ) { + $content = strtolower( $this->tokens[ $i ]['content'] ); - if ( isset( $this->cacheDeleteFunctions[ strtolower( $this->tokens[ $i ]['content'] ) ] ) ) { + if ( isset( $this->cacheDeleteFunctions[ $content ] ) ) { if ( \in_array( $method, array( 'query', 'update', 'replace', 'delete' ), true ) ) { $cached = true; break; } - } elseif ( isset( $this->cacheGetFunctions[ strtolower( $this->tokens[ $i ]['content'] ) ] ) ) { + } elseif ( isset( $this->cacheGetFunctions[ $content ] ) ) { $wp_cache_get = true; - } elseif ( isset( $this->cacheSetFunctions[ strtolower( $this->tokens[ $i ]['content'] ) ] ) ) { + } elseif ( isset( $this->cacheSetFunctions[ $content ] ) ) { if ( $wp_cache_get ) { $cached = true; From 4556d69781ec57be2567dfe43f762e25bd4c69fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Mon, 18 Sep 2023 15:03:42 +0200 Subject: [PATCH 07/15] Update the code that uses merge array and needs to be lowercased --- WordPress/Helpers/EscapingFunctionsTrait.php | 24 +++++-------- WordPress/Helpers/IsUnitTestTrait.php | 10 ++---- WordPress/Helpers/PrintingFunctionsTrait.php | 12 +++---- WordPress/Helpers/SanitizationHelperTrait.php | 24 +++++-------- .../Sniffs/DB/DirectDatabaseQuerySniff.php | 36 +++++++------------ .../Sniffs/PHP/NoSilencedErrorsSniff.php | 3 +- .../Security/NonceVerificationSniff.php | 12 +++---- 7 files changed, 40 insertions(+), 81 deletions(-) diff --git a/WordPress/Helpers/EscapingFunctionsTrait.php b/WordPress/Helpers/EscapingFunctionsTrait.php index cdef43119b..c6fcc3c209 100644 --- a/WordPress/Helpers/EscapingFunctionsTrait.php +++ b/WordPress/Helpers/EscapingFunctionsTrait.php @@ -218,15 +218,11 @@ final public function is_escaping_function( $functionName ) { if ( array() === $this->allEscapingFunctions || $this->customEscapingFunctions !== $this->addedCustomEscapingFunctions['escape'] ) { - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_escaping_functions = array_map( 'strtolower', $this->customEscapingFunctions ); - $escaping_functions = array_change_key_case( $this->escapingFunctions, \CASE_LOWER ); - $this->allEscapingFunctions = RulesetPropertyHelper::merge_custom_array( - $custom_escaping_functions, - $escaping_functions + $this->customEscapingFunctions, + $this->escapingFunctions, + true, + true ); $this->addedCustomEscapingFunctions['escape'] = $this->customEscapingFunctions; @@ -248,15 +244,11 @@ final public function is_auto_escaped_function( $functionName ) { if ( array() === $this->allAutoEscapedFunctions || $this->customAutoEscapedFunctions !== $this->addedCustomEscapingFunctions['autoescape'] ) { - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_auto_escaped_functions = array_map( 'strtolower', $this->customAutoEscapedFunctions ); - $auto_escaped_functions = array_change_key_case( $this->autoEscapedFunctions, \CASE_LOWER ); - $this->allAutoEscapedFunctions = RulesetPropertyHelper::merge_custom_array( - $custom_auto_escaped_functions, - $auto_escaped_functions + $this->customAutoEscapedFunctions, + $this->autoEscapedFunctions, + true, + true ); $this->addedCustomEscapingFunctions['autoescape'] = $this->customAutoEscapedFunctions; diff --git a/WordPress/Helpers/IsUnitTestTrait.php b/WordPress/Helpers/IsUnitTestTrait.php index a6e3b36d32..b5e715bb90 100644 --- a/WordPress/Helpers/IsUnitTestTrait.php +++ b/WordPress/Helpers/IsUnitTestTrait.php @@ -142,15 +142,11 @@ final protected function get_all_test_classes() { } } - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_test_classes = array_map( 'strtolower', $custom_test_classes ); - $known_test_classes = array_change_key_case( $this->known_test_classes, \CASE_LOWER ); - $this->all_test_classes = RulesetPropertyHelper::merge_custom_array( $custom_test_classes, - $known_test_classes + $this->known_test_classes, + true, + true ); // Store the original value so the comparison can succeed. diff --git a/WordPress/Helpers/PrintingFunctionsTrait.php b/WordPress/Helpers/PrintingFunctionsTrait.php index 330b811241..94c034c419 100644 --- a/WordPress/Helpers/PrintingFunctionsTrait.php +++ b/WordPress/Helpers/PrintingFunctionsTrait.php @@ -96,15 +96,11 @@ final public function get_printing_functions() { if ( array() === $this->allPrintingFunctions || $this->customPrintingFunctions !== $this->addedCustomPrintingFunctions ) { - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_printing_functions = array_map( 'strtolower', $this->customPrintingFunctions ); - $printing_functions = array_change_key_case( $this->printingFunctions, \CASE_LOWER ); - $this->allPrintingFunctions = RulesetPropertyHelper::merge_custom_array( - $custom_printing_functions, - $printing_functions + $this->customPrintingFunctions, + $this->printingFunctions, + true, + true ); $this->addedCustomPrintingFunctions = $this->customPrintingFunctions; diff --git a/WordPress/Helpers/SanitizationHelperTrait.php b/WordPress/Helpers/SanitizationHelperTrait.php index df49ebd1f9..ce29ea9e28 100644 --- a/WordPress/Helpers/SanitizationHelperTrait.php +++ b/WordPress/Helpers/SanitizationHelperTrait.php @@ -194,15 +194,11 @@ final public function get_sanitizing_functions() { if ( array() === $this->allSanitizingFunctions || $this->customSanitizingFunctions !== $this->addedCustomSanitizingFunctions['sanitize'] ) { - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_sanitizing_functions = array_map( 'strtolower', $this->customSanitizingFunctions ); - $sanitizing_functions = array_change_key_case( $this->sanitizingFunctions, \CASE_LOWER ); - $this->allSanitizingFunctions = RulesetPropertyHelper::merge_custom_array( - $custom_sanitizing_functions, - $sanitizing_functions + $this->customSanitizingFunctions, + $this->sanitizingFunctions, + true, + true ); $this->addedCustomSanitizingFunctions['sanitize'] = $this->customSanitizingFunctions; @@ -222,15 +218,11 @@ final public function get_sanitizing_and_unslashing_functions() { if ( array() === $this->allUnslashingSanitizingFunctions || $this->customUnslashingSanitizingFunctions !== $this->addedCustomSanitizingFunctions['unslashsanitize'] ) { - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_unslashing_sanitizing_functions = array_map( 'strtolower', $this->customUnslashingSanitizingFunctions ); - $unslashing_sanitizing_functions = array_change_key_case( $this->unslashingSanitizingFunctions, \CASE_LOWER ); - $this->allUnslashingSanitizingFunctions = RulesetPropertyHelper::merge_custom_array( - $custom_unslashing_sanitizing_functions, - $unslashing_sanitizing_functions + $this->customUnslashingSanitizingFunctions, + $this->unslashingSanitizingFunctions, + true, + true ); $this->addedCustomSanitizingFunctions['unslashsanitize'] = $this->customUnslashingSanitizingFunctions; diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php index fe99e6a6f3..11cf0796e5 100644 --- a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php +++ b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php @@ -273,45 +273,33 @@ protected function mergeFunctionLists() { } if ( $this->customCacheGetFunctions !== $this->addedCustomFunctions['cacheget'] ) { - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_cache_get_functions = array_map( 'strtolower', $this->customCacheGetFunctions ); - $cache_get_functions = array_change_key_case( $this->cacheGetFunctions, \CASE_LOWER ); - $this->cacheGetFunctions = RulesetPropertyHelper::merge_custom_array( - $custom_cache_get_functions, - $cache_get_functions + $this->customCacheGetFunctions, + $this->cacheGetFunctions, + true, + true ); $this->addedCustomFunctions['cacheget'] = $this->customCacheGetFunctions; } if ( $this->customCacheSetFunctions !== $this->addedCustomFunctions['cacheset'] ) { - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_cache_set_functions = array_map( 'strtolower', $this->customCacheSetFunctions ); - $cache_set_functions = array_change_key_case( $this->cacheSetFunctions, \CASE_LOWER ); - $this->cacheSetFunctions = RulesetPropertyHelper::merge_custom_array( - $custom_cache_set_functions, - $cache_set_functions + $this->customCacheSetFunctions, + $this->cacheSetFunctions, + true, + true ); $this->addedCustomFunctions['cacheset'] = $this->customCacheSetFunctions; } if ( $this->customCacheDeleteFunctions !== $this->addedCustomFunctions['cachedelete'] ) { - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_cache_delete_functions = array_map( 'strtolower', $this->customCacheDeleteFunctions ); - $cache_delete_functions = array_change_key_case( $this->cacheDeleteFunctions, \CASE_LOWER ); - $this->cacheDeleteFunctions = RulesetPropertyHelper::merge_custom_array( - $custom_cache_delete_functions, - $cache_delete_functions + $this->customCacheDeleteFunctions, + $this->cacheDeleteFunctions, + true, + true ); $this->addedCustomFunctions['cachedelete'] = $this->customCacheDeleteFunctions; diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index 4817f82652..a8fe7409c7 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -184,8 +184,7 @@ public function register() { */ public function process_token( $stackPtr ) { // Handle the user-defined custom function list. - $this->customAllowedFunctionsList = RulesetPropertyHelper::merge_custom_array( $this->customAllowedFunctionsList, array(), false ); - $this->customAllowedFunctionsList = array_map( 'strtolower', $this->customAllowedFunctionsList ); + $this->customAllowedFunctionsList = RulesetPropertyHelper::merge_custom_array( $this->customAllowedFunctionsList, array(), false, true ); /* * Check if the error silencing is done for one of the allowed functions. diff --git a/WordPress/Sniffs/Security/NonceVerificationSniff.php b/WordPress/Sniffs/Security/NonceVerificationSniff.php index 5c893d88c0..60c2e0bb6f 100644 --- a/WordPress/Sniffs/Security/NonceVerificationSniff.php +++ b/WordPress/Sniffs/Security/NonceVerificationSniff.php @@ -411,15 +411,11 @@ private function set_cache( $filename, $start, $end, $nonce ) { */ protected function mergeFunctionLists() { if ( $this->customNonceVerificationFunctions !== $this->addedCustomNonceFunctions ) { - /* - * Lowercase all names, both custom as well as "known", as PHP treats namespaced names case-insensitively. - */ - $custom_nonce_verification_functions = array_map( 'strtolower', $this->customNonceVerificationFunctions ); - $nonce_verification_functions = array_change_key_case( $this->nonceVerificationFunctions, \CASE_LOWER ); - $this->nonceVerificationFunctions = RulesetPropertyHelper::merge_custom_array( - $custom_nonce_verification_functions, - $nonce_verification_functions + $this->customNonceVerificationFunctions, + $this->nonceVerificationFunctions, + true, + true ); $this->addedCustomNonceFunctions = $this->customNonceVerificationFunctions; From 0cdebde740888fbec95764d1d2e7d4435dd3f83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Mon, 18 Sep 2023 15:15:05 +0200 Subject: [PATCH 08/15] Move lowecasing functionality at the beginning of the helper There are some early returns that would make lowecasing not happen even if we passed the last parameter as true. --- WordPress/Helpers/RulesetPropertyHelper.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/WordPress/Helpers/RulesetPropertyHelper.php b/WordPress/Helpers/RulesetPropertyHelper.php index 303c026e83..2722df6ea4 100644 --- a/WordPress/Helpers/RulesetPropertyHelper.php +++ b/WordPress/Helpers/RulesetPropertyHelper.php @@ -54,6 +54,13 @@ final class RulesetPropertyHelper { * @return array */ public static function merge_custom_array( $custom, array $base = array(), $flip = true, $lowercaseKeyValues = false ) { + if ( $lowercaseKeyValues ) { + $base = array_map( 'strtolower', $base ); + $custom = array_map( 'strtolower', $custom ); + $base = array_change_key_case( $base ); + $custom = array_change_key_case( $custom ); + } + if ( true === $flip ) { $base = array_filter( $base ); } @@ -70,13 +77,6 @@ public static function merge_custom_array( $custom, array $base = array(), $flip return $custom; } - if ( $lowercaseKeyValues ) { - $base = array_map( 'strtolower', $base ); - $custom = array_map( 'strtolower', $custom ); - $base = array_change_key_case( $base ); - $custom = array_change_key_case( $custom ); - } - return array_merge( $base, $custom ); } } From af15790f1978ad9901e7337e92562e9d8cdb8216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Mon, 18 Sep 2023 15:18:50 +0200 Subject: [PATCH 09/15] Update tests --- WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc | 8 ++++---- WordPress/Tests/Security/EscapeOutputUnitTest.1.inc | 2 +- WordPress/Tests/Security/NonceVerificationUnitTest.1.inc | 4 ++-- .../Tests/Security/ValidatedSanitizedInputUnitTest.1.inc | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc index 6fe7f16b09..7d80eaefed 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc @@ -336,9 +336,9 @@ function method_names_are_caseinsensitive() { /* * Test using custom properties, setting & unsetting (resetting). */ -// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheGetFunctions[] my_cacheget -// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] my_cacheset,my_other_cacheset -// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] my_cachedel +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheGetFunctions[] my_cacHeget +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] my_cachEset,my_other_cacheSET +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] MY_cachedeL function cache_customA() { global $wpdb; $quux = MY_cacheget( 'quux' ); @@ -363,7 +363,7 @@ function cache_customC() { my_cacheDEL( 'key', 'group' ); } -// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] my_cacheset +// phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] my_cacheSet // phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] function cache_customD() { diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index 84f0604db4..b61932f6c5 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -656,7 +656,7 @@ echo ''; // Bad. echo ''; // OK, well not really, typo in param name, but that's not our concern. echo ''; // Bad. -// phpcs:set WordPress.Security.EscapeOutput customPrintingFunctions[] to_screen,my_print +// phpcs:set WordPress.Security.EscapeOutput customPrintingFunctions[] TO_SCREEN,my_print to_scReen( $var1, esc_attr( $var2 ) ); // Bad x 1. my_prinT( $var1, $var2 ); // Bad x 2. diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc index e277a73b21..3e2946c422 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc @@ -486,8 +486,8 @@ enum MyEnum { echo $_POST['foo']; // OK. } } -// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] my_nonce_check -// phpcs:set WordPress.Security.NonceVerification customUnslashingSanitizingFunctions[] do_something +// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] MY_nonce_check +// phpcs:set WordPress.Security.NonceVerification customUnslashingSanitizingFunctions[] do_sometHING function foo_6() { my_noncE_cheCk( do_soMeThinG( $_POST['tweet'] ) ); // OK. } diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc index 382dde0046..054ad37ac6 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc @@ -511,14 +511,14 @@ function test_this() { $abc = sanitize_color( wp_unslash( $_POST['abc_field'] ) ); // Bad x1 - sanitize. - // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] sanitize_color,sanitize_twitter_handle + // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] sanitize_color,sanitize_TWITTER_handle $abc = sanitize_cOlor( wp_unslash( $_POST['abc_field'] ) ); // OK. $abc = sanitize_facebook_ID( wp_unslash( $_POST['abc_field'] ) ); // Bad x1 - sanitize. $abc = sanitize_twitteR_handle( $_POST['abc_field'] ); // Bad x1 - unslash. - // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] sanitize_color,sanitize_facebook_id - // phpcs:set WordPress.Security.ValidatedSanitizedInput customUnslashingSanitizingFunctions[] sanitize_twitter_handle + // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] sanitize_color,sanitize_facebook_ID + // phpcs:set WordPress.Security.ValidatedSanitizedInput customUnslashingSanitizingFunctions[] sanITize_twitter_handle $abc = sanitizE_coLor( wp_unslash( $_POST['abc_field'] ) ); // OK. $abc = sanitize_facebook_ID( wp_unslash( $_POST['abc_field'] ) ); // OK. From 37389f8398b0e93a1c72390faf7f1530df0a83fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Mon, 18 Sep 2023 15:19:57 +0200 Subject: [PATCH 10/15] Fix phpcs violation in the ruleset helper --- WordPress/Helpers/RulesetPropertyHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Helpers/RulesetPropertyHelper.php b/WordPress/Helpers/RulesetPropertyHelper.php index 2722df6ea4..2eac54b197 100644 --- a/WordPress/Helpers/RulesetPropertyHelper.php +++ b/WordPress/Helpers/RulesetPropertyHelper.php @@ -55,9 +55,9 @@ final class RulesetPropertyHelper { */ public static function merge_custom_array( $custom, array $base = array(), $flip = true, $lowercaseKeyValues = false ) { if ( $lowercaseKeyValues ) { - $base = array_map( 'strtolower', $base ); + $base = array_map( 'strtolower', $base ); $custom = array_map( 'strtolower', $custom ); - $base = array_change_key_case( $base ); + $base = array_change_key_case( $base ); $custom = array_change_key_case( $custom ); } From 30c3e3d67265a7221b5a0a0b59595eff9fb70b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Thu, 21 Sep 2023 10:46:19 +0200 Subject: [PATCH 11/15] Apply PR suggestions in ruleset helper --- WordPress/Helpers/RulesetPropertyHelper.php | 31 ++++++++++++--------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/WordPress/Helpers/RulesetPropertyHelper.php b/WordPress/Helpers/RulesetPropertyHelper.php index 2eac54b197..36db429961 100644 --- a/WordPress/Helpers/RulesetPropertyHelper.php +++ b/WordPress/Helpers/RulesetPropertyHelper.php @@ -43,22 +43,23 @@ final class RulesetPropertyHelper { * @since 2.0.0 No longer supports custom array properties which were incorrectly * passed as a string. * @since 3.0.0 Moved from the Sniff class to this class. - * @since 3.1.0 Added a new parameter to lowercase array keys and values. + * @since 3.0.2 Added a new parameter to lowercase array keys and values. * - * @param array $custom Custom list as provided via a ruleset. - * @param array $base Optional. Base list. Defaults to an empty array. - * Expects `value => true` format when `$flip` is true. - * @param bool $flip Optional. Whether or not to flip the custom list. - * @param bool $lowercaseKeyValues Optional. Whether to lowercase keys and values in the resulting array. - * Defaults to false. + * @param array $custom Custom list as provided via a ruleset. + * @param array $base Optional. Base list. Defaults to an empty array. + * Expects `value => true` format when `$flip` is true. + * @param bool $flip Optional. Whether or not to flip the custom list. + * @param bool $lowercasekeys Optional. Whether to lowercase keys and values in the resulting array. + * Defaults to false. * @return array */ - public static function merge_custom_array( $custom, array $base = array(), $flip = true, $lowercaseKeyValues = false ) { - if ( $lowercaseKeyValues ) { - $base = array_map( 'strtolower', $base ); - $custom = array_map( 'strtolower', $custom ); - $base = array_change_key_case( $base ); - $custom = array_change_key_case( $custom ); + public static function merge_custom_array( $custom, array $base = array(), $flip = true, $lowercasekeys = false ) { + if ( empty( $base ) && empty( $custom ) ) { + return array(); + } + + if ( $lowercasekeys ) { + $base = array_change_key_case( $base ); } if ( true === $flip ) { @@ -73,6 +74,10 @@ public static function merge_custom_array( $custom, array $base = array(), $flip $custom = array_fill_keys( $custom, false ); } + if ( $lowercasekeys ) { + $custom = array_change_key_case( $custom ); + } + if ( empty( $base ) ) { return $custom; } From 794f4cf226639631f4fd507a3e84b560399077d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Thu, 21 Sep 2023 10:46:48 +0200 Subject: [PATCH 12/15] Revert the change of the array values lowercasing in the NoSilenceErrors sniff --- WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php index a8fe7409c7..4817f82652 100644 --- a/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php +++ b/WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php @@ -184,7 +184,8 @@ public function register() { */ public function process_token( $stackPtr ) { // Handle the user-defined custom function list. - $this->customAllowedFunctionsList = RulesetPropertyHelper::merge_custom_array( $this->customAllowedFunctionsList, array(), false, true ); + $this->customAllowedFunctionsList = RulesetPropertyHelper::merge_custom_array( $this->customAllowedFunctionsList, array(), false ); + $this->customAllowedFunctionsList = array_map( 'strtolower', $this->customAllowedFunctionsList ); /* * Check if the error silencing is done for one of the allowed functions. From d9b23edb5e3e0b3f962b83967ce244a8407b5556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Thu, 21 Sep 2023 10:47:20 +0200 Subject: [PATCH 13/15] Change the letter case of passed properties, not methods in tests --- WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc | 10 +++++----- WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc | 2 +- WordPress/Tests/Security/EscapeOutputUnitTest.1.inc | 4 ++-- .../Tests/Security/NonceVerificationUnitTest.1.inc | 2 +- .../Security/ValidatedSanitizedInputUnitTest.1.inc | 12 ++++++------ 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc index 7d80eaefed..f4ba8bb8dd 100644 --- a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc +++ b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc @@ -341,10 +341,10 @@ function method_names_are_caseinsensitive() { // phpcs:set WordPress.DB.DirectDatabaseQuery customCacheDeleteFunctions[] MY_cachedeL function cache_customA() { global $wpdb; - $quux = MY_cacheget( 'quux' ); + $quux = my_cacheget( 'quux' ); if ( false !== $quux ) { $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. - my_cacheSet( 'key', 'group' ); + my_cacheset( 'key', 'group' ); } } @@ -353,14 +353,14 @@ function cache_customB() { $quux = my_cacheget( 'quux' ); if ( false !== $quux ) { $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. - my_other_CacheSet( 'key', 'group' ); + my_other_cacheset( 'key', 'group' ); } } function cache_customC() { global $wpdb; $wpdb->query( 'SELECT X FROM Y' ); // Warning direct DB call. - my_cacheDEL( 'key', 'group' ); + my_cachedel( 'key', 'group' ); } // phpcs:set WordPress.DB.DirectDatabaseQuery customCacheSetFunctions[] my_cacheSet @@ -371,7 +371,7 @@ function cache_customD() { $quux = my_cacheget( 'quux' ); if ( false !== $quux ) { $wpdb->get_results( 'SELECT X FROM Y' ); // Warning direct DB call. - my_cacHeset( 'key', 'group' ); + my_cacheset( 'key', 'group' ); } } diff --git a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc index f007d150bd..ff46a6be65 100644 --- a/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc +++ b/WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc @@ -73,7 +73,7 @@ $files1 = @ & scandir($dir); // Bad. /* * The custom allowed functions list will be respected even when `usePHPFunctionsList` is set to false. */ -// phpcs:set WordPress.PHP.NoSilencedErrors customAllowedFunctionsList[] fgetcsv,hex2bin +// phpcs:set WordPress.PHP.NoSilencedErrors customAllowedFunctionsList[] fgetCsv,hEx2bin while ( ( $csvdata = @fgetcsv( $handle, 2000, $separator ) ) !== false ) {} echo @some_userland_function( $param ); // Bad. $decoded = @hex2bin( $data ); diff --git a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc index b61932f6c5..aa5c1c8fb4 100644 --- a/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc +++ b/WordPress/Tests/Security/EscapeOutputUnitTest.1.inc @@ -657,7 +657,7 @@ echo ''; echo ''; // Bad. // phpcs:set WordPress.Security.EscapeOutput customPrintingFunctions[] TO_SCREEN,my_print -to_scReen( $var1, esc_attr( $var2 ) ); // Bad x 1. -my_prinT( $var1, $var2 ); // Bad x 2. +to_screen( $var1, esc_attr( $var2 ) ); // Bad x 1. +my_print( $var1, $var2 ); // Bad x 2. // phpcs:set WordPress.Security.EscapeOutput customEscapingFunctions[] diff --git a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc index 3e2946c422..8037c21b57 100644 --- a/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc +++ b/WordPress/Tests/Security/NonceVerificationUnitTest.1.inc @@ -489,7 +489,7 @@ enum MyEnum { // phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] MY_nonce_check // phpcs:set WordPress.Security.NonceVerification customUnslashingSanitizingFunctions[] do_sometHING function foo_6() { - my_noncE_cheCk( do_soMeThinG( $_POST['tweet'] ) ); // OK. + my_nonce_check( do_something( $_POST['tweet'] ) ); // OK. } // phpcs:set WordPress.Security.NonceVerification customUnslashingSanitizingFunctions[] // phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] diff --git a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc index 054ad37ac6..8b6f5b29b9 100644 --- a/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc +++ b/WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.1.inc @@ -513,16 +513,16 @@ function test_this() { // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] sanitize_color,sanitize_TWITTER_handle - $abc = sanitize_cOlor( wp_unslash( $_POST['abc_field'] ) ); // OK. - $abc = sanitize_facebook_ID( wp_unslash( $_POST['abc_field'] ) ); // Bad x1 - sanitize. - $abc = sanitize_twitteR_handle( $_POST['abc_field'] ); // Bad x1 - unslash. + $abc = sanitize_color( wp_unslash( $_POST['abc_field'] ) ); // OK. + $abc = sanitize_facebook_id( wp_unslash( $_POST['abc_field'] ) ); // Bad x1 - sanitize. + $abc = sanitize_twitter_handle( $_POST['abc_field'] ); // Bad x1 - unslash. // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] sanitize_color,sanitize_facebook_ID // phpcs:set WordPress.Security.ValidatedSanitizedInput customUnslashingSanitizingFunctions[] sanITize_twitter_handle - $abc = sanitizE_coLor( wp_unslash( $_POST['abc_field'] ) ); // OK. - $abc = sanitize_facebook_ID( wp_unslash( $_POST['abc_field'] ) ); // OK. - $abc = sanitize_TWITTER_haNdle( $_POST['abc_field'] ); // OK. + $abc = sanitize_color( wp_unslash( $_POST['abc_field'] ) ); // OK. + $abc = sanitize_facebook_id( wp_unslash( $_POST['abc_field'] ) ); // OK. + $abc = sanitize_twitter_handle( $_POST['abc_field'] ); // OK. // phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] // phpcs:set WordPress.Security.ValidatedSanitizedInput customUnslashingSanitizingFunctions[] From 93f7c6a7665e5b69d405176dfdfbf9682fbfb4d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sat, 23 Sep 2023 08:00:55 +0200 Subject: [PATCH 14/15] Update WordPress/Helpers/RulesetPropertyHelper.php Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- WordPress/Helpers/RulesetPropertyHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Helpers/RulesetPropertyHelper.php b/WordPress/Helpers/RulesetPropertyHelper.php index 36db429961..d71e1d958d 100644 --- a/WordPress/Helpers/RulesetPropertyHelper.php +++ b/WordPress/Helpers/RulesetPropertyHelper.php @@ -49,7 +49,7 @@ final class RulesetPropertyHelper { * @param array $base Optional. Base list. Defaults to an empty array. * Expects `value => true` format when `$flip` is true. * @param bool $flip Optional. Whether or not to flip the custom list. - * @param bool $lowercasekeys Optional. Whether to lowercase keys and values in the resulting array. + * @param bool $lowercasekeys Optional. Whether to lowercase keys in the resulting array. * Defaults to false. * @return array */ From b4c1765ad1bb9ec94d1904f64ff23de831974684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C5=BDoljom?= Date: Sat, 23 Sep 2023 08:01:04 +0200 Subject: [PATCH 15/15] Update WordPress/Helpers/RulesetPropertyHelper.php Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com> --- WordPress/Helpers/RulesetPropertyHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Helpers/RulesetPropertyHelper.php b/WordPress/Helpers/RulesetPropertyHelper.php index d71e1d958d..afad651c48 100644 --- a/WordPress/Helpers/RulesetPropertyHelper.php +++ b/WordPress/Helpers/RulesetPropertyHelper.php @@ -43,7 +43,7 @@ final class RulesetPropertyHelper { * @since 2.0.0 No longer supports custom array properties which were incorrectly * passed as a string. * @since 3.0.0 Moved from the Sniff class to this class. - * @since 3.0.2 Added a new parameter to lowercase array keys and values. + * @since 3.0.2 Added a new parameter to lowercase array keys for the resulting array. * * @param array $custom Custom list as provided via a ruleset. * @param array $base Optional. Base list. Defaults to an empty array.