PHP Sanitize Input

Created with Sketch.

PHP Sanitize Input

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
  • email
  • 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 is string, the filter will be FILTER_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 the sanitize() 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' => 'joe@example.com</>',
'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] => joe@example.com
[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.

Leave a Reply

Your email address will not be published. Required fields are marked *