Vue / Laravel: How to validate files uploaded from the frontend? - laravel

I have an image uploader on my Vue app that takes multiple files. I want to ensure they are images and of a certain size and if not, obviously don't upload the files and have the frontend display the error. Right now, the route it hits in the controller loos like this:
public function uploadAssets(UploadAssetsFormRequest $request)
{
if ($request->hasFile('file')) {
$files = $request->file('file');
$stack = [];
foreach ($files as $file) {
$fileName = Storage::put('/check/', file_get_contents($file->getRealPath()), ['visibility' => 'public']);
array_push($stack, $fileName);
}
return response()->json($stack);
}
}
My Form Request is below and has the validation but I don't know how to apply that in the controller.
UploadAssetsFormRequest
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class UploadAssetsFormRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'files.*' => 'required|image|max:1000',
];
}
public function messages()
{
return [
'files.*.max' => 'The image is too large',
'files.*.image' => 'Only image files are allowed.',
];
}
}

You need to check files extension :
$extension = $file->extension();
$allowed_file_types = ['jpg','png','gif'];
if (in_array($extension, $allowed_file_types)){
//do upload
}else{
Continue;
}
for file sizes check this thread

You can use laravel image validation
$this->validate ($input, [
'files.*.image' => 'image|max:200',
]):
Note: max(size) is in Kilobytes
You can also use dimension rule
$this->validate ($input, [
'files.*.image' => 'dimensions:min_width=100,min_height=200'
]):
Laravel Image Validation
Laravel Image Dimensions Validation

You can set the following rule in your validation -
'file' => 'required|max:100|mimes:jpg,png,bmp' // 100kb, mimes must have image extensions

Related

Laravel 8: File Upload with Original File Name and Extension

I currently have an API where it saves the uploaded image but it hashes it, turns it into strings but what I want to do now is to retain the original name of the image in the database, not the string-type.
Image Controller:
namespace App\Http\Controllers;
use App\Models\LessonIMG;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class LessonIMGController extends Controller
{
public function FileUpload(Request $request, $id)
{
$rules = [
'file' => 'required',
];
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
return response()->json($validator->errors(), 400);
}
$uploaded_files = $request->file->store('public/uploads/');
$lesson = LessonIMG::find($id);
$lesson->lesson_image = $request->file->hashName();
$results = $lesson->save();
if ($results) {
return ["result" => "Image Added"];
} else {
return ["result" => "Image Not Added"];
}
return ["result" => $uploaded_files];
}
public function DeleteIMG($id)
{
$lesson = LessonIMG::find($id);
if (is_null($lesson)) {
return response()->json('Record not found!', 401);
}
$lesson->update(['lesson_image' => null]);
return response('Image Deleted', 200);
}
}
Any help/suggestion would be appreciated. Thank you!
You can get any file attribute from the request in your controller as it is documented in here. A full reference of file methods is available in here
$file_extension = $request->file->extension();
$file_mime_type = $request->file->getClientMimeType();
$original_file_name = $request->file->getClientOriginalName();
$uploaded_files = $request->file->store('public/uploads/');
You can get the original file by using getClientOriginalName() method:
$filenameWithExt = $files->getClientOriginalName();

How to serve the data returned from laravel Storage::disk('private')->get($file) as PDF

My question is about the problem in link below :
Understanding file storage and protecting contents Laravel 5
I need to use the same method mentioned in above example but instead of an image I need to provide a download link for PDF file or a link to open PDF file in browser and I can't do that because, as mentioned in above example's comments The Storage::disk('private')->get($file) returns the CONTENT of the file NOT the URL.
Please tell me how can I convert the row data (content of file) to a file and provide the link for the users inside the view.
You should follow the below steps:
I have store pdf file into storage/app/pdf
In controller:
public function __construct()
{
$this->middleware('auth');
}
public function index(Request $request, $file)
{
$file = storage_path('app/pdf/') . $file . '.pdf';
if (file_exists($file)) {
$headers = [
'Content-Type' => 'application/pdf'
];
return response()->file($file, $headers);
} else {
abort(404, 'File not found!');
}
}
if laravel below 5.2:
Add use Response; above controller class in the controller.
public function index(Request $request, $file)
{
$file = storage_path('app/pdf/') . $file . '.pdf';
return Response::make(file_get_contents($file), 200, [ 'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="'.$file.'"'
]);
}
In web.php
Route::get('/preview-pdf/{file}', 'Yourcontroller#index');
In the blade view:
PDf
According to the Laravel documentation you can simply use the download method on the Storage facade.
From your controller, return the result of the command.
return Storage::disk('private')->download($file);

Validation for form not checking partly

I have a Laravel program that saves form data and uploads a few pictures. In the validation, there are two rules. The image is required and it has to be of image type (jpg, jpeg, png). However, the validation only checks for the filetype and does not check for 'required'. Even if there is no image, it allows the user to submit. Why?
public function updateImages(Request $request, $id)
{
$validatedData = $request->validate([
'image' => 'required',
'image.*' => 'image|mimes:jpeg,png,jpg|max:2048',
],
[
'image.*.image' => 'Format Error: Please uplaod image in a png or jpg format',
]);
$item = Post::find($id);
$existing_count = Photo::where('post', $item->id)->count();
$countrequest = sizeof($request->file('image'));
$count = $existing_count + $countrequest;
if ($count >= 6) {
return back()
->withInput()
->withErrors(['Only 5 images can be uploaded!']);
}
$upload = $this->imageUpload($item, $request);
return redirect()->back()->with('message', 'Image Updated');
}
Apply require with image.*. Eg.-
image.*' => 'require|image|mimes:jpeg,png,jpg|max:2048',
Try this solution. It will work.
You can use Laravel Request Validation
To create a form request class
php artisan make:request ImageUpdateRequest
Go to app/Http/Requests add the rules
public function authorize()
{
return true;
}
public function rules()
{
return [
'image' => 'required|image|mimes:jpeg,png,jpg|max:2048'
];
}
On your controller
use App\Http\Request\ImageUpdateRequest;
public function updateImages(ImageUpdateRequest $request, $id)
{
$item = Post::find($id);
$existing_count = Photo::where('post',$item->id)->count();
$countrequest = sizeof($request->file('image'));
$count= $existing_count+$countrequest;
if ($count >= 6 ){
return back()
->withInput()
->withErrors(['Only 5 images can be uploaded!']);
}
$upload = $this->imageUpload($item, $request);
return redirect()->back()->with('message', 'Image Updated');
}

Laravel testing file upload and resize

I'm trying to develop something using the TDD way and I'm facing this problem I can't solve.
I'm uploading an image which is resized and store in database.
When I'm doing it manually (using my browser like a regular user) it works, but the test fail.
Here is my controller:
public function store(Product $product)
{
//$name = request('image')->store('products', 'public');
$name = str_random(50).'.jpg';
$path = storage_path('app/public/products/'.$name);
$image = Image::make(request('image'));
$image->fit(400, 400);
$image->save($path);
$product->photos()->save(new Photo([
'name' => $name
]));
return redirect($product->adminPath());
}
and here is my test
public function a_user_can_add_photos_to_the_product()
{
$this->withoutExceptionHandling();
$this->signIn();
$product = ProductFactory::create();
Storage::fake('public');
$this->post($product->adminPath('/photos'), [
'image' => UploadedFile::fake()->image('photo.jpg')
])->assertRedirect($product->adminPath());
$product->load(['photos']);
tap($product->photos->first(), function ($photo) {
$this->assertInstanceOf('App\Photo', $photo);
Storage::disk('public')->assertExists($photo->name);
});
$this->assertEquals(1, $product->photos->count());
}
At this point the test will fail, but If i comment the resize part and use the store method on the request like this:
Tests\Feature\ManageProductPhotoTest::a_user_can_add_photos_to_the_product
Unable to find a file at path [pJ1Zd19XT0aF9fc5W1famc3n7WwxBt3L9MDB0yRJNlVYcWkMwk.jpg].
Failed asserting that false is true.
public function store(Product $product)
{
$name = request('image')->store('products', 'public');
/*$name = str_random(50).'.jpg';
$path = storage_path('app/public/products/'.$name);
$image = Image::make(request('image'));
$image->fit(400, 400);
$image->save($path);*/
$product->photos()->save(new Photo([
'name' => $name
]));
return redirect($product->adminPath());
}
The test passes.
How can I solve this issue ?

laravel array validation only one required

Hello i have a form for image upload
<input type="file" name="ad_image[]">
i want only one image to be required and others to be optional.
This is my validation rule and is not working:
'ad_image.*' => 'required|min:1|mimes:png,gif,jpeg,jpg|max:300',
i have tryed this:
'ad_image' => 'required|array|min:1|mimes:png,gif,jpeg,jpg|max:300',
also not working, when i upload jpg file there is error "The ad image must be a file of type: png, gif, jpeg, jpg."
please help with this issue
You can try:
public function rules()
{
$rules = [
'ad_image0'=> 'image|required|mimes:png,gif,jpeg,jpg|max:300'
];
$nbr = count($this->input('ad_image')) - 1;
foreach(range(0, $nbr) as $index) {
$rules['ad_image.' . $index] ='image|mimes:png,gif,jpeg,jpg|max:300';
}
return $rules;
}
I have decided to make my own custom validation rule:
This code is in boot method of the AppServiceProvider
public function boot()
{
Validator::extend('require_one_of_array', function($attribute, $value, $parameters, $validator) {
if(!is_array($value)){
return false;
}
foreach ($value as $k => $v){
if(!empty($v)){
return true;
}
}
return false;
});
}
The validation message is manualy added as third parameter of the validator
$messages = [
'require_one_of_array' => 'You need to upload at least one pic.',
];
And this is how is used to make sure at lease one image is uploaded (this is in rules array):
'ad_image' => 'require_one_of_array',
'ad_image.*' => 'mimes:jpeg,bmp,png|max:300',

Resources