Tento článek patří do seriálu Práce s čísly účtů. Ostatní články seriálu:
- Jak poznat správné číslo účtu
- Generování a kontrola IBANu pro CZ i SK účty
Každý určitě někdy opisoval nějaké číslo účtu a nebyl si jist, jestli to udělal dobře. Má tu být 0 nebo 8? Přitom je to velmi jednoduché zjistit. Právě pro zamezení těchto překlepů musí číslo účtu splňovat jistá kritéria, podobně jako je tomu u rodného čísla. Jen je to trochu sofistikovanější a složitější.
Klíčem je modulo 11 - neboli zbytek po dělení
Aby bylo rodné číslo platné, musí součet všech jeho číslic být dělitelný 11 beze zbytku (existuje výjimka viz Wiki). Součet všech číslic čísla účtu musí být rovněž dělitelný 11 beze zbytku. Aby se ale zamezilo chybě při prohození číslic, je ještě každá číslice přenásobena koeficientem podle svého umístění. Ty jsou definovány ve Vyhlášce č. 169/2011 Sb., kterou lze nalézt na stránkách ČNB.cz.
Číslo účtu se skládá z nepovinné první části o maximální délce 6 číslic (předčíslí) a druhé povinné části o délce 2 až 10 číslic. Úvodní nuly v kterékoli části nemají žádný význam a mohou být doplněny či odebrány. Následuje lomítko a 4místný kód banky.
Protože čísla účtu byla zaváděna ještě v dobách ČSR, stejná pravidla pro validaci platí jak v Česku tak na Slovensku. Kód lze tedy použít i pro validaci slovenských čísel účtů.
Kontrola první a druhé části čísla účtu
Každá část se kontroluje zvlášť ale shodným postupem. V prvním kroku je pro přehlednost dobré doplnit každou část nulami zleva až do celkové délky 10 číselných znaků. Poté každou číslici přenásobit koeficientem na shodné pozici viz tabulka níže a vše sečíst. Výsledek musí být dělitelný 11 beze zbytku. Jednotlivé pozice se číslují zprava. Protože ale v příkladě níže se vždy číslo doplní nulami až do délky 10 znaků, příliš na tom nezáleží.
Příklad
Číslo účtu Lékařů bez hranic (k 9.1.2019) je 111333/2700. Po doplnění 0 zleva a přenásobením koeficienty bude výpočet vypadat takto:
0*6 + 0*3 + 0*7 +0*9 + 1*10 + 1*5 + 1*8 + 3*4 + 3*2 + 3*1 = 44
44 dělitelné beze zbytku 11 je, takže číslo je správné.
Pro číslo účtu 86-199488014 by validace vypadala následovně
Předčíslí: 0*6 + 0*3 + 0*7 +0*9 + 0*10 + 0*5 + 0*8 + 0*4 + 8*2 + 6*1 = 22
Hl. číslo: 0*6 + 1*3 + 9*7 + 9*9 + 4*10 + 8*5 + 8*8 + 0*4 + 1*2 + 4*1 = 297
Jak 22 tak 297 je dělitelné beze zbytku, takže číslo je také platné. I když neexistuje.
Kontrola kódu banky
Kód banky lze kontrolovat jedině tak, že se ze stránek ČNB stáhne celý číselník možných hodnot. Nejedná se o nic složitého. Je ale nutné pravidelně kontrolovat, jestli nepřibyla nová banka a tím i nový kód, nebo jen stará banka svůj kód nezměnila.
PHP funkce pro kontrolu
Kontrolu v jazyce PHP lze provést následovně. Prvně probíhá kontrola správného tvaru pomocí regulárního výrazu, až poté kontrola správnosti jednotlivých částí. V ukázce se kódy bank validují pouze na přítomnost 4 číslic, nikoli na existující kombinaci.
function isValidBankAccount($accNumber) { $matches = []; if (!preg_match('/^(?:([0-9]{1,6})-)?([0-9]{2,10})\/([0-9]{4})$/', $accNumber, $matches)) { return false; } $weights = [6, 3, 7, 9, 10, 5, 8, 4, 2, 1]; $prefix = str_pad($matches[1], 10, '0', STR_PAD_LEFT); $main = str_pad($matches[2], 10, '0', STR_PAD_LEFT); // Check prefix $checkSum = 0; for ($i=0; $i < strlen($prefix); $i++) { $checkSum += $weights[$i] * (int)$prefix[$i]; } if ($checkSum % 11 !== 0) { return false; } // Check main part $checkSum = 0; for ($i=0; $i < strlen($main); $i++) { $checkSum += $weights[$i] * (int)$main[$i]; } if ($checkSum % 11 !== 0) { return false; } return true; }
Zkušenosti s čísly účtů můžete sdílet v komentářích. Obrázky přejaty z Freepik a Unsplash
K tomuto článku již není možné přidávat další komentáře
Komentáře
Nefunguje. Zkusil jsem dve sva existujici ceska cisla uctu; s kodem banky i bez nej, a vzdy to hodi false.
Zkusil jsem i pridat uvodni nuly,aby souhlasil pocet, take nepomohlo.
At delam, co delam, fce porad haze false, prestoze jde o skutecna cisla uctu.
V textu jsem nepochopil, co mela znamenat veta "V ukázce se kódy bank validují pouze na 4 číslice".
Zkusil jsem 5 čísel (mých, firemních apod.) včetně zmíněného čísla Lékařů bez hranic. U všech mi to vrátilo true. Takže chyba bude jinde.
var_dump(isValidBankAccount('199488014/0300')); // mé již nefunkční č.ú.
var_dump(isValidBankAccount('111333/2700')); // Lékaři bez hranic
To co prezentujete výše je pouze podmínka nutná, nikoli postačující.
Měl jsem trochu jiný use case - chtěl jsem vygenerovat nějaké validní číslo. Ale i když moje nalezená čísla byla Modulo 11 validní, tak je stále validátor od ČNB odmítal. Pak jsem zjistil, že je tam ještě další kontrolní součet. Viz odkaz, který jsem připojil
To co popisujete ve zmíněném článku je spíše kontrola IBANu než českého čísla účtu, což jsem také popsal v článku https://www.kutac.cz/pocitace-a-internety/generovani-a-kontrola-ibanu-pro-cz-i-sk-ucty .
Modulo 11 je tedy nutná a postačující podmínka.
Děkuji za vysvětlení. Myslel jsem si že to celé CZXX je konstanta, a proto mě ani nenapadlo, že kontrolní součet je na úrovni IBANu.