diff --git a/WordPress/Helpers/EscapingFunctionsTrait.php b/WordPress/Helpers/EscapingFunctionsTrait.php
index 4ebff51396..c6fcc3c209 100644
--- a/WordPress/Helpers/EscapingFunctionsTrait.php
+++ b/WordPress/Helpers/EscapingFunctionsTrait.php
@@ -220,7 +220,9 @@ final public function is_escaping_function( $functionName ) {
) {
$this->allEscapingFunctions = RulesetPropertyHelper::merge_custom_array(
$this->customEscapingFunctions,
- $this->escapingFunctions
+ $this->escapingFunctions,
+ true,
+ true
);
$this->addedCustomEscapingFunctions['escape'] = $this->customEscapingFunctions;
@@ -244,7 +246,9 @@ final public function is_auto_escaped_function( $functionName ) {
) {
$this->allAutoEscapedFunctions = RulesetPropertyHelper::merge_custom_array(
$this->customAutoEscapedFunctions,
- $this->autoEscapedFunctions
+ $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 edd6dbe211..94c034c419 100644
--- a/WordPress/Helpers/PrintingFunctionsTrait.php
+++ b/WordPress/Helpers/PrintingFunctionsTrait.php
@@ -98,7 +98,9 @@ final public function get_printing_functions() {
) {
$this->allPrintingFunctions = RulesetPropertyHelper::merge_custom_array(
$this->customPrintingFunctions,
- $this->printingFunctions
+ $this->printingFunctions,
+ true,
+ true
);
$this->addedCustomPrintingFunctions = $this->customPrintingFunctions;
diff --git a/WordPress/Helpers/RulesetPropertyHelper.php b/WordPress/Helpers/RulesetPropertyHelper.php
index b20c6ed3bf..afad651c48 100644
--- a/WordPress/Helpers/RulesetPropertyHelper.php
+++ b/WordPress/Helpers/RulesetPropertyHelper.php
@@ -43,15 +43,25 @@ 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 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.
- * 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 $lowercasekeys Optional. Whether to lowercase keys 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, $lowercasekeys = false ) {
+ if ( empty( $base ) && empty( $custom ) ) {
+ return array();
+ }
+
+ if ( $lowercasekeys ) {
+ $base = array_change_key_case( $base );
+ }
+
if ( true === $flip ) {
$base = array_filter( $base );
}
@@ -64,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;
}
diff --git a/WordPress/Helpers/SanitizationHelperTrait.php b/WordPress/Helpers/SanitizationHelperTrait.php
index c041dfe5c1..ce29ea9e28 100644
--- a/WordPress/Helpers/SanitizationHelperTrait.php
+++ b/WordPress/Helpers/SanitizationHelperTrait.php
@@ -196,7 +196,9 @@ final public function get_sanitizing_functions() {
) {
$this->allSanitizingFunctions = RulesetPropertyHelper::merge_custom_array(
$this->customSanitizingFunctions,
- $this->sanitizingFunctions
+ $this->sanitizingFunctions,
+ true,
+ true
);
$this->addedCustomSanitizingFunctions['sanitize'] = $this->customSanitizingFunctions;
@@ -218,7 +220,9 @@ final public function get_sanitizing_and_unslashing_functions() {
) {
$this->allUnslashingSanitizingFunctions = RulesetPropertyHelper::merge_custom_array(
$this->customUnslashingSanitizingFunctions,
- $this->unslashingSanitizingFunctions
+ $this->unslashingSanitizingFunctions,
+ true,
+ true
);
$this->addedCustomSanitizingFunctions['unslashsanitize'] = $this->customUnslashingSanitizingFunctions;
diff --git a/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php b/WordPress/Sniffs/DB/DirectDatabaseQuerySniff.php
index 590f6478ea..11cf0796e5 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[ $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[ $this->tokens[ $i ]['content'] ] ) ) {
+ } elseif ( isset( $this->cacheGetFunctions[ $content ] ) ) {
$wp_cache_get = true;
- } elseif ( isset( $this->cacheSetFunctions[ $this->tokens[ $i ]['content'] ] ) ) {
+ } elseif ( isset( $this->cacheSetFunctions[ $content ] ) ) {
if ( $wp_cache_get ) {
$cached = true;
@@ -274,7 +275,9 @@ protected function mergeFunctionLists() {
if ( $this->customCacheGetFunctions !== $this->addedCustomFunctions['cacheget'] ) {
$this->cacheGetFunctions = RulesetPropertyHelper::merge_custom_array(
$this->customCacheGetFunctions,
- $this->cacheGetFunctions
+ $this->cacheGetFunctions,
+ true,
+ true
);
$this->addedCustomFunctions['cacheget'] = $this->customCacheGetFunctions;
@@ -283,7 +286,9 @@ protected function mergeFunctionLists() {
if ( $this->customCacheSetFunctions !== $this->addedCustomFunctions['cacheset'] ) {
$this->cacheSetFunctions = RulesetPropertyHelper::merge_custom_array(
$this->customCacheSetFunctions,
- $this->cacheSetFunctions
+ $this->cacheSetFunctions,
+ true,
+ true
);
$this->addedCustomFunctions['cacheset'] = $this->customCacheSetFunctions;
@@ -292,7 +297,9 @@ protected function mergeFunctionLists() {
if ( $this->customCacheDeleteFunctions !== $this->addedCustomFunctions['cachedelete'] ) {
$this->cacheDeleteFunctions = RulesetPropertyHelper::merge_custom_array(
$this->customCacheDeleteFunctions,
- $this->cacheDeleteFunctions
+ $this->cacheDeleteFunctions,
+ true,
+ true
);
$this->addedCustomFunctions['cachedelete'] = $this->customCacheDeleteFunctions;
diff --git a/WordPress/Sniffs/Security/NonceVerificationSniff.php b/WordPress/Sniffs/Security/NonceVerificationSniff.php
index 0241147327..60c2e0bb6f 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.
*/
@@ -413,7 +413,9 @@ protected function mergeFunctionLists() {
if ( $this->customNonceVerificationFunctions !== $this->addedCustomNonceFunctions ) {
$this->nonceVerificationFunctions = RulesetPropertyHelper::merge_custom_array(
$this->customNonceVerificationFunctions,
- $this->nonceVerificationFunctions
+ $this->nonceVerificationFunctions,
+ true,
+ true
);
$this->addedCustomNonceFunctions = $this->customNonceVerificationFunctions;
diff --git a/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc b/WordPress/Tests/DB/DirectDatabaseQueryUnitTest.inc
index eb2d0e7473..f4ba8bb8dd 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/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 cfe20caeee..aa5c1c8fb4 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..8037c21b57 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..8b6f5b29b9 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':