У меня возникают проблемы с отправкой многомерного массива с загрузкой файлов с использованием PHP и CURL.
Например, многомерный массив:
$post['question'] = 'Are you human?'; $post['answers'] = array('yes', 'no', 'maybe'); $post['file'] = '@/path/to/file'; // Output: Array( 'question' => Are you human?, 'answers' => Array( '0' => yes, '1' => no, '2' => maybe ), 'file' => @/path/to/file )
Есть несколько причин, почему это не сработает, если вы просто попытаетесь опубликовать это с помощью CURLOPT_POSTFIELDS в CURL следующим образом:
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://example.com'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); $response = curl_exec($ch);
Прежде всего официальное описание PHP CURLOPT_POSTFIELDS гласит:
Полные данные для отправки в HTTP-режиме «POST». Чтобы опубликовать файл, добавьте имя файла с помощью @ и используйте полный путь. Это может быть либо передано как строка с urlencoded, как «para1 = val1 & para2 = val2 & …», или как массив с именем поля в качестве ключа и данных поля как значение. Если значением является массив, заголовок Content-Type будет установлен в multipart / form-data.
- PHP: Возможно автоматическое получение всех данных POSTed?
- Как я могу переносить данные POST на новую страницу на PHP без формы?
- PHP использует метод GET
- Почему запросы отправки php5-fpm медленны, в то время как тот же php-cli-код / консольный завиток работает очень быстро?
- Запросить сущность слишком большого PHP
Похоже, вы можете передать любой тип массива POSTFIELDS правильно? Неправильно. POSTFIELDS принимает только нескалярные значения и будет подавлять с ошибкой Array to string conversion
при передаче многомерных массивов. Таким образом, единственный другой вариант, который у вас есть, – это http_build_query()
ваш массив, чтобы иметь возможность передавать многомерные массивы, которые не задыхаются.
Но … как вы можете прочитать в примечании на странице PHP:
Примечание. Передача массива в CURLOPT_POSTFIELDS будет кодировать данные как multipart / form-data, в то время как передача строки с кодировкой URL будет кодировать данные как application / x-www-form-urlencoded.
Сообщение не будет закодировано в multipart / form-data, если вы передадите строку urlencoded в POSTFIELDS, что приведет к сбою загрузки файла.
Таким образом, представляется невозможным комбинировать два с CURL, хотя это не было бы проблемой, если бы вы использовали обычную HTML-форму.
Мой вопрос: можно ли обойти эту странную причуду CURL, чтобы иметь возможность отправлять многомерные массивы и загружать файлы?
multipart / form-data не поддерживает вложенные значения. И я не верю, что CURL тоже это сделает.
Я подозреваю, что принимающая сторона вашего запроса также является скриптом PHP. Если, то вы можете представить вложенный массив как одно из значений, если вы просто подготовили его самостоятельно:
$post['answers[0]'] = "yes"; $post['answers[1]'] = "no"; $post['answers[2]'] = "maybe";
Теоретически вам просто нужны 'answers[]'
без индекса, но это перепишет предыдущее значение и, следовательно, будет работать только с http_build_query.
Я не уверен, есть ли какая-либо HTTP-библиотека в PHP, которая может сделать это автоматически.
Другой способ выполнить первый ответ:
foreach( array("yes","no","maybe") as $key=>$value ) $post["answers[$key]"] = $value;
Попробуйте эту рекурсивную функцию.
https://gist.github.com/yisraeldov/ec29d520062575c204be7ab71d3ecd2f
<?php function build_post_fields( $data,$existingKeys='',&$returnArray=[]){ if(($data instanceof CURLFile) or !(is_array($data) or is_object($data))){ $returnArray[$existingKeys]=$data; return $returnArray; } else{ foreach ($data as $key => $item) { build_post_fields($item,$existingKeys?$existingKeys."[$key]":$key,$returnArray); } return $returnArray; } }
И вы можете использовать его так.
curl_setopt($ch, CURLOPT_POSTFIELDS, build_post_fields($postfields));