Generování a kontrola IBANu pro CZ i SK účty

PHP, Tipy & triky

Vše, co jste o IBAN chtěli vědět. Co to je, jak lze zkontrolovat jeho správnost, jak ho lze generovat z běžných čísel účtů v Česku i na Slovensku, nebo jak z IBANu získat zpět běžné číslo účtu.

Generování a kontrola IBANu pro CZ i SK účty

Tento článek patří do seriálu Práce s čísly účtů. Ostatní články seriálu:

  1. Jak poznat správné číslo účtu
  2. Generování a kontrola IBANu pro CZ i SK účty

TL;DR Pokud vás zajímá pouze validace IBANu, použijte knihovnu PHP-IBAN. Ta ale neumí převádět běžná čísla českých a slovenských účtů na IBAN. Umí ale validovat IBAN všech zemí.

IBAN, z anglického International Bank Account Number, je mezinárodně dohodnutý systém pro identifikaci bankovních účtů. Původně vznikl pro potřeby Evropské Unie, nyní je ale rozšířen i do dalších zemí za hranice Evropy.

Formát a validace

Základní formát IBANu je v zásadě jednoduchý. Začíná 2 písmenným kódem země a dvojicí kontrolních číslic. Následuje část, která se skládá z alfanumerických znaků v maximální délce 30 znaků. Každá země si může určit vlastní formát, vždy ale musí být pevné délky. V Česku i na Slovensku to je 20 znaků, které začínají čtyřmístným kódem banky, následuje předčíslí a poté číslo účtu. Vždy doplněno nulami do délky 6 a 10 znaků. Celý IBAN má tedy délku 24 znaků.

Pro validaci se přesunou první 4 znaky (kód země a kontrolní číslice) na konec, znaky abecedy se přepíšou na čísla tak, že A -> 10, B -> 11 ... Z -> 35. Poté se vypočte z tohoto velkého čísla zbytek po dělení 97, který se musí rovnat 1. Protože celé číslo se rozhodně nevleze do datového typu int, je potřeba použít algoritmus založený na modulární aritmetice. Ukázka je níže.

Programový přístup – Kontrola

Pro kontrolu českého nebo slovenského IBANu lze použít kód níže. V PHP existuje rozšíření BC Math, které dokáže pracovat i s extrémně velkými čísly. A obsahuje funkci bcmod(), která je v případě IBANu potřeba k výpočtu zbytku po dělení. V ukázce je ale i případná náhrada.

function replaceCharacters(string $toReplace): string {
    return str_replace(range('A', 'Z'), range(10, 35), $toReplace);
}

function validateIBAN(string $iban): bool {
    $iban = strtoupper($iban);
    if (!preg_match('/^((?:CZ|SK)[0-9]{2})([0-9]{20})$/', $iban, $matches)) {
        return false;
    }
    $rearrangeToNumber = replaceCharacters($matches[2].$matches[1]);
    return bcmod($rearrangeToNumber, '97') === '1'; // Vraci string
}

// Funkci bcmod() lze nahradit touto funkcí, pokud BCMath rozšíření není dostupné
// nebo pokud se kód přepisuje do jiného jazyka
function moduloHugeNumber(string $number, int $modulus): int {
    $remainder = 0;
    for ($i = 0; $i < strlen($number); $i++) {
        $remainder = ($remainder * 10 + ($number[$i] - '0')) % $modulus;
    }
    return $remainder;
}

Regulární výraz lze nahradit za /^([A-Z]{2}[0-9]{2})([0-9A-Z]{11,30})$/ pro kontrolu správnosti IBANu i pro jiné země. Zde ale POZOR, již není kontrolována správná délka nebo kód země. Pouze správně vypočtené kontrolní číslo! Pro opravdovou kontrolu se všemi pravidly každé země je potřeba použít vhodnou knihovnu. Například PHP-IBAN.

Převody z/na národní čísla

Funkce níže dokáží převést české i slovenské národní číslo účtu na IBAN a obráceně. Při výpočtu jsou použity funkce validateIBAN() a replaceCharacters() z ukázky výše a také isValidBankAccount() z předešlého článku Jak poznat správné číslo účtu.

Pokud je IBAN validní, neznamená to, že výsledné číslo účtu je také validní! IBAN v záhlaví je validní, ale číslo účtu v něm obsažené již ne. Kód banky neexistuje a jednotlivé části také nemohou existovat, viz předchozí článek o správném čísle účtu.

function ibanToNationalNumber(string $iban): ?string {
    if (!validateIBAN($iban) || !preg_match('/^(?:CZ|SK)[0-9]{2}([0-9]{4})([0-9]{6})([0-9]{10})$/', $iban, $matches)) {
        return null;
    }
    $prefix = ltrim($matches[2], '0');
    return ($prefix ? $prefix.'-' : '').ltrim($matches[3], '0').'/'.$matches[1];
}

function nationalNumberToIban(string $accNumber, string $countryCode = 'CZ'): ?string {
    if(!isValidBankAccount($accNumber)
        || !in_array($countryCode, ['CZ', 'SK'])
        || !preg_match('/^(?:([0-9]{2,6})-)?([0-9]{2,10})\/([0-9]{4})$/', $accNumber, $matches)
    ) {
        return null;
    }
    $bban = $matches[3].str_pad($matches[1], 6, '0', STR_PAD_LEFT).str_pad($matches[2], 10, '0', STR_PAD_LEFT);
    $remainder = (int)bcmod(replaceCharacters("{$bban}{$countryCode}00"), '97');
    $controllNumber = str_pad((string)(98 - $remainder), 2, '0', STR_PAD_LEFT);
return "{$countryCode}{$controllNumber}{$bban}"; }

Pár dalších informací navíc o IBANu


Zkušenosti s IBAN nebo čísly účtu můžete sdílet v komentářích.

K tomuto článku již není možné přidávat další komentáře