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

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

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

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

  • No related posts
  • 8 responses to “Проводка многомерного массива с PHP и CURL”

      Алекс Хоански said:

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

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

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

      Marc B said:

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

      Luxian said:
       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); } else { 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); 
      Marc B said:

      Самое простое решение:

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

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

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

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

      Гайан Хьюа said:

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

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

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

      Luxian said:

      Параметр 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))); 
      Алекс Хоански said:

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

       <?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; } else { <?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' ) 
      Гайан Хьюа said:
       $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 is the Best Programming Language in the world.