Действия с идентификатором в запросах PHP

Раздел: Веб-разработка на PHP -> Обработка запросов

Основные подходы к обработке id

Наиболее эффективное решение: комбинация фильтрации и подготовленных запросов

Для безопасной обработки параметра id в PHP рекомендуется использовать функцию filter_input с фильтром FILTER_VALIDATE_INT и подготовленные запросы PDO или MySQLi. Это защищает от SQL инъекций и некорректных данных.


<?
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($id === false || $id === null) {
    http_response_code(400);
    echo json_encode(['error' => 'Invalid or missing id']);
    exit;
}
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('SELECT * FROM articles WHERE id = :id');
$stmt->execute([':id' => $id]);
$article = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$article) {
    http_response_code(404);
    echo json_encode(['error' => 'Article not found']);
    exit;
}
echo json_encode($article);
?>

Этот подход гарантирует, что в запрос попадет только целое число, и все строки экранированы через prepared statement.

Как получить id из URL без дополнительных проверок?

Простой способ - использовать суперглобальный массив $_GET напрямую:

$id = $_GET['id'];

Однако при отсутствии параметра возникнет warning, а значение может быть произвольной строкой.

Проблемы:

  • Ошибка уровня E_WARNING при отсутствующем ключе.
  • SQL инъекция при прямом использовании в запросе.
  • XSS уязвимость при выводе без экранирования.

Как проверить существование и тип id с помощью isset и is_numeric?

Можно использовать комбинацию isset и is_numeric:

if (isset($_GET['id']) && is_numeric($_GET['id'])) {
    $id = $_GET['id'];
} else {
    // обработка ошибки
}

Этот метод отсекает случаи, когда id отсутствует или не является числом (включая числа в строковом формате).

Проблемы:

  • is_numeric допускает шестнадцатеричные строки (0x1A) и числа с плавающей точкой, что может быть нежелательно.
  • id все еще может содержать пробелы или другие символы, если число представлено строкой.

Как преобразовать id в целое число с помощью intval?

Приведение к целому числу отбрасывает все нечисловые символы:

$id = intval($_GET['id'] ?? 0);

Если id не передан, по умолчанию используется 0. Это позволяет избежать warning, но может привести к выполнению операций с id=0.

Проблемы:

  • Потеря информации: строка 'abc123' станет 0, хотя пользователь мог ошибиться.
  • Не проверяется факт наличия id, что может скрыть ошибку.
  • 0 может быть валидным id в некоторых системах, что затрудняет отладку.

Как использовать регулярное выражение для проверки id?

Регулярные выражения позволяют задать точный формат id, например, только цифры:

if (preg_match('/^\d+$/', $_GET['id'])) {
    $id = $_GET['id'];
}

Подходит для идентификаторов, состоящих только из цифр.

Проблемы:

  • Избыточная сложность для простых чисел.
  • Не учитывает большие числа, выходящие за границы int.

Как обработать id из POST запроса?

Для модификации данных id часто передается через POST:

$id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT);

Аналогично GET, но источник INPUT_POST.

Проблемы:

  • Необходимо различать методы запроса (GET для чтения, POST для создания/обновления).

Как обработать массив id (несколько идентификаторов)?

Иногда id передается как список через запятую или массив в URL:

// URL: /action.php?id=1,2,3
$ids = array_map('intval', explode(',', $_GET['id']));
// Или через множественные параметры: /action.php?id[]=1&id[]=2
$ids = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, ['flags' => FILTER_REQUIRE_ARRAY]);

Это удобно для массовых операций.

Проблемы:

  • Необходимость дополнительной валидации каждого элемента.
  • Возможность SQL инъекции при неправильной обработке массива.

Как использовать filter_var для уже полученного значения?

Можно сначала проверить isset, а затем применить filter_var:

$id = isset($_GET['id']) ? filter_var($_GET['id'], FILTER_VALIDATE_INT) : null;

Похоже на filter_input, но не использует второй параметр ввода.

Проблемы:

  • Не проверяет наличие ключа в источнике, если он не задан.

Как обработать id в RESTful маршрутах (ЧПУ)?

При использовании чистых URL, id извлекается из сегмента пути:

// URL: /articles/123
$url = $_SERVER['REQUEST_URI'];
preg_match('/\/articles\/(\d+)/', $url, $matches);
$id = $matches[1] ?? null;

Это требует парсинга URL.

Проблемы:

  • Необходимость написания роутера.
  • Сложность с разными методами.

Расширенные примеры использования параметра id

Пример 1: Полный RESTful скрипт с PDO и валидацией

Пример

<?
header('Content-Type: application/json; charset=utf-8');

$method = $_SERVER['REQUEST_METHOD'];
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);

if ($id === false || $id === null) {
    http_response_code(400);
    echo json_encode(['error' => 'Неверный или отсутствующий id']);
    exit;
}

try {
    $pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]);

    if ($method === 'GET') {
        $stmt = $pdo->prepare('SELECT * FROM articles WHERE id = :id');
        $stmt->execute([':id' => $id]);
        $article = $stmt->fetch();
        if (!$article) {
            http_response_code(404);
            echo json_encode(['error' => 'Статья не найдена']);
            exit;
        }
        echo json_encode($article);
    } elseif ($method === 'DELETE') {
        $stmt = $pdo->prepare('DELETE FROM articles WHERE id = :id');
        $stmt->execute([':id' => $id]);
        if ($stmt->rowCount() === 0) {
            http_response_code(404);
            echo json_encode(['error' => 'Статья не найдена']);
            exit;
        }
        echo json_encode(['success' => true, 'deleted_id' => $id]);
    } else {
        http_response_code(405);
        echo json_encode(['error' => 'Метод не поддерживается']);
    }
} catch (Exception $e) {
    http_response_code(500);
    echo json_encode(['error' => 'Внутренняя ошибка сервера']);
}
?>

Результат выполнения GET запроса к /action.php?id=1:

{
    "id": 1,
    "title": "Основы PHP",
    "content": "PHP - скриптовый язык..."
}

Пример 2: Извлечение id из пути с помощью parse_url

Пример

$url = $_SERVER['REQUEST_URI'];
$path = parse_url($url, PHP_URL_PATH);
// Ожидаем формат /api/articles/123
if (preg_match('#/api/articles/(\d+)#', $path, $matches)) {
    $id = (int) $matches[1];
} else {
    // Ошибка маршрута
    http_response_code(404);
    exit;
}

Пример 3: Обработка массива id через GET с разделителем запятая

Пример

$idString = filter_input(INPUT_GET, 'ids', FILTER_SANITIZE_STRING);
if ($idString) {
    $ids = array_map('intval', explode(',', $idString));
    $ids = array_filter($ids, fn($v) => $v > 0); // удаляем нули
    if (empty($ids)) {
        http_response_code(400);
        echo json_encode(['error' => 'Нет корректных id']);
        exit;
    }
    // Строим запрос с плейсхолдерами
    $placeholders = implode(',', array_fill(0, count($ids), '?'));
    $stmt = $pdo->prepare("DELETE FROM articles WHERE id IN ($placeholders)");
    $stmt->execute($ids);
    echo json_encode(['deleted' => $stmt->rowCount()]);
}

Результат для /action.php?ids=1,2,3:

{"deleted": 3}

Пример 4: Валидация UUID в качестве id

Пример

function validateUuid(string $uuid): bool {
    return preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $uuid) === 1;
}

$id = $_GET['uuid'] ?? '';
if (!validateUuid($id)) {
    http_response_code(400);
    echo json_encode(['error' => 'Неверный формат UUID']);
    exit;
}
// Использование в запросе
$stmt = $pdo->prepare('SELECT * FROM users WHERE uuid = :uuid');
$stmt->execute([':uuid' => $id]);

Пример 5: Обработка id с учетом прав доступа (сессия)

Пример

session_start();
if (!isset($_SESSION['user_id'])) {
    http_response_code(401);
    exit;
}
$targetId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
// Пользователь может редактировать только свои записи
$stmt = $pdo->prepare('SELECT user_id FROM articles WHERE id = :id');
$stmt->execute([':id' => $targetId]);
$article = $stmt->fetch();
if (!$article || $article['user_id'] !== $_SESSION['user_id']) {
    http_response_code(403);
    echo json_encode(['error' => 'Доступ запрещен']);
    exit;
}
// продолжение операции

Пример 6: Использование filter_input_array для всех параметров

Пример

$args = [
    'id'    => FILTER_VALIDATE_INT,
    'action' => FILTER_SANITIZE_STRING
];
$inputs = filter_input_array(INPUT_GET, $args);
if ($inputs === null || $inputs['id'] === false) {
    // ошибка валидации
}
$id = $inputs['id'];
$action = $inputs['action'];

Результат filter_input_array для URL ?id=123&action=view:

Array
(
    [id] => 123
    [action] => "view"
)

Действие с параметром id в PHP - comments

En
Action php id (php)