Upload, store in a DB and serve images with REST API

Hi,

I have followed the Odan tutorial to create a REST API with a Mysql DB to serve data in Json format to some clients (VueJs for now).

But I need to use images in my app. I need to send it with my client to my API server, stock them and serve them to the client.
It’s images to illustrate some object (hundreds). Object is a table of my DB with some properties.
So i think I need to store images directly in a directory of my server and store the path in my object table.

But I don’t konw how to do that.

First I tried to serve an existent image form my server to my client (postman to try it) following the image tutorial from Odan
But if switch this line :

// Create image in memory
        $image = $this->imageManager->canvas(800, 600, '#719e40');

to that one :

$image = $this->imageManager->make('public/foo.png');

I got that error :

Type: Intervention\Image\Exception\NotReadableException

Code: 0

Message: Image source not readable

File: XXX/app-core-test/vendor/intervention/image/src/Intervention/Image/AbstractDecoder.php

Line: 351

So for this first part I don’t really know how to deal with that error.

And in a second part I really don’t know how to get an image form my client with the request interface and how to manage it.

Thanks for your help,
Baudouin

I think I have not covered this specific topic in my blog. This would need more explanations and examples etc.

Generally, it’s good to store the files in a directory and the filenames in the specific database table.

How you can handle file uploads is already documented in the Slim documentation: Uploading files using POST forms.

Example to get all uploaded files:

use Psr\Http\Message\UploadedFileInterface;
use Ramsey\Uuid\Uuid;
// ...

$uploadedFiles = $request->getUploadedFiles();

/** @var UploadedFileInterface $file */
foreach ($uploadedFiles as $file) {#
    $extension = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION);
    $filename = sprintf('%s.%s', Uuid::uuid4(), $extension)
    //$contents = (string)$file->getStream();

    // Save file
    $file->moveTo('/path/to/public/img/uploads/' . $filename);

    // save filename in db
    // ...
}

Note that the ImageManager::make method expects an absolute (full) path to locate a file.

Thanks a lot for your help !

I have a strange issue :

$extension = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION);

This command does not work. It’s give me an empty string. I don’t now why because it’s the same line.

With more researches, I find that the getClientFilename() methods send (with a var_dump() : string(14) \"bound sendFile\"\n\"\"
So it’s logical that the pathinfo() methods doesn’t work.

Edit :
I have found the solution : The getClientFileName() methods doesn’t work if we had name property in the FormData javascript object.

So did we need to do 2 request with to respond to send an image and datas ?
For exemple if I have an obect like that :

{
  "objectName": "Some Object",
  "objectQuantity": 2,
  "objectPruchasePrice": 4500,
  "objectThumbnail": "filename.png"
}

Can I get all the data in JSON format and the image in one GET request ?
Or I need to make 2 request, one for the data and an other for the image ?

The pathinfo function works only for “valid” filenames. You could remove or replace all invalid characters before you use the pathinfo function. Generally, it is never very “safe” to use the client’s filename. So maybe consider a “fallback” to detect the correct extension.

You need only one request for the upload. The response from the POST (image upload) request could return a JSON object with the generated object values.