PHP Filters
What Is the Filter Extension? In simple terms: PHP filters are ready-made tools for checking and cleaning data — "is this a valid integer?", "is this an email address?", "remove everything except digi
What Is the Filter Extension?
In simple terms: PHP filters are ready-made tools for checking and cleaning data — "is this a valid integer?", "is this an email address?", "remove everything except digits". Instead of writing your own checks, you choose a filter and apply it to a value.
Technically: The filter extension (enabled by default) provides a set of filters identified by constants such as FILTER_VALIDATE_INT or FILTER_SANITIZE_EMAIL, and functions that apply them to single values (filter_var()), arrays of values (filter_var_array()), or request input directly (filter_input(), filter_input_array()). Each filter can be customized with options and flags.
Three Kinds of Filters
| Kind | Purpose | Result on Success | Result on Failure |
|---|---|---|---|
Validate (FILTER_VALIDATE_*) | Check that a value has a certain form | The value, converted to the right type | false (or null with FILTER_NULL_ON_FAILURE) |
Sanitize (FILTER_SANITIZE_*) | Remove or encode unwanted characters | The cleaned string | Rarely fails |
Other (FILTER_CALLBACK, FILTER_UNSAFE_RAW) | Custom processing / no processing | Depends | Depends |
The form lessons showed how to use filters for validation (PHP Form Validation, PHP Form URL/E-mail) and sanitization (Form Input Sanitizing). This lesson explains the filter API itself; PHP Filters Advanced covers flags and options in detail.
The Filter Functions
| Function | Applies Filters To |
|---|---|
filter_var($value, $filter, $options) | One value |
filter_var_array($array, $definition, $addEmpty) | Several values at once |
filter_input($type, $name, $filter, $options) | One request variable (INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV) |
filter_input_array($type, $definition, $addEmpty) | Several request variables |
filter_has_var($type, $name) | Checks whether a request variable exists |
filter_list() | Names of all available filters |
filter_id($name) | Filter constant for a name |
Available Filters
<?php
$filters = filter_list();
var_dump(in_array('int', $filters, true));
var_dump(in_array('validate_email', $filters, true));
var_dump(filter_id('int') === FILTER_VALIDATE_INT);
Output
bool(true)
bool(true)
bool(true)
Each filter has a name (int, boolean, float, validate_email, email, url, …) and a constant. Code normally uses the constants; filter_list() and filter_id() are useful mainly for configuration-driven validation.
filter_var() and Its Options Structure
Syntax
filter_var(mixed $value, int $filter = FILTER_DEFAULT, array|int $options = 0): mixed
The third argument is either:
- a single flags integer:
filter_var($v, FILTER_VALIDATE_BOOL, FILTER_NULL_ON_FAILURE), or - an array with an
'options'key and/or a'flags'key:
filter_var($value, FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => 100, 'default' => 10],
'flags' => FILTER_FLAG_ALLOW_HEX,
]);
| Part | Contains |
|---|---|
'options' | Filter-specific settings: ranges, default, regexp, decimal, or a callback |
'flags' | Bit flags combined with |, which switch behaviors on |
The default Option
<?php
var_dump(filter_var('abc', FILTER_VALIDATE_INT, ['options' => ['default' => 1]]));
var_dump(filter_var('250', FILTER_VALIDATE_INT, ['options' => ['max_range' => 100, 'default' => 20]]));
var_dump(filter_var('42', FILTER_VALIDATE_INT, ['options' => ['default' => 1]]));
Output
int(1)
int(20)
int(42)
When validation fails, default is returned instead of false. This is convenient for optional parameters with a fallback, such as page numbers or page sizes.
FILTER_CALLBACK: Your Own Filter
<?php
$normalizeTag = fn(string $value): string => strtolower(preg_replace('/\s+/', '-', trim($value)));
var_dump(filter_var(' Web Development ', FILTER_CALLBACK, ['options' => $normalizeTag]));
print_r(filter_var(['PHP Basics', ' MySQL '], FILTER_CALLBACK, ['options' => $normalizeTag]));
Output
string(15) "web-development"
Array
(
[0] => php-basics
[1] => mysql
)
FILTER_CALLBACK calls any function (closure, function name, or first-class callable) on the value. When the value is an array, the callback is applied to each element recursively. This lets custom normalization be part of a filter definition together with built-in filters.
Filtering Arrays
Validation filters expect a scalar by default. Flags control how arrays are handled:
<?php
var_dump(filter_var(['5'], FILTER_VALIDATE_INT));
var_dump(filter_var(['1', '2', 'x'], FILTER_VALIDATE_INT, FILTER_REQUIRE_ARRAY));
var_dump(filter_var('5', FILTER_VALIDATE_INT, FILTER_FORCE_ARRAY));
Output
bool(false)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
bool(false)
}
array(1) {
[0]=>
int(5)
}
| Flag | Effect |
|---|---|
(default) FILTER_REQUIRE_SCALAR | Arrays are rejected |
FILTER_REQUIRE_ARRAY | Only arrays accepted; each element is filtered |
FILTER_FORCE_ARRAY | A scalar is wrapped in an array; arrays are filtered element by element |
This is exactly what is needed for inputs such as checkbox groups (ids[]): FILTER_REQUIRE_ARRAY both checks that an array was sent and validates each element.
Reading Request Data Directly: filter_input()
<?php
// Request: GET /products.php?page=3&debug
$page = filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
$limit = filter_input(INPUT_GET, 'limit', FILTER_VALIDATE_INT);
var_dump($page, $limit);
var_dump(filter_has_var(INPUT_GET, 'debug'));
Output
int(3)
NULL
bool(true)
| Result | Meaning |
|---|---|
| A value | The variable exists and passed the filter |
false | The variable exists but failed the filter |
null | The variable does not exist |
Things to Know About filter_input()
- It reads the original request data. Changes made to
$_GETor$_POSTin your code are not seen by it. - In command-line scripts there is no request, so it always returns
null— which makes code that uses it harder to test. Many applications therefore applyfilter_var()orfilter_var_array()to$_GET/$_POST, or to a request object, instead.
Practical Example: Reading Listing Parameters
A single definition can describe all query parameters of a page:
<?php
function readListingParams(array $query): array
{
$query += ['page' => '1', 'per_page' => '20', 'sort' => 'newest', 'ids' => []];
$definition = [
'page' => [
'filter' => FILTER_VALIDATE_INT,
'options' => ['min_range' => 1, 'default' => 1],
],
'per_page' => [
'filter' => FILTER_VALIDATE_INT,
'options' => ['min_range' => 1, 'max_range' => 100, 'default' => 20],
],
'sort' => [
'filter' => FILTER_VALIDATE_REGEXP,
'options' => ['regexp' => '/^(newest|price|rating)$/', 'default' => 'newest'],
],
'ids' => [
'filter' => FILTER_VALIDATE_INT,
'flags' => FILTER_REQUIRE_ARRAY,
],
];
$params = filter_var_array($query, $definition);
$params['ids'] = is_array($params['ids'])
? array_values(array_filter($params['ids'], 'is_int'))
: [];
return $params;
}
// Simulates: GET /products.php?page=3&per_page=500&sort=price&ids[]=4&ids[]=x&ids[]=9
echo json_encode(readListingParams([
'page' => '3',
'per_page' => '500',
'sort' => 'price',
'ids' => ['4', 'x', '9'],
])) . "\n";
echo json_encode(readListingParams([])) . "\n";
// In the real page: $params = readListingParams($_GET);
Output
{"page":3,"per_page":20,"sort":"price","ids":[4,9]}
{"page":1,"per_page":20,"sort":"newest","ids":[]}
Step-by-Step Explanation
$query += [...]fills in values for missing parameters. This is needed becausefilter_var_array()returnsnullfor keys that are absent from the input; thedefaultoption only replaces values that are present but invalid.- Each parameter has a filter and options; together they describe valid input in one place.
pageis a positive integer;per_pagemust be between 1 and 100, so500falls back to the default20.sortmust match the allow-list pattern.idsmust be an array of integers; the invalid elementxbecomesfalseand is removed afterwards.
The function receives the query array as a parameter, so it is easy to test and to reuse.
Validation Filters at a Glance
| Filter | Returns on Success | Important Options / Flags |
|---|---|---|
FILTER_VALIDATE_INT | int | min_range, max_range, FILTER_FLAG_ALLOW_HEX, FILTER_FLAG_ALLOW_OCTAL |
FILTER_VALIDATE_FLOAT | float | decimal, min_range, max_range, FILTER_FLAG_ALLOW_THOUSAND |
FILTER_VALIDATE_BOOL | bool | FILTER_NULL_ON_FAILURE |
FILTER_VALIDATE_EMAIL | string | FILTER_FLAG_EMAIL_UNICODE |
FILTER_VALIDATE_URL | string | FILTER_FLAG_PATH_REQUIRED, FILTER_FLAG_QUERY_REQUIRED |
FILTER_VALIDATE_IP | string | FILTER_FLAG_IPV4, FILTER_FLAG_IPV6, FILTER_FLAG_NO_PRIV_RANGE, FILTER_FLAG_NO_RES_RANGE |
FILTER_VALIDATE_DOMAIN | string | FILTER_FLAG_HOSTNAME |
FILTER_VALIDATE_MAC | string | separator |
FILTER_VALIDATE_REGEXP | string | regexp |
Common Mistakes
Checking Results Loosely
Effect: Valid values 0, false, or '' are treated as failures.
Fix: Compare with === false (and === null for missing input with filter_input()).
Passing Options in the Wrong Structure
Effect: filter_var($v, FILTER_VALIDATE_INT, ['min_range' => 1]) silently ignores the range.
Fix: Nest options under 'options': ['options' => ['min_range' => 1]].
Expecting Scalar Filters to Accept Arrays
Effect: Array input fails (returns false).
Fix: Use FILTER_REQUIRE_ARRAY or FILTER_FORCE_ARRAY.
Expecting default to Fill Missing Keys in filter_var_array()
Effect: Missing parameters come back as null.
Fix: Merge default values into the input array first ($input += [...]).
Relying on filter_input() in Testable Code
Effect: Functions cannot be tested without real requests.
Fix: Apply filter_var()/filter_var_array() to arrays passed in as parameters.
Best Practices
- Use validation filters for standard formats and types, and convert values to their proper types in the same step.
- Describe all inputs of a form or page in one
filter_var_array()definition with sensible defaults. - Use
FILTER_CALLBACKto integrate custom normalization. - Handle arrays explicitly with
FILTER_REQUIRE_ARRAY/FILTER_FORCE_ARRAY. - Always compare results strictly.
Official reference: https://www.php.net/manual/en/book.filter.php