diff --git a/docs/filter-rules.md b/docs/filter-rules.md index a42e7fe..66f61d2 100644 --- a/docs/filter-rules.md +++ b/docs/filter-rules.md @@ -7,6 +7,7 @@ filters, take a look at the callback filter-rule, or check out "Extending the Fi * [append](#append) * [bool](#bool) * [callback](#callback) +* [encode](#encode) * [float](#float) * [int](#int) * [letters](#letters) @@ -68,6 +69,20 @@ $result = $f->filter(['name' => 'John']); // array(1) { ["name"]=> string(21) "John" ``` +## Encode + +Makes sure that the given value is in a specific encoding format. + +```php +$f = new Filter; +$f->value('text')->encode('Base64', 'UTF-8'); +$result = $f->filter(['text' => 'hello']); +// array(1) { ["text"]=> string(8) "aGVsbG8=" +``` + +if `$f->setEncodingFormat()` is set, you don't need to provide any parameters as the value encoding format will +be set to that. + ## Float Make sure the value is a float. diff --git a/docs/multibyte-encoding.md b/docs/multibyte-encoding.md new file mode 100644 index 0000000..78bbaff --- /dev/null +++ b/docs/multibyte-encoding.md @@ -0,0 +1,35 @@ +# Multibyte encoding + +To make sure your values get filtered correctly, we have to use the multi-byte (`mb_`) functionality from PHP. With +this feature comes the ability to set the encoding format on the filter. + +```php +$filter = new Particle\Filter\Filter; + +$filter->setEncodingFormat('utf-8'); // or another format if you like +``` + +If you don't use the function above, the string adaptive functions from php will use the default value from your +php.ini, which is most likely UTF-8. + +**Note:** Make sure that you set the encoding format on before you add any filter rules to the filter, otherwise the +default encoding format will be used on the filter rules defined before that setEncodingFormat. + +### Converting values to a specific encoding format + +If you know data is coming in in a different encoding format than what you want to be working with, you can use the +encode filter rule to convert the value. + +```php +$filter->value('first_name')->encode('UTF-8')->upper(); +``` + +### Using multibyte a regex + +If you want to use multi-byte encoded regex, the following php functions should be used: + +```php +mb_regex_encoding('UTF-8'); +``` + +These functions are not included in Particle\Filter as it might lead to unexpected behaviour. diff --git a/mkdocs.yml b/mkdocs.yml index 54f2fa6..2852f3c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,3 +6,4 @@ pages: - [basic-usage.md, Basic usage] - [filter-rules.md, Filter-rules] - [extending.md, Extending the Filter] +- [multibyte-encoding.md, Multibyte encoding] diff --git a/src/Chain.php b/src/Chain.php index 4b5b9de..ae8de80 100644 --- a/src/Chain.php +++ b/src/Chain.php @@ -40,10 +40,13 @@ public function filter($value) * Add a new rule to the chain * * @param FilterRule $rule + * @param string|null $encodingFormat * @return $this */ - public function addRule(FilterRule $rule) + public function addRule(FilterRule $rule, $encodingFormat) { + $rule->setEncodingFormat($encodingFormat); + $this->rules[] = $rule; return $this; diff --git a/src/Filter.php b/src/Filter.php index 267ce62..d2bb3f8 100644 --- a/src/Filter.php +++ b/src/Filter.php @@ -18,14 +18,19 @@ class Filter { /** - * @var Chain[] + * @var array */ protected $chains = []; /** * @var Container */ - protected $data = []; + protected $data; + + /** + * @var string|null + */ + protected $encodingFormat = null; /** * @var Chain @@ -80,6 +85,18 @@ public function getFilterResource($keys = null) return new FilterResource($this, $keys); } + /** + * Set the encoding format for all string manipulating filter-rules. + * Note: You should set the encoding format before you add filter-rules to your filter, otherwise the + * encoding format would not be set on the values added before the encoding format was set. + * + * @param string $encodingFormat + */ + public function setEncodingFormat($encodingFormat) + { + $this->encodingFormat = $encodingFormat; + } + /** * Set a filter rule on a chain * @@ -88,7 +105,7 @@ public function getFilterResource($keys = null) */ public function addFilterRule(FilterRule $rule, $key = null) { - $this->getChain($key)->addRule($rule); + $this->getChain($key)->addRule($rule, $this->encodingFormat); } /** @@ -121,7 +138,12 @@ protected function filterChains() { foreach ($this->chains as $key => $chain) { if ($this->data->has($key)) { - $this->data->set($key, $chain->filter($this->data->get($key))); + $this->data->set( + $key, + $chain->filter( + $this->data->get($key) + ) + ); } } } diff --git a/src/FilterResource.php b/src/FilterResource.php index 9e9cfe5..22be846 100644 --- a/src/FilterResource.php +++ b/src/FilterResource.php @@ -35,7 +35,7 @@ public function __construct(Filter $filter, $keys = null) } /** - * Add the alphabetic numeric rule to the chain + * Results rule that returns alphabetic numeric characters from the value * * @return $this */ @@ -45,7 +45,7 @@ public function alnum() } /** - * Add append filter-rule to the chain + * Results rule that returns the value appended with a given value * * @param string $append * @return Chain @@ -56,7 +56,7 @@ public function append($append) } /** - * Add bool filter-rule to the chain + * Results rule that returns a casted boolean * * @return $this */ @@ -66,8 +66,9 @@ public function bool() } /** - * Add callback filter-rule to the chain + * Returns rule that returns a value modified by a callable closure * + * @param callable $callable * @return $this */ public function callback(callable $callable) @@ -76,7 +77,19 @@ public function callback(callable $callable) } /** - * Add float filter-rule to the chain + * Returns rule that returns an value in a specific encoding format + * + * @param string|null $toEncodingFormat + * @param string|null $fromEncodingFormat + * @return FilterResource + */ + public function encode($toEncodingFormat = null, $fromEncodingFormat = null) + { + return $this->addRule(new FilterRule\Encode($toEncodingFormat, $fromEncodingFormat)); + } + + /** + * Returns rule that results a casted float * * @return $this */ @@ -86,7 +99,7 @@ public function float() } /** - * Add int filter-rule to the chain + * Returns rule that results a casted int * * @return $this */ @@ -96,7 +109,7 @@ public function int() } /** - * Add the letters-rule to the chain + * Returns rule that results all letters of a value * * @return $this */ @@ -106,7 +119,7 @@ public function letters() } /** - * Add lower filter-rule to the chain + * Returns rule that results a lower-cased value * * @return $this */ @@ -116,7 +129,7 @@ public function lower() } /** - * Add the numbers-rule to the chain + * Returns rule that results all numbers of a value * * @return $this */ @@ -126,7 +139,7 @@ public function numbers() } /** - * Add prepend filter-rule to the chain + * Results rule that returns the value prepended with a given value * * @param string $prepend * @return Chain @@ -137,7 +150,7 @@ public function prepend($prepend) } /** - * Add replace filter-rule to the chain + * Results rule that returns a value with replacements by a regex * * @param string $searchRegex * @param string $replace @@ -149,7 +162,7 @@ public function regexReplace($searchRegex, $replace) } /** - * Add replace filter-rule to the chain + * Results rule that returns a value with replacements * * @param mixed $search * @param mixed $replace @@ -161,7 +174,7 @@ public function replace($search, $replace) } /** - * Add string filter-rule to the chain + * Returns rule that results a casted string * * @return $this */ @@ -171,7 +184,7 @@ public function string() } /** - * Add stripHtml filter-rule to the chain + * Results rule that results a html-stripped value * * @param null|string $excludeTags * @return $this @@ -182,7 +195,7 @@ public function stripHtml($excludeTags = null) } /** - * Add trim filter-rule to the chain + * Returns rule that results a trimmed value * * @param string|null $characters * @return $this @@ -193,7 +206,7 @@ public function trim($characters = null) } /** - * Add upper filter-rule to the chain + * Results rule that returns an upper-cased value * * @return $this */ @@ -203,7 +216,7 @@ public function upper() } /** - * Add upper-first filter-rule to the chain + * Returns rule that results a value starting with a upper-cased character * * @return $this */ diff --git a/src/FilterRule.php b/src/FilterRule.php index eadaec4..d1db8e4 100644 --- a/src/FilterRule.php +++ b/src/FilterRule.php @@ -13,6 +13,19 @@ */ abstract class FilterRule { + /** + * @var string|null + */ + protected $encodingFormat; + + /** + * @param string|null $encodingFormat + */ + public function setEncodingFormat($encodingFormat) + { + $this->encodingFormat = $encodingFormat; + } + /** * @param mixed $value * @return mixed diff --git a/src/FilterRule/Encode.php b/src/FilterRule/Encode.php new file mode 100644 index 0000000..6d4dd8b --- /dev/null +++ b/src/FilterRule/Encode.php @@ -0,0 +1,62 @@ +encodingFormat; + } + + $this->toEncoding = $toEncoding; + $this->fromEncoding = $fromEncoding; + } + + /** + * Changes encoding of the value + * + * @param mixed $value + * @return string + */ + public function filter($value) + { + if ($this->toEncoding === null) { + return $value; + } + + if ($this->fromEncoding === null) { + return mb_convert_encoding($value, $this->toEncoding); + } + + return mb_convert_encoding($value, $this->toEncoding, $this->fromEncoding); + } +} diff --git a/src/FilterRule/Lower.php b/src/FilterRule/Lower.php index e9c69a9..f437376 100644 --- a/src/FilterRule/Lower.php +++ b/src/FilterRule/Lower.php @@ -25,6 +25,10 @@ class Lower extends FilterRule */ public function filter($value) { - return strtolower($value); + if ($this->encodingFormat !== null) { + return mb_strtolower($value, $this->encodingFormat); + } + + return mb_strtolower($value); } } diff --git a/src/FilterRule/Upper.php b/src/FilterRule/Upper.php index b615386..11a1b46 100644 --- a/src/FilterRule/Upper.php +++ b/src/FilterRule/Upper.php @@ -25,6 +25,10 @@ class Upper extends FilterRule */ public function filter($value) { - return strtoupper($value); + if ($this->encodingFormat !== null) { + return mb_strtoupper($value, $this->encodingFormat); + } + + return mb_strtoupper($value); } } diff --git a/src/FilterRule/UpperFirst.php b/src/FilterRule/UpperFirst.php index 70c9e46..d67a839 100644 --- a/src/FilterRule/UpperFirst.php +++ b/src/FilterRule/UpperFirst.php @@ -25,6 +25,14 @@ class UpperFirst extends FilterRule */ public function filter($value) { - return ucfirst($value); + if ($this->encodingFormat !== null) { + $firstChar = mb_substr($value, 0, 1, $this->encodingFormat); + $rest = mb_substr($value, 1, null, $this->encodingFormat); + return mb_strtoupper($firstChar, $this->encodingFormat) . $rest; + } + + $firstChar = mb_substr($value, 0, 1); + $rest = mb_substr($value, 1); + return mb_strtoupper($firstChar) . $rest; } } diff --git a/tests/FilterRule/AlnumTest.php b/tests/FilterRule/AlnumTest.php index 597aee2..0c05954 100644 --- a/tests/FilterRule/AlnumTest.php +++ b/tests/FilterRule/AlnumTest.php @@ -31,7 +31,7 @@ public function testAlnumFilterRule($value, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/AppendTest.php b/tests/FilterRule/AppendTest.php index a39e79f..a27d482 100644 --- a/tests/FilterRule/AppendTest.php +++ b/tests/FilterRule/AppendTest.php @@ -32,7 +32,7 @@ public function testAppendFilterRule($value, $append, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/BoolTest.php b/tests/FilterRule/BoolTest.php index 383699d..7580c9c 100644 --- a/tests/FilterRule/BoolTest.php +++ b/tests/FilterRule/BoolTest.php @@ -31,7 +31,7 @@ public function testBoolFilterRule($value, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/CallbackTest.php b/tests/FilterRule/CallbackTest.php index 70ff1cd..0aa44c6 100644 --- a/tests/FilterRule/CallbackTest.php +++ b/tests/FilterRule/CallbackTest.php @@ -32,7 +32,7 @@ public function testCallbackFilterRule($value, callable $callable, $filteredValu 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/EncodeTest.php b/tests/FilterRule/EncodeTest.php new file mode 100644 index 0000000..1c88d99 --- /dev/null +++ b/tests/FilterRule/EncodeTest.php @@ -0,0 +1,52 @@ +filter = new Filter(); + } + + /** + * @dataProvider getRegexReplaceResults + * @param string $value + * @param string|null $toFormat + * @param string|null $fromFormat + * @param string $filteredValue + */ + public function testRegexReplaceFilterRule($value, $toFormat, $fromFormat, $filteredValue) + { + $this->filter->value('test')->encode($toFormat, $fromFormat); + + $result = $this->filter->filter([ + 'test' => $value + ]); + + $this->assertEquals($filteredValue, $result['test']); + } + + /** + * @return array + */ + public function getRegexReplaceResults() + { + return [ + ['', null, null, ''], + ['hello', 'UTF-8', null, 'hello'], + ['hello', 'Base64', null, 'aGVsbG8='], + ['hello', 'Base64', 'UTF-8', 'aGVsbG8='], + ['aGVsbG8=', 'UTF-8', 'Base64', 'hello'], + ]; + } +} diff --git a/tests/FilterRule/FloatTest.php b/tests/FilterRule/FloatTest.php index 3a0bcce..d9efc23 100644 --- a/tests/FilterRule/FloatTest.php +++ b/tests/FilterRule/FloatTest.php @@ -31,7 +31,7 @@ public function testFloatFilterRule($value, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/IntTest.php b/tests/FilterRule/IntTest.php index b3543f9..2c7ca14 100644 --- a/tests/FilterRule/IntTest.php +++ b/tests/FilterRule/IntTest.php @@ -31,7 +31,7 @@ public function testIntFilterRule($value, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/LettersTest.php b/tests/FilterRule/LettersTest.php index b413868..75564ac 100644 --- a/tests/FilterRule/LettersTest.php +++ b/tests/FilterRule/LettersTest.php @@ -31,7 +31,7 @@ public function testLettersFilterRule($value, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/LowerTest.php b/tests/FilterRule/LowerTest.php index d8ad549..7982078 100644 --- a/tests/FilterRule/LowerTest.php +++ b/tests/FilterRule/LowerTest.php @@ -22,16 +22,21 @@ public function setUp() * @dataProvider getLowerResults * @param string $value * @param string $filteredValue + * @param string|null $encodingFormat */ - public function testLowerFilterRule($value, $filteredValue) + public function testLowerFilterRule($value, $filteredValue, $encodingFormat) { + if ($encodingFormat !== null) { + $this->filter->setEncodingFormat($encodingFormat); + } + $this->filter->value('test')->lower(); $result = $this->filter->filter([ 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** @@ -40,11 +45,13 @@ public function testLowerFilterRule($value, $filteredValue) public function getLowerResults() { return [ - ['text is low', 'text is low'], - ['', ''], - ['LOL', 'lol'], - ['L0L', 'l0l'], - ['~!LoLz!~', '~!lolz!~'], + ['text is low', 'text is low', null], + ['', '', null], + ['LOL', 'lol', null], + ['L0L', 'l0l', null], + ['~!LoLz!~', '~!lolz!~', null], + ['CE GARÇON EST TOMBÉ', 'ce garçon est tombé', 'utf-8'], + ['Τάχιστη αλώπηξ βαφής ψημένη γη', 'τάχιστη αλώπηξ βαφής ψημένη γη', 'utf-8'], ]; } } diff --git a/tests/FilterRule/NumbersTest.php b/tests/FilterRule/NumbersTest.php index ec23e36..a022a39 100644 --- a/tests/FilterRule/NumbersTest.php +++ b/tests/FilterRule/NumbersTest.php @@ -31,7 +31,7 @@ public function testNumbersFilterRule($value, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/PrependTest.php b/tests/FilterRule/PrependTest.php index 0b744fd..46508be 100644 --- a/tests/FilterRule/PrependTest.php +++ b/tests/FilterRule/PrependTest.php @@ -32,7 +32,7 @@ public function testPrependFilterRule($value, $prepend, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/RegexReplaceTest.php b/tests/FilterRule/RegexReplaceTest.php index fb6bf71..02e99f2 100644 --- a/tests/FilterRule/RegexReplaceTest.php +++ b/tests/FilterRule/RegexReplaceTest.php @@ -21,7 +21,7 @@ public function setUp() /** * @dataProvider getRegexReplaceResults * @param string $value - * @param string $search + * @param string $searchRegex * @param string $replace * @param string $filteredValue */ @@ -33,7 +33,7 @@ public function testRegexReplaceFilterRule($value, $searchRegex, $replace, $filt 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/ReplaceTest.php b/tests/FilterRule/ReplaceTest.php index 53b0e6a..9305d3b 100644 --- a/tests/FilterRule/ReplaceTest.php +++ b/tests/FilterRule/ReplaceTest.php @@ -33,7 +33,7 @@ public function testReplaceFilterRule($value, $search, $replace, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** @@ -46,6 +46,7 @@ public function getReplaceResults() ['no spaces please', ' ', '-', 'no-spaces-please'], ['ror', 'r', 'l', 'lol'], ['no spaces please', [' ', ' '], '-', 'no-spaces-please'], + ['漢字はユニコード', 'は', 'Foo', '漢字Fooユニコード'], ]; } } diff --git a/tests/FilterRule/StringTest.php b/tests/FilterRule/StringTest.php index fc6c256..ac87b29 100644 --- a/tests/FilterRule/StringTest.php +++ b/tests/FilterRule/StringTest.php @@ -31,7 +31,7 @@ public function testStringFilterRule($value, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/StripHtmlTest.php b/tests/FilterRule/StripHtmlTest.php index 81b0b96..8a7e62a 100644 --- a/tests/FilterRule/StripHtmlTest.php +++ b/tests/FilterRule/StripHtmlTest.php @@ -32,7 +32,7 @@ public function testStripHtmlFilterRule($value, $excludeTags, $filteredValue) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/TrimTest.php b/tests/FilterRule/TrimTest.php index 9a5cddb..eaedf07 100644 --- a/tests/FilterRule/TrimTest.php +++ b/tests/FilterRule/TrimTest.php @@ -36,7 +36,7 @@ public function testTrimFilterRule($value, $filteredValue, $characters) 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** diff --git a/tests/FilterRule/UpperFirstTest.php b/tests/FilterRule/UpperFirstTest.php index eba0c72..e39ee9b 100644 --- a/tests/FilterRule/UpperFirstTest.php +++ b/tests/FilterRule/UpperFirstTest.php @@ -22,16 +22,21 @@ public function setUp() * @dataProvider getUpperFirstResults * @param string $value * @param string $filteredValue + * @param string|null $encodingFormat */ - public function testUpperFirstFilterRule($value, $filteredValue) + public function testUpperFirstFilterRule($value, $filteredValue, $encodingFormat) { + if ($encodingFormat !== null) { + $this->filter->setEncodingFormat($encodingFormat); + } + $this->filter->value('test')->upperFirst(); $result = $this->filter->filter([ 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** @@ -40,11 +45,12 @@ public function testUpperFirstFilterRule($value, $filteredValue) public function getUpperFirstResults() { return [ - ['text is low', 'Text is low'], - ['', ''], - ['lol', 'Lol'], - ['l0l', 'L0l'], - ['~!lolz!~', '~!lolz!~'], + ['', '', null], + ['text is low', 'Text is low', null], + ['l0l', 'L0l', null], + ['~!lolz!~', '~!lolz!~', null], + ['çon est tombé', 'Çon est tombé', 'utf-8'], + ['τάχιστη αλώπηξ βαφής ψημένη γη', 'Τάχιστη αλώπηξ βαφής ψημένη γη', 'utf-8'], ]; } } diff --git a/tests/FilterRule/UpperTest.php b/tests/FilterRule/UpperTest.php index 389f753..3b2dfac 100644 --- a/tests/FilterRule/UpperTest.php +++ b/tests/FilterRule/UpperTest.php @@ -22,16 +22,21 @@ public function setUp() * @dataProvider getUpperResults * @param string $value * @param string $filteredValue + * @param string|null $encodingFormat */ - public function testUpperFilterRule($value, $filteredValue) + public function testUpperFilterRule($value, $filteredValue, $encodingFormat) { + if ($encodingFormat !== null) { + $this->filter->setEncodingFormat($encodingFormat); + } + $this->filter->value('test')->upper(); $result = $this->filter->filter([ 'test' => $value ]); - $this->assertEquals($result['test'], $filteredValue); + $this->assertEquals($filteredValue, $result['test']); } /** @@ -40,11 +45,12 @@ public function testUpperFilterRule($value, $filteredValue) public function getUpperResults() { return [ - ['text is up', 'TEXT IS UP'], - ['', ''], - ['lol', 'LOL'], - ['l0l', 'L0L'], - ['~!LoLz!~', '~!LOLZ!~'], + ['', '', null], + ['text is up', 'TEXT IS UP', null], + ['l0l', 'L0L', null], + ['~!LoLz!~', '~!LOLZ!~', null], + ['ce garçon est tombé', 'CE GARÇON EST TOMBÉ', 'utf-8'], + ['τάχιστη αλώπηξ βαφής ψημένη γη', 'ΤΆΧΙΣΤΗ ΑΛΏΠΗΞ ΒΑΦΉΣ ΨΗΜΈΝΗ ΓΗ', 'utf-8'], ]; } }