Viricmind Labs
Validación de NIFs, NIEs, DNIs y CIFs en PHP
Julio 30th, 2011 - [Enlace local]
Hará unas dos semanas estuve lidiando con cierta porción de código dedicada a la validación de NIFs, NIEs, DNIs y CIFs para dificultar fraudes y "suciedad" en la base de datos que usa cierta aplicación que estoy desarrollando para la Facultad de Economía y Empresa de la Universidad de Barcelona. Tengo que decir que lo más difícil no fue programar, sino encontrar la información, que se haya en gran medida de forma dispersa a través de la red, y peor aun, en muchos casos es incorrecta.
Conviene destacar que gran parte de la dificultad de encontrar esa información está ligada a los sucesivos cambios legislativos (el último fue en 2008!), el poco interés que despierta en la "clase programadora", y la escasa reflexión de los primeros diseñadores del sistema de numeración del DNI.
Bien, después de pelearme largo y tendido con el problema, acabé encontrando todo lo que necesitaba, y aquí podéis ver el resultado, para que no tengáis que perder el tiempo buscando en mil y un lugares diferentes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | // Función auxiliar usada para CIFs y NIFs especiales private function getCifSum ($cif) { $sum = $cif[2] + $cif[4] + $cif[6]; for ($i = 1; $i<8; $i += 2) { $tmp = (string) (2 * $cif[$i]); $tmp = $tmp[0] + ((strlen ($tmp) == 2) ? $tmp[1] : 0); $sum += $tmp; } return $sum; } // Valida CIFs // El código comentado es para usar en modelos de CakePHP protected function validateCif ($cif /*$check*/) { $cif_codes = 'JABCDEFGHI'; // $cif = array_pop ($check); $sum = (string) $this->getCifSum ($cif); $n = (10 - substr ($sum, -1)) % 10; if (preg_match ('/^[ABCDEFGHJNPQRSUVW]{1}/', $cif)) { if (in_array ($cif[0], array ('A', 'B', 'E', 'H'))) { // Numerico return ($cif[8] == $n); } elseif (in_array ($cif[0], array ('K', 'P', 'Q', 'S'))) { // Letras return ($cif[8] == $cif_codes[$n]); } else { // Alfanumérico if (is_numeric ($cif[8])) { return ($cif[8] == $n); } else { return ($cif[8] == $cif_codes[$n]); } } } return false; } // Valida NIFs (DNIs y NIFs especiales) // El código comentado es para usar en modelos CakePHP protected function validateNif ($nif /*$check*/) { $nif_codes = 'TRWAGMYFPDXBNJZSQVHLCKE'; // $nif = strtoupper (array_pop ($check)); $sum = (string) $this->getCifSum ($nif); $n = 10 - substr($sum, -1); if (preg_match ('/^[0-9]{8}[A-Z]{1}$/', $nif)) { // DNIs $num = substr($nif, 0, 8); return ($nif[8] == $nif_codes[$num % 23]); } elseif (preg_match ('/^[XYZ][0-9]{7}[A-Z]{1}$/', $nif)) { // NIEs normales $tmp = substr ($nif, 1, 7); $tmp = strtr(substr ($nif, 0, 1), 'XYZ', '012') . $tmp; return ($nif[8] == $nif_codes[$tmp % 23]); } elseif (preg_match ('/^[KLM]{1}/', $nif)) { // NIFs especiales return ($nif[8] == chr($n + 64)); } elseif (preg_match ('/^[T]{1}[A-Z0-9]{8}$/', $nif)) { // NIE extraño return true; } return false; } |
Además, aquí tenéis la lista de fuentes en las que me he basado. En primer lugar las no oficiales, comentadas para indicar las que no me parecen de fiar, porque eso también puede llevar quebraderos de cabeza.
- http://es.wikipedia.org/wiki/Número_de_identificación_fiscal (información incompleta)
- http://es.wikipedia.org/wiki/Código_de_identificación_fiscal (información incompleta)
- http://compartecodigo.com/javascript/validar-nif-cif-nie-segun-ley-vigente-31.html (a mi entender, tiene fallos)
- http://sourcecookbook.com/en/recipes/36/validacion-automatica-de-cif-nif-y-nie-segun-la-ultima-legislacion-j-query (otro con bastantes fallos)
- http://menudoproblema.es/blog/entries/2011/01/05/como-realizar-la-validacion-de-un-cif-en-python/ (incompleto, pero inspirador)
- http://boe.es/boe/dias/1975/10/22/pdfs/A22177-22178.pdf
- http://boe.es/boe/dias/1987/12/24/pdfs/A37785-37839.pdf (artículo 113)
- http://boe.es/boe/dias/1990/03/14/pdfs/A07256-07259.pdf
- http://boe.es/boe/dias/2007/09/05/pdfs/A36512-36594.pdf
- http://boe.es/boe/dias/2008/02/26/pdfs/A11374-11376.pdf