diff --git a/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php b/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php
index 32e9f7a9..77dd1f47 100644
--- a/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php
+++ b/WordPressVIPMinimum/Sniffs/Security/PHPFilterFunctionsSniff.php
@@ -12,6 +12,7 @@
use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Utils\PassedParameters;
use WordPressCS\WordPress\AbstractFunctionParameterSniff;
+use WordPressCS\WordPress\Helpers\RulesetPropertyHelper;
/**
* This sniff ensures that proper sanitization is occurring when PHP's filter_* functions are used.
@@ -65,6 +66,28 @@ class PHPFilterFunctionsSniff extends AbstractFunctionParameterSniff {
'FILTER_UNSAFE_RAW' => true,
];
+ /**
+ * Filter names to exclude from the list of restricted filters.
+ *
+ * This allows a developer who knowingly uses a non-sanitizing filter (for
+ * example, when they sanitize the value themselves afterwards) to prevent
+ * the sniff from flagging it, without having to redeclare the full list.
+ *
+ * Set this from a custom ruleset, for example to allow `FILTER_UNSAFE_RAW`:
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * @var array
+ */
+ public $exclude_filters = [];
+
/**
* Process the parameters of a matched function.
*
@@ -118,7 +141,13 @@ public function process_parameters( $stackPtr, $group_name, $matched_content, $p
return;
}
- if ( isset( $this->restricted_filters[ $target_param['clean'] ] ) ) {
+ // Recalculated on each call so an inline change to the `exclude_filters` property is respected.
+ $restricted_filters = array_diff_key(
+ $this->restricted_filters,
+ RulesetPropertyHelper::merge_custom_array( $this->exclude_filters )
+ );
+
+ if ( isset( $restricted_filters[ $target_param['clean'] ] ) ) {
$first_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, $target_param['start'], ( $target_param['end'] + 1 ), true );
$message = 'Please use an appropriate filter to sanitize, as "%s" does no filtering, see: http://php.net/manual/en/filter.filters.sanitize.php.';
diff --git a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.inc b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.inc
index 0159aac5..ee7c0927 100644
--- a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.inc
+++ b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.inc
@@ -98,3 +98,13 @@ filter_input_array(
],
]
);
+
+/*
+ * Bug #753: the list of restricted filters can be reduced via the `exclude_filters` property.
+ */
+$excludable = filter_input( INPUT_POST, 'a', FILTER_UNSAFE_RAW ); // Warning RestrictedFilter.
+
+// phpcs:set WordPressVIPMinimum.Security.PHPFilterFunctions exclude_filters[] FILTER_UNSAFE_RAW
+$excluded = filter_input( INPUT_POST, 'b', FILTER_UNSAFE_RAW ); // OK - excluded via the property.
+$still_restricted = filter_var( $value, FILTER_DEFAULT ); // Warning RestrictedFilter - other defaults still apply.
+// phpcs:set WordPressVIPMinimum.Security.PHPFilterFunctions exclude_filters[]
diff --git a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php
index 1faa0728..7a53bcd3 100644
--- a/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php
+++ b/WordPressVIPMinimum/Tests/Security/PHPFilterFunctionsUnitTest.php
@@ -32,24 +32,26 @@ public function getErrorList() {
*/
public function getWarningList() {
return [
- 44 => 1,
- 45 => 1,
- 46 => 1,
- 48 => 1,
- 49 => 1,
- 50 => 1,
- 52 => 1,
- 53 => 1,
- 54 => 1,
- 56 => 1,
- 57 => 1,
- 58 => 1,
- 65 => 1,
- 70 => 1,
- 71 => 1,
- 73 => 1,
- 75 => 1,
- 81 => 1,
+ 44 => 1,
+ 45 => 1,
+ 46 => 1,
+ 48 => 1,
+ 49 => 1,
+ 50 => 1,
+ 52 => 1,
+ 53 => 1,
+ 54 => 1,
+ 56 => 1,
+ 57 => 1,
+ 58 => 1,
+ 65 => 1,
+ 70 => 1,
+ 71 => 1,
+ 73 => 1,
+ 75 => 1,
+ 81 => 1,
+ 105 => 1,
+ 109 => 1,
];
}
}