Подтвердить что ты не робот

Проводка многомерного массива с PHP и CURL

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

Я получаю ошибку Array to string conversion

Это 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().

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

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

Спасибо заранее!

4b9b3361

Ответ 1

Вам нужно будет построить строку POST вручную, а не передавать весь массив. Затем вы можете переопределить curl auto-selected content header:

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

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

Ответ 2

Концепция массива на самом деле не существует, когда дело доходит до 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.

Ответ 3

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'
        )
    )
);


http_build_query_for_curl( $arrays, $post );

print_r($post);

Ответ 4

Самое простое решение - сделать:

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

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

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

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

Ответ 5

Сначала я хотел бы поблагодарить Daniel Vandersluis за его проницательный ответ. Основываясь на его вводе, я придумал это, чтобы исправить проблему из оригинального вопроса:

<?php

function curl_postfields_flatten($data, $prefix = '') {
  if (!is_array($data)) {
    return $data; // in case someone sends an url-encoded string by mistake
  }

  $output = array();
  foreach($data as $key => $value) {
    $final_key = $prefix ? "{$prefix}[{$key}]" : $key;
    if (is_array($value)) {
      // @todo: handle name collision here if needed
      $output += curl_postfields_flatten($value, $final_key);
    }
    else {
      $output[$final_key] = $value;
    }
  }
  return $output;
}

Использование должно выглядеть следующим образом:

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

Эта функция преобразует массивы следующим образом:

array(
  'a' => 'a',
  'b' => array(
    'c' => array(
      'd' => 'd',
      'e' => array(
        'f' => 'f',
      ),
    ),
  ),
);

В это:

array(
  'a' => 'a',
  'b[c][d]' => 'd',
  'b[c][e][f]' => 'f',
)

Он не обрабатывает случаи со смешанным форматом, когда есть столкновение клавиш, подобное этому:

array(
 'b[c]' => '1',
 'b' => array(
   'c' => '2', 
  ),
);

Выход будет содержать только первое значение для этого ключа

array(
 'b[c]' => '1'
)

Ответ 6

Я думаю, вам нужно передать параметры в виде строки:

curl_setopt($this->ch, CURLOPT_POSTFIELDS, 'name[]=Jason&name[]=Mary&name[]=Lucy...');

Затем вы можете настроить заголовок вручную с помощью CURLOPT_HTTPHEADER.

Ответ 7

Опция 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)));

Ответ 8

$post = "ac=on&p=1&pr[]=0&pr[]=1&a[]=3&a[]=4&pl=on&sp[]=3&ct[]=3&s=1&o=0&pp=3&sortBy=date";
parse_str($post,$fields); 

$url = 'http://example.com/';


//open connection
$ch = curl_init();

//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);

//execute post
$result = curl_exec($ch);

//close connection
curl_close($ch);