Зачем передавать массив в 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.