$ cat validar-iban-espanol-php-javascript.md

PHP

Validar IBAN español en PHP y JavaScript

12 Nov 2026 · 6 min de lectura

Validar IBAN español en un formulario evita guardar cuentas con un número de más o de menos, y es fácil: un IBAN lleva dos dígitos de control que permiten detectar casi todos los errores de tecleo sin consultar a ningún banco. Aquí tienes las funciones en PHP y en JavaScript, listas para copiar.

Cómo es un IBAN español

Un IBAN español tiene siempre 24 caracteres: las letras ES, dos dígitos de control y los 20 dígitos de la cuenta (el antiguo CCC).

ES91 2100 0418 4502 0005 1332
  • ES: código del país.
  • 91: dígitos de control del IBAN.
  • 2100: entidad (banco).
  • 0418: oficina.
  • 45: dígitos de control de la cuenta.
  • 0200051332: número de cuenta.

El IBAN se suele escribir en grupos de cuatro, pero al validarlo hay que ignorar los espacios y aceptar minúsculas.

Cómo se valida

El algoritmo es el mismo para todos los países (módulo 97) y tiene cuatro pasos:

  1. Quitar espacios, pasar a mayúsculas y comprobar el formato: ES seguido de 22 dígitos.
  2. Mover los cuatro primeros caracteres (ES91) al final.
  3. Sustituir cada letra por un número (A = 10, B = 11 … Z = 35). La E pasa a ser 14 y la S 28.
  4. Dividir el número resultante entre 97. Si el resto es 1, el IBAN es válido.

El número tiene unas 26 cifras y no cabe en un entero de PHP ni en un Number de JavaScript, así que el resto se calcula por trozos: se va dividiendo de siete en siete cifras arrastrando el resto anterior.

Validar IBAN español en PHP

/**
 * Validar un IBAN español (formato y dígitos de control)
 *
 * @param string $iban IBAN con o sin espacios, en mayúsculas o minúsculas
 *
 * @return bool true si es un IBAN español válido
 */
function validarIbanEs($iban) {
    $iban = strtoupper(preg_replace('/\s+/', '', $iban));

    // ES + 2 dígitos de control + 20 dígitos de la cuenta = 24 caracteres
    if (!preg_match('/^ES\d{22}$/', $iban)) {
        return false;
    }

    // Se pasan los 4 primeros caracteres al final y las letras a números (A=10 ... Z=35)
    $reordenado = substr($iban, 4) . substr($iban, 0, 4);
    $numerico = '';
    foreach (str_split($reordenado) as $c) {
        $numerico .= ctype_alpha($c) ? (string) (ord($c) - 55) : $c;
    }

    // Resto de dividir entre 97 por trozos (el número entero no cabe en un int de PHP)
    $resto = 0;
    foreach (str_split($numerico, 7) as $trozo) {
        $resto = (int) ($resto . $trozo) % 97;
    }

    return $resto === 1;
}

Uso:

<?php
var_dump(validarIbanEs('ES91 2100 0418 4502 0005 1332')); // bool(true)
var_dump(validarIbanEs('es9121000418450200051332'));      // bool(true), acepta minúsculas
var_dump(validarIbanEs('ES91 2100 0418 4502 0005 1333')); // bool(false), último dígito cambiado
var_dump(validarIbanEs('FR14 2004 1010 0505 0001 3M02 606')); // bool(false), no es español

Validar IBAN español en JavaScript

La misma lógica, para comprobarlo en el navegador antes de enviar el formulario:

/**
 * Validar un IBAN español (formato y dígitos de control)
 * @param {string} iban IBAN con o sin espacios
 * @returns {boolean} true si es un IBAN español válido
 */
function validarIbanEs(iban) {
  iban = String(iban).replace(/\s+/g, '').toUpperCase();

  // ES + 2 dígitos de control + 20 dígitos de la cuenta = 24 caracteres
  if (!/^ES\d{22}$/.test(iban)) {
    return false;
  }

  // Se pasan los 4 primeros caracteres al final y las letras a números (A=10 ... Z=35)
  const reordenado = iban.slice(4) + iban.slice(0, 4);
  const numerico = reordenado.replace(/[A-Z]/g, (c) => c.charCodeAt(0) - 55);

  // Resto de dividir entre 97 por trozos (el número entero no cabe en un Number)
  let resto = 0;
  for (let i = 0; i < numerico.length; i += 7) {
    resto = Number(String(resto) + numerico.slice(i, i + 7)) % 97;
  }

  return resto === 1;
}

Para avisar al usuario mientras escribe:

const campo = document.querySelector('#iban');
campo.addEventListener('blur', () => {
  campo.setCustomValidity(validarIbanEs(campo.value) ? '' : 'El IBAN no es válido');
  campo.reportValidity();
});

La comprobación del navegador sirve para ayudar al usuario, no para fiarse de ella: valida siempre también en el servidor, porque el formulario se puede saltar.

Comprobar también los dígitos de control de la cuenta (opcional)

Los dos dígitos del IBAN detectan errores de tecleo, pero la cuenta española lleva además sus propios dígitos de control (los dos de después de la oficina). Si quieres una segunda capa, esta función comprueba esos dos dígitos sobre los 20 dígitos de la cuenta, que son los que van después de ES y los dos primeros dígitos de control:

/**
 * Validar los dígitos de control de una cuenta bancaria española (CCC, 20 dígitos)
 * Formato: 4 de banco + 4 de oficina + 2 de control + 10 de cuenta
 *
 * @param string $ccc Los 20 dígitos, sin espacios
 *
 * @return bool true si los dos dígitos de control son correctos
 */
function validarCccEs($ccc) {
    if (!preg_match('/^\d{20}$/', $ccc)) {
        return false;
    }

    $pesos = array(1, 2, 4, 8, 5, 10, 9, 7, 3, 6);
    $digitoControl = function ($digitos) use ($pesos) {
        $suma = 0;
        foreach (str_split($digitos) as $i => $d) {
            $suma += $d * $pesos[$i];
        }
        $dc = 11 - ($suma % 11);
        return $dc === 11 ? 0 : ($dc === 10 ? 1 : $dc);
    };

    // Primer dígito: banco + oficina (con dos ceros delante); segundo: número de cuenta
    $dc1 = $digitoControl('00' . substr($ccc, 0, 8));
    $dc2 = $digitoControl(substr($ccc, 10, 10));

    return substr($ccc, 8, 2) === $dc1 . $dc2;
}

Se usa con el IBAN ya limpio, quitando ES y los dos dígitos de control del IBAN:

<?php
$iban = 'ES9121000418450200051332';
var_dump(validarIbanEs($iban) && validarCccEs(substr($iban, 4))); // bool(true)

Cosas que conviene saber

  • Validar no es comprobar que la cuenta existe. Un IBAN con los dígitos correctos puede no corresponder a ninguna cuenta abierta. Eso solo lo puede decir el banco.
  • Es un dato personal. Guarda el IBAN solo si lo necesitas, y en la base de datos con acceso restringido.
  • Para mostrarlo, puedes agruparlo de cuatro en cuatro con trim(chunk_split($iban, 4, ' ')). Para guardarlo, mejor sin espacios.
  • Otros países: esta función solo acepta IBAN españoles. El algoritmo del módulo 97 es el mismo para todos; lo que cambia es el país y la longitud. La estructura la define la norma ISO 13616, que resume la Wikipedia.

Si te interesa validar otros documentos españoles, mira cómo validar DNI, NIF, CIF y NIE en PHP.

Temas:

0 comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *