├── .gitignore
├── LICENSE
├── README.md
├── composer.json
├── examples
├── ExampleValidator.php
└── index.php
├── phpunit.xml
├── tests
├── BooleanValidatorTest.php
├── CompareValidatorTest.php
├── EmailValidatorTest.php
├── FileValidatorTest.php
├── NumberValidatorTest.php
├── PhoneValidatorTest.php
├── RangeValidatorTest.php
├── RequiredValidatorTest.php
├── StringValidatorTest.php
├── UniqueValidatorTest.php
├── UrlValidatorTest.php
└── ValidatorTest.php
└── valify
├── Validator.php
└── validators
├── AbstractValidator.php
├── BooleanValidator.php
├── CompareValidator.php
├── EmailValidator.php
├── FileValidator.php
├── NumberValidator.php
├── PhoneValidator.php
├── RangeValidator.php
├── RequiredValidator.php
├── StringValidator.php
├── UniqueValidator.php
└── UrlValidator.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /index.php
3 | /vendor
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 xphoenyx
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | __*NB! This project is archived thus not maintained anymore*__
2 |
3 | # Valify
4 | A little framework for user input validation. It is still in development, so keep an eye on commits.
5 | Inspired by [Yii2 input validation implementation](https://github.com/yiisoft/yii2/blob/master/docs/guide/input-validation.md).
6 |
7 | ## Requirements
8 | You need PHP 5.4 to run this code.
9 |
10 | ## Installation
11 | After downloading source, add next code to file, where you data is going to be validated:
12 |
13 | ```php
14 | require 'valify/Validator.php';
15 | $validator = new Validator();
16 | ```
17 |
18 | Framework uses namespaces, so add next line to the top of file, where validator is called:
19 |
20 | ```php
21 | use valify\Validator;
22 | ```
23 |
24 | There is also a more straightforward way to install this framework through the compser.
25 | In your project root, issue next command in terminal:
26 |
27 | `php composer.phar require xphoenyx/valify 1.*`
28 |
29 | Now you are ready to validate your data.
30 |
31 | ### Hint for a MVC pattern users
32 |
33 | You can implement your own methods in base model class.
34 | Please investigate an example below:
35 |
36 | ```php
37 |
38 | use valify\Validator;
39 |
40 | class Model {
41 | /* ... */
42 |
43 | protected $validator;
44 | // Your rules
45 | public $rules = [];
46 | // Here is stored $_POST, for example
47 | public $data = [];
48 |
49 | function __construct() {
50 | /* ... */
51 | $this->validator = new Validator();
52 | /* ... */
53 | }
54 |
55 | /*
56 | * Your other methods
57 | */
58 |
59 | public function validate() {
60 | return $this->validator
61 | ->setRules($this->rules)
62 | ->loadData($this->data)
63 | ->validate();
64 | }
65 |
66 | public function getErrors() {
67 | return $this->validator->getErrors();
68 | }
69 | }
70 | ```
71 |
72 | ## Usage
73 | Usage is similar to [Yii2 input validation](https://github.com/yiisoft/yii2/blob/master/docs/guide/input-validation.md).
74 |
75 | ### Define rules
76 |
77 | ```php
78 | $rules = [
79 | [['username', 'password'], 'string', 'max'=>10],
80 | ['email', 'email', 'message'=>'Please provide a valid email'],
81 | ['remember_me', 'boolean']
82 | /* ... */
83 | ];
84 | ```
85 |
86 | Each validator accepts `message` parameter, which should contain an error message as string.
87 | You can access attribute name and its value in `message` by using so-called 'patterns':
88 |
89 | ```php
90 | ['email', 'email', 'message'=>'{value} for attribute "{attribute}" is not a valid email'],
91 | ```
92 |
93 | *NB! If the value is not representable as a string, value type will be shown instead of value itself*
94 |
95 | You can also implement your own validators by extending `valify\validator\AbstractValidator` class.
96 | In this case, if you are not using composer autoloader, you should also import (require) AbstractValidator.
97 | To use own validator in rules, just define validator namespace as a validator name:
98 |
99 | ```php
100 | $rules = [
101 | /* ... */
102 | ['email', '\\examples\\ExampleValidator', 'ownProperty'=>'abc' /* ... */]
103 | /* ... */
104 | ];
105 | ```
106 |
107 | Make sure your validator is loaded before defining a namespace in rules.
108 | Refer to the `valify\validators\ExampleValidator` for detailed implementation info.
109 |
110 | ### Define data to be validated
111 |
112 | Input data is expected in next format:
113 |
114 | ```php
115 | $data = [
116 | 'username'=>'username',
117 | 'password'=>'123qwe',
118 | 'email'=>'address@gmail.com',
119 | 'remember_me'=>'1',
120 | /* ... */
121 | ];
122 | ```
123 |
124 | ### Set rules and data
125 |
126 | ```php
127 | $validator = new Validator();
128 | $validator = $validator->setRules($rules)->loadData($data)
129 | ```
130 |
131 | You can call `setrules()` and `loadData()` multiple times:
132 |
133 | ```php
134 | $validator = new Validator();
135 | $validator = $validator
136 | ->setRules([...])
137 | ->loadData([...])
138 | ->setRules([...])
139 | ->setRules([...])
140 | ->loadData([...])
141 | ->loadData([...]);
142 | ```
143 |
144 | ### Execute validation
145 |
146 | ```php
147 | $isValid = $validator->validate();
148 | ```
149 |
150 | You have an ability to perform a single value validation, without calling `setRules()` and `loadData()`:
151 |
152 | ```php
153 | $password = $_POST['password'];
154 | $isValid = Validator::validateFor('string', $password, ['min'=>6, 'max'=>20]);
155 | ```
156 |
157 | For multiple value validation, pass an array of desired values as a second argument:
158 |
159 | ```php
160 | $values = [
161 | $_POST['username'],
162 | $_POST['first_name'],
163 | $_POST['password'],
164 | ];
165 | $isValid = Validator::validateFor('string', $values, ['min'=>3, 'max'=>30]);
166 | ```
167 |
168 | `validateFor()` will return an object with two properties:
169 | - `isValid` - contains boolean value;
170 | - `lastError` - contains last validation error message;
171 | - `errors` - contains whole error message stack for validating attribute;
172 |
173 | ### Fetch error messages
174 |
175 | ```php
176 | if($validator->hasErrors()) {
177 | $errorMsgs = $validator->getErrors();
178 | }
179 | ```
180 |
181 | You can also get an error message of a single attribute:
182 |
183 | ```php
184 | $errorMsgForUserAttr = $validator->getError('username');
185 | ```
186 |
187 | As each attribute can have a few error messages, `getError()` will give you
188 | the last message of the corresponding attribute error stack (array).
189 |
190 | ## List of built-in validators:
191 | * boolean
192 | * email
193 | * file
194 | * required
195 | * string
196 | * url
197 | * phone
198 | * in
199 | * number
200 | * compare
201 | * unique
202 |
203 | For detailed parameter description of each validator, see class methods in valify/validators.
204 |
205 | ## Testing
206 | In order to properly run unit tests, you need to specify path to the composer autoloader file.
207 | Then you just issue the `phpunit` command in terminal under `valify` (component root) directory.
208 |
209 | ## Examples
210 | Check index.php in `examples` directory to view framework in action.
211 |
212 | All bug and issue reports are welcome as well as improvement proposals. Enjoy.
213 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xphoenyx/valify",
3 | "type": "library",
4 | "description": "A little framework for user input validation",
5 | "keywords": ["validation", "validator", "validate"],
6 | "homepage": "https://github.com/xphoenyx/valify",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "Pavel Borunov",
11 | "email": "0xphoenyx0@gmail.com",
12 | "role": "Developer"
13 | }
14 | ],
15 | "require": {
16 | "php": ">=5.4.0"
17 | },
18 | "require-dev": {
19 | "phpunit/phpunit": "4.0.*"
20 | },
21 | "autoload": {
22 | "psr-4": {
23 | "valify\\": "valify"
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/examples/ExampleValidator.php:
--------------------------------------------------------------------------------
1 | attribute.
70 | *
71 | * @param $value
72 | */
73 | protected function validateValue($value) {
74 | // Set an error message with some params (you can call addError() as many times as you want):
75 | $this->addError('Example error; Called at: {time}', ['{time}'=>date('H:i')]);
76 |
77 | // Your validation code here
78 | }
79 | }
--------------------------------------------------------------------------------
/examples/index.php:
--------------------------------------------------------------------------------
1 | 10],
19 | ['email', 'email', 'message'=>'Please provide a valid email'],
20 | ['remember_me', 'boolean'],
21 | ['file', 'file', 'minSize'=>10000, 'maxFiles'=>2, 'extensions'=>['jpg'], 'checkExtensionByMimeType'=>false]
22 | // ['email', 'your\\own\\namespace\\ValidatorClass']
23 | ];
24 |
25 | if(!empty($_POST)) {
26 | $data = $_POST;
27 | $data['file'] = $_FILES['file'];
28 | $isValid = $validator->setRules($rules)->loadData($data)->validate();
29 | }
30 |
31 | function getValue($val) {
32 | return isset($_POST[$val]) ? $_POST[$val] : '';
33 | }
34 |
35 | ?>
36 |
37 |
38 |
39 |
40 |
45 |
46 |
47 |
121 |
122 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 | tests
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/BooleanValidatorTest.php:
--------------------------------------------------------------------------------
1 | '1', 'bool2'=>'0'])->isValid;
12 |
13 | $this->assertTrue($isValid);
14 | }
15 |
16 | public function testIntIsValid()
17 | {
18 | $isValid = Validator::validateFor('boolean', ['bool1'=>1, 'bool2'=>0])->isValid;
19 |
20 | $this->assertTrue($isValid);
21 | }
22 |
23 | public function testStrictStringIsValid()
24 | {
25 | $isValid = Validator::validateFor('boolean', ['bool1'=>'1', 'bool2'=>'0'], ['strict'=>true])->isValid;
26 |
27 | $this->assertTrue($isValid);
28 | }
29 |
30 | public function testStrictIntIsValid()
31 | {
32 | $isValid = Validator::validateFor('boolean', ['bool1'=>1, 'bool2'=>0], ['strict'=>true])->isValid;
33 |
34 | $this->assertFalse($isValid);
35 | }
36 |
37 | public function testStrictAnythingElseIsValid()
38 | {
39 | $data = [
40 | 'notBool1'=>'bar',
41 | 'notBool2'=>2,
42 | 'notBool3'=>123.456,
43 | 'notBool4'=>true,
44 | 'notBool5'=>null
45 | ];
46 |
47 | $isValid = Validator::validateFor('boolean', $data, ['strict'=>true])->isValid;
48 |
49 | $this->assertFalse($isValid);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/tests/CompareValidatorTest.php:
--------------------------------------------------------------------------------
1 | '='])->isValid;
11 |
12 | $this->assertFalse($isValid);
13 | }
14 |
15 | public function testAreRepresentableDataTypesValid()
16 | {
17 | $data = [
18 | null,
19 | 1234,
20 | 1234.5678
21 | ];
22 |
23 | $isValid = true;
24 | $message = null;
25 | foreach ($data as $value) {
26 | $valid = Validator::validateFor('compare', $value, ['compareValue' => $value]);
27 | if(!$valid->isValid) {
28 | $isValid = false;
29 | $message = $valid->error;
30 | break;
31 | }
32 | }
33 |
34 | $this->assertTrue($isValid, $message);
35 | }
36 |
37 | public function testSoftComparison() {
38 | $isValid = Validator::validateFor('compare', 1234, ['compareValue' => '1234'])->isValid;
39 |
40 | $this->assertTrue($isValid);
41 | }
42 |
43 | public function testStrictComparison() {
44 | $isValid = Validator::validateFor('compare', 12345, ['compareValue' => '12345', 'operator' => '==='])->isValid;
45 |
46 | $this->assertFalse($isValid);
47 | }
48 |
49 | public function testSoftInvertedComparison() {
50 | $isValid = Validator::validateFor('compare', 12345, ['compareValue' => '12345', 'operator' => '!='])->isValid;
51 |
52 | $this->assertFalse($isValid);
53 | }
54 |
55 | public function testStrictInvertedComparison() {
56 | $isValid = Validator::validateFor('compare', 12345, ['compareValue' => '12345', 'operator' => '!=='])->isValid;
57 |
58 | $this->assertTrue($isValid);
59 | }
60 |
61 | public function testBiggerThanComparison() {
62 | $isValid = Validator::validateFor('compare', 12345.2, ['compareValue' => 12345.1, 'operator' => '>'])->isValid;
63 |
64 | $this->assertTrue($isValid);
65 | }
66 |
67 | public function testMoreOrEqualComparison() {
68 | $data = [
69 | 12344 => 12344,
70 | 12345 => 12344
71 | ];
72 |
73 | $isValid = true;
74 | foreach ($data as $val => $compVal) {
75 | $valid = Validator::validateFor('compare', $val, ['compareValue' => $compVal, 'operator' => '>='])->isValid;
76 | if(!$valid)
77 | $isValid = false;
78 | }
79 |
80 | $this->assertTrue($isValid);
81 | }
82 |
83 | public function testLessThanComparison() {
84 | $isValid = Validator::validateFor('compare', 12345.1, ['compareValue' => 12345.2, 'operator' => '<'])->isValid;
85 |
86 | $this->assertTrue($isValid);
87 | }
88 |
89 | public function testLessOrEqualComparison() {
90 | $data = [
91 | 12345 => 12345,
92 | 12344 => 12345
93 | ];
94 |
95 | $isValid = true;
96 | foreach ($data as $val => $compVal) {
97 | $valid = Validator::validateFor('compare', $val, ['compareValue' => $compVal, 'operator' => '<='])->isValid;
98 | if(!$valid)
99 | $isValid = false;
100 | }
101 |
102 | $this->assertTrue($isValid);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/tests/EmailValidatorTest.php:
--------------------------------------------------------------------------------
1 | isValid;
19 |
20 | $this->assertFalse($isValid);
21 | }
22 |
23 | public function testIsRegExpWorkingProperly() {
24 | $data = [
25 | 'gmail.com',
26 | 'address@gmail',
27 | ];
28 |
29 | $isValid = Validator::validateFor('email', $data)->isValid;
30 |
31 | $this->assertFalse($isValid);
32 | }
33 |
34 | public function testIsDnsFake() {
35 | $isValid = Validator::validateFor('email', 'address@fakedns.eu', ['checkDNS'=>true])->isValid;
36 |
37 | $this->assertFalse($isValid);
38 | }
39 |
40 | public function testIsEmailValid() {
41 | $isValid = Validator::validateFor('email', 'address@gmail.com', ['checkDNS'=>true])->isValid;
42 |
43 | $this->assertTrue($isValid);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/FileValidatorTest.php:
--------------------------------------------------------------------------------
1 | validator = new Validator();
14 |
15 |
16 | $this->path = __DIR__ . '/testfile.txt';
17 |
18 | $testFile = fopen($this->path, "w");
19 | $txt = '';
20 | for($i = 0; $i < 10000; $i++)
21 | $txt .= 'Test text ';
22 | fwrite($testFile, $txt);
23 | fclose($testFile);
24 |
25 | $this->mimeType = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $this->path);
26 | $this->size = filesize($this->path);
27 | }
28 |
29 | public function testIsFakeFileDataValid()
30 | {
31 |
32 | $data = [
33 | 'testFile' => [
34 | 'name' => 'testfile.txt',
35 | 'type' => $this->mimeType,
36 | // 'size' => $this->size, // Lets omit this line to make file data not valid
37 | 'tmp_name' => $this->path,
38 | 'error' => 0,
39 | ]
40 | ];
41 |
42 | // $validator = $this->validator->setRules([[array_keys($data), 'file']]);
43 | //
44 | // $isValid = $validator->loadData($data)->validate();
45 | // $this->assertEquals(false, $isValid);
46 |
47 |
48 | $isValid = Validator::validateFor('file', $data)->isValid;
49 |
50 | $this->assertFalse($isValid);
51 | }
52 |
53 | public function testIsEmptyFileDataValid() {
54 | $data = [
55 | 'testFile' => [
56 | 'name' => '',
57 | 'type' => '',
58 | 'size' => '',
59 | 'tmp_name' => '',
60 | 'error' => 4, // Means that empty file uploaded
61 | ]
62 | ];
63 |
64 | # When using static method validateFor(),
65 | # the value is being checked for emptiness.
66 | # We allow empty value for this case
67 | # by setting 'allowEmpty to true just
68 | # to check that if all array keys exist
69 | # in file array, the file counts as valid
70 | $isValid = Validator::validateFor('file', $data, ['allowEmpty' => true])->isValid;
71 |
72 | $this->assertTrue($isValid);
73 | }
74 |
75 | public function testIsTooBigAmountOfFilesValid() {
76 | $data = [
77 | 'testFile' => [
78 | 'name' => ['testfile.txt', 'testfile.txt'],
79 | 'type' => [$this->mimeType, $this->mimeType],
80 | 'size' => [$this->size, $this->size],
81 | 'tmp_name' => [$this->path, $this->path],
82 | 'error' => [0, 0],
83 | ]
84 | ];
85 |
86 | # By default, only a single file is allowed to be uploaded.
87 | # So multiple file upload should not be valid.
88 | $isValid = Validator::validateFor('file', $data)->isValid;
89 |
90 | $this->assertFalse($isValid);
91 | }
92 |
93 | public function testIsTooBigSizeValid() {
94 | $data = [
95 | 'testFile' => [
96 | 'name' => 'testfile.txt',
97 | 'type' => $this->mimeType,
98 | 'size' => $this->size,
99 | 'tmp_name' => $this->path,
100 | 'error' => 0,
101 | ]
102 | ];
103 |
104 | // $validator = $this->validator->setRules([[array_keys($data), 'file', 'maxSize' => 900]]);
105 | //
106 | // $isValid = $validator->loadData($data)->validate();
107 | // $this->assertEquals(false, $isValid);
108 |
109 |
110 | $isValid = Validator::validateFor('file', $data, ['maxSize' => 900])->isValid;
111 |
112 | $this->assertFalse($isValid);
113 | }
114 |
115 | public function testIsTooSmallSizeValid() {
116 | $data = [
117 | 'testFile' => [
118 | 'name' => 'testfile.txt',
119 | 'type' => $this->mimeType,
120 | 'size' => $this->size,
121 | 'tmp_name' => $this->path,
122 | 'error' => 0,
123 | ]
124 | ];
125 |
126 | // $validator = $this->validator->setRules([[array_keys($data), 'file', 'minSize' => 9000000]]);
127 | //
128 | // $isValid = $validator->loadData($data)->validate();
129 | // $this->assertEquals(false, $isValid);
130 |
131 | $isValid = Validator::validateFor('file', $data, ['minSize' => 9000000])->isValid;
132 |
133 | $this->assertFalse($isValid);
134 | }
135 |
136 | public function testIsWrongExtensionValid() {
137 | $data = [
138 | 'testFile' => [
139 | 'name' => 'testfile.txt',
140 | 'type' => $this->mimeType,
141 | 'size' => $this->size,
142 | 'tmp_name' => $this->path,
143 | 'error' => 0,
144 | ]
145 | ];
146 |
147 | // $validator = $this->validator->setRules([[array_keys($data), 'file', 'extensions' => ['jpg'], 'checkExtensionByMimeType' => false]]);
148 | //
149 | // $isValid = $validator->loadData($data)->validate();
150 | // $this->assertEquals(false, $isValid);
151 |
152 |
153 | $isValid = Validator::validateFor('file', $data, ['extensions' => ['jpg'], 'checkExtensionByMimeType' => false])->isValid;
154 |
155 | $this->assertFalse($isValid);
156 | }
157 |
158 | public function testIsWrongMimeTypeValid() {
159 | $data = [
160 | 'testFile' => [
161 | 'name' => 'testfile.jpg',
162 | 'type' => $this->mimeType,
163 | 'size' => $this->size,
164 | 'tmp_name' => $this->path,
165 | 'error' => 0,
166 | ]
167 | ];
168 |
169 | $isValid = Validator::validateFor('file', $data, ['extensions' => ['jpg']])->isValid;
170 |
171 | $this->assertFalse($isValid);
172 | }
173 |
174 | public function testIsProperFileValidationWorking() {
175 | $data = [
176 | 'testFile' => [
177 | 'name' => 'testfile.txt',
178 | 'type' => $this->mimeType,
179 | 'size' => $this->size,
180 | 'tmp_name' => $this->path,
181 | 'error' => 0,
182 | ]
183 | ];
184 |
185 | $isValid = Validator::validateFor('file', $data, ['extensions' => ['txt']])->isValid;
186 |
187 | $this->assertTrue($isValid);
188 | }
189 |
190 | public function tearDown()
191 | {
192 | unlink($this->path);
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/tests/NumberValidatorTest.php:
--------------------------------------------------------------------------------
1 | isValid;
10 |
11 | $this->assertFalse($isValid);
12 | }
13 |
14 | public function testIsTextIsValid() {
15 | $isValid = Validator::validateFor('number', 'asfsa656')->isValid;
16 |
17 | $this->assertFalse($isValid);
18 | }
19 |
20 | public function testIsStringValid() {
21 | $isValid = Validator::validateFor('number', '656.35')->isValid;
22 |
23 | $this->assertTrue($isValid);
24 | }
25 |
26 | public function testIsValidWithIntegerOnlyEnabled() {
27 | $isValid = Validator::validateFor('number', 656.35, ['integerOnly'=>true])->isValid;
28 |
29 | $this->assertFalse($isValid);
30 | }
31 |
32 | public function testIsBiggerThanAllowedValid() {
33 | $isValid = Validator::validateFor('number', 656.35, ['max'=>656])->isValid;
34 |
35 | $this->assertFalse($isValid);
36 | }
37 |
38 | public function testIsLessThanAllowedValid() {
39 | $isValid = Validator::validateFor('number', 656.35, ['min'=>657])->isValid;
40 |
41 | $this->assertFalse($isValid);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/PhoneValidatorTest.php:
--------------------------------------------------------------------------------
1 | isValid;
11 |
12 | $this->assertFalse($isValid);
13 | }
14 |
15 | public function testIsTooShortValid()
16 | {
17 | $isValid = Validator::validateFor('phone', '555')->isValid;
18 |
19 | $this->assertFalse($isValid);
20 | }
21 |
22 | public function testIsValidWithCountryCodeCheck()
23 | {
24 | $isValid = Validator::validateFor('phone', '55555555')->isValid;
25 |
26 | $this->assertFalse($isValid);
27 | }
28 |
29 | public function testIsValidWithoutCountryCodeCheck()
30 | {
31 | $isValid = Validator::validateFor('phone', '55555555', ['checkCountryCode'=>false])->isValid;
32 |
33 | $this->asserttrue($isValid);
34 | }
35 |
36 | public function testIsValidWitCountryCode()
37 | {
38 | $isValid = Validator::validateFor('phone', '+999 55555555')->isValid;
39 |
40 | $this->assertTrue($isValid);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/RangeValidatorTest.php:
--------------------------------------------------------------------------------
1 | range(1,5)])->isValid;
18 | $this->assertFalse($isValid);
19 | }
20 |
21 | public function testIsOutOfRangeValidWithInvertedComparison() {
22 | $isValid = Validator::validateFor('in', 6, ['range'=>range(1,5), 'not'=>true])->isValid;
23 | $this->assertTrue($isValid);
24 | }
25 |
26 | public function testIsSoftComparisonWorking() {
27 | $isValid = Validator::validateFor('in', "5", ['range'=>range(1,5)])->isValid;
28 | $this->assertTrue($isValid);
29 | }
30 |
31 | public function testIsStrictComparisonWorking() {
32 | $isValid = Validator::validateFor('in', "5", ['range'=>range(1,5), 'strict'=>true])->isValid;
33 | $this->assertFalse($isValid);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/RequiredValidatorTest.php:
--------------------------------------------------------------------------------
1 | isValid;
11 |
12 | $this->assertFalse($isValid);
13 | }
14 |
15 | public function testIsEmptyValidUsingStrictComparison()
16 | {
17 | $isValid = Validator::validateFor('required', '', ['strict'=>true])->isValid;
18 |
19 | $this->assertTrue($isValid);
20 | }
21 |
22 | public function testAreSpacesValid()
23 | {
24 | $isValid = Validator::validateFor('required', ' ')->isValid;
25 |
26 | $this->assertFalse($isValid);
27 | }
28 |
29 | public function testIsEqualToRequiredValue()
30 | {
31 | $isValid = Validator::validateFor('required', '1', ['requiredValue'=>1])->isValid;
32 |
33 | $this->assertTrue($isValid);
34 | }
35 |
36 | public function testIsEqualToRequiredValueUsingStrictComparison()
37 | {
38 | $isValid = Validator::validateFor('required', '1', ['requiredValue'=>1, 'strict'=>true])->isValid;
39 |
40 | $this->assertFalse($isValid);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/StringValidatorTest.php:
--------------------------------------------------------------------------------
1 | validator = new Validator();
10 | }
11 |
12 | public function testEverythingButTheStringIsNotValid()
13 | {
14 | $data = [
15 | 123456789,
16 | 123.456,
17 | true,
18 | null
19 | ];
20 |
21 | $isValid = Validator::validateFor('string', $data)->isValid;
22 |
23 | $this->assertFalse($isValid);
24 | }
25 |
26 | public function testIsStringWithLengthOutOfProperLengthValid()
27 | {
28 | $isValid = Validator::validateFor('string', '123qwe456rty', ['length'=>6])->isValid;
29 |
30 | $this->assertFalse($isValid);
31 | }
32 |
33 | public function testIsTooLongStringValid()
34 | {
35 | $isValid = Validator::validateFor('string', '123qwe456rty', ['max'=>6])->isValid;
36 |
37 | $this->assertFalse($isValid);
38 | }
39 |
40 | public function testIsTooShortStringValid()
41 | {
42 | $isValid = Validator::validateFor('string', '123qwe456rty', ['min'=>50])->isValid;
43 |
44 | $this->assertFalse($isValid);
45 | }
46 |
47 | public function testIsStringValidWithRestrictions()
48 | {
49 | $isValid = Validator::validateFor('string', '123qwe456rty', ['min'=>6, 'max'=>20])->isValid;
50 |
51 | $this->assertTrue($isValid);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/tests/UniqueValidatorTest.php:
--------------------------------------------------------------------------------
1 | 'table', 'column'=>'column']);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/UrlValidatorTest.php:
--------------------------------------------------------------------------------
1 | isValid;
12 |
13 | $this->assertFalse($isValid);
14 | }
15 |
16 | public function testIsValidWithoutProtocol()
17 | {
18 | $isValid = Validator::validateFor('url', 'google.com')->isValid;
19 |
20 | $this->assertFalse($isValid);
21 | }
22 |
23 | public function testIsValidWithoutTopLevelDomain()
24 | {
25 | $isValid = Validator::validateFor('url', 'http://google')->isValid;
26 |
27 | $this->assertFalse($isValid);
28 | }
29 |
30 | public function testIsValidWithProtocol()
31 | {
32 | $isValid = Validator::validateFor('url', 'http://google.com')->isValid;
33 |
34 | $this->assertTrue($isValid);
35 | }
36 |
37 | public function testIsProtocolValidationDisablingWorking()
38 | {
39 | $isValid = Validator::validateFor('url', 'http://google.com', ['validSchemes'=>['https']])->isValid;
40 |
41 | $this->assertFalse($isValid);
42 | }
43 |
44 | public function testIsDisabledIDNCheckWorking()
45 | {
46 | $isValid = Validator::validateFor('url', 'http://täst.de')->isValid;
47 |
48 | $this->assertFalse($isValid);
49 | }
50 |
51 | public function testIsEnabledIDNCheckWorking()
52 | {
53 | $isValid = Validator::validateFor('url', 'http://täst.de', ['enableIDN'=>true])->isValid;
54 |
55 | $this->assertTrue($isValid);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/ValidatorTest.php:
--------------------------------------------------------------------------------
1 | 5, 'max'=>100])->isValid;
10 |
11 | $this->assertTrue($isValid);
12 | }
13 |
14 | public function testSingleValidationOnMultipleValues() {
15 | $emails = [
16 | 'test@gmail.com',
17 | 'test2@yahoo.com'
18 | ];
19 |
20 | $isValid = Validator::validateFor('email', $emails, ['checkDNS'=>true]);
21 |
22 | $this->assertTrue($isValid->isValid, $isValid->lastError);
23 | }
24 |
25 | /**
26 | * @expectedException \UnexpectedValueException
27 | * @expectedExceptionMessage Validator name must be a string, array given
28 | */
29 | public function testIsValidatorNameAsNonStringValid() {
30 | $isValid = Validator::validateFor([], '');
31 |
32 | $this->assertFalse($isValid->isValid, $isValid->lastError);
33 | }
34 |
35 | /**
36 | * As no cycle run on empty array of values,
37 | * no any validation loaded,
38 | * so no any errors produced.
39 | */
40 | public function testIsEmptyArrayValidOnSingleValidation() {
41 | $isValid = Validator::validateFor('phone', []);
42 |
43 | $this->assertTrue($isValid->isValid, $isValid->lastError);
44 | }
45 |
46 | public function testIsEmptyValueValidOnSingleValidation() {
47 | $isValid = Validator::validateFor('phone', '');
48 |
49 | $this->assertFalse($isValid->isValid, $isValid->lastError);
50 | }
51 |
52 | /**
53 | * @expectedException \UnexpectedValueException
54 | * @expectedExceptionMessage Every rule must be provided as an array and must include validator name and value attribute
55 | */
56 | public function testIsNonArrayRuleValid() {
57 | $v = new Validator();
58 | $rules = [
59 | new \stdClass(),
60 | ];
61 |
62 | $v->setRules($rules);
63 | }
64 |
65 | /**
66 | * @expectedException \UnexpectedValueException
67 | * @expectedExceptionMessage Every rule must be provided as an array and must include validator name and value attribute
68 | */
69 | public function testIsRuleWithoutValidatorNameValid() {
70 | $v = new Validator();
71 | $rules = [[
72 | 'first_name',
73 | ]];
74 |
75 | $v->setRules($rules);
76 | }
77 |
78 | /**
79 | * @expectedException \UnexpectedValueException
80 | * @expectedExceptionMessage Validator name must be a string, object given
81 | */
82 | public function testIsNonStringValidatorNameValid() {
83 | $v = new Validator();
84 | $rules = [[
85 | 'first_name',
86 | new \stdClass(),
87 | ]];
88 |
89 | $v->setRules($rules);
90 | }
91 |
92 | public function testLoadRulesAndDataMultipleTimes() {
93 | $v = new Validator();
94 |
95 | $v->loadData(['email' => 'test@gmail.com'])
96 | ->loadData(['first_name' => 'John']);
97 |
98 | $v->loadData(['last_name' => 'Doe'])
99 | ->setRules([['email', 'email']])
100 | ->setRules([[['first_name', 'last_name'], 'string', 'max'=>10]]);
101 |
102 | $isValid = $v->validate();
103 |
104 | $this->assertTrue($isValid);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/valify/Validator.php:
--------------------------------------------------------------------------------
1 | '\valify\validators\BooleanValidator',
12 | 'compare' => '\valify\validators\CompareValidator',
13 | 'date' => '\valify\validators\DateValidator',
14 | 'default' => '\valify\validators\DefaultValueValidator',
15 | 'email' => '\valify\validators\EmailValidator',
16 | 'file' => '\valify\validators\FileValidator',
17 | 'image' => '\valify\validators\ImageValidator',
18 | 'in' => '\valify\validators\RangeValidator',
19 | 'match' => '\valify\validators\RegularExpressionValidator',
20 | 'number' => '\valify\validators\NumberValidator',
21 | 'phone' => '\valify\validators\PhoneValidator',
22 | 'required' => '\valify\validators\RequiredValidator',
23 | 'string' => '\valify\validators\StringValidator',
24 | 'unique' => '\valify\validators\UniqueValidator',
25 | 'url' => '\valify\validators\UrlValidator',
26 | ];
27 |
28 | /**
29 | * You can perform a single validation by using this method.
30 | * Result of validate() method (boolean) will be returned.
31 | *
32 | * @param $name string - Name of validator
33 | * @param $value mixed - Value to validate. If array,
34 | * all keys are taken as attributes and values as values.
35 | * @param $params array - Params for a validator
36 | * @return object
37 | * @throws \Exception
38 | */
39 | public static function validateFor($name, $value, array $params = []) {
40 | if( !is_string($name) )
41 | throw new \UnexpectedValueException("Validator name must be a string, " . gettype($name) . " given");
42 |
43 | $rules = [];
44 | # By default, empty value should be not valid
45 | $params = array_merge(['allowEmpty'=>false], $params);
46 |
47 | if( is_array($value) ) {
48 | $rules[] = array_merge([array_keys($value), $name], $params);
49 | } else {
50 | $rules[] = array_merge([$name, $name], $params);
51 | $value = [$name => $value];
52 | }
53 |
54 | $v = new Validator();
55 | $result = new \stdClass();
56 | $result->isValid = $v->setRules($rules)->loadData($value)->validate();
57 | $result->lastError = $v->getLastError();
58 | $result->errors = $v->getErrors();
59 | unset($v);
60 |
61 | return $result;
62 | }
63 |
64 | /**
65 | * You can call this method multiple times. New rules
66 | * will be merged with already loaded ones.
67 | *
68 | * @param array $rules
69 | * @return $this
70 | */
71 | public function setRules(array $rules = []) {
72 | foreach ($rules as $rule) {
73 | if( !is_array($rule) || count($rule) < 2 )
74 | throw new \UnexpectedValueException("Every rule must be provided as an array and must include validator name and value attribute");
75 |
76 | if( !is_string($rule[1]) )
77 | throw new \UnexpectedValueException("Validator name must be a string, " . gettype($rule[1]) . " given");
78 | }
79 |
80 | $this->_rules = array_merge($this->_rules, $rules);
81 | return $this;
82 | }
83 |
84 | /**
85 | * You can call this method multiple times. New data
86 | * will be merged with already loaded one.
87 | *
88 | * @param array $data
89 | * @return $this
90 | */
91 | public function loadData(array $data = []) {
92 | $this->_data = array_merge($this->_data, $data);
93 | return $this;
94 | }
95 |
96 | /**
97 | * @return bool
98 | */
99 | public function validate() {
100 | # Sort rules by validator name
101 | usort($this->_rules, function ($a, $b) {
102 | if ($a[1] == $b[1]) return 0;
103 | return ($a[1] < $b[1]) ? -1 : 1;
104 | });
105 |
106 | foreach ($this->_rules as $rule) {
107 | $attribute = array_shift($rule);
108 | $validatorName = array_shift($rule);
109 |
110 | if($validatorName) {
111 | if( is_string($attribute) ) {
112 | $value = isset($this->_data[$attribute]) ? $this->_data[$attribute] : null;
113 | $this->callValidator($validatorName, [$attribute => $value], $rule);
114 | } elseif( is_array($attribute) ) {
115 | $safeData = array_intersect_key( $this->_data, array_flip($attribute) );
116 | $this->callValidator($validatorName, $safeData, $rule);
117 | }
118 | }
119 | }
120 |
121 | return !$this->hasErrors();
122 | }
123 |
124 | /**
125 | * After using validate(), we can
126 | * simply check, if there are any errors
127 | *
128 | * @return bool
129 | */
130 | public function hasErrors() {
131 | return !empty($this->_errors);
132 | }
133 |
134 | /**
135 | * Get all error messages, or the only ones
136 | * for a particular attribute, if it is defined
137 | *
138 | * @return array
139 | */
140 | public function getErrors($attribute = null) {
141 | return isset($this->_errors[$attribute]) ? $this->_errors[$attribute] : $this->_errors;
142 | }
143 |
144 | /**
145 | * Get a single error message for a particular attribute
146 | *
147 | * @param $attribute
148 | * @return array|null
149 | */
150 | public function getError($attribute) {
151 | return isset($this->_errors[$attribute]) ? $this->_errors[$attribute][0] : null;
152 | }
153 |
154 | /**
155 | * @return null
156 | */
157 | public function getLastError() {
158 | $errors = array_values($this->_errors);
159 | if( isset($errors[0][0]) )
160 | return $errors[0][0];
161 | return null;
162 | }
163 |
164 | private function callValidator($validator, $data, $rule = []) {
165 | if( isset($this->_builtInValidators[$validator]) ) {
166 | $namespace = $this->_builtInValidators[$validator];
167 | $validator = $this->loadValidator($namespace);
168 | } elseif( strpos($validator, '\\') !== false ) { # Validator name is a namespace
169 | $validator = $this->loadValidator($validator);
170 |
171 | if( !is_subclass_of($validator, '\valify\validators\AbstractValidator', false) )
172 | throw new \DomainException("Validator " . get_class($validator) . " must extend \\valify\\validators\\AbstractValidator class");
173 | }
174 |
175 | if( is_object($validator) ) {
176 | /** @var $validator validators\AbstractValidator */
177 | $validator = $this->setValidatorProperties($validator, $rule);
178 |
179 | foreach ($data as $attr => $val) {
180 | $validator->setAttributeAndValue($attr, $val);
181 | $validator->init();
182 |
183 | if( $validator->gotErrors() )
184 | $this->setErrorStack($validator->fetchErrors());
185 | }
186 | } else {
187 | throw new \UnexpectedValueException("Validator " . get_class($validator) . " not found");
188 | }
189 | }
190 |
191 | private function loadValidator($name) {
192 | $currentValidatorName = is_object($this->_currentValidator)
193 | ? trim(get_class($this->_currentValidator), '\\')
194 | : null;
195 | $name = trim($name, '\\');
196 |
197 | if(!$this->_currentValidator || $currentValidatorName !== $name) {
198 | $validator = new $name();
199 | $this->_currentValidator = $validator;
200 | } else {
201 | $validator = $this->_currentValidator;
202 | }
203 |
204 | return $validator;
205 | }
206 |
207 | private function setValidatorProperties($obj, $params) {
208 | foreach ($params as $prop => $value)
209 | $obj->$prop = $value;
210 |
211 | $obj->_data = $this->_data;
212 |
213 | return $obj;
214 | }
215 |
216 | private function setErrorStack($errors) {
217 | foreach ($errors as $attr => $msgs)
218 | $this->_errors[$attr] = $msgs;
219 | }
220 |
221 | public function cleanErrors() {
222 | $this->_errors = [];
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/valify/validators/AbstractValidator.php:
--------------------------------------------------------------------------------
1 | attribute = $attribute;
31 | $this->value = $value;
32 | }
33 |
34 | /**
35 | * Called by Validator class to execute validation.
36 | * Yes, some errors may be set in the init() method
37 | */
38 | public function init() {
39 | if( !$this->gotErrors() && ( !$this->allowEmpty || ( $this->allowEmpty && !$this->isEmpty($this->value) ) ) ) {
40 | $this->validateValue($this->value);
41 | }
42 | }
43 |
44 | /**
45 | * Error message constructor. Attribute and value will always be
46 | * accessible in message string as {attribute} and {value} templates.
47 | * You can use own params to replace in $msg.
48 | * Usage:
49 | * $msg = "Length should be longer than {min} chars and not exceed {max} chars"
50 | * $params = ['{min}'=>3, '{max}'=>15]
51 | *
52 | * @param string $msg
53 | * @param array $params
54 | */
55 | protected function addError($msg, $params = []) {
56 | $params = array_merge([
57 | '{attribute}' => $this->attribute,
58 | '{value}' => $this->value,
59 | ], $params);
60 |
61 | foreach ($params as $template => $value)
62 | $params[$template] = $this->isPrintable($value) ? $value : gettype($value);
63 |
64 | $msg = str_replace(array_keys($params), array_values($params), $msg);
65 |
66 | $this->_errors[$this->attribute][] = $msg;
67 | }
68 |
69 | /**
70 | * Fetching errors for a particular validator
71 | * @return array
72 | */
73 | public function fetchErrors() {
74 | return $this->_errors;
75 | }
76 |
77 | /**
78 | * Does current validator got any errors
79 | * @return bool
80 | */
81 | public function gotErrors() {
82 | return !empty($this->_errors);
83 | }
84 |
85 | public function isPrintable($value) {
86 | return ( is_string($value) || is_numeric($value) );
87 | }
88 |
89 | public function isEmpty($value) {
90 | $empty = true;
91 |
92 | if ( is_string($value) || is_numeric($value) ) {
93 | $empty = empty($value);
94 | } elseif( is_object($value) ) {
95 | $empty = $this->isEmpty( get_object_vars($value) );
96 | } elseif( is_array($value) ) {
97 | foreach ($value as $key => $val) {
98 | if( !$this->isEmpty($val) ) {
99 | $empty = false;
100 | break;
101 | }
102 | }
103 | }
104 |
105 | return $empty;
106 | }
107 |
108 | abstract protected function validateValue($value);
109 | }
--------------------------------------------------------------------------------
/valify/validators/BooleanValidator.php:
--------------------------------------------------------------------------------
1 | strict && ($value == $this->trueValue || $value == $this->falseValue)
26 | || $this->strict && ($value === $this->trueValue || $value === $this->falseValue);
27 | if (!$valid)
28 | $this->addError($this->message);
29 | }
30 | }
--------------------------------------------------------------------------------
/valify/validators/CompareValidator.php:
--------------------------------------------------------------------------------
1 | `: check if value being validated is greater than the value being compared with.
39 | * - `>=`: check if value being validated is greater than or equal to the value being compared with.
40 | * - `<`: check if value being validated is less than the value being compared with.
41 | * - `<=`: check if value being validated is less than or equal to the value being compared with.
42 | */
43 | public $operator = '==';
44 |
45 | public function init()
46 | {
47 | if ($this->message === null) {
48 | switch ($this->operator) {
49 | case '==':
50 | $this->message = '{compareAttribute} must be repeated exactly.';
51 | break;
52 | case '===':
53 | $this->message = '{compareAttribute} must be repeated exactly.';
54 | break;
55 | case '!=':
56 | $this->message = '{compareAttribute} must not be equal to "{compareValue}".';
57 | break;
58 | case '!==':
59 | $this->message = '{compareAttribute} must not be equal to "{compareValue}".';
60 | break;
61 | case '>':
62 | $this->message = '{compareAttribute} must be greater than "{compareValue}".';
63 | break;
64 | case '>=':
65 | $this->message = '{compareAttribute} must be greater than or equal to "{compareValue}".';
66 | break;
67 | case '<':
68 | $this->message = '{compareAttribute} must be less than "{compareValue}".';
69 | break;
70 | case '<=':
71 | $this->message = '{compareAttribute} must be less than or equal to "{compareValue}".';
72 | break;
73 | default:
74 | $this->addError('Unknown operator: {operator}', ['{operator}' => $this->operator]);
75 | }
76 | }
77 |
78 | parent::init();
79 | }
80 |
81 | protected function validateValue($value) {
82 | if ( !$this->isComparable($value) ) {
83 | $this->addError('{attribute} is invalid.');
84 | } else {
85 | if ($this->compareValue !== null) {
86 | $compareAttribute = $compareValue = $this->compareValue;
87 | } else {
88 | $compareAttribute = $this->compareAttribute === null ? $this->attribute . '_repeat' : $this->compareAttribute;
89 | $compareValue = isset( $this->_data[$compareAttribute] ) ? $this->_data[$compareAttribute] : null;
90 | }
91 |
92 | if ( !$this->compareValues($this->operator, $value, $compareValue) ) {
93 | $this->addError($this->message, [
94 | '{compareAttribute}' => $compareAttribute,
95 | '{compareValue}' => $compareValue,
96 | ]);
97 | }
98 | }
99 | }
100 |
101 | private function compareValues($operator, $value, $compareValue)
102 | {
103 | switch ($operator) {
104 | case '==':
105 | return $value == $compareValue;
106 | case '===':
107 | return $value === $compareValue;
108 | case '!=':
109 | return $value != $compareValue;
110 | case '!==':
111 | return $value !== $compareValue;
112 | case '>':
113 | return $value > $compareValue;
114 | case '>=':
115 | return $value >= $compareValue;
116 | case '<':
117 | return $value < $compareValue;
118 | case '<=':
119 | return $value <= $compareValue;
120 | default:
121 | return false;
122 | }
123 | }
124 |
125 | private function isComparable($value) {
126 | return ( is_null($value) || is_bool($value) || is_numeric($value) || is_string($value) || is_array($value) || is_object($value) );
127 | }
128 | }
--------------------------------------------------------------------------------
/valify/validators/EmailValidator.php:
--------------------------------------------------------------------------------
1 | ";print_r($value);echo "";
22 | if (!is_string($value) || strlen($value) >= 320) {
23 | $this->addError($this->message);
24 | } elseif ( !preg_match('/^(.*)(.*)@(.*?)(>?)$/', $value, $matches) ) {
25 | $this->addError($this->message);
26 | } else {
27 | $domain = $matches[3];
28 | $valid = preg_match($this->pattern, $value);
29 | if (!$valid)
30 | $this->addError($this->message);
31 | if ($valid && $this->checkDNS) {
32 | $valid = checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A');
33 | if(!$valid)
34 | $this->addError($this->DNSIsNotValid, ['{domain}'=>$domain]);
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/valify/validators/FileValidator.php:
--------------------------------------------------------------------------------
1 | extensions) ) {
72 | $this->extensions = preg_split('/[\s,]+/', strtolower($this->extensions), -1, PREG_SPLIT_NO_EMPTY);
73 | } else {
74 | $this->extensions = array_map('strtolower', $this->extensions);
75 | }
76 | if ( !is_array($this->mimeTypes) ) {
77 | $this->mimeTypes = preg_split('/[\s,]+/', strtolower($this->mimeTypes), -1, PREG_SPLIT_NO_EMPTY);
78 | } else {
79 | $this->mimeTypes = array_map('strtolower', $this->mimeTypes);
80 | }
81 |
82 | $uploadMaxFileSize = $this->sizeToBytes(ini_get('upload_max_filesize'));
83 |
84 | if ( isset($_POST['MAX_FILE_SIZE']) && $_POST['MAX_FILE_SIZE'] > 0 && $_POST['MAX_FILE_SIZE'] < $uploadMaxFileSize )
85 | $uploadMaxFileSize = (int)$_POST['MAX_FILE_SIZE'];
86 |
87 | if( $this->maxSize == null || $this->maxSize > $uploadMaxFileSize )
88 | $this->maxSize = $uploadMaxFileSize;
89 |
90 | parent::init();
91 | }
92 |
93 | protected function validateValue($value) {
94 | $amountOfFiles = false;
95 |
96 | if ( !is_array($value) || !$this->isFile($value) ) {
97 | $this->addError($this->message);
98 | } else {
99 | $value = $this->normailzeData($value);
100 | $amountOfFiles = count($value);
101 | }
102 |
103 |
104 | if(!$amountOfFiles || $amountOfFiles > $this->maxFiles) {
105 | $this->addError($this->tooMany, ['{number}'=>$amountOfFiles, '{limit}'=>$this->maxFiles]);
106 | } else {
107 | foreach ($value as $file) {
108 | if($file['error'] == 4 && $this->allowEmpty)
109 | continue;
110 | elseif($file['error'] !== UPLOAD_ERR_OK)
111 | $this->addError( $this->errorCodeToMessage($file['error']) );
112 | elseif($file['size'] == 0)
113 | $this->addError( $this->emptyFile, ['{name}'=>$file['name']] );
114 | elseif($this->maxSize && $file['size'] > $this->maxSize)
115 | $this->addError( $this->tooBig, ['{name}'=>$file['name'], '{maxSize}'=>$this->maxSize] );
116 | elseif($this->minSize && $file['size'] < $this->minSize)
117 | $this->addError( $this->tooSmall, ['{name}'=>$file['name'], '{minSize}'=>$this->minSize] );
118 | elseif( !empty($this->extensions) ) {
119 | $extensions = $this->extensions;
120 | $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
121 |
122 | if($this->checkExtensionByMimeType) {
123 | $mimeTypeExtensions = $this->getExtensionsByFileMimeType($file['tmp_name']);
124 | if( !in_array($extension, $mimeTypeExtensions) )
125 | $extension = null;
126 | }
127 |
128 | if( !in_array($extension, $extensions) )
129 | $this->addError( $this->wrongExtension, ['{extensions}'=>implode(', ', $this->extensions)] );
130 | } elseif( !empty($this->mimeTypes) && !in_array($file['type'], $this->mimeTypes) )
131 | $this->addError( $this->wrongMimeType, ['{mimeTypes}'=>implode(', ', $this->mimeTypes)] );
132 | }
133 | }
134 | }
135 |
136 | private function isFile($value) {
137 | return isset($value['name'], $value['type'], $value['tmp_name'], $value['error'], $value['size']);
138 | }
139 |
140 | private function sizeToBytes($str) {
141 | switch (substr($str, -1)) {
142 | case 'M':
143 | case 'm':
144 | return (int)$str * 1048576;
145 | case 'K':
146 | case 'k':
147 | return (int)$str * 1024;
148 | case 'G':
149 | case 'g':
150 | return (int)$str * 1073741824;
151 | default:
152 | return (int)$str;
153 | }
154 | }
155 |
156 | private function errorCodeToMessage($code) {
157 | switch ($code) {
158 | case UPLOAD_ERR_INI_SIZE:
159 | $message = "The uploaded file exceeds the upload_max_filesize directive in php.ini";
160 | break;
161 | case UPLOAD_ERR_FORM_SIZE:
162 | $message = "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form";
163 | break;
164 | case UPLOAD_ERR_PARTIAL:
165 | $message = "The uploaded file was only partially uploaded";
166 | break;
167 | case UPLOAD_ERR_NO_FILE:
168 | $message = "No file was uploaded";
169 | break;
170 | case UPLOAD_ERR_NO_TMP_DIR:
171 | $message = "Missing a temporary folder";
172 | break;
173 | case UPLOAD_ERR_CANT_WRITE:
174 | $message = "Failed to write file to disk";
175 | break;
176 | case UPLOAD_ERR_EXTENSION:
177 | $message = "File upload stopped by extension";
178 | break;
179 |
180 | default:
181 | $message = "Unknown upload error";
182 | break;
183 | }
184 | return $message;
185 | }
186 |
187 | public function getExtensionsByFileMimeType($file) {
188 | $mimeType = $this->getMimeTypeForFile($file);
189 |
190 | $out = [];
191 | $file = fopen('/etc/mime.types', 'r');
192 | while(($line = fgets($file)) !== false) {
193 | $line = trim(preg_replace('/#.*/', '', $line));
194 | if(!$line)
195 | continue;
196 | $parts = preg_split('/\s+/', $line);
197 | if(count($parts) == 1)
198 | continue;
199 | $type = array_shift($parts);
200 | if($type == $mimeType) {
201 | $out = is_array($parts) ? $parts : [$parts];
202 | break;
203 | }
204 | }
205 | fclose($file);
206 |
207 | return $out;
208 | }
209 |
210 | private function getMimeTypeForFile($file) {
211 | $finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
212 | $fileMimeType = finfo_file($finfo, $file);
213 | finfo_close($finfo);
214 |
215 | return $fileMimeType;
216 | }
217 |
218 | private function normailzeData($value) {
219 | $normalizedValue = [];
220 |
221 | foreach ($value as $key => $val) {
222 | if(is_array($val)) {
223 | foreach ($val as $i => $name)
224 | $normalizedValue[$i][$key] = $name;
225 | } else {
226 | $normalizedValue[0][$key] = $val;
227 | }
228 | }
229 |
230 | return $normalizedValue;
231 | }
232 | }
--------------------------------------------------------------------------------
/valify/validators/NumberValidator.php:
--------------------------------------------------------------------------------
1 | addError($this->message);
49 | } elseif($this->integerOnly && !preg_match($this->integerPattern, "$value") ) {
50 | $this->addError($this->message);
51 | } elseif ($this->min !== null && $value < $this->min) {
52 | $this->addError($this->tooSmall, ['min' => $this->min]);
53 | } elseif ($this->max !== null && $value > $this->max) {
54 | $this->addError($this->tooBig, ['max' => $this->max]);
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/valify/validators/PhoneValidator.php:
--------------------------------------------------------------------------------
1 | = 20) {
23 | $this->addError($this->message);
24 | } else {
25 | $pattern = $this->checkCountryCode ? $this->pattern : $this->phonePattern;
26 | $valid = preg_match($pattern, trim($value));
27 | if (!$valid)
28 | $this->addError($this->message);
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/valify/validators/RangeValidator.php:
--------------------------------------------------------------------------------
1 | range) )
28 | throw new \InvalidArgumentException($this->rangeErrorMessage);
29 |
30 | parent::init();
31 | }
32 |
33 | protected function validateValue($value) {
34 | $value = (is_array($value) ? $value : [$value]);
35 |
36 | $in = true;
37 | foreach ($value as $v) {
38 | if ( !in_array($v, $this->range, $this->strict) ) {
39 | $in = false;
40 | break;
41 | }
42 | }
43 |
44 | if($this->not === $in)
45 | $this->addError($this->message);
46 | }
47 | }
--------------------------------------------------------------------------------
/valify/validators/RequiredValidator.php:
--------------------------------------------------------------------------------
1 | requiredValue === null) {
37 | $value = is_string($value) ? trim($value) : $value;
38 | if ($this->strict && $value === null || !$this->strict && empty($value)) {
39 | $this->addError($this->message);
40 | }
41 | } elseif (!$this->strict && $value != $this->requiredValue || $this->strict && $value !== $this->requiredValue) {
42 | $this->addError($this->message, ['{requiredValue}' => $this->requiredValue]);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/valify/validators/StringValidator.php:
--------------------------------------------------------------------------------
1 | addError($this->message);
46 |
47 | $length = mb_strlen($value, $this->encoding);
48 |
49 | if ($this->min !== null && $length < $this->min)
50 | $this->addError($this->tooShort, ['{min}' => $this->min]);
51 |
52 | if ($this->max !== null && $length > $this->max)
53 | $this->addError($this->tooLong, ['{max}' => $this->max]);
54 |
55 | if ($this->length !== null && $length !== $this->length)
56 | $this->addError($this->notEqual, ['{length}' => $this->length]);
57 | }
58 | }
--------------------------------------------------------------------------------
/valify/validators/UniqueValidator.php:
--------------------------------------------------------------------------------
1 | edsn)
37 | $this->parseEDSN();
38 |
39 | if(!$this->table || !$this->column)
40 | throw new \UnexpectedValueException('Table and column must be specified');
41 |
42 | if( !is_string($this->table) || !is_string($this->column) )
43 | throw new \UnexpectedValueException('Table and column must be set as string');
44 |
45 | mysqli_report(MYSQLI_REPORT_STRICT);
46 | $mysqli = new \mysqli($this->host, $this->user, $this->pass, $this->dbname);
47 |
48 | if($mysqli->connect_errno)
49 | throw new \mysqli_sql_exception(printf("Connection error: %s\n", $mysqli->connect_error));
50 |
51 | $this->conn = $mysqli;
52 |
53 | parent::init();
54 | }
55 |
56 | protected function validateValue($value) {
57 | if( !$this->isPrintable($value) )
58 | $this->addError('Value is not a string');
59 | else {
60 | $value = empty($value) ? 'NULL' : "'" . $this->conn->real_escape_string($value) . "'";
61 |
62 | $sql = "SELECT count(*) as count from " . $this->table . " where " . $this->column . " = " . $value;
63 |
64 | $res = $this->conn->query($sql);
65 | $res = $res->fetch_object();
66 |
67 | if( (int)$res->count > 0 ) {
68 | $this->addError($this->message);
69 | }
70 | }
71 | }
72 |
73 | private function parseEDSN() {
74 | $edsn = explode(';', trim($this->edsn, ';'));
75 |
76 | foreach ($edsn as $param) {
77 | $name = substr($param, 0, strpos($param, '='));
78 | $value = substr($param, strpos($param, '=') + 1);
79 |
80 | switch($name) {
81 | case 'db':
82 | $this->dbname = $value;
83 | break;
84 | case 'h':
85 | $this->host = $value;
86 | break;
87 | case 'u':
88 | $this->user = $value;
89 | break;
90 | case 'p':
91 | $this->pass = $value;
92 | break;
93 | case 't':
94 | $this->table = $value;
95 | break;
96 | case 'c':
97 | $this->column = $value;
98 | break;
99 | }
100 | }
101 | }
102 | }
--------------------------------------------------------------------------------
/valify/validators/UrlValidator.php:
--------------------------------------------------------------------------------
1 | enableIDN && !function_exists('idn_to_ascii'))
37 | $this->addError($this->intlErrorMessage);
38 |
39 | parent::init();
40 | }
41 |
42 | public function validateValue($value) {
43 | // make sure the length is limited to avoid DOS attacks
44 | if (is_string($value) && strlen($value) < 2000) {
45 | if ($this->defaultScheme !== null && strpos($value, '://') === false) {
46 | $value = $this->defaultScheme . '://' . $value;
47 | }
48 | if (strpos($this->pattern, '{schemes}') !== false) {
49 | $pattern = str_replace('{schemes}', '(' . implode('|', $this->validSchemes) . ')', $this->pattern);
50 | } else {
51 | $pattern = $this->pattern;
52 | }
53 |
54 | if ($this->enableIDN) {
55 | $value = preg_replace_callback('/:\/\/([^\/]+)/', function ($matches) {
56 | return '://' . idn_to_ascii($matches[1]);
57 | }, $value);
58 | }
59 | if (!preg_match($pattern, $value)) {
60 | $this->addError($this->message);
61 | }
62 | } else {
63 | $this->addError($this->message);
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------