-
Notifications
You must be signed in to change notification settings - Fork 50
Null value for inputfilter causes exception #159
Comments
Passing nested => [] also works btw, which is clear from the code in the BaseInputFilter |
@weierophinney any clues? |
@MadeRelevant |
This is by design, currently. If you feel this should not be the case, please submit a pull request to allow passing null values. Thanks! |
I will post code to reproduce tomorrow. |
@MadeRelevant Let me flip the question around: why are you allowing a And, related to that: what should the behavior of the input filter be when the data set is set to |
Thanks. It is not exactly that im allowing them to enter a null value but someone can. I think the behavior should be the same as if they didnt enter a value at all. Our API client doesnt allow it actually but the issue came forward out of our tests. |
@weierophinney sorry for the delay but here is the code of the screenshot: public function testBrokenInputFilter() {
$filter1 = new InputFilter();
$filter1->add([
'type' => InputFilter::class,
'nestedField1' => [
'required' => false
]
], 'nested');
$filter1->setData([]);
self::assertNull($filter1->getValues()['nested']['nestedField1']); // <-- works
// this is a value that a client may send when they try to break the API or
// just don't know what to use as value for example. atm it produces an exception
$filter1->setData(['nested' => null]);
self::assertNull($filter1->getValues()['nested']['nestedField1']); // <-- should work
} If this is by design it seems inconsistent because entering null or an empty array is both invalid input but produce different results. The empty array produces no exception while the null value does. Having some inspection run before the call to setData() is made which transforms null values into an empty array if needed seems inefficient and can become very complex imo. |
…y array Per zendframework#159, `BaseInputFilter` works inconsistently when a `null` value is passed to `setData()`, interpreting this as an invalid argument type versus an empty data set. This is particularly problematic with nested sets sent via an API, as they may be nullable. In such cases, they should be treated the same as if an empty array were provided.
@weierophinney the changes are not within 2.8.1 |
Excuse me, it's there, my bad. A variation of the problem still exists. The expected behavior is imo also a bit vague, for example, an array is expected but someone passes an integer or a boolean, it feels strange to turn that into an empty array.. I suppose it is the only option for now? I suppose changing it into an empty array should be done here: https://github.com/zendframework/zend-inputfilter/blob/master/src/BaseInputFilter.php#L190-L196 What do you think? |
Why vague? The expected data types are zend-inputfilter/src/BaseInputFilter.php Lines 172 to 179 in a35c21a
This makes no sense. An input-filter normalizes and validates a set of inputs. If you only want to check one value then use the |
I meant by vague that i am not sure what the expected behavior should be if you dont throw an exception if the given datatype is not of type array (at the end). Sending something else like an integer or boolean doesnt make sense indeed but I dont have control over what a client sends to an input of type InputFilter. They dont care or dont know that it expects an array. Anyway, where an array, null or traversable is expected but a value not meeting that condition is given should be considered as invalid input and not throw an exception imo. Now, am exception gives no clue what i am missing or did wrong with my input, or even worse in production any api consumer cant see and dig into logs or whatever. If we threat any invalid value as empty instead of throwing an exception it would indicate in some way what is going on, what is vague to me. All not perfect if you ask me. |
You can control it. For example: /** @var \Psr\Http\Message\ServerRequestInterface $request */
$inputFilter->setData($request->getQueryParams()); or /** @var \Zend\Http\Request $request */
$inputFilter->setData($request->getPost()); or try {
$inputFilter->setData($data);
} catch (\Zend\InputFilter\Exception\InvalidArgumentException $e) {
// …
} |
@froschdesign Let me clarify with a simple example, assume the following input filter: $filter1 = new InputFilter();
$filter1->add([
'type' => InputFilter::class,
'nestedField1' => [
'required' => false
]
], 'nested');
$filter1->setData($request->getParsedBody()); Next, I will demonstrate two cases, from which one produces valid output and the other produces an exception or nothing in production. Expected {
"nested": null
} Unexpected {
"nested": 123
} However, I don't have control over what is sent to the InputFilter as you can see, the client has. I have to agree that sending back exactly the same as for the first example, saying it treats invalid data types as if it was empty, is also not as clear as I would like it to be.. Ofcourse, I could catch the exception but how would I figure out what was wrong? And in the end, I would just report something like 'hi, you did not enter a valid value for X.Y.Z' but resolving the path to X.Y.Z is way to complex if you ask me and should be the job of the InputFilter. Please let me know if there is something not clear or just doesn't make any sense.. |
The value of "nested" should be an array, it threw a exception if null, fixed in 2.8.1. Giving any non-null and non-iterable value produces an exception which is inconsistent. An exception being raised should never be influenced by user input or what is the purpose of the InputFilter? Do I manually need to check on those specific values? The test where it expects an exception is wrong and inconsistent imo. I have updated my previous post with correct examples. |
@MadeRelevant |
Btw. The method |
Sorry for late response. I have created a fork with the modified tests. @froschdesign The values used in the tests are values any user who has access to a http client can send to the input filter. It is the I.F's job to validate this input and not throw an exception when someone sends a boolean where an array is expected, imho. Let me know if I need to change anything before creating a pull request. |
You missed my last comment! Please see above. |
I didn't miss your comment. setData() calls populate() and the exception is thrown before it calls populate. From your middleware/controller or whatever you use you're supposed to call setData() as well. If you fix it within populate() the problem will still exist in root level input filter in case of invalid data type. Could you show me how you would implement it in case I missed something? @weierophinney could you have a look as well? |
Sorry this is wrong if you use nested input-filters. $filter1->setData(['nested' => false]);
…
$filter1->setData(['nested' => 123]);
…
$filter1->setData(['nested' => new stdClass()]); But this does not means we have to change the expected type for $filter1->setData(false);
Therefore you must look at the method
|
I guess we are getting stuck in this conversation because I dont understand how you would fix it within If |
We should not mix the problems here! Your API consumers are a different topic, which can be fixed by:
|
I updated the code. It fixes nested input filters.
|
Please provide your use case for this. Otherwise we can not reproduce your problem. $inputFilter->setData($_GET);
$inputFilter->setData($_POST);
$inputFilter->setData($request->getParsedBody());
// … No problematic data types. How do you use it? |
At the moment I cant come up with a scenario where this will be problematic, my bad.
I forgot that the null check remains within setData so in case the BodyParamsMIddleware I use from Zend Expressive results into an empty value everything will be fine. Shall I make the PR then? |
Please create a local branch for the bugfix. (see "Contributing Bugfixes or Features") |
PR is made |
Providing NULL as the value of nested input filter causes an exception to be thrown.
At the moment I only have my phone to post this issue so I will make a picture of the code to reproduce.
I am in the middle of moving and my ISP messed up :(
If you ommit the value its ok because an empty array will be used. I expected the same behaviour for NULL values.. Please tell me if I miss something here and how this should be fixed at my side in the case I did miss something.
The text was updated successfully, but these errors were encountered: