" --unicode-subst="" 'IBAN_Registry.txt'`; if($data == '') { die("Couldn't read IBAN_Registry.txt - try downloading from the location described in the REGISTRY-URL file."); } # print header line 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"; # break in to lines $lines = preg_split('/[\r\n]+/',$data); # display foreach($lines as $line) { # if it's not a blank line, and it's not the header row if($line != '' && !preg_match('/SEPA Country/',$line)) { # extract individual tab-separated fields $bits = explode("\t",$line); # remove quotes and superfluous whitespace on fields that have them. for($i=0;$i_offset # .... First we have to parse the freetext $bban_bi_position, eg: # Bank Identifier 1-3, Branch Identifier # Position 1-2 # Positions 1-2 # Positions 1-3 # Positions 1-3 ;Branch is not available # Positions 1-3, Branch identifier # Positions 1-3, Branch identifier positions # Positions 1-4 # Positions 1-4, Branch identifier # Positions 1-4, Branch identifier positions # Positions 1-5 # Positions 1-5 (positions 1-2 bank identifier; positions 3-5 branch identifier). In case of payment institutions Positions 1-5, Branch identifier positions # Positions 1-6, Branch identifier positions # 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) # Positions 1-7 # Positions 1-8 # Positions 2-6, Branch identifier positions # positions 1-3, Branch identifier positions # # ... our algorithm is as follows: # - find all - tokens preg_match_all('/(\d)-(\d\d?)/',$bban_bi_position,$matches); # - discard overlaps ({1-5,1-2,3-5} becomes {1-2,3-5}) $tmptokens = array(); for($j=0;$j= 2) { # now loop through until we assign the branchid start offset # (this occurs just after the first non-discarded field) $found=0; for($f=0; (($found==0) && ($f2 length... if((!isset($tokens['discarded'][$f]) || $tokens['discarded'][$f] != 1) && $tokens[1][$f]>2) { # ... then assign. $pre_offset = $bban_bankid_stop_offset+1; # this is the offset before we reduced the structure to remove the bankid field $bban_branchid_start_offset = $pre_offset + $tokens['offset'][$f]; $bban_branchid_stop_offset = $pre_offset + $tokens['offset'][$f] + $tokens[1][$f] - 1; # decrement by one on assignment $found=1; } } } } # fix for Jordan if($country_code == 'JO') { $bban_bankid_start_offset = 0; $bban_bankid_stop_offset = 3; $bban_branchid_start_offset = 4; $bban_branchid_stop_offset = 7; } # calculate 1=Yes, 0=No for $country_sepa # NOTE: This is buggy due to the free inclusion of random text by the registry publishers. # Notably it requires modification for places like Finland and Portugal where these # comments are known to exist. if(strtolower($country_sepa)=='yes') { $country_sepa=1; } else { $country_sepa = 0; } # set registry edition $registry_edition = date('Y-m-d'); # now prepare generate our registry lines... $to_generate = array($country_code=>$country_name); if($country_code == 'DK') { $to_generate = array('DK'=>$country_name,'FO'=>'Faroe Islands','GL'=>'Greenland'); } elseif($country_code == 'FR') { $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'); } # output loop foreach($to_generate as $country_code=>$country_name) { # fixes for fields duplicating country code #print "CHECKSUM-BEFORE[$country_code] = $iban_electronic_example\n"; $iban_electronic_example = iban_set_checksum($country_code . substr($iban_electronic_example,2)); #print "CHECKSUM-AFTER[$country_code] = $iban_electronic_example\n"; $iban_structure = $country_code . substr($iban_structure,2); # step 1 $iban_regex_fixed = '^' . $country_code; $tmp_country_code = substr($iban_regex,1,2); #print "[DEBUG] $tmp_country_code\n"; # route #1 ... here we are dealing with a country code in the string already if(preg_match('/^[A-Z][A-Z]$/',$tmp_country_code)) { #print "[DEBUG] route #1\n"; $iban_regex_fixed = $iban_regex_fixed . substr($iban_regex,3); } # route #2 ... here there is no country code yet present else { #print "[DEBUG] route #2\n"; $iban_regex_fixed = $iban_regex_fixed . substr($iban_regex,1); } #print "[DEBUG] substited '$iban_regex_fixed' for '$iban_regex'\n"; # output print "$country_code|$country_name|$domestic_example|$bban_example|$bban_structure|$bban_regex|$bban_length|$iban_electronic_example|$iban_structure|$iban_regex_fixed|$iban_length|$bban_bankid_start_offset|$bban_bankid_stop_offset|$bban_branchid_start_offset|$bban_branchid_stop_offset|$registry_edition|$country_sepa\n"; } } } # swift_to_regex() # converts the SWIFT IBAN format specifications to regular expressions # eg: 4!n6!n1!n -> ^(\d{4})(\d{6})(\d{1})$ function swift_to_regex($swift) { # first find tokens $matches = swift_tokenize($swift); # now replace bits $tr = '^' . $swift . '$'; # loop through each matched token for($i=0;$i