formato POST curl para CURLOPT_POSTFIELDS

99

Cuando utilizo curlvia POSTy configuro, CURLOPT_POSTFIELD¿tengo que hacerlo urlencodeo algún formato especial?

por ejemplo: si quiero publicar 2 campos, primero y último:

first=John&last=Smith

¿Cuál es el código / formato exacto que debe usarse con 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);
Conocido
fuente

Respuestas:

100

En caso de que esté enviando una cadena, urlencode () it. De lo contrario, si es una matriz, debe ser clave => valor emparejado y el Content-typeencabezado se establece automáticamente en multipart/form-data.

Además, no tiene que crear funciones adicionales para construir la consulta para sus matrices, ya tiene eso:

$query = http_build_query($data, '', '&');
kodeart
fuente
13
Puede usar http_build_query($data)ya que &es el separador predeterminado.
nulabilidad
6
Por supuesto que puede omitirlos. Esto es para ilustrar los otros dos argumentos que puede (o no puede) cambiar (por ejemplo, el separador predeterminado) para satisfacer sus necesidades específicas.
kodeart
62

EDITAR : Desde php5 en adelante, http_build_queryse recomienda el uso de :

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

Ejemplo simple del 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:

Del manual :

CURLOPT_POSTFIELDS

Los datos completos para publicar en una operación HTTP "POST". Para publicar un archivo, anteponga un nombre de archivo con @ y use la ruta completa. El tipo de archivo se puede especificar explícitamente siguiendo el nombre del archivo con el tipo en el formato '; type = mimetype'. Este parámetro puede pasarse como una cadena codificada en urlencoded como 'para1 = val1 & para2 = val2 & ...' o como una matriz con el nombre del campo como clave y los datos del campo como valor. Si el valor es una matriz, el encabezado Content-Type se establecerá en multipart / form-data. A partir de PHP 5.2.0, los archivos que se pasan a esta opción con el prefijo @ deben estar en forma de matriz para funcionar.

Entonces, algo como esto debería funcionar perfectamente (con parámetros pasados ​​en una matriz asociativa):

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

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

  return implode('&', $params);
}
Czechnología
fuente
11
¿Por qué pasaría una cadena si puede pasar una matriz ...?
ThiefMaster
1
Creo que $ key también debe codificarse, en caso de que lo tenga como "nombre y apellido", etc. Especialmente si los datos los proporciona el usuario final
Marius Balčytis
2
@barius, estoy de acuerdo contigo. Y creo que http_build_query () en realidad es mejor que la función definida anteriormente.
skyfree
1
@skyfree ¡Estoy de acuerdo! Esa función se agregó en php5, aunque todavía estaba lejos de ser estándar en 2011.
Czechnology
1
¿Por qué se requiere http_build_query cuando podría simplemente pasar la matriz?
Offenso
39

¡No pases una cuerda en absoluto!

Puede pasar una matriz y dejar que php / curl haga el trabajo sucio de la codificación, etc.

ThiefMaster
fuente
16
pasar una matriz será un tipo de contenido diferente al de una cadena, por lo que hay una buena razón para hacerlo. Me tomó un tiempo darme cuenta de eso.
Thomas Vander Stichele
No tengo idea de por qué, pero encuentro que en mi pc win dev pasar una matriz toma aproximadamente un segundo más (1.029s usando una matriz frente a 0.016s usando http_build_query()esa misma matriz)
kratenko
2
Las matrices anidadas no funcionarán. cURL intentará convertirlos en cadenas y aparecerá un aviso de conversión de matriz PHP a cadena
7ochem
5

Según el manual de PHP, los datos pasados ​​a cURL como una cadena deben estar codificados en URL. Consulte la página de curl_setopt () y busque CURLOPT_POSTFIELDS.

Sueños surrealistas
fuente
4

Para CURLOPT_POSTFIELDS, los parámetros pueden pasarse como una cadena codificada en URL como para1=val1&para2=val2&..o como una matriz con el nombre del campo como clave y los datos del campo como valor

Pruebe el siguiente 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
fuente
2
Hola Shraddha, json_encode()te dará algo realmente diferente de una cadena de parámetro válida como first=John&last=Smith. json_encode()saldrá: {"first":"John","last":"Smith"}que luego se convertirá en el cuerpo sin procesar de su solicitud POST.
7ochem
1
Para agregar al comentario de @ 7ochem: a menos que el destinatario espere un solo parámetro que contenga una cadena codificada en json , en lugar de json_encode(...)do http_build_query(...). Esto creará la "cadena codificada en URL" esperada que contiene los parámetros separados por "&".
ToolmakerSteve
4

Otra diferencia importante que aún no se menciona aquí es que CURLOPT_POSTFIELDSno se pueden manejar matrices anidadas.

Si tomamos la matriz anidada ['a' => 1, 'b' => [2, 3, 4]], esto debería parametrizarse como a=1&b[]=2&b[]=3&b[]=4( [y ]estará / debería estar codificado en URL). Esto se volverá a convertir automáticamente en una matriz anidada en el otro extremo (asumiendo que aquí el otro extremo también es PHP).

Esto 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"

Esto no funcionará:

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

Esto le dará un aviso. La ejecución del código continuará y su punto final recibirá el parámetro bcomo una cadena "Array":

Aviso de PHP: conversión de matriz a cadena en ... en línea ...

7ochem
fuente
4

Depende de content-type

codificado en URL o multiparte / form-data

Para enviar datos de la forma estándar, como lo haría un navegador con un formulario, simplemente pase una matriz asociativa . Como se indica en el manual de PHP:

Este parámetro puede pasarse como una cadena codificada por urlencoded como 'para1 = val1 & para2 = val2 & ...' o como una matriz con el nombre del campo como clave y los datos del campo como valor. Si el valor es una matriz, el encabezado Content-Type se establecerá en multipart / form-data.

Codificación JSON

No obstante, al comunicarse con las API JSON, el contenido debe estar codificado en JSON para que la API comprenda nuestros datos POST.

En tales casos, el contenido debe codificarse explícitamente como JSON:

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

Cuando nos comunicamos en JSON, también solemos configurar accepty content-typeencabezados en consecuencia:

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

para matrices anidadas puede usar:

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

Curiosamente, la forma en que Postman hace POST es una operación GET completa con estas 2 opciones adicionales:

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

Solo de otra forma, y ​​funciona muy bien.

Klompenrunner
fuente
-3

Esta respuesta también me tomó una eternidad encontrar. Descubrí que todo lo que tienes que hacer es concatenar la URL ('?' Después del nombre y la extensión del archivo) con la cadena de consulta codificada en la URL. Ni siquiera parece que tenga que configurar las opciones POST cURL. Vea el ejemplo falso a continuación:

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

También puede utilizar file_get_contents():

// read entire webpage file into a string
$output = file_get_contents($exampleURL . $data);
usuario2512571
fuente
9
Parece que estás haciendo un GET en lugar de un POST.
grandnasty