@@ -312,11 +312,42 @@ abstract class Sniff implements PHPCS_Sniff {
312312 'doubleval ' => true ,
313313 'floatval ' => true ,
314314 'intval ' => true ,
315- 'is_array ' => true ,
316315 'sanitize_key ' => true ,
317316 'sizeof ' => true ,
318317 );
319318
319+ /**
320+ * List of PHP native functions to test the type of a variable.
321+ *
322+ * Using these functions is safe in combination with superglobals without
323+ * unslashing or sanitization.
324+ *
325+ * They should, however, not be regarded as unslashing or sanitization functions.
326+ *
327+ * @since 2.1.0
328+ *
329+ * @var array
330+ */
331+ protected $ typeTestFunctions = array (
332+ 'is_array ' => true ,
333+ 'is_bool ' => true ,
334+ 'is_callable ' => true ,
335+ 'is_countable ' => true ,
336+ 'is_double ' => true ,
337+ 'is_float ' => true ,
338+ 'is_int ' => true ,
339+ 'is_integer ' => true ,
340+ 'is_iterable ' => true ,
341+ 'is_long ' => true ,
342+ 'is_null ' => true ,
343+ 'is_numeric ' => true ,
344+ 'is_object ' => true ,
345+ 'is_real ' => true ,
346+ 'is_resource ' => true ,
347+ 'is_scalar ' => true ,
348+ 'is_string ' => true ,
349+ );
350+
320351 /**
321352 * Token which when they preceed code indicate the value is safely casted.
322353 *
@@ -1372,12 +1403,17 @@ protected function has_nonce_check( $stackPtr ) {
13721403 }
13731404 }
13741405
1375- $ in_isset = $ this ->is_in_isset_or_empty ( $ stackPtr );
1406+ $ allow_nonce_after = false ;
1407+ if ( $ this ->is_in_isset_or_empty ( $ stackPtr )
1408+ || $ this ->is_in_type_test ( $ stackPtr )
1409+ ) {
1410+ $ allow_nonce_after = true ;
1411+ }
13761412
1377- // We allow for isset( $_POST['var'] ) checks to come before the nonce check.
1378- // If this is inside an isset(), check after it as well, all the way to the
1379- // end of the scope.
1380- if ( $ in_isset ) {
1413+ // We allow for certain actions, such as an isset() check to come before the nonce check.
1414+ // If this superglobal is inside such a check, look for the nonce after it as well,
1415+ // all the way to the end of the scope.
1416+ if ( true === $ allow_nonce_after ) {
13811417 $ end = ( 0 === $ start ) ? $ this ->phpcsFile ->numTokens : $ tokens [ $ start ]['scope_closer ' ];
13821418 }
13831419
@@ -1393,7 +1429,7 @@ protected function has_nonce_check( $stackPtr ) {
13931429 // If we have already found an nonce check in this scope, we just
13941430 // need to check whether it comes before this token. It is OK if the
13951431 // check is after the token though, if this was only a isset() check.
1396- return ( $ in_isset || $ last ['nonce_check ' ] < $ stackPtr );
1432+ return ( true === $ allow_nonce_after || $ last ['nonce_check ' ] < $ stackPtr );
13971433 } elseif ( $ end <= $ last ['end ' ] ) {
13981434 // If not, we can still go ahead and return false if we've already
13991435 // checked to the end of the search area.
@@ -1624,6 +1660,24 @@ protected function is_in_function_call( $stackPtr, $valid_functions, $global = t
16241660 return false ;
16251661 }
16261662
1663+ /**
1664+ * Check if a token is inside of an is_...() statement.
1665+ *
1666+ * @since 2.1.0
1667+ *
1668+ * @param int $stackPtr The index of the token in the stack.
1669+ *
1670+ * @return bool Whether the token is being type tested.
1671+ */
1672+ protected function is_in_type_test ( $ stackPtr ) {
1673+ /*
1674+ * Casting the potential integer stack pointer return value to boolean here is fine.
1675+ * The return can never be `0` as there will always be a PHP open tag before the
1676+ * function call.
1677+ */
1678+ return (bool ) $ this ->is_in_function_call ( $ stackPtr , $ this ->typeTestFunctions );
1679+ }
1680+
16271681 /**
16281682 * Check if something is only being sanitized.
16291683 *
0 commit comments