Uploading the image in Laravel is very easy! So if you are beginners then you can do that simply. Laravel provides a very simple way to create file uploading with proper validation like max file size 2mb, file extension should be jpeg, png, jpg, gif or SVG etc.
In this post, I will walk you through how we can add the profile image to Laravel’s default authentication which comes out of the box.
By the end of this post, you will have a working example like below.
Laravel Image Upload Made Easy
So let’s start.
I assume, you already have fresh Laravel project, if not go and create with below command.
composer create-project laravel/laravel LaravelImageUpload
Now, open .env
file which is located int the root of your LaravelImageUpload project folder. Update the database credentials with your ones.
Once you have connected a database to Laravel, run below command to generate default Laravel’s authentication scaffolding.
php artisan make:auth
Once you have generated the scaffold, we are ready to start.
Laravel provides you a User model and migration for this model by default. Go to database/migrations
folder and open 2014_10_12_000000_create_users_table file.
We will be uploading a profile image for currently authenticated user, so we need to add an extra field in which we will store the image file path. Update the up()
method with below one:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('profile_image')->nullable(); // our profile image field
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
As you have noticed that, we have added a new field called profile_image and set its type to string. Notice that we have added a nullable()
flag to new fields to keep this image uploading optional for users.
Once you have updated your migration, run below command to create all your migrations.
php artisan migrate
Now if you, check your database you will be able to see that Laravel will create two tables called users and password_resets.
Now it’s time to update our User mode. Open app/User.php
file and add profile_image
to $fillable array.
protected $fillable = ['name', 'email', 'password', 'profile_image'];
Also we will add a new accessor method to get the user’s profile image like so auth()->user()->image
instead of using profile_image
field. So add below code within User class.
public function getImageAttribute()
{
return $this->profile_image;
}
After migrating tables and updating User model, now we need to setup a new page with form where we will be able to upload image. So for that create two routes in your web.php
routes file. Like so:
Route::get('/profile', 'ProfileController@index')->name('profile');
Route::post('/profile/update', 'ProfileController@updateProfile')->name('profile.update');
As you have noticed that we have used ProfileController in above routes, so run below command to create a new controller.
php artisan make:controller ProfileController
Now open your newly created controller and update with below code:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('auth.profile');
}
}
As you have seen in the __construct() method we have set up the middleware so only authenticated users will be able to update their profile.
In index()
method we are just loading a new view called profile
which is residing inside authfolder generated by Laravel.
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header">Profile</div>
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
<div class="container">
<div class="row">
<div class="col-12">
@if ($errors->any())
<div class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<ul>
@foreach ($errors->all() as $error)
<li>
{{ $error }}
</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('profile.update') }}" method="POST" role="form" enctype="multipart/form-data">
@csrf
<div class="form-group row">
<label for="name" class="col-md-4 col-form-label text-md-right">Name</label>
<div class="col-md-6">
<input id="name" type="text" class="form-control" name="name" value="{{ old('name', auth()->user()->name) }}">
</div>
</div>
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">Email</label>
<div class="col-md-6">
<input id="email" type="text" class="form-control" name="email" value="{{ old('email', auth()->user()->email) }}" disabled>
</div>
</div>
<div class="form-group row">
<label for="profile_image" class="col-md-4 col-form-label text-md-right">Profile Image</label>
<div class="col-md-6">
<input id="profile_image" type="file" class="form-control" name="profile_image">
@if (auth()->user()->image)
<code>{{ auth()->user()->image }}</code>
@endif
</div>
</div>
<div class="form-group row mb-0 mt-5">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">Update Profile</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
profile.blade.php
Above code example is just bootstrap template with a form to upload an image. In form’s action we have added {{ route('profile.update') }}
route, so when we will submit this form it will hit that route.
Next, we have a input field for user name and loading it’s current value using authentication helper like this auth()->user()->name
.
Next, we have a input field for user email and loading its value in value
attribute. I’m keeping this field disabled so that email change is not possible.
Now, we need to add a drop-down menu for the currently authenticated user to access the profile page. For that in your resources/views/layouts/app.blade.php
file add below line of code just before the Logout dropdown item.
<a class="dropdown-item" href="{{ route('profile') }}">Profile</a>
Now if you click on the Profile link it will load the below view.
Profile Page
After finishing our view templates modification, now we need to configure our file system where we will be uploading images. Go to config/filesystem.php
file and change the settings for public
disk with below.
'public' => [
'driver' => 'local',
'root' => public_path(),
'url' => env('APP_URL').'/public',
'visibility' => 'public',
],
You can handle the image uploading logic within your controller, but I would like to separate this logic into a trait which we can use later on if we need to upload images.
In your app folder, create folder called Traits and add a php file called UploadTrait.php. Add below code snippet in it.
namespace App\Traits;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
trait UploadTrait
{
public function uploadOne(UploadedFile $uploadedFile, $folder = null, $disk = 'public', $filename = null)
{
$name = !is_null($filename) ? $filename : str_random(25);
$file = $uploadedFile->storeAs($folder, $name.'.'.$uploadedFile->getClientOriginalExtension(), $disk);
return $file;
}
}
In the above code example, we are creating a new function called uploadOne
which will handle the file uploading by taking the uploaded image, folder, disk, and filename parameters.
Firstly, we are checking if a filename has been passed, if not then we are creating a random string name.
Next we are uploading the file using UploadedFile‘s storeAs
method and returning the file we just stored. Nothing fancy.
After setting up the filesystem and creating a trait, it’s the time now to use the trait in our ProfileController for handling the form submission. As we already have created a route which will hit the updateProfile method. So let’s add that method. Use the below code example, and replace your current ProfileController with this one.
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
use App\Traits\UploadTrait;
class ProfileController extends Controller
{
use UploadTrait;
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('auth.profile');
}
public function updateProfile(Request $request)
{
// Form validation
$request->validate([
'name' => 'required',
'profile_image' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048'
]);
// Get current user
$user = User::findOrFail(auth()->user()->id);
// Set user name
$user->name = $request->input('name');
// Check if a profile image has been uploaded
if ($request->has('profile_image')) {
// Get image file
$image = $request->file('profile_image');
// Make a image name based on user name and current timestamp
$name = str_slug($request->input('name')).'_'.time();
// Define folder path
$folder = '/uploads/images/';
// Make a file path where image will be stored [ folder path + file name + file extension]
$filePath = $folder . $name. '.' . $image->getClientOriginalExtension();
// Upload image
$this->uploadOne($image, $folder, 'public', $name);
// Set user profile image path in database to filePath
$user->profile_image = $filePath;
}
// Persist user record to database
$user->save();
// Return user back and show a flash message
return redirect()->back()->with(['status' => 'Profile updated successfully.']);
}
}
Above code is self-explained, we have injected our trait into this controller and added a updateProfile method.
After updating the ProfileController, if you now go to the profile page and submit an image it should be working as expected. Try to upload a wrong file type and you will get the validation errors displayed as well like below.
Image Upload Validation
Image Upload Validation
By now you should have a fully functional image upload profile section. One last thing we need to show the currently uploaded image next to the username in header like in the demo image. For that in your app.blade.php
layout file, replace this:
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }} <span class="caret"></span>
</a>
with this:
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
@if (auth()->user()->image)
<img src="{{ asset(auth()->user()->image) }}" style="width: 40px; height: 40px; border-radius: 50%;">
@endif
{{ Auth::user()->name }} <span class="caret"></span>
</a>
Now if you upload an image again, you will be able to see the uploaded image before the user name.
Great! we have successfully created a profile update section with Laravel Image Upload. You can find the Source Code of the above example on Github.
If you have any question or suggestion to improve this post, please let me know in the comments box below.
Recommended Reading
☞ Laravel Performance Optimization: Guide to a Perfect Laravel Developer
☞ How to remove multiple keys from PHP Array?
☞ Learn how to create your first Laravel package
☞ Laravel 5.8 Tutorial - Datatables Dropdown Filter Server-side using Ajax
☞ How to Install Laravel Local Dev Environment On Ubuntu
☞ Laravel Eager Loading Tutorial
☞ How to resize image in Laravel 5.8 App
#laravel #php