be.dev

Web development blog by Philipp Rieber

Creating a PSR-7 Guzzle Request object with form-data

Uploading files with Guzzle 6 using a multipart/form-data request is pretty straightforward. But creating a request object with a file upload independently from the actual sending process turns out to not be that obvious.

When wrapping everything within one step, performing a file upload with Guzzle 6 using multipart/form-data is as simple as:

<?php

use GuzzleHttp\Client;

$client = new Client();
$response = $client->request(
    'POST', 
    'https://xyz.acme.dev/api/upload', 
    [
        'multipart' => [
            [
                'name' => 'upload_file',
                'contents' => fopen('path/to/file', 'r')
            ],
            // ... more fields
        ]
    ]
);

But recently I stumbled upon the requirement to create the request object decoupled from actually sending it with the client. Having only a simple string payload in the message body sending as a POST request would still be quite easy:

<?php

use GuzzleHttp\Psr7\Request;

$payload = 'My payload';
$request = new Request(
    'POST', 
    'https://xyz.acme.dev/api/upload', 
    [], 
    $payload
);
$response = $client->send($request);

But how to a create multipart/form-data payload? Because files can get huge they need to be fed into the request by a stream. Guzzle provides a lot of different stream types. Unfortunately the one we need is currently not linked from the docs, but you can find it in the supporting guzzle/psr7 library. Using a MultipartStream, the request object can now be created decoupled from the client:

<?php

use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\MultipartStream;

$multipart = new MultipartStream([
    [
        'name' => 'upload_file',
        'contents' => fopen('path/to/file', 'r')
    ],
    // ... more fields
]);
$request = new Request(
    'POST', 
    'https://xyz.acme.dev/api/upload', 
    [], 
    $multipart
);
$response = $client->send($request);

If required, you can now pass around this $request object as needed before actually sending it with the Guzzle client.

 

Philipp Rieber is a passionate and certified PHP and Symfony developer working at Paymill in Munich, Germany. He is also engaged in the frontend, the Cloud, on Mobile, as a DevOp and a technical writer. He is never missing the PHP User Group Munich and he is co-organizing the Symfony User Group Munich.

philipp-rieber.net

 

Liked this post? Follow me on Twitter for updates.