Как передать массив в query string: полный разбор на PHP

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Зачем передавать массив в URL? И почему это не так просто, как кажется?

Представьте: вы пишете на PHP фильтр товаров для интернет-магазина. Пользователь выбирает несколько категорий, несколько цветов и диапазон цен. Как передать все эти данные на сервер через GET-запрос? Очевидное решение — ?category=1&category=2&category=3. Но сервер увидит только последнее значение, если не применить хитрость.

На Stack Overflow вопрос "How to pass an array within a query string?" собрал десятки тысяч просмотров. Разработчики спотыкаются на этом каждый день. Сегодня мы разберём эту тему от и до: покажу, как правильно передать массив через URL, как обработать его на сервере и какие подводные камни вас ждут.

Готовы превратить хаотичные GET-параметры в стройную структуру данных? Поехали!

Основы: как PHP обрабатывает query string

Когда вы отправляете GET-запрос, PHP автоматически заполняет суперглобальный массив $_GET. Если в URL есть ?name=John&age=25, то $_GET будет выглядеть так:

array(2) {
  ["name"] => string(4) "John"
  ["age"] => string(2) "25"
}

Но что, если мы попробуем передать несколько значений с одинаковым ключом? Напишем URL: ?color=red&color=green&color=blue. Сервер получит только color=blue. Остальные значения будут перезаписаны, потому что PHP не знает, что делать с дублирующимися ключами.

Здесь и приходит на помощь синтаксис квадратных скобок, который придумали именно для этой задачи.

Способ №1: синтаксис квадратных скобок (самый популярный)

Добавьте к имени параметра квадратные скобки: color[]. Когда PHP видит такой паттерн, он автоматически создаёт массив. Пример URL:

?color[]=red&color[]=green&color[]=blue

На сервере $_GET будет содержать:

array(1) {
  ["color"] => array(3) {
    [0] => string(3) "red"
    [1] => string(5) "green"
    [2] => string(4) "blue"
  }
}

А теперь пример кода на PHP, который это обрабатывает:

<?php
// URL: example.com?color[]=red&color[]=green&color[]=blue
if (isset($_GET['color']) && is_array($_GET['color'])) {
    echo "Выбранные цвета:<br>";
    foreach ($_GET['color'] as $index => $color) {
        echo ($index + 1) . ". " . htmlspecialchars($color) . "<br>";
    }
}
?>

Результат в браузере:

Выбранные цвета:
1. red
2. green
3. blue

Именованные ключи: когда порядок не важен

Иногда нужно передать ассоциативный массив (ключ → значение). Для этого используйте синтаксис key[] с указанием ключа:

?filter[category]=books&filter[price]=100&filter[in_stock]=1

PHP превратит это в:

array(1) {
  ["filter"] => array(3) {
    ["category"] => string(5) "books"
    ["price"] => string(3) "100"
    ["in_stock"] => string(1) "1"
  }
}

Обработка на сервере:

<?php
if (isset($_GET['filter'])) {
    $filter = $_GET['filter'];
    $query = "SELECT * FROM products WHERE 1=1";
    if (!empty($filter['category'])) {
        $query .= " AND category = '" . mysqli_real_escape_string($conn, $filter['category']) . "'";
    }
    if (!empty($filter['price'])) {
        $query .= " AND price <= " . (int)$filter['price'];
    }
    // ... остальные условия
}
?>

Способ №2: JSON в query string (продвинутый)

Если массив сложный (многоуровневый вложенный), синтаксис квадратных скобок становится громоздким. Альтернатива — передать JSON-строку в URL-кодированном виде.

Формируем URL на клиенте (JavaScript):

const data = {
    colors: ['red', 'green', 'blue'],
    sizes: ['S', 'M', 'L'],
    options: {
        gift_wrap: true,
        express_delivery: false
    }
};
const jsonStr = JSON.stringify(data);
const url = `/api/order?data=${encodeURIComponent(jsonStr)}`;
console.log(url); 
// Вывод: /api/order?data=%7B%22colors%22%3A%5B%22red%22%2C%22green%22%2C%22blue%22%5D%2C...%7D

Обрабатываем на PHP:

<?php
if (isset($_GET['data'])) {
    $json = urldecode($_GET['data']);
    $array = json_decode($json, true);
    
    if (json_last_error() === JSON_ERROR_NONE) {
        echo "Ваш заказ:<br>";
        echo "Цвета: " . implode(', ', $array['colors']) . "<br>";
        echo "Размеры: " . implode(', ', $array['sizes']) . "<br>";
        echo "Подарочная упаковка: " . ($array['options']['gift_wrap'] ? 'Да' : 'Нет');
    } else {
        echo "Ошибка в JSON: " . json_last_error_msg();
    }
}
?>

Способ №3: сериализация PHP (не рекомендуется)

Теоретически можно передать serialize() данные через URL, но это опасно. Сериализованные строки содержат двоеточия, точки с запятой и фигурные скобки, которые могут сломать URL. К тому же, если злоумышленник подставит вредоносную сериализованную строку, вы получите уязвимость PHP Object Injection.

Пример, как НЕ надо делать:

// КЛИЕНТ (формируем URL) - ПЛОХОЙ ПРИМЕР
$array = ['apple', 'banana', 'cherry'];
$serialized = serialize($array);
$url = "?data=" . urlencode($serialized);
// URL: ?data=a%3A3%3A%7Bi%3A0%3Bs%3A5%3A%22apple%22%3Bi%3A1%3Bs%3A6%3A%22banana%22%3Bi%3A2%3Bs%3A6%3A%22cherry%22%3B%7D

// СЕРВЕР (обработка) - ПЛОХОЙ ПРИМЕР
$data = unserialize($_GET['data']); // НИКОГДА ТАК НЕ ДЕЛАЙТЕ!

Если очень нужно передать сериализованные данные, используйте base64_encode поверх, но лучше просто выберите JSON.

Сравнение методов: что выбрать?

Блоги

Рекомендаций по книгам