Home / Blog / PSR-7 Middleware File Upload with Formidable

PSR-7 Middleware File Upload with Formidable

In my previous blog post I wrote about handling form data with Formidable, but I didn’t mention how to work with file uploads. This is because Formidable by itself does not handle file uploads at all, but only string data. So by now many people asked be already how to handle that, if not with that library itself. My answer to that is quite simple: Use the tools your PSR-7 middleware file upload implementation already gives you.

Meet the UploadedFileInterface

Any library implementing PSR-7 has a method getUploadedFiles() on their server request implementation. This method returns an array of objects implementing PsrHttpMessageUploadedFileInterface. There are many ways that files can be transmitted to the server, so let’s roll with the simplest one right now, where you have a form with a single file input and nothing else, in which case your middleware may look something like this:

<?php
use InteropHttpServerMiddlewareDelegateInterface;
use InteropHttpServerMiddlewareMiddlewareInterface;
use PsrHttpMessageServerRequestInterface;
use PsrHttpMessageUploadedFileInterface;
 
final class UploadMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, DelegateInterface $delegate)
    {
        $uploadedFiles = $request->getUploadedFiles();
         
        if (!array_key_exists('file', $uploadedFiles)) {
            // Return an error response
        }
         
        /* @var $file UploadedFileInterface */
        $file = $uploadedFiles['file'];
 
        if (UPLOAD_ERR_OK !== $file->getError()) {
            // Return error response
        }
         
        $file->moveTo('/storage/location');
         
        // At this point you may want to check if the uploaded file matches the criteria your domain dictates. If you
        // want to check for valid images, you may try to load it with Imagick, or use finfo to validate the mime type.
         
        // Return successful response
    }
}


This is a very basic example, but it illustrates how to handle any kind of file upload. Please note that the PsrHttpMessageUploadedFileInterface doesn’t give you access to temporary file name, so you actually have to move it to another location first before doing any checks on the file. This is to ensure that the file was actually uploaded and is not coming from any malicious source.

Integration with Formidable

The previous example just gave you an idea for handling a PSR-7 middleware file upload on its own, without any further data transmitted with the file. If you want to first validate your POST data, your middleware could look similar to this:

<?php
use DASPRiDFormidableFormErrorFormError;
use DASPRiDFormidableFormInterface;
use InteropHttpServerMiddlewareDelegateInterface;
use InteropHttpServerMiddlewareMiddlewareInterface;
use PsrHttpMessageServerRequestInterface;
 
final class UploadMiddleware implements MiddlewareInterfacenterface
{
    /**
     * @var FormInterface
     */
    private $form;
 
    public function process(ServerRequestInterface $request, DelegateInterface $delegate)
    {
        $form = $this->form;
         
        if ('POST' === $request->getMethod()) {
            $form = $form->bindFromRequest($request);
             
            if (!$form->hasErrors()) {
                $fileUploadSuccess = $this->processFileUpload($request);
                 
                if (!$fileUploadSuccess) {
                    // Persist $form->getValue();
                }
                 
                $form->withError(new FormError('file', 'Upload error'));
            }
        }
 
        // Render HTML with $form
    }
     
    private function processFileUpload(ServerRequestInterface $request) : bool
    {
        // Do the same checks as in the previous example
    }
}

As you can see, you simply stack the file upload processing onto the normal form handling, they don’t have to interact at all, except putting an error on the form for the file element.

Want to learn more? Get more of our insights on web development strategies.

Leave a Comment

Your email address will not be published. Required fields are marked *