1<?php 2/* vim: set expandtab tabstop=4 shiftwidth=4: */ 3/** 4 * Financial functions for validation and calculation 5 * 6 * PHP Versions 4 and 5 7 * 8 * This source file is subject to version 3.01 of the PHP license, 9 * that is bundled with this package in the file LICENSE, and is 10 * available through the world-wide-web at the following URI: 11 * http://www.php.net/license/3_01.txt 12 * If you did not receive a copy of the PHP license and are unable to 13 * obtain it through the world-wide-web, please send a note to 14 * license@php.net so we can mail you a copy immediately. 15 * 16 * @category Validate 17 * @package Validate_Finance 18 * @author Stefan Neufeind <pear.neufeind@speedpartner.de> 19 * @copyright 1997-2009 The PHP Group 20 * @license http://www.php.net/license/3_01.txt PHP License 3.01 21 * @version SVN: $Id$ 22 * @link http://pear.php.net/package/Validate_Finance 23 */ 24 25// needed for call to isError() 26require_once 'PEAR.php'; 27 28/* 29 * Error codes for the IBAN interface, which will be mapped to textual messages 30 * in the IBAN::errorMessage() function. If you are to add a new error code, be 31 * sure to add the textual messages to the IBAN::errorMessage() function as well 32 */ 33 34define('VALIDATE_FINANCE_IBAN_OK', 1); 35define('VALIDATE_FINANCE_IBAN_ERROR', -1); 36define('VALIDATE_FINANCE_IBAN_GENERAL_INVALID', -2); 37define('VALIDATE_FINANCE_IBAN_TOO_SHORT', -4); 38define('VALIDATE_FINANCE_IBAN_TOO_LONG', -5); 39define('VALIDATE_FINANCE_IBAN_COUNTRY_INVALID', -6); 40// tested via regex; e.g. if un-allowed characters in IBAN 41define('VALIDATE_FINANCE_IBAN_INVALID_FORMAT', -7); 42define('VALIDATE_FINANCE_IBAN_CHECKSUM_INVALID', -8); 43 44/** 45 * Validate and process IBAN (international bank account numbers) 46 * 47 * @category File_Formats 48 * @package Validate_Finance 49 * @author Stefan Neufeind <pear.neufeind@speedpartner.de> 50 * @copyright 1997-2009 The PHP Group 51 * @license http://www.php.net/license/3_01.txt PHP License 3.01 52 * @link http://pear.php.net/package/Validate_Finance 53 */ 54class Validate_Finance_IBAN 55{ 56 /** 57 * String containing the IBAN to be processed 58 * @var string 59 * @access private 60 */ 61 var $_iban = ''; 62 63 /** 64 * Integer containing errorcode of last validation 65 * @var integer 66 * @access private 67 */ 68 var $_errorcode = 0; 69 70 /** 71 * List of all IBAN countrycodes; also gives corresponding countrynames (in 72 * long form) 73 * 74 * @return array 75 * @access private 76 */ 77 function _getCountrycodeCountryname() 78 { 79 static $_iban_countrycode_countryname; 80 if (!isset($_iban_countrycode_countryname)) { 81 $_iban_countrycode_countryname = array( 82 'AD' => 'Andorra', 83 'AE' => 'United Arab Emirates', 84 'AL' => 'Albania', 85 'AT' => 'Austria', 86 'BA' => 'Bosnia and Herzegovina', 87 'BE' => 'Belgium', 88 'BG' => 'Bulgaria', 89 'CH' => 'Switzerland', 90 'CY' => 'Cyprus', 91 'CZ' => 'Czech Republic', 92 'DE' => 'Germany', 93 'DK' => 'Denmark', 94 'EE' => 'Estonia', 95 'ES' => 'Spain', 96 'FR' => 'France', 97 'FI' => 'Finland', 98 'GB' => 'United Kingdom', 99 'GE' => 'Georgia', 100 'GI' => 'Gibraltar', 101 'GR' => 'Greece', 102 'HR' => 'Croatia', 103 'HU' => 'Hungary', 104 'IE' => 'Ireland', 105 'IL' => 'Israel', 106 'IS' => 'Iceland', 107 'IT' => 'Italy', 108 'KW' => 'Kuwait', 109 'LB' => 'Lebanon', 110 'LI' => 'Liechtenstein', 111 'LT' => 'Lithuania', 112 'LU' => 'Luxembourg', 113 'LV' => 'Latvia', 114 'MC' => 'Monaco', 115 'ME' => 'Montenegro', 116 'MK' => 'Macedonia', 117 'MR' => 'Mauritania', 118 'MT' => 'Malta', 119 'MU' => 'Mauritius', 120 'NL' => 'The Netherlands', 121 'NO' => 'Norwegian', 122 'PL' => 'Poland', 123 'PT' => 'Portugal', 124 'RO' => 'Romania', 125 'RS' => 'Serbia', 126 'SA' => 'Saudi Arabia', 127 'SE' => 'Sweden', 128 'SI' => 'Slovenia', 129 'SK' => 'Slovak Republic', 130 'SM' => 'San Marino', 131 'TN' => 'Tunisia', 132 'TR' => 'Turkey', 133 ); 134 } 135 return $_iban_countrycode_countryname; 136 } 137 138 /** 139 * List of IBAN length; can be used for a quick check 140 * 141 * @return array 142 * @access private 143 */ 144 function _getCountrycodeIBANLength() 145 { 146 static $_iban_countrycode_length; 147 if (!isset($_iban_countrycode_length)) { 148 $_iban_countrycode_length = array( 149 'AD' => 24, 150 'AE' => 23, 151 'AL' => 28, 152 'AT' => 20, 153 'BA' => 20, 154 'BE' => 16, 155 'BG' => 22, 156 'CH' => 21, 157 'CY' => 28, 158 'CZ' => 24, 159 'DE' => 22, 160 'DK' => 18, 161 'EE' => 20, 162 'ES' => 24, 163 'FR' => 27, 164 'FI' => 18, 165 'GB' => 22, 166 'GE' => 22, 167 'GI' => 23, 168 'GR' => 27, 169 'HR' => 21, 170 'HU' => 28, 171 'IE' => 22, 172 'IL' => 23, 173 'IS' => 26, 174 'IT' => 27, 175 'KW' => 30, 176 'LB' => 28, 177 'LI' => 21, 178 'LT' => 20, 179 'LU' => 20, 180 'LV' => 21, 181 'MC' => 27, 182 'ME' => 22, 183 'MK' => 19, 184 'MR' => 27, 185 'MT' => 31, 186 'MU' => 30, 187 'NL' => 18, 188 'NO' => 15, 189 'PL' => 28, 190 'PT' => 25, 191 'RO' => 24, 192 'RS' => 22, 193 'SA' => 24, 194 'SE' => 24, 195 'SI' => 19, 196 'SK' => 24, 197 'SM' => 27, 198 'TN' => 24, 199 'TR' => 26, 200 ); 201 } 202 return $_iban_countrycode_length; 203 } 204 205 /** 206 * List of where the bankcode inside an IBAN starts (starting from 0) and 207 * its length 208 * 209 * @return array 210 * @access private 211 */ 212 function _getCountrycodeBankcode() 213 { 214 static $_iban_countrycode_bankcode; 215 if (!isset($_iban_countrycode_bankcode)) { 216 $_iban_countrycode_bankcode = array( 217 //AD: first 4 chars bankcode, last 4 chars branch 218 'AD' => array('start' => 4, 'length' => 8), 219 'AE' => array('start' => 4, 'length' => 3), 220 //AL: first 3 chars bankcode, next 4 chars branch, one char checksum 221 'AL' => array('start' => 4, 'length' => 8), 222 'AT' => array('start' => 4, 'length' => 5), 223 //BA: first 3 chars bankcode, last 3 chars branch 224 'BA' => array('start' => 4, 'length' => 6), 225 'BE' => array('start' => 4, 'length' => 3), 226 'BG' => array('start' => 4, 'length' => 8), 227 'CH' => array('start' => 4, 'length' => 5), 228 //CY: first 3 chars bankcode, last 5 chars branch 229 'CY' => array('start' => 4, 'length' => 8), 230 'CZ' => array('start' => 4, 'length' => 4), 231 'DE' => array('start' => 4, 'length' => 8), 232 'DK' => array('start' => 4, 'length' => 4), 233 //EE: first 2 chars bankidentifier, last 2 chars bankcode 234 'EE' => array('start' => 4, 'length' => 4), 235 // ES: followed by 2 chars (checksum) 236 'ES' => array('start' => 4, 'length' => 8), 237 'FR' => array('start' => 4, 'length' => 10), 238 'FI' => array('start' => 4, 'length' => 6), 239 //GB: first 4 chars bankidentifier, last 6 chars bank-branchcode 240 'GB' => array('start' => 4, 'length' => 10), 241 'GE' => array('start' => 4, 'length' => 2), 242 'GI' => array('start' => 4, 'length' => 4), 243 //GR: first 3 chars bankcode, last 4 chars branch 244 'GR' => array('start' => 4, 'length' => 7), 245 'HR' => array('start' => 4, 'length' => 7), 246 //HU: first 3 chars bankcode, last 4 chars branch, 247 //followed by 1 char (checksum) 248 'HU' => array('start' => 4, 'length' => 7), 249 //IE: first 4 chars bankcode, last 6 chars branch 250 'IE' => array('start' => 4, 'length' => 10), 251 //IL: first 3 chars bankcode, last 3 chars branch 252 'IL' => array('start' => 4, 'length' => 6), 253 'IS' => array('start' => 4, 'length' => 4), 254 'IT' => array('start' => 4, 'length' => 11), 255 'KW' => array('start' => 4, 'length' => 4), 256 'LB' => array('start' => 4, 'length' => 4), 257 //LI: bankcode and branch 258 'LI' => array('start' => 4, 'length' => 5), 259 'LT' => array('start' => 4, 'length' => 5), 260 'LU' => array('start' => 4, 'length' => 3), 261 'LV' => array('start' => 4, 'length' => 4), 262 //MC: first 5 chars bankcode, last 5 chars branch 263 'MC' => array('start' => 4, 'length' => 10), 264 'ME' => array('start' => 4, 'length' => 3), 265 'MK' => array('start' => 4, 'length' => 3), 266 //MR: first 5 chars bankcode, last 5 chars branch 267 'M$' => array('start' => 4, 'length' => 10), 268 //MT: first 4 chars bankcode, last 5 chars bank sort code 269 'MT' => array('start' => 4, 'length' => 9), 270 //MU: first 6 chars bankcode, last 2 chars branch 271 'MU' => array('start' => 4, 'length' => 8), 272 'NL' => array('start' => 4, 'length' => 4), 273 'NO' => array('start' => 4, 'length' => 4), 274 'PL' => array('start' => 4, 'length' => 8), 275 'PT' => array('start' => 4, 'length' => 8), 276 'RO' => array('start' => 4, 'length' => 4), 277 'RS' => array('start' => 4, 'length' => 3), 278 'SA' => array('start' => 4, 'length' => 2), 279 //SE: bankcode and branch 280 'SE' => array('start' => 4, 'length' => 3), 281 'SI' => array('start' => 4, 'length' => 5), 282 'SK' => array('start' => 4, 'length' => 4), 283 //SM: starts with one char, followed by 5 chars bankcode, last 5 chars branch 284 'SM' => array('start' => 5, 'length' => 10), 285 //TN: first 2 chars bankcode, last 3 chars branch 286 'TN' => array('start' => 4, 'length' => 5), 287 //TR: followed by 1 char (reserved field) 288 'TR' => array('start' => 4, 'length' => 5), 289 ); 290 } 291 return $_iban_countrycode_bankcode; 292 } 293 294 /** 295 * List of where the bankaccount-number inside an IBAN starts (starting from 0) 296 * and its length 297 * 298 * @return array 299 * @access private 300 */ 301 function _getCountrycodeBankaccount() 302 { 303 static $_iban_countrycode_bankaccount; 304 if (!isset($_iban_countrycode_bankaccount)) { 305 $_iban_countrycode_bankaccount = array( 306 'AD' => array('start' => 12, 'length' => 12), 307 'AE' => array('start' => 7, 'length' => 23), 308 'AL' => array('start' => 12, 'length' => 16), 309 'AT' => array('start' => 9, 'length' => 11), 310 //BA: followed by 2 chars (checksum) 311 'BA' => array('start' => 10, 'length' => 8), 312 //BE: followed by 2 chars (checksum) 313 'BE' => array('start' => 7, 'length' => 7), 314 'BG' => array('start' => 12, 'length' => 10), 315 'CH' => array('start' => 9, 'length' => 12), 316 'CY' => array('start' => 12, 'length' => 16), 317 'CZ' => array('start' => 8, 'length' => 16), 318 'DE' => array('start' => 12, 'length' => 10), 319 //DK: followed by 1 char (checksum) 320 'DK' => array('start' => 8, 'length' => 9), 321 //EE: followed by 1 char (checksum) 322 'EE' => array('start' => 8, 'length' => 11), 323 'ES' => array('start' => 14, 'length' => 10), 324 //FR: followed by 2 chars (checksum) 325 'FR' => array('start' => 14, 'length' => 11), 326 //FI: followed by 1 char (checksum) 327 'FI' => array('start' => 10, 'length' => 7), 328 'GB' => array('start' => 14, 'length' => 8), 329 'GE' => array('start' => 6, 'length' => 16), 330 'GI' => array('start' => 8, 'length' => 15), 331 'GR' => array('start' => 11, 'length' => 16), 332 'HR' => array('start' => 11, 'length' => 10), 333 //HU: followed by 1 char (checksum) 334 'HU' => array('start' => 12, 'length' => 15), 335 'IE' => array('start' => 14, 'length' => 8), 336 'IL' => array('start' => 10, 'length' => 13), 337 //IS: 2 accounttype, 6 account number, 10 identification number 338 'IS' => array('start' => 8, 'length' => 18), 339 'IT' => array('start' => 15, 'length' => 12), 340 'KW' => array('start' => 8, 'length' => 22), 341 'LB' => array('start' => 8, 'length' => 20), 342 'LI' => array('start' => 9, 'length' => 12), 343 'LT' => array('start' => 9, 'length' => 11), 344 'LU' => array('start' => 7, 'length' => 13), 345 'LV' => array('start' => 8, 'length' => 13), 346 'MC' => array('start' => 14, 'length' => 13), 347 'ME' => array('start' => 7, 'length' => 15), 348 //MK: followed by 2 chars (checksum) 349 'MK' => array('start' => 7, 'length' => 10), 350 //MR: followed by 2 chars (checksum?) 351 'MR' => array('start' => 14, 'length' => 13), 352 'MT' => array('start' => 13, 'length' => 18), 353 'MU' => array('start' => 12, 'length' => 18), 354 'NL' => array('start' => 8, 'length' => 10), 355 //NO: followed by 1 char (checksum) 356 'NO' => array('start' => 8, 'length' => 6), 357 'PL' => array('start' => 12, 'length' => 16), 358 //PT: followed by 2 chars (checksum) 359 'PT' => array('start' => 12, 'length' => 11), 360 // branch and client account identifier 361 'RO' => array('start' => 8, 'length' => 16), 362 'RS' => array('start' => 7, 'length' => 15), 363 'SA' => array('start' => 6, 'length' => 18), 364 //SE: followed by 1 char (checksum) 365 'SE' => array('start' => 7, 'length' => 16), 366 //SI: followed by 2 chars (checksum) 367 'SI' => array('start' => 9, 'length' => 8), 368 'SK' => array('start' => 8, 'length' => 16), 369 'SM' => array('start' => 15, 'length' => 12), 370 //TN: followed by 2 chars (checksum) 371 'TN' => array('start' => 9, 'length' => 13), 372 'TR' => array('start' => 10, 'length' => 16), 373 ); 374 } 375 return $_iban_countrycode_bankaccount; 376 } 377 378 /** 379 * List of regex for validating an IBAN according to standards for each country 380 * 381 * @return array 382 * @access private 383 */ 384 function _getCountrycodeRegex() 385 { 386 static $_iban_countrycode_regex; 387 if (!isset($_iban_countrycode_regex)) { 388 $_iban_countrycode_regex = array( 389 'AD' => '/^AD[0-9]{2}[0-9]{8}[A-Z0-9]{12}$/', 390 'AE' => '/^AE[0-9]{2}[0-9]{3}[0-9]{16}$/', 391 'AL' => '/^AL[0-9]{2}[0-9]{8}[A-Z0-9]{16}$/', 392 'AT' => '/^AT[0-9]{2}[0-9]{5}[0-9]{11}$/', 393 'BA' => '/^BA[0-9]{2}[0-9]{6}[0-9]{10}$/', 394 'BE' => '/^BE[0-9]{2}[0-9]{3}[0-9]{9}$/', 395 'BG' => '/^BG[0-9]{2}[A-Z]{4}[0-9]{4}[0-9]{2}[A-Z0-9]{8}$/', 396 'CH' => '/^CH[0-9]{2}[0-9]{5}[A-Z0-9]{12}$/', 397 'CY' => '/^CY[0-9]{2}[0-9]{8}[A-Z0-9]{16}$/', 398 'CZ' => '/^CZ[0-9]{2}[0-9]{4}[0-9]{16}$/', 399 'DE' => '/^DE[0-9]{2}[0-9]{8}[0-9]{10}$/', 400 'DK' => '/^DK[0-9]{2}[0-9]{4}[0-9]{10}$/', 401 'EE' => '/^EE[0-9]{2}[0-9]{4}[0-9]{12}$/', 402 'ES' => '/^ES[0-9]{2}[0-9]{8}[0-9]{12}$/', 403 'FR' => '/^FR[0-9]{2}[0-9]{10}[A-Z0-9]{13}$/', 404 'FI' => '/^FI[0-9]{2}[0-9]{6}[0-9]{8}$/', 405 'GB' => '/^GB[0-9]{2}[A-Z]{4}[0-9]{14}$/', 406 'GE' => '/^GE[0-9]{2}[A-Z]{2}[0-9]{16}$/', 407 'GI' => '/^GI[0-9]{2}[A-Z]{4}[A-Z0-9]{15}$/', 408 'GR' => '/^GR[0-9]{2}[0-9]{7}[A-Z0-9]{16}$/', 409 'HR' => '/^HR[0-9]{2}[0-9]{7}[0-9]{10}$/', 410 'HU' => '/^HU[0-9]{2}[0-9]{7}[0-9]{1}[0-9]{15}[0-9]{1}$/', 411 'IE' => '/^IE[0-9]{2}[A-Z0-9]{4}[0-9]{6}[0-9]{8}$/', 412 'IL' => '/^IL[0-9]{2}[0-9]{6}[0-9]{13}$/', 413 'IS' => '/^IS[0-9]{2}[0-9]{4}[0-9]{18}$/', 414 'IT' => '/^IT[0-9]{2}[A-Z]{1}[0-9]{10}[A-Z0-9]{12}$/', 415 'KW' => '/^KW[0-9]{2}[A-Z]{4}[A-Z0-9]{22}$/', 416 'LB' => '/^LB[0-9]{2}[0-9]{4}[A-Z0-9]{20}$/', 417 'LI' => '/^LI[0-9]{2}[0-9]{5}[A-Z0-9]{12}$/', 418 'LU' => '/^LU[0-9]{2}[0-9]{3}[A-Z0-9]{13}$/', 419 'LT' => '/^LT[0-9]{2}[0-9]{5}[0-9]{11}$/', 420 'LV' => '/^LV[0-9]{2}[A-Z]{4}[A-Z0-9]{13}$/', 421 'MC' => '/^MC[0-9]{2}[0-9]{10}[A-Z0-9]{11}[0-9]{2}$/', 422 'ME' => '/^ME[0-9]{2}[0-9]{3}[0-9]{15}$/', 423 'MK' => '/^MK[0-9]{2}[0-9]{3}[A-Z0-9]{10}[0-9]{2}$/', 424 'MR' => '/^MR[0-9]{2}[0-9]{10}[0-9]{13}$/', 425 'MT' => '/^MT[0-9]{2}[A-Z]{4}[0-9]{5}[A-Z0-9]{18}$/', 426 'MU' => '/^MU[0-9]{2}[A-Z]{4}[0-9]{4}[0-9]{15}[A-Z]{3}$/', 427 'NL' => '/^NL[0-9]{2}[A-Z]{4}[0-9]{10}$/', 428 'NO' => '/^NO[0-9]{2}[0-9]{4}[0-9]{7}$/', 429 'PL' => '/^PL[0-9]{2}[0-9]{8}[0-9]{16}$/', 430 'PT' => '/^PT[0-9]{2}[0-9]{8}[0-9]{13}$/', 431 'RO' => '/^RO[0-9]{2}[A-Z]{4}[A-Z0-9]{16}$/', 432 'RS' => '/^RS[0-9]{2}[0-9]{3}[0-9]{15}$/', 433 'SA' => '/^SA[0-9]{2}[0-9]{2}[A-Z0-9]{18}$/', 434 'SE' => '/^SE[0-9]{2}[0-9]{3}[0-9]{17}$/', 435 'SI' => '/^SI[0-9]{2}[0-9]{5}[0-9]{8}[0-9]{2}$/', 436 'SK' => '/^SK[0-9]{2}[0-9]{4}[0-9]{16}$/', 437 'SM' => '/^SM[0-9]{2}[A-Z]{1}[0-9]{10}[A-Z0-9]{12}$/', 438 'TN' => '/^TN[0-9]{2}[0-9]{5}[0-9]{15}$/', 439 'TR' => '/^TR[0-9]{2}[0-9]{5}[A-Z0-9]{17}$/', 440 ); 441 } 442 return $_iban_countrycode_regex; 443 } 444 445 /** 446 * Class constructor 447 * 448 * @param string $iban IBAN to be validated / processed 449 * 450 * @access public 451 */ 452 function Validate_Finance_IBAN($iban = '') 453 { 454 $iban = strtoupper($iban); 455 $this->_iban = $iban; 456 } 457 458 /** 459 * Returns the current IBAN 460 * 461 * @access public 462 * @return string 463 */ 464 function getIBAN() 465 { 466 return $this->_iban; 467 } // end func getIBAN 468 469 /** 470 * Sets the current IBAN to a new value 471 * 472 * @param string $iban IBAN to be validated / processed 473 * 474 * @access public 475 * @return void 476 */ 477 function setIBAN($iban = '') 478 { 479 $iban = strtoupper($iban); 480 $this->_iban = $iban; 481 } 482 483 /** 484 * Performs validation of the IBAN 485 * 486 * @param string $arg optional parameter for calling validate as static function 487 * 488 * @access public 489 * @return boolean true if no error found 490 */ 491 function validate($arg = null) 492 { 493 if (isset($this) && is_a($this, 'Validate_Finance_IBAN')) { 494 $iban = $this->_iban; 495 } else { 496 $iban = $arg; 497 } 498 $iban = strtoupper($iban); 499 500 $errorcode = VALIDATE_FINANCE_IBAN_OK; 501 502 static $_iban_countrycode_countryname; 503 if (!isset($_iban_countrycode_countryname)) { 504 $_iban_countrycode_countryname = Validate_Finance_IBAN::_getCountrycodeCountryname(); 505 } 506 static $_iban_countrycode_length; 507 if (!isset($_iban_countrycode_length)) { 508 $_iban_countrycode_ibanlength = Validate_Finance_IBAN::_getCountrycodeIBANLength(); 509 } 510 static $_iban_countrycode_regex; 511 if (!isset($_iban_countrycode_regex)) { 512 $_iban_countrycode_regex = Validate_Finance_IBAN::_getCountrycodeRegex(); 513 } 514 515 // 2 character abbreviation at start of IBAN - the country code 516 $abbrev = substr($iban, 0, 2); 517 518 if (strlen($iban) <= 4) { 519 $errorcode = VALIDATE_FINANCE_IBAN_TOO_SHORT; 520 } elseif (!isset( $_iban_countrycode_countryname[$abbrev])) { 521 $errorcode = VALIDATE_FINANCE_IBAN_COUNTRY_INVALID; 522 } elseif (strlen($iban) < $_iban_countrycode_ibanlength[$abbrev]) { 523 $errorcode = VALIDATE_FINANCE_IBAN_TOO_SHORT; 524 } elseif (strlen($iban) > $_iban_countrycode_ibanlength[$abbrev]) { 525 $errorcode = VALIDATE_FINANCE_IBAN_TOO_LONG; 526 } elseif (!preg_match($_iban_countrycode_regex[$abbrev], $iban)) { 527 $errorcode = VALIDATE_FINANCE_IBAN_INVALID_FORMAT; 528 } else { 529 // todo: maybe implement direct checks for bankcodes of certain countries 530 531 // let's see if checksum is also correct 532 $iban_replace_chars = range('A', 'Z'); 533 foreach (range(10, 35) as $tempvalue) { 534 $iban_replace_values[] = strval($tempvalue); 535 } 536 537 // move first 4 chars (countrycode and checksum) to the end of the string 538 $tempiban = substr($iban, 4) . substr($iban, 0, 4); 539 $tempiban = str_replace( 540 $iban_replace_chars, 541 $iban_replace_values, 542 $tempiban 543 ); 544 545 $tempcheckvalue = intval(substr($tempiban, 0, 1)); 546 for ($strcounter = 1; $strcounter < strlen($tempiban); $strcounter++) { 547 $tempcheckvalue *= 10; 548 $tempcheckvalue += intval(substr($tempiban, $strcounter, 1)); 549 $tempcheckvalue %= 97; 550 } 551 552 // checkvalue of 1 indicates correct IBAN checksum 553 if ($tempcheckvalue != 1) { 554 $errorcode = VALIDATE_FINANCE_IBAN_CHECKSUM_INVALID; 555 } else { 556 $errorcode = VALIDATE_FINANCE_IBAN_OK; 557 } 558 } 559 560 if (isset($this)) { 561 $this->_errorcode = $errorcode; 562 } 563 return ($errorcode == VALIDATE_FINANCE_IBAN_OK); 564 } // end func validate 565 566 /** 567 * Returns errorcode corresponding to last validation 568 * 569 * @access public 570 * @return integer errorcode 571 */ 572 function getErrorcode() 573 { 574 return $this->_errorcode; 575 } // end func getErrorcode 576 577 /** 578 * Returns the countrycode of the IBAN 579 * 580 * @access public 581 * @return string 582 */ 583 function getCountrycode() 584 { 585 if (strlen($this->_iban)>4) { 586 // return first two characters 587 return substr($this->_iban, 0, 2); 588 } else { 589 $this->_errorcode = VALIDATE_FINANCE_IBAN_TOO_SHORT; 590 $msg = $this->errorMessage($this->_errorcode); 591 return PEAR::raiseError( 592 $msg, 593 $this->_errorcode, 594 PEAR_ERROR_TRIGGER, 595 E_USER_WARNING, 596 "$msg in VALIDATE_FINANCE_IBAN::getCountrycode()" 597 ); 598 } 599 } // end func getCountrycode 600 601 /** 602 * Returns the countryname of the IBAN 603 * If the name can not be determined then return the country code. 604 * 605 * @access public 606 * @return string 607 */ 608 function getCountryname() 609 { 610 $countrycode = $this->getCountrycode(); 611 if (is_string($countrycode)) { 612 $countryname = Validate_Finance_IBAN::_getCountrycodeCountryname(); 613 return $countryname[$countrycode]; 614 } else { // e.g. if it's an error 615 return $countrycode; 616 } 617 } // end func getCountryname 618 619 /** 620 * Returns the bankcode of the IBAN 621 * 622 * @access public 623 * @return string 624 */ 625 function getBankcode() 626 { 627 if (!$this->validate()) { 628 $this->_errorcode = VALIDATE_FINANCE_IBAN_GENERAL_INVALID; 629 $msg = $this->errorMessage($this->_errorcode); 630 return PEAR::raiseError( 631 $msg, 632 $this->_errorcode, 633 PEAR_ERROR_TRIGGER, 634 E_USER_WARNING, 635 "$msg in VALIDATE_FINANCE_IBAN::getBankcode()" 636 ); 637 } else { 638 $bankcode = Validate_Finance_IBAN::_getCountrycodeBankcode(); 639 $position = substr($this->_iban, 0, 2); 640 // find out where the bankcode is inside the iban 641 $currCountrycodeBankcode = $bankcode[$position]; 642 // extract and return that code 643 return substr( 644 $this->_iban, 645 $currCountrycodeBankcode['start'], 646 $currCountrycodeBankcode['length'] 647 ); 648 } 649 } // end func getBankcode 650 651 /** 652 * Returns the bankaccount of the IBAN 653 * 654 * @access public 655 * @return string 656 */ 657 function getBankaccount() 658 { 659 if (!$this->validate()) { 660 $this->_errorcode = VALIDATE_FINANCE_IBAN_GENERAL_INVALID; 661 //get error message 662 $msg = $this->errorMessage($this->_errorcode); 663 return PEAR::raiseError( 664 $msg, 665 $this->_errorcode, 666 PEAR_ERROR_TRIGGER, 667 E_USER_WARNING, 668 "$msg in VALIDATE_FINANCE_IBAN::getBankaccount()" 669 ); 670 } else { 671 $bankaccount = Validate_Finance_IBAN::_getCountrycodeBankaccount(); 672 //extract details 673 $currCountrycodeBankaccount = $bankaccount[substr($this->_iban, 0, 2)]; 674 return substr( 675 $this->_iban, 676 $currCountrycodeBankaccount['start'], 677 $currCountrycodeBankaccount['length'] 678 ); 679 } 680 } // end func getAccount 681 682 /** 683 * Return a textual error message for an IBAN error code 684 * 685 * @param int $value error code 686 * 687 * @access public 688 * @return string error message 689 */ 690 function errorMessage($value) 691 { 692 // make the variable static so that it only has to do the defining on the first call 693 static $errorMessages; 694 695 // define the varies error messages 696 if (!isset($errorMessages)) { 697 $errorMessages = array( 698 VALIDATE_FINANCE_IBAN_OK => 'no error', 699 VALIDATE_FINANCE_IBAN_ERROR => 'unknown error', 700 VALIDATE_FINANCE_IBAN_GENERAL_INVALID => 'IBAN generally invalid', 701 VALIDATE_FINANCE_IBAN_TOO_SHORT => 'IBAN is too short', 702 VALIDATE_FINANCE_IBAN_TOO_LONG => 'IBAN is too long', 703 VALIDATE_FINANCE_IBAN_COUNTRY_INVALID => 'IBAN countrycode is invalid', 704 VALIDATE_FINANCE_IBAN_INVALID_FORMAT => 'IBAN has invalid format', 705 VALIDATE_FINANCE_IBAN_CHECKSUM_INVALID => 'IBAN checksum is invalid' 706 ); 707 } 708 709 // If this is an error object, then grab the corresponding error code 710 if (PEAR::isError($value)) { 711 $value = $value->getCode(); 712 } 713 714 // return the textual error message corresponding to the code 715 return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[VALIDATE_FINANCE_IBAN_ERROR]; 716 } // end func errorMessage 717} // end class VALIDATE_FINANCE_IBAN 718