Bernd Wurst commited on 2013-12-20 19:13:16
Zeige 23 geänderte Dateien mit 2074 Einfügungen und 1 Löschungen.
... | ... |
@@ -0,0 +1 @@ |
1 |
+1.4.0 |
... | ... |
@@ -0,0 +1,35 @@ |
1 |
+This file lists specific errors observed in the official IBAN specification. |
|
2 |
+ |
|
3 |
+In addition to the specific errors, there persist basic outstanding |
|
4 |
+matters that cause issue for implementers: |
|
5 |
+ - Non 1:1 mapping of records to countries (eg: French territories, etc.) |
|
6 |
+ - Mixing of free text and hard data in specification fields |
|
7 |
+ - Lack of validation of information in fields prior to publishing |
|
8 |
+ - Lack of synchronisation between TXT and PDF versions of the registry |
|
9 |
+ |
|
10 |
+2011-07-16 |
|
11 |
+---------- |
|
12 |
+ - No information for Kuwait past sixth column |
|
13 |
+ - Total absence of information regarding Kazakhstan |
|
14 |
+ - '1.00001E+15' instead of a valid BBAN example for Lithuania |
|
15 |
+ - Repeated IBAN example in human format instead of IBAN format- |
|
16 |
+ specification for UAE |
|
17 |
+ - Incorrect domestic example for Bulgaria, Kazakhstan, Latvia, |
|
18 |
+ Lithuania, Luxembourg, Macedonia, Mauritius, Romania, San Marino |
|
19 |
+ (complete, human-format IBAN instead of domestic example) |
|
20 |
+ |
|
21 |
+Early 2012 |
|
22 |
+---------- |
|
23 |
+ - Inconsistent record ordering (KW, KZ) |
|
24 |
+ - Inconsistent capitalization (DK) |
|
25 |
+ - Continued presence of incorrect domestic examples |
|
26 |
+ |
|
27 |
+February 2013 |
|
28 |
+------------- |
|
29 |
+ - Deployment of unparseable special values such as "Not in use" (FI). |
|
30 |
+ - Still(!) missing a registry entry for 2010's 'new' entry of Khazakstan |
|
31 |
+ |
|
32 |
+September 2013 |
|
33 |
+-------------- |
|
34 |
+ - Azerbaijan, Brazil, Costa Rica, Palestine, Virgin Islands 'SEPA |
|
35 |
+ Country' field in PDF (yes/no) is completely blank |
... | ... |
@@ -0,0 +1,63 @@ |
1 |
+By unix tradition, this file outlines information that may be useful to |
|
2 |
+people who wish to modify the php-iban project. It outlines some basic |
|
3 |
+information around design decisions and other considerations. |
|
4 |
+ |
|
5 |
+ Procedural style |
|
6 |
+ ---------------- |
|
7 |
+ The code is written in PHP's original procedural style, and does |
|
8 |
+ not require or assume any OO model. This is unix tradition and |
|
9 |
+ should ease any integration pains due to objectspace mismatches. |
|
10 |
+ In addition, it should make it easy for users both within an OO |
|
11 |
+ or a procedural codebase to make use of the library. An OO wrapper |
|
12 |
+ has been supplied to make things more familiar for those who are |
|
13 |
+ only exposed to OO PHP: please try to keep it in synch with the |
|
14 |
+ procedural (main) library where possible. |
|
15 |
+ |
|
16 |
+ Registry maintenance |
|
17 |
+ -------------------- |
|
18 |
+ The 'convert-registry.php' tool found in the 'utils/' subdirectory |
|
19 |
+ is intended to assist with the automatic conversion of the SWIFT- |
|
20 |
+ provided 'IBAN Registry' text files to the format required to |
|
21 |
+ support php-iban execution. Why is there a new format, and why is it |
|
22 |
+ distributed with php-iban instead of being generated on the fly |
|
23 |
+ from SWIFT-provided data files? There are a few reasons: |
|
24 |
+ |
|
25 |
+ - Error correction |
|
26 |
+ If errors are discovered in the official specification then they |
|
27 |
+ can be resolved by us. There are (or have been) known errors |
|
28 |
+ with the official IBAN Registry. (See COMEDY-OF-ERRORS) |
|
29 |
+ |
|
30 |
+ - Exclusion correction |
|
31 |
+ If exclusions are discovered in the official specification then |
|
32 |
+ they can be resolved by us. There are (or have been) known |
|
33 |
+ exclusions from the official IBAN Registry. (See COMEDY-OF-ERRORS) |
|
34 |
+ |
|
35 |
+ - Efficiency |
|
36 |
+ Because pattern matching is a core part of the functionality of |
|
37 |
+ php-iban, and the pattern algorithms distributed by SWIFT are |
|
38 |
+ (rather strangely) not in regular expression format, using their |
|
39 |
+ files directly would result in a fairly significant startup |
|
40 |
+ penalty as pattern conversion would be required (at each |
|
41 |
+ invocation!) unless a caching strategy were deployed, which would |
|
42 |
+ create additional complexity and sources of bugs (in addition, |
|
43 |
+ due to the previous two points automatic conversion is not |
|
44 |
+ presently possible ... and may never be!) |
|
45 |
+ |
|
46 |
+ - Maintainability |
|
47 |
+ Distribution of a modified registry along with php-iban places |
|
48 |
+ the burden of registry maintenance on with the package |
|
49 |
+ maintainer(s) rather than with the user. This is better for |
|
50 |
+ users who, if they really want, can still hack their local copy. |
|
51 |
+ |
|
52 |
+ Note that due to points one and two, the 'convert-registry.php' tool |
|
53 |
+ is insufficient to produce a correct 'registry.txt' file. (You may |
|
54 |
+ wish to review the differences between your newly generated file |
|
55 |
+ and the original with the 'diff' tool in order to ascertain what |
|
56 |
+ has changed.) |
|
57 |
+ |
|
58 |
+ A closing point on the registry: obviously, if any new fields are |
|
59 |
+ added, then it is best to append them to the end of the registry |
|
60 |
+ (rightmost, new field) in order to preserve backwards compatibility |
|
61 |
+ instead of re-ordering the fields which would break older installs. |
|
62 |
+ (The internal '_iban_load_registry()' function re-orders these fields |
|
63 |
+ at load time in order to simplify runtime debugging, anyway.) |
... | ... |
@@ -0,0 +1,165 @@ |
1 |
+ GNU LESSER GENERAL PUBLIC LICENSE |
|
2 |
+ Version 3, 29 June 2007 |
|
3 |
+ |
|
4 |
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
|
5 |
+ Everyone is permitted to copy and distribute verbatim copies |
|
6 |
+ of this license document, but changing it is not allowed. |
|
7 |
+ |
|
8 |
+ |
|
9 |
+ This version of the GNU Lesser General Public License incorporates |
|
10 |
+the terms and conditions of version 3 of the GNU General Public |
|
11 |
+License, supplemented by the additional permissions listed below. |
|
12 |
+ |
|
13 |
+ 0. Additional Definitions. |
|
14 |
+ |
|
15 |
+ As used herein, "this License" refers to version 3 of the GNU Lesser |
|
16 |
+General Public License, and the "GNU GPL" refers to version 3 of the GNU |
|
17 |
+General Public License. |
|
18 |
+ |
|
19 |
+ "The Library" refers to a covered work governed by this License, |
|
20 |
+other than an Application or a Combined Work as defined below. |
|
21 |
+ |
|
22 |
+ An "Application" is any work that makes use of an interface provided |
|
23 |
+by the Library, but which is not otherwise based on the Library. |
|
24 |
+Defining a subclass of a class defined by the Library is deemed a mode |
|
25 |
+of using an interface provided by the Library. |
|
26 |
+ |
|
27 |
+ A "Combined Work" is a work produced by combining or linking an |
|
28 |
+Application with the Library. The particular version of the Library |
|
29 |
+with which the Combined Work was made is also called the "Linked |
|
30 |
+Version". |
|
31 |
+ |
|
32 |
+ The "Minimal Corresponding Source" for a Combined Work means the |
|
33 |
+Corresponding Source for the Combined Work, excluding any source code |
|
34 |
+for portions of the Combined Work that, considered in isolation, are |
|
35 |
+based on the Application, and not on the Linked Version. |
|
36 |
+ |
|
37 |
+ The "Corresponding Application Code" for a Combined Work means the |
|
38 |
+object code and/or source code for the Application, including any data |
|
39 |
+and utility programs needed for reproducing the Combined Work from the |
|
40 |
+Application, but excluding the System Libraries of the Combined Work. |
|
41 |
+ |
|
42 |
+ 1. Exception to Section 3 of the GNU GPL. |
|
43 |
+ |
|
44 |
+ You may convey a covered work under sections 3 and 4 of this License |
|
45 |
+without being bound by section 3 of the GNU GPL. |
|
46 |
+ |
|
47 |
+ 2. Conveying Modified Versions. |
|
48 |
+ |
|
49 |
+ If you modify a copy of the Library, and, in your modifications, a |
|
50 |
+facility refers to a function or data to be supplied by an Application |
|
51 |
+that uses the facility (other than as an argument passed when the |
|
52 |
+facility is invoked), then you may convey a copy of the modified |
|
53 |
+version: |
|
54 |
+ |
|
55 |
+ a) under this License, provided that you make a good faith effort to |
|
56 |
+ ensure that, in the event an Application does not supply the |
|
57 |
+ function or data, the facility still operates, and performs |
|
58 |
+ whatever part of its purpose remains meaningful, or |
|
59 |
+ |
|
60 |
+ b) under the GNU GPL, with none of the additional permissions of |
|
61 |
+ this License applicable to that copy. |
|
62 |
+ |
|
63 |
+ 3. Object Code Incorporating Material from Library Header Files. |
|
64 |
+ |
|
65 |
+ The object code form of an Application may incorporate material from |
|
66 |
+a header file that is part of the Library. You may convey such object |
|
67 |
+code under terms of your choice, provided that, if the incorporated |
|
68 |
+material is not limited to numerical parameters, data structure |
|
69 |
+layouts and accessors, or small macros, inline functions and templates |
|
70 |
+(ten or fewer lines in length), you do both of the following: |
|
71 |
+ |
|
72 |
+ a) Give prominent notice with each copy of the object code that the |
|
73 |
+ Library is used in it and that the Library and its use are |
|
74 |
+ covered by this License. |
|
75 |
+ |
|
76 |
+ b) Accompany the object code with a copy of the GNU GPL and this license |
|
77 |
+ document. |
|
78 |
+ |
|
79 |
+ 4. Combined Works. |
|
80 |
+ |
|
81 |
+ You may convey a Combined Work under terms of your choice that, |
|
82 |
+taken together, effectively do not restrict modification of the |
|
83 |
+portions of the Library contained in the Combined Work and reverse |
|
84 |
+engineering for debugging such modifications, if you also do each of |
|
85 |
+the following: |
|
86 |
+ |
|
87 |
+ a) Give prominent notice with each copy of the Combined Work that |
|
88 |
+ the Library is used in it and that the Library and its use are |
|
89 |
+ covered by this License. |
|
90 |
+ |
|
91 |
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license |
|
92 |
+ document. |
|
93 |
+ |
|
94 |
+ c) For a Combined Work that displays copyright notices during |
|
95 |
+ execution, include the copyright notice for the Library among |
|
96 |
+ these notices, as well as a reference directing the user to the |
|
97 |
+ copies of the GNU GPL and this license document. |
|
98 |
+ |
|
99 |
+ d) Do one of the following: |
|
100 |
+ |
|
101 |
+ 0) Convey the Minimal Corresponding Source under the terms of this |
|
102 |
+ License, and the Corresponding Application Code in a form |
|
103 |
+ suitable for, and under terms that permit, the user to |
|
104 |
+ recombine or relink the Application with a modified version of |
|
105 |
+ the Linked Version to produce a modified Combined Work, in the |
|
106 |
+ manner specified by section 6 of the GNU GPL for conveying |
|
107 |
+ Corresponding Source. |
|
108 |
+ |
|
109 |
+ 1) Use a suitable shared library mechanism for linking with the |
|
110 |
+ Library. A suitable mechanism is one that (a) uses at run time |
|
111 |
+ a copy of the Library already present on the user's computer |
|
112 |
+ system, and (b) will operate properly with a modified version |
|
113 |
+ of the Library that is interface-compatible with the Linked |
|
114 |
+ Version. |
|
115 |
+ |
|
116 |
+ e) Provide Installation Information, but only if you would otherwise |
|
117 |
+ be required to provide such information under section 6 of the |
|
118 |
+ GNU GPL, and only to the extent that such information is |
|
119 |
+ necessary to install and execute a modified version of the |
|
120 |
+ Combined Work produced by recombining or relinking the |
|
121 |
+ Application with a modified version of the Linked Version. (If |
|
122 |
+ you use option 4d0, the Installation Information must accompany |
|
123 |
+ the Minimal Corresponding Source and Corresponding Application |
|
124 |
+ Code. If you use option 4d1, you must provide the Installation |
|
125 |
+ Information in the manner specified by section 6 of the GNU GPL |
|
126 |
+ for conveying Corresponding Source.) |
|
127 |
+ |
|
128 |
+ 5. Combined Libraries. |
|
129 |
+ |
|
130 |
+ You may place library facilities that are a work based on the |
|
131 |
+Library side by side in a single library together with other library |
|
132 |
+facilities that are not Applications and are not covered by this |
|
133 |
+License, and convey such a combined library under terms of your |
|
134 |
+choice, if you do both of the following: |
|
135 |
+ |
|
136 |
+ a) Accompany the combined library with a copy of the same work based |
|
137 |
+ on the Library, uncombined with any other library facilities, |
|
138 |
+ conveyed under the terms of this License. |
|
139 |
+ |
|
140 |
+ b) Give prominent notice with the combined library that part of it |
|
141 |
+ is a work based on the Library, and explaining where to find the |
|
142 |
+ accompanying uncombined form of the same work. |
|
143 |
+ |
|
144 |
+ 6. Revised Versions of the GNU Lesser General Public License. |
|
145 |
+ |
|
146 |
+ The Free Software Foundation may publish revised and/or new versions |
|
147 |
+of the GNU Lesser General Public License from time to time. Such new |
|
148 |
+versions will be similar in spirit to the present version, but may |
|
149 |
+differ in detail to address new problems or concerns. |
|
150 |
+ |
|
151 |
+ Each version is given a distinguishing version number. If the |
|
152 |
+Library as you received it specifies that a certain numbered version |
|
153 |
+of the GNU Lesser General Public License "or any later version" |
|
154 |
+applies to it, you have the option of following the terms and |
|
155 |
+conditions either of that published version or of any later version |
|
156 |
+published by the Free Software Foundation. If the Library as you |
|
157 |
+received it does not specify a version number of the GNU Lesser |
|
158 |
+General Public License, you may choose any version of the GNU Lesser |
|
159 |
+General Public License ever published by the Free Software Foundation. |
|
160 |
+ |
|
161 |
+ If the Library as you received it specifies that a proxy can decide |
|
162 |
+whether future versions of the GNU Lesser General Public License shall |
|
163 |
+apply, that proxy's public statement of acceptance of any version is |
|
164 |
+permanent authorization for you to choose that version for the |
|
165 |
+Library. |
... | ... |
@@ -0,0 +1,207 @@ |
1 |
+php-iban README |
|
2 |
+--------------- |
|
3 |
+ |
|
4 |
+php-iban is a library for parsing and validating International Bank |
|
5 |
+Account Number (IBAN) information in PHP. |
|
6 |
+ |
|
7 |
+It also validates Internet International Bank Account Number |
|
8 |
+(IIBAN) as specified at http://tools.ietf.org/html/draft-iiban-01 |
|
9 |
+(see also http://www.ifex-project.org/our-proposals/iiban) |
|
10 |
+ |
|
11 |
+php-iban lives at http://code.google.com/p/php-iban |
|
12 |
+ |
|
13 |
+ What is an IBAN? |
|
14 |
+ ---------------- |
|
15 |
+ An IBAN is basically a standardised way of explaining a bank |
|
16 |
+ account number that works across borders. Its structure is: |
|
17 |
+ |
|
18 |
+ <Two Letter ISO Country Code> + <Two Digit Checksum] + <BBAN> |
|
19 |
+ |
|
20 |
+ BBAN is the term used to describe the national-level format |
|
21 |
+ for a bank account number, which varies between countries |
|
22 |
+ (and was sometimes created just to get IBAN connectivity!). |
|
23 |
+ Note that a BBAN may have its own checksum algorithm. |
|
24 |
+ |
|
25 |
+ IBAN provides basic protection, using the checksum, against |
|
26 |
+ transcription (ie: human copying) errors. It also provides |
|
27 |
+ a registry of valid destination countries and their BBAN |
|
28 |
+ formats. Thus, when you ask php-iban to 'validate' an IBAN |
|
29 |
+ it ensures that these checks are passed. However, it cannot |
|
30 |
+ ensure that a bank account actually exists - the only party |
|
31 |
+ who can do that is the receiving bank or country. |
|
32 |
+ |
|
33 |
+ IBAN was invented in Europe, however its usage is growing |
|
34 |
+ rapidly to other parts of the world. Thus, the future of |
|
35 |
+ this library looks pretty good. |
|
36 |
+ |
|
37 |
+ For further information, please see 'docs/ISO13616.pdf' or |
|
38 |
+ visit Wikipedia at http://en.wikipedia.org/wiki/IBAN |
|
39 |
+ |
|
40 |
+ What is an IIBAN? |
|
41 |
+ ----------------- |
|
42 |
+ An Internet IBAN (IIBAN) identifies an internet-based financial |
|
43 |
+ endpoint in a manner that is superset-compatible with the existing |
|
44 |
+ European Committee for Banking Standards (ECBS) International Bank |
|
45 |
+ Account Number (IBAN) standard [ISO13616]. |
|
46 |
+ |
|
47 |
+ For more information see http://tools.ietf.org/html/draft-iiban-00 |
|
48 |
+ and http://www.ifex-project.org/our-proposals/iiban |
|
49 |
+ |
|
50 |
+ To disable IIBAN support from your installation, simply remove |
|
51 |
+ the second ('AA|...') line from the top of the registry.txt file. |
|
52 |
+ |
|
53 |
+ Execution environment |
|
54 |
+ --------------------- |
|
55 |
+ At present the library merely requires a PHP engine to be present |
|
56 |
+ and has no external dependencies. It is recommended that your |
|
57 |
+ PHP engine is configured to disable verbose warnings for events |
|
58 |
+ such as access of unknown array indexes, though this should be |
|
59 |
+ standard on almost any PHP deployment today. Any PHP engine |
|
60 |
+ in use today should be compatible, though PHP3 or PHP4 execution |
|
61 |
+ environments may require minor modifications (specifically, |
|
62 |
+ some string functions may have changed). |
|
63 |
+ |
|
64 |
+ Installation |
|
65 |
+ ------------ |
|
66 |
+ Simply copy 'php-iban.php' and 'registry.txt' to an appropriate |
|
67 |
+ location for your project. The location of the files will affect |
|
68 |
+ the 'require_once()' line used to load the library from your |
|
69 |
+ codebase, and may have relevance security (see 'Security' below). |
|
70 |
+ Note that 'php-iban.php' expects to find 'registry.txt' in the |
|
71 |
+ same directory as itself. |
|
72 |
+ |
|
73 |
+ Security |
|
74 |
+ -------- |
|
75 |
+ Following best practice for library files, the location chosen |
|
76 |
+ for the php-iban.php and registry.txt files should ideally be |
|
77 |
+ outside of any web-accessible directories. Thus, if your |
|
78 |
+ web project lives in /var/www/myproject/htdocs/ then it would |
|
79 |
+ be preferably to place php-iban in /var/www/myproject or some |
|
80 |
+ other directory that is not visible to regular web users. |
|
81 |
+ |
|
82 |
+ Secondly, neither file should be writable by the web server |
|
83 |
+ itself in order to prevent compromise of the execution path |
|
84 |
+ (ie: getting hacked). So, for example if your web server runs |
|
85 |
+ as user 'www', group 'www', you can ensure that the web server |
|
86 |
+ has minimal required privileges against the files as follows |
|
87 |
+ (note that you will need to be root to execute these commands): |
|
88 |
+ |
|
89 |
+ # chown <myuser> php-iban registry.txt # where <myuser> is a |
|
90 |
+ # non-root user that |
|
91 |
+ # is not 'www'. |
|
92 |
+ # chgrp www php-iban registry.txt # set group to 'www' |
|
93 |
+ # chmod ugo-rwx php-iban registry.txt # remove privileges |
|
94 |
+ # chmod g+r php-iban registry.txt # allow 'www' group |
|
95 |
+ # to read the files |
|
96 |
+ |
|
97 |
+ Obviously the above do not apply if you are using PHP in a |
|
98 |
+ non web-oriented project (eg: a cronjob or daemon), a usage |
|
99 |
+ of the language that is apparently growing - but limited. |
|
100 |
+ |
|
101 |
+ Using the library |
|
102 |
+ ----------------- |
|
103 |
+ Basic invocation is as follows: |
|
104 |
+ |
|
105 |
+ # include the library |
|
106 |
+ require_once('/path/to/php-iban.php'); # /path/to/ is optional |
|
107 |
+ |
|
108 |
+ # use some library function or other... |
|
109 |
+ if(!verify_iban($iban_to_verify)) { |
|
110 |
+ # blame the user... |
|
111 |
+ } |
|
112 |
+ |
|
113 |
+ Note that because the library is designed in a procedural manner |
|
114 |
+ rather than an object-oriented manner it should be easy to |
|
115 |
+ integrate with a wide variety of established codebases and |
|
116 |
+ PHP interpreter versions. |
|
117 |
+ |
|
118 |
+ Using the library's OO wrapper |
|
119 |
+ ------------------------------ |
|
120 |
+ Because many new PHP programmers seems to learn the language via |
|
121 |
+ books that only teach OO based programming and are thus unfamiliar |
|
122 |
+ with procedural PHP (and often relatively inexperienced as |
|
123 |
+ programmers, too) an OO wrapper-library has been provided. |
|
124 |
+ |
|
125 |
+ ======================= READ THIS ================================= |
|
126 |
+ However *you should avoid excessive use of OO*. For some thought |
|
127 |
+ provoking discussions of the negative aspects of overusing OO, |
|
128 |
+ please refer to 'Coders at Work' and 'The Art of UNIX Programming'. |
|
129 |
+ (OO is great for some problems, but simply pointless for most.) |
|
130 |
+ =================================================================== |
|
131 |
+ |
|
132 |
+ Anyway, to use the OO wrapper supplied, invocation is as follows: |
|
133 |
+ |
|
134 |
+ # include the OO wrapper to the library |
|
135 |
+ require_once('/path/to/oophp-iban.php'); # /path/to is optional |
|
136 |
+ |
|
137 |
+ # instantiate an IBAN object |
|
138 |
+ $myIban = new IBAN('AZ12345678901234'); |
|
139 |
+ if(!$myIban->Verify()) { |
|
140 |
+ # blame the user... |
|
141 |
+ } |
|
142 |
+ |
|
143 |
+ Documentation |
|
144 |
+ ------------- |
|
145 |
+ There are three types of functions provided by the library: |
|
146 |
+ |
|
147 |
+ - IBAN-level functions |
|
148 |
+ |
|
149 |
+ These are functions that operate on an IBAN. All of these |
|
150 |
+ functions accept either machine format or human format |
|
151 |
+ IBANs as input. Typically they return facts about an IBAN |
|
152 |
+ as their output (for example whether it is valid or not, |
|
153 |
+ or the BBAN (national-level) portion of the IBAN), though |
|
154 |
+ some of them may perform other functions (eg: fixing a |
|
155 |
+ broken IBAN checksum). These functions are named 'iban_*' |
|
156 |
+ with the exception of the most commonly used function, |
|
157 |
+ 'verify_iban()', and excepting the country-level functions. |
|
158 |
+ |
|
159 |
+ (Regarding the object oriented wrapper - all of these |
|
160 |
+ functions are implemented as methods on IBAN objects) |
|
161 |
+ |
|
162 |
+ - IBAN country-level functions |
|
163 |
+ These functions return information about countries that are |
|
164 |
+ part of the IBAN standard. They each take the two letter |
|
165 |
+ ISO country code at the beginning of an IBAN as their |
|
166 |
+ argument. They are named 'iban_country_*', with the |
|
167 |
+ exception of 'iban_countries()' which returns a list of |
|
168 |
+ the known IBAN countries. (For example, functions that |
|
169 |
+ return an example IBAN or BBAN for the country, or the |
|
170 |
+ name of the country.) |
|
171 |
+ |
|
172 |
+ (Regarding the object oriented wrapper - all of these |
|
173 |
+ functions are implemented as methods on IBANCountry |
|
174 |
+ objects, except for 'iban_countries()' which is |
|
175 |
+ implemented as the Countries() method on the IBAN class) |
|
176 |
+ |
|
177 |
+ - Internal functions |
|
178 |
+ These functions begin with '_iban_*' and can be ignored. |
|
179 |
+ |
|
180 |
+ (Regarding the object oriented wrapper - these functions |
|
181 |
+ are not present) |
|
182 |
+ |
|
183 |
+ Please refer to either http://code.google.com/p/php-iban or the |
|
184 |
+ commented source code of php-iban itself for the complete list of |
|
185 |
+ which functions are available. Of course, in unix style one could |
|
186 |
+ achieve the same in a pinch as follows (instant documentation!): |
|
187 |
+ $ grep function php-iban.php |
|
188 |
+ $ egrep '(Class|function)' oophp-iban.php |
|
189 |
+ |
|
190 |
+ Community |
|
191 |
+ --------- |
|
192 |
+ You are encouraged to contribute bugs, feedback and suggestions |
|
193 |
+ through the project's website. |
|
194 |
+ |
|
195 |
+ Particularly if you deploy php-iban in a commercial setting, you are |
|
196 |
+ STRONGLY encouraged to join the project's mailing list, which can |
|
197 |
+ be found via the website. Joining the mailing list ensures that you |
|
198 |
+ can be made aware of important updates. Important updates include: |
|
199 |
+ - Updates to new registry editions (support new countries that have |
|
200 |
+ been added to the IBAN system) |
|
201 |
+ - Bug fixes |
|
202 |
+ - Security updates |
|
203 |
+ |
|
204 |
+ The email list receives almost no traffic and as a 'Google Group' is |
|
205 |
+ well protected from spam, so don't worry about junk in your inbox. |
|
206 |
+ |
|
207 |
+Thanks for choosing php-iban! You have excellent taste in software ;) |
... | ... |
@@ -0,0 +1,11 @@ |
1 |
+To get the latest ISO13616 IBAN registry as a .txt file |
|
2 |
+for parsing, go to: |
|
3 |
+ http://www.swift.com/solutions/messaging/information_products/directory_products/iban_format_registry/index.page?lang=en |
|
4 |
+... then follow the '.txt format' link. |
|
5 |
+ |
|
6 |
+Unfortunately, it has been noticed in 2011 that the official .txt file is |
|
7 |
+not an accurate representation of the PDF format specification, and lacks |
|
8 |
+some information. It is hoped that in future SWIFT will be more careful to |
|
9 |
+publish only correct standards information. |
|
10 |
+ |
|
11 |
+(For more information on this subject, see the HACKING file) |
... | ... |
@@ -0,0 +1,9 @@ |
1 |
+Interpreting the SEPA Field |
|
2 |
+=========================== |
|
3 |
+ |
|
4 |
+Note that some IIBAN providers may in fact provide SEPA connectivity. |
|
5 |
+ |
|
6 |
+Thus, implementers are reminded to consider the reported SEPA status |
|
7 |
+of a country within the registry as confirming rather than negating |
|
8 |
+the potential SEPA status of a potential financial institution who |
|
9 |
+may be party to a proposed transaction. |
... | ... |
@@ -0,0 +1,21 @@ |
1 |
+TODO |
|
2 |
+---- |
|
3 |
+ |
|
4 |
+ - Finnish record suggests position at which to pad domestic account |
|
5 |
+ numbers in order to reach a BBAN / IBAN, this data could be of |
|
6 |
+ some use for certain applications and would be nice to include |
|
7 |
+ - Addition of information regarding preferred human-level formatting |
|
8 |
+ for each country's BBAN - worthwhile? |
|
9 |
+ - Addition of 'date effective' information for records such as BH |
|
10 |
+ and the UAE that published data in advance of deployment |
|
11 |
+ - Support for calculating or validating any known national (sub- |
|
12 |
+ BBAN-level) checksum algorithms? |
|
13 |
+ - URLs to national-level BBAN format specifications |
|
14 |
+ - Consider adding a library of localised forms and abbreviations |
|
15 |
+ for account number portions, for example Austria and Germany seem |
|
16 |
+ to have 'Kontonummer' (KTO) for account number, and 'Bankleitzah' |
|
17 |
+ (BLZ) for bank identifier. This could assist greatly with |
|
18 |
+ deployments requiring international and/or constrained input. |
|
19 |
+ - Consider building a library of national-level bank or payment |
|
20 |
+ institution identifier codes. This would be rather large and an |
|
21 |
+ optional extension. |
... | ... |
@@ -0,0 +1,49 @@ |
1 |
+ ; formalities |
|
2 |
+ input-roman = number / letter |
|
3 |
+ number = c-0 / c-1 / c-2 / c-3 / c-4 / c-5 / c-6 / c-7 / c-8 / c-9 |
|
4 |
+ letter = c-a / c-b / c-c / c-d / c-e / c-f / c-g / c-h / c-i / c-j |
|
5 |
+ / c-k / c-l / c-m / c-n / c-o / c-p / c-q / c-r / c-s |
|
6 |
+ / c-t / c-u / c-v / c-w / c-x / c-y / c-z |
|
7 |
+ |
|
8 |
+ ; possible sources of mistranscribed numbers |
|
9 |
+ c-0 = "O" / "6" / "D" / "G" |
|
10 |
+ c-1 = "I" / "L" / "7" / "2" / "Z" |
|
11 |
+ c-2 = "Z" / "7" / "P" / "E" / "1" |
|
12 |
+ c-3 = "8" / "B" |
|
13 |
+ c-4 = "G" / "U" |
|
14 |
+ c-5 = "S" / "7" |
|
15 |
+ c-6 = "0" / "O" / "8" / "G" / "C" / "B" / "D" |
|
16 |
+ c-7 = "J" / "I" / "1" / "L" |
|
17 |
+ c-8 = "B" / "3" / "6" |
|
18 |
+ c-9 = "G" / "Y" / "O" / "0" / "D" |
|
19 |
+ |
|
20 |
+ ; possible sources of mistranscribed letters |
|
21 |
+ c-a = "G" / "Q" / "O" / "0" |
|
22 |
+ c-b = "6" / "3" / "8" / "P" / "0" / "O" |
|
23 |
+ c-c = "R" / "6" / "I" / "L" / "O" / "0" |
|
24 |
+ c-d = "0" / "O" / "9" / "Q" / "G" / "6" / "A" |
|
25 |
+ c-e = "F" / "G" / "0" / "2" / "K" / "Z" / "S" / "O" |
|
26 |
+ c-f = "E" / "K" / "T" / "P" / "Y" / "4" / "B" / "7" / "1" |
|
27 |
+ c-g = "9" / "Q" / "8" / "6" / "0" / "C" / "4" / "O" |
|
28 |
+ c-h = "B" / "N" / "A" / "4" / "6" / "M" / "W" / "F" / "R" / "T" / "X" |
|
29 |
+ c-i = "1" / "L" / "7" / "J" / "2" / "T" / "Z" |
|
30 |
+ c-j = "I" / "7" / "2" / "9" / "1" / "U" / "T" / "Q" / "P" / "Y" / "Z" |
|
31 |
+ / "L" / "S" |
|
32 |
+ c-k = "F" / "X" / "H" / "R" |
|
33 |
+ c-l = "1" / "2" / "7" / "C" / "I" / "J" / "R" / "T" / "Y" / "Z" |
|
34 |
+ c-m = "H" / "8" / "E" / "3" / "N" / "V" / "W" |
|
35 |
+ c-n = "H" / "R" / "C" / "2" / "4" / "M" / "O" / "P" / "K" / "T" / "Z" |
|
36 |
+ c-o = "0" / "6" / "9" / "A" / "D" / "G" / "C" / "E" / "B" / "N" / "P" |
|
37 |
+ / "Q" / "R" |
|
38 |
+ c-p = "F" / "4" / "8" / "2" / "B" / "J" / "R" / "N" / "O" / "T" / "Y" |
|
39 |
+ c-q = "O" / "G" / "9" / "Y" / "1" / "7" / "L" |
|
40 |
+ c-r = "K" / "B" / "V" / "C" / "1" / "L" / "2" |
|
41 |
+ c-s = "5" / "6" / "9" / "B" / "G" / "Q" / "A" / "Y" |
|
42 |
+ c-t = "1" / "4" / "7" / "F" / "I" / "J" / "L" / "P" / "X" / "Y" |
|
43 |
+ c-u = "V" / "N" / "A" / "4" / "9" / "W" / "Y" |
|
44 |
+ c-v = "U" / "R" / "N" |
|
45 |
+ c-w = "M" / "N" / "U" / "V" |
|
46 |
+ c-x = "K" / "F" / "4" / "T" / "V" / "Y" |
|
47 |
+ c-y = "G" / "V" / "J" / "I" / "4" / "9" / "T" / "F" / "Q" / "1" |
|
48 |
+ c-z = "2" / "1" / "L" / "R" / "I" / "7" / "V" / "3" / "4" |
|
49 |
+ |
... | ... |
@@ -0,0 +1,157 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+# OO wrapper for 'php-iban.php' |
|
4 |
+Class IBAN { |
|
5 |
+ |
|
6 |
+ function __construct($iban = '') { |
|
7 |
+ require_once('php-iban.php'); # load the procedural codebase |
|
8 |
+ $this->iban = $iban; |
|
9 |
+ } |
|
10 |
+ |
|
11 |
+ public function Verify($iban='') { |
|
12 |
+ if($iban!='') { return verify_iban($iban); } |
|
13 |
+ return verify_iban($this->iban); |
|
14 |
+ # we could throw exceptions of various types, but why - does it really |
|
15 |
+ # add anything? possibly some slightly better user feedback potential. |
|
16 |
+ # however, this can be written by hand by performing individual checks |
|
17 |
+ # ala the code in verify_iban() itself where required, which is likely |
|
18 |
+ # almost never. for the increased complexity and |
|
19 |
+ # maintenance/documentation cost, i say, therefore: no. no exceptions. |
|
20 |
+ } |
|
21 |
+ |
|
22 |
+ public function MistranscriptionSuggestions() { |
|
23 |
+ return iban_mistranscription_suggestions($this->iban); |
|
24 |
+ } |
|
25 |
+ |
|
26 |
+ public function MachineFormat() { |
|
27 |
+ return iban_to_machine_format($this->iban); |
|
28 |
+ } |
|
29 |
+ |
|
30 |
+ public function HumanFormat() { |
|
31 |
+ return iban_to_human_format($this->iban); |
|
32 |
+ } |
|
33 |
+ |
|
34 |
+ public function Country($iban='') { |
|
35 |
+ return iban_get_country_part($this->iban); |
|
36 |
+ } |
|
37 |
+ |
|
38 |
+ public function Checksum($iban='') { |
|
39 |
+ return iban_get_checksum_part($this->iban); |
|
40 |
+ } |
|
41 |
+ |
|
42 |
+ public function BBAN() { |
|
43 |
+ return iban_get_bban_part($this->iban); |
|
44 |
+ } |
|
45 |
+ |
|
46 |
+ public function VerifyChecksum() { |
|
47 |
+ return iban_verify_checksum($this->iban); |
|
48 |
+ } |
|
49 |
+ |
|
50 |
+ public function FindChecksum() { |
|
51 |
+ return iban_find_checksum($this->iban); |
|
52 |
+ } |
|
53 |
+ |
|
54 |
+ public function SetChecksum() { |
|
55 |
+ $this->iban = iban_set_checksum($this->iban); |
|
56 |
+ } |
|
57 |
+ |
|
58 |
+ public function ChecksumStringReplace() { |
|
59 |
+ return iban_checksum_string_replace($this->iban); |
|
60 |
+ } |
|
61 |
+ |
|
62 |
+ public function Parts() { |
|
63 |
+ return iban_get_parts($this->iban); |
|
64 |
+ } |
|
65 |
+ |
|
66 |
+ public function Bank() { |
|
67 |
+ return iban_get_bank_part($this->iban); |
|
68 |
+ } |
|
69 |
+ |
|
70 |
+ public function Branch() { |
|
71 |
+ return iban_get_branch_part($this->iban); |
|
72 |
+ } |
|
73 |
+ |
|
74 |
+ public function Account() { |
|
75 |
+ return iban_get_account_part($this->iban); |
|
76 |
+ } |
|
77 |
+ |
|
78 |
+ public function Countries() { |
|
79 |
+ return iban_countries(); |
|
80 |
+ } |
|
81 |
+} |
|
82 |
+ |
|
83 |
+# IBANCountry |
|
84 |
+Class IBANCountry { |
|
85 |
+ |
|
86 |
+ # constructor with code |
|
87 |
+ function __construct($code = '') { |
|
88 |
+ $this->code = $code; |
|
89 |
+ } |
|
90 |
+ |
|
91 |
+ public function Name() { |
|
92 |
+ return iban_country_get_country_name($this->code); |
|
93 |
+ } |
|
94 |
+ |
|
95 |
+ public function DomesticExample() { |
|
96 |
+ return iban_country_get_domestic_example($this->code); |
|
97 |
+ } |
|
98 |
+ |
|
99 |
+ public function BBANExample() { |
|
100 |
+ return iban_country_get_bban_example($this->code); |
|
101 |
+ } |
|
102 |
+ |
|
103 |
+ public function BBANFormatSWIFT() { |
|
104 |
+ return iban_country_get_bban_format_swift($this->code); |
|
105 |
+ } |
|
106 |
+ |
|
107 |
+ public function BBANFormatRegex() { |
|
108 |
+ return iban_country_get_bban_format_regex($this->code); |
|
109 |
+ } |
|
110 |
+ |
|
111 |
+ public function BBANLength() { |
|
112 |
+ return iban_country_get_bban_length($this->code); |
|
113 |
+ } |
|
114 |
+ |
|
115 |
+ public function IBANExample() { |
|
116 |
+ return iban_country_get_iban_example($this->code); |
|
117 |
+ } |
|
118 |
+ |
|
119 |
+ public function IBANFormatSWIFT() { |
|
120 |
+ return iban_country_get_iban_format_swift($this->code); |
|
121 |
+ } |
|
122 |
+ |
|
123 |
+ public function IBANFormatRegex() { |
|
124 |
+ return iban_country_get_iban_format_regex($this->code); |
|
125 |
+ } |
|
126 |
+ |
|
127 |
+ public function IBANLength() { |
|
128 |
+ return iban_country_get_iban_length($this->code); |
|
129 |
+ } |
|
130 |
+ |
|
131 |
+ public function BankIDStartOffset() { |
|
132 |
+ return iban_country_get_bankid_start_offset($this->code); |
|
133 |
+ } |
|
134 |
+ |
|
135 |
+ public function BankIDStopOffset() { |
|
136 |
+ return iban_country_get_bankid_stop_offset($this->code); |
|
137 |
+ } |
|
138 |
+ |
|
139 |
+ public function BranchIDStartOffset() { |
|
140 |
+ return iban_country_get_branchid_start_offset($this->code); |
|
141 |
+ } |
|
142 |
+ |
|
143 |
+ public function BranchIDStopOffset() { |
|
144 |
+ return iban_country_get_branchid_stop_offset($this->code); |
|
145 |
+ } |
|
146 |
+ |
|
147 |
+ public function RegistryEdition() { |
|
148 |
+ return iban_country_get_registry_edition($this->code); |
|
149 |
+ } |
|
150 |
+ |
|
151 |
+ public function IsSEPA() { |
|
152 |
+ return iban_country_is_sepa($this->code); |
|
153 |
+ } |
|
154 |
+ |
|
155 |
+} |
|
156 |
+ |
|
157 |
+?> |
... | ... |
@@ -0,0 +1,486 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+# PHP IBAN - http://code.google.com/p/php-iban - LGPLv3 |
|
4 |
+ |
|
5 |
+# Global flag by request |
|
6 |
+$__disable_iiban_gmp_extension=false; |
|
7 |
+ |
|
8 |
+# Verify an IBAN number. Returns true or false. |
|
9 |
+# NOTE: Input can be printed 'IIBAN xx xx xx...' or 'IBAN xx xx xx...' or machine 'xxxxx' format. |
|
10 |
+function verify_iban($iban) { |
|
11 |
+ |
|
12 |
+ # First convert to machine format. |
|
13 |
+ $iban = iban_to_machine_format($iban); |
|
14 |
+ |
|
15 |
+ # Get country of IBAN |
|
16 |
+ $country = iban_get_country_part($iban); |
|
17 |
+ |
|
18 |
+ # Test length of IBAN |
|
19 |
+ if(strlen($iban)!=iban_country_get_iban_length($country)) { return false; } |
|
20 |
+ |
|
21 |
+ # Get checksum of IBAN |
|
22 |
+ $checksum = iban_get_checksum_part($iban); |
|
23 |
+ |
|
24 |
+ # Get country-specific IBAN format regex |
|
25 |
+ $regex = '/'.iban_country_get_iban_format_regex($country).'/'; |
|
26 |
+ |
|
27 |
+ # Check regex |
|
28 |
+ if(preg_match($regex,$iban)) { |
|
29 |
+ # Regex passed, check checksum |
|
30 |
+ if(!iban_verify_checksum($iban)) { |
|
31 |
+ return false; |
|
32 |
+ } |
|
33 |
+ } |
|
34 |
+ else { |
|
35 |
+ return false; |
|
36 |
+ } |
|
37 |
+ |
|
38 |
+ # Otherwise it 'could' exist |
|
39 |
+ return true; |
|
40 |
+} |
|
41 |
+ |
|
42 |
+# Convert an IBAN to machine format. To do this, we |
|
43 |
+# remove IBAN from the start, if present, and remove |
|
44 |
+# non basic roman letter / digit characters |
|
45 |
+function iban_to_machine_format($iban) { |
|
46 |
+ # Uppercase and trim spaces from left |
|
47 |
+ $iban = ltrim(strtoupper($iban)); |
|
48 |
+ # Remove IIBAN or IBAN from start of string, if present |
|
49 |
+ $iban = preg_replace('/^I?IBAN/','',$iban); |
|
50 |
+ # Remove all non basic roman letter / digit characters |
|
51 |
+ $iban = preg_replace('/[^a-zA-Z0-9]/','',$iban); |
|
52 |
+ return $iban; |
|
53 |
+} |
|
54 |
+ |
|
55 |
+# Convert an IBAN to human format. To do this, we |
|
56 |
+# simply insert spaces right now, as per the ECBS |
|
57 |
+# (European Committee for Banking Standards) |
|
58 |
+# recommendations available at: |
|
59 |
+# http://www.europeanpaymentscouncil.eu/knowledge_bank_download.cfm?file=ECBS%20standard%20implementation%20guidelines%20SIG203V3.2.pdf |
|
60 |
+function iban_to_human_format($iban) { |
|
61 |
+ # First verify validity, or return |
|
62 |
+ if(!verify_iban($iban)) { return false; } |
|
63 |
+ # Add spaces every four characters |
|
64 |
+ $human_iban = ''; |
|
65 |
+ for($i=0;$i<strlen($iban);$i++) { |
|
66 |
+ $human_iban .= substr($iban,$i,1); |
|
67 |
+ if(($i>0) && (($i+1)%4==0)) { $human_iban .= ' '; } |
|
68 |
+ } |
|
69 |
+ return $human_iban; |
|
70 |
+} |
|
71 |
+ |
|
72 |
+# Get the country part from an IBAN |
|
73 |
+function iban_get_country_part($iban) { |
|
74 |
+ $iban = iban_to_machine_format($iban); |
|
75 |
+ return substr($iban,0,2); |
|
76 |
+} |
|
77 |
+ |
|
78 |
+# Get the checksum part from an IBAN |
|
79 |
+function iban_get_checksum_part($iban) { |
|
80 |
+ $iban = iban_to_machine_format($iban); |
|
81 |
+ return substr($iban,2,2); |
|
82 |
+} |
|
83 |
+ |
|
84 |
+# Get the BBAN part from an IBAN |
|
85 |
+function iban_get_bban_part($iban) { |
|
86 |
+ $iban = iban_to_machine_format($iban); |
|
87 |
+ return substr($iban,4); |
|
88 |
+} |
|
89 |
+ |
|
90 |
+# Check the checksum of an IBAN - code modified from Validate_Finance PEAR class |
|
91 |
+function iban_verify_checksum($iban) { |
|
92 |
+ # convert to machine format |
|
93 |
+ $iban = iban_to_machine_format($iban); |
|
94 |
+ # move first 4 chars (countrycode and checksum) to the end of the string |
|
95 |
+ $tempiban = substr($iban, 4).substr($iban, 0, 4); |
|
96 |
+ # subsitutute chars |
|
97 |
+ $tempiban = iban_checksum_string_replace($tempiban); |
|
98 |
+ # mod97-10 |
|
99 |
+ $result = iban_mod97_10($tempiban); |
|
100 |
+ # checkvalue of 1 indicates correct IBAN checksum |
|
101 |
+ if ($result != 1) { |
|
102 |
+ return false; |
|
103 |
+ } |
|
104 |
+ return true; |
|
105 |
+} |
|
106 |
+ |
|
107 |
+# Find the correct checksum for an IBAN |
|
108 |
+# $iban The IBAN whose checksum should be calculated |
|
109 |
+function iban_find_checksum($iban) { |
|
110 |
+ $iban = iban_to_machine_format($iban); |
|
111 |
+ # move first 4 chars to right |
|
112 |
+ $left = substr($iban,0,2) . '00'; # but set right-most 2 (checksum) to '00' |
|
113 |
+ $right = substr($iban,4); |
|
114 |
+ # glue back together |
|
115 |
+ $tmp = $right . $left; |
|
116 |
+ # convert letters using conversion table |
|
117 |
+ $tmp = iban_checksum_string_replace($tmp); |
|
118 |
+ # get mod97-10 output |
|
119 |
+ $checksum = iban_mod97_10_checksum($tmp); |
|
120 |
+ # return 98 minus the mod97-10 output, left zero padded to two digits |
|
121 |
+ return str_pad((98-$checksum),2,'0',STR_PAD_LEFT); |
|
122 |
+} |
|
123 |
+ |
|
124 |
+# Set the correct checksum for an IBAN |
|
125 |
+# $iban IBAN whose checksum should be set |
|
126 |
+function iban_set_checksum($iban) { |
|
127 |
+ $iban = iban_to_machine_format($iban); |
|
128 |
+ return substr($iban,0,2) . iban_find_checksum($iban) . substr($iban,4); |
|
129 |
+} |
|
130 |
+ |
|
131 |
+# Character substitution required for IBAN MOD97-10 checksum validation/generation |
|
132 |
+# $s Input string (IBAN) |
|
133 |
+function iban_checksum_string_replace($s) { |
|
134 |
+ $iban_replace_chars = range('A','Z'); |
|
135 |
+ foreach (range(10,35) as $tempvalue) { $iban_replace_values[]=strval($tempvalue); } |
|
136 |
+ return str_replace($iban_replace_chars,$iban_replace_values,$s); |
|
137 |
+} |
|
138 |
+ |
|
139 |
+# Same as below but actually returns resulting checksum |
|
140 |
+function iban_mod97_10_checksum($numeric_representation) { |
|
141 |
+ $checksum = intval(substr($numeric_representation, 0, 1)); |
|
142 |
+ for ($position = 1; $position < strlen($numeric_representation); $position++) { |
|
143 |
+ $checksum *= 10; |
|
144 |
+ $checksum += intval(substr($numeric_representation,$position,1)); |
|
145 |
+ $checksum %= 97; |
|
146 |
+ } |
|
147 |
+ return $checksum; |
|
148 |
+} |
|
149 |
+ |
|
150 |
+# Perform MOD97-10 checksum calculation ('Germanic-level effiency' version - thanks Chris!) |
|
151 |
+function iban_mod97_10($numeric_representation) { |
|
152 |
+ global $__disable_iiban_gmp_extension; |
|
153 |
+ # prefer php5 gmp extension if available |
|
154 |
+ if(!($__disable_iiban_gmp_extension) && function_exists('gmp_intval')) { return gmp_intval(gmp_mod(gmp_init($numeric_representation, 10),'97')) === 1; } |
|
155 |
+ |
|
156 |
+/* |
|
157 |
+ # old manual processing (~16x slower) |
|
158 |
+ $checksum = intval(substr($numeric_representation, 0, 1)); |
|
159 |
+ for ($position = 1; $position < strlen($numeric_representation); $position++) { |
|
160 |
+ $checksum *= 10; |
|
161 |
+ $checksum += intval(substr($numeric_representation,$position,1)); |
|
162 |
+ $checksum %= 97; |
|
163 |
+ } |
|
164 |
+ return $checksum; |
|
165 |
+ */ |
|
166 |
+ |
|
167 |
+ # new manual processing (~3x slower) |
|
168 |
+ $length = strlen($numeric_representation); |
|
169 |
+ $rest = ""; |
|
170 |
+ $position = 0; |
|
171 |
+ while ($position < $length) { |
|
172 |
+ $value = 9-strlen($rest); |
|
173 |
+ $n = $rest . substr($numeric_representation,$position,$value); |
|
174 |
+ $rest = $n % 97; |
|
175 |
+ $position = $position + $value; |
|
176 |
+ } |
|
177 |
+ return ($rest === 1); |
|
178 |
+} |
|
179 |
+ |
|
180 |
+# Get an array of all the parts from an IBAN |
|
181 |
+function iban_get_parts($iban) { |
|
182 |
+ return array( |
|
183 |
+ 'country' => iban_get_country_part($iban), |
|
184 |
+ 'checksum' => iban_get_checksum_part($iban), |
|
185 |
+ 'bban' => iban_get_bban_part($iban), |
|
186 |
+ 'bank' => iban_get_bank_part($iban), |
|
187 |
+ 'country' => iban_get_country_part($iban), |
|
188 |
+ 'branch' => iban_get_branch_part($iban), |
|
189 |
+ 'account' => iban_get_account_part($iban) |
|
190 |
+ ); |
|
191 |
+} |
|
192 |
+ |
|
193 |
+# Get the Bank ID (institution code) from an IBAN |
|
194 |
+function iban_get_bank_part($iban) { |
|
195 |
+ $iban = iban_to_machine_format($iban); |
|
196 |
+ $country = iban_get_country_part($iban); |
|
197 |
+ $start = iban_country_get_bankid_start_offset($country); |
|
198 |
+ $stop = iban_country_get_bankid_stop_offset($country); |
|
199 |
+ if($start!=''&&$stop!='') { |
|
200 |
+ $bban = iban_get_bban_part($iban); |
|
201 |
+ return substr($bban,$start,($stop-$start+1)); |
|
202 |
+ } |
|
203 |
+ return ''; |
|
204 |
+} |
|
205 |
+ |
|
206 |
+# Get the Branch ID (sort code) from an IBAN |
|
207 |
+function iban_get_branch_part($iban) { |
|
208 |
+ $iban = iban_to_machine_format($iban); |
|
209 |
+ $country = iban_get_country_part($iban); |
|
210 |
+ $start = iban_country_get_branchid_start_offset($country); |
|
211 |
+ $stop = iban_country_get_branchid_stop_offset($country); |
|
212 |
+ if($start!=''&&$stop!='') { |
|
213 |
+ $bban = iban_get_bban_part($iban); |
|
214 |
+ return substr($bban,$start,($stop-$start+1)); |
|
215 |
+ } |
|
216 |
+ return ''; |
|
217 |
+} |
|
218 |
+ |
|
219 |
+# Get the (branch-local) account ID from an IBAN |
|
220 |
+function iban_get_account_part($iban) { |
|
221 |
+ $iban = iban_to_machine_format($iban); |
|
222 |
+ $country = iban_get_country_part($iban); |
|
223 |
+ $start = iban_country_get_branchid_stop_offset($country); |
|
224 |
+ if($start=='') { |
|
225 |
+ $start = iban_country_get_bankid_stop_offset($country); |
|
226 |
+ } |
|
227 |
+ if($start!='') { |
|
228 |
+ $bban = iban_get_bban_part($iban); |
|
229 |
+ return substr($bban,$start+1); |
|
230 |
+ } |
|
231 |
+ return ''; |
|
232 |
+} |
|
233 |
+ |
|
234 |
+# Get the name of an IBAN country |
|
235 |
+function iban_country_get_country_name($iban_country) { |
|
236 |
+ return _iban_country_get_info($iban_country,'country_name'); |
|
237 |
+} |
|
238 |
+ |
|
239 |
+# Get the domestic example for an IBAN country |
|
240 |
+function iban_country_get_domestic_example($iban_country) { |
|
241 |
+ return _iban_country_get_info($iban_country,'domestic_example'); |
|
242 |
+} |
|
243 |
+ |
|
244 |
+# Get the BBAN example for an IBAN country |
|
245 |
+function iban_country_get_bban_example($iban_country) { |
|
246 |
+ return _iban_country_get_info($iban_country,'bban_example'); |
|
247 |
+} |
|
248 |
+ |
|
249 |
+# Get the BBAN format (in SWIFT format) for an IBAN country |
|
250 |
+function iban_country_get_bban_format_swift($iban_country) { |
|
251 |
+ return _iban_country_get_info($iban_country,'bban_format_swift'); |
|
252 |
+} |
|
253 |
+ |
|
254 |
+# Get the BBAN format (as a regular expression) for an IBAN country |
|
255 |
+function iban_country_get_bban_format_regex($iban_country) { |
|
256 |
+ return _iban_country_get_info($iban_country,'bban_format_regex'); |
|
257 |
+} |
|
258 |
+ |
|
259 |
+# Get the BBAN length for an IBAN country |
|
260 |
+function iban_country_get_bban_length($iban_country) { |
|
261 |
+ return _iban_country_get_info($iban_country,'bban_length'); |
|
262 |
+} |
|
263 |
+ |
|
264 |
+# Get the IBAN example for an IBAN country |
|
265 |
+function iban_country_get_iban_example($iban_country) { |
|
266 |
+ return _iban_country_get_info($iban_country,'iban_example'); |
|
267 |
+} |
|
268 |
+ |
|
269 |
+# Get the IBAN format (in SWIFT format) for an IBAN country |
|
270 |
+function iban_country_get_iban_format_swift($iban_country) { |
|
271 |
+ return _iban_country_get_info($iban_country,'iban_format_swift'); |
|
272 |
+} |
|
273 |
+ |
|
274 |
+# Get the IBAN format (as a regular expression) for an IBAN country |
|
275 |
+function iban_country_get_iban_format_regex($iban_country) { |
|
276 |
+ return _iban_country_get_info($iban_country,'iban_format_regex'); |
|
277 |
+} |
|
278 |
+ |
|
279 |
+# Get the IBAN length for an IBAN country |
|
280 |
+function iban_country_get_iban_length($iban_country) { |
|
281 |
+ return _iban_country_get_info($iban_country,'iban_length'); |
|
282 |
+} |
|
283 |
+ |
|
284 |
+# Get the BBAN Bank ID start offset for an IBAN country |
|
285 |
+function iban_country_get_bankid_start_offset($iban_country) { |
|
286 |
+ return _iban_country_get_info($iban_country,'bban_bankid_start_offset'); |
|
287 |
+} |
|
288 |
+ |
|
289 |
+# Get the BBAN Bank ID stop offset for an IBAN country |
|
290 |
+function iban_country_get_bankid_stop_offset($iban_country) { |
|
291 |
+ return _iban_country_get_info($iban_country,'bban_bankid_stop_offset'); |
|
292 |
+} |
|
293 |
+ |
|
294 |
+# Get the BBAN Branch ID start offset for an IBAN country |
|
295 |
+function iban_country_get_branchid_start_offset($iban_country) { |
|
296 |
+ return _iban_country_get_info($iban_country,'bban_branchid_start_offset'); |
|
297 |
+} |
|
298 |
+ |
|
299 |
+# Get the BBAN Branch ID stop offset for an IBAN country |
|
300 |
+function iban_country_get_branchid_stop_offset($iban_country) { |
|
301 |
+ return _iban_country_get_info($iban_country,'bban_branchid_stop_offset'); |
|
302 |
+} |
|
303 |
+ |
|
304 |
+# Get the registry edition for an IBAN country |
|
305 |
+function iban_country_get_registry_edition($iban_country) { |
|
306 |
+ return _iban_country_get_info($iban_country,'registry_edition'); |
|
307 |
+} |
|
308 |
+ |
|
309 |
+# Is the IBAN country a SEPA member? |
|
310 |
+function iban_country_is_sepa($iban_country) { |
|
311 |
+ return _iban_country_get_info($iban_country,'country_sepa'); |
|
312 |
+} |
|
313 |
+ |
|
314 |
+# Get the list of all IBAN countries |
|
315 |
+function iban_countries() { |
|
316 |
+ global $_iban_registry; |
|
317 |
+ return array_keys($_iban_registry); |
|
318 |
+} |
|
319 |
+ |
|
320 |
+# Given an incorrect IBAN, return an array of zero or more checksum-valid |
|
321 |
+# suggestions for what the user might have meant, based upon common |
|
322 |
+# mistranscriptions. |
|
323 |
+function iban_mistranscription_suggestions($incorrect_iban) { |
|
324 |
+ |
|
325 |
+ # abort on ridiculous length input (but be liberal) |
|
326 |
+ $length = strlen($incorrect_iban); |
|
327 |
+ if($length<5 || $length>34) { return array('(length bad)'); } |
|
328 |
+ |
|
329 |
+ # abort if mistranscriptions data is unable to load |
|
330 |
+ if(!_iban_load_mistranscriptions()) { return array('(failed to load)'); } |
|
331 |
+ |
|
332 |
+ # init |
|
333 |
+ global $_iban_mistranscriptions; |
|
334 |
+ $suggestions = array(); |
|
335 |
+ |
|
336 |
+ # we have a string of approximately IBAN-like length. |
|
337 |
+ # ... now let's make suggestions. |
|
338 |
+ $numbers = array('0','1','2','3','4','5','6','7','8','9'); |
|
339 |
+ for($i=0;$i<$length;$i++) { |
|
340 |
+ # get the character at this position |
|
341 |
+ $character = substr($incorrect_iban,$i,1); |
|
342 |
+ # for each known transcription error resulting in this character |
|
343 |
+ foreach($_iban_mistranscriptions[$character] as $possible_origin) { |
|
344 |
+ # if we're: |
|
345 |
+ # - in the first 2 characters (country) and the possible replacement |
|
346 |
+ # is a letter |
|
347 |
+ # - in the 3rd or 4th characters (checksum) and the possible |
|
348 |
+ # replacement is a number |
|
349 |
+ # - later in the string |
|
350 |
+ if(($i<2 && !in_array($possible_origin,$numbers)) || |
|
351 |
+ ($i>=2 && $i<=3 && in_array($possible_origin,$numbers)) || |
|
352 |
+ $i>3) { |
|
353 |
+ # construct a possible IBAN using this possible origin for the |
|
354 |
+ # mistranscribed character, replaced at this position only |
|
355 |
+ $possible_iban = substr($incorrect_iban,0,$i) . $possible_origin . substr($incorrect_iban,$i+1); |
|
356 |
+ # if the checksum passes, return it as a possibility |
|
357 |
+ if(verify_iban($possible_iban)) { |
|
358 |
+ array_push($suggestions,$possible_iban); |
|
359 |
+ } |
|
360 |
+ } |
|
361 |
+ } |
|
362 |
+ } |
|
363 |
+ |
|
364 |
+ # now we check for the type of mistransposition case where all of |
|
365 |
+ # the characters of a certain type within a string were mistransposed. |
|
366 |
+ # - first generate a character frequency table |
|
367 |
+ $char_freqs = array(); |
|
368 |
+ for($i=0;$i<strlen($incorrect_iban);$i++) { |
|
369 |
+ if(!isset($char_freqs[substr($incorrect_iban,$i,1)])) { |
|
370 |
+ $char_freqs[substr($incorrect_iban,$i,1)] = 1; |
|
371 |
+ } |
|
372 |
+ else { |
|
373 |
+ $char_freqs[substr($incorrect_iban,$i,1)]++; |
|
374 |
+ } |
|
375 |
+ } |
|
376 |
+ # - now, for each of the characters in the string... |
|
377 |
+ foreach($char_freqs as $char=>$freq) { |
|
378 |
+ # if the character occurs more than once |
|
379 |
+ if($freq>1) { |
|
380 |
+ # check the 'all occurrences of <char> were mistranscribed' case |
|
381 |
+ foreach($_iban_mistranscriptions[$char] as $possible_origin) { |
|
382 |
+ $possible_iban = str_replace($char,$possible_origin,$incorrect_iban); |
|
383 |
+ if(verify_iban($possible_iban)) { |
|
384 |
+ array_push($suggestions,$possible_iban); |
|
385 |
+ } |
|
386 |
+ } |
|
387 |
+ } |
|
388 |
+ } |
|
389 |
+ |
|
390 |
+ return $suggestions; |
|
391 |
+} |
|
392 |
+ |
|
393 |
+ |
|
394 |
+##### internal use functions - safe to ignore ###### |
|
395 |
+ |
|
396 |
+# Load the IBAN registry from disk. |
|
397 |
+global $_iban_registry; |
|
398 |
+$_iban_registry = array(); |
|
399 |
+_iban_load_registry(); |
|
400 |
+function _iban_load_registry() { |
|
401 |
+ global $_iban_registry; |
|
402 |
+ # if the registry is not yet loaded, or has been corrupted, reload |
|
403 |
+ if(!is_array($_iban_registry) || count($_iban_registry)<1) { |
|
404 |
+ $data = file_get_contents(dirname(__FILE__) . '/registry.txt'); |
|
405 |
+ $lines = explode("\n",$data); |
|
406 |
+ array_shift($lines); # drop leading description line |
|
407 |
+ # loop through lines |
|
408 |
+ foreach($lines as $line) { |
|
409 |
+ if($line!='') { |
|
410 |
+ # split to fields |
|
411 |
+ $old_display_errors_value = ini_get('display_errors'); |
|
412 |
+ ini_set('display_errors',false); |
|
413 |
+ $old_error_reporting_value = ini_get('error_reporting'); |
|
414 |
+ ini_set('error_reporting',false); |
|
415 |
+ list($country,$country_name,$domestic_example,$bban_example,$bban_format_swift,$bban_format_regex,$bban_length,$iban_example,$iban_format_swift,$iban_format_regex,$iban_length,$bban_bankid_start_offset,$bban_bankid_stop_offset,$bban_branchid_start_offset,$bban_branchid_stop_offset,$registry_edition,$country_sepa) = explode('|',$line); |
|
416 |
+ ini_set('display_errors',$old_display_errors_value); |
|
417 |
+ ini_set('error_reporting',$old_error_reporting_value); |
|
418 |
+ # assign to registry |
|
419 |
+ $_iban_registry[$country] = array( |
|
420 |
+ 'country' => $country, |
|
421 |
+ 'country_name' => $country_name, |
|
422 |
+ 'country_sepa' => $country_sepa, |
|
423 |
+ 'domestic_example' => $domestic_example, |
|
424 |
+ 'bban_example' => $bban_example, |
|
425 |
+ 'bban_format_swift' => $bban_format_swift, |
|
426 |
+ 'bban_format_regex' => $bban_format_regex, |
|
427 |
+ 'bban_length' => $bban_length, |
|
428 |
+ 'iban_example' => $iban_example, |
|
429 |
+ 'iban_format_swift' => $iban_format_swift, |
|
430 |
+ 'iban_format_regex' => $iban_format_regex, |
|
431 |
+ 'iban_length' => $iban_length, |
|
432 |
+ 'bban_bankid_start_offset' => $bban_bankid_start_offset, |
|
433 |
+ 'bban_bankid_stop_offset' => $bban_bankid_stop_offset, |
|
434 |
+ 'bban_branchid_start_offset' => $bban_branchid_start_offset, |
|
435 |
+ 'bban_branchid_stop_offset' => $bban_branchid_stop_offset, |
|
436 |
+ 'registry_edition' => $registry_edition |
|
437 |
+ ); |
|
438 |
+ } |
|
439 |
+ } |
|
440 |
+ } |
|
441 |
+} |
|
442 |
+ |
|
443 |
+# Get information from the IBAN registry by example IBAN / code combination |
|
444 |
+function _iban_get_info($iban,$code) { |
|
445 |
+ $country = iban_get_country_part($iban); |
|
446 |
+ return _iban_country_get_info($country,$code); |
|
447 |
+} |
|
448 |
+ |
|
449 |
+# Get information from the IBAN registry by country / code combination |
|
450 |
+function _iban_country_get_info($country,$code) { |
|
451 |
+ global $_iban_registry; |
|
452 |
+ $country = strtoupper($country); |
|
453 |
+ $code = strtolower($code); |
|
454 |
+ if(array_key_exists($country,$_iban_registry)) { |
|
455 |
+ if(array_key_exists($code,$_iban_registry[$country])) { |
|
456 |
+ return $_iban_registry[$country][$code]; |
|
457 |
+ } |
|
458 |
+ } |
|
459 |
+ return false; |
|
460 |
+} |
|
461 |
+ |
|
462 |
+# Load common mistranscriptions from disk. |
|
463 |
+function _iban_load_mistranscriptions() { |
|
464 |
+ global $_iban_mistranscriptions; |
|
465 |
+ # do not reload if already present |
|
466 |
+ if(is_array($_iban_mistranscriptions) && count($_iban_mistranscriptions) == 36) { return true; } |
|
467 |
+ $_iban_mistranscriptions = array(); |
|
468 |
+ $file = dirname(__FILE__) . '/mistranscriptions.txt'; |
|
469 |
+ if(!file_exists($file) || !is_readable($file)) { return false; } |
|
470 |
+ $data = file_get_contents($file); |
|
471 |
+ $lines = explode("\n",$data); |
|
472 |
+ foreach($lines as $line) { |
|
473 |
+ # match lines with ' c-<x> = <something>' where x is a word-like character |
|
474 |
+ if(preg_match('/^ *c-(\w) = (.*?)$/',$line,$matches)) { |
|
475 |
+ # normalize the character to upper case |
|
476 |
+ $character = strtoupper($matches[1]); |
|
477 |
+ # break the possible origins list at '/', strip quotes & spaces |
|
478 |
+ $chars = explode(' ',str_replace('"','',preg_replace('/ *?\/ *?/','',$matches[2]))); |
|
479 |
+ # assign as possible mistranscriptions for that character |
|
480 |
+ $_iban_mistranscriptions[$character] = $chars; |
|
481 |
+ } |
|
482 |
+ } |
|
483 |
+ return true; |
|
484 |
+} |
|
485 |
+ |
|
486 |
+?> |
... | ... |
@@ -0,0 +1,79 @@ |
1 |
+country_code|country_name|domestic_example|bban_example|bban_format_swift|bban_format_regex|bban_length|iban_example|iban_format_swift|iban_format_regex|iban_length|bban_bankid_start_offset|bban_bankid_stop_offset|bban_branchid_start_offset|bban_branchid_stop_offset|registry_edition|country_sepa |
|
2 |
+AA|IIBAN (Internet)|0011123Z5678|0011123Z5678|12!a|^[A-Z0-9]{12}$|12|AA120011123Z5678|AA2!n12!a|^AA(\d{2})([A-Z0-9]{12})$|16|0|3|||N/A|0 |
|
3 |
+AL|Albania|0000000235698741|212110090000000235698741|8!n16!c|^(\d{8})([A-Za-z0-9]{16})$|24|AL47212110090000000235698741|AL2!n8!n16!c|^AL(\d{2})(\d{8})([A-Za-z0-9]{16})$|28|0|2|3|6|2011-06-20|0 |
|
4 |
+AD|Andorra|2030200359100100|00012030200359100100|4!n4!n12!c|^(\d{4})(\d{4})([A-Za-z0-9]{12})$|20|AD1200012030200359100100|AD2!n4!n4!n12!c|^AD(\d{2})(\d{4})(\d{4})([A-Za-z0-9]{12})$|24|0|3|4|7|2011-06-20|0 |
|
5 |
+AT|Austria|19043-234573201|1904300234573201|5!n11!n|^(\d{5})(\d{11})$|16|AT611904300234573201|AT2!n5!n11!n|^AT(\d{2})(\d{5})(\d{11})$|20|0|4|||2011-06-20|1 |
|
6 |
+AX|Aland Islands|123456-785|12345600000785|6!n7!n1!n|^(\d{6})(\d{7})(\d{1})$|14|AX2112345600000785|AX2!n6!n7!n1!n|^AX(\d{2})(\d{6})(\d{7})(\d{1})$|18|0|2|||2013-09-05|1 |
|
7 |
+AZ|Azerbaijan|NABZ00000000137010001944|NABZ00000000137010001944|4!a20!c|^([A-Z]{4})([A-Za-z0-9]{20})$|24|AZ21NABZ00000000137010001944|AZ2!n4!a20!c|^AZ(\d{2})([A-Z]{4})([A-Za-z0-9]{20})$|28|0|3|||2012-05-29|0 |
|
8 |
+BH|Bahrain|00001299123456|BMAG00001299123456|4!a14!c|^([A-Z]{4})([A-Za-z0-9]{14})$|22|BH67BMAG00001299123456|BH2!n4!a14!c|^BH(\d{2})([A-Z]{4})([A-Za-z0-9]{14})$|22|0|3|||2012-05-29|0 |
|
9 |
+BE|Belgium|539-0075470-34|539007547034|3!n7!n2!n|^(\d{3})(\d{7})(\d{2})$|12|BE68539007547034|BE2!n3!n7!n2!n|^BE(\d{2})(\d{3})(\d{7})(\d{2})$|16|0|2|||2011-06-20|1 |
|
10 |
+BA|Bosnia and Herzegovina|199-044-00012002-79|1990440001200279|3!n3!n8!n2!n|^(\d{3})(\d{3})(\d{8})(\d{2})$|16|BA391290079401028494|BA2!n3!n3!n8!n2!n|^BA(\d{2})(\d{3})(\d{3})(\d{8})(\d{2})$|20|0|2|3|5|2011-06-20|0 |
|
11 |
+BR|Brazil|0009795493C1|00360305000010009795493P1|8!n5!n10!n1!a1!c|^(\d{8})(\d{5})(\d{10})([A-Z]{1})([A-Za-z0-9]{1})$|25|BR2300360305000010009795493P1BR1800000000141455123924100C2|BR2!n8!n5!n10!n1!a1!c|^BR(\d{2})(\d{8})(\d{5})(\d{10})([A-Z]{1})([A-Za-z0-9]{1})$|29|0|7|8|12|2013-06-20|0 |
|
12 |
+BG|Bulgaria|BNBG 9661 1020 3456 78|BNBG96611020345678|4!a4!n2!n8!c|^([A-Z]{4})(\d{4})(\d{2})([A-Za-z0-9]{8})$|18|BG80BNBG96611020345678|BG2!n4!a4!n2!n8!c|^BG(\d{2})([A-Z]{4})(\d{4})(\d{2})([A-Za-z0-9]{8})$|22|0|3|4|7|2011-06-20|1 |
|
13 |
+CR|Costa Rica|1026284066|15202001026284066|3!n14!n|^(\d{3})(\d{14})$|7|CR91202001026284066|CR2!n3!n14!n|^CR(\d{2})(\d{3})(\d{14})$|21|0|2|||2012-05-29|0 |
|
14 |
+HR|Croatia|1001005-1863000160|10010051863000160|7!n10!n|^(\d{7})(\d{10})$|17|HR1210010051863000160|HR2!n7!n10!n|^HR(\d{2})(\d{7})(\d{10})$|21|0|6|||2011-06-20|0 |
|
15 |
+CY|Cyprus|1200527600|002001280000001200527600|3!n5!n16!c|^(\d{3})(\d{5})([A-Za-z0-9]{16})$|24|CY17002001280000001200527600|CY2!n3!n5!n16!c|^CY(\d{2})(\d{3})(\d{5})([A-Za-z0-9]{16})$|28|0|2|3|7|2011-06-20|1 |
|
16 |
+CZ|Czech Republic|19-2000145399/0800|08000000192000145399|4!n6!n10!n|^(\d{4})(\d{6})(\d{10})$|20|CZ6508000000192000145399|CZ2!n4!n6!n10!n|^CZ(\d{2})(\d{4})(\d{6})(\d{10})$|24|0|3|4|9|2011-06-20|1 |
|
17 |
+DK|Denmark|0040 0440116243, 6460 0001631634, 6471 0001000206|00400440116243, 64600001631634, 64710001000206|4!n9!n1!n|^(\d{4})(\d{9})(\d{1})$|14|DK5000400440116243|DK2!n4!n9!n1!n|^DK(\d{2})(\d{4})(\d{9})(\d{1})$|18|0|3|||2011-06-20|1 |
|
18 |
+FO|Faroe Islands|0040 0440116243, 6460 0001631634, 6471 0001000206|00400440116243, 64600001631634, 64710001000206|4!n9!n1!n|^(\d{4})(\d{9})(\d{1})$|14|FO2000400440116243|FO2!n4!n9!n1!n|^FO(\d{2})(\d{4})(\d{9})(\d{1})$|18|0|3|||2011-06-20|1 |
|
19 |
+GL|Greenland|0040 0440116243, 6460 0001631634, 6471 0001000206|00400440116243, 64600001631634, 64710001000206|4!n9!n1!n|^(\d{4})(\d{9})(\d{1})$|14|GL2000400440116243|GL2!n4!n9!n1!n|^GL(\d{2})(\d{4})(\d{9})(\d{1})$|18|0|3|||2011-06-20|1 |
|
20 |
+DO|Dominican Republic|1212453611324|AGR00000001212453611324|4!c20!n|^([A-Za-z0-9]{4})(\d{20})$|24|DO28BAGR00000001212453611324|DO2!n4!c20!n|^DO(\d{2})([A-Za-z0-9]{4})(\d{20})$|28|0|3|||2011-06-20|0 |
|
21 |
+EE|Estonia|221020145685|2200221020145685|2!n2!n11!n1!n|^(\d{2})(\d{2})(\d{11})(\d{1})$|16|EE382200221020145685|EE2!n2!n2!n11!n1!n|^EE(\d{2})(\d{2})(\d{2})(\d{11})(\d{1})$|20|0|1|||2011-06-20|1 |
|
22 |
+FI|Finland|123456-785|12345600000785|6!n7!n1!n|^(\d{6})(\d{7})(\d{1})$|14|FI2112345600000785|FI2!n6!n7!n1!n|^FI(\d{2})(\d{6})(\d{7})(\d{1})$|18|0|2|||2013-08-05|1 |
|
23 |
+FR|France|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|FR1420041010050500013M02606|FR2!n5!n5!n11!c2!n|^FR(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2013-08-28|1 |
|
24 |
+BL|Saint Barthelemy|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|BL9820041010050500013M02606|BL2!n5!n5!n11!c2!n|^BL(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2013-02-08|0 |
|
25 |
+GF|French Guyana|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|GF4120041010050500013M02606|GF2!n5!n5!n11!c2!n|^GF(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2013-08-28|1 |
|
26 |
+GP|Guadelope|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|GP1120041010050500013M02606|GP2!n5!n5!n11!c2!n|^GP(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2013-08-28|1 |
|
27 |
+MF|Saint Martin (French Part)|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|MF9820041010050500013M02606|MF2!n5!n5!n11!c2!n|^MF(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2013-02-08|0 |
|
28 |
+MQ|Martinique|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|MQ5120041010050500013M02606|MQ2!n5!n5!n11!c2!n|^MQ(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2013-08-28|1 |
|
29 |
+RE|Reunion|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|RE4220041010050500013M02606|RE2!n5!n5!n11!c2!n|^RE(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2013-08-28|1 |
|
30 |
+PF|French Polynesia|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|PF5720041010050500013M02606|PF2!n5!n5!n11!c2!n|^PF(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2011-06-20|0 |
|
31 |
+TF|French Southern Territories|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|TF2120041010050500013M02606|TF2!n5!n5!n11!c2!n|^TF(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2011-06-20|0 |
|
32 |
+YT|Mayotte|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|YT3120041010050500013M02606|YT2!n5!n5!n11!c2!n|^YT(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2013-08-28|1 |
|
33 |
+NC|New Caledonia|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|NC8420041010050500013M02606|NC2!n5!n5!n11!c2!n|^NC(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2011-06-20|0 |
|
34 |
+PM|Saint Pierre et Miquelon|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|PM3620041010050500013M02606|PM2!n5!n5!n11!c2!n|^PM(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2013-08-28|1 |
|
35 |
+WF|Wallis and Futuna Islands|20041 01005 0500013M026 06|20041010050500013M02606|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|WF9120041010050500013M02606|WF2!n5!n5!n11!c2!n|^WF(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2011-06-20|0 |
|
36 |
+GE|Georgia|0000000101904917|NB0000000101904917|2!a16!n|^([A-Z]{2})(\d{16})$|18|GE29NB0000000101904917|GE2!n2!a16!n|^GE(\d{2})([A-Z]{2})(\d{16})$|22|0|1|||2011-06-20|0 |
|
37 |
+DE|Germany|37040044-532013000|370400440532013000|8!n10!n|^(\d{8})(\d{10})$|18|DE89370400440532013000|DE2!n8!n10!n|^DE(\d{2})(\d{8})(\d{10})$|22|0|7|||2011-06-20|1 |
|
38 |
+GI|Gibraltar|0000 00007099 453|NWBK000000007099453|4!a15!c|^([A-Z]{4})([A-Za-z0-9]{15})$|19|GI75NWBK000000007099453|GI2!n4!a15!c|^GI(\d{2})([A-Z]{4})([A-Za-z0-9]{15})$|23|0|3|||2011-06-20|1 |
|
39 |
+GR|Greece|01250000000012300695|01101250000000012300695|3!n4!n16!c|^(\d{3})(\d{4})([A-Za-z0-9]{16})$|23|GR1601101250000000012300695|GR2!n3!n4!n16!c|^GR(\d{2})(\d{3})(\d{4})([A-Za-z0-9]{16})$|27|0|2|3|6|2011-06-20|1 |
|
40 |
+GT|Guatemala|01020000001210029690|TRAJ01020000001210029690|4!c20!c|^([A-Za-z0-9]{4})([A-Za-z0-9]{20})$|24|GT82TRAJ01020000001210029690|GT2!n4!c20!c|^GT(\d{2})([A-Za-z0-9]{4})([A-Za-z0-9]{20})$|28|0|3|||2012-05-29|0 |
|
41 |
+HU|Hungary|11773016-11111018-00000000|117730161111101800000000|3!n4!n1!n15!n1!n|^(\d{3})(\d{4})(\d{1})(\d{15})(\d{1})$|24|HU42117730161111101800000000|HU2!n3!n4!n1!n15!n1!n|^HU(\d{2})(\d{3})(\d{4})(\d{1})(\d{15})(\d{1})$|28|0|2|3|6|2011-06-20|1 |
|
42 |
+IS|Iceland|0159-26-007654-551073-0339|0159260076545510730339|4!n2!n6!n10!n|^(\d{4})(\d{2})(\d{6})(\d{10})$|22|IS140159260076545510730339|IS2!n4!n2!n6!n10!n|^IS(\d{2})(\d{4})(\d{2})(\d{6})(\d{10})$|26|0|3|6|11|2011-06-20|1 |
|
43 |
+IE|Ireland|93-11-52 12345678|AIBK93115212345678|4!a6!n8!n|^([A-Z]{4})(\d{6})(\d{8})$|18|IE29AIBK93115212345678|IE2!n4!a6!n8!n|^IE(\d{2})([A-Z]{4})(\d{6})(\d{8})$|22|0|3|4|9|2011-06-20|1 |
|
44 |
+IL|Israel|10-800-99999999|100800000099999000|3!n3!n13!n|^(\d{3})(\d{3})(\d{13})$|19|IL620108000000099999999|IL2!n3!n3!n13!n|^IL(\d{2})(\d{3})(\d{3})(\d{13})$|23|0|2|3|5|2011-06-20|0 |
|
45 |
+IT|Italy|X 05428 11101 000000123456|X0542811101000000123456|1!a5!n5!n12!c|^([A-Z]{1})(\d{5})(\d{5})([A-Za-z0-9]{12})$|23|IT60X0542811101000000123456|IT2!n1!a5!n5!n12!c|^IT(\d{2})([A-Z]{1})(\d{5})(\d{5})([A-Za-z0-9]{12})$|27|0|5|6|10|2011-06-20|1 |
|
46 |
+KZ|Kazakhstan|125K ZT50 0410 0100|125KZT5004100100|3!n13!c|^(\d{3})([A-Za-z0-9]{13})$|16|KZ86125KZT5004100100|KZ2!n3!n13!c|^KZ(\d{2})(\d{3})([A-Za-z0-9]{13})$|20|0|2|||2011-06-20|0 |
|
47 |
+KW|Kuwait|CBKU0000000000001234560101|CBKU0000000000001234560101|4!a22!c|^([A-Z]{4})([A-Za-z0-9]{22})$|26|KW81CBKU0000000000001234560101|KW2!n4!a22!n|^KW(\d{2})([A-Z]{4})(\d{22})$|30|0|3|||2011-06-20|0 |
|
48 |
+LV|Latvia|BANK 0000 4351 9500 1|BANK0000435195001|4!a13!c|^([A-Z]{4})([A-Za-z0-9]{13})$|17|LV80BANK0000435195001|LV2!n4!a13!c|^LV(\d{2})([A-Z]{4})([A-Za-z0-9]{13})$|21|0|3|||2011-06-20|1 |
|
49 |
+LB|Lebanon|01 001 901229114|0999 0000 0001 0019 0122 9114|4!n20!c|^(\d{4})([A-Za-z0-9]{20})$|24|LB62099900000001001901229114|LB2!n4!n20!c|^LB(\d{2})(\d{4})([A-Za-z0-9]{20})$|28|0|3|||2011-06-20|0 |
|
50 |
+LI|Liechtenstein|8810 2324013AA|088100002324013AA|5!n12!c|^(\d{5})([A-Za-z0-9]{12})$|19|LI21088100002324013AA|LI2!n5!n12!c|^LI(\d{2})(\d{5})([A-Za-z0-9]{12})$|21|0|4|||2012-05-29|1 |
|
51 |
+LT|Lithuania|1000 0111 0100 1000|10000011101001000|5!n11!n|^(\d{5})(\d{11})$|16|LT121000011101001000|LT2!n5!n11!n|^LT(\d{2})(\d{5})(\d{11})$|20|0|4|||2011-06-20|1 |
|
52 |
+LU|Luxembourg|0019 4006 4475 0000|0019400644750000|3!n13!c|^(\d{3})([A-Za-z0-9]{13})$|16|LU280019400644750000|LU2!n3!n13!c|^LU(\d{2})(\d{3})([A-Za-z0-9]{13})$|20|0|2|||2011-06-20|1 |
|
53 |
+MK|Macedonia|300 0000000424 25|250120000058984|3!n10!c2!n|^(\d{3})([A-Za-z0-9]{10})(\d{2})$|15|MK07250120000058984|MK2!n3!n10!c2!n|^MK(\d{2})(\d{3})([A-Za-z0-9]{10})(\d{2})$|19|0|2|||2012-05-29|0 |
|
54 |
+MT|Malta|12345MTLCAST001S|MALT011000012345MTLCAST001S|4!a5!n18!c|^([A-Z]{4})(\d{5})([A-Za-z0-9]{18})$|27|MT84MALT011000012345MTLCAST001S|MT2!n4!a5!n18!c|^MT(\d{2})([A-Z]{4})(\d{5})([A-Za-z0-9]{18})$|31|0|3|4|8|2011-06-20|1 |
|
55 |
+MR|Mauritania|00020 00101 00001234567 53|00020001010000123456753|5!n5!n11!n2!n|^(\d{5})(\d{5})(\d{11})(\d{2})$|23|MR1300020001010000123456753|MR135!n5!n11!n2!n|^MR13(\d{5})(\d{5})(\d{11})(\d{2})$|27|0|4|5|9|2011-06-20|0 |
|
56 |
+MU|Mauritius|BOMM 0101 1010 3030 0200 000M UR|BOMM0101101030300200000MUR|4!a2!n2!n12!n3!n3!a|^([A-Z]{4})(\d{2})(\d{2})(\d{12})(\d{3})([A-Z]{3})$|26|MU17BOMM0101101030300200000MUR|MU2!n4!a2!n2!n12!n3!n3!a|^MU(\d{2})([A-Z]{4})(\d{2})(\d{2})(\d{12})(\d{3})([A-Z]{3})$|30|0|5|6|7|2011-06-20|0 |
|
57 |
+MD|Moldova|00225100013104168|AG000225100013104168|2!c18!c|^([A-Za-z0-9]{2})([A-Za-z0-9]{18})$|20|MD24AG000225100013104168|MD2!n20!c|^MD(\d{2})([A-Za-z0-9]{20})$|24|0|1|||2012-09-09|0 |
|
58 |
+MC|Monaco|0011111000h|11222 00001 01234567890 30|5!n5!n11!c2!n|^(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|23|MC5811222000010123456789030|MC2!n5!n5!n11!c2!n|^MC(\d{2})(\d{5})(\d{5})([A-Za-z0-9]{11})(\d{2})$|27|0|4|5|9|2011-06-20|1 |
|
59 |
+ME|Montenegro|505 0000123456789 51|505000012345678951|3!n13!n2!n|^(\d{3})(\d{13})(\d{2})$|18|ME25505000012345678951|ME2!n3!n13!n2!n|^ME(\d{2})(\d{3})(\d{13})(\d{2})$|22|0|2|||2011-06-20|0 |
|
60 |
+NL|The Netherlands|041 71 64 300|ABNA0417164300|4!a10!n|^([A-Z]{4})(\d{10})$|14|NL91ABNA0417164300|NL2!n4!a10!n|^NL(\d{2})([A-Z]{4})(\d{10})$|18|0|3|4|3|2013-06-20|1 |
|
61 |
+NO|Norway|8601 11 17947|86011117947|4!n6!n1!n|^(\d{4})(\d{6})(\d{1})$|11|NO9386011117947|NO2!n4!n6!n1!n|^NO(\d{2})(\d{4})(\d{6})(\d{1})$|15|0|3|||2011-06-20|1 |
|
62 |
+PK|Pakistan|00260101036360|SCBL0000001123456702|4!a16!c|^([A-Z]{4})([A-Za-z0-9]{16})$|20|PK36SCBL0000001123456702|PK2!n4!a16!c|^PK(\d{2})([A-Z]{4})([A-Za-z0-9]{16})$|24|0|3|||2012-05-29|0 |
|
63 |
+PL|Poland|61 1090 1014 0000 0712 1981 2874|109010140000071219812874|8!n16!n|^(\d{8})(\d{16})$|24|PL61109010140000071219812874|PL2!n8!n16n|^PL(\d{2})(\d{8})(\d{1,16})$|28|0|7|||2011-06-20|1 |
|
64 |
+PS|Palestine|400123456702|PALS000000000400123456702|4!a21!c|^([A-Z]{4})([A-Za-z0-9]{21})$|25|PS92PALS000000000400123456702|PS2!n4!a21!c|^PS(\d{2})([A-Z]{4})([A-Za-z0-9]{21})$|29|0|3|||2013-09-05|0 |
|
65 |
+PT|Portugal|0002.0123.12345678901.54|000201231234567890154|4!n4!n11!n2!n|^(\d{4})(\d{4})(\d{11})(\d{2})$|21|PT50000201231234567890154|PT2!n4!n4!n11!n2!n|^PT(\d{2})(\d{4})(\d{4})(\d{11})(\d{2})$|25|0|3|4|7|2013-09-05|1 |
|
66 |
+RO|Romania|AAAA 1B31 0075 9384 0000|AAAA1B31007593840000|4!a16!c|^([A-Z]{4})([A-Za-z0-9]{16})$|20|RO49AAAA1B31007593840000|RO2!n4!a16!c|^RO(\d{2})([A-Z]{4})([A-Za-z0-9]{16})$|24|0|3|||2011-06-20|1 |
|
67 |
+SM|San Marino|U032 2509 8000 0000 0270 100|U0322509800000000270100|1!a5!n5!n12!c|^([A-Z]{1})(\d{5})(\d{5})([A-Za-z0-9]{12})$|23|SM86U0322509800000000270100|SM2!n1!a5!n5!n12!c|^SM(\d{2})([A-Z]{1})(\d{5})(\d{5})([A-Za-z0-9]{12})$|27|0|5|6|10|2011-06-20|0 |
|
68 |
+SA|Saudi Arabia|608010167519|80000000608010167519|2!n18!c|^(\d{2})([A-Za-z0-9]{18})$|20|SA0380000000608010167519|SA2!n2!n18!c|^SA(\d{2})(\d{2})([A-Za-z0-9]{18})$|24|0|1|||2012-05-29|0 |
|
69 |
+RS|Serbia|260-0056010016113-79|260005601001611379|3!n13!n2!n|^(\d{3})(\d{13})(\d{2})$|18|RS35260005601001611379|RS2!n3!n13!n2!n|^RS(\d{2})(\d{3})(\d{13})(\d{2})$|22|0|2|||2011-06-20|0 |
|
70 |
+SK|Slovak Republic|19-8742637541/1200|12000000198742637541|4!n6!n10!n|^(\d{4})(\d{6})(\d{10})$|20|SK3112000000198742637541|SK2!n4!n6!n10!n|^SK(\d{2})(\d{4})(\d{6})(\d{10})$|24|0|3|4|9|2011-06-20|1 |
|
71 |
+SI|Slovenia|2633 0001 2039 086|263300012039086|5!n8!n2!n|^(\d{5})(\d{8})(\d{2})$|15|SI56191000000123438|SI2!n5!n8!n2!n|^SI(\d{2})(\d{5})(\d{8})(\d{2})$|19|0|1|2|4|2012-09-09|1 |
|
72 |
+ES|Spain|2100 0418 45 0200051332|21000418450200051332|4!n4!n1!n1!n10!n|^(\d{4})(\d{4})(\d{1})(\d{1})(\d{10})$|20|ES9121000418450200051332|ES2!n4!n4!n1!n1!n10!n|^ES(\d{2})(\d{4})(\d{4})(\d{1})(\d{1})(\d{10})$|24|0|3|4|7|2013-09-05|1 |
|
73 |
+SE|Sweden|1234 12 3456 1|5000 0000 0583 9825 7466|3!n16!n1!n|^(\d{3})(\d{16})(\d{1})$|20|SE4550000000058398257466|SE2!n3!n16!n1!n|^SE(\d{2})(\d{3})(\d{16})(\d{1})$|24|0|2|||2011-06-20|1 |
|
74 |
+CH|Switzerland|762 1162-3852.957|00762011623852957|5!n12!c|^(\d{5})([A-Za-z0-9]{12})$|17|CH9300762011623852957|CH2!n5!n12!c|^CH(\d{2})(\d{5})([A-Za-z0-9]{12})$|21|0|4|||2011-06-20|1 |
|
75 |
+TN|Tunisia|10 006 0351835984788 31|10006035183598478831|2!n3!n13!n2!n|^(\d{2})(\d{3})(\d{13})(\d{2})$|20|TN5910006035183598478831|TN592!n3!n13!n2!n|^TN59(\d{2})(\d{3})(\d{13})(\d{2})$|24|0|1|2|4|2011-06-20|0 |
|
76 |
+TR|Turkey|0061 01299 1234567890123456789|0006100519786457841326|5!n1!c16!c|^(\d{5})([A-Za-z0-9]{1})([A-Za-z0-9]{16})$|22|TR330006100519786457841326|TR2!n5!n1!c16!c|^TR(\d{2})(\d{5})([A-Za-z0-9]{1})([A-Za-z0-9]{16})$|26|0|4|||2011-06-20|0 |
|
77 |
+AE|United Arab Emirates|1234567890123456|0331234567890123456|3!n16!n|^(\d{3})(\d{16})$|19|AE070331234567890123456|AE2!n3!n16!n|^AE(\d{2})(\d{3})(\d{16})$|23|0|2|||2011-06-20|0 |
|
78 |
+GB|United Kingdom|60-16-13 31926819|NWBK60161331926819|4!a6!n8!n|^([A-Z]{4})(\d{6})(\d{8})$|18|GB29NWBK60161331926819|GB2!n4!a6!n8!n|^GB(\d{2})([A-Z]{4})(\d{6})(\d{8})$|22|0|3|4|9|2011-06-20|1 |
|
79 |
+VG|British Virgin Islands|00000 12 345 678 901|VPVG0000012345678901|4!a16!n|^([A-Z]{4})(\d{16})$|20|VG96VPVG0000012345678901|VG2!n4!a16!n|^VG(\d{2})([A-Z]{4})(\d{16})$|24|0|3|||2012-05-29|0 |
... | ... |
@@ -0,0 +1,268 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+# this script converts the IBAN_registry.txt file's entries to registry.txt format (php-iban's required internal format). |
|
4 |
+ |
|
5 |
+# init |
|
6 |
+require_once(dirname(dirname(__FILE__)) . '/php-iban.php'); |
|
7 |
+date_default_timezone_set('UTC'); # mutes a warning |
|
8 |
+ |
|
9 |
+# read registry |
|
10 |
+$data = file_get_contents('IBAN_Registry.txt'); |
|
11 |
+if($data == '') { die("Couldn't read IBAN_Registry.txt - try downloading from the location described in the REGISTRY-URL file."); } |
|
12 |
+ |
|
13 |
+# print header line |
|
14 |
+print "country_code|country_name|domestic_example|bban_example|bban_format_swift|bban_format_regex|bban_length|iban_example|iban_format_swift|iban_format_regex|iban_length|bban_bankid_start_offset|bban_bankid_stop_offset|bban_branchid_start_offset|bban_branchid_stop_offset|registry_edition|country_sepa\n"; |
|
15 |
+ |
|
16 |
+# break in to lines |
|
17 |
+$lines = preg_split('/[\r\n]+/',$data); |
|
18 |
+ |
|
19 |
+# display |
|
20 |
+foreach($lines as $line) { |
|
21 |
+ # if it's not a blank line, and it's not the header row |
|
22 |
+ if($line != '' && !preg_match('/SEPA Country/',$line)) { |
|
23 |
+ # extract individual tab-separated fields |
|
24 |
+ $bits = explode("\t",$line); |
|
25 |
+ # remove quotes and superfluous whitespace on fields that have them. |
|
26 |
+ for($i=0;$i<count($bits);$i++) { |
|
27 |
+ $bits[$i] = preg_replace('/^"(.*)"$/','$1',$bits[$i]); |
|
28 |
+ $bits[$i] = preg_replace('/^ */','',$bits[$i]); |
|
29 |
+ $bits[$i] = preg_replace('/ *$/','',$bits[$i]); |
|
30 |
+ } |
|
31 |
+ # assigned fields to named variables |
|
32 |
+ list($country_name,$country_code,$domestic_example,$bban,$bban_structure,$bban_length,$bban_bi_position,$bban_bi_length,$bban_bi_example,$bban_example,$iban,$iban_structure,$iban_length,$iban_electronic_example,$iban_print_example,$country_sepa,$contact_details) = $bits; |
|
33 |
+ # sanitise |
|
34 |
+ $country_code = strtoupper(substr($country_code,0,2)); # sanitise comments away |
|
35 |
+ $bban_structure = preg_replace('/[:;]/','',$bban_structure); # errors seen in Germany, Hungary entries |
|
36 |
+ $iban_structure = preg_replace('/, .*$/','',$iban_structure); # duplicates for FO, GL seen in DK |
|
37 |
+ $iban_electronic_example = preg_replace('/, .*$/','',$iban_electronic_example); # duplicates for FO, GL seen in DK |
|
38 |
+ if($country_code=='MU') { |
|
39 |
+ $iban_electronic_example = str_replace(' ','',$iban_electronic_example); # MU example has a spurious space |
|
40 |
+ } |
|
41 |
+ if($country_code=='CZ') { |
|
42 |
+ $iban_electronic_example = preg_replace('/ \w{10,}+$/','',$iban_electronic_example); # extra example for CZ |
|
43 |
+ $iban_print_example = preg_replace('/^(CZ.. .... .... .... .... ....).*$/','$1',$iban_print_example); # extra example |
|
44 |
+ } |
|
45 |
+ if($country_code=='FI') { |
|
46 |
+ # remove additional example |
|
47 |
+ $iban_electronic_example = preg_replace('/ or .*$/','',$iban_electronic_example); |
|
48 |
+ # fix bban example to remove verbosity and match domestic example |
|
49 |
+ $bban = '12345600000785'; |
|
50 |
+ } |
|
51 |
+ $iban_print_example = preg_replace('/, .*$/','',$iban_print_example); # DK includes FO and GL examples in one record |
|
52 |
+ |
|
53 |
+ # debugging |
|
54 |
+ if(false) { |
|
55 |
+ print "[$country_name ($country_code)]\n"; |
|
56 |
+ print "Domestic account number example: $domestic_example\n"; |
|
57 |
+ print "BBAN structure: $bban_structure\n"; |
|
58 |
+ print "BBAN length: $bban_length\n"; |
|
59 |
+ print "BBAN bank identifier position: $bban_bi_position\n"; |
|
60 |
+ print "BBAN bank identifier length: $bban_bi_length\n"; |
|
61 |
+ print "BBAN bank identifier example: $bban_bi_example\n"; |
|
62 |
+ print "BBAN example: $bban_example\n"; |
|
63 |
+ print "IBAN structure: $iban_structure\n"; |
|
64 |
+ print "IBAN length: $iban_length\n"; |
|
65 |
+ print "IBAN electronic format example: $iban_electronic_example\n"; |
|
66 |
+ print "IBAN print format example: $iban_print_example\n"; |
|
67 |
+ print "SEPA country: $country_sepa\n"; |
|
68 |
+ print "Contact details: $contact_details\n\n"; |
|
69 |
+ } |
|
70 |
+ |
|
71 |
+ # calculate $bban_regex from $bban_structure |
|
72 |
+ $bban_regex = swift_to_regex($bban_structure); |
|
73 |
+ # calculate $iban_regex from $iban_structure |
|
74 |
+ $iban_regex = swift_to_regex($iban_structure); |
|
75 |
+ # calculate numeric $bban_length |
|
76 |
+ $bban_length = preg_replace('/[^\d]/','',$bban_length); |
|
77 |
+ # calculate numeric $iban_length |
|
78 |
+ $iban_length = preg_replace('/[^\d]/','',$iban_length); |
|
79 |
+ # calculate bban_bankid_<start|stop>_offset |
|
80 |
+ # .... First we have to parse the freetext $bban_bi_position, eg: |
|
81 |
+ # Bank Identifier 1-3, Branch Identifier |
|
82 |
+ # Position 1-2 |
|
83 |
+ # Positions 1-2 |
|
84 |
+ # Positions 1-3 |
|
85 |
+ # Positions 1-3 ;Branch is not available |
|
86 |
+ # Positions 1-3, Branch identifier |
|
87 |
+ # Positions 1-3, Branch identifier positions |
|
88 |
+ # Positions 1-4 |
|
89 |
+ # Positions 1-4, Branch identifier |
|
90 |
+ # Positions 1-4, Branch identifier positions |
|
91 |
+ # Positions 1-5 |
|
92 |
+ # Positions 1-5 (positions 1-2 bank identifier; positions 3-5 branch identifier). In case of payment institutions Positions 1-5, Branch identifier positions |
|
93 |
+ # Positions 1-6, Branch identifier positions |
|
94 |
+ # Positions 1-6. First two digits of bank identifier indicate the bank or banking group (For example, 1 or 2 for Nordea, 31 for Handelsbanken, 5 for cooperative banks etc) |
|
95 |
+ # Positions 1-7 |
|
96 |
+ # Positions 1-8 |
|
97 |
+ # Positions 2-6, Branch identifier positions |
|
98 |
+ # positions 1-3, Branch identifier positions |
|
99 |
+ # |
|
100 |
+ # ... our algorithm is as follows: |
|
101 |
+ # - find all <digit>-<digit> tokens |
|
102 |
+ preg_match_all('/(\d)-(\d\d?)/',$bban_bi_position,$matches); |
|
103 |
+ # - discard overlaps ({1-5,1-2,3-5} becomes {1-2,3-5}) |
|
104 |
+ $tmptokens = array(); |
|
105 |
+ for($j=0;$j<count($matches[0]);$j++) { |
|
106 |
+ #print "tmptokens was... " . print_r($tmptokens,1) . "\n"; |
|
107 |
+ $from = $matches[1][$j]; |
|
108 |
+ $to = $matches[2][$j]; |
|
109 |
+ # (if we don't yet have a match starting here, or it goes further, |
|
110 |
+ # overwrite the match-from-this-position record) |
|
111 |
+ if(!isset($tmptokens[$from]) || $to < $tmptokens[$from]) { |
|
112 |
+ $tmptokens[$from] = $to; |
|
113 |
+ } |
|
114 |
+ } |
|
115 |
+ unset($matches); # done |
|
116 |
+ # - assume the token starting from position 1 is the bank identifier |
|
117 |
+ # (or, if it does not exist, the token starting from position 2) |
|
118 |
+ $bban_bankid_start_offset = 0; # decrement 1 on assignment |
|
119 |
+ if(isset($tmptokens[1])) { |
|
120 |
+ $bban_bankid_stop_offset = $tmptokens[1]-1; # decrement 1 on assignment |
|
121 |
+ unset($tmptokens[1]); |
|
122 |
+ } |
|
123 |
+ else { |
|
124 |
+ $bban_bankid_stop_offset = $tmptokens[2]-1; # decrement 1 on assignment |
|
125 |
+ unset($tmptokens[2]); |
|
126 |
+ } |
|
127 |
+ # - assume any subsequent token, if present, is the branch identifier. |
|
128 |
+ $tmpkeys = array_keys($tmptokens); |
|
129 |
+ $start = array_shift($tmpkeys); |
|
130 |
+ unset($tmpkeys); # done |
|
131 |
+ $bban_branchid_start_offset=''; |
|
132 |
+ $bban_branchid_stop_offset=''; |
|
133 |
+ if($start!= '') { |
|
134 |
+ # we have a branch identifier! |
|
135 |
+ $bban_branchid_start_offset=$start-1; |
|
136 |
+ $bban_branchid_stop_offset=$tmptokens[$start]-1; |
|
137 |
+ } |
|
138 |
+ else { |
|
139 |
+ # (note: this codepath occurs for around two thirds of all records) |
|
140 |
+ # we have not yet found a branch identifier. HOWEVER, we can analyse the |
|
141 |
+ # structure of the BBAN to determine whether there is more than one |
|
142 |
+ # remaining non-tiny field (tiny fields on the end of a BBAN typically |
|
143 |
+ # being checksums) and, if so, assume that the first/shorter one is the |
|
144 |
+ # branch identifier. |
|
145 |
+ $reduced_bban_structure = preg_replace('/^\d+![nac]/','',$bban_structure); |
|
146 |
+ $tokens = swift_tokenize($reduced_bban_structure,1); |
|
147 |
+ # discard any tokens of length 1 or 2 |
|
148 |
+ for($t=0;$t<count($tokens[0]);$t++) { |
|
149 |
+ if($tokens[1][$t] < 3) { |
|
150 |
+ $tokens['discarded'][$t] = 1; |
|
151 |
+ } |
|
152 |
+ } |
|
153 |
+ # interesting fields are those that are not discarded... |
|
154 |
+ if(!isset($tokens['discarded'])) { |
|
155 |
+ $interesting_field_count = count($tokens[0]); } |
|
156 |
+ else { |
|
157 |
+ $interesting_field_count = (count($tokens[0])-count($tokens['discarded'])); |
|
158 |
+ } |
|
159 |
+ # ...if we have at least two of them, there's a branchid-type field |
|
160 |
+ if($interesting_field_count >= 2) { |
|
161 |
+ # now loop through until we assign the branchid start offset |
|
162 |
+ # (this occurs just after the first non-discarded field) |
|
163 |
+ $found=0; |
|
164 |
+ for($f=0; (($found==0) && ($f<count($tokens[0]))); $f++) { |
|
165 |
+ # if this is a non-discarded token, of >2 length... |
|
166 |
+ if((!isset($tokens['discarded'][$f]) || $tokens['discarded'][$f] != 1) && $tokens[1][$f]>2) { |
|
167 |
+ # ... then assign. |
|
168 |
+ $pre_offset = $bban_bankid_stop_offset+1; # this is the offset before we reduced the structure to remove the bankid field |
|
169 |
+ $bban_branchid_start_offset = $pre_offset + $tokens['offset'][$f]; |
|
170 |
+ $bban_branchid_stop_offset = $pre_offset + $tokens['offset'][$f] + $tokens[1][$f] - 1; # decrement by one on assignment |
|
171 |
+ $found=1; |
|
172 |
+ } |
|
173 |
+ } |
|
174 |
+ } |
|
175 |
+ } |
|
176 |
+ |
|
177 |
+ # calculate 1=Yes, 0=No for $country_sepa |
|
178 |
+ # NOTE: This is buggy due to the free inclusion of random text by the registry publishers. |
|
179 |
+ # Notably it requires modification for places like Finland and Portugal where these |
|
180 |
+ # comments are known to exist. |
|
181 |
+ if(strtolower($country_sepa)=='yes') { $country_sepa=1; } else { $country_sepa = 0; } |
|
182 |
+ # set registry edition |
|
183 |
+ $registry_edition = date('Y-m-d'); |
|
184 |
+ |
|
185 |
+ # now prepare generate our registry lines... |
|
186 |
+ $to_generate = array($country_code=>$country_name); |
|
187 |
+ if($country_code == 'DK') { |
|
188 |
+ $to_generate = array('DK'=>$country_name,'FO'=>'Faroe Islands','GL'=>'Greenland'); |
|
189 |
+ } |
|
190 |
+ elseif($country_code == 'FR') { |
|
191 |
+ $to_generate = array('FR'=>$country_name,'BL'=>'Saint Barthelemy','GF'=>'French Guyana','GP'=>'Guadelope','MF'=>'Saint Martin (French Part)','MQ'=>'Martinique','RE'=>'Reunion','PF'=>'French Polynesia','TF'=>'French Southern Territories','YT'=>'Mayotte','NC'=>'New Caledonia','PM'=>'Saint Pierre et Miquelon','WF'=>'Wallis and Futuna Islands'); |
|
192 |
+ } |
|
193 |
+ |
|
194 |
+ # output loop |
|
195 |
+ foreach($to_generate as $country_code=>$country_name) { |
|
196 |
+ # fixes for fields duplicating country code |
|
197 |
+ #print "CHECKSUM-BEFORE[$country_code] = $iban_electronic_example\n"; |
|
198 |
+ $iban_electronic_example = iban_set_checksum($country_code . substr($iban_electronic_example,2)); |
|
199 |
+ #print "CHECKSUM-AFTER[$country_code] = $iban_electronic_example\n"; |
|
200 |
+ $iban_structure = $country_code . substr($iban_structure,2); |
|
201 |
+ $iban_regex = '^' . $country_code . substr($iban_regex,3); |
|
202 |
+ # output |
|
203 |
+ print "$country_code|$country_name|$domestic_example|$bban_example|$bban_structure|$bban_regex|$bban_length|$iban_electronic_example|$iban_structure|$iban_regex|$iban_length|$bban_bankid_start_offset|$bban_bankid_stop_offset|$bban_branchid_start_offset|$bban_branchid_stop_offset|$registry_edition|$country_sepa\n"; |
|
204 |
+ } |
|
205 |
+ |
|
206 |
+ } |
|
207 |
+} |
|
208 |
+ |
|
209 |
+# swift_to_regex() |
|
210 |
+# converts the SWIFT IBAN format specifications to regular expressions |
|
211 |
+# eg: 4!n6!n1!n -> ^(\d{4})(\d{6})(\d{1})$ |
|
212 |
+function swift_to_regex($swift) { |
|
213 |
+ # first find tokens |
|
214 |
+ $matches = swift_tokenize($swift); |
|
215 |
+ # now replace bits |
|
216 |
+ $tr = '^' . $swift . '$'; |
|
217 |
+ # loop through each matched token |
|
218 |
+ for($i=0;$i<count($matches[0]);$i++) { |
|
219 |
+ # calculate replacement |
|
220 |
+ $replacement = '(TOKEN)'; |
|
221 |
+ # type 'n' |
|
222 |
+ if($matches[3][$i] == 'n') { |
|
223 |
+ $replacement = '(\d{length})'; |
|
224 |
+ } |
|
225 |
+ # type 'c' |
|
226 |
+ elseif($matches[3][$i] == 'c') { |
|
227 |
+ $replacement = '([A-Za-z0-9]{length})'; |
|
228 |
+ } |
|
229 |
+ # type 'a' |
|
230 |
+ elseif($matches[3][$i] == 'a') { |
|
231 |
+ $replacement = '([A-Z]{length})'; |
|
232 |
+#' . $matches[1][$i] . '})'; |
|
233 |
+ } |
|
234 |
+ else { |
|
235 |
+ print "unknown type: $matches[3][$i]\n"; |
|
236 |
+ exit(1); |
|
237 |
+ } |
|
238 |
+ # now add length indicator to the token |
|
239 |
+ $length = '(LENGTH)'; |
|
240 |
+ if($matches[2][$i] == '!') { |
|
241 |
+ $length = $matches[1][$i]; |
|
242 |
+ } |
|
243 |
+ else { |
|
244 |
+ $length = '1,' . $matches[1][$i]; |
|
245 |
+ } |
|
246 |
+ $replacement = preg_replace('/length/',$length,$replacement,1); |
|
247 |
+ # finally, replace the entire token with the replacement |
|
248 |
+ $tr = preg_replace('/' . $matches[0][$i] . '/',$replacement,$tr,1); |
|
249 |
+ } |
|
250 |
+ return $tr; |
|
251 |
+} |
|
252 |
+ |
|
253 |
+# swift_tokenize() |
|
254 |
+# fetch individual tokens in a swift structural string |
|
255 |
+function swift_tokenize($string,$calculate_offsets=0) { |
|
256 |
+ preg_match_all('/((?:\d*?[1-2])?\d)(!)?([anc])/',$string,$matches); |
|
257 |
+ if($calculate_offsets) { |
|
258 |
+ $current_offset=0; |
|
259 |
+ for($i=0;$i<count($matches[0]);$i++) { |
|
260 |
+ $matches['offset'][$i] = $current_offset; |
|
261 |
+ $current_offset+=$matches[1][$i]; |
|
262 |
+ } |
|
263 |
+ #print "ANALYSE[raw]: " . join(',',$matches['offset']); |
|
264 |
+ } |
|
265 |
+ return $matches; |
|
266 |
+} |
|
267 |
+ |
|
268 |
+?> |
... | ... |
@@ -0,0 +1,91 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+# Basic test script for the object-oriented version of the php-iban library |
|
4 |
+# - Exit status is 0 in case of success, or the number of failed tests |
|
5 |
+# in case of failure |
|
6 |
+ |
|
7 |
+# Engine configuration |
|
8 |
+# - first we enable error display |
|
9 |
+ini_set('display_errors',1); |
|
10 |
+# - next we ensure that all errors are displayed |
|
11 |
+ini_set('error_reporting',E_ALL); |
|
12 |
+ |
|
13 |
+# include the object oriented version of the library itself |
|
14 |
+require_once(dirname(dirname(__FILE__)) . '/oophp-iban.php'); |
|
15 |
+ |
|
16 |
+# display registry contents |
|
17 |
+#print_r($_iban_registry); |
|
18 |
+ |
|
19 |
+# init |
|
20 |
+$errors=0; |
|
21 |
+ |
|
22 |
+# Try to validate an invalid IBAN |
|
23 |
+$iban = "(@#(*@*ZV-This is NOT an IBAN!"; |
|
24 |
+$myIban = new IBAN($iban); |
|
25 |
+if($myIban->verify()) { |
|
26 |
+ print "ERROR: An invalid IBAN was validated!\n"; |
|
27 |
+ $errors++; |
|
28 |
+} |
|
29 |
+print "Hooray! - Invalid IBAN successfully rejected.\n\n"; |
|
30 |
+ |
|
31 |
+# Broken IIBAN |
|
32 |
+$broken_iiban = 'AA12011123ZS6'; |
|
33 |
+$myIban = new IBAN($broken_iiban); |
|
34 |
+$suggestions = $myIban->MistranscriptionSuggestions(); |
|
35 |
+if(count($suggestions)) { |
|
36 |
+ print "Hooray! Successfully derived '" . implode(',',$suggestions) . "' as likely transcription error source suggestion(s) for the incorrect IBAN $broken_iiban.\n"; |
|
37 |
+} |
|
38 |
+else { |
|
39 |
+ print "ERROR: Not able to ascertain suggested transcription error source(s) for $broken_iiban.\n"; |
|
40 |
+} |
|
41 |
+print "\n"; |
|
42 |
+ |
|
43 |
+# Get list of countries |
|
44 |
+$countries = $myIban->Countries(); |
|
45 |
+ |
|
46 |
+# Loop through the registry's examples, validating |
|
47 |
+foreach($countries as $countrycode) { |
|
48 |
+ |
|
49 |
+ # instantiate |
|
50 |
+ $myCountry = new IBANCountry($countrycode); |
|
51 |
+ |
|
52 |
+ # start section |
|
53 |
+ print "[$countrycode: " . $myCountry->Name() . "]\n"; |
|
54 |
+ |
|
55 |
+ # output remaining country properties |
|
56 |
+ print "Is a SEPA member? "; |
|
57 |
+ if($myCountry->IsSEPA()) { print "Yes"; } else { print "No"; } |
|
58 |
+ print ".\n"; |
|
59 |
+ |
|
60 |
+ # get example iban |
|
61 |
+ $myIban = new IBAN($myCountry->IBANExample()); |
|
62 |
+ |
|
63 |
+ # output example iban properties one by one |
|
64 |
+ print "Example IBAN: " . $myIban->HumanFormat() . "\n"; |
|
65 |
+ print " - country " . $myIban->Country() . "\n"; |
|
66 |
+ print " - checksum " . $myIban->Checksum() . "\n"; |
|
67 |
+ print " - bban " . $myIban->BBAN() . "\n"; |
|
68 |
+ print " - bank " . $myIban->Bank() . "\n"; |
|
69 |
+ print " - branch " . $myIban->Branch() . "\n"; |
|
70 |
+ print " - account " . $myIban->Account() . "\n"; |
|
71 |
+ |
|
72 |
+ # output all properties |
|
73 |
+ #$parts = $myIban->Parts(); |
|
74 |
+ #print_r($parts); |
|
75 |
+ |
|
76 |
+ # verify |
|
77 |
+ print "\nChecking validity... "; |
|
78 |
+ if($myIban->Verify()) { |
|
79 |
+ print "IBAN $myIban->iban is valid.\n"; |
|
80 |
+ } |
|
81 |
+ else { |
|
82 |
+ print "ERROR: IBAN $myIban->iban is invalid.\n"; |
|
83 |
+ $errors++; |
|
84 |
+ } |
|
85 |
+ |
|
86 |
+ print "\n"; |
|
87 |
+} |
|
88 |
+ |
|
89 |
+exit($errors); |
|
90 |
+ |
|
91 |
+?> |
... | ... |
@@ -0,0 +1,86 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+# Basic test script for the php-iban library |
|
4 |
+# - Exit status is 0 in case of success, or the number of failed tests |
|
5 |
+# in case of failure |
|
6 |
+ |
|
7 |
+# Engine configuration |
|
8 |
+# - first we enable error display |
|
9 |
+ini_set('display_errors',1); |
|
10 |
+# - next we ensure that all errors are displayed |
|
11 |
+ini_set('error_reporting',E_ALL); |
|
12 |
+ |
|
13 |
+# include the library itself |
|
14 |
+require_once(dirname(dirname(__FILE__)) . '/php-iban.php'); |
|
15 |
+ |
|
16 |
+# display registry contents |
|
17 |
+#print_r($_iban_registry); |
|
18 |
+ |
|
19 |
+# init |
|
20 |
+$errors=0; |
|
21 |
+ |
|
22 |
+# Try to validate an invalid IBAN |
|
23 |
+$iban = "(@#(*@*ZV-This is NOT an IBAN!"; |
|
24 |
+if(verify_iban($iban)) { |
|
25 |
+ print "ERROR: An invalid IBAN was validated!\n"; |
|
26 |
+ $errors++; |
|
27 |
+} |
|
28 |
+print "Hooray! - Invalid IBAN successfully rejected.\n\n"; |
|
29 |
+ |
|
30 |
+# Broken IIBAN |
|
31 |
+$broken_iiban = 'AA12011123ZS6'; |
|
32 |
+$suggestions = iban_mistranscription_suggestions($broken_iiban); |
|
33 |
+if(count($suggestions)) { |
|
34 |
+ print "Hooray! Successfully derived '" . implode(',',$suggestions) . "' as likely transcription error source suggestion(s) for the incorrect IBAN $broken_iiban.\n"; |
|
35 |
+} |
|
36 |
+else { |
|
37 |
+ print "ERROR: Not able to ascertain suggested transcription error source(s) for $broken_iiban.\n"; |
|
38 |
+} |
|
39 |
+print "\n"; |
|
40 |
+ |
|
41 |
+# Loop through the registry's examples, validating |
|
42 |
+foreach($_iban_registry as $country) { |
|
43 |
+ |
|
44 |
+ # get country code |
|
45 |
+ $countrycode = $country['country']; |
|
46 |
+ |
|
47 |
+ # start section |
|
48 |
+ print "[$countrycode: " . iban_country_get_country_name($countrycode) . "]\n"; |
|
49 |
+ |
|
50 |
+ # output remaining country properties |
|
51 |
+ print "Is a SEPA member? "; |
|
52 |
+ if(iban_country_is_sepa($countrycode)) { print "Yes"; } else { print "No"; } |
|
53 |
+ print ".\n"; |
|
54 |
+ |
|
55 |
+ # get example iban |
|
56 |
+ $iban = $country['iban_example']; |
|
57 |
+ |
|
58 |
+ # output example iban properties one by one |
|
59 |
+ print "Example IBAN: " . iban_to_human_format($iban) . "\n"; |
|
60 |
+ print " - country " . iban_get_country_part($iban) . "\n"; |
|
61 |
+ print " - checksum " . iban_get_checksum_part($iban) . "\n"; |
|
62 |
+ print " - bban " . iban_get_bban_part($iban) . "\n"; |
|
63 |
+ print " - bank " . iban_get_bank_part($iban) . "\n"; |
|
64 |
+ print " - branch " . iban_get_branch_part($iban) . "\n"; |
|
65 |
+ print " - account " . iban_get_account_part($iban) . "\n"; |
|
66 |
+ |
|
67 |
+ # output all properties |
|
68 |
+ #$parts = iban_get_parts($iban); |
|
69 |
+ #print_r($parts); |
|
70 |
+ |
|
71 |
+ # verify |
|
72 |
+ print "\nChecking validity... "; |
|
73 |
+ if(verify_iban($iban)) { |
|
74 |
+ print "IBAN $iban is valid.\n"; |
|
75 |
+ } |
|
76 |
+ else { |
|
77 |
+ print "ERROR: IBAN $iban is invalid.\n"; |
|
78 |
+ $errors++; |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ print "\n"; |
|
82 |
+} |
|
83 |
+ |
|
84 |
+exit($errors); |
|
85 |
+ |
|
86 |
+?> |
... | ... |
@@ -193,6 +193,11 @@ function in_homedir($path) |
193 | 193 |
return strncmp($_SESSION['userinfo']['homedir'], $path, count($_SESSION['userinfo']['homedir'])) == 0; |
194 | 194 |
} |
195 | 195 |
|
196 |
+function check_date( $input ) |
|
197 |
+{ |
|
198 |
+ return (bool) preg_match("/[0-9]{4}-(0?[1-9]|11|12)-([012]?[0-9]|30|31)/", $input); |
|
199 |
+} |
|
200 |
+ |
|
196 | 201 |
|
197 | 202 |
function check_emailaddr( $input ) |
198 | 203 |
{ |
... | ... |
@@ -72,5 +72,35 @@ if (! $show_paid) { |
72 | 72 |
output('<p>'.internal_link('upcoming', 'Zukünftige Rechnungsposten anzeigen').'</p>'); |
73 | 73 |
|
74 | 74 |
|
75 |
+output('<h3>Bezahlung per Lastschrift</h3>'); |
|
76 |
+ |
|
77 |
+output('<p>Gerne buchen wir Ihre Beiträge von Ihrem Konto ab. Bei Lastschriftzahlung werden Sie durch Zustellung einer Rechnung informiert, die Abbuchung erfolgt dann eine Woche später.</p>'); |
|
78 |
+ |
|
79 |
+$mandate = get_sepamandate(); |
|
80 |
+if ($mandate) { |
|
81 |
+ output('<p>Folgende Mandate sind bisher erteilt worden (momentan gültiges Mandat ist Fett dargestellt):</p> |
|
82 |
+<table> |
|
83 |
+<tr><th>Mandatsreferenz</th><th>IBAN</th><th>Gültigkeit</th></tr |
|
84 |
+'); |
|
85 |
+ foreach ($mandate as $m) { |
|
86 |
+ $gueltig = 'ab '.$m['gueltig_ab']; |
|
87 |
+ if ($m['gueltig_bis']) { |
|
88 |
+ $gueltig = $m['gueltig_ab'].' - '.$m['gueltig_bis']; |
|
89 |
+ } |
|
90 |
+ $aktiv = false; |
|
91 |
+ if ($m['gueltig_ab'] <= date('Y-m-d') && ($m['gueltig_bis'] == NULL || $m['gueltig_bis'] >= date('Y-m-d'))) { |
|
92 |
+ $aktiv = true; |
|
93 |
+ } |
|
94 |
+ output('<tr><td'.($aktiv ? ' style="font-weight: bold;"' : '').'>'.internal_link('sepamandat_detail', $m['mandatsreferenz'], 'ref='.$m['mandatsreferenz']).'</td><td>'.$m['iban'].'</td><td>'.$gueltig.'</td></tr>'); |
|
95 |
+ } |
|
96 |
+ output('</table>'); |
|
97 |
+} |
|
98 |
+ |
|
99 |
+ |
|
100 |
+addnew('sepamandat', 'Erteilen Sie uns ein Lastschrift-Mandat'); |
|
101 |
+ |
|
102 |
+output('<p>Sie können Ihr Mandat jederzeit widerrufen. Senden Sie uns dazu bitte eine entsprechende E-Mail.</p>'); |
|
103 |
+ |
|
104 |
+ |
|
75 | 105 |
|
76 | 106 |
?> |
... | ... |
@@ -17,6 +17,9 @@ Nevertheless, in case you use a significant part of this code, we ask (but not r |
17 | 17 |
require_once('inc/base.php'); |
18 | 18 |
require_once('inc/security.php'); |
19 | 19 |
|
20 |
+include("external/php-iban/php-iban.php"); |
|
21 |
+ |
|
22 |
+ |
|
20 | 23 |
function my_invoices() |
21 | 24 |
{ |
22 | 25 |
$c = (int) $_SESSION['customerinfo']['customerno']; |
... | ... |
@@ -161,6 +164,63 @@ function generate_bezahlcode_image($id) |
161 | 164 |
} |
162 | 165 |
|
163 | 166 |
|
167 |
+function get_sepamandate() |
|
168 |
+{ |
|
169 |
+ $cid = (int) $_SESSION['customerinfo']['customerno']; |
|
170 |
+ $result = db_query("SELECT id, mandatsreferenz, erteilt, medium, gueltig_ab, gueltig_bis, erstlastschrift, kontoinhaber, adresse, iban, bic, bankname FROM kundendaten.sepamandat WHERE kunde={$cid}"); |
|
171 |
+ $ret = array(); |
|
172 |
+ while ($entry = mysql_fetch_assoc($result)) { |
|
173 |
+ array_push($ret, $entry); |
|
174 |
+ } |
|
175 |
+ return $ret; |
|
176 |
+} |
|
177 |
+ |
|
178 |
+ |
|
179 |
+function yesterday($date) |
|
180 |
+{ |
|
181 |
+ $date = mysql_real_escape_string($date); |
|
182 |
+ $result = db_query("SELECT '{$date}' - INTERVAL 1 DAY"); |
|
183 |
+ return mysql_fetch_array($result)[0]; |
|
184 |
+} |
|
185 |
+ |
|
186 |
+ |
|
187 |
+function invalidate_sepamandat($id, $date) |
|
188 |
+{ |
|
189 |
+ $cid = (int) $_SESSION['customerinfo']['customerno']; |
|
190 |
+ $id = (int) $id; |
|
191 |
+ $date = mysql_real_escape_string($date); |
|
192 |
+ db_query("UPDATE kundendaten.sepamandat SET gueltig_bis='{$date}' WHERE id={$id} AND kunde={$cid}"); |
|
193 |
+} |
|
194 |
+ |
|
195 |
+ |
|
196 |
+function sepamandat($name, $adresse, $iban, $bankname, $bic, $gueltig_ab) |
|
197 |
+{ |
|
198 |
+ $cid = (int) $_SESSION['customerinfo']['customerno']; |
|
199 |
+ if ($gueltig_ab < date('Y-m-d')) { |
|
200 |
+ system_failure('Das Mandat kann nicht rückwirkend erteilt werden. Bitte geben Sie ein Datum in der Zukunft an.'); |
|
201 |
+ } |
|
202 |
+ $alte_mandate = get_sepamandate(); |
|
203 |
+ $referenzen = array(); |
|
204 |
+ foreach ($alte_mandate as $mandat) { |
|
205 |
+ if ($mandat['gueltig_bis'] == NULL || $mandat['gueltig_bis'] >= $gueltig_ab) { |
|
206 |
+ DEBUG('Altes Mandat wird für ungültig erklärt.'); |
|
207 |
+ DEBUG($mandat); |
|
208 |
+ invalidate_sepamandat($mandat['id'], yesterday($gueltig_ab)); |
|
209 |
+ } |
|
210 |
+ array_push($referenzen, $mandat['mandatsreferenz']); |
|
211 |
+ } |
|
212 |
+ $counter = 1; |
|
213 |
+ $referenz = sprintf('K%04d-M%03d', $cid, $counter); |
|
214 |
+ while (in_array($referenz, $referenzen)) { |
|
215 |
+ $counter++; |
|
216 |
+ $referenz = sprintf('K%04d-M%03d', $cid, $counter); |
|
217 |
+ } |
|
218 |
+ DEBUG('Nächste freie Mandatsreferenz: '. $referenz); |
|
219 |
+ |
|
220 |
+ $today = date('Y-m-d'); |
|
221 |
+ db_query("INSERT INTO kundendaten.sepamandat (mandatsreferenz, kunde, erteilt, medium, gueltig_ab, kontoinhaber, adresse, iban, bic, bankname) VALUES ('{$referenz}', {$cid}, '{$today}', 'online', '{$gueltig_ab}', '{$name}', '{$adresse}', '{$iban}', '{$bic}', '{$bankname}')"); |
|
222 |
+} |
|
223 |
+ |
|
224 |
+ |
|
164 | 225 |
|
165 |
-# bank://singlepaymentsepa?name=SCHOKOKEKS.ORG%20GBR&reason=RE%20256%20KD%2032%20vom%202008-03-01&iban=DE91602911200041512006&bic=GENODES1VBK&amount=45%2C00 |
|
166 | 226 |
?> |
... | ... |
@@ -0,0 +1,82 @@ |
1 |
+<?php |
|
2 |
+/* |
|
3 |
+This file belongs to the Webinterface of schokokeks.org Hosting |
|
4 |
+ |
|
5 |
+Written 2008-2013 by schokokeks.org Hosting, namely |
|
6 |
+ Bernd Wurst <bernd@schokokeks.org> |
|
7 |
+ Hanno Böck <hanno@schokokeks.org> |
|
8 |
+ |
|
9 |
+To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. |
|
10 |
+ |
|
11 |
+You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see |
|
12 |
+http://creativecommons.org/publicdomain/zero/1.0/ |
|
13 |
+ |
|
14 |
+Nevertheless, in case you use a significant part of this code, we ask (but not require, see the license) that you keep the authors' names in place and return your changes to the public. We would be especially happy if you tell us what you're going to do with this code. |
|
15 |
+*/ |
|
16 |
+ |
|
17 |
+require_role(ROLE_CUSTOMER); |
|
18 |
+ |
|
19 |
+require('invoice.php'); |
|
20 |
+require_once("inc/debug.php"); |
|
21 |
+global $debugmode; |
|
22 |
+ |
|
23 |
+$section = 'invoice_current'; |
|
24 |
+ |
|
25 |
+ |
|
26 |
+if ($_GET['action'] == 'new') |
|
27 |
+{ |
|
28 |
+ check_form_token('sepamandat_neu'); |
|
29 |
+ |
|
30 |
+ $gueltig_ab = $_REQUEST['gueltig_ab']; |
|
31 |
+ if ($gueltig_ab == 'datum') { |
|
32 |
+ $gueltig_ab = $_REQUEST['gueltig_ab_datum_year'].'-'.$_REQUEST['gueltig_ab_datum_month'].'-'.$_REQUEST['gueltig_ab_datum_day']; |
|
33 |
+ } |
|
34 |
+ if (! check_date($gueltig_ab)) { |
|
35 |
+ system_failure('Konnte das Datum nicht auslesen'); |
|
36 |
+ } |
|
37 |
+ DEBUG('Gültig ab: '.$gueltig_ab); |
|
38 |
+ |
|
39 |
+ if (empty($_REQUEST['kontoinhaber'])) { |
|
40 |
+ system_failure('Bitte geben Sie den Kontoinhaber so an, wie dies bei Ihrer Bank hinterlegt ist.'); |
|
41 |
+ } |
|
42 |
+ $name = $_REQUEST['kontoinhaber']; |
|
43 |
+ DEBUG('Kontoinhaber:'.$name); |
|
44 |
+ |
|
45 |
+ if (empty($_REQUEST['adresse'])) { |
|
46 |
+ system_failure('Bitte geben Sie die Adresse des Kontoinhabers an.'); |
|
47 |
+ } |
|
48 |
+ $adresse = $_REQUEST['adresse']; |
|
49 |
+ DEBUG('Adresse: '.$adresse); |
|
50 |
+ |
|
51 |
+ if (empty($_REQUEST['iban'])) { |
|
52 |
+ system_failure('Es wurde keine IBAN angegeben.'); |
|
53 |
+ } |
|
54 |
+ $iban = $_REQUEST['iban']; |
|
55 |
+ if (! verify_iban($iban)) { |
|
56 |
+ system_failure("Die IBAN scheint nicht korrekt zu sein!"); |
|
57 |
+ } |
|
58 |
+ DEBUG('IBAN: '.$iban); |
|
59 |
+ |
|
60 |
+ $bankname = $_REQUEST['bankname']; |
|
61 |
+ if (empty($_REQUEST['bankname'])) { |
|
62 |
+ system_failure('Bitte geben Sie den Namen der Bank an.'); |
|
63 |
+ } |
|
64 |
+ DEBUG('Bank: '.$bankname); |
|
65 |
+ |
|
66 |
+ $bic = NULL; |
|
67 |
+ if (empty($_REQUEST['bic'])) { |
|
68 |
+ if (substr($iban, 0, 2) == 'DE') { |
|
69 |
+ $bic=NULL; |
|
70 |
+ } else { |
|
71 |
+ system_failure('Sie haben keinen BIC angegeben. Für Konten außerhalb Deutschlands ist ein BIC weiterhin erforderlich.'); |
|
72 |
+ } |
|
73 |
+ } else { |
|
74 |
+ $bic = $_REQUEST['bic']; |
|
75 |
+ } |
|
76 |
+ DEBUG('BIC: '.$bic); |
|
77 |
+ |
|
78 |
+ |
|
79 |
+ sepamandat($name, $adresse, $iban, $bankname, $bic, $gueltig_ab); |
|
80 |
+ |
|
81 |
+ redirect($prefix.'go/invoice/current'); |
|
82 |
+} |
... | ... |
@@ -0,0 +1,75 @@ |
1 |
+<?php |
|
2 |
+/* |
|
3 |
+This file belongs to the Webinterface of schokokeks.org Hosting |
|
4 |
+ |
|
5 |
+Written 2008-2013 by schokokeks.org Hosting, namely |
|
6 |
+ Bernd Wurst <bernd@schokokeks.org> |
|
7 |
+ Hanno Böck <hanno@schokokeks.org> |
|
8 |
+ |
|
9 |
+To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. |
|
10 |
+ |
|
11 |
+You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see |
|
12 |
+http://creativecommons.org/publicdomain/zero/1.0/ |
|
13 |
+ |
|
14 |
+Nevertheless, in case you use a significant part of this code, we ask (but not require, see the license) that you keep the authors' names in place and return your changes to the public. We would be especially happy if you tell us what you're going to do with this code. |
|
15 |
+*/ |
|
16 |
+ |
|
17 |
+require_once('invoice.php'); |
|
18 |
+ |
|
19 |
+require_role(ROLE_CUSTOMER); |
|
20 |
+$section = 'invoice_current'; |
|
21 |
+ |
|
22 |
+title('Erteilung eines Mandats zur SEPA-Basis-Lastschrift'); |
|
23 |
+ |
|
24 |
+output('<p>Ich ermächtige die Firma schokokeks.org GbR, Zahlungen von meinem Konto mittels Lastschrift |
|
25 |
+einzuziehen. Zugleich weise ich mein Kreditinstitut an, die von der Firma schokokeks.org GbR auf mein |
|
26 |
+Konto gezogenen Lastschriften einzulösen.</p> |
|
27 |
+<p>Hinweis: Ich kann innerhalb von acht Wochen, beginnend mit dem Belastungsdatum, die Erstattung des |
|
28 |
+belasteten Betrages verlangen. Es gelten dabei diemit meinem Kreditinstitut vereinbarten Bedingungen. |
|
29 |
+Insbesondere fallen bei Zurückweisung einer gerechtfertigten Abbuchung i.d.R. Gebühren an.</p>'); |
|
30 |
+ |
|
31 |
+$name = $_SESSION['customerinfo']['name']; |
|
32 |
+if ($_SESSION['customerinfo']['company']) { |
|
33 |
+ if ($_SESSION['customerinfo']['name']) { |
|
34 |
+ $name = $_SESSION['customerinfo']['company'] .' / '. $_SESSION['customerinfo']['name']; |
|
35 |
+ } else { |
|
36 |
+ $name = $_SESSION['customerinfo']['company']; |
|
37 |
+ } |
|
38 |
+} |
|
39 |
+output('<p>Dieses Mandat gilt für Forderungen bzgl. der Kundennummer <strong>'.$_SESSION['customerinfo']['customerno'].'</strong> ('.$name.'). Sämtliche Forderungen werden mindestens 6 Bankarbeitstage vor Fälligkeit angekündigt. Diese Ankündigung erfolgt in der Regel durch Zusendung einer Rechnung per E-Mail.</p>'); |
|
40 |
+ |
|
41 |
+ |
|
42 |
+ |
|
43 |
+$first_date = date('Y-m-d'); |
|
44 |
+$invoices = my_invoices(); |
|
45 |
+foreach ($invoices as $i) { |
|
46 |
+ if ($i['bezahlt'] == 0 && $i['datum'] < $first_date) { |
|
47 |
+ $first_date = $i['datum']; |
|
48 |
+ } |
|
49 |
+} |
|
50 |
+ |
|
51 |
+$html = '<h4>Gültigkeit des Mandats</h4>'; |
|
52 |
+$checked = False; |
|
53 |
+if ($first_date != date('Y-m-d')) { |
|
54 |
+ $checked = True; |
|
55 |
+ $html .= '<p><input type="radio" id="gueltig_ab_'.$first_date.'" name="gueltig_ab" value="'.$first_date.'" checked="checked" /><label for="gueltig_ab_'.$first_date.'">Dieses Mandat gilt <strong>ab '.$first_date.'</strong> (Alle bisher offenen Forderungen werden ebenfalls abgebucht)</label></p>'; |
|
56 |
+} |
|
57 |
+$html .= '<p><input type="radio" id="gueltig_ab_heute" name="gueltig_ab" value="'.date('Y-m-d').'" '.($checked ? '' : 'checked="checked"').' /><label for="gueltig_ab_heute">Dieses Mandat gilt <strong>ab heute</strong> ('.date('Y-m-d').')</label></p>'; |
|
58 |
+$html .= '<p><input type="radio" id="gueltig_ab_datum" name="gueltig_ab" value="datum" /><label for="gueltig_ab_datum">Dieses Mandat gilt <strong>erst ab</strong></label> '.html_datepicker("gueltig_ab_datum", time()).' (Ein eventuell zuvor erteiltes Mandat wird zu diesem Datum automatisch ungültig.)</p>'; |
|
59 |
+ |
|
60 |
+$html .= '<h4>Ihre Bankverbindung</h4>'; |
|
61 |
+$html .= '<table> |
|
62 |
+<tr><td><label for="kontoinhaber">Name des Kontoinhabers:</label></td><td><input type="text" name="kontoinhaber" id="kontoinhaber" value="'.$_SESSION['customerinfo']['name'].'" /></td></tr> |
|
63 |
+<tr><td><label for="adresse">Adresse des Kontoinhabers:</label></td><td><textarea cols="50" lines="2" name="adresse" id="adresse"></textarea></td></tr> |
|
64 |
+<tr><td><label for="iban">IBAN:</label></td><td><input type="text" name="iban" id="iban" /></td></tr> |
|
65 |
+<tr><td><label for="bankname">Name der Bank:</label></td><td><input type="text" name="bankname" id="bankname" /></td></tr> |
|
66 |
+<tr><td><label for="bic">BIC:</label></td><td><input type="text" name="bic" id="bic" /></td></tr> |
|
67 |
+</table>'; |
|
68 |
+ |
|
69 |
+$html .= '<p><input type="submit" value="Mandat erteilen" /></p>'; |
|
70 |
+ |
|
71 |
+ |
|
72 |
+output(html_form('sepamandat_neu', 'save', 'action=new', $html)); |
|
73 |
+ |
|
74 |
+ |
|
75 |
+?> |
... | ... |
@@ -0,0 +1,93 @@ |
1 |
+<?php |
|
2 |
+/* |
|
3 |
+This file belongs to the Webinterface of schokokeks.org Hosting |
|
4 |
+ |
|
5 |
+Written 2008-2013 by schokokeks.org Hosting, namely |
|
6 |
+ Bernd Wurst <bernd@schokokeks.org> |
|
7 |
+ Hanno Böck <hanno@schokokeks.org> |
|
8 |
+ |
|
9 |
+To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. |
|
10 |
+ |
|
11 |
+You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see |
|
12 |
+http://creativecommons.org/publicdomain/zero/1.0/ |
|
13 |
+ |
|
14 |
+Nevertheless, in case you use a significant part of this code, we ask (but not require, see the license) that you keep the authors' names in place and return your changes to the public. We would be especially happy if you tell us what you're going to do with this code. |
|
15 |
+*/ |
|
16 |
+ |
|
17 |
+require_once('invoice.php'); |
|
18 |
+ |
|
19 |
+require_role(ROLE_CUSTOMER); |
|
20 |
+$section = 'invoice_current'; |
|
21 |
+ |
|
22 |
+title('Daten Ihres Lastschrift-Mandats'); |
|
23 |
+ |
|
24 |
+$ref = $_REQUEST['ref']; |
|
25 |
+$mandate = get_sepamandate(); |
|
26 |
+$m = NULL; |
|
27 |
+ |
|
28 |
+foreach ($mandate as $man) { |
|
29 |
+ if ($man['mandatsreferenz'] == $ref) { |
|
30 |
+ $m = $man; |
|
31 |
+ } |
|
32 |
+} |
|
33 |
+if (! $m) { |
|
34 |
+ system_failure('Konnte das Mandat nicht finden.'); |
|
35 |
+} |
|
36 |
+ |
|
37 |
+if ($m['medium'] == 'legacy') { |
|
38 |
+ output('<p>Sie hatten uns vor längerer Zeit eine Einzugsermächtigung ausgesprochen. Wir haben diese selbstständig in das nachstehende SEPA-Mandat überführt.</p>'); |
|
39 |
+} else { |
|
40 |
+ $medium = 'über unser Webinterface'; |
|
41 |
+ switch ($m['medium']) { |
|
42 |
+ case 'email': |
|
43 |
+ $medium = 'per E-Mail'; |
|
44 |
+ break; |
|
45 |
+ case 'fax': |
|
46 |
+ $medium = 'per Fax'; |
|
47 |
+ break; |
|
48 |
+ case 'post': |
|
49 |
+ $medium = 'per Post'; |
|
50 |
+ break; |
|
51 |
+ } |
|
52 |
+ output('<p>Wir haben das nachstehende Mandat am '.$m['erteilt'].' '.$medium.' entgegen genommen.</p>'); |
|
53 |
+} |
|
54 |
+output('<h3>Stammdaten</h3> |
|
55 |
+<dl> |
|
56 |
+<dt>Mandatsreferenz</dt><dd>'.$m['mandatsreferenz'].'</dd> |
|
57 |
+<dt>Unsere Gläubiger-ID<dt><dd>'.config('glaeubiger_id').'</dd> |
|
58 |
+</dl>'); |
|
59 |
+ |
|
60 |
+output('<h3>Gültigkeit</h3>'); |
|
61 |
+ |
|
62 |
+$gueltigkeit = 'ab '.$m['gueltig_ab']; |
|
63 |
+if ($m['gueltig_bis']) { |
|
64 |
+ $gueltigkeit = 'von '.$m['gueltig_ab'].' bis '.$m['gueltig_bis']; |
|
65 |
+} |
|
66 |
+if ($m['gueltig_ab'] <= date('Y-m-d') && ($m['gueltig_bis'] == NULL || $m['gueltig_bis'] >= date('Y-m-d'))) { |
|
67 |
+ output('<p>Das Mandat ist momentan gültig ('.$gueltigkeit.').</p>'); |
|
68 |
+} elseif ($m['gueltig_ab'] > date('Y-m-d')) { |
|
69 |
+ output('<p>Das Mandat ist noch nicht gültig ('.$gueltigkeit.').</p>'); |
|
70 |
+} else { |
|
71 |
+ output('<p>Das Mandat ist erloschen ('.$gueltigkeit.').</p>'); |
|
72 |
+} |
|
73 |
+ |
|
74 |
+if ($m['erstlastschrift'] == NULL) { |
|
75 |
+ output('<p>Es wurden bisher keine Abbuchungen mit Bezug auf dieses Mandat durchgeführt.</p>'); |
|
76 |
+} elseif ($m['letztelastschrift'] != NULL) { |
|
77 |
+ output('<p>Dieses Mandat wurde zuletzt für eine Abbuchung am '.$m['letztelastschrift'].' in Anspruch genommen.</p>'); |
|
78 |
+} |
|
79 |
+ |
|
80 |
+ |
|
81 |
+output('<h3>Kontodaten</h3> |
|
82 |
+<dl> |
|
83 |
+<dt>Kontoinhaber</dt><dd>'.$m['kontoinhaber'].'</dd> |
|
84 |
+<dt>Adresse des Kontoinhabers</dt><dd>'.nl2br($m['adresse']).'</dd> |
|
85 |
+<dt>IBAN</dt><dd>'.$m['iban'].'</dd> |
|
86 |
+<dt>Name der Bank</dt><dd>'.$m['bankname'].'</dd> |
|
87 |
+<dt>BIC</dt><dd>'.$m['bic'].'</dd> |
|
88 |
+</dl>'); |
|
89 |
+ |
|
90 |
+ |
|
91 |
+output('<p>'.internal_link('current', 'Zurück').'</p>'); |
|
92 |
+ |
|
93 |
+?> |
|
0 | 94 |