curl POST format dla CURLOPT_POSTFIELDS

99

Kiedy używam curlvia POSTi set, CURLOPT_POSTFIELDczy muszę mieć urlencodejakiś specjalny format?

na przykład: Jeśli chcę opublikować 2 pola, pierwsze i ostatnie:

first=John&last=Smith

jaki jest dokładny kod / format, który powinien być używany z 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);
Rozpoznać
źródło

Odpowiedzi:

100

Jeśli wysyłasz ciąg, urlencode () go. W przeciwnym razie, jeśli tablica, powinna być sparowana klucz => wartość, a Content-typenagłówek jest automatycznie ustawiany na multipart/form-data.

Nie musisz też tworzyć dodatkowych funkcji, aby zbudować zapytanie dla swoich tablic, już to masz:

$query = http_build_query($data, '', '&');
kodeart
źródło
13
Możesz po prostu użyć, http_build_query($data)ponieważ &jest domyślnym separatorem.
nieważność
6
Oczywiście możesz je pominąć. Ma to na celu zilustrowanie pozostałych dwóch argumentów, które możesz (lub nie) zmienić (np. Domyślny separator), aby dopasować się do swoich konkretnych potrzeb.
kodeart
62

EDYCJA : Od php5 w górę http_build_queryzalecane jest użycie:

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

Prosty przykład z instrukcji:

<?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
*/

?>

przed php5:

Z instrukcji :

CURLOPT_POSTFIELDS

Pełne dane do wysłania w operacji „POST” HTTP. Aby opublikować plik, poprzedź jego nazwę znakiem @ i użyj pełnej ścieżki. Typ pliku można jawnie określić, dodając po nazwie pliku typ w formacie „; type = mimetype”. Ten parametr można przekazać jako ciąg zakodowany jako urlen, taki jak „para1 = val1 & para2 = val2 & ...” lub jako tablicę z nazwą pola jako kluczem i danymi pola jako wartością. Jeśli wartość jest tablicą, nagłówek Content-Type zostanie ustawiony na multipart / form-data. Począwszy od PHP 5.2.0, pliki przekazywane do tej opcji z prefiksem @ muszą mieć postać tablicową, aby działały.

Więc coś takiego powinno działać idealnie (z parametrami przekazanymi w tablicy asocjacyjnej):

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

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

  return implode('&', $params);
}
Czechnology
źródło
11
Dlaczego miałbyś przekazywać ciąg, skoro możesz przekazać tablicę ...?
ThiefMaster
1
Myślę, że klucz $ również powinien być zakodowany, na wypadek gdybyś miał go w stylu "imię i nazwisko" itp. Zwłaszcza jeśli dane są podane przez użytkownika końcowego
Marius Balčytis.
2
@barius, zgadzam się z tobą. I myślę, że http_build_query () faktycznie jest lepsze niż funkcja zdefiniowana powyżej.
skyfree
1
@skyfree Zgadzam się! Ta funkcja została dodana w php5, co wciąż było dalekie od standardu w 2011.
Czechnology
1
dlaczego http_build_query jest wymagane, skoro można po prostu przekazać tablicę?
Offenso
39

W ogóle nie przekazuj ciągu!

Możesz przekazać tablicę i pozwolić php / curl wykonać brudną robotę kodowania itp.

ThiefMaster
źródło
16
przekazanie tablicy będzie innym typem zawartości niż ciąg, więc jest dobry powód, aby to zrobić. Zajęło mi trochę czasu, zanim to rozgryzłem.
Thomas Vander Stichele
Nie mam pojęcia dlaczego, ale uważam, że na mój dev pc wygrana przekazywanie tablicy trwa około sekundy dłużej (1.029s wykorzystujące 0.016s tablicę vs. przy użyciu http_build_query()tego samego tablicy)
kratenko
2
Tablice zagnieżdżone nie będą działać. cURL spróbuje przekonwertować je na ciągi znaków i nastąpi powiadomienie o konwersji tablicy PHP na ciąg
7ochem.
5

Zgodnie z instrukcją PHP dane przekazywane do cURL jako ciąg znaków powinny być zakodowane w postaci adresu URL. Zobacz stronę dotyczącą curl_setopt () i wyszukaj CURLOPT_POSTFIELDS.

Surreal Dreams
źródło
4

W CURLOPT_POSTFIELDSprzypadku parametrów można przekazywać jako ciąg znaków z kodem urlen, na przykład para1=val1&para2=val2&..jako tablicę z nazwą pola jako kluczem i danymi pola jako wartością

Wypróbuj następujący format:

$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);
Shraddha Vadnere
źródło
2
Cześć Shraddha, json_encode()da ci coś naprawdę innego od prawidłowego ciągu parametrów jako first=John&last=Smith. json_encode()wyświetli: {"first":"John","last":"Smith"}które następnie stanie się surową treścią twojego żądania POST.
7ochem
1
Aby dodać do komentarza @ 7ochem: Chyba że odbiorca oczekuje pojedynczego parametru zawierającego ciąg zakodowany w formacie JSON zamiast json_encode(...)do http_build_query(...). Spowoduje to utworzenie oczekiwanego „ciągu zakodowanego w adresie URL” zawierającego parametry oddzielone znakiem „&”.
ToolmakerSteve
4

Inną ważną różnicą, o której jeszcze nie wspomniano, jest CURLOPT_POSTFIELDSbrak obsługi tablic zagnieżdżonych.

Jeśli weźmiemy zagnieżdżoną tablicę, ['a' => 1, 'b' => [2, 3, 4]]należy ją sparametryzować jako a=1&b[]=2&b[]=3&b[]=4( [i ]będzie / powinno być zakodowane w postaci adresu URL). Zostanie to automatycznie przekonwertowane z powrotem na zagnieżdżoną tablicę na drugim końcu (zakładając, że drugi koniec to również PHP).

To zadziała:

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"

To nie zadziała:

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

To da ci ostrzeżenie. Wykonywanie kodu będzie kontynuowane, a punkt końcowy otrzyma parametr w bpostaci ciągu "Array":

Uwaga PHP: konwersja tablicy na ciąg w ... on-line ...

7ochem
źródło
4

To zależy od content-type

url-encoded lub multipart / form-data

Aby wysłać dane w standardowy sposób, tak jak robiłaby to przeglądarka z formularzem, wystarczy przekazać tablicę asocjacyjną . Jak stwierdzono w podręczniku PHP:

Ten parametr można przekazać jako ciąg zakodowany jako urlen, taki jak „para1 = val1 & para2 = val2 & ...”, lub jako tablicę z nazwą pola jako kluczem i danymi pola jako wartością. Jeśli wartość jest tablicą, nagłówek Content-Type zostanie ustawiony na multipart / form-data.

Kodowanie JSON

Niemniej jednak podczas komunikacji z interfejsami API JSON zawartość musi być zakodowana w formacie JSON, aby interfejs API mógł zrozumieć nasze dane POST.

W takich przypadkach treść musi być wyraźnie zakodowana w formacie JSON:

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

Podczas komunikacji w JSON, również zazwyczaj ustawione accepti content-typenagłówki odpowiednio:

CURLOPT_HTTPHEADER => [
    'accept: application/json',
    'content-type: application/json'
]
Buzut
źródło
2

w przypadku tablic zagnieżdżonych możesz użyć:

$data = [
  'name[0]' = 'value 1',
  'name[1]' = 'value 2',
  'name[2]' = 'value 3',
  'id' = 'value 4',
  ....
];
Maxim Rysevets
źródło
0

Co ciekawe, sposób, w jaki Postman wykonuje POST, to kompletna operacja GET z dwoma dodatkowymi opcjami:

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

Po prostu inny sposób i działa bardzo dobrze.

Klompenrunner
źródło
-3

Ta odpowiedź również zajęła mi wieczność. Odkryłem, że wszystko, co musisz zrobić, to połączyć adres URL („?” Po nazwie pliku i rozszerzeniu) z ciągiem zapytania zakodowanym w adresie URL. Nawet nie wygląda na to, że musisz ustawić opcje POST cURL. Zobacz fałszywy przykład poniżej:

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

Możesz również użyć file_get_contents():

// read entire webpage file into a string
$output = file_get_contents($exampleURL . $data);
user2512571
źródło
9
Wygląda na to, że robisz raczej GET niż POST.
grandnasty