Passed
Branch master (a1faa7)
by refat
03:26
created

Validator::dateMethods()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 4
nop 1
dl 0
loc 15
rs 9.5555
c 0
b 0
f 0
1
<?php
2
3
namespace System\Validation;
4
5
use System\Application;
6
use System\Validation\Date;
7
use System\Validation\Characters;
8
use System\Validation\AllowedCharacters;
9
10
class Validator
11
{
12
  /**
13
   * Application Object
14
   *
15
   * @var \System\Application
16
   */
17
  private $app;
18
19
  /**
20
   * Input name
21
   *
22
   * @var string
23
   */
24
  private $input;
25
26
  /**
27
   * Input value
28
   *
29
   * @var string
30
   */
31
  private $value;
32
33
  /**
34
   * Errors container
35
   *
36
   * @var array
37
   */
38
  private $errors = [];
39
40
  /**
41
   * Constructor
42
   *
43
   * @param \System\Application $app
44
   */
45
  public function __construct(Application $app)
46
  {
47
    $this->app = $app;
48
  }
49
50
  public function input($input, $request = 'post')
51
  {
52
    $this->input = $input;
53
54
    $this->value = $this->app->request->$request($this->input);
55
56
    return $this;
57
  }
58
59
  /**
60
   * Get the value for the input name
61
   *
62
   * @return mixed
63
   */
64
  private function value()
65
  {
66
    return mb_strtolower($this->value);
67
  }
68
69
  /**
70
   * Determine if the input is not empty
71
   *
72
   * @param bool $call
73
   * @param string $msg
74
   * @return $this
75
   */
76
  public function require($call = true, $msg = null)
77
  {
78
    if ($call === false) return $this;
79
80
    $value = $this->value();
81
82
    if ($value === '' || $value === null) {
83
      $msg = $msg ?: 'this field is required';
84
85
      $this->addError($this->input, $msg);
86
    }
87
    return $this;
88
  }
89
90
  /**
91
   * Call the function by given $type
92
   *
93
   * @param string $type
94
   * @return mix
0 ignored issues
show
Bug introduced by
The type System\Validation\mix was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
95
   */
96
  public function type($type)
97
  {
98
    return $this->$type();
99
  }
100
101
  /**
102
   * Determine if the input is valid email
103
   *
104
   * @param bool $call
105
   * @param string $msg
106
   * @return $this
107
   */
108
  public function email($call = true, $msg = null)
109
  {
110
    if ($call === false) return $this;
111
112
    $value = $this->value();
113
114
    if (!$value && $value != '0') return $this;
115
116
    if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
117
      $msg = $msg ?: 'e-mail is not valid';
118
119
      $this->addError($this->input, $msg);
120
    }
121
    return $this;
122
  }
123
124
  /**
125
   * Determine if the input is an image
126
   *
127
   * @param bool $call
128
   * @param string $customErrorMessage
129
   * @return $this
130
   */
131
  public function image($call = true, $msg = null)
132
  {
133
    if ($call === false) return $this;
134
135
    $file = $this->app->request->file($this->input);
136
137
    if (!$file->exists()) return $this;
138
139
    if (!$file->isImage()) {
140
      $msg = $msg ?: 'image is not valid';
141
142
      $this->addError($this->input, $msg);
143
    }
144
    return $this;
145
  }
146
147
  /**
148
   * Determine if the input has number
149
   *
150
   * @param bool $call
151
   * @param string $msg
152
   * @return $this
153
   */
154
  public function number($call = true, $msg = null)
155
  {
156
    if ($call === false) return $this;
157
158
    $value = $this->value();
159
160
    if (!$value && $value != '0') return $this;
161
162
    if (!is_numeric($value)) {
163
      $msg = $msg ?: 'this field must be a number';
164
165
      $this->addError($this->input, $msg);
166
    }
167
    return $this;
168
  }
169
170
  /**
171
   * Determine if the input has float value
172
   *
173
   * @param bool $call
174
   * @param string $msg
175
   * @return $this
176
   */
177
  public function float($call = true, $msg = null)
178
  {
179
    if ($call === false) return $this;
180
181
    $value = $this->value();
182
183
    if (!$value && $value != '0') return $this;
184
185
    if (!is_float($value)) {
0 ignored issues
show
introduced by
The condition is_float($value) is always false.
Loading history...
186
      $msg = $msg ?: "this field must be a float number";
187
188
      $this->addError($this->input, $msg);
189
    }
190
    return $this;
191
  }
192
193
  /**
194
   * Determine if the input is a date
195
   * Determine if the input between the range if the $options['start']
196
   * or the $options ['end'] is exists
197
   *
198
   * @param string $options
199
   * @param string $msg
200
   * @return $this
201
   */
202
  public function date($options = [], $msg = null)
203
  {
204
    if ($options === false) return $this;
0 ignored issues
show
introduced by
The condition $options === false is always false.
Loading history...
205
206
    $value = $this->value();
207
208
    if (!$value && $value != '0') return $this;
209
210
    $options = json_encode($options);
211
    $options = json_decode($options);
212
213
    extract($this->dateMethods($options));
214
215
    $date = new Date($value, $options);
216
217
    if (!$date->$method()) {
218
      $this->addError($this->input, $msg);
219
    }
220
    return $this;
221
  }
222
223
  private function dateMethods($options)
224
  {
225
    $method = null;
226
    $msg = null;
227
    if ($options->start && $options->end) {
228
      $method = 'isDateBetween';
229
      $msg = 'this field must be between ' . $options->start . ' and ' . $options->end;
230
    } elseif ($options->start) {
231
      $method = 'minimum';
232
      $msg = 'the date can\'t be under ' . $options->start;
233
    } elseif ($options->end) {
234
      $method = 'maximum';
235
      $msg = 'the date can\'t be above ' . $options->end;
236
    }
237
    return array('method' => $method, 'msg'=> $msg);
238
  }
239
240
  /**
241
   * Determine if the input has simple text
242
   *
243
   * @param bool $call
244
   * @param string $msg
245
   * @return $this
246
   */
247
  public function text($call = true, $msg = null)
248
  {
249
    if ($call === false) return $this;
250
251
    $value = $this->value();
252
253
    if (!$value && $value != '0') return $this;
254
255
    if (!is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always true.
Loading history...
256
      $msg = $msg ?: 'the field must be a text';
257
258
      $this->addError($this->input, $msg);
259
    }
260
    return $this;
261
  }
262
263
  /**
264
   * Determine if the input has pure string
265
   *
266
   * @param bool $call
267
   * @param string $msg
268
   * @return $this
269
   */
270
  public function noNumbers($call = true, $msg = null)
271
  {
272
    if ($call === false) return $this;
273
274
    $value = $this->value();
275
276
    if (!$value && $value != '0') return $this;
277
278
    if (preg_match('~[0-9]~', $value)) {
279
      $msg = $msg ?: 'numbers are not allow';
280
281
      $this->addError($this->input, $msg);
282
    }
283
284
    return $this;
285
  }
286
287
  /**
288
   * Determine if the input has pure string
289
   *
290
   * @param array $excepts
291
   * @param string $msg
292
   * @return $this
293
   */
294
  public function characters($excepts, $msg = null)
295
  {
296
    if ($excepts === false) return $this;
0 ignored issues
show
introduced by
The condition $excepts === false is always false.
Loading history...
297
298
    $value = $this->value();
299
300
    if (!$value && $value != '0') return $this;
301
302
    extract($this->charactersvariables($excepts, $value));
303
304
    if ($this->checkForErrorsInCharactersMethods($methods, $msg)) {
305
      return $this;
306
    }
307
    $re = "/^[0-9\\s$chars$langsRegex]*$/u";
308
    if (!preg_match($re, $value)) {
309
      $msg = $this->charactersMsg($chars, $languages, $msg);
310
      $this->addError($this->input, $msg);
311
    }
312
    return $this;
313
  }
314
315
  private function charactersMsg($chars, $languages, $msg)
316
  {
317
    $chars = $this->charactersFormatCharsMsg($chars);
318
    $languages = $languages ? "[ $languages ]" : '';
319
    $msg = $msg ?: "just $chars $languages letters can be used";
320
    return $msg;
321
  }
322
323
  private function charactersFormatCharsRegex($chars)
324
  {
325
    if (strlen($chars) > 1) {
326
      $chars = str_split($chars);
327
      $chars = "\\" . implode('|\\', $chars);
328
    }
329
    return $chars;
330
  }
331
332
  private function charactersFormatCharsMsg($chars)
333
  {
334
    $chars = explode('\\', $chars);
335
    $chars = implode('', $chars);
336
    $chars = $chars ? "[ $chars ] and" : '';
337
    return $chars;
338
  }
339
340
  private function charactersvariables($excepts, $value)
341
  {
342
    $characters = new Characters($excepts);
343
    $chars = $characters->getChars();
344
    $langsRegex = $characters->getLangsRegex();
345
    $languages = $characters->getLanguages();
346
    $times = $characters->getTimes();
347
    $atFirst = $characters->getAtFirst();
348
    $atEnd = $characters->getAtEnd();
349
    $between = $characters->getBetween();
350
    $methods = $this->charactersMethods([
351
      "times" => $times,
352
      "atFirst" => $atFirst,
353
      "atEnd" => $atEnd,
354
      "between" => $between,
355
      "chars" => $chars,
356
      "value" => $value,
357
    ]);
358
359
    return [
360
      'characters' => $characters,
361
      'chars' => $chars,
362
      'langsRegex' => $langsRegex,
363
      'languages' => $languages,
364
      'times' => $times,
365
      'atFirst' => $atFirst,
366
      'atEnd' => $atEnd,
367
      'between' => $between,
368
      'methods' => $methods,
369
    ];
370
  }
371
372
  private function charactersMethods($args)
373
  {
374
    extract($args);
375
    return [
376
      'charactersTimes' => [
377
        [$times, $chars, $value],
378
        'charachters are too many',
379
      ],
380
      'charactersAtFirst' => [
381
        [$atFirst, $chars, $value],
382
        'charachters cant be at the first',
383
      ],
384
      'charactersAtEnd' => [
385
        [$atEnd, $chars, $value],
386
        'charachters cant be at the end',
387
      ],
388
      'charactersBetween' => [
389
        [$between, $chars, $value],
390
        'charachters cant be between',
391
      ],
392
    ];
393
  }
394
395
  private function charactersTimes($times, $chars, $value)
396
  {
397
    if ($times > 0) {
398
      $chars = $this->charactersFormatCharsRegex($chars);
399
      $re = "/($chars)/";
400
      if (preg_match($re, $value) && preg_match_all($re, $value) > $times) {
401
        return true;
402
      }
403
      return false;
404
    }
405
  }
406
407
  private function charactersAtFirst($atFirst, $chars, $value)
408
  {
409
    if ($atFirst === false) {
410
      $chars = $this->charactersFormatCharsRegex($chars);
411
      $re = "/^($chars" . "|\\s+\\$chars)/";
412
      if (preg_match_all($re, $value)) {
413
        return true;
414
      }
415
      return false;
416
    }
417
  }
418
419
  private function charactersAtEnd($atEnd, $chars, $value)
420
  {
421
    if ($atEnd === false) {
422
      $chars = $this->charactersFormatCharsRegex($chars);
423
      $re = "/($chars" . "|\\$chars\\s+)$/";
424
      if (preg_match_all($re, $value)) {
425
        return true;
426
      }
427
      return false;
428
    }
429
  }
430
431
  private function charactersBetween($between, $chars, $value)
432
  {
433
    if ($between === false) {
434
      $chars = $this->charactersFormatCharsRegex($chars);
435
      $re = "/.+(${chars})(.+|\\s)/";
436
      if (preg_match_all($re, $value)) {
437
        return true;
438
      }
439
      return false;
440
    }
441
  }
442
443
  private function checkForErrorsInCharactersMethods($methods, $msg)
444
  {
445
    foreach ($methods as $method => $options) {
446
      if (call_user_func_array(array($this, $method), $options[0])) {
447
        $msg = $msg ?: $options[1];
448
        $this->addError($this->input, $msg);
449
        return true;
450
      }
451
    }
452
    return false;
453
  }
454
455
  /**
456
   * Determine if the input has spaces between the letters or the words
457
   *
458
   * @param bool $call
459
   * @param string $msg
460
   * @return $this
461
   */
462
  public function noSpaces($call = true, $msg = null)
463
  {
464
    if ($call === false) return $this;
465
466
    $value = $this->value();
467
468
    if (!$value && $value != '0') return $this;
469
470
    if (preg_match('/\s/', $value)) {
471
      $msg = $msg ?: 'spaces are not allow';
472
473
      $this->addError($this->input, $msg);
474
    }
475
    return $this;
476
  }
477
478
  /**
479
   * Determine if the given input has the value that are passed
480
   *
481
   * @param array $characters
482
   * @param string $msg
483
   * @return $this
484
   */
485
  public function containJust($characters = [], $msg = null)
486
  {
487
    if ($characters === false) return $this;
0 ignored issues
show
introduced by
The condition $characters === false is always false.
Loading history...
488
489
    $value = $this->value();
490
491
    if (!$value && $value != '0') return $this;
492
493
    if (!is_array($characters) && $characters !== '') {
0 ignored issues
show
introduced by
The condition is_array($characters) is always true.
Loading history...
494
      $characters = [$characters];
495
    }
496
497
    $allowedCharacters = new AllowedCharacters($this->app, $characters);
498
    $characters = $allowedCharacters->getCharacters($characters);
0 ignored issues
show
Unused Code introduced by
The call to System\Validation\Allowe...acters::getCharacters() has too many arguments starting with $characters. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

498
    /** @scrutinizer ignore-call */ 
499
    $characters = $allowedCharacters->getCharacters($characters);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
499
500
    if (!in_array($value, $characters)) {
501
      $msg = $msg ?: 'wrong value';
502
      $this->addError($this->input, $msg);
503
    }
504
    return $this;
505
  }
506
507
  /**
508
   * Determine if the input value should equal length
509
   *
510
   * @param int $length
511
   * @param string $msg
512
   * @return $this
513
   */
514
  public function length($length = null, $msg = null)
515
  {
516
    if ($length === false) return $this;
0 ignored issues
show
introduced by
The condition $length === false is always false.
Loading history...
517
518
    $value = $this->value();
519
520
    if (!$value && $value != '0') return $this;
521
522
    if (strlen($value) !== $length) {
523
      $msg = $msg ?: `this field can be just ${length} charachter`;
524
525
      $this->addError($this->input, $msg);
526
    }
527
    return $this;
528
  }
529
530
  /**
531
   * Determine if the input value should be at most the given length
532
   *
533
   * @param int $length
534
   * @param string $msg
535
   * @return $this
536
   */
537
  public function maxLen($length = null, $msg = null)
538
  {
539
    if ($length === false) return $this;
0 ignored issues
show
introduced by
The condition $length === false is always false.
Loading history...
540
541
    $value = $this->value();
542
543
    if (!$value && $value != '0') return $this;
544
545
    if (strlen($value) > $length) {
546
      $msg = $msg ?: "this field can be maximum $length charachter";
547
548
      $this->addError($this->input, $msg);
549
    }
550
    return $this;
551
  }
552
553
  /**
554
   * Determine if the input value should be at least the given length
555
   *
556
   * @param int $length
557
   * @param string $msg
558
   * @return $this
559
   */
560
  public function minLen($length = null, $msg = null)
561
  {
562
    if ($length === false) return $this;
0 ignored issues
show
introduced by
The condition $length === false is always false.
Loading history...
563
564
    $value = $this->value();
565
566
    if (!$value && $value != '0') return $this;
567
568
    if (strlen($value) < $length) {
569
      $msg = $msg ?: "this field can be minimum $length charachter";
570
571
      $this->addError($this->input, $msg);
572
    }
573
    return $this;
574
  }
575
576
  /**
577
   * Determine if the $input matches the given input
578
   *
579
   * @param string $input
580
   * @param string $msg
581
   * @return $this
582
   */
583
  public function match($input, $msg = null)
584
  {
585
    if ($input === false) return $this;
0 ignored issues
show
introduced by
The condition $input === false is always false.
Loading history...
586
587
    $value = $this->value();
588
589
    $valueConfirm = $this->app->request->post($input);
590
591
    if ($value && $valueConfirm) {
592
      if ($value !== $valueConfirm) {
593
        $msg = $msg ?: 'passwords doesn\'t match';
594
595
        $this->addError('match', $msg);
596
      }
597
    }
598
    return $this;
599
  }
600
601
  /**
602
   * Determine if the input is unique in database
603
   *
604
   * @param array $data
605
   * @param string $msg
606
   * @return $this
607
   */
608
  public function unique($data = [], $msg = null)
609
  {
610
    if ($data === false) return $this;
0 ignored issues
show
introduced by
The condition $data === false is always false.
Loading history...
611
612
    $value = $this->value();
613
614
    if (!$data) return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression $data of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
615
616
    if (is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always true.
Loading history...
617
      list($table, $column) = $data;
618
    } else {
619
      $table = $data;
620
      $column = $this->input;
621
    }
622
623
    $result = $this->app->db->select($column)->from($table)->where($column . ' = ? ', $value)->fetch();
624
625
    if ($result) {
626
      $msg = $msg ?: sprintf('%s is already exist', ucfirst($this->input));
627
628
      $this->addError($this->input, $msg);
629
    }
630
    return $this;
631
  }
632
633
  /**
634
   * Determine if all inputs are valid
635
   *
636
   * @return bool
637
   */
638
  public function passes()
639
  {
640
    return empty($this->errors);
641
  }
642
643
  /**
644
   * Determine if there are any invalid inputs
645
   *
646
   * @return bool
647
   */
648
  public function fails()
649
  {
650
    return !empty($this->errors);
651
  }
652
653
  /**
654
   * Determine if the given input has previous errors
655
   *
656
   * @param string $input
657
   */
658
  private function hasError($input)
659
  {
660
    return array_key_exists($input, $this->errors);
661
  }
662
663
  /**
664
   * Add input error
665
   *
666
   * @param string $inputName
667
   * @param string $msg
668
   * @return void
669
   */
670
  public function addError($input, $msg)
671
  {
672
    if (!$this->hasError($input)) $this->errors[$input] = $msg;
673
  }
674
675
  /**
676
   * Get all errors
677
   *
678
   * @return array
679
   */
680
  public function getErrors()
681
  {
682
    return $this->errors;
683
  }
684
}
685