Using database to store images in Laravel 5.1

In this post I will show you how to store images in a database in Laravel 5.1. Almost for sure in most cases better solution would be to store the images (or other files) directly in the file system. There are some advantages of storing images in database, though. For example you can replicate and backup all your data much easier. Of course the database will be bigger and backup/replication slower.

There can be also other, not technical reasons to keep the images in the database. I don’t want to explore here the question is keeping the pics in the database is politically correct or not – it’s possible so why not to give it a try?

In this example we’ll build extremely simple application which will show the web page containing a table with list of pictures, their names and id’s. It will also allow you to add a picture.

Because we’re going to use database to store the data, what we need is working and configured Laravel 5.1 installation with a database. It can be MySQL, SQLite, Postgress or SQL Server.

We also need some extra functionality:

  • HTML Forms – to make HTML forms easily – not 100% necessary but it’s nice
  • Image manipulation – to be able to do things with images

Configuration

HTML Forms

Since version 5.1 to build and HTML form using HTML Forms (see: http://laravelcollective.com/docs/5.1/html) you have to install them separately as they was removed from the core of Laravel framework. Of course you don’t have to install this component and use pure HTML forms instead.

Installing HTML Forms in Laravel 5.1

Let’s begin by installing HTML Forms package through Composer. Edit your project’s composer.json file to require laravelcollective/html.

"require": {
    "laravelcollective/html": "5.1.*"
}
$ composer update

Next, add your new provider to the providers array of config/app.php:

  'providers' => [
    // ...
    Collective\Html\HtmlServiceProvider::class,
    // ...
  ],

Finally, add two class aliases to the aliases array of config/app.php:

 'aliases' => [
    // ...
      'Form' => Collective\Html\FormFacade::class,
      'Html' => Collective\Html\HtmlFacade::class,
    // ...
  ],

Image manipulation library

I’ve chosen Intervention Image package (see: http://image.intervention.io/).
Intervention Image is an open source PHP image handling and manipulation library. It provides an easier and expressive way to create, edit, and compose images and supports currently the two most common image processing libraries GD Library and Imagick.

Installing Intervention Image

$ composer require intervention/image

See http://image.intervention.io/getting_started/installation

Now when we have our extra packages installed we need to inform Laravel that we want access them in our application.

Add to configuration file ../config/app.php

 'providers' => [

    // ...
      Intervention\Image\ImageServiceProvider::class,
    // ...
  ],
'aliases' => [
    // ...
      'Image'     => Intervention\Image\Facades\Image::class,
    // ...
  ],

OK. At this point we’re done with configuration.

Creating the Application

Creating the database

To store an image in the database you have to use the blob field type. Let’s create customer database using migrations.
Open your terminal, go to the project root directory and type:

$ php artisan make:migration create_pictures_table
Created Migration: 2015_09_29_093244_create_pictures_table

Open up the migration file (should be in ../app/database/migrations/2015_09_29_093244_create_pictures_table.php) and fill it in:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePicturesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('pictures', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->binary('pic');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('pictures');
    }
}

Save it and back in the terminal execute the migration:

$ php artisan migrate

Now we have our database.

Routes

Route::get('list', 'PictureController@showPictureList');
Route::get('pic/{id}', 'PictureController@showPicture');
Route::get('add', 'PictureController@addPicture');
Route::post('add', 'PictureController@savePicture');

Creating the controller

$ php artisan make:controller ImageController --plain

Now we need few methods to:

  • show list of pictures
  • show a picture itself
  • add a picture to the database

Of course in real life you would like to have few more possibilities like editing and deleting.

<?php

namespace App\Http\Controllers;

use App\Picture;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Input;

use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Validator;
use Image;

class PictureController extends Controller
{
    public function showPictureList()
    {
        $pictures = Picture::all();
        return view('picturelist')->with('pictures', $pictures);
    }

    public function addPicture()
    {
        return view('addpicture');
    }

    public function savePicture(Request $request)
    {

         $file = Input::file('pic');
         $img = Image::make($file);
         Response::make($img->encode('jpeg'));

         $picture = new Picture;
         $picture->name = $request->get('name');
         $picture->pic = $img;
         $picture->save();


         return Redirect::to('list');
    }

    /*
     * Extracts picture's data from DB and makes an image 
     */
    public function showPicture($id)
    {
        $picture = Picture::findOrFail($id);
        $pic = Image::make($picture->pic);
        $response = Response::make($pic->encode('jpeg'));

        //setting content-type
        $response->header('Content-Type', 'image/jpeg');

        return $response;
    }

 

Views

We need two views. First to show the list of pictures and second to show the form to add a new picture. To show the mechanism I’ve created extremely simple views:

1. picturelist.blade.php

If anything needs explanation here it can be how we are showing the picture. You can’t just put {{ $picture->pic }} in the page because it will show raw binary data in the page. Instead we have to extract the data first, convert it to a proper type and return it as an image. This we’re doing using showPicture($id) method in the controller.

<!DOCTYPE html>
<html>
    <head>
        <title>Image list</title>
    </head>
    <body>
        <h1>My Pictures</h1>
        <p>
            <a href="add">Add picture</a>
        </p>
        <table border="1">
            <tr><td>Id</td><td>Name</td><td>Picture</td></tr>
            @foreach($pictures as $key => $picture)
                <tr><td>{{ $picture->id }}</td><td>{{ $picture->name }}</td><td><img src="pic/{{ $picture->id }}"></td></tr>
            @endforeach
        </table>


    </body>
</html>

 

2. addpicture.blade.php

What’s important here is that we have to explicitly say that we are uploading files with this form by adding ‘files’=>true to the array while creating the form:

Form::open(array('url' => 'add', 'files'=>true))

The view can look like this:

<!DOCTYPE html>
<html>
    <head>
        <title>Add Image</title>
    </head>
    <body>
        <h1>Add Image</h1>
        {!! Form::open(array('url' => 'add', 'files'=>true)) !!}
        <div>
            {!! Form::label('name', 'Name:') !!}
            {!! Form::text('name') !!}
        </div>
        <div>
            <p>
                {!! Form::label('Chose the picture:') !!}
                {!! Form::file('pic') !!}
            </p>

        </div>
        <div>
            {!! Form::submit('Add record') !!}
        </div>
    </body>
</html>

Comments appreciated.

Comments

  • Hi,

    Thank you for your tutorial.

    However, there are few mistakes which i need to point out.

    Firstly, the steps doesn't include Picture model creation -> php artisan make:model Picture
    The content of the file will be:
    ================================================
    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class Picture extends Model
    {
    protected $fillable = [
    'name', 'pic',
    ];

    }
    ===============================================

    Also Controller name is not correct:
    Should be =>php artisan make:controller PictureController

  • @Kaushik:
    You don't have to add fillable to your model if you save directly like in this case: $picture->save();
    You also don't need to
    use Intervention\Image\ImageManagerStatic as Image;
    Unless you don't have the aliases in config.php like this:
    'Image' => Intervention\Image\Facades\Image::class

    All of this is explained it the post.

  • @ender lobo:
    Si no me equivoco bytea es como se guarda las imágenes en Postgresql, ¿no?
    Pues, diría que antes de todo tienes que convertirlo al objeto usando Intervention Image de esa manera:
    $pic = Image::make($picture->pic);
    Si consigas eso, todo el resto no será ningún problema.

  • image was inserted successfully . but unable to store images with large size
    how can i add large image file.

  • @ronit
    it can be the database field type.
    If it's big you should use longtext or longblob.

Leave a comment

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