2010-09-22 2 views
41

Ho problemi a registrare i dati dei moduli tramite CURL su uno script PHP ricevente situato su un host diverso.Invio di array multidimensionali con PHP e CURL

ottengo un errore Array to string conversion

Questo è print_r della matrice sto postando:

Array 
(
    [name] => Array 
    (
     [0] => Jason 
     [1] => Mary 
     [2] => Lucy 
    ) 
    [id] => 12 
    [status] => local 
    [file] => @/test.txt 
) 

Questa è la linea l'errore si verifica:

curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post); 

Il terzo argomento deve essere essere un array perché ho bisogno dell'intestazione Content-Type da impostare su multipart/form-data poiché sto inviando un file tramite questo stesso array, quindi non posso convertire l'array in una stringa di query o utilizzare http_build_query().

Inoltre, non ho accesso al codice sull'host di ricezione, quindi non posso serializzare e non serializzare l'array.

Sto supponendo che il valore della chiavenome essendo un array è la causa di questo errore, sto anche assumendo che CURLOPT_POSTFIELDS non supporta gli array multidimensionali. C'è un altro modo per aggirare questo o sono condannato?

Grazie in anticipo!

risposta

23

Avresti per costruire la stringa POST manualmente, piuttosto che far passare l'intero array in È quindi possibile eseguire l'override del ricciolo auto-scelto intestazione contenuti con:.

curl_setopt($c, CURLOPT_HTTPHEADER, array("Content-type: multipart/form-data")); 

Serializzare/JSON-ficare sarebbe più facile , ma come dici tu, non hai il controllo sulla parte ricevente, quindi hai un po 'di lavoro extra da fare.

+4

Grazie! In realtà non sapevo di poterlo fare. Ho aggiunto 'CURLOPT_HTTPHEADER' e ho passato il mio array in' http_build_query() '. Lavoro fatto! –

+0

Grazie per aver menzionato 'http_build_query()'. Ha funzionato come un fascino per me! – mccbala

+1

Nel mio caso questo non funziona. L'errore è ** Avviso: limite mancante nei dati POST multipart/form-data in Unknown sulla linea 0 **. Ciò che ha funzionato per me è stato [questo post] (http://stackoverflow.com/a/8224117/1057527) di Khristenko Yura – machineaddict

27

Il concetto di una matrice non esiste realmente quando si tratta di richieste HTTP. PHP (e probabilmente altri linguaggi server-side) ha una logica cotto in grado di prendere di richiesta dati che sguardi come un array (ad essa) e la mette insieme come una matrice durante il popolamento $_GET, $_POST ecc

Per esempio , quando si registra una matrice da un modulo, gli elementi del modulo appaiono spesso qualcosa di simile:

<form ...> 
    <input name="my_array[0]"> 
    <input name="my_array[1]"> 
    <input name="my_array[2]"> 
</form> 

o anche:

<form ...> 
    <input name="my_array[]"> 
    <input name="my_array[]"> 
    <input name="my_array[]"> 
</form> 

Mentre PHP sa cosa fare con questi dati quando lo riceve (es. costruire un array), in HTML e HTTP, si hanno tre input non collegati che hanno solo nomi simili (o lo stesso, sebbene questo non sia tecnicamente valido HTML).

Per eseguire l'operazione inversa per la richiesta cURL, è necessario decomporre l'array in rappresentazioni di stringa dei tasti. Quindi, con il vostro name array, si potrebbe fare qualcosa di simile:

foreach ($post['name'] as $id => $name) 
{ 
    $post['name[' . $id . ']'] = $name; 
} 
unset($post['name']); 

che si tradurrebbe in $post array di ricerca come:

Array 
(
    [name[0]] => Jason 
    [name[1]] => Mary 
    [name[2]] => Lucy 
    [id] => 12 
    [status] => local 
    [file] => @/test.txt 
) 

E poi ogni tasto della matrice stai scrivendo sarebbe un scalare il valore, che cURL è in attesa e la matrice verrà rappresentata come necessario per HTTP.

+2

Grazie per la risposta, si non ha risposto alla domanda ma è stato molto perspicace! –

+0

GRAZIE MOLTO !! –

0

penso che sarà necessario passare le opzioni come una stringa:

curl_setopt($this->ch, CURLOPT_POSTFIELDS, 'name[]=Jason&name[]=Mary&name[]=Lucy...'); 

si dovrebbe quindi essere in grado di impostare manualmente l'intestazione via CURLOPT_HTTPHEADER.

27
function http_build_query_for_curl($arrays, &$new = array(), $prefix = null) { 

    if (is_object($arrays)) { 
     $arrays = get_object_vars($arrays); 
    } 

    foreach ($arrays AS $key => $value) { 
     $k = isset($prefix) ? $prefix . '[' . $key . ']' : $key; 
     if (is_array($value) OR is_object($value) ) { 
      http_build_query_for_curl($value, $new, $k); 
     } else { 
      $new[$k] = $value; 
     } 
    } 
} 

$arrays = array(
    'name' => array(
     'first' => array(
      'Natali', 'Yura' 
     ) 
    ) 
); 


http_build_query_for_curl($arrays, $post); 

print_r($post); 
+1

molto utile, grazie! Avrai bisogno di questo se hai array annidati e hai bisogno di caricare file – fishbone

+0

Questo ha funzionato alla grande per me. Grazie –

+2

Ritengo che questa sia la soluzione migliore, poiché gestisce anche i caricamenti di file. Grazie! – Tominator

-1
$post = "ac=on&p=1&pr[]=0&pr[]=1&a[]=3&a[]=4&pl=on&sp[]=3&ct[]=3&s=1&o=0&pp=3&sortBy=date"; 
parse_str($post,$fields); 

$url = 'http://example.com/'; 


//open connection 
$ch = curl_init(); 

//set the url, number of POST vars, POST data 
curl_setopt($ch,CURLOPT_URL, $url); 
curl_setopt($ch,CURLOPT_POST, true); 
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields); 
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true); 

//execute post 
$result = curl_exec($ch); 

//close connection 
curl_close($ch); 
13

soluzione più semplice è quello di fare un:

$array = urldecode(http_build_query($array)); 

Di seguito è riportato il codice di esempio in cui questo è usato nella vita reale:

https://gist.github.com/gayanhewa/142c48162f72e68a4a23

Dopo aver nidificato $ sezione params nel gist sopra lo analizzerà di conseguenza e prepararlo per la pubblicazione tramite arricciatura.

0

L'opzione cURL CURLOPT_POSTFIELDS accetta una stringa o un array semplice ma non un array nidificato. Il tentativo di farlo genererà l'errore Array to string conversion.

Tuttavia, http_build_query() può gestire un array nidificato in modo da utilizzarlo per convertire l'array $_POST in una stringa, quindi inviare tale stringa. Quindi dove hai;

curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST); 

utilizzare questo;

curl_setopt($ch, CURLOPT_POSTFIELDS, urldecode(http_build_query($_POST))); 
1

Prima di tutto vorrei ringraziare Daniel Vandersluis per la sua insightful reply. Sulla base della sua entrata sono arrivato fino a questo per risolvere il problema della domanda iniziale:

<?php 

function curl_postfields_flatten($data, $prefix = '') { 
    if (!is_array($data)) { 
    return $data; // in case someone sends an url-encoded string by mistake 
    } 

    $output = array(); 
    foreach($data as $key => $value) { 
    $final_key = $prefix ? "{$prefix}[{$key}]" : $key; 
    if (is_array($value)) { 
     // @todo: handle name collision here if needed 
     $output += curl_postfields_flatten($value, $final_key); 
    } 
    else { 
     $output[$final_key] = $value; 
    } 
    } 
    return $output; 
} 

uso dovrebbe essere simile a questo:

curl_setopt($this->ch, CURLOPT_POSTFIELDS, curl_postfields_flatten($post)); 

Questa funzione convertirà array come questo:

array(
    'a' => 'a', 
    'b' => array(
    'c' => array(
     'd' => 'd', 
     'e' => array(
     'f' => 'f', 
    ), 
    ), 
), 
); 

In questa:

array(
    'a' => 'a', 
    'b[c][d]' => 'd', 
    'b[c][e][f]' => 'f', 
) 

Non gestisce i casi con formato misto quando c'è una collisione chiave come questo:

array(
'b[c]' => '1', 
'b' => array(
    'c' => '2', 
), 
); 

L'uscita conterrà solo il primo valore per quella chiave

array(
'b[c]' => '1' 
)