Обработка ввода в PHP: создание собственного класса и альтернативные методы
Основные подходы к обработке ввода в PHP
Наиболее эффективное решение: универсальный класс Input
Данный класс инкапсулирует получение данных из различных суперглобальных массивов ($_GET, $_POST, $_REQUEST), применяет фильтрацию, валидацию и преобразование типов. Основные возможности:
- Единый интерфейс для доступа к данным запроса.
- Автоматическая фильтрация с помощью встроенных фильтров PHP (
FILTER_SANITIZE_STRING,FILTER_VALIDATE_INTи др.). - Поддержка значений по умолчанию.
- Удобная работа с вложенными массивами (например,
$_POST['user']['name']).
class Input {
private $source;
public function __construct($source = null) {
$this->source = $source ?? $_REQUEST;
}
public function get($key, $default = null, $filter = FILTER_DEFAULT) {
if (strpos($key, '.') !== false) {
$keys = explode('.', $key);
$value = $this->source;
foreach ($keys as $k) {
if (!isset($value[$k])) {
return $default;
}
$value = $value[$k];
}
return filter_var($value, $filter) ?: $default;
}
return isset($this->source[$key]) ? filter_var($this->source[$key], $filter) : $default;
}
public function has($key) {
if (strpos($key, '.') !== false) {
$keys = explode('.', $key);
$value = $this->source;
foreach ($keys as $k) {
if (!isset($value[$k])) {
return false;
}
$value = $value[$k];
}
return true;
}
return isset($this->source[$key]);
}
public function all() {
return $this->source;
}
public function only(array $keys) {
$result = [];
foreach ($keys as $key) {
$result[$key] = $this->get($key);
}
return $result;
}
}
Input class php (класс для обработки ввода в php)
Пример использования:
$input = new Input();
$name = $input->get('name', 'Гость', FILTER_SANITIZE_STRING);
$age = $input->get('age', 0, FILTER_VALIDATE_INT);
if ($input->has('user.email')) {
$email = $input->get('user.email', null, FILTER_VALIDATE_EMAIL);
}
Типичные проблемы и решения:
- Проблема: небезопасное использование
$_REQUEST(может содержать куки). Решение: передавать конкретный источник ($_POST,$_GET) в конструктор. - Проблема: фильтр
FILTER_DEFAULTне удаляет теги. Решение: использоватьFILTER_SANITIZE_STRINGилиhtmlspecialcharsпосле получения. - Проблема: работа с массивами может вернуть неверный тип после фильтра. Решение: проверять тип результата и приводить к нужному.
Как обработать ввод без создания собственного класса: функция filter_input?
В PHP есть встроенные функции filter_input() и filter_var(), которые позволяют получать и фильтровать данные напрямую.
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
$age = filter_input(INPUT_GET, 'age', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 120]]);
Цель: быстрая обработка единичных полей без создания классов. Подходит для простых скриптов.
Проблема: filter_input не поддерживает точечную нотацию для вложенных массивов. Для массивов (например, $_POST['user']) нужно использовать filter_var после ручного извлечения.
Как обрабатывать ввод вручную через суперглобальные массивы?
Прямой доступ к $_GET, $_POST, $_SERVER без дополнительных абстракций. Пример:
if (isset($_POST['email'])) {
$email = trim($_POST['email']);
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
// валидный email
}
}
Цель: полный контроль над обработкой, отсутствие накладных расходов. Подходит для небольших проектов.
Проблема: дублирование кода, риск забыть фильтрацию, сложность поддержки при росте проекта. Типичная ошибка: использование $_REQUEST без проверки источника (может привести к подмене данных).
Как использовать готовые библиотеки для обработки ввода (например, Symfony HttpFoundation)?
Компонент symfony/http-foundation предоставляет объекты Request и ParameterBag для работы с входными данными.
use Symfony\Component\HttpFoundation\Request;
$request = Request::createFromGlobals();
$name = $request->request->get('name', 'default');
$age = $request->query->getInt('age', 0);
Цель: использование проверенного решения с расширенной функциональностью (загрузка файлов, сессии, куки). Подходит для фреймворков и крупных проектов.
Проблема: избыточность для простых скриптов, зависимость от внешнего пакета, необходимость автозагрузки.
Расширенные примеры обработки ввода в PHP
Пример 1: обработка файлов через класс Input
Добавим в класс метод file() для работы с $_FILES.
class Input {
// ... остальные методы
public function file($key) {
if (isset($_FILES[$key]) && $_FILES[$key]['error'] === UPLOAD_ERR_OK) {
return $_FILES[$key];
}
return null;
}
}
$input = new Input();
$uploadedFile = $input->file('avatar');
if ($uploadedFile) {
$name = $uploadedFile['name'];
$tmpPath = $uploadedFile['tmp_name'];
move_uploaded_file($tmpPath, 'uploads/' . basename($name));
}
// Результат: файл перемещен в папку uploads (если загрузка прошла успешно). // В случае ошибки возвращается null.
Пример 2: цепочечная фильтрация и валидация
Добавим методы для последовательной обработки: сначала санитизация, потом валидация.
class Input {
// ...
public function sanitize($key, $filter = FILTER_SANITIZE_STRING) {
$value = $this->get($key, null, $filter);
return $value;
}
public function validate($key, $filter, $options = []) {
$value = $this->get($key);
if ($value === null) return false;
return filter_var($value, $filter, ['options' => $options]) !== false;
}
}
$input = new Input($_POST);
$email = $input->sanitize('email', FILTER_SANITIZE_EMAIL);
if ($input->validate('email', FILTER_VALIDATE_EMAIL)) {
echo "Email корректен: $email";
} else {
echo "Некорректный email";
}
// Ввод: <script>alert('xss')</script>user@example.com
// После санитизации: user@example.com (теги удалены)
// Валидация проходит, вывод: Email корректен: user@example.com
Пример 3: извлечение вложенных данных из JSON запроса
Для REST API данные часто приходят в формате JSON. Адаптируем класс для работы с php://input.
class JsonInput extends Input {
public function __construct() {
$raw = file_get_contents('php://input');
$data = json_decode($raw, true) ?? [];
parent::__construct($data);
}
}
$input = new JsonInput();
$userId = $input->get('user.id', 0, FILTER_VALIDATE_INT);
$action = $input->get('meta.action', 'view');
// Тело запроса: {"user":{"id":42},"meta":{"action":"delete"}}
// Результат: $userId = 42, $action = "delete"
Пример 4: использование кастомных фильтров с callback
Создадим метод, применяющий произвольную функцию фильтрации.
class Input {
// ...
public function custom($key, callable $callback, $default = null) {
$value = $this->get($key);
return $value !== null ? $callback($value) : $default;
}
}
$input = new Input($_POST);
$trimmed = $input->custom('name', function($v) {
return trim(strip_tags($v));
});
// или с использованием стрелочной функции (PHP 7.4+)
$trimmed = $input->custom('name', fn($v) => trim(strip_tags($v)));
// Ввод: " <b>Привет</b> " // Результат: "Привет" (пробелы и теги удалены)
Пример 5: получение всех данных с автоматической фильтрацией
Метод allFiltered() применяет фильтр ко всем элементам массива.
class Input {
// ...
public function allFiltered($filter = FILTER_SANITIZE_STRING) {
return filter_var_array($this->source, $filter);
}
}
$input = new Input($_GET);
$safeParams = $input->allFiltered(FILTER_SANITIZE_ENCODED);
print_r($safeParams);
// Входной массив: ['name' => '', 'id' => '123'] // Результат: Array ( [name] => %3Ctest%3E [id] => 123 )