Intereting Posts
Проверка пользовательского поля vTiger beforesave Внедрить карту в javascript, которая поддерживает методы объектов как отображаемые функции? добавить день к текущей дате ftp_get (): Не удается открыть файл1: нет такого файла или каталога в Разбор массива JSON для сервера с Swift 3.0 Вызов статического метода из имени строки в PHP Должен ли я обрезать расшифрованную строку после mcrypt_decrypt? Объектно-ориентированное программирование -> Оператор Как я могу проверить знак плюса с помощью регулярных выражений? Правильно отформатированный оператор даты date MySQL возвращает все 0 CakePHP помню меня с Auth php – date_default_timezone_set не работает, но ini_set 'date.timezone' делает. Зачем? Уникальный хэш изображения, который не изменяется, если обновлена ​​информация EXIF Как разделить кеш APC между несколькими процессами PHP при работе в FastCGI? PHP-скрипт не может выводиться из сценария Python

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Параметр 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))); 
 $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);