PortugueseNif.php 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. <?php
  2. /*
  3. * Copyright (c) Alexandre Gomes Gaigalas <alganet@gmail.com>
  4. * SPDX-License-Identifier: MIT
  5. */
  6. declare(strict_types=1);
  7. namespace Respect\Validation\Rules;
  8. use function array_keys;
  9. use function array_map;
  10. use function array_pop;
  11. use function array_sum;
  12. use function intval;
  13. use function is_numeric;
  14. use function is_string;
  15. use function str_split;
  16. use function strlen;
  17. /**
  18. * Validates Portugal's fiscal identification number (NIF)
  19. *
  20. *
  21. * @see https://pt.wikipedia.org/wiki/N%C3%BAmero_de_identifica%C3%A7%C3%A3o_fiscal
  22. *
  23. * @author Gonçalo Andrade <goncalo.andrade95@gmail.com>
  24. */
  25. final class PortugueseNif extends AbstractRule
  26. {
  27. /**
  28. * {@inheritDoc}
  29. */
  30. public function validate($input): bool
  31. {
  32. // Validate format and length
  33. if (!is_string($input)) {
  34. return false;
  35. }
  36. if (!is_numeric($input)) {
  37. return false;
  38. }
  39. if (strlen($input) != 9) {
  40. return false;
  41. }
  42. $digits = array_map(static fn (string $digit) => intval($digit), str_split($input));
  43. // Validate first and second digits
  44. switch ($digits[0]) {
  45. case 4:
  46. switch ($digits[1]) {
  47. case 5:
  48. break;
  49. default:
  50. return false;
  51. }
  52. break;
  53. case 7:
  54. switch ($digits[1]) {
  55. case 0:
  56. case 1:
  57. case 2:
  58. case 4:
  59. case 5:
  60. case 7:
  61. case 8:
  62. case 9:
  63. break;
  64. default:
  65. return false;
  66. }
  67. break;
  68. case 9:
  69. switch ($digits[1]) {
  70. case 0:
  71. case 1:
  72. case 8:
  73. case 9:
  74. break;
  75. default:
  76. return false;
  77. }
  78. break;
  79. default:
  80. break;
  81. }
  82. // Validate check digit
  83. $checkDigit = array_pop($digits);
  84. $digitKeys = array_keys($digits);
  85. $sumTerms = array_map(static fn (int $digit, int $position) => $digit * (9 - $position), $digits, $digitKeys);
  86. $sum = array_sum($sumTerms);
  87. $modulus = $sum % 11;
  88. if ($modulus == 0 || $modulus == 1) {
  89. return $checkDigit == 0;
  90. }
  91. return $checkDigit == 11 - $modulus;
  92. }
  93. }