curl формат POST для CURLOPT_POSTFIELDS

99

Когда я использую curlчерез POSTи устанавливаю, CURLOPT_POSTFIELDнужно ли мне использовать urlencodeкакой-либо специальный формат?

например: если я хочу опубликовать 2 поля, первое и последнее:

first=John&last=Smith

какой точный код / ​​формат следует использовать с curl?

$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$reply=curl_exec($ch);
curl_close($ch);
Кен
источник

Ответы:

100

Если вы отправляете строку, urlencode () ее. В противном случае, если массив, он должен быть парным ключом => значением, а Content-typeзаголовок автоматически устанавливается на multipart/form-data.

Кроме того, вам не нужно создавать дополнительные функции для построения запроса для ваших массивов, они у вас уже есть:

$query = http_build_query($data, '', '&');
Кодеарт
источник
13
Вы можете просто использовать, http_build_query($data)поскольку &это разделитель по умолчанию.
Обнуление
6
Конечно, вы можете их пропустить. Это иллюстрирует два других аргумента, которые вы можете (или не можете) изменить (например, разделитель по умолчанию) в соответствии с вашими конкретными потребностями.
kodeart
62

РЕДАКТИРОВАТЬ : Начиная с php5 и выше http_build_queryрекомендуется использовать:

string http_build_query ( mixed $query_data [, string $numeric_prefix [, 
                          string $arg_separator [, int $enc_type = PHP_QUERY_RFC1738 ]]] )

Простой пример из мануала:

<?php
$data = array('foo'=>'bar',
              'baz'=>'boom',
              'cow'=>'milk',
              'php'=>'hypertext processor');

echo http_build_query($data) . "\n";

/* output:
foo=bar&baz=boom&cow=milk&php=hypertext+processor
*/

?>

перед php5:

Из руководства :

CURLOPT_POSTFIELDS

Полные данные для публикации в операции HTTP POST. Чтобы опубликовать файл, добавьте к имени файла @ и используйте полный путь. Тип файла можно указать явно, указав после имени файла тип в формате '; type = mimetype'. Этот параметр может быть передан как строка с URL-кодом, например 'para1 = val1 & para2 = val2 & ...', или как массив с именем поля в качестве ключа и данными поля как значением. Если значение является массивом, заголовок Content-Type будет установлен в multipart / form-data. Начиная с PHP 5.2.0, файлы, которые передаются в эту опцию с префиксом @, для работы должны быть в форме массива.

Так что что-то вроде этого должно работать отлично (с параметрами, переданными в ассоциативном массиве):

function preparePostFields($array) {
  $params = array();

  foreach ($array as $key => $value) {
    $params[] = $key . '=' . urlencode($value);
  }

  return implode('&', $params);
}
Чехнология
источник
11
Зачем передавать строку, если можно передать массив ...?
ThiefMaster 07
1
Я думаю, что $ key тоже нужно закодировать, на всякий случай, если у вас есть «имя и фамилия» и т. Д. Особенно, если данные предоставлены конечным пользователем
Мариус Балчитис
2
@barius, я с тобой согласен. И я думаю, что http_build_query () на самом деле лучше, чем функция, определенная выше.
Skyfree
1
@skyfree Согласен! Эта функция была добавлена ​​в php5, хотя в 2011 году
она
1
зачем нужен http_build_query, если можно просто передать массив?
Offenso
39

Ни в коем случае не передавайте строку!

Вы можете передать массив и позволить php / curl выполнять грязную работу по кодированию и т. Д.

ThiefMaster
источник
16
Передача массива будет иметь другой Content-type, чем строка, поэтому для этого есть веская причина. Мне потребовалось время, чтобы понять это.
Thomas Vander Stichele
Я понятия не имею, почему, но я обнаружил, что на моем компьютере win dev передача массива занимает примерно секунду больше (1,029 с с использованием массива против 0,016 с http_build_query()с использованием того же массива)
Кратенко
2
Вложенные массивы работать не будут. cURL попытается преобразовать их в строку, после чего последует уведомление о преобразовании массива PHP в строку
7ochem
5

Согласно руководству по PHP, данные, передаваемые в cURL в виде строки, должны быть закодированы в URL. Смотрите страницу для curl_setopt () и ищите CURLOPT_POSTFIELDS.

Сюрреалистические мечты
источник
4

В CURLOPT_POSTFIELDSсамом деле, параметры могут быть переданы как строка с URL-кодом, например, para1=val1&para2=val2&..или как массив с именем поля в качестве ключа и данными поля в качестве значения.

Попробуйте следующий формат:

$data = json_encode(array(
"first"  => "John",
"last" => "Smith"
));

$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$output = curl_exec($ch);
curl_close($ch);
Шраддха Ваднере
источник
2
Привет, Шраддха, json_encode()даст вам что-то действительно отличное от действительной строки параметров в виде first=John&last=Smith. json_encode()выведет: {"first":"John","last":"Smith"}который затем станет необработанным телом вашего запроса POST.
7ochem 05
1
Чтобы добавить к комментарию @ 7ochem: если получатель не ожидает единственный параметр, содержащий строку в кодировке json , вместо json_encode(...)do http_build_query(...). Это создаст ожидаемую «строку в кодировке url», содержащую параметры, разделенные «&».
ToolmakerSteve
4

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

Если мы возьмем вложенный массив, ['a' => 1, 'b' => [2, 3, 4]]тогда он должен быть параметризован как a=1&b[]=2&b[]=3&b[]=4( [и ]будет / должно быть закодировано в URL). Он будет автоматически преобразован обратно во вложенный массив на другом конце (при условии, что здесь другой конец также PHP).

Это будет работать:

var_dump(http_build_query(['a' => 1, 'b' => [2, 3, 4]]));
// output: string(36) "a=1&b%5B0%5D=2&b%5B1%5D=3&b%5B2%5D=4"

Это не сработает:

curl_setopt($ch, CURLOPT_POSTFIELDS, ['a' => 1, 'b' => [2, 3, 4]]);

Это даст вам уведомление. Выполнение кода продолжится, и ваша конечная точка получит параметр в bвиде строки "Array":

Уведомление PHP: преобразование массива в строку в ... в строке ...

7очем
источник
3

Это зависит от content-type

url-кодированные или multipart / form-data

Чтобы отправлять данные стандартным способом, как браузер с формой, просто передайте ассоциативный массив . Как указано в руководстве PHP:

Этот параметр может быть передан как строка с URL-кодом, например 'para1 = val1 & para2 = val2 & ...', или как массив с именем поля в качестве ключа и данными поля в качестве значения. Если значение является массивом, заголовок Content-Type будет установлен в multipart / form-data.

Кодировка JSON

Тем не менее, при взаимодействии с JSON API содержимое должно быть в кодировке JSON, чтобы API мог понимать наши данные POST.

В таких случаях контент должен быть явно закодирован как JSON:

CURLOPT_POSTFIELDS => json_encode(['param1' => $param1, 'param2' => $param2]),

При обмене данными в формате JSON, мы также обычно устанавливают acceptи content-typeзаголовки соответственно:

CURLOPT_HTTPHEADER => [
    'accept: application/json',
    'content-type: application/json'
]
Бузут
источник
2

для вложенных массивов вы можете использовать:

$data = [
  'name[0]' = 'value 1',
  'name[1]' = 'value 2',
  'name[2]' = 'value 3',
  'id' = 'value 4',
  ....
];
Максим Рысевец
источник
0

Интересно способ Postman выполняет POST как полную операцию GET с двумя дополнительными опциями:

curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, '');

Просто другой способ, и он очень хорошо работает.

Klompenrunner
источник
-3

Я тоже искал этот ответ целую вечность. Я обнаружил, что все, что вам нужно сделать, это объединить URL-адрес ('?' После имени файла и расширения) со строкой запроса в кодировке URL. Даже не похоже, что вам нужно устанавливать параметры POST cURL. См. Пример подделки ниже:

//create URL
$exampleURL = 'http://www.example.com/example.php?';

// create curl resource
$ch = curl_init(); 

// build URL-encoded query string
$data = http_build_query(
    array('first' => 'John', 'last' => 'Smith', '&'); // set url
curl_setopt($ch, CURLOPT_URL, $exampleURL . $data); 

// return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 

// $output contains the output string
$output = curl_exec($ch); 

// close curl resource to free up system resources <br/>
curl_close($ch);

Вы также можете использовать file_get_contents():

// read entire webpage file into a string
$output = file_get_contents($exampleURL . $data);
user2512571
источник
9
Похоже, вы выполняете GET, а не POST.
grandnasty