1: <?php
2: 3: 4: 5: 6: 7:
8:
9: namespace Wei\Validator;
10:
11: 12: 13: 14: 15:
16: class Password extends BaseValidator
17: {
18: protected $lengthTooShortMessage = '%name% must have a length greater than %minLength%';
19:
20: protected $lengthTooLongMessage = '%name% must have a length lower than %maxLength%';
21:
22: protected $missingCharTypeMessage = '%name% must contains %missingType%';
23:
24: protected $missingCharMessage = '%name% must contains %missingCount% of these characters : %missingType%';
25:
26: 27: 28: 29: 30:
31: protected $name = 'Password';
32:
33: 34: 35: 36: 37:
38: protected $typeNames = array(
39: 'digit' => 'digits (0-9)',
40: 'letter' => 'letters (a-z)',
41: 'lower' => 'lowercase letters (a-z)',
42: 'upper' => 'uppercase letters (A-Z)',
43: 'nonAlnum' => 'non-alphanumeric (For example: !, @, or #) characters'
44: );
45:
46: 47: 48:
49: protected $minLength;
50:
51: 52: 53:
54: protected $maxLength;
55:
56: 57: 58:
59: protected $needDigit = false;
60:
61: 62: 63:
64: protected $needLetter = false;
65:
66: 67: 68:
69: protected $needNonAlnum = false;
70:
71: 72: 73:
74: protected $atLeastPresent = 0;
75:
76: 77: 78:
79: protected $regexMap = array(
80: 'digit' => '0-9',
81: 'letter' => 'a-zA-Z',
82: 'lower' => 'a-z',
83: 'upper' => 'A-Z',
84: 'nonAlnum' => '^0-9a-zA-Z'
85: );
86:
87: 88: 89: 90: 91:
92: protected $missingCount;
93:
94: 95: 96: 97: 98:
99: protected $missingType;
100:
101: 102: 103: 104: 105:
106: protected $missingTypes = array();
107:
108: 109: 110:
111: public function __invoke($input, array $options = array())
112: {
113: $options && $this->storeOption($options);
114: return $this->isValid($input);
115: }
116:
117: 118: 119:
120: protected function doValidate($input)
121: {
122: if (!$this->isString($input)) {
123: $this->addError('notString');
124: return false;
125: }
126:
127: $length = strlen($input);
128:
129: if ($this->minLength && $length < $this->minLength) {
130: $this->addError('lengthTooShort');
131: return false;
132: }
133:
134: if ($this->maxLength && $length > $this->maxLength) {
135: $this->addError('lengthTooLong');
136: return false;
137: }
138:
139:
140: $missing = array();
141: foreach ($this->regexMap as $type => $regex) {
142: if (!preg_match('/[' . $regex . ']/', $input)) {
143: $missing[$type] = true;
144: }
145: }
146:
147: $needTypes = array();
148: foreach (array('digit', 'letter', 'nonAlnum') as $type) {
149: $propertyName = 'need' . ucfirst($type);
150: if ($this->$propertyName && isset($missing[$type])) {
151: $needTypes[] = $type;
152: }
153: }
154:
155: if (count($needTypes)) {
156: $this->missingTypes = array_intersect_key($this->typeNames, array_flip($needTypes));
157: $this->addError('missingCharType');
158: return false;
159: }
160:
161: if ($this->atLeastPresent) {
162: unset($missing['letter']);
163:
164: $total = 4;
165: $remains = count($missing);
166: $needPresent = $this->atLeastPresent - ($total - $remains);
167:
168: if ($needPresent > 0) {
169: $this->missingTypes = array_intersect_key($this->typeNames, $missing);
170: if (count($missing) == $needPresent) {
171: $this->addError('missingCharType');
172: } else {
173: $this->missingCount = $needPresent;
174: $this->addError('missingChar');
175: }
176: return false;
177: }
178: }
179:
180: return true;
181: }
182:
183: 184: 185:
186: public function getMessages($name = null)
187: {
188: if ($this->missingTypes) {
189: $this->loadTranslationMessages();
190: $types = array();
191: foreach ($this->missingTypes as $type) {
192: $types[] = $this->t($type);
193: }
194: $this->missingType = implode(', ', $types);
195: }
196: return parent::getMessages($name);
197: }
198: }
199: