How to upload multiple images and files in Laravel with validation

Prerequisites

In this tutorial, we will learn how to upload multiple image and file to the database. we will need below-mentioned requirements for this tutorial

  1. Linux
  2. Laravel 5.8
  3. Mysql
  4. Web server Apache2

Step 1. Setting up the project

At the time of writing this article current version of Laravel is 5.8. Also, I am assuming you have already installed Laravel in your system. If not, you can follow below link for the installation of the latest Laravel project.

Install Laravel 5 On Linux Ubuntu 16.04 And 18.04

Step 2. Create a migration with model

To create migration with a model. Goto the application root directory. Eg: my application root directory is /var/www/html/uploadImage  and enter the following command.

php artisan make:model Post -m
php artisan make:model Image -m

Note: you can append -m keyword to create a migration.

The above command will create a migration with the model. Here I have created two migration

  1. To add the post data
  2. To add the post's images

Next, Add the post's required fields to the migration file.

<?php

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

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title');
            $table->text('body');
            $table->timestamps();
        });
    }

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

Next, add the required fields to the Image upload migration file

<?php

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

class CreatePostImagesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('post_images', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('post_id');
            $table->string('image_path');
            $table->timestamps();
        });
    }

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

Once you are done with adding the fields. Now the time to run the migration. To do so enter the following command

php artisan migrate

The above command will create two tables post and postImages table.

To verify if the table has been successfully created Login to MySQL. Here I am using my terminal to check the tables. you can use PHPMyAdmin or any other application you are comfortable with.

php artisan verify table

 

Step 3. Setting up the Laravel model relationship

Note: Here, I am setting the relationship to fetch the images by post. if you don't want you can skip this step.

We are using the post table to save the title and body of the blog and post_images table to store the images of the post.

Open Post Model and add the following code.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function images()
    {
    	return $this->hasMany('App\PostImage');
    }
}

Next, Open PostImage model and add the following function to complete the relationship between both tables.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class PostImage extends Model
{
    public function post()
    {
    	return $this->belongsTo('App\Post');
    }
}

Step 4. Define the routes in the web.php file

Setup the routes for the image upload. The route file can be located in routes/web.php

Route::get('create-post', 'PostController@index');
Route::post('create-post', 'PostController@store');

Step 5. Create the Controller 

Next, We will create the PostController where we define the image upload logic. To create the Controller Enter the following command

php artisan make:controller PostController

Now, go to App\Http\Controllers\PostController.php and add the following code to display the form

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostController extends Controller
{
    public function index()
    {
    	return view('createPost');
    }
}

Here I have defined a function with a named index which is returning a view file. Let's create a view file now.

Step 6. Create the form

To create a view file go to resources/views and create a new file called createPost and add the following code in it.

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Create Post</div>

                <div class="card-body">
                    <form method="post" action="/create-post" enctype="multipart/form-data">
                        {{ csrf_field() }}
                        <div class="form-group">
                            <label for="title">Title</label>
                            <input type="text" name="title" class="form-control" value="{{Request::old('title')}}">
                            @if($errors->has('title'))
                            <span class="help-block text-danger">{{ $errors->first('title') }}</span>
                            @endif
                        </div>

                        <div class="form-group">
                            <label for="title">Image/file</label>
                            <input type="file" name="images[]" class="form-control" multiple="">
                            @if($errors->has('images'))
                            <span class="help-block text-danger">{{ $errors->first('images') }}</span>
                            @endif
                        </div>

                        <div class="form-group">
                            <label for="title">Body</label>
                            <textarea name="body" class="form-control">{{Request::old('body')}}</textarea>
                            @if($errors->has('body'))
                            <span class="help-block text-danger">{{ $errors->first('body') }}</span>
                            @endif
                        </div>

                        <div class="text-center">
                            <button class="btn btn-primary">Submit</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Step 7. Validate the form and save the data

Next, We will validate the image upload and write the logic to upload the multiple image, save the post and save the image path to the database. To do so, create a new function store and paste the following code

public function store(Request $request)
{
	$validator = \Validator::make($request->all(), [
		'title' => 'required',
		'images' => 'required',
		'body' => 'required'
	])->validate();

	$post = new Post();
	$post->title = $request->title;
	$post->body = $request->body;
	$post->save();

	foreach ($request->file('images') as $image) {
		$postImage = new PostImage;
		$name = $image->getClientOriginalName();
		$path = public_path().'images/post/'.$post->id.'/'.$name;
		$image->move($path);
		$postImage->post_id = $post->id;
		$postImage->image_path = $path;
		$postImage->save();
	}

	return redirect()->back();
}

In the above code, I have added the validation of the title, body, and image with type. if the image input field does not contain jpg, png, etc it will throw the error and as you can see the above store function it will redirect back to the createPost.blade.php file and display the errors.  

Laravel Multiple image upload form