/**
* IBAN is the international bank account number.
* It has a country - specific format, that is checked here too
*
* Validation is case-insensitive. Please make sure to normalize input yourself.
*/
$.validator.addMethod( "iban", function( value, element ) {
// Some quick simple tests to prevent needless work
if ( this.optional( element ) ) {
return true;
}
// Remove spaces and to upper case
var iban = value.replace( / /g, "" ).toUpperCase(),
ibancheckdigits = "",
leadingZeroes = true,
cRest = "",
cOperator = "",
countrycode, ibancheck, charAt, cChar, bbanpattern, bbancountrypatterns, ibanregexp, i, p;
// Check for IBAN code length.
// It contains:
// country code ISO 3166-1 - two letters,
// two check digits,
// Basic Bank Account Number (BBAN) - up to 30 chars
var minimalIBANlength = 5;
if ( iban.length < minimalIBANlength ) {
return false;
}
// Check the country code and find the country specific format
countrycode = iban.substring( 0, 2 );
bbancountrypatterns = {
"AL": "\\d{8}[\\dA-Z]{16}",
"AD": "\\d{8}[\\dA-Z]{12}",
"AT": "\\d{16}",
"AZ": "[\\dA-Z]{4}\\d{20}",
"BE": "\\d{12}",
"BH": "[A-Z]{4}[\\dA-Z]{14}",
"BA": "\\d{16}",
"BR": "\\d{23}[A-Z][\\dA-Z]",
"BG": "[A-Z]{4}\\d{6}[\\dA-Z]{8}",
"CR": "\\d{17}",
"HR": "\\d{17}",
"CY": "\\d{8}[\\dA-Z]{16}",
"CZ": "\\d{20}",
"DK": "\\d{14}",
"DO": "[A-Z]{4}\\d{20}",
"EE": "\\d{16}",
"FO": "\\d{14}",
"FI": "\\d{14}",
"FR": "\\d{10}[\\dA-Z]{11}\\d{2}",
"GE": "[\\dA-Z]{2}\\d{16}",
"DE": "\\d{18}",
"GI": "[A-Z]{4}[\\dA-Z]{15}",
"GR": "\\d{7}[\\dA-Z]{16}",
"GL": "\\d{14}",
"GT": "[\\dA-Z]{4}[\\dA-Z]{20}",
"HU": "\\d{24}",
"IS": "\\d{22}",
"IE": "[\\dA-Z]{4}\\d{14}",
"IL": "\\d{19}",
"IT": "[A-Z]\\d{10}[\\dA-Z]{12}",
"KZ": "\\d{3}[\\dA-Z]{13}",
"KW": "[A-Z]{4}[\\dA-Z]{22}",
"LV": "[A-Z]{4}[\\dA-Z]{13}",
"LB": "\\d{4}[\\dA-Z]{20}",
"LI": "\\d{5}[\\dA-Z]{12}",
"LT": "\\d{16}",
"LU": "\\d{3}[\\dA-Z]{13}",
"MK": "\\d{3}[\\dA-Z]{10}\\d{2}",
"MT": "[A-Z]{4}\\d{5}[\\dA-Z]{18}",
"MR": "\\d{23}",
"MU": "[A-Z]{4}\\d{19}[A-Z]{3}",
"MC": "\\d{10}[\\dA-Z]{11}\\d{2}",
"MD": "[\\dA-Z]{2}\\d{18}",
"ME": "\\d{18}",
"NL": "[A-Z]{4}\\d{10}",
"NO": "\\d{11}",
"PK": "[\\dA-Z]{4}\\d{16}",
"PS": "[\\dA-Z]{4}\\d{21}",
"PL": "\\d{24}",
"PT": "\\d{21}",
"RO": "[A-Z]{4}[\\dA-Z]{16}",
"SM": "[A-Z]\\d{10}[\\dA-Z]{12}",
"SA": "\\d{2}[\\dA-Z]{18}",
"RS": "\\d{18}",
"SK": "\\d{20}",
"SI": "\\d{15}",
"ES": "\\d{20}",
"SE": "\\d{20}",
"CH": "\\d{5}[\\dA-Z]{12}",
"TN": "\\d{20}",
"TR": "\\d{5}[\\dA-Z]{17}",
"AE": "\\d{3}\\d{16}",
"GB": "[A-Z]{4}\\d{14}",
"VG": "[\\dA-Z]{4}\\d{16}"
};
bbanpattern = bbancountrypatterns[ countrycode ];
// As new countries will start using IBAN in the
// future, we only check if the countrycode is known.
// This prevents false negatives, while almost all
// false positives introduced by this, will be caught
// by the checksum validation below anyway.
// Strict checking should return FALSE for unknown
// countries.
if ( typeof bbanpattern !== "undefined" ) {
ibanregexp = new RegExp( "^[A-Z]{2}\\d{2}" + bbanpattern + "$", "" );
if ( !( ibanregexp.test( iban ) ) ) {
return false; // Invalid country specific format
}
}
// Now check the checksum, first convert to digits
ibancheck = iban.substring( 4, iban.length ) + iban.substring( 0, 4 );
for ( i = 0; i < ibancheck.length; i++ ) {
charAt = ibancheck.charAt( i );
if ( charAt !== "0" ) {
leadingZeroes = false;
}
if ( !leadingZeroes ) {
ibancheckdigits += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf( charAt );
}
}
// Calculate the result of: ibancheckdigits % 97
for ( p = 0; p < ibancheckdigits.length; p++ ) {
cChar = ibancheckdigits.charAt( p );
cOperator = "" + cRest + "" + cChar;
cRest = cOperator % 97;
}
return cRest === 1;
}, "Please specify a valid IBAN" );
|