Monday, February 5, 2024

[SOLVED] Upload file using Guzzle

Issue

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'


Solution

I'd review the Guzzle's multipart request options. I see two issues:

  1. 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).
  2. 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']
        ],
    ],
]);


Answered By - Jacob Budin
Answer Checked By - Terry (WPSolving Volunteer)