Rutificador
\n\n\n```\n\n## Integración con Laravel\n\n### Regla de validación personalizada:\n\n```php\nmessage;\n }\n}\n\n// app/Providers/AppServiceProvider.php\nnamespace AppProviders;\n\nuse IlluminateSupportServiceProvider;\nuse IlluminateSupportFacadesValidator;\n\nclass AppServiceProvider extends ServiceProvider\n{\n public function boot()\n {\n // Registrar validación personalizada\n Validator::extend('rut', function ($attribute, $value, $parameters, $validator) {\n return RutValidator::validar($value);\n });\n \n // Mensaje personalizado\n Validator::replacer('rut', function ($message, $attribute, $rule, $parameters) {\n return str_replace(':attribute', $attribute, 'El campo :attribute debe ser un RUT válido.');\n });\n }\n}\n\n// Uso en controlador\nnamespace AppHttpControllers;\n\nuse AppRulesRutChileno;\nuse IlluminateHttpRequest;\n\nclass ClienteController extends Controller\n{\n public function store(Request $request)\n {\n $validated = $request->validate([\n 'nombre' => 'required|string|max:255',\n 'rut' => ['required', new RutChileno],\n 'email' => 'required|email'\n ]);\n \n // Formatear RUT antes de guardar\n $validated['rut'] = RutValidator::formatear($validated['rut']);\n \n $cliente = Cliente::create($validated);\n \n return response()->json([\n 'message' => 'Cliente creado exitosamente',\n 'cliente' => $cliente\n ], 201);\n }\n}\n\n// Modelo con mutador\nnamespace AppModels;\n\nuse IlluminateDatabaseEloquentModel;\n\nclass Cliente extends Model\n{\n protected $fillable = ['nombre', 'rut', 'email'];\n \n /**\n * Mutador para formatear RUT al guardar\n */\n public function setRutAttribute($value)\n {\n $this->attributes['rut'] = RutValidator::formatear($value);\n }\n \n /**\n * Accessor para obtener info del RUT\n */\n public function getRutInfoAttribute()\n {\n return RutValidator::extraerInfo($this->rut);\n }\n}\n```\n\n## Integración con Symfony\n\n### Constraint personalizado para Symfony:\n\n```php\ncontext->buildViolation($constraint->message)\n ->setParameter('{{ value }}', $value)\n ->addViolation();\n }\n }\n}\n\n// src/Entity/Cliente.php\nnamespace AppEntity;\n\nuse AppValidatorConstraints as AppAssert;\nuse DoctrineORMMapping as ORM;\nuse SymfonyComponentValidatorConstraints as Assert;\n\n/**\n * @ORMEntity\n * @ORMTable(name=\"clientes\")\n */\nclass Cliente\n{\n /**\n * @ORMId\n * @ORMGeneratedValue\n * @ORMColumn(type=\"integer\")\n */\n private $id;\n \n /**\n * @ORMColumn(type=\"string\", length=100)\n * @AssertNotBlank\n * @AssertLength(max=100)\n */\n private $nombre;\n \n /**\n * @ORMColumn(type=\"string\", length=12, unique=true)\n * @AssertNotBlank\n * @AppAssertRutChileno\n */\n private $rut;\n \n /**\n * @ORMColumn(type=\"string\", length=255)\n * @AssertNotBlank\n * @AssertEmail\n */\n private $email;\n \n // Getters y setters...\n \n public function setRut(string $rut): self\n {\n $this->rut = RutValidator::formatear($rut);\n return $this;\n }\n}\n```\n\n## API REST con validación\n\n### Endpoint completo con manejo de errores:\n\n```php\n true,\n 'message' => 'RUT es requerido'\n ]);\n }\n \n $rut = $input['rut'];\n $esValido = RutValidator::validar($rut);\n \n $response = [\n 'valido' => $esValido,\n 'rut_original' => $rut,\n 'rut_limpio' => RutValidator::limpiar($rut)\n ];\n \n if ($esValido) {\n $info = RutValidator::extraerInfo($rut);\n $response = array_merge($response, [\n 'rut_formateado' => $info['formateado'],\n 'numero' => $info['numero'],\n 'digito_verificador' => $info['dv'],\n 'tipo' => $info['tipo']\n ]);\n }\n \n echo json_encode($response);\n \n } catch (Exception $e) {\n http_response_code(500);\n echo json_encode([\n 'error' => true,\n 'message' => 'Error interno del servidor'\n ]);\n }\n }\n \n /**\n * Valida múltiples RUTs\n * POST /api/rut/validar-lote\n */\n public function validarLote()\n {\n header('Content-Type: application/json');\n \n try {\n $input = json_decode(file_get_contents('php://input'), true);\n \n if (!isset($input['ruts']) || !is_array($input['ruts'])) {\n http_response_code(400);\n return json_encode([\n 'error' => true,\n 'message' => 'Se requiere un array de RUTs'\n ]);\n }\n \n $resultados = [];\n $validos = 0;\n $invalidos = 0;\n \n foreach ($input['ruts'] as $rut) {\n $esValido = RutValidator::validar($rut);\n \n $resultado = [\n 'rut' => $rut,\n 'valido' => $esValido\n ];\n \n if ($esValido) {\n $resultado['formateado'] = RutValidator::formatear($rut);\n $validos++;\n } else {\n $invalidos++;\n }\n \n $resultados[] = $resultado;\n }\n \n echo json_encode([\n 'total' => count($input['ruts']),\n 'validos' => $validos,\n 'invalidos' => $invalidos,\n 'porcentaje_validos' => count($input['ruts']) > 0 \n ? round(($validos / count($input['ruts'])) * 100, 2) \n : 0,\n 'resultados' => $resultados\n ]);\n \n } catch (Exception $e) {\n http_response_code(500);\n echo json_encode([\n 'error' => true,\n 'message' => 'Error procesando lote'\n ]);\n }\n }\n \n /**\n * Calcula dígito verificador\n * GET /api/rut/calcular-dv/{numero}\n */\n public function calcularDV($numero)\n {\n header('Content-Type: application/json');\n \n if (!is_numeric($numero) || $numero < 1000000 || $numero > 99999999) {\n http_response_code(400);\n echo json_encode([\n 'error' => true,\n 'message' => 'Número de RUT inválido'\n ]);\n return;\n }\n \n $dv = RutValidator::calcularDV($numero);\n \n echo json_encode([\n 'numero' => (int)$numero,\n 'digito_verificador' => $dv,\n 'rut_completo' => RutValidator::formatear($numero . $dv)\n ]);\n }\n}\n```\n\n## Procesamiento masivo de archivos\n\n### Script para procesar CSV con RUTs:\n\n```php\n 0,\n 'validos' => 0,\n 'invalidos' => 0,\n 'procesados' => 0,\n 'errores' => []\n ];\n \n /**\n * Procesa un archivo CSV con RUTs\n * \n * @param string $archivoEntrada Path del archivo CSV\n * @param string $archivoSalida Path del archivo de salida\n * @param int $columnaRut Índice de la columna con RUTs (0-based)\n * @return array Estadísticas del procesamiento\n */\n public function procesarCSV($archivoEntrada, $archivoSalida, $columnaRut = 0)\n {\n if (!file_exists($archivoEntrada)) {\n throw new Exception(\"Archivo no encontrado: $archivoEntrada\");\n }\n \n $entrada = fopen($archivoEntrada, 'r');\n $salida = fopen($archivoSalida, 'w');\n \n if (!$entrada || !$salida) {\n throw new Exception(\"Error abriendo archivos\");\n }\n \n // Procesar encabezados\n $encabezados = fgetcsv($entrada);\n if ($encabezados) {\n // Agregar columnas nuevas\n $encabezados[] = 'rut_valido';\n $encabezados[] = 'rut_formateado';\n $encabezados[] = 'rut_tipo';\n fputcsv($salida, $encabezados);\n }\n \n // Procesar datos\n while (($fila = fgetcsv($entrada)) !== false) {\n $this->stats['total']++;\n \n try {\n if (isset($fila[$columnaRut])) {\n $rut = $fila[$columnaRut];\n $esValido = RutValidator::validar($rut);\n \n if ($esValido) {\n $this->stats['validos']++;\n $info = RutValidator::extraerInfo($rut);\n $fila[] = 'SI';\n $fila[] = $info['formateado'];\n $fila[] = $info['tipo'];\n } else {\n $this->stats['invalidos']++;\n $fila[] = 'NO';\n $fila[] = '';\n $fila[] = '';\n }\n } else {\n $this->stats['errores'][] = \"Fila {$this->stats['total']}: columna RUT no encontrada\";\n $fila[] = 'ERROR';\n $fila[] = '';\n $fila[] = '';\n }\n \n fputcsv($salida, $fila);\n $this->stats['procesados']++;\n \n // Mostrar progreso cada 1000 registros\n if ($this->stats['procesados'] % 1000 === 0) {\n echo \"Procesados: {$this->stats['procesados']}\\r\";\n }\n \n } catch (Exception $e) {\n $this->stats['errores'][] = \"Fila {$this->stats['total']}: \" . $e->getMessage();\n }\n }\n \n fclose($entrada);\n fclose($salida);\n \n return $this->stats;\n }\n \n /**\n * Genera reporte de procesamiento\n * \n * @return string Reporte formateado\n */\n public function generarReporte()\n {\n $porcentajeValidos = $this->stats['total'] > 0 \n ? round(($this->stats['validos'] / $this->stats['total']) * 100, 2) \n : 0;\n \n $reporte = \"\\n=== REPORTE DE PROCESAMIENTO ===\\n\";\n $reporte .= \"Total de registros: {$this->stats['total']}\\n\";\n $reporte .= \"RUTs válidos: {$this->stats['validos']} ($porcentajeValidos%)\\n\";\n $reporte .= \"RUTs inválidos: {$this->stats['invalidos']}\\n\";\n $reporte .= \"Registros procesados: {$this->stats['procesados']}\\n\";\n \n if (count($this->stats['errores']) > 0) {\n $reporte .= \"\\nErrores encontrados:\\n\";\n foreach ($this->stats['errores'] as $error) {\n $reporte .= \"- $error\\n\";\n }\n }\n \n return $reporte;\n }\n}\n\n// Script principal\nif (php_sapi_name() === 'cli') {\n if ($argc < 2) {\n echo \"Uso: php procesar_ruts.php [archivo_salida.csv] [columna_rut]\\n\";\n exit(1);\n }\n \n $archivoEntrada = $argv[1];\n $archivoSalida = $argv[2] ?? 'ruts_validados.csv';\n $columnaRut = isset($argv[3]) ? (int)$argv[3] : 0;\n \n try {\n require_once 'RutValidator.php';\n \n $processor = new RutProcessor();\n echo \"Procesando archivo: $archivoEntrada\\n\";\n \n $stats = $processor->procesarCSV($archivoEntrada, $archivoSalida, $columnaRut);\n \n echo $processor->generarReporte();\n echo \"\\nArchivo de salida: $archivoSalida\\n\";\n \n } catch (Exception $e) {\n echo \"Error: \" . $e->getMessage() . \"\\n\";\n exit(1);\n }\n}\n?>\n```\n\n## Testing con PHPUnit\n\n### Suite completa de pruebas:\n\n```php\nassertEquals($esperado, RutValidator::validar($rut));\n }\n \n public function rutValidosProvider()\n {\n return [\n ['12.345.678-5', true],\n ['12345678-5', true],\n ['123456785', true],\n ['11.111.111-1', true],\n ['15.834.661-K', true],\n ['15834661-k', true], // k minúscula\n ['5.126.663-3', true],\n ];\n }\n \n /**\n * @dataProvider rutInvalidosProvider\n */\n public function testValidarRutsIncorrectos($rut)\n {\n $this->assertFalse(RutValidator::validar($rut));\n }\n \n public function rutInvalidosProvider()\n {\n return [\n ['12.345.678-9'],\n ['11.111.111-2'],\n ['00000000-0'],\n ['abc123'],\n [''],\n ['1'],\n ['12.345.678'],\n ['12345678-'],\n ];\n }\n \n /**\n * @dataProvider digitoVerificadorProvider\n */\n public function testCalcularDigitoVerificador($numero, $dvEsperado)\n {\n $this->assertEquals($dvEsperado, RutValidator::calcularDV($numero));\n }\n \n public function digitoVerificadorProvider()\n {\n return [\n [12345678, '5'],\n [11111111, '1'],\n [22222222, '2'],\n [15834660, '0'],\n [15834661, 'K'],\n [8942487, '6'],\n ];\n }\n \n public function testFormatearRut()\n {\n $this->assertEquals('12.345.678-5', RutValidator::formatear('123456785'));\n $this->assertEquals('1.111.111-1', RutValidator::formatear('11111111'));\n $this->assertEquals('1.234.567-K', RutValidator::formatear('1234567K'));\n }\n \n public function testLimpiarRut()\n {\n $this->assertEquals('123456785', RutValidator::limpiar('12.345.678-5'));\n $this->assertEquals('123456785', RutValidator::limpiar('12 345 678-5'));\n $this->assertEquals('12345678K', RutValidator::limpiar('12.345.678-k'));\n }\n \n public function testExtraerInfo()\n {\n $info = RutValidator::extraerInfo('12.345.678-5');\n \n $this->assertIsArray($info);\n $this->assertEquals(12345678, $info['numero']);\n $this->assertEquals('5', $info['dv']);\n $this->assertEquals('12.345.678-5', $info['formateado']);\n $this->assertTrue($info['es_persona']);\n $this->assertFalse($info['es_empresa']);\n \n // Test con RUT inválido\n $this->assertNull(RutValidator::extraerInfo('12.345.678-9'));\n }\n \n public function testCacheFunciona()\n {\n RutValidator::limpiarCache();\n \n $rut = '12.345.678-5';\n \n // Primera validación (sin cache)\n $resultado1 = RutValidator::validar($rut);\n \n // Segunda validación (con cache)\n $resultado2 = RutValidator::validar($rut);\n \n $this->assertEquals($resultado1, $resultado2);\n }\n \n public function testRendimientoMasivo()\n {\n $inicio = microtime(true);\n \n // Validar 1000 RUTs\n for ($i = 0; $i < 1000; $i++) {\n RutValidator::validar('12.345.678-5');\n }\n \n $tiempo = microtime(true) - $inicio;\n \n // Debería tomar menos de 1 segundo con cache\n $this->assertLessThan(1.0, $tiempo);\n }\n}\n?>\n```\n\n## Consideraciones de seguridad\n\n### Mejores prácticas para producción:\n\n```php\n 100) { // Máximo 100 intentos por hora\n return [\n 'error' => true,\n 'message' => 'Demasiados intentos. Intente más tarde.'\n ];\n }\n \n apcu_store($cacheKey, $attempts + 1, 3600); // TTL 1 hora\n \n // Sanitizar entrada\n $rut = self::sanitizar($rut);\n \n // Validar\n $esValido = parent::validar($rut);\n \n // Log para auditoría\n self::logValidacion($rut, $ip, $esValido);\n \n return [\n 'valido' => $esValido,\n 'rut_sanitizado' => $rut\n ];\n }\n \n /**\n * Sanitiza entrada para prevenir XSS\n * \n * @param string $input Entrada del usuario\n * @return string Entrada sanitizada\n */\n private static function sanitizar($input)\n {\n // Remover tags HTML\n $input = strip_tags($input);\n \n // Remover caracteres de control\n $input = preg_replace('/[\u0000-\u001f]/u', '', $input);\n \n // Limitar longitud\n $input = substr($input, 0, 20);\n \n return $input;\n }\n \n /**\n * Registra validaciones para auditoría\n * \n * @param string $rut RUT validado\n * @param string $ip IP del cliente\n * @param bool $esValido Resultado de validación\n */\n private static function logValidacion($rut, $ip, $esValido)\n {\n $log = sprintf(\n \"[%s] IP: %s, RUT: %s, Válido: %s\\n\",\n date('Y-m-d H:i:s'),\n $ip,\n substr($rut, 0, -4) . '****', // Ocultar últimos 4 caracteres\n $esValido ? 'SI' : 'NO'\n );\n \n error_log($log, 3, '/var/log/rut_validations.log');\n }\n}\n\n// Middleware para aplicaciones web\nclass RutValidationMiddleware\n{\n public function handle($request, $next)\n {\n if ($request->has('rut')) {\n $ip = $request->ip();\n $rut = $request->input('rut');\n \n $resultado = SecureRutValidator::validarConLimite($rut, $ip);\n \n if (isset($resultado['error'])) {\n return response()->json($resultado, 429); // Too Many Requests\n }\n \n $request->merge(['rut_validado' => $resultado]);\n }\n \n return $next($request);\n }\n}\n?>\n```\n\n## Conclusión\n\nPHP ofrece una implementación robusta y eficiente para la validación de RUTs chilenos. Las soluciones presentadas cubren desde scripts simples hasta integraciones empresariales complejas:\n\n- **Funciones básicas**: Para validaciones rápidas y scripts simples\n- **Clases OOP**: Para aplicaciones estructuradas y reutilizables\n- **Integraciones con frameworks**: Laravel y Symfony para aplicaciones modernas\n- **APIs REST**: Para servicios web escalables\n- **Procesamiento masivo**: Para manejar grandes volúmenes de datos\n- **Seguridad**: Implementaciones seguras para producción\n\nLa clave está en elegir la implementación adecuada según tus necesidades, siempre manteniendo las mejores prácticas de seguridad y rendimiento.\n\n---\n\n### Recursos adicionales\n\n- **PHP.net**: Documentación oficial del lenguaje\n- **Packagist**: Busca paquetes como `freshwork/chilean-bundle`\n- **GitHub**: Repositorios con implementaciones de RUT para PHP\n- **Comunidad PHP Chile**: Foros y grupos de desarrolladores chilenos\n","keywords":"PHP, RUT, programación, validación, backend","articleSection":"Desarrollo"}

Desarrollo · · 9 min de lectura

Validar RUT en PHP: implementación del algoritmo módulo 11

Aprende a validar RUT chilenos en PHP con código profesional. Incluye función completa, ejemplos de uso y mejores prácticas de seguridad.

Catalina FuentesDesarrolladora backend

PHP en el contexto empresarial chileno

PHP sigue siendo uno de los lenguajes más utilizados en aplicaciones web chilenas, especialmente en sistemas de facturación, e-commerce y plataformas empresariales. La validación correcta del RUT es crítica para cumplir con las normativas del SII y evitar rechazos en documentos tributarios electrónicos.

Este tutorial te mostrará cómo implementar una validación robusta y segura del RUT en PHP, desde funciones básicas hasta integraciones con frameworks modernos como Laravel y Symfony.

Función básica para calcular el dígito verificador

Implementación directa del algoritmo

PHP
1<?php
2/**
3 * Calcula el dígito verificador de un RUT chileno
4 * 
5 * @param int|string $rutNumero Número del RUT sin dígito verificador
6 * @return string Dígito verificador (0-9 o K)
7 */
8function calcularDigitoVerificador($rutNumero) {
9    // Asegurar que sea string y tenga 8 dígitos
10    $rut = str_pad((string)$rutNumero, 8, '0', STR_PAD_LEFT);
11    
12    // Multiplicadores según algoritmo módulo 11
13    $multiplicadores = [2, 3, 4, 5, 6, 7];
14    
15    // Calcular suma ponderada
16    $suma = 0;
17    $rutReverso = strrev($rut);
18    
19    for ($i = 0; $i < strlen($rutReverso); $i++) {
20        $digito = (int)$rutReverso[$i];
21        $multiplicador = $multiplicadores[$i % 6];
22        $suma += $digito * $multiplicador;
23    }
24    
25    // Calcular dígito verificador
26    $resto = $suma % 11;
27    $digitoVerificador = 11 - $resto;
28    
29    // Casos especiales
30    if ($digitoVerificador == 11) {
31        return '0';
32    } elseif ($digitoVerificador == 10) {
33        return 'K';
34    } else {
35        return (string)$digitoVerificador;
36    }
37}
38
39// Ejemplos de uso
40echo calcularDigitoVerificador(12345678);  // 5
41echo calcularDigitoVerificador(11111111);  // 1
42echo calcularDigitoVerificador(15834661);  // K
43?>

Clase completa para manejo de RUT

Implementación orientada a objetos con mejores prácticas

PHP
1<?php
2/**
3 * Clase para validar y formatear RUTs chilenos
4 * 
5 * @author Tu Nombre
6 * @version 1.0.0
7 */
8class RutValidator
9{
10    /**
11     * Cache de validaciones para mejorar rendimiento
12     * @var array
13     */
14    private static $cache = [];
15    
16    /**
17     * Tamaño máximo del cache
18     * @var int
19     */
20    private const MAX_CACHE_SIZE = 1000;
21    
22    /**
23     * Limpia el RUT removiendo puntos, guiones y espacios
24     * 
25     * @param string $rut RUT en cualquier formato
26     * @return string RUT limpio
27     */
28    public static function limpiar($rut)
29    {
30        // Remover caracteres no deseados y convertir a mayúsculas
31        return strtoupper(preg_replace('/[^0-9kK]/', '', $rut));
32    }
33    
34    /**
35     * Formatea el RUT con puntos y guión
36     * 
37     * @param string $rut RUT sin formato
38     * @return string RUT formateado (ej: 12.345.678-9)
39     */
40    public static function formatear($rut)
41    {
42        $rutLimpio = self::limpiar($rut);
43        
44        if (strlen($rutLimpio) < 2) {
45            return $rutLimpio;
46        }
47        
48        // Separar número y dígito verificador
49        $numero = substr($rutLimpio, 0, -1);
50        $dv = substr($rutLimpio, -1);
51        
52        // Formatear número con puntos
53        $numeroFormateado = '';
54        $contador = 0;
55        
56        for ($i = strlen($numero) - 1; $i >= 0; $i--) {
57            if ($contador > 0 && $contador % 3 === 0) {
58                $numeroFormateado = '.' . $numeroFormateado;
59            }
60            $numeroFormateado = $numero[$i] . $numeroFormateado;
61            $contador++;
62        }
63        
64        return $numeroFormateado . '-' . $dv;
65    }
66    
67    /**
68     * Calcula el dígito verificador
69     * 
70     * @param int|string $rutNumero Número del RUT sin DV
71     * @return string Dígito verificador
72     */
73    public static function calcularDV($rutNumero)
74    {
75        // Asegurar string de 8 dígitos
76        $rut = str_pad((string)$rutNumero, 8, '0', STR_PAD_LEFT);
77        
78        // Calcular suma ponderada usando array_reduce
79        $suma = array_reduce(
80            array_map(
81                function($i) use ($rut) {
82                    $digito = (int)$rut[strlen($rut) - 1 - $i];
83                    $factor = (($i % 6) + 2);
84                    return $digito * $factor;
85                },
86                range(0, strlen($rut) - 1)
87            ),
88            function($carry, $item) {
89                return $carry + $item;
90            },
91            0
92        );
93        
94        // Obtener dígito verificador
95        $dv = 11 - ($suma % 11);
96        
97        if ($dv == 11) {
98            return '0';
99        } elseif ($dv == 10) {
100            return 'K';
101        } else {
102            return (string)$dv;
103        }
104    }
105    
106    /**
107     * Valida un RUT completo
108     * 
109     * @param string $rut RUT completo con o sin formato
110     * @return bool True si es válido
111     */
112    public static function validar($rut)
113    {
114        $rutLimpio = self::limpiar($rut);
115        
116        // Verificar cache
117        if (isset(self::$cache[$rutLimpio])) {
118            return self::$cache[$rutLimpio];
119        }
120        
121        // Validar largo mínimo
122        if (strlen($rutLimpio) < 2) {
123            return self::actualizarCache($rutLimpio, false);
124        }
125        
126        // Separar número y DV
127        $numero = substr($rutLimpio, 0, -1);
128        $dvIngresado = substr($rutLimpio, -1);
129        
130        // Validar que el número contenga solo dígitos
131        if (!ctype_digit($numero)) {
132            return self::actualizarCache($rutLimpio, false);
133        }
134        
135        // Calcular DV esperado y comparar
136        $dvCalculado = self::calcularDV($numero);
137        $esValido = $dvIngresado === $dvCalculado;
138        
139        return self::actualizarCache($rutLimpio, $esValido);
140    }
141    
142    /**
143     * Actualiza el cache con límite de tamaño
144     * 
145     * @param string $rut RUT limpio
146     * @param bool $esValido Resultado de validación
147     * @return bool El resultado de validación
148     */
149    private static function actualizarCache($rut, $esValido)
150    {
151        // Limitar tamaño del cache
152        if (count(self::$cache) >= self::MAX_CACHE_SIZE) {
153            // Eliminar el primer elemento (FIFO)
154            array_shift(self::$cache);
155        }
156        
157        self::$cache[$rut] = $esValido;
158        return $esValido;
159    }
160    
161    /**
162     * Extrae información detallada del RUT
163     * 
164     * @param string $rut RUT a analizar
165     * @return array|null Array con información o null si es inválido
166     */
167    public static function extraerInfo($rut)
168    {
169        if (!self::validar($rut)) {
170            return null;
171        }
172        
173        $rutLimpio = self::limpiar($rut);
174        $numero = (int)substr($rutLimpio, 0, -1);
175        
176        return [
177            'numero' => $numero,
178            'dv' => substr($rutLimpio, -1),
179            'formateado' => self::formatear($rutLimpio),
180            'sin_formato' => $rutLimpio,
181            'es_empresa' => $numero >= 50000000,
182            'es_persona' => $numero < 50000000,
183            'tipo' => $numero >= 50000000 ? 'Empresa' : 'Persona Natural'
184        ];
185    }
186    
187    /**
188     * Limpia el cache de validaciones
189     * 
190     * @return void
191     */
192    public static function limpiarCache()
193    {
194        self::$cache = [];
195    }
196}
197
198// Ejemplos de uso
199$ruts = ['12.345.678-5', '11111111-1', '12.345.678-9', '15.834.661-K'];
200
201foreach ($ruts as $rut) {
202    if (RutValidator::validar($rut)) {
203        echo "✓ {$rut} es válido - " . RutValidator::formatear($rut) . PHP_EOL;
204    } else {
205        echo "✗ {$rut} es inválido" . PHP_EOL;
206    }
207}
208
209// Extraer información
210$info = RutValidator::extraerInfo('12.345.678-5');
211print_r($info);
212?>

Integración con formularios web

Validación AJAX en tiempo real

PHP
1<?php
2// api/validar-rut.php
3header('Content-Type: application/json');
4header('Access-Control-Allow-Origin: *');
5
6// Incluir clase RutValidator
7require_once 'RutValidator.php';
8
9// Obtener RUT desde POST o GET
10$rut = $_REQUEST['rut'] ?? '';
11
12// Validar
13$esValido = RutValidator::validar($rut);
14$response = [
15    'valido' => $esValido,
16    'rut_original' => $rut,
17    'rut_limpio' => RutValidator::limpiar($rut),
18    'mensaje' => $esValido ? 'RUT válido' : 'RUT inválido'
19];
20
21if ($esValido) {
22    $response['rut_formateado'] = RutValidator::formatear($rut);
23    $response['info'] = RutValidator::extraerInfo($rut);
24}
25
26echo json_encode($response);
27?>

Formulario HTML con validación en tiempo real

HTML
1<!DOCTYPE html>
2<html lang="es">
3<head>
4    <meta charset="UTF-8">
5    <title>Validador de RUT PHP</title>
6    <style>
7        .form-control { 
8            padding: 10px; 
9            font-size: 16px; 
10            border: 2px solid #ddd; 
11            border-radius: 4px; 
12            width: 300px;
13        }
14        .is-valid { border-color: #28a745; }
15        .is-invalid { border-color: #dc3545; }
16        .feedback { margin-top: 5px; font-size: 14px; }
17        .valid-feedback { color: #28a745; }
18        .invalid-feedback { color: #dc3545; }
19        .loading { color: #6c757d; }
20    </style>
21</head>
22<body>
23    <h2>Validador de RUT en PHP</h2>
24    
25    <form id="rutForm">
26        <div class="form-group">
27            <label for="rut">Ingrese RUT:</label>
28            <input 
29                type="text" 
30                id="rut" 
31                name="rut" 
32                class="form-control" 
33                placeholder="12.345.678-9"
34                maxlength="12"
35            >
36            <div class="feedback"></div>
37        </div>
38        
39        <button type="submit">Validar</button>
40    </form>
41    
42    <div id="resultado"></div>
43
44    <script>
45        const rutInput = document.getElementById('rut');
46        const feedback = document.querySelector('.feedback');
47        const resultado = document.getElementById('resultado');
48        let timeoutId;
49        
50        // Validación en tiempo real
51        rutInput.addEventListener('input', function(e) {
52            clearTimeout(timeoutId);
53            const rut = e.target.value;
54            
55            if (rut.length < 3) {
56                rutInput.classList.remove('is-valid', 'is-invalid');
57                feedback.textContent = '';
58                return;
59            }
60            
61            feedback.textContent = 'Validando...';
62            feedback.className = 'feedback loading';
63            
64            // Debounce de 500ms
65            timeoutId = setTimeout(() => {
66                validarRut(rut);
67            }, 500);
68        });
69        
70        // Función para validar RUT
71        async function validarRut(rut) {
72            try {
73                const response = await fetch('api/validar-rut.php', {
74                    method: 'POST',
75                    headers: {
76                        'Content-Type': 'application/x-www-form-urlencoded',
77                    },
78                    body: 'rut=' + encodeURIComponent(rut)
79                });
80                
81                const data = await response.json();
82                
83                if (data.valido) {
84                    rutInput.classList.remove('is-invalid');
85                    rutInput.classList.add('is-valid');
86                    feedback.className = 'feedback valid-feedback';
87                    feedback.textContent = '✓ ' + data.mensaje;
88                    
89                    // Actualizar input con formato correcto
90                    if (data.rut_formateado && rutInput.value !== data.rut_formateado) {
91                        rutInput.value = data.rut_formateado;
92                    }
93                } else {
94                    rutInput.classList.remove('is-valid');
95                    rutInput.classList.add('is-invalid');
96                    feedback.className = 'feedback invalid-feedback';
97                    feedback.textContent = '✗ ' + data.mensaje;
98                }
99                
100            } catch (error) {
101                feedback.className = 'feedback invalid-feedback';
102                feedback.textContent = 'Error al validar';
103            }
104        }
105        
106        // Prevenir envío del formulario
107        document.getElementById('rutForm').addEventListener('submit', function(e) {
108            e.preventDefault();
109            const rut = rutInput.value;
110            if (rut) {
111                validarRut(rut);
112            }
113        });
114    </script>
115</body>
116</html>

Integración con Laravel

Regla de validación personalizada

PHP
1<?php
2// app/Rules/RutChileno.php
3namespace AppRules;
4
5use IlluminateContractsValidationRule;
6
7class RutChileno implements Rule
8{
9    /**
10     * Mensaje de error personalizado
11     *
12     * @var string
13     */
14    protected $message = 'El :attribute no es un RUT válido.';
15    
16    /**
17     * Determina si la validación pasa
18     *
19     * @param  string  $attribute
20     * @param  mixed  $value
21     * @return bool
22     */
23    public function passes($attribute, $value)
24    {
25        return RutValidator::validar($value);
26    }
27    
28    /**
29     * Obtiene el mensaje de error
30     *
31     * @return string
32     */
33    public function message()
34    {
35        return $this->message;
36    }
37}
38
39// app/Providers/AppServiceProvider.php
40namespace AppProviders;
41
42use IlluminateSupportServiceProvider;
43use IlluminateSupportFacadesValidator;
44
45class AppServiceProvider extends ServiceProvider
46{
47    public function boot()
48    {
49        // Registrar validación personalizada
50        Validator::extend('rut', function ($attribute, $value, $parameters, $validator) {
51            return RutValidator::validar($value);
52        });
53        
54        // Mensaje personalizado
55        Validator::replacer('rut', function ($message, $attribute, $rule, $parameters) {
56            return str_replace(':attribute', $attribute, 'El campo :attribute debe ser un RUT válido.');
57        });
58    }
59}
60
61// Uso en controlador
62namespace AppHttpControllers;
63
64use AppRulesRutChileno;
65use IlluminateHttpRequest;
66
67class ClienteController extends Controller
68{
69    public function store(Request $request)
70    {
71        $validated = $request->validate([
72            'nombre' => 'required|string|max:255',
73            'rut' => ['required', new RutChileno],
74            'email' => 'required|email'
75        ]);
76        
77        // Formatear RUT antes de guardar
78        $validated['rut'] = RutValidator::formatear($validated['rut']);
79        
80        $cliente = Cliente::create($validated);
81        
82        return response()->json([
83            'message' => 'Cliente creado exitosamente',
84            'cliente' => $cliente
85        ], 201);
86    }
87}
88
89// Modelo con mutador
90namespace AppModels;
91
92use IlluminateDatabaseEloquentModel;
93
94class Cliente extends Model
95{
96    protected $fillable = ['nombre', 'rut', 'email'];
97    
98    /**
99     * Mutador para formatear RUT al guardar
100     */
101    public function setRutAttribute($value)
102    {
103        $this->attributes['rut'] = RutValidator::formatear($value);
104    }
105    
106    /**
107     * Accessor para obtener info del RUT
108     */
109    public function getRutInfoAttribute()
110    {
111        return RutValidator::extraerInfo($this->rut);
112    }
113}

Integración con Symfony

Constraint personalizado para Symfony

PHP
1<?php
2// src/Validator/Constraints/RutChileno.php
3namespace AppValidatorConstraints;
4
5use SymfonyComponentValidatorConstraint;
6
7/**
8 * @Annotation
9 */
10class RutChileno extends Constraint
11{
12    public $message = 'El RUT "{{ value }}" no es válido.';
13}
14
15// src/Validator/Constraints/RutChilenoValidator.php
16namespace AppValidatorConstraints;
17
18use SymfonyComponentValidatorConstraint;
19use SymfonyComponentValidatorConstraintValidator;
20use SymfonyComponentValidatorExceptionUnexpectedTypeException;
21
22class RutChilenoValidator extends ConstraintValidator
23{
24    public function validate($value, Constraint $constraint)
25    {
26        if (!$constraint instanceof RutChileno) {
27            throw new UnexpectedTypeException($constraint, RutChileno::class);
28        }
29        
30        if (null === $value || '' === $value) {
31            return;
32        }
33        
34        if (!RutValidator::validar($value)) {
35            $this->context->buildViolation($constraint->message)
36                ->setParameter('{{ value }}', $value)
37                ->addViolation();
38        }
39    }
40}
41
42// src/Entity/Cliente.php
43namespace AppEntity;
44
45use AppValidatorConstraints as AppAssert;
46use DoctrineORMMapping as ORM;
47use SymfonyComponentValidatorConstraints as Assert;
48
49/**
50 * @ORMEntity
51 * @ORMTable(name="clientes")
52 */
53class Cliente
54{
55    /**
56     * @ORMId
57     * @ORMGeneratedValue
58     * @ORMColumn(type="integer")
59     */
60    private $id;
61    
62    /**
63     * @ORMColumn(type="string", length=100)
64     * @AssertNotBlank
65     * @AssertLength(max=100)
66     */
67    private $nombre;
68    
69    /**
70     * @ORMColumn(type="string", length=12, unique=true)
71     * @AssertNotBlank
72     * @AppAssertRutChileno
73     */
74    private $rut;
75    
76    /**
77     * @ORMColumn(type="string", length=255)
78     * @AssertNotBlank
79     * @AssertEmail
80     */
81    private $email;
82    
83    // Getters y setters...
84    
85    public function setRut(string $rut): self
86    {
87        $this->rut = RutValidator::formatear($rut);
88        return $this;
89    }
90}

API REST con validación

Endpoint completo con manejo de errores

PHP
1<?php
2// api/RutController.php
3class RutController
4{
5    /**
6     * Valida un RUT individual
7     * POST /api/rut/validar
8     */
9    public function validar()
10    {
11        header('Content-Type: application/json');
12        
13        try {
14            // Obtener datos de entrada
15            $input = json_decode(file_get_contents('php://input'), true);
16            
17            if (!isset($input['rut'])) {
18                http_response_code(400);
19                return json_encode([
20                    'error' => true,
21                    'message' => 'RUT es requerido'
22                ]);
23            }
24            
25            $rut = $input['rut'];
26            $esValido = RutValidator::validar($rut);
27            
28            $response = [
29                'valido' => $esValido,
30                'rut_original' => $rut,
31                'rut_limpio' => RutValidator::limpiar($rut)
32            ];
33            
34            if ($esValido) {
35                $info = RutValidator::extraerInfo($rut);
36                $response = array_merge($response, [
37                    'rut_formateado' => $info['formateado'],
38                    'numero' => $info['numero'],
39                    'digito_verificador' => $info['dv'],
40                    'tipo' => $info['tipo']
41                ]);
42            }
43            
44            echo json_encode($response);
45            
46        } catch (Exception $e) {
47            http_response_code(500);
48            echo json_encode([
49                'error' => true,
50                'message' => 'Error interno del servidor'
51            ]);
52        }
53    }
54    
55    /**
56     * Valida múltiples RUTs
57     * POST /api/rut/validar-lote
58     */
59    public function validarLote()
60    {
61        header('Content-Type: application/json');
62        
63        try {
64            $input = json_decode(file_get_contents('php://input'), true);
65            
66            if (!isset($input['ruts']) || !is_array($input['ruts'])) {
67                http_response_code(400);
68                return json_encode([
69                    'error' => true,
70                    'message' => 'Se requiere un array de RUTs'
71                ]);
72            }
73            
74            $resultados = [];
75            $validos = 0;
76            $invalidos = 0;
77            
78            foreach ($input['ruts'] as $rut) {
79                $esValido = RutValidator::validar($rut);
80                
81                $resultado = [
82                    'rut' => $rut,
83                    'valido' => $esValido
84                ];
85                
86                if ($esValido) {
87                    $resultado['formateado'] = RutValidator::formatear($rut);
88                    $validos++;
89                } else {
90                    $invalidos++;
91                }
92                
93                $resultados[] = $resultado;
94            }
95            
96            echo json_encode([
97                'total' => count($input['ruts']),
98                'validos' => $validos,
99                'invalidos' => $invalidos,
100                'porcentaje_validos' => count($input['ruts']) > 0 
101                    ? round(($validos / count($input['ruts'])) * 100, 2) 
102                    : 0,
103                'resultados' => $resultados
104            ]);
105            
106        } catch (Exception $e) {
107            http_response_code(500);
108            echo json_encode([
109                'error' => true,
110                'message' => 'Error procesando lote'
111            ]);
112        }
113    }
114    
115    /**
116     * Calcula dígito verificador
117     * GET /api/rut/calcular-dv/{numero}
118     */
119    public function calcularDV($numero)
120    {
121        header('Content-Type: application/json');
122        
123        if (!is_numeric($numero) || $numero < 1000000 || $numero > 99999999) {
124            http_response_code(400);
125            echo json_encode([
126                'error' => true,
127                'message' => 'Número de RUT inválido'
128            ]);
129            return;
130        }
131        
132        $dv = RutValidator::calcularDV($numero);
133        
134        echo json_encode([
135            'numero' => (int)$numero,
136            'digito_verificador' => $dv,
137            'rut_completo' => RutValidator::formatear($numero . $dv)
138        ]);
139    }
140}

Procesamiento masivo de archivos

Script para procesar CSV con RUTs

PHP
1<?php
2/**
3 * Procesador de RUTs desde archivo CSV
4 * Uso: php procesar_ruts.php archivo.csv
5 */
6
7class RutProcessor
8{
9    private $stats = [
10        'total' => 0,
11        'validos' => 0,
12        'invalidos' => 0,
13        'procesados' => 0,
14        'errores' => []
15    ];
16    
17    /**
18     * Procesa un archivo CSV con RUTs
19     * 
20     * @param string $archivoEntrada Path del archivo CSV
21     * @param string $archivoSalida Path del archivo de salida
22     * @param int $columnaRut Índice de la columna con RUTs (0-based)
23     * @return array Estadísticas del procesamiento
24     */
25    public function procesarCSV($archivoEntrada, $archivoSalida, $columnaRut = 0)
26    {
27        if (!file_exists($archivoEntrada)) {
28            throw new Exception("Archivo no encontrado: $archivoEntrada");
29        }
30        
31        $entrada = fopen($archivoEntrada, 'r');
32        $salida = fopen($archivoSalida, 'w');
33        
34        if (!$entrada || !$salida) {
35            throw new Exception("Error abriendo archivos");
36        }
37        
38        // Procesar encabezados
39        $encabezados = fgetcsv($entrada);
40        if ($encabezados) {
41            // Agregar columnas nuevas
42            $encabezados[] = 'rut_valido';
43            $encabezados[] = 'rut_formateado';
44            $encabezados[] = 'rut_tipo';
45            fputcsv($salida, $encabezados);
46        }
47        
48        // Procesar datos
49        while (($fila = fgetcsv($entrada)) !== false) {
50            $this->stats['total']++;
51            
52            try {
53                if (isset($fila[$columnaRut])) {
54                    $rut = $fila[$columnaRut];
55                    $esValido = RutValidator::validar($rut);
56                    
57                    if ($esValido) {
58                        $this->stats['validos']++;
59                        $info = RutValidator::extraerInfo($rut);
60                        $fila[] = 'SI';
61                        $fila[] = $info['formateado'];
62                        $fila[] = $info['tipo'];
63                    } else {
64                        $this->stats['invalidos']++;
65                        $fila[] = 'NO';
66                        $fila[] = '';
67                        $fila[] = '';
68                    }
69                } else {
70                    $this->stats['errores'][] = "Fila {$this->stats['total']}: columna RUT no encontrada";
71                    $fila[] = 'ERROR';
72                    $fila[] = '';
73                    $fila[] = '';
74                }
75                
76                fputcsv($salida, $fila);
77                $this->stats['procesados']++;
78                
79                // Mostrar progreso cada 1000 registros
80                if ($this->stats['procesados'] % 1000 === 0) {
81                    echo "Procesados: {$this->stats['procesados']}\r";
82                }
83                
84            } catch (Exception $e) {
85                $this->stats['errores'][] = "Fila {$this->stats['total']}: " . $e->getMessage();
86            }
87        }
88        
89        fclose($entrada);
90        fclose($salida);
91        
92        return $this->stats;
93    }
94    
95    /**
96     * Genera reporte de procesamiento
97     * 
98     * @return string Reporte formateado
99     */
100    public function generarReporte()
101    {
102        $porcentajeValidos = $this->stats['total'] > 0 
103            ? round(($this->stats['validos'] / $this->stats['total']) * 100, 2) 
104            : 0;
105        
106        $reporte = "\n=== REPORTE DE PROCESAMIENTO ===\n";
107        $reporte .= "Total de registros: {$this->stats['total']}\n";
108        $reporte .= "RUTs válidos: {$this->stats['validos']} ($porcentajeValidos%)\n";
109        $reporte .= "RUTs inválidos: {$this->stats['invalidos']}\n";
110        $reporte .= "Registros procesados: {$this->stats['procesados']}\n";
111        
112        if (count($this->stats['errores']) > 0) {
113            $reporte .= "\nErrores encontrados:\n";
114            foreach ($this->stats['errores'] as $error) {
115                $reporte .= "- $error\n";
116            }
117        }
118        
119        return $reporte;
120    }
121}
122
123// Script principal
124if (php_sapi_name() === 'cli') {
125    if ($argc < 2) {
126        echo "Uso: php procesar_ruts.php <archivo_entrada.csv> [archivo_salida.csv] [columna_rut]\n";
127        exit(1);
128    }
129    
130    $archivoEntrada = $argv[1];
131    $archivoSalida = $argv[2] ?? 'ruts_validados.csv';
132    $columnaRut = isset($argv[3]) ? (int)$argv[3] : 0;
133    
134    try {
135        require_once 'RutValidator.php';
136        
137        $processor = new RutProcessor();
138        echo "Procesando archivo: $archivoEntrada\n";
139        
140        $stats = $processor->procesarCSV($archivoEntrada, $archivoSalida, $columnaRut);
141        
142        echo $processor->generarReporte();
143        echo "\nArchivo de salida: $archivoSalida\n";
144        
145    } catch (Exception $e) {
146        echo "Error: " . $e->getMessage() . "\n";
147        exit(1);
148    }
149}
150?>

Testing con PHPUnit

Suite completa de pruebas

PHP
1<?php
2use PHPUnitFrameworkTestCase;
3
4class RutValidatorTest extends TestCase
5{
6    /**
7     * @dataProvider rutValidosProvider
8     */
9    public function testValidarRutsCorrectos($rut, $esperado)
10    {
11        $this->assertEquals($esperado, RutValidator::validar($rut));
12    }
13    
14    public function rutValidosProvider()
15    {
16        return [
17            ['12.345.678-5', true],
18            ['12345678-5', true],
19            ['123456785', true],
20            ['11.111.111-1', true],
21            ['15.834.661-K', true],
22            ['15834661-k', true], // k minúscula
23            ['5.126.663-3', true],
24        ];
25    }
26    
27    /**
28     * @dataProvider rutInvalidosProvider
29     */
30    public function testValidarRutsIncorrectos($rut)
31    {
32        $this->assertFalse(RutValidator::validar($rut));
33    }
34    
35    public function rutInvalidosProvider()
36    {
37        return [
38            ['12.345.678-9'],
39            ['11.111.111-2'],
40            ['00000000-0'],
41            ['abc123'],
42            [''],
43            ['1'],
44            ['12.345.678'],
45            ['12345678-'],
46        ];
47    }
48    
49    /**
50     * @dataProvider digitoVerificadorProvider
51     */
52    public function testCalcularDigitoVerificador($numero, $dvEsperado)
53    {
54        $this->assertEquals($dvEsperado, RutValidator::calcularDV($numero));
55    }
56    
57    public function digitoVerificadorProvider()
58    {
59        return [
60            [12345678, '5'],
61            [11111111, '1'],
62            [22222222, '2'],
63            [15834660, '0'],
64            [15834661, 'K'],
65            [8942487, '6'],
66        ];
67    }
68    
69    public function testFormatearRut()
70    {
71        $this->assertEquals('12.345.678-5', RutValidator::formatear('123456785'));
72        $this->assertEquals('1.111.111-1', RutValidator::formatear('11111111'));
73        $this->assertEquals('1.234.567-K', RutValidator::formatear('1234567K'));
74    }
75    
76    public function testLimpiarRut()
77    {
78        $this->assertEquals('123456785', RutValidator::limpiar('12.345.678-5'));
79        $this->assertEquals('123456785', RutValidator::limpiar('12 345 678-5'));
80        $this->assertEquals('12345678K', RutValidator::limpiar('12.345.678-k'));
81    }
82    
83    public function testExtraerInfo()
84    {
85        $info = RutValidator::extraerInfo('12.345.678-5');
86        
87        $this->assertIsArray($info);
88        $this->assertEquals(12345678, $info['numero']);
89        $this->assertEquals('5', $info['dv']);
90        $this->assertEquals('12.345.678-5', $info['formateado']);
91        $this->assertTrue($info['es_persona']);
92        $this->assertFalse($info['es_empresa']);
93        
94        // Test con RUT inválido
95        $this->assertNull(RutValidator::extraerInfo('12.345.678-9'));
96    }
97    
98    public function testCacheFunciona()
99    {
100        RutValidator::limpiarCache();
101        
102        $rut = '12.345.678-5';
103        
104        // Primera validación (sin cache)
105        $resultado1 = RutValidator::validar($rut);
106        
107        // Segunda validación (con cache)
108        $resultado2 = RutValidator::validar($rut);
109        
110        $this->assertEquals($resultado1, $resultado2);
111    }
112    
113    public function testRendimientoMasivo()
114    {
115        $inicio = microtime(true);
116        
117        // Validar 1000 RUTs
118        for ($i = 0; $i < 1000; $i++) {
119            RutValidator::validar('12.345.678-5');
120        }
121        
122        $tiempo = microtime(true) - $inicio;
123        
124        // Debería tomar menos de 1 segundo con cache
125        $this->assertLessThan(1.0, $tiempo);
126    }
127}
128?>

Consideraciones de seguridad

Mejores prácticas para producción

PHP
1<?php
2/**
3 * Versión segura con validaciones adicionales
4 */
5class SecureRutValidator extends RutValidator
6{
7    /**
8     * Valida RUT con límite de intentos por IP
9     * 
10     * @param string $rut RUT a validar
11     * @param string $ip IP del cliente
12     * @return array Resultado con información adicional
13     */
14    public static function validarConLimite($rut, $ip)
15    {
16        // Implementar rate limiting
17        $cacheKey = "rut_attempts_" . md5($ip);
18        $attempts = apcu_fetch($cacheKey) ?: 0;
19        
20        if ($attempts > 100) { // Máximo 100 intentos por hora
21            return [
22                'error' => true,
23                'message' => 'Demasiados intentos. Intente más tarde.'
24            ];
25        }
26        
27        apcu_store($cacheKey, $attempts + 1, 3600); // TTL 1 hora
28        
29        // Sanitizar entrada
30        $rut = self::sanitizar($rut);
31        
32        // Validar
33        $esValido = parent::validar($rut);
34        
35        // Log para auditoría
36        self::logValidacion($rut, $ip, $esValido);
37        
38        return [
39            'valido' => $esValido,
40            'rut_sanitizado' => $rut
41        ];
42    }
43    
44    /**
45     * Sanitiza entrada para prevenir XSS
46     * 
47     * @param string $input Entrada del usuario
48     * @return string Entrada sanitizada
49     */
50    private static function sanitizar($input)
51    {
52        // Remover tags HTML
53        $input = strip_tags($input);
54        
55        // Remover caracteres de control
56        $input = preg_replace('/[-]/u', '', $input);
57        
58        // Limitar longitud
59        $input = substr($input, 0, 20);
60        
61        return $input;
62    }
63    
64    /**
65     * Registra validaciones para auditoría
66     * 
67     * @param string $rut RUT validado
68     * @param string $ip IP del cliente
69     * @param bool $esValido Resultado de validación
70     */
71    private static function logValidacion($rut, $ip, $esValido)
72    {
73        $log = sprintf(
74            "[%s] IP: %s, RUT: %s, Válido: %s\n",
75            date('Y-m-d H:i:s'),
76            $ip,
77            substr($rut, 0, -4) . '****', // Ocultar últimos 4 caracteres
78            $esValido ? 'SI' : 'NO'
79        );
80        
81        error_log($log, 3, '/var/log/rut_validations.log');
82    }
83}
84
85// Middleware para aplicaciones web
86class RutValidationMiddleware
87{
88    public function handle($request, $next)
89    {
90        if ($request->has('rut')) {
91            $ip = $request->ip();
92            $rut = $request->input('rut');
93            
94            $resultado = SecureRutValidator::validarConLimite($rut, $ip);
95            
96            if (isset($resultado['error'])) {
97                return response()->json($resultado, 429); // Too Many Requests
98            }
99            
100            $request->merge(['rut_validado' => $resultado]);
101        }
102        
103        return $next($request);
104    }
105}
106?>

Conclusión

PHP ofrece una implementación robusta y eficiente para la validación de RUTs chilenos. Las soluciones presentadas cubren desde scripts simples hasta integraciones empresariales complejas:

  • Funciones básicas: Para validaciones rápidas y scripts simples
  • Clases OOP: Para aplicaciones estructuradas y reutilizables
  • Integraciones con frameworks: Laravel y Symfony para aplicaciones modernas
  • APIs REST: Para servicios web escalables
  • Procesamiento masivo: Para manejar grandes volúmenes de datos
  • Seguridad: Implementaciones seguras para producción

La clave está en elegir la implementación adecuada según tus necesidades, siempre manteniendo las mejores prácticas de seguridad y rendimiento.

Recursos adicionales

  • PHP.net: Documentación oficial del lenguaje
  • Packagist: Busca paquetes como freshwork/chilean-bundle
  • GitHub: Repositorios con implementaciones de RUT para PHP
  • Comunidad PHP Chile: Foros y grupos de desarrolladores chilenos
  • Desarrollo
  • PHP
  • RUT
  • programación
  • validación
  • backend
Compartir

Escrito por

Catalina Fuentes

Desarrolladora backend

Programadora backend con amor por Python y el código limpio. Practica yoga y es mentora en comunidades tech.

2 artículos de Catalina