Skip first index of array validation rule? - laravel

Good Evening Devs,
I'm trying to skip the first index of the array while applying validation rule and this is what I tried so far
$validatedData = Validator::make($request->all(),([
'inventories.0' => 'bail',
'inventories' => 'required|array|filled',
'quantities.0' => 'bail',
'quantities.*' => 'required|array|filled',
'required.0' => 'bail',
'required.*' => 'required|array|filled',
]));
But it's not working, any ideas?
I'm trying to add multiple dynamic fields, but want to skip the first index of it.
Please review the picture given below to get the clear picture of the problem.

try this:
$validatedData = Validator::make($request->except(['inventories[0],quantities[0],required[0]']),([
'inventories.*' => 'required|array|filled',
'quantities.*' => 'required|array|filled',
'required.*' => 'required|array|filled',
]));

Bail is not used for skipping an entry. But it may be used for skipping validation logic.
for example,
'phone' => 'bail|numeric|unique:users'
In this case, if somehow the entered phone number is not numeric, it will not check the third validation (i.e. whether the phone number is unique in 'users' table or not).
For your case, you should not use "$request->all()". You should use "request()->except(['inventories[0], quantities[0], required[0]'])" instead

This is perhaps, not the best practice. You're trying to allow the presentation layer to have a direct influence over the data / logic layer of your application. It would probably be better to only send over the data you want to validate rather than sending over everything and they tying to get your validation (and other logic) to ignore the first array element.
Is it an api call or a standard web form you are submitting? If it is an api call, can you not build up your data of only the rows you want to send over, before you make the call?
This will keep your logic layer much cleaner, and allow you to change the ui much easier without affecting the logic, and it being tightly coupled.
Just a suggestion.

Related

Laravel Validation 'starts_with' alpha

I am looking to use Laravel validation for user input fields, and all works well aside from one rule I'm looking to enforce: how to ensure a field starts with alpha (where it allows alpha_dash elsewhere). I tried the PHP 'regexp' version [A-Za-z] (shown in code snippet below) but to no avail. I also tried 'starts_with:alpha' also to no avail. I'm hoping to avoid regexp and the like and would rather wait for Laravel solution if there is no simple solution.
Thanks!
'username' => 'required|starts_with:[A-Za-z]|alpha_dash|max:20|unique:users,username',
'firstname' => 'required|starts_with:[A-Za-z]|alpha_dash|max:20',
'lastname' => 'required|starts_with:[A-Za-z]|alpha_dash|max:30',
Try this rule instead of alpha_dash & starts_with:
'required|min:2|max:30|regex:/^[A-Z][a-zA-Z0-9_-]+$/'

Laravels syncWithoutDetaching and additional data

I have Googled my fingers sore, and I can't see anyone discussing this, but I have a suspicion that Laravels syncWithoutDetaching() method doesn't take any parameters for extra data like save(), sync() and attach() does?
Does anybody know this? In the API documentation the method has the following parameters:
array syncWithoutDetaching(Collection|Model|array $ids)
I have trouble adding existing data to a relationship between a Guest and an Event. I need to add status for the guests and what event they are attending, maybe attending or declined.
sync() and syncWithoutDetaching() both don't have a parameter for additional values, you have to pass the additional values as an array with the ids.
According to the docs:
You may also pass additional intermediate table values with the IDs:
$user->roles()->sync([
1 => ['expires' => true],
2,
3
]);
If you look here you can see that syncWithoutDetaching() just calls sync() but passes false as the second argument.
In your case it would be something like this:
$event->guests()->syncWithoutDetaching([
1 => ['attending' => true],
2 => ['attending' => false]
])
I think #remul answer is the best, but it requires additions for people like me who get to this page.
syncWithoutDetaching() - is just an abbreviation for sync() - here. This corresponds to sync($data, false)
The documentation talks about another great method:
If you would like to insert the same intermediate table values with
each of the synced model IDs, you may use the syncWithPivotValues
method
But the documentation does not say that the method accepts the third argument, which just corresponds to the logic of syncWithoutDetaching().
Look here.
If you pass false, the IDs not passed will not be detaching.
I think this is what the question was about.

How to add / remove elements from array that is in Request

My request looks like this
Array
(
[name] => Eugene A
[address] => Array
(
[billing] => Array
(
[address] => aaa
)
[shipping] => Array
(
[address] => bbb
)
)
)
I need to delete the shipping address. But how?
I can only delete both addresses,
$request->request->remove('address');
but I don't want it.
I want to delete only shipping address, like so
$request->request->remove('address.shipping');
But it is not working for me
Laravel 5.6
Update
Why do I need it?
Easy. I have abstracted out my Form Request validation into a class that is a child to Illuminate\Foundation\Http\FormRequest.
I actually have few classes for validation. I call them one by one in a controller like so:
app()->make(CustomerPostRequest::class); // validate Customer information
app()->make(AddressSaveRequest::class); // validate Addresses
Why?
Now I can Mock this requests in unit-tests, and I can have my validation abstracted out. And I can use Address validation in many places.
But Now I need more flexibility. Why?
Because AddressSaveRequest rule looks like this
public function rules(): array
{
return [
'address.*.address' => [
'bail',
'required',
'string',
],
...
It validates all addresses.
But sometimes I don't want to validate shipping address, if the the chech_box - ship_to_the_same_address is ticked.
But I have my Address validator abstracted in separate file and it is used in many places. There are places where ship_to_the_same_address tick box is not presented.
Thus I cannot use 'required_unless:ship_to_same_address,yes',
And I cannot use
app()->makeWith(AddressSaveRequest::class, ['ship_to_the_same_address ' => 'yes']);
Because Taylor said ...when calling makeWith. In my opinion it should make a new instance each time this method is called because the given parameter array is dynamic.. And it does, and it does not work correctly with app()->instance(AddressSaveRequest::class, $addressSaveRequest); and cannot be mocked in unit tests.
Why Taylor decided it - I seriously don't know.
PS
And yes, I know that mocking requests is not recommended.
If you were trying to add or remove inputs from the Request itself:
You can add data to the request pretty easily by merging it in and letting Laravel handle which data source is being used:
$request->merge(['input' => 'value']);
That will merge in the input named input into the input source for the Request.
For removing inputs you could try to replace all the inputs without that particular input in the replacement:
$request->replace($request->except('address.shipping'));
Just one idea to try.
Try this:
$request->except(['address.shipping']);
Details: Laravel Request
Laravel has a helper method called array_forget, which does exactly what it sounds like:
$requestArray = $request->all();
$newArray = array_forget($requestArray, 'address.shipping')
Documentation
After the edit to the main question with why some inputs of the request are to be deleted, my main answer isn't correct anymore. User Lagbox has the correct answer for the question that was asked.
However, I would like to note that another solution would be to have seperate Request classes with validation. One for placing an order (assuming it is a system where someone can order stuff) where ship_to_same_address is present and another one for things like updating your account, like PlaceOrderRequest and UpdateAccountRequest classes.

zend expressive - middleware checks if there is a next one available?

In my routes.global.php I've this one in routes.
[
'name' => 'test',
'path' => '/test',
'middleware' => [App\Action\Test1Action::class, App\Action\Test2Action::class],
'allowed_methods' => ['GET'],
],
And I've this return $next($request, new JsonResponse($data)); at the end of Test1Action class so it will send the data to the next action.
But is there a way inside Test1Action to check if there's another action after?
Maybe there's another way so I can do the above return if there is one after or return the json response rite away.
return new JsonResponse($data);
That way I can either use Test1Action alone or plug it in before other action.
I tried few options but didn't work. Any help will be great. Thanks.
Maybe you can check $next if it's null or not. But it might always be set, I've never tried it. However in Expressive 2 it's always set and it changes to Delegates. Also the last middleware will always be the NotFoundHandler.
Since you develop your application yourself you know the order of middleware and Actions. I would let Test1Action middleware do it's thing, add the result to the $request as an attribute and let the next middleware figure out if the data was set or not. If the data wasn't set than skip it and execute the next middleware in line. It makes it a lot easier.

blacklisting vs whitelisting in form's input filtering and validation

which is the preferred approach in sanitizing inputs coming from the user?
thank you!
I think whitelisting is the desired approach, however I never met a real whitelist HTML form validation. For example here is a symfony 1.x form with validation from the documentation:
class ContactForm extends sfForm
{
protected static $subjects = array('Subject A', 'Subject B', 'Subject C');
public function configure()
{
$this->setWidgets(array(
'name' => new sfWidgetFormInput(),
'email' => new sfWidgetFormInput(),
'subject' => new sfWidgetFormSelect(array('choices' => self::$subjects)),
'message' => new sfWidgetFormTextarea(),
));
$this->widgetSchema->setNameFormat('contact[%s]');
$this->setValidators(array(
'name' => new sfValidatorString(array('required' => false)),
'email' => new sfValidatorEmail(),
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
'message' => new sfValidatorString(array('min_length' => 4)),
));
}
}
What you cannot see, that it accepts new inputs without validation settings and it does not check the presence of inputs which are not registered in the form. So this is a blacklist input validation. By whitelist you would define an input validator first, and only after that bind an input field to that validator. By a blacklist approach like this, it is easy to forget to add a validator to an input, and it works perfectly without that, so you would not notice the vulnerability, only when it is too late...
A hypothetical whitelist approach would look like something like this:
class ContactController {
/**
* #input("name", type = "string", singleLine = true, required = false)
* #input("email", type = "email")
* #input("subject", type = "string", alternatives = ['Subject A', 'Subject B', 'Subject C'])
* #input("message", type = "string", range = [4,])
*/
public function post(Inputs $inputs){
//automatically validates inputs
//throws error when an input is not on the list
//throws error when an input has invalid value
}
}
/**
* #controller(ContactController)
* #method(post)
*/
class ContactForm extends sfFormX {
public function configure(InputsMeta $inputs)
{
//automatically binds the form to the input list of the #controller.#method
//throws error when the #controller.#method.#input is not defined for a widget
$this->addWidgets(
new sfWidgetFormInput($inputs->name),
new sfWidgetFormInput($inputs->email),
new sfWidgetFormSelect($inputs->subject),
new sfWidgetFormTextarea($inputs->message)
);
$this->widgetSchema->setNameFormat('contact[%s]');
}
}
The best approach is to either use stored procedures or parameterized queries. White listing is an additional technique that is ok to prevent any injections before they reach the server, but should not be used as your primary defense. Black listing is usually a bad idea because it's usually impossible to filter out all malicious inputs.
BTW, this answer is considering you mean sanitizing as in preventing sql injection.
WL is a best practice against BL whenever it is practicable.
The reason is simple: you can't be reasonably safe enumerating what it is not permitted, an attacker could always find a way you did not think about. If you can, say what is allowed for sure, it is simpler and much much safer !
Let me explain your question with few more question and answer.
Blacklist VS Whitelist restriction
i. A Blacklist XSS and SQL Injection handling verifies a desired input against a list of negative input's. Basically one would compile a list of all the negative or bad conditions, and verifies that the input received is not one among the bad or negative conditions.
ii. A Whitelist XSS and SQL Injection handling verifies a desired input against a list of possible correct input's. To do this one would compile a list of all the good/positive input values/conditions, and verifies that the input received is one among the correct conditions.
Which one is better to have?
i. An attacker will use any possible means to gain access to your application. This includes trying all sort of negative or bad conditions, various encoding methods, and appending malicious input data to valid data. Do you think you can think of every possible bad permutation that could occur?
ii. A Whitelist is the best way to validate input. You will know exacty what is desired and that there is not any bad types accepted. Typically the best way to create a whitelist is with the use of regular expression's. Using regular expressions is a great way to abstract the whitelisting, instead of manually listing every possible correct value.
Build a good regular expression. Just because you are using a regular expression does not mean bad input will not be accepted. Make sure you test your regular expression and that invalid input cannot be accepted by your regular expression.
Personally, I gauge the number of allowed or disallowed characters and go from there. If there are more allowed chars than disallowed, then blacklist. Else whitelist. I don't believe that there is any 'standard' that says you should do it one way or the other.
BTW, this answer is assuming you want to limit inputs into form fields such as phone numbers or names :) #posterBelow
As a general rule it's best to use whitelist validation since it's easier to accept only characters you know should go there, for example if you have a field where the user inputs his/her phone number you could just do a regex and check that the values received are only numbers, drop everything else and just store the numbers. Note that you should proceed to validate the resulting numbers as well. Blacklist validation is weaker because a skilled attacker could evade your validation functions or send values that your function did not expect, from OWASP "Sanitize with Blacklist":
Eliminate or translate characters (such as to HTML entities or to remove quotes) in an effort to make the input "safe". Like blacklists, this approach requires maintenance and is usually incomplete. As most fields have a particular grammar, it is simpler, faster, and more secure to simply validate a single correct positive test than to try to include complex and slow sanitization routines for all current and future attacks.
Realize that this validation is just a first front defense against attacks. For XSS you should always "Escape" your output so you can print any character's needed but they are escaped meaning that they are changed to their HTML entity and thus the browser knows it's data and not something that the parser should interpret thus effectively shutting down all XSS attacks. For SQL injections escape all data before storing it, try to never use dynamic queries as they are the easiest type of query to exploit. Try to use parameterized store procedures. Also remember to use connections relevant to what the connection has to do. If the connection only needs to read data, create a db account with only "Read" privileges this depends mostly on the roles of the users. For more information please check the links from where this information was extracted from:
Data Validation OWASP
Guide to SQL Injection OWASP
The answer generally is, it depends.
For inputs with clearly defined parameters (say the equivalent of a dropdown menu), I would whitelist the options and ignore anything that wasn't one of those.
For free-text inputs, it's significantly more difficult. I subscribe to the school of thought that you should just filter it as best you can so it's as safe as possible (escape HTML, etc). Some other suggestions would be to specifically disallow any invalid input - however, while this might protect against attacks, it might also affect usability for genuine users.
I think it's just a case of finding the blend that works for you. I can't think of any one solution that would work for all possibilities. Mostly it depends on your userbase.

Resources