Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Validator / Iban.php
blob58f7ae29174768616418a03e57b0c745ab1ce912
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Validator;
12 use Traversable;
13 use Zend\Stdlib\ArrayUtils;
14 use Zend\Validator\AbstractValidator;
15 use Zend\Validator\Exception;
17 /**
18 * Validates IBAN Numbers (International Bank Account Numbers)
20 class Iban extends AbstractValidator
22 const NOTSUPPORTED = 'ibanNotSupported';
23 const SEPANOTSUPPORTED = 'ibanSepaNotSupported';
24 const FALSEFORMAT = 'ibanFalseFormat';
25 const CHECKFAILED = 'ibanCheckFailed';
27 /**
28 * Validation failure message template definitions
30 * @var array
32 protected $messageTemplates = array(
33 self::NOTSUPPORTED => "Unknown country within the IBAN",
34 self::SEPANOTSUPPORTED => "Countries outside the Single Euro Payments Area (SEPA) are not supported",
35 self::FALSEFORMAT => "The input has a false IBAN format",
36 self::CHECKFAILED => "The input has failed the IBAN check",
39 /**
40 * Optional country code by ISO 3166-1
42 * @var string|null
44 protected $countryCode;
46 /**
47 * Optionally allow IBAN codes from non-SEPA countries. Defaults to true
49 * @var bool
51 protected $allowNonSepa = true;
53 /**
54 * The SEPA country codes
56 * @var array<ISO 3166-1>
58 protected static $sepaCountries = array(
59 'AT', 'BE', 'BG', 'CY', 'CZ', 'DK', 'FO', 'GL', 'EE', 'FI', 'FR', 'DE',
60 'GI', 'GR', 'HU', 'IS', 'IE', 'IT', 'LV', 'LI', 'LT', 'LU', 'MT', 'MC',
61 'NL', 'NO', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'CH', 'GB'
64 /**
65 * IBAN regexes by country code
67 * @var array
69 protected static $ibanRegex = array(
70 'AD' => 'AD[0-9]{2}[0-9]{4}[0-9]{4}[A-Z0-9]{12}',
71 'AE' => 'AE[0-9]{2}[0-9]{3}[0-9]{16}',
72 'AL' => 'AL[0-9]{2}[0-9]{8}[A-Z0-9]{16}',
73 'AT' => 'AT[0-9]{2}[0-9]{5}[0-9]{11}',
74 'AZ' => 'AZ[0-9]{2}[A-Z]{4}[A-Z0-9]{20}',
75 'BA' => 'BA[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{8}[0-9]{2}',
76 'BE' => 'BE[0-9]{2}[0-9]{3}[0-9]{7}[0-9]{2}',
77 'BG' => 'BG[0-9]{2}[A-Z]{4}[0-9]{4}[0-9]{2}[A-Z0-9]{8}',
78 'BH' => 'BH[0-9]{2}[A-Z]{4}[A-Z0-9]{14}',
79 'BR' => 'BR[0-9]{2}[0-9]{8}[0-9]{5}[0-9]{10}[A-Z][A-Z0-9]',
80 'CH' => 'CH[0-9]{2}[0-9]{5}[A-Z0-9]{12}',
81 'CR' => 'CR[0-9]{2}[0-9]{3}[0-9]{14}',
82 'CY' => 'CY[0-9]{2}[0-9]{3}[0-9]{5}[A-Z0-9]{16}',
83 'CZ' => 'CZ[0-9]{2}[0-9]{20}',
84 'DE' => 'DE[0-9]{2}[0-9]{8}[0-9]{10}',
85 'DO' => 'DO[0-9]{2}[A-Z0-9]{4}[0-9]{20}',
86 'DK' => 'DK[0-9]{2}[0-9]{14}',
87 'EE' => 'EE[0-9]{2}[0-9]{2}[0-9]{2}[0-9]{11}[0-9]{1}',
88 'ES' => 'ES[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{1}[0-9]{1}[0-9]{10}',
89 'FI' => 'FI[0-9]{2}[0-9]{6}[0-9]{7}[0-9]{1}',
90 'FO' => 'FO[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}',
91 'FR' => 'FR[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}',
92 'GB' => 'GB[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}',
93 'GE' => 'GE[0-9]{2}[A-Z]{2}[0-9]{16}',
94 'GI' => 'GI[0-9]{2}[A-Z]{4}[A-Z0-9]{15}',
95 'GL' => 'GL[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}',
96 'GR' => 'GR[0-9]{2}[0-9]{3}[0-9]{4}[A-Z0-9]{16}',
97 'GT' => 'GT[0-9]{2}[A-Z0-9]{4}[A-Z0-9]{20}',
98 'HR' => 'HR[0-9]{2}[0-9]{7}[0-9]{10}',
99 'HU' => 'HU[0-9]{2}[0-9]{3}[0-9]{4}[0-9]{1}[0-9]{15}[0-9]{1}',
100 'IE' => 'IE[0-9]{2}[A-Z]{4}[0-9]{6}[0-9]{8}',
101 'IL' => 'IL[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{13}',
102 'IS' => 'IS[0-9]{2}[0-9]{4}[0-9]{2}[0-9]{6}[0-9]{10}',
103 'IT' => 'IT[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}',
104 'KW' => 'KW[0-9]{2}[A-Z]{4}[0-9]{22}',
105 'KZ' => 'KZ[0-9]{2}[0-9]{3}[A-Z0-9]{13}',
106 'LB' => 'LB[0-9]{2}[0-9]{4}[A-Z0-9]{20}',
107 'LI' => 'LI[0-9]{2}[0-9]{5}[A-Z0-9]{12}',
108 'LT' => 'LT[0-9]{2}[0-9]{5}[0-9]{11}',
109 'LU' => 'LU[0-9]{2}[0-9]{3}[A-Z0-9]{13}',
110 'LV' => 'LV[0-9]{2}[A-Z]{4}[A-Z0-9]{13}',
111 'MC' => 'MC[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}',
112 'MD' => 'MD[0-9]{2}[A-Z0-9]{20}',
113 'ME' => 'ME[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',
114 'MK' => 'MK[0-9]{2}[0-9]{3}[A-Z0-9]{10}[0-9]{2}',
115 'MR' => 'MR13[0-9]{5}[0-9]{5}[0-9]{11}[0-9]{2}',
116 'MT' => 'MT[0-9]{2}[A-Z]{4}[0-9]{5}[A-Z0-9]{18}',
117 'MU' => 'MU[0-9]{2}[A-Z]{4}[0-9]{2}[0-9]{2}[0-9]{12}[0-9]{3}[A-Z]{3}',
118 'NL' => 'NL[0-9]{2}[A-Z]{4}[0-9]{10}',
119 'NO' => 'NO[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{1}',
120 'PK' => 'PK[0-9]{2}[A-Z]{4}[A-Z0-9]{16}',
121 'PL' => 'PL[0-9]{2}[0-9]{8}[0-9]{16}',
122 'PS' => 'PS[0-9]{2}[A-Z]{4}[A-Z0-9]{21}',
123 'PT' => 'PT[0-9]{2}[0-9]{4}[0-9]{4}[0-9]{11}[0-9]{2}',
124 'RO' => 'RO[0-9]{2}[A-Z]{4}[A-Z0-9]{16}',
125 'RS' => 'RS[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',
126 'SA' => 'SA[0-9]{2}[0-9]{2}[A-Z0-9]{18}',
127 'SE' => 'SE[0-9]{2}[0-9]{3}[0-9]{16}[0-9]{1}',
128 'SI' => 'SI[0-9]{2}[0-9]{5}[0-9]{8}[0-9]{2}',
129 'SK' => 'SK[0-9]{2}[0-9]{4}[0-9]{6}[0-9]{10}',
130 'SM' => 'SM[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}',
131 'TN' => 'TN59[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}',
132 'TR' => 'TR[0-9]{2}[0-9]{5}[A-Z0-9]{1}[A-Z0-9]{16}',
133 'VG' => 'VG[0-9]{2}[A-Z]{4}[0-9]{16}',
137 * Sets validator options
139 * @param array|Traversable $options OPTIONAL
141 public function __construct($options = array())
143 if ($options instanceof Traversable) {
144 $options = ArrayUtils::iteratorToArray($options);
147 if (array_key_exists('country_code', $options)) {
148 $this->setCountryCode($options['country_code']);
151 if (array_key_exists('allow_non_sepa', $options)) {
152 $this->setAllowNonSepa($options['allow_non_sepa']);
155 parent::__construct($options);
159 * Returns the optional country code by ISO 3166-1
161 * @return string|null
163 public function getCountryCode()
165 return $this->countryCode;
169 * Sets an optional country code by ISO 3166-1
171 * @param string|null $countryCode
172 * @return Iban provides a fluent interface
173 * @throws Exception\InvalidArgumentException
175 public function setCountryCode($countryCode = null)
177 if ($countryCode !== null) {
178 $countryCode = (string) $countryCode;
180 if (!isset(static::$ibanRegex[$countryCode])) {
181 throw new Exception\InvalidArgumentException(
182 "Country code '{$countryCode}' invalid by ISO 3166-1 or not supported"
187 $this->countryCode = $countryCode;
188 return $this;
192 * Returns the optional allow non-sepa countries setting
194 * @return bool
196 public function allowNonSepa()
198 return $this->allowNonSepa;
202 * Sets the optional allow non-sepa countries setting
204 * @param bool $allowNonSepa
205 * @return Iban provides a fluent interface
207 public function setAllowNonSepa($allowNonSepa)
209 $this->allowNonSepa = (bool) $allowNonSepa;
210 return $this;
214 * Returns true if $value is a valid IBAN
216 * @param string $value
217 * @return bool
219 public function isValid($value)
221 if (!is_string($value)) {
222 $this->error(self::FALSEFORMAT);
223 return false;
226 $value = str_replace(' ', '', strtoupper($value));
227 $this->setValue($value);
229 $countryCode = $this->getCountryCode();
230 if ($countryCode === null) {
231 $countryCode = substr($value, 0, 2);
234 if (!array_key_exists($countryCode, static::$ibanRegex)) {
235 $this->setValue($countryCode);
236 $this->error(self::NOTSUPPORTED);
237 return false;
240 if (!$this->allowNonSepa && !in_array($countryCode, static::$sepaCountries)) {
241 $this->setValue($countryCode);
242 $this->error(self::SEPANOTSUPPORTED);
243 return false;
246 if (!preg_match('/^' . static::$ibanRegex[$countryCode] . '$/', $value)) {
247 $this->error(self::FALSEFORMAT);
248 return false;
251 $format = substr($value, 4) . substr($value, 0, 4);
252 $format = str_replace(
253 array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
254 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'),
255 array('10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22',
256 '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35'),
257 $format
260 $temp = intval(substr($format, 0, 1));
261 $len = strlen($format);
262 for ($x = 1; $x < $len; ++$x) {
263 $temp *= 10;
264 $temp += intval(substr($format, $x, 1));
265 $temp %= 97;
268 if ($temp != 1) {
269 $this->error(self::CHECKFAILED);
270 return false;
273 return true;