【问题标题】:Guzzle post multipart request with nested arrayGuzzle 使用嵌套数组发布多部分请求
【发布时间】:2017-05-26 00:33:11
【问题描述】:

经过一整天的调试和反复尝试,尝试使用带有嵌套数组和资源项的 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')
    ]
]

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

【问题讨论】:

  • 所以你基本上想要创建一个循环来迭代每个键并以多部分格式创建一个新数组

标签: php arrays laravel guzzle guzzle6


【解决方案1】:

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

例子:

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


$request_pararms = http_build_query($params);

现在在 Guzzle 中发送 $request_params

【讨论】:

  • 此方法无效。我需要发布具有多部分内容类型的图像。当值包含 fopen() 值时,您的答案会删除图片。
  • 构建查询参数,如果是这种情况,然后附加图像。
  • 如何将文件附加到 guzzle post 请求中,文档中没有可用的附加功能。
【解决方案2】:

经过一整天的工作,我得到了我的多部分表单数据数组。对于每个有同样问题的人,这里是代码。在 $output 中有一个数据中的字段数组。它可以在 ['multipart' => $output] 中与 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)];
        }
    }

【讨论】:

    【解决方案3】:

    我使用了上面的@DannyBevers 答案,但发现它不适用于需要作为多部分发送的深层嵌套数组,所以这里有一个替代解决方案:

    // 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));
    

    【讨论】:

      【解决方案4】:

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

      我合并了@John 和@DannyBevers 解决方案以获得name 参数的完整密钥和contents 参数的值。 然后,我在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
                      )
      
              )
      
      )
      

      my 项目中,我的函数不会抛出任何错误,而 @DannyBevers 会抛出任何错误。

      希望对您有所帮助!

      【讨论】:

        【解决方案5】:

        为它使用漂亮的功能:

        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
            ]
        

        【讨论】:

          【解决方案6】:

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

          我创建了解决问题的 Gist: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']
          ];
          

          【讨论】:

            【解决方案7】:

            @见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];
            }
            

            【讨论】:

              【解决方案8】:

              示例数据:

              $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];
              }
              

              【讨论】:

                猜你喜欢
                • 2015-08-12
                • 2019-02-23
                • 2019-09-13
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-01-02
                • 1970-01-01
                相关资源
                最近更新 更多