Completed
Push — master ( aeb269...0ca918 )
by Bobby
04:04
created

Validator::countOccurrences()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2
1
<?php
2
3
namespace Ballen\Plexity\Support;
4
5
use Ballen\Plexity\Plexity;
6
use Ballen\Plexity\Exceptions\ValidationException;
7
8
/**
9
 * Plexity
10
 *
11
 * Plexity (Password Complexity) is a password complexity library that
12
 * enables you to set "rules" for a password (or any other kind of string) that
13
 * you can then check against in your application.
14
 *
15
 * @author Bobby Allen <[email protected]>
16
 * @license http://opensource.org/licenses/MIT
17
 * @link https://github.com/allebb/passplexity
18
 * @link https://bobbyallen.me
19
 *
20
 */
21
class Validator
22
{
23
24
    /**
25
     * The Plexity object (contains the validation configuration)
26
     * @var Plexity
27
     */
28
    private $configuration;
29
30
    /**
31
     * Numeric values list
32
     * @var array
33
     */
34
    protected $numbers = [
35
        1, 2, 3, 4, 5, 6, 7, 8, 9, 0
36
    ];
37
38
    /**
39
     * Special Character list
40
     * @see https://www.owasp.org/index.php/Password_special_characters
41
     * @var array
42
     */
43
    protected $specialCharacters = [
44
        ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '.',
45
        '/', ':', ';', '<', '=', '>', '?', '@', '[', ']', '\\', '^', '_', '`',
46
        '{', '|', '}', '~',
47
    ];
48
49
    /**
50
     * Validates all the configured rules and responds as requested.
51
     * @return boolean
52
     * @throws ValidationException
53
     */
54 26
    public function validate(Plexity $configuration)
55
    {
56 26
        $this->configuration = $configuration;
57 26
        $this->checkMinimumLength();
58 24
        $this->checkMaximumLength();
59 22
        $this->checkLowerCase();
60 20
        $this->checkUpperCase();
61 18
        $this->checkNumericCharacters();
62 16
        $this->checkSpecialCharacters();
63 14
        $this->checkNotIn();
64 13
        return true;
65
    }
66
67
    /**
68
     * Checks the minimum length requirement.
69
     * @throws ValidationException
70
     */
71 26 View Code Duplication
    public function checkMinimumLength()
72
    {
73 26
        if ($this->configuration->rules()->get(Plexity::RULE_LENGTH_MIN) > 0) {
74 6
            if (!$this->validateLengthMin()) {
75 2
                throw new ValidationException('The length does not meet the minimum length requirements.');
76
            }
77
        }
78 24
    }
79
80
    /**
81
     * Checks the minimum maximum length requirement.
82
     * @throws ValidationException
83
     */
84 24 View Code Duplication
    public function checkMaximumLength()
85
    {
86 24
        if ($this->configuration->rules()->get(Plexity::RULE_LENGTH_MAX) > 0) {
87 5
            if (!$this->validateLengthMax()) {
88 2
                throw new ValidationException('The length exceeds the maximum length requirements.');
89
            }
90
        }
91 22
    }
92
93
    /**
94
     * Checks the lowercase character(s) requirement.
95
     * @throws ValidationException
96
     */
97 22 View Code Duplication
    public function checkLowerCase()
98
    {
99 22
        if ($this->configuration->rules()->get(Plexity::RULE_LOWER) > 0) {
100 4
            if (!$this->validateLowerCase()) {
101 2
                throw new ValidationException('The string failed to meet the lower case requirements.');
102
            }
103
        }
104 20
    }
105
106
    /**
107
     * Checks the upper case character(s) requirement.
108
     * @throws ValidationException
109
     */
110 20 View Code Duplication
    public function checkUpperCase()
111
    {
112 20
        if ($this->configuration->rules()->get(Plexity::RULE_UPPER) > 0) {
113 4
            if (!$this->validateUpperCase()) {
114 2
                throw new ValidationException('The string failed to meet the upper case requirements.');
115
            }
116
        }
117 18
    }
118
119
    /**
120
     * Checks the numeric character(s) requirement.
121
     * @throws ValidationException
122
     */
123 18 View Code Duplication
    public function checkNumericCharacters()
124
    {
125 18
        if ($this->configuration->rules()->get(Plexity::RULE_NUMERIC) > 0) {
126 4
            if (!$this->validateNumericCharacters()) {
127 2
                throw new ValidationException('The string failed to meet the numeric character requirements.');
128
            }
129
        }
130 16
    }
131
132
    /**
133
     * Checks the special character(s) requirement.
134
     * @throws ValidationException
135
     */
136 16 View Code Duplication
    public function checkSpecialCharacters()
137
    {
138 16
        if ($this->configuration->rules()->get(Plexity::RULE_SPECIAL) > 0) {
139 4
            if (!$this->validateSpecialCharacters()) {
140 2
                throw new ValidationException('The string failed to meet the special character requirements.');
141
            }
142
        }
143 14
    }
144
145
    /**
146
     * Validates if a string is not in a array (password history database).
147
     * @throws ValidationException
148
     */
149 14 View Code Duplication
    public function checkNotIn()
150
    {
151 14
        if (count($this->configuration->rules()->get(Plexity::RULE_NOT_IN)) > 0) {
152 2
            if (!$this->validateNotIn()) {
153 1
                throw new ValidationException('The string exists in the list of disallowed values requirements.');
154
            }
155
        }
156 13
    }
157
158
    /**
159
     * Validates the upper case requirements.
160
     * @return boolean
161
     */
162 4 View Code Duplication
    private function validateUpperCase()
163
    {
164 4
        $occurences = preg_match_all("/[A-Z]/", $this->configuration->checkString());
165
166 4
        if ($occurences >= $this->configuration->rules()->get(Plexity::RULE_UPPER)) {
167 2
            return true;
168
        }
169
170 2
        return false;
171
    }
172
173
    /**
174
     * Validates the lower case requirements.
175
     * @return boolean
176
     */
177 4 View Code Duplication
    private function validateLowerCase()
178
    {
179 4
        $occurences = preg_match_all("/[a-z]/", $this->configuration->checkString());
180
181 4
        if ($occurences >= $this->configuration->rules()->get(Plexity::RULE_LOWER)) {
182 2
            return true;
183
        }
184
185 2
        return false;
186
    }
187
188
    /**
189
     * Validates the special character requirements.
190
     * @return boolean
191
     */
192 4 View Code Duplication
    private function validateSpecialCharacters()
193
    {
194 4
        if ($this->countOccurrences($this->specialCharacters, $this->configuration->checkString()) >= $this->configuration->rules()->get(Plexity::RULE_SPECIAL)) {
195 2
            return true;
196
        }
197 2
        return false;
198
    }
199
200
    /**
201
     * Validates the numeric case requirements.
202
     * @return boolean
203
     */
204 4 View Code Duplication
    private function validateNumericCharacters()
205
    {
206 4
        if ($this->countOccurrences($this->numbers, $this->configuration->checkString()) >= $this->configuration->rules()->get(Plexity::RULE_NUMERIC)) {
207 2
            return true;
208
        }
209 2
        return false;
210
    }
211
212
    /**
213
     * Validates the minimum string length requirements.
214
     * @return boolean
215
     */
216 6 View Code Duplication
    private function validateLengthMin()
217
    {
218 6
        if (strlen($this->configuration->checkString()) >= $this->configuration->rules()->get(Plexity::RULE_LENGTH_MIN)) {
219 4
            return true;
220
        }
221 2
        return false;
222
    }
223
224
    /**
225
     * Validates the maximum string length requirements.
226
     * @return boolean
227
     */
228 5 View Code Duplication
    private function validateLengthMax()
229
    {
230 5
        if (strlen($this->configuration->checkString()) <= $this->configuration->rules()->get(Plexity::RULE_LENGTH_MAX)) {
231 3
            return true;
232
        }
233 2
        return false;
234
    }
235
236
    /**
237
     * Validates the not_in requirements.
238
     * @return boolean
239
     */
240 2 View Code Duplication
    private function validateNotIn()
241
    {
242 2
        if (in_array($this->configuration->checkString(), (array)$this->configuration->rules()->get(Plexity::RULE_NOT_IN))) {
243 1
            return false;
244
        }
245 1
        return true;
246
    }
247
248
    /**
249
     * Count the number of occurences of a character or string in a string.
250
     * @param array $needles The character/string to count occurrences of.
251
     * @param string $haystack The string to check against.
252
     * @return int The number of occurrences.
253
     */
254 8
    private function countOccurrences(array $needles, $haystack)
255
    {
256 8
        $count = 0;
257 8
        foreach ($needles as $char) {
258 8
            $count += substr_count($haystack, $char);
259
        }
260 8
        return $count;
261
    }
262
}
263