| 4 |
lars |
1 |
/**
|
|
|
2 |
* IBAN is the international bank account number.
|
|
|
3 |
* It has a country - specific format, that is checked here too
|
|
|
4 |
*
|
|
|
5 |
* Validation is case-insensitive. Please make sure to normalize input yourself.
|
|
|
6 |
*/
|
|
|
7 |
$.validator.addMethod( "iban", function( value, element ) {
|
|
|
8 |
|
|
|
9 |
// Some quick simple tests to prevent needless work
|
|
|
10 |
if ( this.optional( element ) ) {
|
|
|
11 |
return true;
|
|
|
12 |
}
|
|
|
13 |
|
|
|
14 |
// Remove spaces and to upper case
|
|
|
15 |
var iban = value.replace( / /g, "" ).toUpperCase(),
|
|
|
16 |
ibancheckdigits = "",
|
|
|
17 |
leadingZeroes = true,
|
|
|
18 |
cRest = "",
|
|
|
19 |
cOperator = "",
|
|
|
20 |
countrycode, ibancheck, charAt, cChar, bbanpattern, bbancountrypatterns, ibanregexp, i, p;
|
|
|
21 |
|
|
|
22 |
// Check for IBAN code length.
|
|
|
23 |
// It contains:
|
|
|
24 |
// country code ISO 3166-1 - two letters,
|
|
|
25 |
// two check digits,
|
|
|
26 |
// Basic Bank Account Number (BBAN) - up to 30 chars
|
|
|
27 |
var minimalIBANlength = 5;
|
|
|
28 |
if ( iban.length < minimalIBANlength ) {
|
|
|
29 |
return false;
|
|
|
30 |
}
|
|
|
31 |
|
|
|
32 |
// Check the country code and find the country specific format
|
|
|
33 |
countrycode = iban.substring( 0, 2 );
|
|
|
34 |
bbancountrypatterns = {
|
|
|
35 |
"AL": "\\d{8}[\\dA-Z]{16}",
|
|
|
36 |
"AD": "\\d{8}[\\dA-Z]{12}",
|
|
|
37 |
"AT": "\\d{16}",
|
|
|
38 |
"AZ": "[\\dA-Z]{4}\\d{20}",
|
|
|
39 |
"BE": "\\d{12}",
|
|
|
40 |
"BH": "[A-Z]{4}[\\dA-Z]{14}",
|
|
|
41 |
"BA": "\\d{16}",
|
|
|
42 |
"BR": "\\d{23}[A-Z][\\dA-Z]",
|
|
|
43 |
"BG": "[A-Z]{4}\\d{6}[\\dA-Z]{8}",
|
|
|
44 |
"CR": "\\d{17}",
|
|
|
45 |
"HR": "\\d{17}",
|
|
|
46 |
"CY": "\\d{8}[\\dA-Z]{16}",
|
|
|
47 |
"CZ": "\\d{20}",
|
|
|
48 |
"DK": "\\d{14}",
|
|
|
49 |
"DO": "[A-Z]{4}\\d{20}",
|
|
|
50 |
"EE": "\\d{16}",
|
|
|
51 |
"FO": "\\d{14}",
|
|
|
52 |
"FI": "\\d{14}",
|
|
|
53 |
"FR": "\\d{10}[\\dA-Z]{11}\\d{2}",
|
|
|
54 |
"GE": "[\\dA-Z]{2}\\d{16}",
|
|
|
55 |
"DE": "\\d{18}",
|
|
|
56 |
"GI": "[A-Z]{4}[\\dA-Z]{15}",
|
|
|
57 |
"GR": "\\d{7}[\\dA-Z]{16}",
|
|
|
58 |
"GL": "\\d{14}",
|
|
|
59 |
"GT": "[\\dA-Z]{4}[\\dA-Z]{20}",
|
|
|
60 |
"HU": "\\d{24}",
|
|
|
61 |
"IS": "\\d{22}",
|
|
|
62 |
"IE": "[\\dA-Z]{4}\\d{14}",
|
|
|
63 |
"IL": "\\d{19}",
|
|
|
64 |
"IT": "[A-Z]\\d{10}[\\dA-Z]{12}",
|
|
|
65 |
"KZ": "\\d{3}[\\dA-Z]{13}",
|
|
|
66 |
"KW": "[A-Z]{4}[\\dA-Z]{22}",
|
|
|
67 |
"LV": "[A-Z]{4}[\\dA-Z]{13}",
|
|
|
68 |
"LB": "\\d{4}[\\dA-Z]{20}",
|
|
|
69 |
"LI": "\\d{5}[\\dA-Z]{12}",
|
|
|
70 |
"LT": "\\d{16}",
|
|
|
71 |
"LU": "\\d{3}[\\dA-Z]{13}",
|
|
|
72 |
"MK": "\\d{3}[\\dA-Z]{10}\\d{2}",
|
|
|
73 |
"MT": "[A-Z]{4}\\d{5}[\\dA-Z]{18}",
|
|
|
74 |
"MR": "\\d{23}",
|
|
|
75 |
"MU": "[A-Z]{4}\\d{19}[A-Z]{3}",
|
|
|
76 |
"MC": "\\d{10}[\\dA-Z]{11}\\d{2}",
|
|
|
77 |
"MD": "[\\dA-Z]{2}\\d{18}",
|
|
|
78 |
"ME": "\\d{18}",
|
|
|
79 |
"NL": "[A-Z]{4}\\d{10}",
|
|
|
80 |
"NO": "\\d{11}",
|
|
|
81 |
"PK": "[\\dA-Z]{4}\\d{16}",
|
|
|
82 |
"PS": "[\\dA-Z]{4}\\d{21}",
|
|
|
83 |
"PL": "\\d{24}",
|
|
|
84 |
"PT": "\\d{21}",
|
|
|
85 |
"RO": "[A-Z]{4}[\\dA-Z]{16}",
|
|
|
86 |
"SM": "[A-Z]\\d{10}[\\dA-Z]{12}",
|
|
|
87 |
"SA": "\\d{2}[\\dA-Z]{18}",
|
|
|
88 |
"RS": "\\d{18}",
|
|
|
89 |
"SK": "\\d{20}",
|
|
|
90 |
"SI": "\\d{15}",
|
|
|
91 |
"ES": "\\d{20}",
|
|
|
92 |
"SE": "\\d{20}",
|
|
|
93 |
"CH": "\\d{5}[\\dA-Z]{12}",
|
|
|
94 |
"TN": "\\d{20}",
|
|
|
95 |
"TR": "\\d{5}[\\dA-Z]{17}",
|
|
|
96 |
"AE": "\\d{3}\\d{16}",
|
|
|
97 |
"GB": "[A-Z]{4}\\d{14}",
|
|
|
98 |
"VG": "[\\dA-Z]{4}\\d{16}"
|
|
|
99 |
};
|
|
|
100 |
|
|
|
101 |
bbanpattern = bbancountrypatterns[ countrycode ];
|
|
|
102 |
|
|
|
103 |
// As new countries will start using IBAN in the
|
|
|
104 |
// future, we only check if the countrycode is known.
|
|
|
105 |
// This prevents false negatives, while almost all
|
|
|
106 |
// false positives introduced by this, will be caught
|
|
|
107 |
// by the checksum validation below anyway.
|
|
|
108 |
// Strict checking should return FALSE for unknown
|
|
|
109 |
// countries.
|
|
|
110 |
if ( typeof bbanpattern !== "undefined" ) {
|
|
|
111 |
ibanregexp = new RegExp( "^[A-Z]{2}\\d{2}" + bbanpattern + "$", "" );
|
|
|
112 |
if ( !( ibanregexp.test( iban ) ) ) {
|
|
|
113 |
return false; // Invalid country specific format
|
|
|
114 |
}
|
|
|
115 |
}
|
|
|
116 |
|
|
|
117 |
// Now check the checksum, first convert to digits
|
|
|
118 |
ibancheck = iban.substring( 4, iban.length ) + iban.substring( 0, 4 );
|
|
|
119 |
for ( i = 0; i < ibancheck.length; i++ ) {
|
|
|
120 |
charAt = ibancheck.charAt( i );
|
|
|
121 |
if ( charAt !== "0" ) {
|
|
|
122 |
leadingZeroes = false;
|
|
|
123 |
}
|
|
|
124 |
if ( !leadingZeroes ) {
|
|
|
125 |
ibancheckdigits += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf( charAt );
|
|
|
126 |
}
|
|
|
127 |
}
|
|
|
128 |
|
|
|
129 |
// Calculate the result of: ibancheckdigits % 97
|
|
|
130 |
for ( p = 0; p < ibancheckdigits.length; p++ ) {
|
|
|
131 |
cChar = ibancheckdigits.charAt( p );
|
|
|
132 |
cOperator = "" + cRest + "" + cChar;
|
|
|
133 |
cRest = cOperator % 97;
|
|
|
134 |
}
|
|
|
135 |
return cRest === 1;
|
|
|
136 |
}, "Please specify a valid IBAN" );
|