Разноска многомерного массива с PHP и CURL

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

Я получаю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 не поддерживает многомерные массивы. Есть ли другой способ обойти это или я обречен?

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

Ответы на вопрос(8)

Решение Вопроса

а не передавать весь массив. Затем вы можете переопределить автоматически выбранный заголовок содержимого curl с помощью:

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

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

 mccbala16 сент. 2013 г., 10:10
Спасибо за упоминаниеhttp_build_query(), Это сработало как шарм для меня!
 machineaddict11 апр. 2014 г., 11:43
В моем случае это не работает. ОшибкаПредупреждение: отсутствует граница в POST-данных multipart / form-data в Unknown в строке 0, Что сработало для меняэта почта Христенко Юра
 David Hancock23 сент. 2010 г., 11:38
Спасибо! Я на самом деле не знал, что смогу сделать это. я добавилCURLOPT_HTTPHEADER и передал мой массив вhttp_build_query(), Работа выполнена!

когда дело касается HTTP-запросов. PHP (и, вероятно, другие серверные языки) имеет запутанную логику, которая может принимать данные запроса, которыевыглядит как массив (к нему) и собирает его вместе как массив при заполнении$_GET, $_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.

 David Hancock24 сент. 2010 г., 12:06
Спасибо за ваш ответ, он не совсем ответил на вопрос, но он был очень проницательным!

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

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

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

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

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

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

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);
 Ali Gangji11 апр. 2013 г., 19:31
Это отлично сработало для меня. Спасибо
 atfergus04 нояб. 2014 г., 19:18
Может кто-нибудь показать, как это использовать?
 Tominator13 мар. 2014 г., 09:27
Я считаю, что это лучшее решение, поскольку оно также легко обрабатывает загрузку файлов. Спасибо!
 fishbone10 февр. 2012 г., 20:08
очень полезно, спасибо! Вам это понадобится, если у вас есть вложенные массивы и вам нужно загружать файлы
 iautomation15 авг. 2015 г., 03:23
Если $ post еще не определен, вы можете просто добавитьreturn $new; в конце функции
 Nico18 авг. 2016 г., 15:33
Я изменил (в моем коде), чтобы вернуть$new массив. Есть ли причина, по которой вы используете&$new (по ссылке) и возвратvoid вместо того, чтобы просто вернуться$new?
$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);

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

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

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

Ваш ответ на вопрос