Image blob and cache problems

Asked

Viewed 890 times

0

I’m having trouble with images BLOB, programming is being done with the framework Laravel in versão 5.2. The mini world is next:

I upload the file and save only one BLOB, I don’t do any size validation or anything like just save the BLOB and other data like image name, etc...

Something use the image together from tag html <img src="MEU BLOB"/>, strange behavior is triggered, randomly and the images do not appear. When checking the code it is written perfectly, but it is not compiled.

Doing some tests I realized that when I clear the browser cache, some images appear and others are still missing. To validate this test I cleaned several times and every time, hours appeared some images hours appeared another. I identified with this that probably the cache has a size, and the images were filling this cache due to this hours appeared and hours not some images.

Here comes my question:

I’d have some way to fix this without doing the resize image, because the idea is to have image of various sizes, the right thing would be to decrease the image quality.

By the way of increnmento my question, today I am saving the image so:

    $file = $request->file('BLOB');
    $name = $file->getPathName();
    $file = base64_encode(file_get_contents($name));
    $src = 'data: image/jpg;base64,'.$file;

    $imagem = Imagem::create([
        'CdProduto' => $request->CdProduto,
        'NmImagem' => $request->NmImagem,
        'DscImagem' => $request->DscImagem,
        'BLOB' => $src,
        'FlgPrincipal' => $request->FlgPrincipal
    ]);

I need to make sure that all images will be uploaded, due to the project being related to the product.

I ask a question would be more feasible not to save this image in BLOB, but a fixed file on disco ? Or both, it’s a plausible solution ?

  • 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 the path from the bank and charge it.

  • Yes, but in case you need to use this image via json, for example in an app ?

1 answer

1


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

  1. Absurd (and unnecessary) growth of the database
  2. Higher cost of using the database
  3. Difficulty of horizontal scaling
  4. Difficult mass processing of images
  5. Need to implement image caching on your own
  6. Impossibility of using CDN (Content Delivery Network)
  7. Inability to enjoy low cloud storage prices
  8. Inability to benefit from services such as Amazon S3, Cloudfront, Azure Storage, etc.
  9. You cannot type direct HTML by pointing to the image URL
  10. 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.

  • I could add in your reply, how you would make this use (saving the image in the best way) as explained by you in your reply ?

  • 1

    @Renanrodrigues will depend a lot on your architecture! Where will you record this image? If you are going to write, for example, to an Azure blob you have to use their client library for PHP. If you are going to write to Amazon S3, you can use the great flysystem.php library. Virtually all your questions can be answered in the Laravel documentation: https://laravel.com/docs/5.3/filesystem (but I will update the answer with a suggested code, estimating how your architecture works, where the file comes from to record, etc.)

  • I intend to take the service initially with a shared hosting, like localweb.

  • I mean saving the image in a specific folder or something like

  • 1

    @Renanrodrigues I gave an example to record on Amazon S3, because I thought you trivial record in a folder. Do not refrain from reading the documentation of the Variable, because it is up to you to understand how it works, otherwise I will simply copy the documentation from there to here and this is outside the scope of the Stack Overflow! Still, to write to the local disk you can use Flysystem itself. It records, as reported at the beginning of the documentation, by default on storage/app/public. Now, if you are going to host a Locaweb of life, beware because you may not have access to the filing system, or have no space!

  • @Renanrodrigues try reading the answer in http://stackoverflow.com/a/29704990/285678 ... You need to make the correct use. How you were dealing with files before?

  • is actually missing some dependencies, looking for found this https://github.com/GrahamCampbell/Laravel-Flysystem I’m following further seeing that there are many changes, maybe it is feasible for a more complete response, and beforehand leaving the context of the question more using as increment it is nice to put the installation part. I’ll see if I can do it myself

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.