Guzzle使用嵌套数组发布多部分请求

时间:2017-01-11 09:32:15

标签: php arrays laravel guzzle guzzle6

经过漫长的一天调试后,尝试和错误尝试使用嵌套数组和资源项的Guzzle6帖子搜索一个好的方法。

我在Guzzle6文档中发现需要使用['multipart'=>发布数据[]]。当我得到单个数组项时,这个工作。但我得到了这样的嵌套数组项。

[
    [firstname] => 'Danny',
    [phone] => [
        [0] => [
            [phone] => 0612345678
        ]
    ]
    [picture] => '/data/...'
]

这需要格式化为Guzzle6的多部分,如下所示。

[
    [
        'name' => 'firstname',
        'contents' => 'Danny'
    ],
    [
        'name' => 'phone[0][phone]
        'contents' => '0612345678'
    ],
    [
        'name' => 'picture',
        'contents' => fopen('....', 'r')
    ]
]

我想在没有特殊技巧的情况下解决这个问题。有没有一种方法可以将带有嵌套数组和资源的post数组发送到multipart数组。

8 个答案:

答案 0 :(得分:6)

经过一整天的工作后,我得到了我的多部分表单数据。对于每个有相同问题的人来说,这里是代码。在$ output中,数据中有一系列字段。它可用于['multipart'=> Guzzle。

    $output = [];

    foreach($data as $key => $value){
        if(!is_array($value)){
            $output[] = ['name' => $key, 'contents' => $value];
            continue;
        }

        foreach($value as $multiKey => $multiValue){
            $multiName = $key . '[' .$multiKey . ']' . (is_array($multiValue) ? '[' . key($multiValue) . ']' : '' ) . '';
            $output[] = ['name' => $multiName, 'contents' => (is_array($multiValue) ? reset($multiValue) : $multiValue)];
        }
    }

答案 1 :(得分:3)

我上面使用了@DannyBevers答案,但发现它不适用于需要作为multipart发送的深层嵌套数组,所以这里是另一种解决方案:

// fake nested array to be sent multipart by guzzle
$array = array(
        'title' => 'Test title',
        'content' => 'Test content',
        'id' => 17,
        'Post' => array(

                0 => array(
                        'id' => 100027,
                        'name' => 'Fake post title',
                        'content' => 'More test content ',
                        'Comments' => array (

                                0 => 'My first comment',
                                1 => 'My second comment',
                                2 => 'My third comment'
                        )
                ),
                1 => array(
                        'id' => 100028,
                        'name' => 'Another fake post title',
                        'overall' => 2,
                        'content' => 'Even More test content ',
                        'Comments' => array (

                                0 => 'My other first comment',
                                1 => 'My other second comment',

                        )
                )

        )
);


$flatten = function($array, $original_key = '') use (&$flatten) {

    $output = [];

    foreach ($array as $key => $value) {

        $new_key = $original_key;

        if (empty($original_key)) {

            $new_key .= $key;

        } else {

            $new_key .= '[' . $key . ']';

        }

        if (is_array($value)) {

            $output = array_merge($output, $flatten($value, $new_key));

        } else {

            $output[$new_key] = $value;

        }
    }

    return $output;

};


$flat_array = $flatten($array);

$data = [];

foreach($flat_array as $key => $value) {

    $data[] = [

            'name'  => $key,
            'contents' => $value

    ];


}

$response = $guzzle->request($type, $get, array('multipart' => $data));

答案 2 :(得分:1)

由于我遇到了完全相同的问题而且我得到了收集字段,因此我有一个多嵌套级数组!所以,我需要调整这里发布的功能。

我合并了@John和@DannyBevers解决方案,以获取name param的完整密钥以及contents param的值。 然后,我在multipart

下添加了函数结果

功能:

private function flatten($array, $prefix = "[", $suffix = "]") {
    global $i;
    $result = array();
    foreach($array as $key=>$value) {
        if(is_array($value)) {
            if($i == 0) {
                $result = $result + $this->flatten($value, $key.$prefix, $suffix);
            }
            else {
                foreach ($this->flatten($value, $prefix . $key . $suffix."[", $suffix) as $k => $v){
                    $result[] = $v;
                }
            }
        }
        else {                
            if($value instanceof UploadedFile){
                $result[] = ["name" => $prefix.$key.$suffix,
                    "filename" => $value->getClientOriginalName(),
                    "Mime-Type" => $value->getMimeType(),
                    "contents" => fopen($value->getPathname(), "r")];
            }
            else {
                $result[] = ["name" => $prefix . $key . $suffix, "contents" => $value];
            }
        }
        $i++;
    }
    return $result;
}

输出:

Array
(
    [multipart] => Array
        (
            [0] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[sessionType]
                    [contents] => 1
                )
            [1] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[globalServiceType]
                    [contents] => 1
                )
            [2] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[brand]
                    [contents] => 1
                )
            [3] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[device]
                    [contents] => 1
                )
            [4] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[interfaces][0]
                    [contents] => 1
                )
            [5] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[interfaces][1]
                    [contents] => 1
                )
            [6] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[applicationsProductQuantity][0][application]
                    [contents] => 6
                )
            [7] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[applicationsProductQuantity][0][quantity]
                    [contents] => 2
                )
            [8] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[applicationsProductQuantity][2][application]
                    [contents] => 2
                )
            [9] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[applicationsProductQuantity][2][quantity]
                    [contents] => 3
                )
            [10] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[applicationsProductQuantity][5][application]
                    [contents] => 5
                )
            [11] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[applicationsProductQuantity][5][quantity]
                    [contents] => 5
                )
            [12] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[trackingNumber]
                    [contents] => CPV_XXXX
                )
            [13] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][companyAddress]
                    [contents] => street
                )
            [14] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][companyCity]
                    [contents] => Caen
                )
            [15] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][companyCountry]
                    [contents] => AF
                )
            [16] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][companyFax]
                    [contents] => 
                )
            [17] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][companyName]
                    [contents] => Society
                )
            [18] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][companyPhone]
                    [contents] => 0233445566
                )
            [19] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][companyPostalCode]
                    [contents] => 14000
                )
            [20] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][companyState]
                    [contents] => 
                )
            [21] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][email]
                    [contents] => john@mail.fr
                )
            [22] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][fullName]
                    [contents] => John
                )
            [23] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[platformImport]
                    [contents] => 1
                )
            [24] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[standardProfileImport]
                    [contents] => 1
                )
            [25] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[technicalContact][email]
                    [contents] => patou@mail.fr
                )
            [26] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[technicalContact][fullName]
                    [contents] => Patou
                )
            [27] => Array 
                (
                    [name] => requestbundle_issuingserviceproduct[filesForm][0][binaryContent]
                    [filename] => "File_test_to_upload.txt"
                    [Mime-Type] => "text/plain"
                    [contents] => stream resource @28{
                            timed_out: false
                            blocked: true
                            eof: false
                            wrapper_type: "plainfile"
                            stream_type: "STDIO"
                            mode: "r"
                            unread_bytes: 0
                            seekable: true
                            uri: "/tmp/phpEgxr10"
                            options: []
                                                  }
              )
        )
)

@Danny Bevers解决方案将输出:

Array
(
    [multipart] => Array
        (
            [0] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[sessionType]
                    [contents] => 1
                )

            [1] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[globalServiceType]
                    [contents] => 1
                )    
            [2] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[brand]
                    [contents] => 1
                )    
            [3] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[device]
                    [contents] => 1
                )    
            [4] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[interfaces][0]
                    [contents] => 1
                )    
            [5] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[applicationsProductQuantity][0]
                    [contents] => Array
                        (
                            [application] => 6
                            [quantity] => 2
                        )

                )    
            [6] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[trackingNumber]
                    [contents] => CPV_XXXX
                )
            [7] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[billingContact][companyAddress]
                    [contents] => street
                )   
            [8] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[platformImport]
                    [contents] => 1
                )   
            [9] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[standardProfileImport]
                    [contents] => 1
                )

            [10] => Array
                (
                    [name] => requestbundle_issuingserviceproduct[technicalContact][email]
                    [contents] => patou@mail.fr
                )

        )

)

我的项目中,我的函数在@ DannyBevers时没有抛出任何错误。

希望它会有所帮助!

答案 3 :(得分:0)

为它采取相当的功能:

function getFlatten($key, array $data, $result = [])
{
    foreach ($data as $subKey => $value) {
        $subKey = $key . '[' . $subKey . ']';
        if (\is_array($value)) {
            $result = $this->getFlatten($subKey, $value, $result);
        } else {
            $result[] = ['name' => $subKey, 'contents' => $value];
        }
    }

    return $result;
}

示例

   $data = [
        'first' => [
            'second' => ['third' => 12, 'third_a' => 13],
            'second_2' => 3,
            'second_3' => ['third_2' => ['fours' => 15]],
        ],
    ];

if (is_array($data)) {
    $request = getFlatten('main_key', $data)
}

<强>输出

    0 => [
        'name' => 'main_key[first][second][third]'
        'contents' => 12
    ]
    1 => [
        'name' => 'main_key[first][second][third_a]'
        'contents' => 13
    ]
    2 => [
        'name' => 'main_key[first][second_2]'
        'contents' => 3
    ]
    3 => [
        'name' => 'main_key[first][second_3][third_2][fours]'
        'contents' => 15
    ]

答案 4 :(得分:0)

上述解决方案都不适用于我,因为我的数组结构具有顶级值以及嵌套。

我创建了这个解决问题的要点:https://gist.github.com/matthew-inamdar/a17701f948770ac0a55acd9d12445645

您可以简单地使用以下内容:

$data = [
    'name' => 'John',
    'language' => [
        'main' => 'English',
        'secondary' => [
            0 => 'Spanish',
            1 => 'German'
        ]
    ],
];

$flattened = (new Flatten())->flatten($data);

$flattened = [
    ['name' => 'name', 'contents' => 'John'],
    ['name' => 'language[main]', 'contents' => 'English'],
    ['name' => 'language[secondary][0]', 'contents' => 'Spanish'],
    ['name' => 'language[secondary][1]', 'contents' => 'German']
];

答案 5 :(得分:0)

@请参阅https://github.com/guzzle/guzzle/issues/1679#issuecomment-342233663

使用http_build_query获取拼合名称,然后建立多部分内容。

$multipart = [];
$vars = explode('&', http_build_query($postData));
foreach ($vars as $var) {
    list($nameRaw, $contentsRaw) = explode('=', $var);
    $name = urldecode($nameRaw);
    $contents = urldecode($contentsRaw);
    $multipart[] = ['name' => $name, 'contents' => $contents];
}

答案 6 :(得分:0)

示例数据:

$array = [
  "doc_id" => 2,
  "data" => [
    [
      "field" => "10"
      "value" => "test10"
    ],
    [
      "field" => "11"
      "value" => "test11"
    ]
  ]
]

编码多维数组

$outputArray = explode('&', urldecode(http_build_query($array)))

输出:

array[
  0 => "doc_id =2",
  1 => "data[0][field]=10",
  2 => "data[0][value]=test10",
  3 => "data[1][field]=11",
  4 => "data[1][value]=test11"
]

添加帖子数据:

foreach ($outputArray as $data) {
    list($key, $value) = explode('=', $data);
    $postData[] = ['name' => $key, 'contents' => $value];
}

答案 7 :(得分:-1)

是的,有一种更简单的方法。您可以使用所需格式将值作为数组发送,并使用kernel/reboot.c组合它们。

示例:

http_build_query

现在在Guzzle中发送 $ request_params