From 8ae66857e83733b25adde724866c1d72ac64bf02 Mon Sep 17 00:00:00 2001 From: jo Date: Tue, 15 Jul 2025 22:49:03 +0900 Subject: [PATCH 1/2] 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 --- src/Illuminate/Http/Client/PendingRequest.php | 16 ++++++- tests/Http/HttpClientTest.php | 47 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index 28bde9944772..bac32e74ad3f 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -1021,7 +1021,21 @@ protected function parseHttpOptions(array $options) protected function parseMultipartBodyFormat(array $data) { return (new Collection($data)) - ->map(fn ($value, $key) => is_array($value) ? $value : ['name' => $key, 'contents' => $value]) + ->flatMap(function ($value, $key) { + if (is_array($value)) { + // If the array has 'name' and 'contents' keys, it's already formatted for multipart + if (isset($value['name']) && isset($value['contents'])) { + return [$value]; + } + + // Otherwise, treat it as multiple values for the same field name + return (new Collection($value))->map(function ($item) use ($key) { + return ['name' => $key.'[]', 'contents' => $item]; + }); + } + + return [['name' => $key, 'contents' => $value]]; + }) ->values() ->all(); } diff --git a/tests/Http/HttpClientTest.php b/tests/Http/HttpClientTest.php index 1604be010c15..535d7c12aee2 100644 --- a/tests/Http/HttpClientTest.php +++ b/tests/Http/HttpClientTest.php @@ -785,6 +785,53 @@ public function testCanSendMultipartDataWithBothSimplifiedAndExtendedParameters( }); } + public function testCanSendMultipartDataWithArrayValues() + { + $this->factory->fake(); + + $this->factory->asMultipart()->post('http://foo.com/multipart', [ + 'name' => 'Steve', + 'roles' => ['Network Administrator', 'Janitor'], + ]); + + $this->factory->assertSent(function (Request $request) { + return $request->url() === 'http://foo.com/multipart' && + Str::startsWith($request->header('Content-Type')[0], 'multipart') && + $request[0]['name'] === 'name' && + $request[0]['contents'] === 'Steve' && + $request[1]['name'] === 'roles[]' && + $request[1]['contents'] === 'Network Administrator' && + $request[2]['name'] === 'roles[]' && + $request[2]['contents'] === 'Janitor'; + }); + } + + public function testCanSendMultipartDataWithFileAndArrayValues() + { + $this->factory->fake(); + + $this->factory + ->attach('attachment', 'photo_content', 'photo.jpg', ['Content-Type' => 'image/jpeg']) + ->post('http://foo.com/multipart', [ + 'name' => 'Steve', + 'roles' => ['Network Administrator', 'Janitor'], + ]); + + $this->factory->assertSent(function (Request $request) { + return $request->url() === 'http://foo.com/multipart' && + Str::startsWith($request->header('Content-Type')[0], 'multipart') && + $request[0]['name'] === 'name' && + $request[0]['contents'] === 'Steve' && + $request[1]['name'] === 'roles[]' && + $request[1]['contents'] === 'Network Administrator' && + $request[2]['name'] === 'roles[]' && + $request[2]['contents'] === 'Janitor' && + $request[3]['name'] === 'attachment' && + $request[3]['contents'] === 'photo_content' && + $request[3]['filename'] === 'photo.jpg'; + }); + } + public function testItCanSendToken() { $this->factory->fake(); From e351e00fb58ede01d2d66699614849df8fd67413 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 18 Jul 2025 11:30:10 -0500 Subject: [PATCH 2/2] Update PendingRequest.php --- src/Illuminate/Http/Client/PendingRequest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/Client/PendingRequest.php b/src/Illuminate/Http/Client/PendingRequest.php index bac32e74ad3f..43169c9c4b75 100644 --- a/src/Illuminate/Http/Client/PendingRequest.php +++ b/src/Illuminate/Http/Client/PendingRequest.php @@ -1023,12 +1023,12 @@ protected function parseMultipartBodyFormat(array $data) return (new Collection($data)) ->flatMap(function ($value, $key) { if (is_array($value)) { - // If the array has 'name' and 'contents' keys, it's already formatted for multipart + // If the array has 'name' and 'contents' keys, it's already formatted for multipart... if (isset($value['name']) && isset($value['contents'])) { return [$value]; } - // Otherwise, treat it as multiple values for the same field name + // Otherwise, treat it as multiple values for the same field name... return (new Collection($value))->map(function ($item) use ($key) { return ['name' => $key.'[]', 'contents' => $item]; });