Проверка числовых параметров в PHP

Адресная строка топика на Рутрекере

То, что параметры в PHP надо фильтровать, думаю знают все. Наиболее распространённая задача — фильтрация числовых параметров, которые в большинстве своём являются целыми числами, и в подавляющем большинстве еще и числами натуральными, то есть большими нуля. Хочу поделиться своим способом проверки на натуральные числа, может кому-то он покажется более удобным, чем его собственный.

Например возьмём такой адрес: http://example.com/price.php?product=859844&page=99.

Скрипт выводит список цен в магазинах для товара product, необязательный параметр page указывает номер страницы. Если page не указан, и url выглядит как http://example.com/price.php?product=859844, тогда выводим первую страницу.

До версии PHP 5.2.0 задачу можно было решить таким нехитрым образом.

// Функция получения параметра, являющегося натуральным числом
// $arr = массив параметров ($GET или $POST), $name = имя параметра,
// Функция возвращает значение параметра, либо $default если параметр отсутствует, либо некорректен

function get_param_nat($arr, $name, $default=null) {
	if (!isset($arr[$name]))
		return $default;

	// Проверяем очень нехитрым способом, конвертируем параметр в число, потом обратно в строку
	// Если все нормально, то полученная строка должна совпадать с исходным значеним параметра
	$val	= $arr[$name];
	$intval = intval($val);

	// В нагрузку проверяем, что число у нас получилось больше нуля
	if (strval($intval) !== $val || $intval < 1)
		return $default;

	return $intval;
}

// Проверяем параметр product
if (($product = get_param_nat($_GET, 'product')) === null)
	die('Product not found');

// Получаем номер страницы
$page = get_param_nat($_GET, 'page', 1);

Начиная в версии 5.2.0 в PHP появилась группа функций Filter: filter_var, filter_input, filter_var_array и несколько других. Функции могут проверять переменные на целые числа, числа с плавающей точкой, e‑mail, ip‑адреса, url и т.д., а также очищать строки в соответствии заданным параметрам.

Перепишем код с использование функции filter_input.

function get_param_nat($type, $name, $default=null) {
	$val = filter_input($type, FILTER_VALIDATE_INT, array('min_range' => 1, 'max_range' => PHP_INT_MAX ));
 
	// filter_input возвращает false, если фильтрация закончилась неудачей, или null, если переменная неопределена
	if ($val === null || $val === false)
		return $default;

	return $val;
}

// Проверяем параметр product
if (($product = get_param_nat(INPUT_GET, 'product')) === null)
	die('Product not found');

// Получаем номер страницы
$page = get_param_nat(INPUT_GET, 'page', 1);

Небольшое тестирование показало, что по скорости работы два варианта функции get_param_nat практически одинаковы, а в случае отсутствия параметра, например не будет указано page, первый вариант будет отрабатывать даже несколько быстрее.

Поэтому вам решать, что использовать. Я лично использую первую функцию, мне она как‑то ближе и понятнее.

Ну и небольшое лирическое отступление в конце. Во избежании дублирования страницы для поисковиков, например без page и с page=1, рекомендую в разделе head страницы указывать канонический url. Выглядеть это будет примерно так:

<head>
	...
	<link rel="canonical" href="/price.php?product=<?= $product ?><?= $page!=1 ? "&page=$page" : null ?>">
	...
</head>