Nif.php 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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_pop;
  9. use function array_sum;
  10. use function is_numeric;
  11. use function is_string;
  12. use function mb_substr;
  13. use function preg_match;
  14. use function str_split;
  15. /**
  16. * Validates Spain's fiscal identification number (NIF).
  17. *
  18. *
  19. * @see https://es.wikipedia.org/wiki/N%C3%BAmero_de_identificaci%C3%B3n_fiscal
  20. *
  21. * @author Henrique Moody <henriquemoody@gmail.com>
  22. * @author Julián Gutiérrez <juliangut@gmail.com>
  23. * @author Senén <senen@instasent.com>
  24. */
  25. final class Nif extends AbstractRule
  26. {
  27. /**
  28. * {@inheritDoc}
  29. */
  30. public function validate($input): bool
  31. {
  32. if (!is_string($input)) {
  33. return false;
  34. }
  35. if (preg_match('/^(\d{8})([A-Z])$/', $input, $matches)) {
  36. return $this->validateDni((int) $matches[1], $matches[2]);
  37. }
  38. if (preg_match('/^([KLMXYZ])(\d{7})([A-Z])$/', $input, $matches)) {
  39. return $this->validateNie($matches[1], $matches[2], $matches[3]);
  40. }
  41. if (preg_match('/^([A-HJNP-SUVW])(\d{7})([0-9A-Z])$/', $input, $matches)) {
  42. return $this->validateCif($matches[2], $matches[3]);
  43. }
  44. return false;
  45. }
  46. private function validateDni(int $number, string $control): bool
  47. {
  48. return mb_substr('TRWAGMYFPDXBNJZSQVHLCKE', $number % 23, 1) === $control;
  49. }
  50. private function validateNie(string $prefix, string $number, string $control): bool
  51. {
  52. if ($prefix === 'Y') {
  53. return $this->validateDni((int) ('1' . $number), $control);
  54. }
  55. if ($prefix === 'Z') {
  56. return $this->validateDni((int) ('2' . $number), $control);
  57. }
  58. return $this->validateDni((int) $number, $control);
  59. }
  60. private function validateCif(string $number, string $control): bool
  61. {
  62. $code = 0;
  63. $position = 1;
  64. /** @var int $digit */
  65. foreach (str_split($number) as $digit) {
  66. $increaser = $digit;
  67. if ($position % 2 !== 0) {
  68. $increaser = array_sum(str_split((string) ($digit * 2)));
  69. }
  70. $code += $increaser;
  71. ++$position;
  72. }
  73. $digits = str_split((string) $code);
  74. $lastDigit = (int) array_pop($digits);
  75. $key = $lastDigit === 0 ? 0 : 10 - $lastDigit;
  76. if (is_numeric($control)) {
  77. return (int) $key === (int) $control;
  78. }
  79. return mb_substr('JABCDEFGHI', $key % 10, 1) === $control;
  80. }
  81. }