diff --git a/.gitignore b/.gitignore index 723ef36..8925195 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -.idea \ No newline at end of file +.idea +vendor +composer.lock \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..92e29de --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +language: php + +php: + - 7.1 + - 7.2 + - nightly + +install: + - travis_retry composer self-update + - travis_retry composer install --no-interaction --no-suggest --prefer-dist --dev + +script: + - vendor/bin/phpunit --coverage-clover=coverage.xml + +after_success: + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/README.md b/README.md index 31f38f0..71af58e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # PHP Banks DB +[![Build Status](https://travis-ci.com/chekalskiy/php-bank-db.svg?branch=master)](https://travis-ci.com/chekalskiy/php-bank-db) [![codecov](https://codecov.io/gh/chekalskiy/php-bank-db/branch/master/graph/badge.svg)](https://codecov.io/gh/chekalskiy/php-bank-db) + > It is a PHP port of [ramoona's banks-db](https://github.com/ramoona/banks-db). Returns bank's name and brand color by bank card number's first digits (BIN, Issuer Identification Numbers, IIN). diff --git a/composer.json b/composer.json index 2055d79..b35c756 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,10 @@ } ], "require": { - "php": ">=7.0" + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7" }, "autoload": { "psr-4": { diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..13b1d2b --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,13 @@ + + + + + ./src + + + + + tests + + + \ No newline at end of file diff --git a/src/BankDb.php b/src/BankDb.php index 1c68ba3..af1af91 100644 --- a/src/BankDb.php +++ b/src/BankDb.php @@ -10,11 +10,6 @@ class BankDb */ protected $database = []; - /** - * @var string - */ - protected $database_file_path; - /** * BankDb constructor. * @@ -25,7 +20,6 @@ class BankDb public function __construct(string $db_file_path = null) { $this->initializeDatabase($db_file_path); - $this->loadDatabase(); } /** @@ -57,7 +51,7 @@ public function getBankInfo(string $card_number): BankInfo * * @throws BankDbException */ - protected function initializeDatabase(string $db_file_path = null) + protected function initializeDatabase(string $db_file_path = null): void { if ($db_file_path === null) { $db_file_path = __DIR__ . '/../db/bank_db.php'; @@ -67,15 +61,7 @@ protected function initializeDatabase(string $db_file_path = null) throw new BankDbException('Cannot find DB file'); } - $this->database_file_path = $db_file_path; - } - - /** - * Database preload - */ - protected function loadDatabase() - { - $this->database = include $this->database_file_path; + $this->database = include $db_file_path; } /** diff --git a/src/BankInfo.php b/src/BankInfo.php index 76258d8..03a5696 100644 --- a/src/BankInfo.php +++ b/src/BankInfo.php @@ -28,19 +28,23 @@ class BankInfo protected $card_type = 'unknown'; /** + * @see https://github.com/braintree/credit-card-type/blob/master/index.js + * @see https://en.wikipedia.org/wiki/Payment_card_number + * @see https://github.com/ramoona/banks-db/blob/2a882c921e4c4e1d1ee452e97671aedfbe325abe/type.js + * * @var array */ protected static $card_prefixes = [ 'electron' => '/^(4026|417500|4405|4508|4844|4913|4917)/', 'interpayment' => '/^636/', - 'unionpay' => '/^62/', - 'maestro' => '/^(50|56|57|58|6)/', + 'unionpay' => '/^(62|88)/', + 'discover' => '/^6(?:011|4|5)/', + 'maestro' => '/^(50|5[6-9]|6)/', 'visa' => '/^4/', - 'mastercard' => '/^(5[1-5]|[2221-2720])/', + 'mastercard' => '/^(5[1-5]|(?:222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720))/', // [2221-2720] 'amex' => '/^3[47]/', - 'diners' => '/^3(?:0[0-5]|[68][0-9])/', - 'discover' => '/^6(?:011|5[0-9]{2})/', - 'jcb' => '/^(?:2131|1800|[3528-3589])/', + 'diners' => '/^3(?:0([0-5]|95)|[689])/', + 'jcb' => '/^(?:2131|1800|(?:352[89]|35[3-8][0-9]))/', // 3528-3589 'mir' => '/^220[0-4]/', ]; @@ -63,6 +67,7 @@ public function __construct(array $data, string $prefix = '') foreach (self::$card_prefixes as $card_type => $card_prefix) { if (preg_match($card_prefix, $prefix)) { $this->card_type = $card_type; + break; } } } @@ -70,7 +75,7 @@ public function __construct(array $data, string $prefix = '') /** * Make this bank object unknown */ - protected function makeUnknown() + protected function makeUnknown(): void { $this->is_unknown = true; $this->data = [ @@ -83,7 +88,7 @@ protected function makeUnknown() ]; } - public function getName(bool $is_local = true): string + public function getTitle(bool $is_local = true): string { if ($is_local && isset($this->data['localTitle'])) { return $this->data['localTitle']; diff --git a/tests/BankDbTest.php b/tests/BankDbTest.php new file mode 100644 index 0000000..1e4b75f --- /dev/null +++ b/tests/BankDbTest.php @@ -0,0 +1,38 @@ +bank_db = new BankDb(); + } + + public function testCanBeConstructed(): void + { + $this->assertNotEmpty($this->bank_db); + } + + public function testExceptionIfDatabaseNotFound(): void + { + $this->expectException(BankDbException::class); + + new BankDb('/unknown/path'); + } + + public function testGetBankInfoIsWorking(): void + { + $bank_info = $this->bank_db->getBankInfo('400000'); + + $this->assertTrue($bank_info->isUnknown()); + } +} diff --git a/tests/BankInfoTest.php b/tests/BankInfoTest.php new file mode 100644 index 0000000..572f543 --- /dev/null +++ b/tests/BankInfoTest.php @@ -0,0 +1,129 @@ +bank_db = new BankDb(); + } + + public function testAnyInput(): void + { + $bank_info_1 = $this->bank_db->getBankInfo('5321 30'); + $bank_info_2 = $this->bank_db->getBankInfo('532130'); + $bank_info_3 = $this->bank_db->getBankInfo('5!3_2l1$3*0'); + $bank_info_4 = $this->bank_db->getBankInfo('5321300000000000'); + $bank_info_5 = $this->bank_db->getBankInfo(''); + + $this->assertFalse($bank_info_1->isUnknown()); + $this->assertSame($bank_info_2->getTitle(), $bank_info_1->getTitle()); + $this->assertSame($bank_info_3->getTitle(), $bank_info_1->getTitle()); + $this->assertSame($bank_info_4->getTitle(), $bank_info_1->getTitle()); + $this->assertTrue($bank_info_5->isUnknown()); + } + + public function testCardTypes(): void + { + // amex + $this->assertSame('amex', $this->bank_db->getBankInfo('340000')->getCardType()); + $this->assertSame('amex', $this->bank_db->getBankInfo('370000')->getCardType()); + + // unionpay + $this->assertSame('unionpay', $this->bank_db->getBankInfo('620000')->getCardType()); + $this->assertSame('unionpay', $this->bank_db->getBankInfo('880000')->getCardType()); + + // discover + $this->assertSame('discover', $this->bank_db->getBankInfo('601100')->getCardType()); + $this->assertSame('discover', $this->bank_db->getBankInfo('640000')->getCardType()); + $this->assertSame('discover', $this->bank_db->getBankInfo('650000')->getCardType()); + + // electron + $this->assertSame('electron', $this->bank_db->getBankInfo('402600')->getCardType()); + $this->assertSame('electron', $this->bank_db->getBankInfo('417500')->getCardType()); + + // interpayment + $this->assertSame('interpayment', $this->bank_db->getBankInfo('636000')->getCardType()); + + // maestro + $this->assertSame('maestro', $this->bank_db->getBankInfo('501800')->getCardType()); + $this->assertSame('maestro', $this->bank_db->getBankInfo('561200')->getCardType()); + $this->assertSame('maestro', $this->bank_db->getBankInfo('589300')->getCardType()); + $this->assertSame('maestro', $this->bank_db->getBankInfo('630400')->getCardType()); + $this->assertSame('maestro', $this->bank_db->getBankInfo('639000')->getCardType()); + + // visa + $this->assertSame('visa', $this->bank_db->getBankInfo('411111')->getCardType()); + $this->assertSame('visa', $this->bank_db->getBankInfo('400000')->getCardType()); + + // mastercard + $this->assertSame('mastercard', $this->bank_db->getBankInfo('510000')->getCardType()); + $this->assertSame('mastercard', $this->bank_db->getBankInfo('520000')->getCardType()); + $this->assertSame('mastercard', $this->bank_db->getBankInfo('530000')->getCardType()); + $this->assertSame('mastercard', $this->bank_db->getBankInfo('540000')->getCardType()); + $this->assertSame('mastercard', $this->bank_db->getBankInfo('550000')->getCardType()); + $this->assertSame('mastercard', $this->bank_db->getBankInfo('222100')->getCardType()); + $this->assertSame('mastercard', $this->bank_db->getBankInfo('259000')->getCardType()); + $this->assertSame('mastercard', $this->bank_db->getBankInfo('272000')->getCardType()); + + // diners + $this->assertSame('diners', $this->bank_db->getBankInfo('360000')->getCardType()); + $this->assertSame('diners', $this->bank_db->getBankInfo('300000')->getCardType()); + $this->assertSame('diners', $this->bank_db->getBankInfo('305000')->getCardType()); + $this->assertSame('diners', $this->bank_db->getBankInfo('309500')->getCardType()); + $this->assertSame('diners', $this->bank_db->getBankInfo('380000')->getCardType()); + $this->assertSame('diners', $this->bank_db->getBankInfo('390000')->getCardType()); + + // jcb + $this->assertSame('jcb', $this->bank_db->getBankInfo('352800')->getCardType()); + $this->assertSame('jcb', $this->bank_db->getBankInfo('355000')->getCardType()); + $this->assertSame('jcb', $this->bank_db->getBankInfo('358900')->getCardType()); + + // mir + $this->assertSame('mir', $this->bank_db->getBankInfo('220000')->getCardType()); + $this->assertSame('mir', $this->bank_db->getBankInfo('220400')->getCardType()); + } + + public function testBanks(): void + { + $this->assertSame('Rocketbank', $this->bank_db->getBankInfo('532130')->getTitle(false)); + $this->assertSame('Alfa-Bank', $this->bank_db->getBankInfo($this->valid_prefix)->getTitle(false)); + + // $this->assertSame('Millennium', $this->bank_db->getBankInfo('487474')->getTitle(false)); + } + + public function testColor(): void + { + $this->assertRegExp('/^#[a-f0-9]{6}$/', $this->bank_db->getBankInfo($this->valid_prefix)->getColor()); + $this->assertRegExp('/^#[a-f0-9]{6}$/', $this->bank_db->getBankInfo('')->getColor()); + } + + public function testCountryCode(): void + { + $this->assertSame('ru', $this->bank_db->getBankInfo($this->valid_prefix)->getCountryCode()); + } + + public function testUrl(): void + { + $this->assertRegExp('/^https?:\/\//', $this->bank_db->getBankInfo($this->valid_prefix)->getUrl()); + } + + public function testDefunct(): void + { + $this->assertFalse($this->bank_db->getBankInfo($this->valid_prefix)->isDefunct()); + } +}