web-dev-qa-db-ja.com

PHPおよびCURLを使用した多次元配列の投稿

別のホストにある受信側のPHPスクリプトにCURLを介してフォームデータを送信するのに問題があります。

_Array to string conversion_エラーが表示されます

これは、私が投稿している配列の_print_r_です。

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

これは、エラーが発生する行です。

_curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post);
_

3番目の引数mustは配列である必要があるため、この同じ配列を介してファイルを送信するときに_Content-Type_ヘッダーを_multipart/form-data_に設定する必要があるため、配列を変換できませんクエリ文字列に使用するか、http_build_query()を使用します。

また、受信ホストのコードにアクセスできないため、アレイをシリアル化および非シリアル化できません。

配列であるnameキーの値がこのエラーの原因であると想定しています。また、_CURLOPT_POSTFIELDS_多次元配列をサポートしていません。これを回避する他の方法はありますか、それとも運命ですか?

前もって感謝します!

43
David Hancock

配列全体を渡すのではなく、POST文字列を手動で構築する必要があります。その後、curlの自動選択コンテ​​ンツヘッダーを次のようにオーバーライドできます。

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

シリアル化/ json化は簡単ですが、あなたが言うように、受信側を制御することはできないので、やることが少し余分にあります。

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);
32
Khristenko Yura

HTTPリクエストに関しては、配列の概念は実際には存在しません。 PHP(および他のサーバー側言語の可能性が高い)には、looksのような要求データを取得できるロジックが組み込まれています(それに)配列し、$_GET$_POSTなどにデータを入力しながら配列としてまとめます.

たとえば、POSTフォームの配列の場合、フォーム要素は次のようになります。

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

あるいは:

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

PHPは受信時にこのデータをどのように処理するか(つまり、配列を構築する)をHTMLとHTTPに認識していますが、同様の(または同じ、これは技術的に有効なHTMLではありません)の名前です。

CURLリクエストの逆を行うには、配列をキーの文字列表現に分解する必要があります。 name配列を使用すると、次のようなことができます。

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

その結果、$post配列は次のようになります。

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

そして、投稿する配列内の各キーは、scalar値になります。これはcURLが予期しているもので、配列は必要に応じて表されますHTTP。

27

最も簡単な解決策は以下を実行することです:

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

以下は、これが実際に使用されるサンプルコードです。

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

上記のGistに$ paramsセクションをネストすると、それに応じて解析され、curlを介した投稿の準備が行われます。

16
Gayan Hewa

最初に、彼の 洞察に満ちた返信 に感謝しますDaniel Vandersluis。彼の入力に基づいて、元の質問の問題を解決するためにこれを思いつきました。

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

使用法は次のようになります。

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

この関数は、配列を次のように変換します。

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

これに:

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

次のようなキーの衝突がある場合、混合フォーマットの場合は処理しません。

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

出力には、そのキーの最初の値のみが含まれます

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

オプションを文字列として渡す必要があると思います。

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

その後、CURLOPT_HTTPHEADERを使用してヘッダーを手動で設定できるはずです。

0
Alex Howansky

CURLオプション_CURLOPT_POSTFIELDS_は、文字列または単純な配列のいずれかを受け入れますが、ネストされた配列は受け入れません。そうしようとすると、_Array to string conversion_エラーが生成されます。

ただし、http_build_query()はネストされた配列を処理できるので、それを使用して_$_POST_配列を文字列に変換し、代わりにその文字列を送信します。だからあなたが持っているところ;

_curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);
_

代わりにこれを使用してください。

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