скрутити формат 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 () - це. В іншому випадку, якщо масив, він повинен бути key => значенням в парі, і Content-typeзаголовок автоматично встановлюється на multipart/form-data.

Крім того, вам не потрібно створювати додаткові функції для складання запиту для своїх масивів, у вас уже є це:

$query = http_build_query($data, '', '&');

13
Ви можете просто використовувати, http_build_query($data)оскільки &це роздільник за замовчуванням.
знесення нанівець

6
Звичайно, ви можете їх пропустити. Це для ілюстрації двох інших аргументів, які ви можете (або не можете) змінити (наприклад, роздільник за замовчуванням) відповідно до ваших конкретних потреб.
kodeart

62

EDIT : Від 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'. Цей параметр може бути переданий у вигляді рядка, що кодується urlen, як "para1 = val1 & para2 = val2 & ...", або як масив із назвою поля як ключовим, а дані поля - як значення. Якщо значення - це масив, заголовок Content-Type буде встановлено на багаточастинні / форми-дані. Станом на PHP 5.2.0, файли, передані цій опції з префіксом @, повинні працювати у формі масиву для роботи.

Отже, щось подібне повинно працювати ідеально (з параметрами, переданими в асоціативному масиві):

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

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

  return implode('&', $params);
}

11
Навіщо вам передавати рядок, якщо ви можете передати масив ...?
ThiefMaster

1
Я думаю, що $ ключ також повинен бути закодований, про всяк випадок, якщо у вас він є "ім'я та прізвище" тощо. Особливо, якщо дані надає кінцевий користувач
Marius Balčytis,

2
@barius, я згоден з тобою. І я думаю, що http_build_query () насправді кращий за функцію, визначену вище.
skyfree

1
@skyfree Я згоден! Ця функція була додана в php5, хоча це було ще далеко від стандартного в 2011 році.
Czechnology

1
чому потрібен http_build_query, коли ви можете просто передати масив?
Оффенсо

39

Не передавайте рядок взагалі!

Ви можете передати масив і дозволити php / curl виконувати брудну роботу з кодування тощо.


16
передача масиву буде іншим типом вмісту, ніж рядок, тому для цього є вагома причина. Зайняв мене час, щоб зрозуміти це.
Томас Вандер Стіхеле

Я не маю поняття, чому, але я вважаю, що на моєму ПК win win проходження масиву займає приблизно секунду довше (1,029 секунд, використовуючи масив проти 0,016, використовуючи http_build_query()цей самий масив)
kratenko

2
Вкладені масиви не працюватимуть. cURL спробує перетворити їх у рядок, і слідуватиме PHP- масив до повідомлення про перетворення рядків
7ochem


4

Для CURLOPT_POSTFIELDSцього параметри можуть бути передані у вигляді рядка, що кодується urlen, 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-запиту.
7оч.

1
Щоб додати до коментаря @ 7ochem: Якщо одержувач не очікує єдиного параметра, що містить кодовану json рядок , а не json_encode(...)робити 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: Перетворення масиву на рядок у ... on line ...


4

Це залежить від content-type

Дані, кодовані URL-адресою або багаточастинні / форми

Щоб надіслати дані стандартним способом, як браузер із формою, просто передайте асоціативний масив . Як зазначено в посібнику PHP:

Цей параметр може бути переданий у вигляді рядка, що кодується urlen, як "para1 = val1 & para2 = val2 & ...", або як масив із назвою поля як ключовим, а дані поля - як значення. Якщо значення - це масив, заголовок Content-Type буде встановлено на багаточастинні / форми-дані.

Кодування JSON

Незважаючи на це, під час спілкування з API JSON вміст повинен бути кодований 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, '');

Просто інший спосіб, і він працює дуже добре.


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

9
Схоже, ви робите GET, а не POST.
велич
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.