Laravel Tutorials - Laravel Image Upload Tutorial

Laravel Image Upload Tutorial

2020-03-08 Lukas Markevičius
Laravel Image Upload Tutorial featured image

If you followed my tutorial on How to create Step by Step Laravel Project you should have learned how to make a basic blog platform in which the users can create their posts. Today we are going to upgrade this application by adding an ability to upload images. If you want you can get a source code from which I started this tutorial.

Clone the repository and in your terminal run:

$ git checkout create-slugs -b <your-branch-name>

For this functionality we will be using Intervention Image library. So lets get started on how to create a Laravel image upload functionality. You will learn:

How to upload image to the server

First of all, we need to install image library into our project. To do this we need to have composer and enter this command in terminal:

$ composer require intervention/image

After the files have been downloaded we need to open our config/app.php file and add one line at the bottom of the providers array:

Intervention\Image\ImageServiceProvider::class

and one to the aliases:

'Image' => Intervention\Image\Facades\Image::class

After we've done this we need to create another column in the posts table to store image filename. To do that we need to create a migration file:

$ php artisan make:migration add_image_column_to_posts --table=posts

And in newly created file we specify our column for image:

<?php

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

class AddImageColumnToPosts extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
          $table->string('image')->after('slug')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
          $table->dropColumn('image');
        });
    }
}

Now we need to migrate it to the database by entering this command:

$ php artisan migrate

We now have successfully setup everything for our image upload. We can now add new input field for the image in the post create page. If you are following this tutorial with the source code you will find create.blade.php file in the resources/views/post folder. First we need to add a new attribute enctype="multipart/form-data" to the form so that it could accept file uploads:

...
<form method="POST" action="{{ route('post.store') }}" enctype="multipart/form-data">
    @csrf
...

Then we add a new input field for the image file:

...
<div class="form-group">
    <label for="slug">Slug</label>
    <input type="text" name="slug" class="form-control" value="{{ old('slug') }}" placeholder="post-slug">
</div>

<div class="form-group">
    <label for="image">Post Image</label>
    <input type="file" class="form-control-file" name="image">
</div>

<div class="form-group">
    <label for="description">Description</label>
    <textarea name="description" rows="8" cols="80" class="form-control">{{ old('description') }}</textarea>
</div>
...

Now we can open PostController.php file and add additional code to store method for saving the image:

...
public function store(Request $request)
{
      $validatedData = $this->validate($request, [
        'title'         => 'required|min:3|max:255',
        'slug'          => 'required|min:3|max:255|unique:posts',
        'image'         => 'sometimes|image',
        'description'   => 'required|min:3'
      ]);

      $validatedData['slug'] = Str::slug($validatedData['slug'], '-');

      $post = Post::create($validatedData);

      if ($request->hasfile('image')) {
        $image = $request->file('image');
        $filename = time() . '.' . $image->getClientOriginalExtension();
        $location = storage_path('app/public/images/') . $filename;

        Image::make($image)->save($location);

        $post->image = $filename;
        $post->save();
      }
      
      return redirect()->route('post.index');
}
...

For this example we validate image input field so that it would be not mandatory and the file would be only an image. Then we generate a new filename with the time() function, create a file location and save it to the server and then we store the filename to the database. For the location we are using storage path images folder which we need to create ourselves inside storage/app/public folder. Also don't forget to include Image class at the top:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Post;
use Image;
...

How to display image

We can now test it ourselves. If everything ran smoothly you should be able to save the post without any errors. We now can show this image in our post show view:

...
<div class="card-body">
    @if ($post->image)
        <img src="{{ asset('storage/images/' . $post->image) }}" alt="{{ $post->title }} photo" class="img-fluid">
    @endif

    <p>{{ $post->description }}</p>
...

Also to access files from storage folder we need to create a symbolic link. You can do so by running command in your terminal:

$ php artisan storage:link

How to edit and delete image from the server

We will add an image upload functionality to the post edit page too. In our edit.blade.php file we need to add the same attribute to form as before:

...
<form method="POST" action="{{ route('post.update', $post->slug) }}" enctype="multipart/form-data">
    @csrf
    @method('PUT')
...

Then we will add an image input field and display current image filename so that we would know that it exists: 

...
<div class="form-group">
    <label for="slug">Slug</label>
    <input type="text" name="slug" class="form-control" value="{{ $post->slug }}" placeholder="post-slug">
</div>

<div class="form-group">
    <label for="image">Post Image</label>
    @if ($post->image)
        <ul>
            <li>{{ $post->image }}</li>
        </ul>
    @endif
    <input type="file" class="form-control-file" name="image">
</div>
...

In our PostController.php update method we do almost the same thing except if the user uploads the new image we want to delete the old one from the server so that it wouldn't take up our server storage space:

...
public function update(Request $request, Post $post)
{
      $validatedData = $this->validate($request, [
        'title'         => 'required|min:3|max:255',
        'slug'          => 'required|min:3|max:255|unique:posts,id,' . $post->slug,
        'image'         => 'sometimes|image',
        'description'   => 'required|min:3'
      ]);

      $validatedData['slug'] = Str::slug($validatedData['slug'], '-');

      $post->update($validatedData);

      if ($request->hasfile('image')) {
        Storage::disk('public')->delete("images/$post->image");

        $image = $request->file('image');
        $filename = time() . '.' . $image->getClientOriginalExtension();
        $location = storage_path('app/public/images/') . $filename;

        Image::make($image)->save($location);

        $post->image = $filename;
        $post->save();
      }

      return redirect()->route('post.show', $post);
}
...

Also don't forget to include Storage class at the top:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Post;
use Image;
use Storage;
...

Lastly, we need to delete image from the server when we delete our post. We can do that by adding one line in a destroy function in our post controller:

...
public function destroy(Post $post)
{
      Storage::disk('public')->delete("images/$post->image");
      $post->delete();

      return redirect()->route('post.index');
}
...

And that is it! You now know how to upload image in Laravel by using Intervention image library. If you had any troubles following this tutorial just let me know down below in the comments.

If you want to get a complete source code of this tutorial you can get it from here. Just don't forget to checkout to create-images tag:

$ git checkout create-images -b <your-branch-name>
Laravel Image Upload Tutorial pinterest image

Related Tutorials

How to Generate a Simple XML Sitemap using Laravel

Posted 2020-03-08 Lukas Markevičius

Today we are going to learn how to generate a simple XML sitemap using Laravel. Mainly you can create it either manually or create some sort of automated solution. To create it manually you can make y...

How to Create Slugs in Laravel

Posted 2020-03-27 Lukas Markevičius

Today we are going to learn how to create slugs in Laravel. You are going to learn: Why use slugs How to create slugs How to show objects with the slugs How to edit slugs Why use Slugs If yo...

Back