Table of Contents
File uploads is very basic functionality which require in almost all web-applications. It includes various file types like Images, PDFs, etc. In this tutorial i will show you how to upload Image/File with validation in laravel 6. We will also see file validations as well.
Lets start file upload tutorial in laravel 6 by installing fresh laravel using below command.
composer create-project --prefer-dist laravel/laravel laravel-file-upload
Now update database credentials in .env
file.
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=lara-file DB_USERNAME=root DB_PASSWORD=
Next, start server using below command.
php artisan serve
In this tutorial, we will make simple form which upload any document such as Image
, PDF
, Doc
etc. and list them out.
Lets create document migration using below artisan migration command.
php artisan make:migration create_documents_table
This command will generate document migration file under database/migrations
directory. Open document migration file and add two fields title
and file_url
as shown below.
2019_09_13_150436_create_documents_table.php
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateDocumentsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('documents', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('title'); $table->string('file_url')->nullable(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('documents'); } }
Next, lets make a document model file using below artisan command.
php artisan make:model Document
This command will generate document model file Document.php
under app/
directory. Open Document.php
file and add table fields for mass assignable.
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Document extends Model { /** * The attributes that are mass assignable. * * @var array */ protected $fillable = ['title', 'file_url']; }
Next create document controller using below artisan command.
php artisan make:controller DocumentController --resource
This command will create DocumentController.php
file under app/Http/Controllers
directory as shown below. The controller will contain a method for each of the available resource operations. Resource operations like CRUD (CREATE, READ, UPDATE and DELETE). tiktok izlenme satın al
DocumentController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class DocumentController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { // } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { // } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { // } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { // } }
This is default DocumentController with resource route methods generated by make:controller artisan command. We can easily create CRUD using this controller.
Next, we will add route in web.php
file. Open routes/web.php
file and add document routes as shown below.
web.php
<?php /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::get('/', function () { return redirect('document'); }); Route::resource('document', 'DocumentController'); Route::post('update-document/{id}', ['as' => 'update-document', 'uses' => '[email protected]']);
Let me explain routes here.
- First route is responsible to redirect on document route, because we haven’t anything on homepage ‘/’ to display users.
- Second route is Resource route which is responsible for CREATE, READ, UPDATE and DELETE operation for document.
- Third route is responsible for document update operation as we have to deal with file and PUT HTTP method has some bad experience to upload file.
List All Documents
To list all the documents, lest use index method of controller and display data in index.blade.php
layout file.
DocumentController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Document; class DocumentController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { $docs = Document::all(); return view('document.index', ['docs' => $docs]); } // Other Methods }
index.blade.php [Layout File]
index.blade.php layout file is responsible to display all document in list view. It extends main layout file layout.blade.php
@extends('layout') @section('content') <div class="control-btn float-right"> <a href="{{ route('document.create') }}" class="btn btn-primary">Add File</a> </div> <div class="title"> <h1>Documents</h1> </div> @if (session('success')) <div class="alert alert-success" role="alert"> {{ session('success') }} </div> @endif @if (session('error')) <div class="alert alert-danger" role="alert"> {{ session('error') }} </div> @endif <table class="table table-bordered"> <thead> <tr> <th>Title</th> <th>File Name</th> <th>Actions</th> </tr> </thead> <tbody> @forelse ($docs as $doc) <tr> <td>{{ $doc->title }}</td> <td>{{ $doc->file_url }}</td> <td> <div class="action_btn"> <div class="action_btn"> <a href="{{ route('document.edit', $doc->id)}}" class="btn btn-warning btn-sm">Edit</a> </div> <div class="action_btn margin-left-10"> <form action="{{ route('document.destroy', $doc->id)}}" method="post"> @csrf @method('DELETE') <button class="btn btn-danger btn-sm" type="submit">Delete</button> </form> </div> </div> </td> </tr> @empty <tr> <td colspan="3"> <center> No data found </center> </td> </tr> @endforelse </tbody> </table> @endsection
Add New Document
To add new document [Image/File], We will use create and store method of DocumentController.php file. create method stands for rendering form and store method will store data while submitted data.
DocumentController.php
/** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { return view('document.add'); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $reqData = $request->input(); if ($request->hasFile('file')) { $file = $request->file('file'); $name = time() . rand(11111, 99999) . '.' . $file->getClientOriginalExtension(); $destinationPath = public_path('docs'); $file->move($destinationPath, $name); $reqData['file_url'] = $name; } $newFile = Document::create($reqData); if ($newFile) { $request->session()->flash('success', 'Data successfully added'); } else { $request->session()->flash('error', 'Data successfully added'); } return redirect('document'); }
add.blade.php
This layout file contain code for rendering add document form. This is located in resources/views/document/
directory.
@extends('layout') @section('content') <div class="title"> <h1>Add Document</h1> </div> <form action="{{ route('document.store') }}" method="POST" enctype="multipart/form-data"> <div class="form-group"> <label for="title">Title:</label> <input type="text" class="form-control" id="title" name="title"> </div> <div class="form-group"> <label for="file">Choose File:</label> <input type="file" class="form-control-file" id="file" name="file"> </div> @csrf <button type="submit" class="btn btn-primary">Submit</button> <a href="{{ route('document.index') }}" class="btn btn-danger">Back</a> </form> @endsection
Edit/Update Document
To update any document, we will use edit and update method from DocumentController.php file. Here edit method stands for render document form with data and update method will manipulate with submitted data.
DocumentController.php
/** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { $doc = Document::find($id); if ($doc) { return view('document.edit', [ 'doc' => $doc ]); } else { return redirect('document')->with('error', 'File not found'); } } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { $document = Document::find($id); if (!$document) { return redirect('document')->with('error', 'Data not found'); } if ($document->file_url == null) { $oldImage = ''; } else { $oldImage = $document->file_url; } $updateData = $request->input(); // Supplier Image if ($request->hasFile('file')) { $file = $request->file('file'); $name = time() . rand(11111, 99999) . '.' . $file->getClientOriginalExtension(); $destinationPath = public_path('docs/'); $file->move($destinationPath, $name); $updateData['file_url'] = $name; // Delete Old supplier_image if (!empty($oldImage)) { if (\File::exists(public_path('docs/' . $oldImage))) { \File::delete(public_path('docs/' . $oldImage)); } } } $docStatus = $document->update($updateData); if ($docStatus) { return redirect('document')->with('success', 'Data successfully updated.'); } else { return redirect()->route('document.edit', ['id' => 1])->with('error', 'Oops something went wrong. Please try again.'); } }
In update method, if user submit new file then it will automatically deleted old file and update new file. So it will not create bunch of file in the public/docs
directory and require more space.
Here we will create edit.blade.php
file for rendering document form with data. See the code below.
edit.blade.php
@extends('layout') @section('content') <div class="title"> <h1>Edit Document</h1> </div> <form action="{{ route('update-document', ['id' => $doc->id]) }}" method="POST" enctype="multipart/form-data"> <div class="form-group"> <label for="title">Title:</label> <input type="text" class="form-control" id="title" name="title" value="{{ $doc->title }}"> </div> <div class="form-group"> <label for="file">Choose File:</label> <input type="file" class="form-control-file" id="file" name="file"> </div> <div class="form-group"> <img src="/docs/{{ $doc->file_url }}" width="150" height="150"> </div> @csrf {{-- @method('PUT') --}} <button type="submit" class="btn btn-primary">Submit</button> <a href="{{ route('document.index') }}" class="btn btn-danger">Back</a> </form> @endsection
Delete/Destroy Document
To delete document, we will use destroy method of DocumentController.php file. It will delete database records using $document->delete()
and also delete document file from public/docs
directory.
DocumentController.php
/** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { $document = Document::find($id); if (!$document) { $respStatus = 'error'; $respMsg = 'Data not found'; } // Delete file $fileUrl = $document->file_url; if (\File::exists(public_path('docs/'.$fileUrl))) { \File::delete(public_path('docs/'.$fileUrl)); } // Delete document from database $isDocDeleted = $document->delete(); if ($isDocDeleted) { $respStatus = 'success'; $respMsg = 'Data deleted successfully'; } return redirect('document')->with($respStatus, $respMsg); }
After successfully deleted operation, it will redirect to document listing page with appropriate response message.
Awesome. We have completed basic CRUD in our document app.
File Validation
File validation is necessary to get rid of unwanted file extensions. Here we will do validations of image and pdf file extensions. For images we will allow only jpg,jpeg and png. We will also validate file size till 10000 kb.
Lets add validation code in store and update method.
/** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { // Validate request data $validatedData = $request->validate([ 'title' => 'required|max:255', 'file' => 'required|max:10000|mimes:png,jpeg,jpg,pdf', ]); ... // store validated document } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { // Validate request data $validatedData = $request->validate([ 'title' => 'required|max:255', 'file' => 'required|max:10000|mimes:png,jpeg,jpg,pdf', ]); ... // update validated document }
We can also validate doc and docx extension by adding them in validation mimes.
'file' => 'required|max:10000|mimes:png,jpeg,jpg,pdf,doc,docx',
This tutorial is on github. You can download code this tutorial from here.
I hope that you enjoyed this tutorial on file/image upload with validation in laravel 6. Let me know if you have any issue regarding this tutorial. Please do share with your friends. Thank you guys.