Why image validation accpet text file laravel postman? - laravel

I am using laravel 8 and i am uploading file from postman. I have also write validation rules for png, jpeg and jpg. But when i select any other file its also upload it.
Form data in postman is
enter image description here
and my resource file for validation is
public function rules()
{
return [
'invoice_id' => ['required', 'string'],
'invoice_date' => ['required', 'date'],
'invoice_photo_url' => ['required','image','mimes:jpeg,png,jpg'],
'invoice_net_total' => ['required','regex:/^\d*(\.\d{1,2})?$/'],
];
}
and my controller method is
public function upload(InvoiceUploadRequest $request)
{
try {
return $this->responseWithSuccess(true,"Invoice successfully uploaded!",
$this->invoiceInterface->uploadInvoice($request), Response::HTTP_OK);
}catch (\Exception $exception){
return $this->responseWithError($exception->getMessage(), Response::HTTP_OK);
}
}
how can is solve this.
thanks

Related

Laravel validator does'nt correctly validate file mime type

I send multiple files to my server with postman
And these files are uploaded correctly but they are not properly validated before uploading
this is my controller
public function store(Request $request)
{
// دریافت دایرکتوری مطالبه مربوطه : $demand=Demand::find(72)->files->first()->file_directoryس
//{"title":"this is test title","demandContent":"this is test content "} send as form-data request
//------------------------------------------- Valid Uploaded File ---------------------------------
$rules = array(
'file' => 'required',
'file.' => 'mimes:doc,pdf,docx,zip,jpg,jpeg,rar'
);
$error = Validator::make($request->all(), $rules);
if($error->fails())
return response()->json(['errors' => $error->errors()->all()]);
//-------------------------------------------- Valid Uploaded File -------------------------------
$request->data=json_decode($request->data); //دریافت به صورت جیسون و تبدیل به شی
$demand=new Demand(['title' => $request->data->title,'content'=>$request->data->demandContent,'user_id'=>auth('api')->user()->id]);
if($demand->save()) //اگر درخواست در دیتابیس قبت شد
{
//----------------------------File Upload Scope---------------------------------------
if($request->hasfile('file'))
{
$path='public/demands/'.$demand->id.'/files';
foreach($request->file('file') as $file)
{
$filename=$file->getClientOriginalName();
$file->move($path, $filename);
}
$demand->files()->save(new File(['file_directory'=>$path]));
}
//----------------------------File Upload Scope---------------------------------------
return response()->json(['demand'=>new DemandResource($demand)],200);
}
return response()->json(['state'=>'false']);
}
In your validation rules you have forgotten * like:
$rules = [
'file' => 'required',
'file.*' => 'required|file|mimes:doc,pdf,docx,zip,jpg,jpeg,rar',
];

Find data before validate form request laravel

I want to update the data using the request form validation with a unique email role, everything works normally.
Assume I have 3 data from id 1-3 with url:
127.0.0.1:8000/api/user/update/3
Controller:
use App\Http\Requests\Simak\User\Update;
...
public function update(Update $request, $id)
{
try {
// UPDATE DATA
return resp(200, trans('general.message.200'), true);
} catch (\Exception $e) {
// Ambil error
return $e;
}
}
FormRequest "Update":
public function rules()
{
return [
'user_akses_id' => 'required|numeric',
'nama' => 'required|max:50',
'email' => 'required|email|unique:users,email,' . $this->id,
'password' => 'required',
'foto' => 'nullable|image|max:1024|mimes:jpg,png,jpeg',
'ip' => 'nullable|ip',
'status' => 'required|boolean'
];
}
but if the updated id is not found eg:
127.0.0.1:8000/api/user/update/4
The response gets The email has already been taken.
What is the solution so that the return of the data is not found instead of validation first?
The code looks like it should work fine, sharing a few things below that may help.
Solution 1: Check if $this->id contains the id you are updating for.
Solution 2: Try using the following changes, try to get the id from the URL segment.
public function rules()
{
return [
'user_akses_id' => 'required|numeric',
'nama' => 'required|max:50',
'email' => 'required|email|unique:users,email,' . $this->segment(4),
'password' => 'required',
'foto' => 'nullable|image|max:1024|mimes:jpg,png,jpeg',
'ip' => 'nullable|ip',
'status' => 'required|boolean'
];
}
Sharing one more thing that may help you.
Some person uses Request keyword at the end of the request name. The Update sounds generic and the same as the method name you are using the request for. You can use UpdateRequest for more code readability.
What I understand from your question is, you need a way to check if the record really exists or not in the form request. If that's the case create a custom rule that will check if the record exists or not and use that rule inside your request.
CheckRecordRule
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CheckRecordRule implements Rule
{
protected $recordId;
public function __construct($id)
{
$this->recordId = $id;
}
public function passes($attribute, $value)
{
// this will check and return true/false
return User::where('id', $this->recordId)->exists();
}
public function message()
{
return 'Record not found.';
}
}
Update form request
public function rules()
{
return [
'email' => 'required|email|unique:users,email,' . $this->id.'|'. new CheckRecordRule($this->id),
];
}
So when checking for duplicate it will also check if the record really exists or not and then redirect back with the proper message.

Image validation rule not working as expected

Here's my validation rule:
public function rules() {
$channel_id = Auth::user()->channels->first()->id;
return [
'name' => 'required|max:30|unique:channel,name,' . $channel_id,
'slug' => 'required|max:30|alpha_num|unique:channel,slug,' . $channel_id,
'description' => 'max:1000',
'channelImage' => 'image',
];
}
public function messages() {
return [
'slug.unique' => 'That unique URL has already been taken.',
'channelImage.image' => 'Only jpeg, jpg, png, bmp, gif and svg formats are supported.',
];
}
Although, is it not mandatory to upload channel image while filling the form, the image validation rule for channelImage works as if it's mandatory i.e. I need to upload an image every time I submit the request.
Why is working like that?? I did not mention required rule for channelImage, still why it is validating channelImage when I am not uploading any image?
Try using nullable:
'channelImage' => 'nullable|image',

Error from Laravel to AJAX fileupload

I have an AJAX upload that sends the uploaded file (image in this case) to a function in Laravel 5.3. There I have this validation check in said function:
...
$validator = Validator::make($request->all(), [
'image' => 'image|mimes:jpeg,png,jpg|max:512',
]);
// If validator fails return this error to AJAX
if($validator->fails()) {
return response()->json('error', 422);
}
...
How would I be able to set the response()->json('error', 422) with a custom error. Now I only get an error that the file upload has failed. I would like more feedback then that.
For example: let the user know his file is to large or let the user know his extension is not allowed.
Thanks
You can get error messages from validator and send it to response, here is example.
if ($validator->fails()) {
return response()->json([
'success' => false,
'error' => $validator->getMessageBag()->toArray()
], 422);
}

Better way for testing validation errors

I'm testing a form where user must introduce some text between let's say 100 and 500 characters.
I use to emulate the user input:
$this->actingAs($user)
->visit('myweb/create')
->type($this->faker->text(1000),'description')
->press('Save')
->see('greater than');
Here I'm looking for the greater than piece of text in the response... It depends on the translation specified for that validation error.
How could do the same test without having to depend on the text of the validation error and do it depending only on the error itself?
Controller:
public function store(Request $request)
{
$success = doStuff($request);
if ($success){
Flash::success('Created');
} else {
Flash::error('Fail');
}
return Redirect::back():
}
dd(Session::all()):
`array:3 [
"_token" => "ONoTlU2w7Ii2Npbr27dH5WSXolw6qpQncavQn72e"
"_sf2_meta" => array:3 [
"u" => 1453141086
"c" => 1453141086
"l" => "0"
]
"flash" => array:2 [
"old" => []
"new" => []
]
]
you can do it like so -
$this->assertSessionHas('flash_notification.level', 'danger'); if you are looking for a particular error or success key.
or use
$this->assertSessionHasErrors();
I think there is more clear way to get an exact error message from session.
/** #var ViewErrorBag $errors */
$errors = request()->session()->get('errors');
/** #var array $messages */
$messages = $errors->getBag('default')->getMessages();
$emailErrorMessage = array_shift($messages['email']);
$this->assertEquals('Already in use', $emailErrorMessage);
Pre-requirements: code was tested on Laravel Framework 5.5.14
get the MessageBag object from from session erros and get all the validation error names using $errors->get('name')
$errors = session('errors');
$this->assertSessionHasErrors();
$this->assertEquals($errors->get('name')[0],"The title field is required.");
This works for Laravel 5 +
Your test doesn't have a post call. Here is an example using Jeffery Way's flash package
Controller:
public function store(Request $request, Post $post)
{
$post->fill($request->all());
$post->user_id = $request->user()->id;
$created = false;
try {
$created = $post->save();
} catch (ValidationException $e) {
flash()->error($e->getErrors()->all());
}
if ($created) {
flash()->success('New post has been created.');
}
return back();
}
Test:
public function testStoreSuccess()
{
$data = [
'title' => 'A dog is fit',
'status' => 'active',
'excerpt' => 'Farm dog',
'content' => 'blah blah blah',
];
$this->call('POST', 'post', $data);
$this->assertTrue(Post::where($data)->exists());
$this->assertResponseStatus(302);
$this->assertSessionHas('flash_notification.level', 'success');
$this->assertSessionHas('flash_notification.message', 'New post has been created.');
}
try to split your tests into units, say if you testing a controller function
you may catch valication exception, like so:
} catch (ValidationException $ex) {
if it was generated manually, this is how it should be generated:
throw ValidationException::withMessages([
'abc' => ['my message'],
])->status(400);
you can assert it liks so
$this->assertSame('my message', $ex->errors()['abc'][0]);
if you cannot catch it, but prefer testing routs like so:
$response = $this->json('POST', route('user-post'), [
'name' => $faker->name,
'email' => $faker->email,
]);
then you use $response to assert that the validation has happened, like so
$this->assertSame($response->errors->{'name'}[0], 'The name field is required.');
PS
in the example I used
$faker = \Faker\Factory::create();
ValidationException is used liks this
use Illuminate\Validation\ValidationException;
just remind you that you don't have to generate exceptions manually, use validate method for common cases:
$request->validate(['name' => [
'required',
],
]);
my current laravel version is 5.7

Resources