Upload Files to MySQL on Laravel 8

Last modified: June 11, 2021

Create a new Laravel project called upload-file-to-database by using the below command.

composer create-project laravel/laravel upload-file-to-database

We are creating Document Model with migration file by using artisan make command and with -m flag.

php artisan make:model Document -m

Since we are going to deal with name, file and mime property, we add them to the fillable in the Document Model.

<?php namespace App\\Models; use Illuminate\\Database\\Eloquent\\Factories\\HasFactory; use Illuminate\\Database\\Eloquent\\Model; class Document extends Model { use HasFactory; protected $fillable = [ 'name', 'file', 'mime', ]; }

In the migration file, we add name and mime (for identifying type of file e.g. pdf) fields as string. We also add file as MEDIUMBLOB file type by running ALTER table statement. The binary Laravel which will translate to BLOB might not be enough field length.

<?php use Illuminate\\Database\\Migrations\\Migration; use Illuminate\\Database\\Schema\\Blueprint; use Illuminate\\Support\\Facades\\Schema; use Illuminate\\Support\\Facades\\DB; class CreateDocumentsTable extends Migration { public function up() { Schema::create('documents', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('mime'); $table->timestamps(); }); DB::statement("ALTER TABLE documents ADD file MEDIUMBLOB"); } public function down() { Schema::dropIfExists('documents'); } }

Go to http://localhost/phpmyadmin/ and create a database name laravel

Ensure your databse connection details are correct in .env file.

DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=root DB_PASSWORD=

Now it is time to migrate (create database tables) by running artisan migrate command.

php artisan migrate

To create a controller, we make use of the make:controller artisan command.

php artisan make:controller DocumentContoller

$documents = Document::all(); will get all the documents stored in the database, and we return it to document.index view.

Before deleting a document record, we first need to get that record by using find() method ```$doc = Document::find($id);``. Then we can call the ->delete function $doc->delete();.

We can put filter to method (upload file) to type of file the can be uploaded to database e.g. pdf, jpg. We extract the mime type, file content before adding to the database.

<?php namespace App\\Http\\Controllers; use Illuminate\\Http\\Request; use App\\Models\\Document; class DocumentContoller extends Controller { public function index() { $documents = Document::all(); return view('document.index', [ 'documents' => $documents, ]); } public function destroy($id) { $doc = Document::find($id); $doc->delete(); return redirect()->route('document'); } public function update(Request $request) { $request->validate([ 'file' => 'mimes:jpeg,bmp,png,pdf,jpg', 'name' => 'required|max:255', ]); if ($request->hasFile('file')) { $path = $request->file('file')->getRealPath(); $ext = $request->file->extension(); $doc = file_get_contents($path); $base64 = base64_encode($doc); $mime = $request->file('file')->getClientMimeType(); Document::create([ 'name'=> $request->name .'.'.$ext, 'file' => $base64, 'mime'=> $mime, ]); return redirect()->route('document'); } } public function download($id) { $document = Document::find($id); $file_contents = base64_decode($document->file); return response($file_contents) ->header('Cache-Control', 'no-cache private') ->header('Content-Description', 'File Transfer') ->header('Content-Type', $document->mime) ->header('Content-length', strlen($file_contents)) ->header('Content-Disposition', 'attachment; filename=' . $document->name) ->header('Content-Transfer-Encoding', 'binary'); } }
<div class="row"> @if ($documents->count()) <h3>Documents</h3> <table class="table table-striped table-bordered table-hover"> <thead> <tr> <td>Name</td> <td></td> <td></td> </tr> </thead> <tbody> @foreach ($documents as $document) <tr> <td>{{$document->name}}</td> <td><a href="{{ route('document.download', $document->id) }}">Download</a></td> <td><a href="{{ route('document.destroy', $document->id) }}">Delete</a></td> </tr> </tbody> @endforeach </table> @endif </div> <form action="{{ route('document.update') }}" method="post" enctype="multipart/form-data"> @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <div class="row"> <div> <br /> @csrf <div class="form-group"> <label for="name">End Date</label> <input type="text" value="{{ old('name') }}" class="form-control @error('name') is-invalid @enderror" name="name" id="name" placeholder="Enter document name"> </div> <div class="form-group"> <input type="file" class="form-control" name="file" required> </div> <button type="submit" class="btn btn-primary">Submit</button> </div> </div> </div> </form>
Route::get('/documents', [App\\Http\\Controllers\\DocumentContoller::class, 'index'])->name('document'); Route::post('/documents/upload', [App\\Http\\Controllers\\DocumentContoller::class, 'update'])->name('document.update'); Route::get('/documents/download/{documentId}', [App\\Http\\Controllers\\DocumentContoller::class, 'download'])->name('document.download'); Route::get('/documents/delete/{documentId}', [App\\Http\\Controllers\\DocumentContoller::class, 'destroy'])->name('document.destroy');