-
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add the support for SWIFT Business Identifier Code (BIC) format
Signed-off-by: codisart <[email protected]>
- Loading branch information
Showing
3 changed files
with
234 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Iban Validator | ||
|
||
`Laminas\Validator\BusinessIdentifierCode` validates if a given value could be | ||
a BIC code as defined by ISO 9362:2014. BIC is the abbreviation for "Business | ||
Identifier Code". | ||
> The original scope of ISO 9362 was limited to the identification of banks; | ||
> consequently, the acronym “BIC” was used as an abbreviation for “bank | ||
> identifier code”. The scope has since been extended, in the first place to | ||
> cover all types of financial institutions, and in the 2009 edition, to cover | ||
> non-financial institutions as well. | ||
> | ||
> --- [ISO 9362:2014 Banking — Banking telecommunication messages — Business | ||
> identifier code (BIC)](https://www.iso.org/standard/60390.htm) | ||
## Supported options | ||
|
||
There are no additional supported options for the `BusinessIdentifierCode` validator. | ||
|
||
## BIC validation | ||
|
||
BIC codes should be a string which length should be equal to 8 or 11. | ||
|
||
* The 4 first characters can only be letters and it is used to identify a bank or an institution. | ||
|
||
* The following 2 characters can only be letters too and it should be a country code assigned within ISO 3166-1 alpha-2. The only exception is the code 'XK' used for the Republic of Kosovo. | ||
|
||
* The following 2 characters can be letters or digits. It is used to represent a location (like a city) | ||
|
||
* The last 3 characters are optional and can be letters or digits. It can represent a branche office. The code 'XXX' is often used to represent the ain office when the 11 characters code is used. | ||
|
||
## Basic usage | ||
|
||
```php | ||
$validator = new Laminas\Validator\BusinessIdentifierCode(); | ||
|
||
if ($validator->isValid($bicCode)) { | ||
// bic appears to be valid | ||
} else { | ||
// bic is invalid; print the reasons | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<?php | ||
/** | ||
* @see https://github.com/laminas/laminas-validator for the canonical source repository | ||
* @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md | ||
* @license https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License | ||
*/ | ||
|
||
namespace Laminas\Validator; | ||
|
||
use Laminas\Stdlib\ArrayUtils; | ||
use Traversable; | ||
|
||
class BusinessIdentifierCode extends AbstractValidator | ||
{ | ||
const INVALID = 'valueNotBic'; | ||
const NOT_STRING = 'valueNotString'; | ||
const NOT_VALID_COUNTRY = 'valueNotCountry'; | ||
|
||
/** | ||
* @var array | ||
*/ | ||
protected $messageTemplates = [ | ||
self::NOT_STRING => 'Invalid type given; string expected', | ||
self::INVALID => 'Invalid BIC format', | ||
self::NOT_VALID_COUNTRY => 'Invalid country code', | ||
]; | ||
|
||
private const REGEX_BIC = '/^[A-Za-z]{4}([A-Za-z]{2})[0-9A-Za-z]{2}([0-9A-Za-z]{3})?$/'; | ||
|
||
/** | ||
* @var array<ISO 3166-1 alpha-2> | ||
*/ | ||
private const ISO_COUNTRIES = [ | ||
'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', | ||
'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BQ', 'BR', 'BS', 'BT', 'BV', 'BW', | ||
'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', | ||
'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', | ||
'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', | ||
'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', | ||
'IR', 'IS', 'IT', 'JE', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR', 'KW', 'KY', 'KZ', | ||
'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', | ||
'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', | ||
'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PK', 'PL', | ||
'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', | ||
'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SX', 'SY', 'SZ', 'TC', 'TD', | ||
'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', | ||
'UY', 'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'YE', 'YT', 'ZA', 'ZM', 'ZW', | ||
]; | ||
|
||
private const KOSOVO_EXCEPTION = 'XK'; | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function isValid($value) | ||
{ | ||
if (! is_string($value)) { | ||
$this->error(self::NOT_STRING); | ||
return false; | ||
} | ||
|
||
if (empty($value) | ||
|| !preg_match(self::REGEX_BIC, $value, $matches) | ||
) { | ||
$this->error(self::INVALID); | ||
return false; | ||
} | ||
|
||
if (!$this->isSwiftValidCountry($matches[1])) { | ||
$this->error(self::NOT_VALID_COUNTRY); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private function isSwiftValidCountry(string $countryCode) : bool | ||
{ | ||
return in_array($countryCode, self::ISO_COUNTRIES) | ||
|| $countryCode === self::KOSOVO_EXCEPTION; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
<?php | ||
/** | ||
* @see https://github.com/laminas/laminas-validator for the canonical source repository | ||
* @copyright https://github.com/laminas/laminas-validator/blob/master/COPYRIGHT.md | ||
* @license https://github.com/laminas/laminas-validator/blob/master/LICENSE.md New BSD License | ||
*/ | ||
|
||
namespace LaminasTest\Validator; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use Laminas\Validator\BusinessIdentifierCode; | ||
|
||
/** | ||
* \Laminas\BusinessIdentifierCode | ||
* | ||
* @group Laminas_Validator | ||
*/ | ||
class BusinessIdentifierCodeTest extends TestCase | ||
{ | ||
public function successProvider() | ||
{ | ||
return [ | ||
'BANQUE ATLANTIQUE COTE D\'IVOIRE, ABIDJAN, Cote d\'Ivoire' => ['ATCICIAB'], | ||
'BANQUE NATIONALE DU CANADA, MONTREAL, Canada' => ['BNDCCAMMINT'], | ||
'BDO UNIBANK, INC., MANILA, Philippines' => ['BNORPHMM'], | ||
'FEDERATION DES CAISSES DESJARDINS DU QUEBEC, LEVIS, Canada ' => ['CCDQCAMM'], | ||
'COMMERZBANK AG, FRANKFURT AM MAIN, Germany' => ['COBADEFF'], | ||
'DANSKE BANK A/S, COPENHAGEN, Denmark' => ['DABADKKK'], | ||
'DEUTSCHE BANK AG, FRANKFURT AM MAIN, Germany ' => ['DEUTDEFF'], | ||
'DEUTSCHE BANK AG, BAD HOMBURG, Germany' => ['DEUTDEFF500'], | ||
'DB PRIVAT-UND FIRMENKUNDENBANK, DUSSELDORF, Germany' => ['DEUTDEDBDUE'], | ||
'DAH SING BANK (CHINA) LIMITED, SHANGHAI, China ' => ['DSBACNBXSHA'], | ||
'FINANCIERE DES PAIEMENTS ELECTRONIQUES, CHARENTON LE PONT, France' => ['FPELFR21XXX'], | ||
'BNP PARIBAS FORTIS, BRUSSELS, Belgium ' => ['GEBABEBB'], | ||
'PROCREDIT BANK SH.A KOSOVO, HEAD QUARTER, PRISTINA, Kosovo' => ['MBKOXKPRXXX'], | ||
'NEDBANK LIMITED, JOHANNESBURG, South Africa' => ['NEDSZAJJ'], | ||
'NEDBANK LIMITED, JOHANNESBURG, South Africa (primary office)' => ['NEDSZAJJXXX'], | ||
'LA BANQUE POSTALE, MONTPELLIER, France' => ['PSSTFRPPMON'], | ||
'LA BANQUE POSTALE, NANTES, France' => ['PSSTFRPPNTE'], | ||
'UNICREDIT S.P.A., MILANO, Italy ' => ['UNCRITMM'], | ||
]; | ||
} | ||
|
||
/** | ||
* @dataProvider successProvider | ||
*/ | ||
public function testValidateSuccess($code) | ||
{ | ||
$validator = new BusinessIdentifierCode(); | ||
self::assertTrue($validator->isValid($code)); | ||
} | ||
|
||
public function NotAStringProvider() | ||
{ | ||
return [ | ||
'number' => [123], | ||
'array' => [['DEUTDEFF']], | ||
'object' => [new \stdClass()], | ||
]; | ||
} | ||
|
||
/** | ||
* @dataProvider NotAStringProvider | ||
*/ | ||
public function testNotAStringFailure($code) | ||
{ | ||
$validator = new BusinessIdentifierCode(); | ||
self::assertFalse($validator->isValid($code)); | ||
self::assertCount(1, $validator->getMessages()); | ||
self::assertSame('Invalid type given; string expected', $validator->getMessages()['valueNotString']); | ||
} | ||
|
||
public function NotBicFormatProvider() | ||
{ | ||
return [ | ||
'too short' => ['SHORT'], | ||
'too long' => ['SOLOOOOOOOOOOOOOOOOOOONG'], | ||
'use numbers for country code' => ['DEUT12AA'], | ||
]; | ||
} | ||
|
||
/** | ||
* @dataProvider NotBicFormatProvider | ||
*/ | ||
public function testNotBicFormatFailure($code) | ||
{ | ||
$validator = new BusinessIdentifierCode(); | ||
self::assertFalse($validator->isValid($code)); | ||
self::assertCount(1, $validator->getMessages()); | ||
self::assertSame('Invalid BIC format', $validator->getMessages()['valueNotBic']); | ||
} | ||
|
||
public function NotSwiftCountryCodeProvider() | ||
{ | ||
return [ | ||
'AA is not a assigned code' => ['DEUTAAFF'], | ||
'UK is not the iso code for the united kingdom' => ['ABCDUKFF'], | ||
]; | ||
} | ||
|
||
/** | ||
* @dataProvider NotSwiftCountryCodeProvider | ||
*/ | ||
public function testNotSwiftCountryCodeFailure($code) | ||
{ | ||
$validator = new BusinessIdentifierCode(); | ||
self::assertFalse($validator->isValid($code)); | ||
self::assertCount(1, $validator->getMessages()); | ||
self::assertSame('Invalid country code', $validator->getMessages()['valueNotCountry']); | ||
} | ||
} |