Strange behavior with component Zend\InputFilter and 'required' => false, validator NotEmpty and validator Regex

NotEmpty validator is not considered with the ‘required’ => false from the input filter validation.
I would allow only to send a MD5 string, null have to be invalid. But the MD5 have not to be required.

This is the code to reproduce the strange behavior.

return new ValidationMiddleware([
   [
      'name' => 'name',
      'required' => false,
      'filters' => [
         [
            'name' => 'StripTags'
         ],
         [
            'name' => 'StringTrim'
         ],
         [
            'name' => 'StripNewlines'
         ]
      ],
      'validators' => [
         [
            'name' => 'NotEmpty',
         ],
         [
            'name' => 'Regex',
            'options' => [
               'pattern' => '/^[a-fA-F0-9]{32}$/'
         ]
      ]
   ]
]

When required attribute is set to false the validator NotEmpty it seems not to be considered. This means that I can send this request with this body

{
	"name": null
}

The request is valid also if the Regex is not valid: null should not be accepted by ‘/^[a-fA-F0-9]{32}$/’

If I remove ‘required’ => false from the input filter validation or I set to true, the filter work fine.
The result is:

{
    "errors": [
        {
            "name": "name",
            "value": null,
            "messages": [
                "Value is required and can't be empty",
                "Invalid type given. String, integer or float expected"
            ]
        }
    ],
    "title": "Bad Request",
    "type": "https://httpstatus.es/400",
    "status": 400,
    "detail": "Validation error"
}

Use the option continue_if_empty. Example:

$inputFilter = (new Zend\InputFilter\InputFilter())->getFactory()->createInputFilter(
    [
        [
            'name'              => 'foo',
            'required'          => false,
            'continue_if_empty' => true,
            'validators'        => [
                [
                    'name' => Zend\Validator\NotEmpty::class,
                ],
                [
                    'name'    => Zend\Validator\Regex::class,
                    'options' => [
                        'pattern' => '/^[a-fA-F0-9]{32}$/'
                    ]
                ]
            ]
        ]
    ]
);

$inputFilter->setData([]);
var_dump($inputFilter->isValid()); // true

$inputFilter->setData(['foo' => null]);
var_dump($inputFilter->isValid()); // false

$inputFilter->setData(['foo' => 'bar']);
var_dump($inputFilter->isValid()); // false

$inputFilter->setData(['foobar' => md5('bar')]);
var_dump($inputFilter->isValid()); // true

See also: https://github.com/zendframework/zend-inputfilter/blob/master/src/Input.php#L417-L419

1 Like

Thanks a lot, it works!