Skip to content

Commit 0934e18

Browse files
committed
ValidatedSanitizedInput: treat array-value comparison functions same as other comparisons
Whether a comparison is made via a comparison operator or via one of the array-value comparison functions shouldn't make a difference for this sniff. Both ways of making a comparison should be treated the same. This was, so far, not the case. While `in_array()` was listed in the `$sanitizingFunctions` list, the other array-value comparison functions were not. And for `in_array()` a "missing unslash" error would still be thrown, while this doesn't happen when using straight comparisons. This PR fixes that and adds a new `is_in_array_comparison()` utility function to the `Sniff` class. Includes unit tests via the sniff.
1 parent 14c77a8 commit 0934e18

File tree

4 files changed

+63
-1
lines changed

4 files changed

+63
-1
lines changed

WordPress/Sniff.php

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,6 @@ abstract class Sniff implements PHPCS_Sniff {
256256
'filter_input' => true,
257257
'filter_var' => true,
258258
'hash_equals' => true,
259-
'in_array' => true,
260259
'is_email' => true,
261260
'number_format' => true,
262261
'sanitize_bookmark_field' => true,
@@ -380,6 +379,22 @@ abstract class Sniff implements PHPCS_Sniff {
380379
'map_deep' => 2,
381380
);
382381

382+
/**
383+
* Array functions to compare a $needle to a predefined set of values.
384+
*
385+
* If the value is set to an integer, the function needs to have at least that
386+
* many parameters for it to be considered as a comparison.
387+
*
388+
* @since 2.1.0
389+
*
390+
* @var array <string function name> => <true|int>
391+
*/
392+
protected $arrayCompareFunctions = array(
393+
'in_array' => true,
394+
'array_search' => true,
395+
'array_keys' => 2,
396+
);
397+
383398
/**
384399
* Functions that format strings.
385400
*
@@ -2263,6 +2278,34 @@ protected function is_comparison( $stackPtr ) {
22632278
return false;
22642279
}
22652280

2281+
/**
2282+
* Check if a token is inside of an array-value comparison function.
2283+
*
2284+
* @since 2.1.0
2285+
*
2286+
* @param int $stackPtr The index of the token in the stack.
2287+
*
2288+
* @return bool Whether the token is (part of) a parameter to an
2289+
* array-value comparison function.
2290+
*/
2291+
protected function is_in_array_comparison( $stackPtr ) {
2292+
$function_ptr = $this->is_in_function_call( $stackPtr, $this->arrayCompareFunctions, true, true );
2293+
if ( false === $function_ptr ) {
2294+
return false;
2295+
}
2296+
2297+
$function_name = $this->tokens[ $function_ptr ]['content'];
2298+
if ( true === $this->arrayCompareFunctions[ $function_name ] ) {
2299+
return true;
2300+
}
2301+
2302+
if ( $this->get_function_call_parameter_count( $function_ptr ) >= $this->arrayCompareFunctions[ $function_name ] ) {
2303+
return true;
2304+
}
2305+
2306+
return false;
2307+
}
2308+
22662309
/**
22672310
* Check what type of 'use' statement a token is part of.
22682311
*

WordPress/Sniffs/Security/ValidatedSanitizedInputSniff.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ function ( $symbol ) {
155155
return;
156156
}
157157

158+
// If this is a comparison using the array comparison functions, sanitization isn't needed.
159+
if ( $this->is_in_array_comparison( $stackPtr ) ) {
160+
return;
161+
}
162+
158163
$this->mergeFunctionLists();
159164

160165
// Now look for sanitizing functions.

WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.inc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,16 @@ function test_additional_array_walking_functions() {
276276
$sane = map_deep( wp_unslash( $_GET['test'] ), 'sanitize_text_field' ); // Ok.
277277
$sane = map_deep( wp_unslash( $_GET['test'] ), 'foo' ); // Bad.
278278
}
279+
280+
function test_recognize_array_comparison_functions_as_such() {
281+
if ( ! isset( $_POST['form_fields'] ) ) {
282+
return;
283+
}
284+
285+
if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'install', 'update', 'activate' ), true ) ) {} // OK.
286+
if ( isset( $_REQUEST['plugin_state'] ) && in_array( $_REQUEST['plugin_state'], $states, true ) ) {} // OK.
287+
if ( in_array( 'my_form_hidden_field_value', $_POST['form_fields'], true ) ) {} // OK.
288+
if ( array_search( $_POST['form_fields'], 'my_form_hidden_field_value' ) ) {} // OK.
289+
if ( array_keys( $_POST['form_fields'], 'my_form_hidden_field_value', true ) ) {} // OK.
290+
if ( array_keys( $_POST['form_fields'] ) ) {} // Bad x2.
291+
}

WordPress/Tests/Security/ValidatedSanitizedInputUnitTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public function getErrorList() {
6767
257 => 1,
6868
266 => 1,
6969
277 => 1,
70+
290 => 2,
7071
);
7172
}
7273

0 commit comments

Comments
 (0)