Image upload and validation using Laravel and VueJs
We all know that
An image is worth a thousand words
We find images in almost every application that we use in today’s world. And Laravel being so nice, it supports image uploads out of the box.
$request->file('image')->store('images');
However, It’s even more fun if we can upload images via ajax and validate.
So, let’s get started. I assume you already have a new Laravel application running and generated authentication scaffolding (it’s not necessary, but gives us a nice looking view to work with). I am gonna copy content of my home.blade.php in to welcome.blade.php and work on it.
Under your resources/assets/js/components create a file called FileUpload.vue
<template>
<div class="row">
<div class="col-md-12">
<div class="col-md-2">
<img :src="image" class="img-responsive">
</div>
<div class="col-md-8">
<input type="file" v-on:change="onFileChange" class="form-control">
</div>
<div class="col-md-2">
<button class="btn btn-success btn-block" @click="upload">Upload</button>
</div>
</div>
</div>
</template>
<style scoped>
img{
max-height: 36px;
}
</style>
<script>
export default{
data(){
return {
image: ''
}
},
methods: {
onFileChange(e) {
let files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
},
createImage(file) {
let reader = new FileReader();
let vm = this;
reader.onload = (e) => {
vm.image = e.target.result;
};
reader.readAsDataURL(file);
},
upload(){
axios.post('/api/upload',{image: this.image}).then(response => {
});
}
}
}
</script>
Once we have created FileUpload component let’s register it in app.js
Vue.component('file-upload',require('./components/FileUpload.vue'));
now that we have registered our component, we can use it like
<file-upload></file-upload>
edit your welcome.blade.php, and serve application.
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Upload your favorite image!</div>
<div class="panel-body">
<file-upload></file-upload>
</div>
</div>
</div>
</div>
</div>
@endsection
If you now visit localhost:8000 you should have an output like the following.
For uploading image will be making use of image/intervention php library, follow the instruction and install this package.
In our axios post method we are sending image data which is in base64 encoded format back to our server, so let’s create that route.
Route::post('/upload', function (Request $request) {
$validator = Validator::make($request->all(), [
'image' => 'required|image64:jpeg,jpg,png'
]);
if ($validator->fails()) {
return response()->json(['errors'=>$validator->errors()]);
} else {
$imageData = $request->get('image');
$fileName = Carbon::now()->timestamp . '_' . uniqid() . '.' . explode('/', explode(':', substr($imageData, 0, strpos($imageData, ';')))[1])[1];
Image::make($request->get('image'))->save(public_path('images/').$fileName);
return response()->json(['error'=>false]);
}
});
In the above code, we are using custom validation rule called image64 let’s define our custom validation rule first.
Inside AppServiceProvider under boot function register our custom validation rule as
public function boot()
{
Validator::extend('image64', function ($attribute, $value, $parameters, $validator) {
$type = explode('/', explode(':', substr($value, 0, strpos($value, ';')))[1])[1];
if (in_array($type, $parameters)) {
return true;
}
return false;
});
Validator::replacer('image64', function($message, $attribute, $rule, $parameters) {
return str_replace(':values',join(",",$parameters),$message);
});
}
and, one last final step is to register a validation message in validation.php
'image64' => 'The :attribute must be a file of type: :values.','custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
Final output