Upload file using Guzzle - php

I have a form where video can be uploaded and sent to remote destination. I have a cURL request which I want to 'translate' to PHP using Guzzle.
So far I have this:
public function upload(Request $request)
{
$file = $request->file('file');
$fileName = $file->getClientOriginalName();
$realPath = $file->getRealPath();
$client = new Client();
$response = $client->request('POST', 'http://mydomain.de:8080/spots', [
'multipart' => [
[
'name' => 'spotid',
'country' => 'DE',
'contents' => file_get_contents($realPath),
],
[
'type' => 'video/mp4',
],
],
]);
dd($response);
}
This is cURL which I use and want to translate to PHP:
curl -X POST -F 'body={"name":"Test","country":"Deutschland"};type=application/json' -F 'file=#C:\Users\PROD\Downloads\617103.mp4;type= video/mp4 ' http://mydomain.de:8080/spots
So when I upload the video, I want to replace this hardcoded
C:\Users\PROD\Downloads\617103.mp4.
When I run this, I get an error:
Client error: POST http://mydomain.de:8080/spots resulted in a 400 Bad Request response: request body invalid: expecting form value 'body`'
Client error: POST http://mydomain.de/spots resulted in a 400 Bad Request response:
request body invalid: expecting form value 'body'

I'd review the Guzzle's multipart request options. I see two issues:
The JSON data needs to be stringified and passed with the same name you're using in the curl request (it's confusingly named body).
The type in the curl request maps to the header Content-Type. From $ man curl:
You can also tell curl what Content-Type to use by using 'type='.
Try something like:
$response = $client->request('POST', 'http://mydomain.de:8080/spots', [
'multipart' => [
[
'name' => 'body',
'contents' => json_encode(['name' => 'Test', 'country' => 'Deutschland']),
'headers' => ['Content-Type' => 'application/json']
],
[
'name' => 'file',
'contents' => fopen('617103.mp4', 'r'),
'headers' => ['Content-Type' => 'video/mp4']
],
],
]);

While using the multipart option, make sure you are not passing content-type => application/json :)
If you want to POST form fields AND upload file together, just use this multipart option. It's an array of arrays where name is form field name and it's value is the POSTed form value. An example:
'multipart' => [
[
'name' => 'attachments[]', // could also be `file` array
'contents' => $attachment->getContent(),
'filename' => 'dummy.png',
],
[
'name' => 'username',
'contents' => $username
]
]

Related

Send Multipart Form from PHP with Guzzle

I'm trying to create a multipart form for upload file in my API.
According the docs of guzzle :
\\$data = picture of form
\\$uri = Endpoint in my API
$this->client->post($uri, [
'multipart' => [
[
'name' => 'picture',
'contents' => file_get_contents($data),
]
],
'headers' => $headers
]);
When I'm using Insomnia or Postman :
I'm not understand why it not working in Guzzle.
$file = new File($data->getPathname());
$tmp_picture_path = Storage::putFile("temp_dir", $file);
$tmp_picture = Storage::readStream($tmp_picture_path);
$response = $this->client->post(
$uri,
[
'multipart' => [
[
'name' => 'picture',
'contents' => $tmp_picture,
'filename' => "avatar." . $data->getClientOriginalExtension()
]
],
'headers' => $headers
]
);
Storage::delete($tmp_picture_path);
Just save locally the file and read the stream dor send it properly.

Issue converting from cURL to Guzzle 6 with JSON and XML file

I am having a hard time converting cURL to Guzzle6. I'm want to send a name and reference UUID via JSON AND the contents of an XML file to process to a REST endpoint.
cURL
curl -H 'Expect:' -F
'request={"name":"test", "reference":"870e0320-021e-4c67-9169-d4b2c7e5b9c9"}'
-F 'file=#sample.xml' http://ec2-48-88-173-9.us-east-1.compute.amazonaws.com:8180/rs/process
Guzzle
$client = new Client(['debug' => true]);
$request = $client->request('POST',
'http://ec2-48-88-173-9.us-east-1.compute.amazonaws.com:8180/rs/process', [
'multipart' => [
[
'name' => 'data',
'contents' => "{'name':'test','reference':870e0320-021e-4c67-9169-d4b2c7e5b9c9}",
'headers' => ['Content-Type' => 'application/json']
],
[
'name' => 'file',
'contents' => fopen('sample.xml', 'r'),
'headers' => ['Content-Type' => 'text/xml']
],
]
]
);
$response = $request->getBody()->getContents();
Also, I'm not sure what the 'name' fields should be ('name' => 'data'), etc.
This is the Guzzle equivalent of your curl command:
$client = new Client(['debug' => true]);
$request = $client->request('POST',
'http://ec2-48-88-173-9.us-east-1.compute.amazonaws.com:8180/rs/process', [
'multipart' => [
[
'name' => 'request',
'contents' => "{'name':'test','reference':870e0320-021e-4c67-9169-d4b2c7e5b9c9}",
],
[
'name' => 'file',
'contents' => fopen('sample.xml', 'r'),
],
]
]
);
$response = $request->getBody()->getContents();
For the file Guzzle will specify the appropriate content type, as curl does. Name for the first part is request — from -F
'request={"name":"test", "reference":"870e0320-021e-4c67-9169-d4b2c7e5b9c9"}'

guzzle, how to force content-type in a multipart/form-data

I'm new with Guzzle and I'm trying to make a REST request to sign PDF file. The provider says :
you need to use BASIC authentication
the request must be a POST request
the mimetype should be multipart/form-data
the file sent must be application/octet-stream and its name should be "file"
the data sent must be application/json and its name should be "data"
The system returns a response which contains the signed PDF file and type is application/octet-stream
This is the code I tested with Guzzle, but the provider says that the type mime sent in application/pdf. How can I "force" the mimetype for the PDF file ?
$client = new Client([
'auth' => ['login', 'password'],
'debug' => true,
'curl' => [
CURLOPT_PROXY => '192.168.1.232',
CURLOPT_PROXYPORT => '8080',
CURLOPT_PROXYUSERPWD => 'username:password',
],
]);
$boundary = 'my_custom_boundary';
$multipart = [
[
'name' => 'data',
'contents' => "{'nomDocument':'documentTest.pdf','externalid':'123456'}",
'Content-Type' => 'application/json'
],
[
'name' => 'file',
'contents' => fopen('documentTest.pdf', 'r'),
'Content-Type' => 'application/octet-stream'
],
];
$params = [
'headers' => [
'Connection' => 'close',
'Content-Type' => 'multipart/form-data; boundary='.$boundary,
],
'body' => new GuzzleHttp\Psr7\MultipartStream($multipart, $boundary),
];
try{
$response = $client->request('POST', 'https://server.com/api/sendDocument', $params);
} catch (RequestException $e) {
echo Psr7\str($e->getRequest());
if ($e->hasResponse()) {
echo Psr7\str($e->getResponse());
}
}
Thank you for your help.
You have to pass the Content-Type in headers
$multipart = [
[
'name' => 'data',
'contents' => "{'nomDocument':'documentTest.pdf','externalid':'123456'}",
'headers' => [ 'Content-Type' => 'application/json']
],
[
'name' => 'file',
'contents' => fopen('documentTest.pdf', 'r'),
'headers' => [ 'Content-Type' => 'application/octet-stream']
],
];
in Guzzle Documentation say that you can specify headers for every multipart data.
If you not set header Guzzle put a Content-Type for you based on file.

Upload image file using slack API files.upload method

The following code seems to work, but the Slack API saves the file a plain text.
protected function upload($file)
{
$client = $this->guzzle;
if (!$token) {
$token = env('SLACK_TOKEN');
}
$response = $client->request('POST', env('SLACK_API') . "/files.upload?token=$token", [
'form_params' => [
'name' => $file->getFilename(),
'content' => File::get($file->getRealPath()),
'filename' => $file->getFilename(),
'filetype' => 'image',
'channels' => "#_test",
]
]);
return json_decode((string)$response->getBody());
}
When I use the guzzle multipart post, I get the error: 'no_file_data' I feel like I am missing something.
Is there a way to upload images or non-text files using the files.upload method in the Slack API?
Almost as soon as I posted this question, I realized that I was formatting the array incorrectly on the multipart post in guzzle.
This seems to work:
$response = $this->guzzle->post(env('SLACK_API') . "/files.upload?token=$token",
['multipart' =>
[
[
'name' => 'filename',
'contents' => $file->getClientOriginalName()
],
[
'name' => 'file',
'contents' => fopen($file,'r')
],
[
'name' => 'channels',
'contents' => '#_test'
]
]
]);

Can not upload file with data by guzzle

I want to upload a file with data parameter, but it do not work.
$client->post('http://xxx/', [
'json' => [
'abc' => 'abc'
],
'multipart' => [
[
'name' => 'file',
'contents' => fopen('xxx.sh', 'r')
]
],
]);
It only post abc parameter. And it only can post file when I delete json parameter.
I want to upload file and post some data in one request, How can I do that?
In order to send the JSON information, it will have to be sent with the Multipart message. Multipart cannot be mixed with any other body related request option. Verification from the owner of Guzzle: https://github.com/guzzle/guzzle/issues/1386
Note
multipart cannot be used with the form_params option. You will need to use one or the other. Use form_params for application/x-www-form-urlencoded requests, and multipart for multipart/form-data requests.
from: http://docs.guzzlephp.org/en/latest/request-options.html#multipart
do this:
$response = $client->post('http://example.com/api', [
'multipart' => [
[
'name' => 'image',
'contents' => fopen('/path/to/image', 'r')
],
[
'name' => 'name',
'contents' => 'Example name'
]
]
]);
from: Guzzle ~6.0 multipart and form_params
done.

Categories