Yii2 compare email without case sensitive - validation

I use the simple compare validation rule offered by Yii2 like this:
[confirm_email', 'compare', 'compareAttribute'=>'email', 'message'=>"Emails don't match"],
The problem is that this rule compares two emails 100% including Case Sensitive which means email#test.com and email#Test.com will generate validation error.
Is there a way to remove this Case Sensitive comparison from this rule?

strcasecmp does not handle multibyte characters, read this
suggestion is to use strtolower()
you might also be interested in yii's input filter, to transform input to lowercase, like this:
[
// both email fields tolower
[['email', 'confirm_email'], 'filter', 'filter' => 'strtolower'],
// normalize "phone" input
['phone', 'filter', 'filter' => function ($value) {
// normalize phone input here
return $value;
}], ]

You can create custom validation if you want.
public function rules()
{
return [
// an inline validator defined as the model method validateEmail()
['email', 'validateEmail'],
];
}
public function validateEmail($attribute, $params)
{
if (strcasecmp($this->attribute, $this->confirm_email) == 0) {
$this->addError($attribute, 'Username should only contain alphabets');
}
}
It will compare emails with binary safe case-insensitive.

Related

Laravel validation numeric with gte:1 throws exception

Why Laravel throws
InvalidArgumentException('The values under comparison must be of the same type');
exception, when input non-numeric text like 'test' on rule:
public function rules()
{
return [
'account_no' => 'required|numeric|gte:1'
];
}
When expected just not to pass validation and display message:
account_no field must be numeric
How to solve this exception?
Merdan the field under gte validation must be greater than or equal to the given field. The two fields must be of the same type.
example let's say you have two fields
POST DATA
// $request->comparison = 1;
// $request->account_no = 20319312;
your rules should be something like
return [
'account_no' => 'required|numeric|gte:comparison'
];
You have to use gte, the gt and gte are added in Laravel 5.6 and latest versions and I'm not sure what laravel version you are using.
I think you can try like this:
public function rules()
{
return [
'account_no' => 'required|numeric|min:1'
];
}
OR
public function rules()
{
return [
'account_no' => 'required|numeric|min:0|not_in:0'
];
}
The min:1 is the minimum value of 1 and no negative values are allowed
The not_in:0 is the value cannot be 0.
Also you can also use regular expression for doing this job.
I hope it would be helpful. Thanks

Laravel email validation issue

Default Laravel Validation class allows strange emails. Here is the Validation rules that I defined:
return Validation::make($data, [
'email' => 'required|string|email|max:100|unique:customers,email'
]);
When I tried to use some strange email like:
aaaa?#%&'#şğüçi̇ö.com it passes the validation. However the non latin characters on the email is converted before DB insert. So the email address on the database doesn't match with the original one.
In order to prevent this I want to disallow the usage of non-latin characters after the # symbol. I tried the custom rule which is:
public function passes($attribute, $value)
{
return filter_var($value, FILTER_VALIDATE_EMAIL)
&& preg_match('/#.+\./', $value);
}
but it is not working. It would be good to get some help on this.
Edit 1
Thanks for your responses! But apparently the reason that the custom validator not taking action is that Laravel sanitizes all input data before any manipulation. That's why after it converts the non-latin characters, preg_replace() returns 1 all the time since there is no non-latin characters on the input. First of all I need to find a solution to this and prevent Laravel to sanitize the input.
From your question I understand you already created a custom Validation Rule and use it like
...
'email' => [
'required',
'string',
...
new ValidateLatinEmail()
]
As you can see here, your RegEx is the problem with that validation
This one should work:
public function passes($attribute, $value)
{
return filter_var($value, FILTER_VALIDATE_EMAIL)
&& preg_match('/#[\x00-\x7F]*\./', $value);
}

Laravel Validation sometimes rules for date validation

I currently have a validation rule which looks like this:
public function rules()
{
return [
'startDate' => 'required|sometimes|before_or_equal:endDate',
'endDate' => 'sometimes|required|after_or_equal:startDate',
];
}
The sometimes option works as I understand it on the basis that if the field is present, run the validation rule. However, if the end date is not sent or is null, my before or equal rule kicks in and fails. In some instances within my application, end date will be null. Is there a way to 'cancel' the startDate validation rule in this instance or would I need to create a custom validator for this purpose?
something like before_or_equal_when_present ?
You can use IFs to add and manipulate rules in the rules function. You can access the inputs there referring to $this as the request itself:
public function rules()
{
$rules = [
'startDate' => 'required|sometimes|before_or_equal:endDate',
'endDate' => 'sometimes|required|after_or_equal:startDate',
];
if( $this->input('endDate') > 0)
$rules['endDate'] = "rule". $rules['endDate']
return $rules;
}
This is just a mockup just to let you know that you can manipulate and have access to the fields passed.

Change date format before validation

I have to change the date format before validation.
I use the german date format (dd.mm.yyyy). But for the validation i need the format yyyy-mm-dd.
here my rules from the requests file:
public function rules()
{
return [
'title' => 'required|min:5',
'start' => 'required|date_format:d.m.Y|after:+1 week|unique:talks,start',
'end' => 'required|date_format:d.m.Y|after:start|unique:talks,end',
'interval' => 'required'
];
}
Now i found this function:
public function all()
{
$input = parent::all();
//modify input here
return $input;
}
But how can i modify the input here???
Thanks for your help
The $input variable is just an associative array with key -> value pairs of the request input. You can directly modify the array:
public function all()
{
$input = parent::all();
$input['start'] = date("Y-m-d", strtotime($input['start']));
$input['end'] = date("Y-m-d", strtotime($input['end']));
return $input;
}
This will translate your date values for the purposes of validation. Because the validator calls the all() method.
However, this does not modify the original values in your input.
Whenever you access the input values by a different method than all(), the original value will appear. E.g. $request->input('start') will give you the original German format but $request->all()['start'] will give you the translated international formal.
Such a situation is a potential source of bugs and it's hard to maintain. The right solution for your problem is to write a tiny custom middleware that will modify the request values. See here: https://laracasts.com/discuss/channels/general-discussion/laravel-5-modify-input-before-validation?page=2

How can I validate input does not contain specific words?

In my signup form I have a nickname field that users can enter text in to identify themselves on my site. In the past some users have entered nicknames which others might find offensive. Laravel provides validation functionality for forms, but how can I ensure that a form field doesn't contain words users might find offensive?
Whilst Laravel has a wide range of validations rules included, checking for the presence of a word from a given list isn't one of them:
http://laravel.com/docs/validation#available-validation-rules
However, Laravel also allows us to create our own custom validation rules:
http://laravel.com/docs/validation#custom-validation-rules
We can create validation rules using Validator::extend():
Validator::extend('not_contains', function($attribute, $value, $parameters)
{
// Banned words
$words = array('a***', 'f***', 's***');
foreach ($words as $word)
{
if (stripos($value, $word) !== false) return false;
}
return true;
});
The code above defines a validation rule called not_contains - it looks for presence of each word in $words in the fields value and returns false if any are found. Otherwise it returns true to indicate the validation passed.
We can then use our rule as normal:
$rules = array(
'nickname' => 'required|not_contains',
);
$messages = array(
'not_contains' => 'The :attribute must not contain banned words',
);
$validator = Validator::make(Input::all(), $rules, $messages);
if ($validator->fails())
{
return Redirect::to('register')->withErrors($validator);
}
In Laravel 5.7 and possibly earlier versions, you could use the built in not_regex rule to check for some strings. Like this for example, within a controller using the validate method. Validate form input that expects a name for a dog. :
...
public function update(Request $request) {
$custom_validation_messages = [
'not_regex' => "C'mon! Be original. Give your dog a more interesting name!"
];
$this->validate($request, [
'pet_name' => [ 'not_regex:/^(fido|max|bingo)$/i' ],
], $custom_validation_messages);
...
}
In this case if the submitted 'pet_name' value is:
fido
FIDO
MaX
MAx
BinGO
bingo
etc.
Then validation will fail.
For the inverse of this, i.e. you only want Fido, Max or Bingo then you could use the regex rule like so:
[ 'regex:/^(fido|max|bingo)$/i' ]
See Laravel Validation (not regex).

Resources