Skip to content

Commit 347cc4a

Browse files
Fix multipart array value parsing in HTTP client (#55732) (#56302)
* Fix multipart array value parsing in HTTP client - Fixed parseMultipartBodyFormat to handle array values correctly - Array values are now formatted as 'field[]' entries for multipart/form-data - Maintains backward compatibility with existing name/contents format - Added tests for array values and mixed file+array scenarios Fixes #55732 * Update PendingRequest.php --------- Co-authored-by: Taylor Otwell <[email protected]>
1 parent 1784f2e commit 347cc4a

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

src/Illuminate/Http/Client/PendingRequest.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,21 @@ protected function parseHttpOptions(array $options)
10211021
protected function parseMultipartBodyFormat(array $data)
10221022
{
10231023
return (new Collection($data))
1024-
->map(fn ($value, $key) => is_array($value) ? $value : ['name' => $key, 'contents' => $value])
1024+
->flatMap(function ($value, $key) {
1025+
if (is_array($value)) {
1026+
// If the array has 'name' and 'contents' keys, it's already formatted for multipart...
1027+
if (isset($value['name']) && isset($value['contents'])) {
1028+
return [$value];
1029+
}
1030+
1031+
// Otherwise, treat it as multiple values for the same field name...
1032+
return (new Collection($value))->map(function ($item) use ($key) {
1033+
return ['name' => $key.'[]', 'contents' => $item];
1034+
});
1035+
}
1036+
1037+
return [['name' => $key, 'contents' => $value]];
1038+
})
10251039
->values()
10261040
->all();
10271041
}

tests/Http/HttpClientTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,53 @@ public function testCanSendMultipartDataWithBothSimplifiedAndExtendedParameters(
786786
});
787787
}
788788

789+
public function testCanSendMultipartDataWithArrayValues()
790+
{
791+
$this->factory->fake();
792+
793+
$this->factory->asMultipart()->post('http://foo.com/multipart', [
794+
'name' => 'Steve',
795+
'roles' => ['Network Administrator', 'Janitor'],
796+
]);
797+
798+
$this->factory->assertSent(function (Request $request) {
799+
return $request->url() === 'http://foo.com/multipart' &&
800+
Str::startsWith($request->header('Content-Type')[0], 'multipart') &&
801+
$request[0]['name'] === 'name' &&
802+
$request[0]['contents'] === 'Steve' &&
803+
$request[1]['name'] === 'roles[]' &&
804+
$request[1]['contents'] === 'Network Administrator' &&
805+
$request[2]['name'] === 'roles[]' &&
806+
$request[2]['contents'] === 'Janitor';
807+
});
808+
}
809+
810+
public function testCanSendMultipartDataWithFileAndArrayValues()
811+
{
812+
$this->factory->fake();
813+
814+
$this->factory
815+
->attach('attachment', 'photo_content', 'photo.jpg', ['Content-Type' => 'image/jpeg'])
816+
->post('http://foo.com/multipart', [
817+
'name' => 'Steve',
818+
'roles' => ['Network Administrator', 'Janitor'],
819+
]);
820+
821+
$this->factory->assertSent(function (Request $request) {
822+
return $request->url() === 'http://foo.com/multipart' &&
823+
Str::startsWith($request->header('Content-Type')[0], 'multipart') &&
824+
$request[0]['name'] === 'name' &&
825+
$request[0]['contents'] === 'Steve' &&
826+
$request[1]['name'] === 'roles[]' &&
827+
$request[1]['contents'] === 'Network Administrator' &&
828+
$request[2]['name'] === 'roles[]' &&
829+
$request[2]['contents'] === 'Janitor' &&
830+
$request[3]['name'] === 'attachment' &&
831+
$request[3]['contents'] === 'photo_content' &&
832+
$request[3]['filename'] === 'photo.jpg';
833+
});
834+
}
835+
789836
public function testItCanSendToken()
790837
{
791838
$this->factory->fake();

0 commit comments

Comments
 (0)