formato POST curl para CURLOPT_POSTFIELDS

99

Quando uso curlvia POSTe set CURLOPT_POSTFIELD, preciso usar urlencodealgum formato especial?

por exemplo: Se eu quiser postar 2 campos, primeiro e último:

first=John&last=Smith

qual é o código / formato exato que deve ser usado com 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);
Ken
fonte

Respostas:

100

Caso você esteja enviando uma string, urlencode () a. Caso contrário, se array, deve ser key => value pair e o Content-typecabeçalho é automaticamente definido como multipart/form-data.

Além disso, você não precisa criar funções extras para construir a consulta para seus arrays, você já tem isso:

$query = http_build_query($data, '', '&');
kodeart
fonte
13
Você pode apenas usar, http_build_query($data)pois &é o separador padrão.
nulidade
6
Claro que você pode ignorá-los. Isso é para ilustrar os outros dois argumentos que você pode (ou não) alterar (por exemplo, o separador padrão) para atender às suas necessidades específicas.
kodeart
62

EDITAR : A partir de php5, o uso de http_build_queryé recomendado:

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

Exemplo simples do manual:

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

?>

antes de php5:

Do manual :

CURLOPT_POSTFIELDS

Os dados completos para postar em uma operação HTTP "POST". Para postar um arquivo, acrescente um nome de arquivo com @ e use o caminho completo. O tipo de arquivo pode ser especificado explicitamente seguindo o nome do arquivo com o tipo no formato '; type = mimetype'. Este parâmetro pode ser passado como uma string codificada por url como 'para1 = val1 & para2 = val2 & ...' ou como uma matriz com o nome do campo como chave e os dados do campo como valor. Se o valor for uma matriz, o cabeçalho Content-Type será definido como multipart / form-data. A partir do PHP 5.2.0, os arquivos passados ​​para esta opção com o prefixo @ devem estar na forma de array para funcionar.

Então, algo assim deve funcionar perfeitamente (com parâmetros passados ​​em uma matriz associativa):

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

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

  return implode('&', $params);
}
Czechnology
fonte
11
Por que você passaria uma string se você pode passar um array ...?
ThiefMaster
1
Acho que $ key também deve ser codificada, apenas no caso de você tê-la como "nome e sobrenome" etc. Especialmente se os dados forem fornecidos pelo usuário final
Marius Balčytis
2
@barius, concordo com você. E eu acho que http_build_query () na verdade é melhor do que a função definida acima.
skyfree
1
@skyfree eu concordo! Essa função foi adicionada no php5, embora ainda estivesse longe do padrão em 2011.
Czechnology
1
por que http_build_query é necessário quando você poderia apenas passar array?
Offenso de
39

Não passe uma string!

Você pode passar um array e deixar o php / curl fazer o trabalho sujo de codificação, etc.

ThiefMaster
fonte
16
passar um array será um tipo de conteúdo diferente de uma string, então há um bom motivo para fazer isso. Levei um tempo para descobrir isso.
Thomas Vander Stichele
Não tenho ideia do porquê, mas acho que no meu win dev pc passar um array leva cerca de um segundo a mais (1.029s usando array vs. 0,016s usando o http_build_query()mesmo array)
kratenko
2
Matrizes aninhadas não funcionam. cURL tentará convertê-los em string e um aviso de conversão de array de PHP em string seguirá
7ochem
5

De acordo com o manual do PHP, os dados passados ​​para cURL como uma string devem ser codificados por URL. Veja a página para curl_setopt () e pesquise CURLOPT_POSTFIELDS.

Sonhos surreais
fonte
4

Para CURLOPT_POSTFIELDS, os parâmetros podem ser passados ​​como uma string codificada por url para1=val1&para2=val2&..ou como uma matriz com o nome do campo como chave e os dados do campo como valor

Experimente o seguinte formato:

$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
fonte
2
Oi Shraddha, json_encode()vou lhe dar algo realmente diferente de uma string de parâmetro válida como first=John&last=Smith. json_encode()irá imprimir: {"first":"John","last":"Smith"}que se tornará o corpo bruto da sua solicitação POST.
7ochem
1
Para adicionar ao comentário de @ 7ochem: A menos que o destinatário esteja esperando um único parâmetro contendo uma string codificada em json , em vez de json_encode(...)do http_build_query(...). Isso criará a "string codificada em url" esperada contendo os parâmetros separados por "&".
Toolmaker Steve
4

Outra diferença importante que ainda não foi mencionada aqui é que CURLOPT_POSTFIELDSnão é possível lidar com matrizes aninhadas.

Se pegarmos a matriz aninhada, ['a' => 1, 'b' => [2, 3, 4]]então isso deve ser parametrizado como a=1&b[]=2&b[]=3&b[]=4( [e ]será / deve ser codificado por URL). Isso será convertido de volta automaticamente em um array aninhado na outra extremidade (assumindo aqui que a outra extremidade também é PHP).

Isso vai funcionar:

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"

Isso não vai funcionar:

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

Isso lhe dará um aviso. A execução do código continuará e seu endpoint receberá o parâmetro bcomo string "Array":

Aviso do PHP: conversão de array em string em ... on-line ...

7ochem
fonte
4

Depende do content-type

url-codificado ou multipart / form-data

Para enviar dados da maneira padrão, como um navegador faria com um formulário, basta passar um array associativo . Conforme declarado pelo manual do PHP:

Este parâmetro pode ser passado como uma string codificada por url como 'para1 = val1 & para2 = val2 & ...' ou como uma matriz com o nome do campo como chave e os dados do campo como valor. Se o valor for uma matriz, o cabeçalho Content-Type será definido como multipart / form-data.

Codificação JSON

No entanto, ao se comunicar com APIs JSON, o conteúdo deve ser codificado em JSON para que a API entenda nossos dados POST.

Nesses casos, o conteúdo deve ser explicitamente codificado como JSON:

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

Ao comunicar no JSON, nós também geralmente definido accepte content-typecabeçalhos em conformidade:

CURLOPT_HTTPHEADER => [
    'accept: application/json',
    'content-type: application/json'
]
Buzut
fonte
2

para matrizes aninhadas, você pode usar:

$data = [
  'name[0]' = 'value 1',
  'name[1]' = 'value 2',
  'name[2]' = 'value 3',
  'id' = 'value 4',
  ....
];
Maxim Rysevets
fonte
0

Curiosamente, a maneira como o Postman faz o POST é uma operação GET completa com estas 2 opções adicionais:

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

Apenas outra maneira, e funciona muito bem.

Klompenrunner
fonte
-3

Essa resposta também me levou uma eternidade para ser encontrada. Descobri que tudo o que você precisa fazer é concatenar a URL ('?' Após o nome e a extensão do arquivo) com a string de consulta codificada por URL. Nem parece que você precisa definir as opções do POST cURL. Veja o exemplo falso abaixo:

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

Você também pode usar file_get_contents():

// read entire webpage file into a string
$output = file_get_contents($exampleURL . $data);
user2512571
fonte
9
Parece que você está fazendo um GET em vez de um POST.
grandnasty