I created a custom validation rule by using the command:
php artisan make:rule Horizontal
Now, how to check if the submitted picture from my post form is horizontal?
I tried this:
public function passes($attribute, $value)
{
if ($this->request->has('picture')) {
$image = $this->request->get('picture');
if ($image->width < $image->height) {
session()->flash('error', 'Image must be horizontal!');
return false;
}
}
}
public function message()
{
return 'The validation error message.';
}
My Post Request:
public function rules()
{
return [
'title' => 'required|min:2|max:255',
'body' => 'required|min:10',
'picture' => [
'required',
new Horizontal()
]
];
}
After Image upload
Laravel Intervention Image Can help like this:
$img = Image::make('public/foo.jpg');
$img->flip('h');
h for horizontal and v for vertical.
There is one more method orientate to set auto Orientation as well
You can compare height and width as well
This image library required GD library and Imagick plugin
Good luck!
Related
I'm working on validating an image file with two different dimensions rule, it can b Icon or Banner depending on the selection of recently selected field. I'm doing this by adding a custom Rule class, here is my validation rule which works fine on Icon Only OR Banner Only
$validator = Validator::make([
'file' => $value,
], [
'file' => 'mimes:png,webp|dimensions:width=512,height=512|max:2048'
]);
$validator->validate();
now the problem is to validate the banner with a different dimension in the same field. Is there any way to add another Width & Height to this line? I've tried to add another rule under this file with the same name, but it doesn't work. Or is there any other approach to solve this problem? I've read the documentation but could not find the solution there.
Thanks in advance.
Validation rules by default must all pass for the input to be valid. In your case you need one of the two rules to pass which is not possible via built-in validation rules. You can create your own validation rule e.g.:
php artisan make:rule DimensionRule
Then modify the generated rule:
class DimensionRule implements Rule {
public function passes($attribute, $value) {
$validator1 = Validator::make([ $attribute => $value ], [ $attribute => 'dimensions:width=512,height=512' ]);
if ($validator1->passes()) {
return true;
}
$validator2 = Validator::make([ $attribute => $value ], [ $attribute => 'dimensions:width=800,height=30' ]);
return $validator2->passes();
}
public function message()
{
return 'Dimensions must either be 512x512 or 800x30';
}
}
Then you can use this rule:
$validator = Validator::make([
'file' => $value,
], [
'file' => [ 'mimes:png,webp', new DimensionRule(), 'max:2048' ]
]);
$validator->validate();
I would do it this way, buy running few validations in a row, and if it passes one, it should be OK. You can write more validation rules after that of course, I think only the dimensions validation should be here.
class FileUploadController extends Controller
{
/**
* Update the avatar for the user.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function fileUpload(Request $request)
{
foreach ([[100, 50], [200, 150]] as $k => $dim) {
$validators[$k] = Validator::make($request->all(), [
'avatar' => "dimensions:width={$dim[0]},height={$dim[1]}"
]);
}
foreach ($validators as $validator) {
if ($validator->fails()) {
$invalid = true;
} else {
$invalid = false;
break;
}
}
if ($invalid) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
$path = Storage::putFile('public', $request->file('avatar'));
return $path;
}
}
And here is also a feature test:
class FileUploadTest extends TestCase
{
/**
* #dataProvider cases
*/
public function test_avatars_can_be_uploaded($w, $h, $shoudReturnError)
{
Storage::fake('public');
$file = UploadedFile::fake()->image('av1.jpg', $w, $h);
$response = $this->post('/file-upload', [
'avatar' => $file,
]);
if ($shoudReturnError) {
// The image dimensions are not right and it should return error
$response->assertSessionHasErrors(['avatar']);
} else {
// The image dimensions are fine and it should pass
Storage::assertExists('public/' . $file->hashName());
}
}
public function cases()
{
return [
[100, 50, $shoudReturnError = false],
[600, 850, $shoudReturnError = true],
[200, 150, $shoudReturnError = false],
[102, 50, $shoudReturnError = true],
];
}
}
I've provided cases where the validation should pass and where it should fail.
Cheers
I'm working on a file upload and it upload well until I try to get a file I'm not supposed to be able to upload.
My rules are:
public function rules()
{
return [
'media' => ['required', 'image', 'max:2000']
];
}
public function messages()
{
return [
'media.required' => 'You must give a file to upload!',
'media.image' => 'The file is not an image!',
'media.max' => 'The file is too big!',
];
}
and when I try to upload a file which is 2,3Mo I got a 422 but the message is always The given data is invalid without telling me which one is invalid.
Then in my controller, this is how I use it:
public function uploadMedia(AddMediaRequest $request, MyEntity $entity)
{
$filename = $entity->addMedia($request->validated());
return response()->json(['filename' => $filename], 200);
}
Am I missing a simple point ? (I use Vue for the front end with axios)
Trying to implement update article in my update controller it seems works, but the problem is when I only want to update the post without uploading an image the old always getting remove which is it shouldn't.
here's my store function
public function store(Post $post)
{
$post->update($this->validateRequest());
$this->storeImage($post);
return redirect('post/'.$post->id)->with('success', 'New ariticle has been posted');
}
}
here's my validation
private function validateRequest()
{
return request()->validate([
'title'=> 'required',
'content' => 'required',
'image' => 'sometimes|image|max:5000',
]);
}
here's my update function
public function update(Post $post)
{
File::delete(public_path('storage/'.$post->image));
$post->update($this->validateRequest());
$this->storeImage($post);
return redirect('post/'.$post->id)->with('success', 'This post has
been Edited');
}
}
I've tried to add File::delete to my storeImage function and delete it from my update function, it fix the problem but the old image is not removed from directory
private function storeImage($post)
{
if (request()->has('image')){
File::delete(public_path('storage/'.$post->image))
$post->update([
'image' => request()->image->store('uploads', 'public'),
]);
$image = Image::make(public_path('storage/'.$post->image))->fit(750, 300);
$image->save();
}
}
Ok since I use model binding in my controller I don't have to find the id right?
so I change my update function which is basically Akhtar munir suggested, and turn out to be something like this. The image update work, it also remove the old image when I update it. But I have found another issue, the problem is when I edit article and title it didn't change like when I update it, I hope you can take look at this is this correct?
public function update(Post $post){
$this->validateRequest();
if(request()->hasFile('image') && request('image') != ''){
$imagePath = public_path('storage/'.$post->image);
if(File::exists($imagePath)){
unlink($imagePath);
}
$image = request()->file('image')->store('uploads', 'public');
$post->update([
'title' => request()->title,
'content' => request()->content,
'image' => $image,
]);
}
}
This is what I have done in one of my method. It may help you.
public function update(Request $request, $id)
{
if (UserDocument::where('id',$id)->exists()) {
$this->validateUserDocument($request);
if ($request->hasFile('doc_file') && $request->doc_file != '') {
$doc = UserDocument::where('id',$id)->first();
// dd($doc);
$file_path = storage_path().'/app/'.$doc['doc_file'];
//You can also check existance of the file in storage.
if(Storage::exists($file_path)) {
unlink($file_path); //delete from storage
// Storage::delete($file_path); //Or you can do it as well
}
$file = $request->file('doc_file')->store('documents'); //new file path
$doc->update([
'title' => $request->title,
'doc_file' => $file //new file path updated
]);
session()->flash('success','Document updated successfully!');
return redirect()->route('userdocs');
}
session()->flash('error','Empty file can not be updated!');
return redirect()->back();
}
session()->flash('error','Record not found!');
return redirect()->back();
}
In this code, I just simply want to clearify to you that I have stored image path in database, first I have retrieved that path and with that path I have found image in my local storage, delete it first and then update it with the new one. But make sure to store image path in database in both cases ofcourse with insert and update.
So finally you can also optimize your code like this, it will do the same thing as you expect, whether image and all data or only title and content.
public function update(Post $post){
$this->validateRequest();
$data = [
'title' => request()->title,
'content' => request()->content
];
if (request()->hasFile('image') && request('image') != '') {
$imagePath = public_path('storage/'.$post->image);
if(File::exists($imagePath)){
unlink($imagePath);
}
$image = request()->file('image')->store('uploads', 'public');
$data['image'] = $image;
//$post->update($data);
}
$post->update($data);
}
Try this one
private function storeImage($post)
{
if (request()->hasFile('image')){
$image_path = "/storage/".'prev_img_name'; // prev image path
if(File::exists($image_path)) {
File::delete($image_path);
}
$post->update([
'image' => request()->image->store('uploads', 'public'),
]);
$image = Image::make(public_path('storage/'.$post->image))->fit(750, 300);
$image->save();
}
}
I have a user registration form, where i am using file input box to upload image.
Now the problem is , if i will select video file to upload it will pass ValidateRequest .
In ValidateRequest, i already define the rule for image, below is the code:
class UserValidateRequest extends Request {
public function __construct() {
}
protected $messages = [
'required.password' => 'We need to know your e-mail address!',
];
protected $rules = [
'first_name' => 'required|regex:"[a-zA-Z 0-9]"',
'last_name' => 'regex:"[a-zA-Z 0-9]"',
'image' => ' mimes:jpeg,jpg,png,gif |max:2048',
];
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize() {
return true;
}
public function messages() {
return [
'password.regex' => 'Password shall be 8-20 characters, must have a number and an alphabet', ,
'image.mimes' => 'Upload Gif || JPG || JPEG || PNG Images Only'
];
}
public function attributes() {
return[];
}
}
Instead of using mime type validation, try to add image validation rule to image field:
'image' => 'image|max:2048'
I am very new to Yii.
I have to apply image validation (.svg and .png allowed) only if user have selected the image.
public function rules() {
return [
[['logo'], 'file', 'extensions'=>'svg, png'],
];
}
When user select image it works fine.
But on update form we have only name of file. Now if we submit the form it will apply validation. I need validation only if user changes the image.
My Controller code
if ($model->load(Yii::$app->request->post())) {
$model->logo = UploadedFile::getInstance($model, 'logo');
if (!empty($model->logo)) {
$model->logo->name = $model->logo->baseName . Yii::$app->formatter->asTimestamp(date('Y-d-m h:i:s')) . '.' . $model->logo->extension;
$logoPath = Yii::getAlias('#common') . '/web/uploads/logo/' . $model->logo->name;
$model->logo->saveAs($logoPath, false);
}
if ($model->updateSite()) {
return $this->redirect(['site-list']);
}
}
Please let me know if you need more clarification.
Thanks.
Using scenarios may be helpful in this case.
Define validation rules to dependend on scenario
public function rules() {
return [
[['logo'], 'file', 'extensions'=>'svg, png', 'on' => 'imageUploaded'],
];
}
Then define scenario for model in controller. Something like this.
if ($model->load(Yii::$app->request->post())) {
$model->logo = UploadedFile::getInstance($model, 'logo');
if (!empty($model->logo)) {
$model->scenario = 'imageUploaded';
...
}
}
It's also possible to define anonymous function for conditional validation.
public function rules() {
return [
[['logo'], 'file', 'extensions'=>'svg, png', 'when' => function ($model) {
//return true to apply the rule
return $model->isImageUploaded();
}],
];
}
More on rules and scenarios can be found here https://github.com/yiisoft/yii2/blob/master/docs/guide/input-validation.md#declaring-rules-