*/ private const array LENGTHS = [ 'AD' => 24, 'AT' => 20, 'BE' => 16, 'BG' => 22, 'CH' => 21, 'CY' => 28, 'CZ' => 24, 'DE' => 22, 'DK' => 18, 'EE' => 20, 'ES' => 24, 'FI' => 18, 'FR' => 27, 'GB' => 22, 'GI' => 23, 'GR' => 27, 'HR' => 21, 'HU' => 28, 'IE' => 22, 'IS' => 26, 'IT' => 27, 'LI' => 21, 'LT' => 20, 'LU' => 20, 'LV' => 21, 'MC' => 27, 'MT' => 31, 'NL' => 18, 'NO' => 15, 'PL' => 28, 'PT' => 25, 'RO' => 24, 'SE' => 24, 'SI' => 19, 'SK' => 24, 'SM' => 27, 'VA' => 22, ]; /** Leerzeichen raus, Großbuchstaben -- die kanonische Form, die gespeichert wird. */ public static function normalize(string $iban): string { return strtoupper(preg_replace('/\s+/', '', $iban) ?? ''); } public static function isValid(string $iban): bool { $iban = self::normalize($iban); if (preg_match('/^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$/', $iban) !== 1) { return false; } $expected = self::LENGTHS[substr($iban, 0, 2)] ?? null; if ($expected !== null && strlen($iban) !== $expected) { return false; } return self::checksum($iban) === 1; } /** In Vierergruppen -- die Schreibweise auf Belegen und Formularen. */ public static function format(string $iban): string { return trim(chunk_split(self::normalize($iban), 4, ' ')); } /** * Mod 97-10: die ersten vier Zeichen ans Ende, Buchstaben durch ihre Position + 9 ersetzen * (A = 10 … Z = 35), das Ergebnis modulo 97. Eine gültige IBAN ergibt 1. * * Der Rest wird stellenweise fortgeschrieben, weil die Zahl sonst jeden Integer sprengt. */ private static function checksum(string $iban): int { $rearranged = substr($iban, 4) . substr($iban, 0, 4); $remainder = 0; foreach (str_split($rearranged) as $char) { $value = ctype_digit($char) ? $char : (string) (ord($char) - 55); foreach (str_split($value) as $digit) { $remainder = ($remainder * 10 + (int) $digit) % 97; } } return $remainder; } }