2010-08-10 12 views
6

Tengo problemas para publicar una matriz multidimensional con archivos cargados usando PHP y CURL.Cómo subir archivos (multipart/form-data) con POSTFIELDS multidimensionales usando PHP y CURL?

La matriz multidimensional es, por ejemplo:

$post['question'] = 'Are you human?'; 
$post['answers'] = array('yes', 'no', 'maybe'); 
$post['file'] = '@/path/to/file'; 

// Output: 

Array(
    'question' => Are you human?, 
    'answers' => Array(
     '0' => yes, 
     '1' => no, 
     '2' => maybe 
     ), 
    'file' => @/path/to/file 
) 

Hay algunas cosas por qué esto no funcionaría si simplemente intenta publicar esto con CURLOPT_POSTFIELDS en CURL así:

$ch = curl_init(); 

curl_setopt($ch, CURLOPT_URL, 'http://example.com'); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
curl_setopt($ch, CURLOPT_POST, true); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $post); 

$response = curl_exec($ch); 

En primer lugar, el PHP oficial description de CURLOPT_POSTFIELDS dice:

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. Esto puede hacerse pasar como una cadena urlencoded como 'párrafo1 = val1 val2 = párrafo2 & & ...' o como una matriz con el nombre del campo como datos clave y de campo como valor. Si value es una matriz , el encabezado Content-Type será establecido en multipart/form-data.

Parece que se puede pasar cualquier tipo de matriz a POSTFIELDS ¿verdad? Incorrecto. POSTFIELDS solo acepta valores no escalares y se ahogará con un error Array to string conversion al pasar en matrices multidimensionales. Entonces, la única otra opción que tiene es http_build_query() su matriz para poder pasar matrices multidimensionales que no se ahogan.

Pero .. como se puede leer en la nota en la página PHP:

Nota: Pasar una matriz a CURLOPT_POSTFIELDS codificará los datos como multipart/form-data, mientras que pasar una URL -encoded cadena codificar los datos como application/x-www-form-urlencoded.

La publicación no será multipart/form-data encoded si pasa una cadena urlencoded a POSTFIELDS, lo que hace que la carga de su archivo falle.

Parece casi imposible combinar los dos con CURL, mientras que no sería un problema si hubiera usado un formulario HTML normal.

Mi pregunta es: ¿es posible eludir esta extraña peculiaridad de CURL para poder publicar matrices multidimensionales y subir archivos?

Respuesta

6

multipart/form-data no admite valores anidados. Y no creo que CURL pueda hacerlo tampoco.

Sospecho que la recepción de su solicitud también es un script PHP. Si, a continuación, puede presentar una matriz anidada como uno de los valores, si sólo se prepara usted mismo:

$post['answers[0]'] = "yes"; 
$post['answers[1]'] = "no"; 
$post['answers[2]'] = "maybe"; 

Teóricamente que acaba necesitaría 'answers[]' sin el índice, pero que podría sobrescribir el valor precedente - y por lo tanto solo funciona con http_build_query.

No estoy seguro de si hay alguna biblioteca HTTP en PHP que pueda hacer esto automáticamente.

+0

Me gusta esta solución, gracias. – Melvin

+0

¡Gran truco, funciona como un encanto! – aknatn

2

Otra manera de lograr la primera respuesta:

foreach(array("yes","no","maybe") as $key=>$value) 
    $post["answers[$key]"] = $value;
+0

Esto no funcionará para matrices multidimensionales –

1

Pruebe esta función recursiva.

https://gist.github.com/yisraeldov/ec29d520062575c204be7ab71d3ecd2f

<?php 
function build_post_fields($data,$existingKeys='',&$returnArray=[]){ 
    if(($data instanceof CURLFile) or !(is_array($data) or is_object($data))){ 
     $returnArray[$existingKeys]=$data; 
     return $returnArray; 
    } 
    else{ 
     foreach ($data as $key => $item) { 
      build_post_fields($item,$existingKeys?$existingKeys."[$key]":$key,$returnArray); 
     } 
     return $returnArray; 
    } 
} 

Y se puede utilizar de esta manera.

curl_setopt($ch, CURLOPT_POSTFIELDS, build_post_fields($postfields)); 
Cuestiones relacionadas