Passed
Push — master ( a506cc...7f1720 )
by Alan
02:44
created

RuleFactory::addSlashes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 2
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace FigTree\Validation;
4
5
use Closure;
6
use FigTree\Validation\Contracts\RuleInterface;
7
8
class RuleFactory extends AbstractRuleFactory
9
{
10
	/**
11
	 * Create a Rule for a valid boolean.
12
	 *
13
	 * @param mixed $default
14
	 *
15
	 * @return \FigTree\Validation\Contracts\RuleInterface
16
	 */
17
	public function validBool($default = null): RuleInterface
18
	{
19
		return $this->applyDefault($this->create(FILTER_VALIDATE_BOOL, FILTER_NULL_ON_FAILURE), $default);
20
	}
21
22
	/**
23
	 * Create a Rule for a valid domain name.
24
	 *
25
	 * @param boolean $checkHostname Adds ability to specifically validate hostnames (they must start with an alphanumeric character and contain only alphanumerics or hyphens).
26
	 * @param mixed $default
27
	 *
28
	 * @return \FigTree\Validation\Contracts\RuleInterface
29
	 */
30
	public function validDomain(bool $checkHostname = false, $default = null): RuleInterface
31
	{
32
		$flags = $this->addFlagIf(0, $checkHostname, FILTER_FLAG_HOSTNAME);
33
34
		return $this->applyDefault($this->create(FILTER_VALIDATE_DOMAIN, $flags), $default);
35
	}
36
37
	/**
38
	 * Create a Rule for a valid e-mail address.
39
	 *
40
	 * @param boolean $checkUnicode
41
	 * @param mixed $default
42
	 *
43
	 * @return \FigTree\Validation\Contracts\RuleInterface
44
	 */
45
	public function validEmail(bool $checkUnicode = false, $default = null): RuleInterface
46
	{
47
		$flags = $this->addFlagIf(0, $checkUnicode, FILTER_FLAG_EMAIL_UNICODE);
48
49
		return $this->applyDefault($this->create(FILTER_VALIDATE_EMAIL, $flags), $default);
50
	}
51
52
	/**
53
	 * Create a Rule for a valid floating-point value.
54
	 *
55
	 * @param float|null $min
56
	 * @param float|null $max
57
	 * @param integer|null $decimals
58
	 * @param boolean $allowThousands Allow thousand separators (commas).
59
	 * @param mixed $default
60
	 *
61
	 * @return \FigTree\Validation\Contracts\RuleInterface
62
	 */
63
	public function validFloat(?float $min = null, ?float $max = null, ?int $decimals = null, bool $allowThousands = false, $default = null): RuleInterface
64
	{
65
		$options = [];
66
67
		if (!is_null($min)) {
68
			$options['min_range'] = $min;
69
		}
70
71
		if (!is_null($max)) {
72
			$options['max_range'] = $max;
73
		}
74
75
		if (!is_null($decimals)) {
76
			$options['decimal'] = $decimals;
77
		}
78
79
		$flags = $this->addFlagIf(0, $allowThousands, FILTER_FLAG_ALLOW_THOUSAND);
80
81
		return $this->applyDefault($this->create(FILTER_VALIDATE_FLOAT, $flags, $options), $default);
82
	}
83
84
	/**
85
	 * Create a Rule for a valid integer.
86
	 *
87
	 * @param integer|null $min
88
	 * @param integer|null $max
89
	 * @param boolean $allowOctal
90
	 * @param boolean $allowHex
91
	 * @param mixed $default
92
	 *
93
	 * @return \FigTree\Validation\Contracts\RuleInterface
94
	 */
95
	public function validInt(?int $min = null, ?int $max = null, bool $allowOctal = false, bool $allowHex = false, $default = null): RuleInterface
96
	{
97
		$options = [];
98
99
		if (!is_null($min)) {
100
			$options['min_range'] = $min;
101
		}
102
103
		if (!is_null($max)) {
104
			$options['max_range'] = $max;
105
		}
106
107
		$conditions = [
108
			FILTER_FLAG_ALLOW_OCTAL => ($allowOctal),
109
			FILTER_FLAG_ALLOW_HEX => ($allowHex),
110
		];
111
112
		$flags = $this->addFlagsIf(0, $conditions);
113
114
		return $this->applyDefault($this->create(FILTER_VALIDATE_INT, $flags, $options), $default);
115
	}
116
117
	/**
118
	 * Create a Rule for a valid IP address.
119
	 *
120
	 * @param boolean $allowV4
121
	 * @param boolean $allowV6
122
	 * @param boolean $allowPrivateRange Allow IP addresses within private ranges.
123
	 * @param boolean $allowReservedRange Allow IP addresses within other reserved ranges.
124
	 * @param mixed $default
125
	 *
126
	 * @return \FigTree\Validation\Contracts\RuleInterface
127
	 *
128
	 * @see https://en.wikipedia.org/wiki/Reserved_IP_addresses
129
	 */
130
	public function validIpAddress(bool $allowV4 = false, bool $allowV6 = false, bool $allowPrivateRange = true, bool $allowReservedRange = true, $default = null): RuleInterface
131
	{
132
		$conditions = [
133
			FILTER_FLAG_IPV4 => ($allowV4),
134
			FILTER_FLAG_IPV6 => ($allowV6),
135
			FILTER_FLAG_NO_PRIV_RANGE => (!$allowPrivateRange),
136
			FILTER_FLAG_NO_RES_RANGE => (!$allowReservedRange),
137
		];
138
139
		$flags = $this->addFlagsIf(0, $conditions);
140
141
		return $this->applyDefault($this->create(FILTER_VALIDATE_IP, $flags), $default);
142
	}
143
144
	/**
145
	 * Create a Rule for a valid MAC address.
146
	 *
147
	 * @param mixed $default
148
	 *
149
	 * @return \FigTree\Validation\Contracts\RuleInterface
150
	 */
151
	public function validMacAddress($default = null): RuleInterface
152
	{
153
		return $this->applyDefault($this->create(FILTER_VALIDATE_MAC), $default);
154
	}
155
156
	/**
157
	 * Create a Rule for a valid regular expression match.
158
	 *
159
	 * @param string $regex
160
	 * @param mixed $default
161
	 *
162
	 * @return \FigTree\Validation\Contracts\RuleInterface
163
	 */
164
	public function validRegExp(string $regex, $default = null): RuleInterface
165
	{
166
		$options = [
167
			'regexp' => $regex,
168
		];
169
170
		return $this->applyDefault($this->create(FILTER_VALIDATE_REGEXP, 0, $options), $default);
171
	}
172
173
	/**
174
	 * Apply default option to the Rule.
175
	 *
176
	 * @param \FigTree\Validation\Contracts\RuleInterface $rule
177
	 * @param mixed $default
178
	 *
179
	 * @return \FigTree\Validation\Contracts\RuleInterface
180
	 */
181
	protected function applyDefault(RuleInterface $rule, $default = null): RuleInterface
182
	{
183
		if (!is_null($default)) {
184
			$rule->setOption('default', $default);
185
		}
186
187
		return $rule;
188
	}
189
190
	/**
191
	 * Apply addslashes().
192
	 *
193
	 * @return \FigTree\Validation\Contracts\RuleInterface
194
	 *
195
	 * @see https://www.php.net/manual/en/function.addslashes.php
196
	 */
197
	public function addSlashes(): RuleInterface
198
	{
199
		return $this->create(FILTER_SANITIZE_ADD_SLASHES);
200
	}
201
202
	/**
203
	 * Remove all characters except letters, digits and !#$%&'*+-=?^_`{|}~@.[].
204
	 *
205
	 * @return \FigTree\Validation\Contracts\RuleInterface
206
	 */
207
	public function cleanEmail(): RuleInterface
208
	{
209
		return $this->create(FILTER_SANITIZE_EMAIL);
210
	}
211
212
	/**
213
	 * URL-encode string, optionally strip or encode special characters.
214
	 *
215
	 * @return \FigTree\Validation\Contracts\RuleInterface
216
	 */
217
	public function cleanEncodedString(bool $stripLow = false, bool $stripHigh = false, bool $stripBacktick = false, bool $encodeLow = false, bool $encodeHigh = false): RuleInterface
218
	{
219
		$conditions = [
220
			FILTER_FLAG_STRIP_LOW => ($stripLow),
221
			FILTER_FLAG_STRIP_HIGH => ($stripHigh),
222
			FILTER_FLAG_STRIP_BACKTICK => ($stripBacktick),
223
			FILTER_FLAG_ENCODE_LOW => ($encodeLow),
224
			FILTER_FLAG_ENCODE_HIGH => ($encodeHigh),
225
		];
226
227
		$flags = $this->addFlagsIf(0, $conditions);
228
229
		return $this->create(FILTER_SANITIZE_ENCODED, $flags);
230
	}
231
232
	/**
233
	 * Remove all characters except digits, +- and optionally .,eE.
234
	 *
235
	 * @param bool $allowFractions
236
	 * @param bool $allowThousands
237
	 * @param bool $allowScientific
238
	 *
239
	 * @return \FigTree\Validation\Contracts\RuleInterface
240
	 */
241
	public function cleanFloat(bool $allowFractions = false, bool $allowThousands = false, $allowScientific = false): RuleInterface
242
	{
243
		$conditions = [
244
			FILTER_FLAG_ALLOW_FRACTION => ($allowFractions),
245
			FILTER_FLAG_ALLOW_THOUSAND => ($allowThousands),
246
			FILTER_FLAG_ALLOW_SCIENTIFIC => ($allowScientific),
247
		];
248
249
		$flags = $this->addFlagsIf(0, $conditions);
250
251
		return $this->create(FILTER_SANITIZE_NUMBER_FLOAT, $flags);
252
	}
253
254
	/**
255
	 * Equivalent to calling htmlspecialchars() with ENT_QUOTES set.
256
	 *
257
	 * Like htmlspecialchars(), this filter is aware of the default_charset and
258
	 * if a sequence of bytes is detected that makes up an invalid character in
259
	 * the current character set then the entire string is rejected resulting
260
	 * in a 0-length string.
261
	 *
262
	 * @param bool $encodeQuotes Whether or not to encode quotes.
263
	 *
264
	 * @return \FigTree\Validation\Contracts\RuleInterface
265
	 */
266
	public function cleanFullSpecialChars(bool $encodeQuotes = true): RuleInterface
267
	{
268
		$flags = $this->addFlagIf(0, !$encodeQuotes, FILTER_FLAG_NO_ENCODE_QUOTES);
269
270
		return $this->create(FILTER_SANITIZE_FULL_SPECIAL_CHARS, $flags);
271
	}
272
273
	/**
274
	 * Remove all characters except digits, plus and minus sign.
275
	 *
276
	 * @return \FigTree\Validation\Contracts\RuleInterface
277
	 */
278
	public function cleanInt(): RuleInterface
279
	{
280
		return $this->create(FILTER_SANITIZE_NUMBER_INT);
281
	}
282
283
	/**
284
	 * HTML-encode '"<>& and characters with ASCII value less than 32, optionally strip or encode other special characters.
285
	 *
286
	 * @param bool $stripLow
287
	 * @param bool $stripHigh
288
	 * @param bool $stripBacktick
289
	 * @param bool $encodeHigh
290
	 *
291
	 * @return \FigTree\Validation\Contracts\RuleInterface
292
	 */
293
	public function cleanSpecialChars(bool $stripLow = false, bool $stripHigh = false, bool $stripBacktick = false, bool $encodeHigh = false): RuleInterface
294
	{
295
		$conditions = [
296
			FILTER_FLAG_STRIP_LOW => ($stripLow),
297
			FILTER_FLAG_STRIP_HIGH => ($stripHigh),
298
			FILTER_FLAG_STRIP_BACKTICK => ($stripBacktick),
299
			FILTER_FLAG_ENCODE_HIGH => ($encodeHigh),
300
		];
301
302
		$flags = $this->addFlagsIf(0, $conditions);
303
304
		return $this->create(FILTER_SANITIZE_SPECIAL_CHARS, $flags);
305
	}
306
307
	/**
308
	 * Strip tags and HTML-encode double and single quotes, optionally strip or encode special characters.
309
	 *
310
	 * @param bool $encodeQuotes
311
	 * @param bool $stripLow
312
	 * @param bool $stripHigh
313
	 * @param bool $stripBacktick
314
	 * @param bool $encodeLow
315
	 * @param bool $encodeHigh
316
	 * @param bool $encodeAmp
317
	 *
318
	 * @return \FigTree\Validation\Contracts\RuleInterface
319
	 */
320
	public function cleanString(bool $encodeQuotes = true, bool $stripLow = false, bool $stripHigh = false, bool $stripBacktick = false, bool $encodeLow = false, bool $encodeHigh = false, bool $encodeAmp = false): RuleInterface
321
	{
322
		$conditions = [
323
			FILTER_FLAG_NO_ENCODE_QUOTES => (!$encodeQuotes),
324
			FILTER_FLAG_STRIP_LOW => ($stripLow),
325
			FILTER_FLAG_STRIP_HIGH => ($stripHigh),
326
			FILTER_FLAG_STRIP_BACKTICK => ($stripBacktick),
327
			FILTER_FLAG_ENCODE_LOW => ($encodeLow),
328
			FILTER_FLAG_ENCODE_HIGH => ($encodeHigh),
329
			FILTER_FLAG_ENCODE_AMP => ($encodeAmp),
330
		];
331
332
		$flags = $this->addFlagsIf(0, $conditions);
333
334
		return $this->create(FILTER_SANITIZE_STRING, $flags);
335
	}
336
337
	/**
338
	 * Do nothing, optionally strip or encode special characters.
339
	 *
340
	 * @param bool $stripLow
341
	 * @param bool $stripHigh
342
	 * @param bool $stripBacktick
343
	 * @param bool $encodeLow
344
	 * @param bool $encodeHigh
345
	 * @param bool $encodeAmp
346
	 *
347
	 * @return \FigTree\Validation\Contracts\RuleInterface
348
	 */
349
	public function cleanUnsafe(bool $stripLow = false, bool $stripHigh = false, bool $stripBacktick = false, bool $encodeLow = false, bool $encodeHigh = false, bool $encodeAmp = false): RuleInterface
350
	{
351
		$conditions = [
352
			FILTER_FLAG_STRIP_LOW => ($stripLow),
353
			FILTER_FLAG_STRIP_HIGH => ($stripHigh),
354
			FILTER_FLAG_STRIP_BACKTICK => ($stripBacktick),
355
			FILTER_FLAG_ENCODE_LOW => ($encodeLow),
356
			FILTER_FLAG_ENCODE_HIGH => ($encodeHigh),
357
			FILTER_FLAG_ENCODE_AMP => ($encodeAmp),
358
		];
359
360
		$flags = $this->addFlagsIf(0, $conditions);
361
362
		return $this->create(FILTER_UNSAFE_RAW, $flags);
363
	}
364
365
	/**
366
	 * Remove all characters except letters, digits and
367
	 * $-_.+!*'(),{}|\\^~[]`<>#%";/?:@&=.
368
	 *
369
	 * @return \FigTree\Validation\Contracts\RuleInterface
370
	 */
371
	public function cleanUrl(): RuleInterface
372
	{
373
		return $this->create(FILTER_SANITIZE_URL);
374
	}
375
376
	/**
377
	 * Create a Rule for a valid boolean.
378
	 *
379
	 * @param callable $callback
380
	 *
381
	 * @return \FigTree\Validation\Contracts\RuleInterface
382
	 */
383
	public function withCallable(callable $callback): RuleInterface
384
	{
385
		return $this->create(FILTER_CALLBACK)
386
			->setCallback(Closure::fromCallable($callback));
387
	}
388
389
	/**
390
	 * Create a Rule for a valid boolean.
391
	 *
392
	 * @param \Closure $callback
393
	 *
394
	 * @return \FigTree\Validation\Contracts\RuleInterface
395
	 */
396
	public function withClosure(Closure $callback): RuleInterface
397
	{
398
		return $this->create(FILTER_CALLBACK)
399
			->setCallback($callback);
400
	}
401
402
	/**
403
	 * Add a flag if the given condition is true.
404
	 *
405
	 * @param int $flags The flags being modified.
406
	 * @param bool $condition The condition being checked.
407
	 * @param int $flag The flag being added.
408
	 *
409
	 * @return int
410
	 */
411
	protected function addFlagIf(int $flags, bool $condition, int $flag): int
412
	{
413
		if ($condition) {
414
			$flags |= $flag;
415
		}
416
417
		return $flags;
418
	}
419
420
421
	/**
422
	 * Add a set of flags if their given conditions are true.
423
	 *
424
	 * @param int $flags The flags being modified.
425
	 * @param array $flagConditions An array of flags and their conditions to determine if they should be added.
426
	 *
427
	 * @return int
428
	 */
429
	protected function addFlagsIf(int $flags, array $flagConditions): int
430
	{
431
		foreach ($flagConditions as $flag => $condition) {
432
			if (is_int($flag) && is_bool($condition)) {
433
				$flags = $this->addFlagIf($flags, $condition, $flag);
434
			}
435
		}
436
437
		return $flags;
438
	}
439
}
440