Summary: in this tutorial, you’ll learn to develop a reusable PHP sanitize()
function to sanitize inputs.
Introduction to sanitizing input
Before processing data from untrusted sources such as HTTP post
or get
request, you should always sanitize it first.
Sanitizing input means removing illegal characters using deleting, replacing, encoding, or escaping techniques.
PHP provides a list of sanitizing filters that you can use to sanitize input effectively. The following functions use these filters to sanitize the input:
- filter_input()
- filter_var()
- filter_input_array()
- filter_var_array()
In this tutorial, we’ll create a reusable sanitize()
function that sanitizes the inputs in a more expressive way.
Define the sanitize() function
Suppose you have the following fields in the $_POST
variable and want to sanitize them:
- name
- age
- weight
- homepage
To do that, you can define a sanitize()
function and call it as follows:
$data = santize($_POST, $fields);
Code language: PHP (php)
The sanitize()
function should look like this:
function sanitize(array $inputs, array $fields) : array
Code language: PHP (php)
The function has two parameters:
- The
$inputs
parameter is an associative array. It can be$_POST
,$_GET
, or a regular associative array. - The
$fields
parameter is an array that specifies a list of fields with rules.
The sanitize()
function returns an array that contains the sanitized data.
The$fields
should be an associative array in which the key is the field name and value is the rule for that field. For example:
$fields = [
'name' => 'string',
'email' => 'email',
'age' => 'int',
'weight' => 'float',
'github' => 'url',
'hobbies' => 'string[]'
];
Code language: PHP (php)
Note that the string[]
means an array of strings.
To sanitize these fields:
- First, iterate over the
$fields
and use the corresponding filter for each. For example, if the rule isstring
, the filter will beFILTER_SANITIZE_STRING
. - Second, sanitize the field using the filter.
To get a filter based on the rule of a field, you can define a mapping between the rules with the filters like this:
const FILTERS = [
'string' => FILTER_SANITIZE_STRING,
'string[]' => [
'filter' => FILTER_SANITIZE_STRING,
'flags' => FILTER_REQUIRE_ARRAY
],
'email' => FILTER_SANITIZE_EMAIL,
'int' => [
'filter' => FILTER_SANITIZE_NUMBER_INT,
'flags' => FILTER_REQUIRE_SCALAR
],
'int[]' => [
'filter' => FILTER_SANITIZE_NUMBER_INT,
'flags' => FILTER_REQUIRE_ARRAY
],
'float' => [
'filter' => FILTER_SANITIZE_NUMBER_FLOAT,
'flags' => FILTER_FLAG_ALLOW_FRACTION
],
'float[]' => [
'filter' => FILTER_SANITIZE_NUMBER_FLOAT,
'flags' => FILTER_REQUIRE_ARRAY
],
'url' => FILTER_SANITIZE_URL,
];
Code language: PHP (php)
For example, the following returns the filter of the string
rule:
FILTER['string']
Code language: PHP (php)
To sanitize multiple fields at a time, you can use the filter_var_array()
function:
filter_var_array($inputs, $options)
Code language: PHP (php)
The first parameter of the filter_var_array()
function is an array of variables to filter. And the second parameter is an array of filters. For example, it should look like this:
$options = [
'name' => FILTER_SANITIZE_STRING,
'email' => FILTER_SANITIZE_EMAIL,
'age' => [
'filter' => FILTER_SANITIZE_NUMBER_INT,
'flags' => FILTER_REQUIRE_SCALAR
],
'weight' => [
'filter' => FILTER_SANITIZE_NUMBER_FLOAT,
'flags' => FILTER_FLAG_ALLOW_FRACTION
],
'github' => FILTER_SANITIZE_URL,
];
Code language: PHP (php)
So you need to return this $options
from the $fields
and FILTERS
arrays. To do that, you can use the array_map()
function like this:
$options = array_map(fn($field) => FILTERS[$field], $fields);
Code language: PHP (php)
The following shows the sanitize()
function:
function sanitize(array $inputs, array $fields): array
{
$options = array_map(fn($field) => FILTERS[$field], $fields);
return filter_var_array($inputs, $options);
}
Code language: PHP (php)
Make the sanitize() function more flexible
The sanitize()
function uses the FILTERS
constant. To make it more flexible, you can add a parameter and set its default value to the FILTERS
constant like this:
function sanitize(array $inputs, array $fields, array $filters = FILTERS): array
{
$options = array_map(fn($field) => $filters[$field], $fields);
return filter_var_array($inputs, $options);
}
Code language: PHP (php)
Also, you may want to sanitize the fields in the $inputs
using one filter e.g., FILTER_SANITIZE_STRING
.
To do that, you can:
- First, make the
$fields
parameter optional and set its default value to an empty array[]
. - Second, add a default filter parameter.
- Third, if the
$filters
array is empty, use the default filter.
The sanitize()
function will look like the following:
function sanitize(array $inputs, array $fields = [], int $default_filter = FILTER_SANITIZE_STRING, array $filters = FILTERS): array
{
if ($fields) {
$options = array_map(fn($field) => $filters[$field], $fields);
return filter_var_array($inputs, $options);
}
return filter_var_array($inputs, $default_filter);
}
Code language: PHP (php)
Remove whitespaces of strings
To remove the whitespaces of a string, you use the trim()
function. And to remove the whitespaces of an array of strings, you use the array_map()
function with the trim()
function:
$trimmed_data = array_map('trim', $inputs);
Code language: PHP (php)
However, the $inputs
may contain items that are not strings. To trim the string item only, you can use is_string()
function to check if the item is a string before trimming it:
$trimmed_data = array_map(function ($item) {
if (is_string($item)) {
return trim($item);
}
return $item;
}, $inputs);
Code language: PHP (php)
The $inputs
may contain an item that is an array of strings. For example:
$inputs = [
...
'hobbies' => [
' Reading',
'Running ',
' Programming '
]
]
Code language: PHP (php)
To trim the strings in the hobbies
item, you need to use a recursive function:
function array_trim(array $items): array
{
return array_map(function ($item) {
if (is_string($item)) {
return trim($item);
} elseif (is_array($item)) {
return array_trim($item);
} else
return $item;
}, $items);
}
Code language: PHP (php)
Call array_trim() from the sanitize() function
To call the array_trim()
function from the sanitize()
function:
- First, add a new parameter called
$trim
to thesanitize()
function and set its default value to true. - Second, call the
array_trim()
if the $trim parameter is true.
The following shows the updated sanitize()
function:
function sanitize(array $inputs, array $fields = [], int $default_filter = FILTER_SANITIZE_STRING, array $filters = FILTERS, bool $trim = true): array
{
if ($fields) {
$options = array_map(fn($field) => $filters[$field], $fields);
$data = filter_var_array($inputs, $options);
} else {
$data = filter_var_array($inputs, $default_filter);
}
return $trim ? array_trim($data) : $data;
}
Code language: PHP (php)
Put it all together
The following shows the complete sanitization.php
file with FILTERS
, array_trim()
, and sanitize()
functions:
const FILTERS = [
'string' => FILTER_SANITIZE_STRING,
'string[]' => [
'filter' => FILTER_SANITIZE_STRING,
'flags' => FILTER_REQUIRE_ARRAY
],
'email' => FILTER_SANITIZE_EMAIL,
'int' => [
'filter' => FILTER_SANITIZE_NUMBER_INT,
'flags' => FILTER_REQUIRE_SCALAR
],
'int[]' => [
'filter' => FILTER_SANITIZE_NUMBER_INT,
'flags' => FILTER_REQUIRE_ARRAY
],
'float' => [
'filter' => FILTER_SANITIZE_NUMBER_FLOAT,
'flags' => FILTER_FLAG_ALLOW_FRACTION
],
'float[]' => [
'filter' => FILTER_SANITIZE_NUMBER_FLOAT,
'flags' => FILTER_REQUIRE_ARRAY
],
'url' => FILTER_SANITIZE_URL,
];
/**
* Recursively trim strings in an array
* @param array $items
* @return array
*/
function array_trim(array $items): array
{
return array_map(function ($item) {
if (is_string($item)) {
return trim($item);
} elseif (is_array($item)) {
return array_trim($item);
} else
return $item;
}, $items);
}
/**
* Sanitize the inputs based on the rules an optionally trim the string
* @param array $inputs
* @param array $fields
* @param int $default_filter FILTER_SANITIZE_STRING
* @param array $filters FILTERS
* @param bool $trim
* @return array
*/
function sanitize(array $inputs, array $fields = [], int $default_filter = FILTER_SANITIZE_STRING, array $filters = FILTERS, bool $trim = true): array
{
if ($fields) {
$options = array_map(fn($field) => $filters[$field], $fields);
$data = filter_var_array($inputs, $options);
} else {
$data = filter_var_array($inputs, $default_filter);
}
return $trim ? array_trim($data) : $data;
}
Code language: PHP (php)
Use the sanitize() function
The following shows how to use the sanitize()
function to sanitize data in the $input
using the sanitization rules specified in the $fields
:
<?php
require __DIR__ . '/sanitization.php';
$inputs = [
'name' => 'joe<script>',
'email' => '[email protected]</>',
'age' => '18abc',
'weight' => '100.12lb',
'github' => 'https://github.com/joe',
'hobbies' => [
' Reading',
'Running ',
' Programming '
]
];
$fields = [
'name' => 'string',
'email' => 'email',
'age' => 'int',
'weight' => 'float',
'github' => 'url',
'hobbies' => 'string[]'
];
$data = sanitize($inputs,$fields);
var_dump($data);
Code language: PHP (php)
Output:
Array
(
[name] => joe
[email] => [email protected]
[age] => 18
[weight] => 100.12
[github] => https://github.com/joe
[hobbies] => Array
(
[0] => Reading
[1] => Running
[2] => Programming
)
)
Code language: PHP (php)
In this tutorial, you have learned how to develop a reusable PHP sanitize()
function from scratch.