0

Отправка многомерного массива с помощью PHP и CURL

8

Я испытываю проблемы с отправкой данных формы через CURL на PHP-скрипт, расположенный на другом хосте.

Я получаю ошибку Преобразование массива в строку.

Вот print_r массива, который я отправляю:

Array
(
    [name] => Array
    (
        [0] => Jason
        [1] => Mary
        [2] => Lucy
    )
    [id] => 12
    [status] => local
    [file] => @/test.txt
)

Ошибка возникает на этой строке:

curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post);

Третий аргумент обязательно должен быть массивом, так как мне нужно, чтобы заголовок Content-Type был установлен на multipart/form-data, поскольку я отправляю файл через этот же массив. Поэтому я не могу преобразовать массив в строку запроса или использовать http_build_query().

Также у меня нет доступа к коду на принимающем хосте, поэтому я не могу сериализовать и десериализовать массив.

Я предполагаю, что значение ключа name, будучи массивом, является причиной этой ошибки. Я также предполагаю, что CURLOPT_POSTFIELDS не поддерживает многомерные массивы. Есть ли какие-либо обходные пути для этой проблемы, или мне не повезло?

Заранее спасибо!

5 ответ(ов)

0

Функция http_build_query_for_curl предназначена для преобразования многомерного массива или объекта в ассоциативный массив, который можно использовать для отправки данных через cURL в формате application/x-www-form-urlencoded. Вот подробное объяснение кода:

function http_build_query_for_curl( $arrays, &$new = array(), $prefix = null ) {
    // Если входные данные - объект, преобразуем его в массив
    if ( is_object( $arrays ) ) {
        $arrays = get_object_vars( $arrays );
    }

    // Проходим по каждому элементу массива
    foreach ( $arrays AS $key => $value ) {
        // Формируем ключ с учетом префикса, если он задан
        $k = isset( $prefix ) ? $prefix . '[' . $key . ']' : $key;
        // Если значение является массивом или объектом, рекурсивно вызываем функцию
        if ( is_array( $value ) OR is_object( $value )  ) {
            http_build_query_for_curl( $value, $new, $k );
        } else {
            // Если значение - скаляр, добавляем его в результирующий массив
            $new[$k] = $value;
        }
    }
}

// Пример данных
$arrays = array(
    'name' => array(
        'first' => array(
            'Natali', 'Yura'
        )
    )
);

// Инициализируем пустой массив для результата
$post = array();

// вызываем функцию
http_build_query_for_curl( $arrays, $post );

// Выводим результирующий массив
print_r($post);

Объяснение работы функции:

  1. Преобразование объекта в массив: В начале функции проверяется, является ли $arrays объектом. Если это так, он преобразуется в массив с помощью get_object_vars().

  2. Итерация по массиву: Цикл foreach проходит по каждому элементу массива или объекта.

  3. Формирование ключей: Используется префикс для формирования ключей, что позволяет поддерживать вложенную структуру данных. Например, если у вас есть массив с вложенными массивами, вы получите ключи в формате name[first][0].

  4. Рекурсивный вызов: Если значение является массивом или объектом, функция будет вызываться рекурсивно, что позволяет обработать любое количество уровней вложенности.

  5. Заполнение результирующего массива: Если значение является скаляром (например, строка или число), оно добавляется в результирующий массив $new.

Результат

При выполнении кода с указанным массивом, вы получите структурированный массив $post, который можно использовать для передачи данных через cURL.

0

Концепция массива на самом деле не существует в контексте HTTP-запросов. PHP (предположительно, как и другие серверные языки) имеет встроенную логику, которая позволяет принимать данные запроса, которые выглядят как массив (для него), и преобразует их в массив, заполняя такие суперглобальные массивы, как $_GET, $_POST и так далее.

Например, когда вы отправляете массив из формы методом POST, элементы формы часто выглядят примерно так:

<form ...>
  <input name="my_array[0]">
  <input name="my_array[1]">
  <input name="my_array[2]">
</form>

или даже так:

<form ...>
  <input name="my_array[]">
  <input name="my_array[]">
  <input name="my_array[]">
</form>

Хотя PHP знает, что делать с этими данными, когда он их получает (т.е. строить массив), для HTML и HTTP это всего лишь три независимых поля ввода, которые случайно имеют похожие (или даже одинаковые, хотя это не является технически корректным HTML) имена.

Чтобы сделать обратное в вашем запросе cURL, вам нужно разложить ваш массив на строковые представления его ключей. Например, для вашего массива name вы можете сделать что-то вроде этого:

foreach ($post['name'] as $id => $name) {
  $post['name[' . $id . ']'] = $name;
}
unset($post['name']);

В результате ваш массив $post будет выглядеть так:

Array
(
    [name[0]] => Jason
    [name[1]] => Mary
    [name[2]] => Lucy
    [id] => 12
    [status] => local
    [file] => @/test.txt
)

Таким образом, каждый ключ в массиве, который вы отправляете, будет скалярным значением, что и ожидает cURL, а массив будет представлен так, как это необходимо для HTTP.

0

Вам нужно будет вручную сформировать строку POST, а не передавать целый массив. Затем вы можете переопределить автоматически выбираемый заголовок контента cURL с помощью:

curl_setopt($c, CURLOPT_HTTPHEADER, array("Content-type: multipart/form-data"));

Сериализация в JSON была бы проще, но, как вы сами говорите, у вас нет контроля над принимающей стороной, поэтому придется немного повозиться.

0

Самое простое решение — это сделать следующее:

$array = urldecode(http_build_query($array));

Ниже приведен пример кода, где это используется на практике:

https://gist.github.com/gayanhewa/142c48162f72e68a4a23

Когда у вас есть вложенный раздел $params в приведенном выше примере, он будет правильно обработан и подготовлен для отправки через curl.

0

Опция cURL CURLOPT_POSTFIELDS принимает в качестве аргумента либо строку, либо простой массив, но не поддерживает вложенные массивы. Если вы попытаетесь передать вложенный массив, то получите ошибку Array to string conversion.

Однако функция http_build_query() может обрабатывать вложенные массивы, поэтому вы можете использовать её для преобразования массива $_POST в строку и затем отправить эту строку. То есть, если у вас есть следующий код:

curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);

замените его на:

curl_setopt($ch, CURLOPT_POSTFIELDS, urldecode(http_build_query($_POST)));

Таким образом, ваша проблема будет решена, и данные будут корректно отправлены.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь