Today we are going to make simple & yet beautiful photo and image gallery in laravel.
It is very important for general websites of clients to make one image gallery that is linked with database, so that user can easily upload their own photos and images in their website.
Lets get Going..
What we are going to do ?
- Create form for multiple image upload.
- Creating table and fields to store images name in the database.
- Writing function and routes to upload images in the database.
Lets create form by creating new view in resources/views
folder named imageupload.blade.php.
Lets create the form.
I am using bootstrap to make elegant design quickly, make sure you have also used the bootstrap CDN as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" /> <!-- Optional theme --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" /> <!-- Latest compiled and minified JavaScript --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <div class="container"> <form action="{{url('upload-image')}}" method="POST" role="form" enctype="multipart/form-data"> {!! csrf_field() !!} <legend>Form title</legend> <div class="form-group"> <label for="">title</label> <input type="text" name="title" class="form-control"/> </div> <div class="form-group"> <label for="">Image</label> <input type="file" name="image[]" multiple="true"> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> </div> |
Now, lets create database. Go to command line
and write php artisan make:model tbl_images -m
. By now you must have created the model and migration file.
Go to / database / migrations
and select your migration file and create the fields like one below. Take a look at my migration file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateTblImagesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('tbl_images', function (Blueprint $table) { $table->increments('img_id'); $table->string('title'); $table->string('image'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('tbl_images'); } } |
Since, we have assigned different primary key we need to specify it in our recent created tbl_images
model. Open up model add the function like below in your model.
1 2 3 4 5 6 7 8 9 10 11 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class tbl_images extends Model { protected $table = 'tbl_images'; protected $primaryKey = 'img_id'; } |
Now, lets run php artisan migrate:refresh
to create fields and they should now be like the image below.
Now let us create routes and functions
to load this view file via browser.
Go to Application folder / Routes / web.php
and write these codes to load the view file into the browser.
1 2 3 4 |
Route::get('multiupload',function(){ $images = DB::table('tbl_images')->get(); return view('multiupload.imageupload',['images'=>$images]); }); |
Now, the multiple image upload code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Route::post('upload-image',function(){ $data = Input::except('_token'); $picture = ''; if (Input::hasFile('image')) { $files = Input::file('image'); foreach($files as $file){ $filename = $file->getClientOriginalName(); $extension = $file->getClientOriginalExtension(); $picture = date('His').$filename; $destinationPath = public_path().'/uploads'; $file->move($destinationPath, $picture); DB::table('tbl_images')->insert(['image'=>$picture,'title'=>$data['title']]); } } if (!empty($data['image'])) { $data['image'] = $picture; } else { unset($data['image']); } return redirect('multiupload'); }); |
Now try visiting the url with above routes.
In my case it would be http://localhost/app/imageupload.
Try adding some of the images and you will view the image gallery just like below.
Image gallery has been created but, we need to create an zoom in image effect when the image is clicked. So lets add zoom in effect by using jQuery maginific pop-up and css to make it more elegant.
You can download jQuery Magnific-PopUp Code from here.
Add this jquery code just above the div where you have loaded the image in resources/views
/ imageupload.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<script type="text/javascript"> $(document).ready(function() { $('.image-popup-vertical-fit').magnificPopup({ type: 'image', closeOnContentClick: true, mainClass: 'mfp-img-mobile', image: { verticalFit: true } }); $('.image-popup-fit-width').magnificPopup({ type: 'image', closeOnContentClick: true, image: { verticalFit: false } }); $('.image-popup-no-margins').magnificPopup({ type: 'image', closeOnContentClick: true, closeBtnInside: false, fixedContentPos: true, mainClass: 'mfp-no-margins mfp-with-zoom', // class to remove default margin from left and right side image: { verticalFit: true }, zoom: { enabled: true, duration: 300 // don't foget to change the duration also in CSS } }); }); </script> |
Little bit of CSS for design. Its my style, but you may want to make it work the way you want.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<style type="text/css"> <style type="text/css"> /* padding-bottom and top for image */ .mfp-no-margins img.mfp-img { padding: 0; } /* position of shadow behind the image */ .mfp-no-margins .mfp-figure:after { top: 0; bottom: 0; } /* padding for main container */ .mfp-no-margins .mfp-container { padding: 0; } .mfp-with-zoom .mfp-container, .mfp-with-zoom.mfp-bg { opacity: 0; -webkit-backface-visibility: hidden; -webkit-transition: all 0.3s ease-out; -moz-transition: all 0.3s ease-out; -o-transition: all 0.3s ease-out; transition: all 0.3s ease-out; } .mfp-with-zoom.mfp-ready .mfp-container { opacity: 1; } .mfp-with-zoom.mfp-ready.mfp-bg { opacity: 0.8; } .mfp-with-zoom.mfp-removing .mfp-container, .mfp-with-zoom.mfp-removing.mfp-bg { opacity: 0; } </style> </style> |
Now bind your image with the class image-popup-no-margins
to give the zoom in effect. Check below how it looks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<link rel="stylesheet" type="text/css" href="{{URL::to('public/dist/magnific-popup.css')}}"> <script src="{{url('public/dist/jquery.magnific-popup.min.js')}}"></script> <div class="container"> <div class="row"> @if(isset($images)) @if(count($images)>0) @foreach($images as $image) <div class="col-sm-3" style="height: 200px"> <a class="image-popup-no-margins" href=""><img src="{{url('public/uploads')}}/{{$image->image}}" class="img img-thumbnail" alt=""></a> <br> <center><strong>{{$image->title}}</strong></center> </div> @endforeach @endif @endif </div> </div> |
Now your Final Code looks like this :-
imageupload.blade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
<!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" /> <!-- Optional theme --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" /> <!-- Latest compiled and minified JavaScript --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <link rel="stylesheet" type="text/css" href="{{URL::to('public/dist/magnific-popup.css')}}"> <script src="{{url('public/dist/jquery.magnific-popup.min.js')}}"></script> <script type="text/javascript"> $(document).ready(function() { $('.image-popup-vertical-fit').magnificPopup({ type: 'image', closeOnContentClick: true, mainClass: 'mfp-img-mobile', image: { verticalFit: true } }); $('.image-popup-fit-width').magnificPopup({ type: 'image', closeOnContentClick: true, image: { verticalFit: false } }); $('.image-popup-no-margins').magnificPopup({ type: 'image', closeOnContentClick: true, closeBtnInside: false, fixedContentPos: true, mainClass: 'mfp-no-margins mfp-with-zoom', // class to remove default margin from left and right side image: { verticalFit: true }, zoom: { enabled: true, duration: 300 // don't foget to change the duration also in CSS } }); }); </script> <style type="text/css"> <style type="text/css"> /* padding-bottom and top for image */ .mfp-no-margins img.mfp-img { padding: 0; } /* position of shadow behind the image */ .mfp-no-margins .mfp-figure:after { top: 0; bottom: 0; } /* padding for main container */ .mfp-no-margins .mfp-container { padding: 0; } .mfp-with-zoom .mfp-container, .mfp-with-zoom.mfp-bg { opacity: 0; -webkit-backface-visibility: hidden; -webkit-transition: all 0.3s ease-out; -moz-transition: all 0.3s ease-out; -o-transition: all 0.3s ease-out; transition: all 0.3s ease-out; } .mfp-with-zoom.mfp-ready .mfp-container { opacity: 1; } .mfp-with-zoom.mfp-ready.mfp-bg { opacity: 0.8; } .mfp-with-zoom.mfp-removing .mfp-container, .mfp-with-zoom.mfp-removing.mfp-bg { opacity: 0; } </style> </style> <div class="container"> <form action="{{url('upload-image')}}" method="POST" role="form" enctype="multipart/form-data"> {!! csrf_field() !!} <legend>Form title</legend> <div class="form-group"> <label for="">title</label> <input type="text" name="title" class="form-control"/> </div> <div class="form-group"> <label for="">Image</label> <input type="file" name="image[]" multiple="true"> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> </div> <div class="container"> <div class="row"> @if(isset($images)) @if(count($images)>0) @foreach($images as $image) <div class="col-sm-3" style="height: 200px"> <a class="image-popup-no-margins" href=""><img src="{{url('public/uploads')}}/{{$image->image}}" class="img img-thumbnail" alt=""></a> <br> <center><strong>{{$image->title}}</strong></center> </div> @endforeach @endif @endif </div> </div> |
routes
/ web.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
Route::get('multiupload',function(){ $images = DB::table('tbl_images')->get(); return view('multiupload.imageupload',['images'=>$images]); }); Route::post('upload-image',function(){ $data = Input::except('_token'); $picture = ''; if (Input::hasFile('image')) { $files = Input::file('image'); foreach($files as $file){ $filename = $file->getClientOriginalName(); $extension = $file->getClientOriginalExtension(); $picture = date('His').$filename; $destinationPath = public_path().'/uploads'; $file->move($destinationPath, $picture); DB::table('tbl_images')->insert(['image'=>$picture,'title'=>$data['title']]); } } if (!empty($data['image'])) { $data['image'] = $picture; } else { unset($data['image']); } dump($data); return redirect('multiupload'); }); |
Thats it, now you would have cool looking jQuery image gallery using laravel.
Mike Jones says
Im not sure if its just me. but i was unable to get this to work with Laravel 7.
i had to Import Symphony components to accept the input for this;
Route::post(‘upload-image’,function(){
$data = Input::except(‘_token’);
$picture = ”;
if (Input::hasFile(‘image’)) {
But then i failed at the except bit.
Shashank Bhattarai says
Can you send me dd(Input). May be the CSRF token is not present in your form. If also showing error you can try one of the options.
1. Try replacing Input::except(‘_token’) to Input::all();
2. Also you can pass function(Request $request) into the function parameter. Yes you have to import some components from symphony. Once it is done your final code will look something like this.
Route::post(‘upload-image’, function(Request $request){ // imports that use this use Illuminate\Http\Request;
$data = $request->except(‘_token’); // Even if its failing then, your CSRF token it not present in your form. If you are using ajax to do this just use $request->all()
$picture = ”;
if ($request->hasFile(‘image’)) {