Symfony 无法识别通过 Guzzle multipart/form-data 请求上传的多个文件
Multiple files uploaded via Guzzle multipart/form-data request are not recognized by Symfony
环境:
Guzzle 6
交响乐 2.3
正在通过 Guzzle POST 请求 should be done with a multipart request 上传多个文件。所以我像这样配置我的 $options 数组:
Array
(
[multipart] => Array
(
[0] => Array
(
[name] => filename-0
[contents] => Resource id #440
[filename] => filename-0
)
[1] => Array
(
[name] => filename-1
[contents] => Resource id #441
[filename] => filename-1
)
[2] => Array
(
[name] => filename-2
[contents] => Resource id #442
[filename] => filename-2
)
)
[headers] => Array
(
[Accept] => application/json
[Content-Type] => multipart/form-data
[Accept-Language] => de
)
[allow_redirects] =>
[http_errors] =>
)
multipart-array 中的资源是 fopen() 的结果。
并使用
发送请求
$response = $this->client->post(
'/someUrl/someAction',
$options
);
使用已经创建的客户端。
在接受 Symfony-Controllers 方面,我无法发送文件:
var_dump($_FILES); // array(0) {}
var_dump($_POST); // array(0) {}
var_dump(count($request->files->all())); // int(0)
但是,这两个:
var_dump(file_get_contents("php://input"));
var_dump($request->getContent());
Return 输入流上的数据:
/myPath/FileController.php:xx:
string(601) "--e55f849feb078da4a9e35ba77da3ded02ec813a7
Content-Disposition: form-data; name="filename-0"; filename="filename-0"
Content-Length: 43
This is a testfile...
--e55f849feb078da4a9e35ba77da3ded02ec813a7
Content-Disposition: form-data; name="filename-1"; filename="filename-1"
Content-Length: 43
This is a testfile...
--e55f849feb078da4a9e35ba77da3ded02ec813a7
Content-Disposition: form-data; name="filename-2"; filename="filename-2"
Content-Length: 43
This is a testfile...
--e55f849feb078da4a9e35ba77da3ded02ec813a7--
"
我怎样才能进入 Symfony-way 中的接收控制器?
考虑的好奇心:
主计长报告
var_dump($request->getContentType()); // NULL
我的直觉告诉我这可能很重要。
使用multipart
选项时,不能自己指定Content-Type
header。 Guzzle 将处理此问题,并且 - 对于此问题更重要的是 - 边界 将原始请求 body 中的内容部分分开。主要 Content-Type
header 定义边界如下:
Content-Type: multipart/form-data; boundary=unique-string-that-is-hopefully-not-used-in-the-real-content-because-it-separates-the-content-parts`
检查Client.php#L308:
当使用 multipart
选项时,Guzzle 将请求 body 创建为 GuzzleHttp\Psr7\MultipartStream
object。
然后检查 MultipartStream.php#L30 处的 MultipartStream
构造函数:
创建一个随机值用作边界:sha1(uniqid('', true))
Guzzle 将使用边界自行在 Client.php#L383.
处设置正确的内容类型
但由于 Guzzle 不会覆盖您明确指定的选项,主要 header 指定一个空边界,原始 body 部分将由创建的部分分隔通过 MultpartStream
构造函数。在接收端PHP无法再将内容部分分开。
这段代码对我有用:
(new GuzzleHttp\Client())->request(
'POST',
'http://localhost/upload',
[
'multipart' => [
[
'name' => 'filename-0',
'contents' => fopen(__DIR__.'/sample-0.txt', 'rb'),
'filename' => 'filename-0',
],
[
'name' => 'filename-1',
'contents' => fopen(__DIR__.'/sample-1.txt', 'rb'),
'filename' => 'filename-1',
],
[
'name' => 'filename-2',
'contents' => fopen(__DIR__.'/sample-2.txt', 'rb'),
'filename' => 'filename-2',
],
],
'headers' => [
# Do not override the Content-Type header here, Guzzle takes care of it
] ,
]
);
请注意,所有这些都与 Symfony 无关,即 Symfony 只是从 Request
object 可以通过 PHP 的本地资源(如 [=21)获得的内容创建它=], $_POST
等 你可以看到原始请求 body ($request->getContent()
) 中的所有内容,因为它是这样发送的,但是 PHP 无法拆分内容部分,因为它不知道正确的边界。
这段代码对我有用。我认为您的 API 正在接收一个名为 file.
的 var 类型数组
$fopen=fopen("/etc/file.txt");//verify that file exists
$fopen2=fopen("/etc/file.txt");//verify that file exists
$apiRequest = $client->request('POST', 'http://xxx.xx.xxx.xx/upload/1/9',
[
'multipart' => [
[
'name' => 'file[]',
'contents' => $fopen
],
[
'name' => 'file[]',
'contents' => $fopen2
]
]
]);
$response = json_decode($apiRequest->getBody());
dd($response);
环境: Guzzle 6 交响乐 2.3
正在通过 Guzzle POST 请求 should be done with a multipart request 上传多个文件。所以我像这样配置我的 $options 数组:
Array
(
[multipart] => Array
(
[0] => Array
(
[name] => filename-0
[contents] => Resource id #440
[filename] => filename-0
)
[1] => Array
(
[name] => filename-1
[contents] => Resource id #441
[filename] => filename-1
)
[2] => Array
(
[name] => filename-2
[contents] => Resource id #442
[filename] => filename-2
)
)
[headers] => Array
(
[Accept] => application/json
[Content-Type] => multipart/form-data
[Accept-Language] => de
)
[allow_redirects] =>
[http_errors] =>
)
multipart-array 中的资源是 fopen() 的结果。
并使用
发送请求$response = $this->client->post(
'/someUrl/someAction',
$options
);
使用已经创建的客户端。
在接受 Symfony-Controllers 方面,我无法发送文件:
var_dump($_FILES); // array(0) {}
var_dump($_POST); // array(0) {}
var_dump(count($request->files->all())); // int(0)
但是,这两个:
var_dump(file_get_contents("php://input"));
var_dump($request->getContent());
Return 输入流上的数据:
/myPath/FileController.php:xx:
string(601) "--e55f849feb078da4a9e35ba77da3ded02ec813a7
Content-Disposition: form-data; name="filename-0"; filename="filename-0"
Content-Length: 43
This is a testfile...
--e55f849feb078da4a9e35ba77da3ded02ec813a7
Content-Disposition: form-data; name="filename-1"; filename="filename-1"
Content-Length: 43
This is a testfile...
--e55f849feb078da4a9e35ba77da3ded02ec813a7
Content-Disposition: form-data; name="filename-2"; filename="filename-2"
Content-Length: 43
This is a testfile...
--e55f849feb078da4a9e35ba77da3ded02ec813a7--
"
我怎样才能进入 Symfony-way 中的接收控制器?
考虑的好奇心: 主计长报告
var_dump($request->getContentType()); // NULL
我的直觉告诉我这可能很重要。
使用multipart
选项时,不能自己指定Content-Type
header。 Guzzle 将处理此问题,并且 - 对于此问题更重要的是 - 边界 将原始请求 body 中的内容部分分开。主要 Content-Type
header 定义边界如下:
Content-Type: multipart/form-data; boundary=unique-string-that-is-hopefully-not-used-in-the-real-content-because-it-separates-the-content-parts`
检查Client.php#L308:
当使用 multipart
选项时,Guzzle 将请求 body 创建为 GuzzleHttp\Psr7\MultipartStream
object。
然后检查 MultipartStream.php#L30 处的 MultipartStream
构造函数:
创建一个随机值用作边界:sha1(uniqid('', true))
Guzzle 将使用边界自行在 Client.php#L383.
处设置正确的内容类型但由于 Guzzle 不会覆盖您明确指定的选项,主要 header 指定一个空边界,原始 body 部分将由创建的部分分隔通过 MultpartStream
构造函数。在接收端PHP无法再将内容部分分开。
这段代码对我有用:
(new GuzzleHttp\Client())->request(
'POST',
'http://localhost/upload',
[
'multipart' => [
[
'name' => 'filename-0',
'contents' => fopen(__DIR__.'/sample-0.txt', 'rb'),
'filename' => 'filename-0',
],
[
'name' => 'filename-1',
'contents' => fopen(__DIR__.'/sample-1.txt', 'rb'),
'filename' => 'filename-1',
],
[
'name' => 'filename-2',
'contents' => fopen(__DIR__.'/sample-2.txt', 'rb'),
'filename' => 'filename-2',
],
],
'headers' => [
# Do not override the Content-Type header here, Guzzle takes care of it
] ,
]
);
请注意,所有这些都与 Symfony 无关,即 Symfony 只是从 Request
object 可以通过 PHP 的本地资源(如 [=21)获得的内容创建它=], $_POST
等 你可以看到原始请求 body ($request->getContent()
) 中的所有内容,因为它是这样发送的,但是 PHP 无法拆分内容部分,因为它不知道正确的边界。
这段代码对我有用。我认为您的 API 正在接收一个名为 file.
的 var 类型数组$fopen=fopen("/etc/file.txt");//verify that file exists
$fopen2=fopen("/etc/file.txt");//verify that file exists
$apiRequest = $client->request('POST', 'http://xxx.xx.xxx.xx/upload/1/9',
[
'multipart' => [
[
'name' => 'file[]',
'contents' => $fopen
],
[
'name' => 'file[]',
'contents' => $fopen2
]
]
]);
$response = json_decode($apiRequest->getBody());
dd($response);