Recording the images directly into the database is, most of the time, conceptually wrong. It should be avoided with all force to record images in database blobs. What should be stored in the database is a URI (Universal Resource Identifier) indicating the location of the image, it is even better to place a relative URI, which facilitates mass relocation of the images in the future.
Some disadvantages of saving images in a database
- Absurd (and unnecessary) growth of the database
- Higher cost of using the database
- Difficulty of horizontal scaling
- Difficult mass processing of images
- Need to implement image caching on your own
- Impossibility of using CDN (Content Delivery Network)
- Inability to enjoy low cloud storage prices
- Inability to benefit from services such as Amazon S3, Cloudfront, Azure Storage, etc.
- You cannot type direct HTML by pointing to the image URL
- Your images become dynamic, non-static content (spending your application/server’s CPU the simple fact of serving an image).
And those are just the ones I immediately remembered when writing that reply!
NOTE: I will detail each of these disadvantages as I refine the answer, but I need more time to do so. So go back to that answer from time to time if you’re interested in knowing more about each of these drawbacks.
How to send image to APPS
You don’t need to send images to Apps through JSON. Virtually all framerworks for application development can upload images directly from Urls, making it trivial to upload your images if they are stored on file/content servers like Amazon S3, or Azure Storage.
In android, for example, to load any image just use the following code in Java excellent library Glide:
Glide
.with(this)
.load(url) // qualquer URL acessível!!!
.into(meuImageView); // ImageView é um objeto que exibe imagens no android
The library already takes care of using an advanced HTTP client, which allows access via HTTPS, multiple attempts in case of download failure, expects reestablishment of the internet connection, etc. That is, much easier than passing the image as JSON, which would make the call size much larger (an order of magnitude larger) and still require code to interpret JSON on the client. Already send the URL directly allows the client to display it without difficulty.
Still, if you want to send the image as JSON, nothing prevents you from doing a "GET" on your server and reading the image as an array of bytes (like you would with the blob) and then encapsulating it in a JSON response. However, I repeat: this is a conceptual error!
To save the image to Amazon S3
Laravel provides powerful file system abstraction using the package Flysystem created by Frank de Jonge. Documentation of this feature can be seen on the page: https://laravel.com/docs/5.3/filesystem (outside the scope of that answer duplicate the configuration information of that library. Just read the documentation)
We can automatically use file system abstractions to record directly to Amazon S3. Below we see a way to do this.
Include the use where needed:
use Illuminate\Support\Facades\Storage;
Modify the original code to:
$file = $request->file('BLOB');
$name = $file->getPathName();
// o método putFile retorna a URL do arquivo conforme armazenado
// estou assumindo que $name tenha o caminho para o arquivo sendo gravado
$url = Storage::putFile('imagens', new File($name), 'public');
$imagem = Imagem::create([
'CdProduto' => $request->CdProduto,
'NmImagem' => $request->NmImagem,
'DscImagem' => $request->DscImagem,
'URL' => $url,
'FlgPrincipal' => $request->FlgPrincipal
]);
Note that you must have already created one Bucket on Amazon S3 and configured, according to the already referenced documentation of Laravel, the Filesystem
with your Bucket data and Amazon account.
To burn to local disk
The same Laravel file system abstraction allows you to write to the local file system. Even, this is the default behavior. So just leave the setting as default that your images will be saved automatically in the path: storage/app/public
. Directly from the documentation:
The public disk is intended for files that are going to be publicly
accessible. By default, the public disk uses the local driver and
Stores These files in Storage/app/public. To make them accessible from
the web, you should create a Symbolic link from public/Storage to
Storage/app/public. This Convention will Keep your publicly accessible
files in one directory that can be easily Shared Across Deployments
when using zero down-time Deployment systems like Envoyer.
The only change in the code would be the removal of the 'public'
of the image save call:
$url = Storage::putFile('imagens', new File($name));
That’s why this file system abstraction is so powerful: just modify the setting to write to local disk, or to Amazon S3, for example.
Note on hosting
If you are going to host this system on a shared hosting, be careful as you may not have full access to the file system. Or you can have access, but with very little space. Also the file system can be cleaned, automatically, from time to time. And it can be difficult to backup the images as it may not have FTP to the file system from where the system is hosted. And in the end, you may have access to the file system and it will not be publicly visible, which will make it impossible to pass the images through a public URL.
My suggestion is to use real professional hosting, and to hire file storage services, such as Amazon with Amazon S3. The advantages are huge and the cost is very low (you pay less than 0.12 (twelve cents) on average per Gigabyte!). And it gains the benefits of having images accessible (and with access control if you want) by Urls. However, you need to study at least the basics of Amazon S3 to use it correctly, which is pretty easy at the end of the day.
It is usually saved in the bank only the
path
image and the image itself is saved in a directory. And when you need to recover this image just recover thepath
from the bank and charge it.– JcSaint
Yes, but in case you need to use this image via json, for example in an app ?
– Renan Rodrigues