web-dev-qa-db-fra.com

Publier un tableau multidimensionnel avec PHP et CURL

Je ne parviens pas à envoyer des données de formulaire via CURL à un script PHP de destination situé sur un hôte différent.

Je reçois une erreur Array to string conversion

Ceci est print_r du tableau que je poste:

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

C'est la ligne sur laquelle l'erreur se produit:

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

Le troisième argument must doit être un tableau car j'ai besoin que l'en-tête Content-Type soit défini sur multipart/form-data car j'envoie un fichier via ce même tableau. Je ne peux donc pas convertir le tableau en chaîne de requête ni utiliser http_build_query().

De plus, je n'ai pas accès au code sur l'hôte destinataire, je ne peux donc pas sérialiser ni désérialiser la matrice.

Je suppose que la valeur de la clé name étant un tableau étant la cause de cette erreur, je suppose également que CURLOPT_POSTFIELDS ne prend pas en charge les tableaux multidimensionnels. Y a-t-il un autre moyen de contourner cela ou suis-je condamné?

Merci d'avance!

43
David Hancock

Vous devez créer manuellement la chaîne POST, plutôt que de transmettre l'intégralité du tableau. Vous pouvez ensuite remplacer l'en-tête de contenu choisi par curl par:

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

Sérialiser/json-ifying serait plus facile, mais comme vous le dites, vous n’avez aucun contrôle sur le destinataire, vous avez donc un peu de travail supplémentaire à faire.

23
Marc B
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);
31
Khristenko Yura

La solution la plus simple est de faire un:

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

Voici un exemple de code utilisé dans la vie réelle:

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

Lorsque vous avez imbriqué la section $ params dans le fichier Gist ci-dessus, elle est analysée en conséquence et préparée en vue de son affichage via curl.

15
Gayan Hewa

J'aimerais tout d'abord remercier Daniel Vandersluis pour son réponse perspicace . Sur la base de sa contribution, je suis venu avec ceci pour résoudre le problème de la question initiale:

<?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;
}

L'utilisation devrait ressembler à ceci:

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

Cette fonction convertira les tableaux comme ceci:

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

Dans ceci:

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

Il ne gère pas les cas avec un format mixte lorsqu'il y a une collision clé comme ceci:

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

La sortie contiendra uniquement la première valeur pour cette clé

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

Je pense que vous aurez besoin de passer les options sous forme de chaîne:

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

Vous devriez alors pouvoir définir l'en-tête manuellement via CURLOPT_HTTPHEADER.

0
Alex Howansky

L'option cURL CURLOPT_POSTFIELDS acceptera une chaîne ou un tableau simple, mais pas un tableau imbriqué. Si vous tentez de le faire, l'erreur Array to string conversion est générée.

Cependant, http_build_query() peut gérer un tableau imbriqué, utilisez-le pour convertir le tableau $_POST en chaîne puis envoyez-la à la place. Alors où tu as;

curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);

utilisez ceci à la place;

curl_setopt($ch, CURLOPT_POSTFIELDS, urldecode(http_build_query($_POST)));
0
Nigel Alderton