Creating filters
While the net::stubbles::ipo::request::filters package contains a whole bunch of filters where it is difficult to remember which filter to use for what and what they require, there is an easy way to create filter objects with the stubFilterFactory.
Numeric filters
To create a filter that filters values for numeric values, use this piece of code:
$intFilter = stubFilterFactory::forType('int');
$floatFilter = stubFilterFactory::forType('float');
Both filters will cast a given value to the respective type using the native PHP function settype.
Sometimes it is necessary to limit the lower and/or upper border of these values:
// value must be 1, 2, 3 or 4
$intFilter = stubFilterFactory::forType('int')->inRange(1, 4);
// value must be between 3.03 and 3.13
$floatFilter = stubFilterFactory::forType('float')->inRange(3.03, 3.13);
This will force the filter to do additionally checks, if the value is inside these borders. If you only want an upper border, use null for the first argument, if you only want a lower border use null for the second argument:
// value must be equal to or smaller than 4
$intFilter = stubFilterFactory::forType('int')->inRange(null, 4);
// value must be equal to or greater than 3.03
$floatFilter = stubFilterFactory::forType('float')->inRange(3.03, null);
Please note that the borders are inclusive and therefore valid values itself.
String filters
There are two kind of string filters available:
$stringFilter = stubFilterFactory::forType('string');
$textFilter = stubFilterFactory::forType('text');
While the string filter will remove all line breaks the text filter only removes windows line feeds, leaving unix line breaks. Both remove HTML tags from the value, but the text filter can be configured to allow certain type of tags:
$textFilter = stubFilterFactory::forType('text')->setAllowedTags(array('b', 'i'));
echo $textFilter->execute('This <b>text</b> <i>contains</i> a <a href="http://stubbles.org/">link</a>.');
The result will be This <b>text</b> <i>contains</i> a link. Please be aware that allowing any tag does not protect you against XSS attacks when using this filter.
Additionally you may sometimes check for the length of the string:
// only strings with 2, 3, 4 or 5 characters are allowed
$stringFilter = stubFilterFactory::forType('string')->length(2, 5);
$textFilter = stubFilterFactory::forType('text')->length(2, 5);
If you only want an upper border, use null for the first argument, if you only want a lower border use null for the second argument:
// string must be at least 2 characters long
$stringFilter = stubFilterFactory::forType('string')->length(2, null);
// string may be maximal 5 characters long
$textFilter = stubFilterFactory::forType('text')->length(null, 5);
Other filters
By default the filter factory can create three other types of filters as well:
HTTP filter
The HTTP filter checks if the given value is a valid URL with scheme HTTP or HTTPS.
$httpFilter = stubFilterFactory::forType('http', array($rveFactory));
It is possible to disable DNS checks, which are carried out by default:
$httpFilter = stubFilterFactory::forType('http', array($rveFactory))->checkDNS(false);
Please note that this does not change the filter behaviour on Windows systems, as PHP has no support for DNS checks under Windows.
Mail filter
The mail filter checks if the given value is a valid mail address:
$mail = stubFilterFactory::forType('mail', array($rveFactory));
Password filter
The password filter is able to do some specialised checks:
$password = stubFilterFactory::forType('password', array($rveFactory));
If the value to filter is an array the fields with key 0 and 1 are compared. If they are not equal the password is not allowed. This can be used to prevent mistyped passwords in register or password change forms.
Additionally it is possible to set the minimum amount of different characters a password must contain:
$password = stubFilterFactory::forType('password', array($rveFactory))->minDiffChars(3);
A password checked against this filter must contain at least three different characters.
It is possible to check against a list of non-allowed passwords (e.g. the username or the login name):
$password = stubFilterFactory::forType('password', array($rveFactory))->nonAllowedValues(array('foo', 'bar', 'baz'));
Now the values foo, bar and baz are not allowed as passwords any more.
Additionally the length of the password may be checked as well:
// password must be at least 8 characters long
$password = stubFilterFactory::forType('password', array($rveFactory))->length(8, null);
Of course it is possible to combine any of these requirements:
// password must be at least 5 characters long, contain at least 3 different characters,
// and foobar and barbaz are not allowed as password
$password = stubFilterFactory::forType('password', array($rveFactory))->length(5, null)->minDiffChars(3)->nonAllowedValues(array('foobar', 'barbaz'));
Decorating the filter
The following methods may be used to decorate the created filter. They are freely combinable. Please note that the sequence of the methods denotes the order in which the filters will be applied.
Default values
Sometimes it is necessary to return a default value instead of null if the given value to check is empty:
$filter = stubFilterFactory::forType('int')->inRange(1, 4)->defaultsTo(2);
Now, if the argument for the execute() method of the filter is empty, the filter will return 2 instead.
Using a validator
It may be a good idea to check the value to filter against a regular expression. The net::stubbles::util::validators package already contains a stubRegexValidator, so we reuse it:
$filter = stubFilterFactory::forType('string')->validatedBy(new stubRegexValidator($regex));
The validatedBy method takes any class implementing the net::stubbles::util::validators::stubValidator interface.
Encoding the value
In some cases it may be helpful to apply a net::stubbles::php::stubStringEncoder on the value to filter. For instance, it may be a good idea to encode the checked password:
$password = stubFilterFactory::forType('password', array($rveFactory))->encodedWith(new stubMd5Encoder());
(Please note that md5 in these days may not be secure enough.)
Decoding the value
In other cases it may be helpful to apply a net::stubbles::php::stubStringEncoder on the value to filter to decode a value. For instance, it may be a good idea to decode a base64-encoded value:
$password = stubFilterFactory::forType('string')->decodedWith(new stubBase64Encoder());
Forcing a non-empty value
All filters will work on empty values as well. To make sure that the value to check is not empty the required filter may be used:
$filter = stubFilterFactory::forType('int')->asRequired();
Now, if the value after its cast to int is empty, the filter will fail.
Examples
Some examples for useful filter combinations:
$filter = stubFilterFactory::forType('int')->inRange(1, 4)->asRequired();
$filter = stubFilterFactory::forType('int')->using(new MyRVEFactory())->inRange(1, 4)->asRequired();
$filter = stubFilterFactory::forType('int')->inRange(1, 4)->defaultsTo(2);
$filter = stubFilterFactory::forType('string')->length(2, 5)->validatedBy(new stubRegexValidator($regex))->asRequired();
$filter = stubFilterFactory::forType('string')->length(2, 5)->validatedBy(new stubRegexValidator($regex))->defaultsTo('foo');
$password = stubFilterFactory::forType('password', array($rveFactory))->length(5, null)->minDiffChars(3)->nonAllowedValues(array('foobar', 'barbaz'))->encodedWith(new stubMd5Encoder(), stubStringEncoder::MODE_ENCODE);
$http = stubFilterFactory::forType('http', array($rveFactory))->checkDNS(true);
$mail = stubFilterFactory::forType('mail', array($rveFactory));
Request value error factories
Beside the password, http and mail filter, which require an instance of net::stubbles::ipo::request::stubRequestValueErrorFactory on their construction, the usage of the request value error factory is hidden. The default implementation used is the net::stubbles::ipo::request::stubRequestValueErrorXJConfFactory. There are two ways of changing this:
1. Configure another class via the stubRegistry. To do this, the config value stored under the key net.stubbles.ipo.request.valueerrorfactory.class needs to contain the full qualified classname of the request value error factory implementation to be used instead.
2. Set the implementation to be used via using():
$filter = stubFilterFactory::forType('integer')->using(new MyRVEFactory())->inRange(1, 4)->asRequired();
Now all filters and filter decorators for this filter will use the MyRVEFactory instance. If you already supplied the request value error factory in the forType() method for the password, http or mail filter it is not required to set it again with using(), this instance will be reused then.
Registering own filters for the filter factory
Beside the default filters it is possible to register its own filters to be used with the forType() method. For this you need to provide an implementation of the net::stubbles::ipo::request::filters::provider::stubFilterProvider interface and add this to the filter factory with
stubFilterFactory::addFilterProvider(new MyFilterProvider());
Supposed the filter provider is responsible for the myfilter, you can now create an instance of it and decorating it using the filter factory:
$filter = stubFilterFactory::forType('myfilter')->asRequired()->validatedBy(new stubRegexValidator($regex));
If this is too much work you may skip the filter provider:
$filter = stubFilterFactory::forFilter(new MyFilter())->asRequired()->validatedBy(new stubRegexValidator($regex));
yields the same result without the need for a filter provider.
