├── .github
├── dependabot.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── .gitmodules
├── .php-cs-fixer.dist.php
├── .travis.yml
├── LICENSE
├── README.md
├── composer.json
├── db
└── bank_db.php
├── parse.php
├── phpcs.xml
├── phpunit.xml
├── psalm.xml
├── rector.php
├── src
├── BankDb.php
├── BankDbException.php
└── BankInfo.php
└── tests
└── BankDb
├── BankDbTest.php
└── BankInfoTest.php
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: gitsubmodule
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 | reviewers:
9 | - chekalsky
10 | assignees:
11 | - chekalsky
12 |
13 | - package-ecosystem: composer
14 | directory: "/"
15 | schedule:
16 | interval: weekly
17 | open-pull-requests-limit: 10
18 | reviewers:
19 | - chekalsky
20 | assignees:
21 | - chekalsky
22 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: PHP Tests
2 |
3 | on:
4 | pull_request:
5 |
6 | jobs:
7 | php-lint:
8 | name: PHP Lint
9 | runs-on: ubuntu-latest
10 | strategy:
11 | matrix:
12 | php-version: [ '8.3', '8.4' ]
13 | steps:
14 | - uses: actions/checkout@v4
15 |
16 | - name: Setup PHP with tools
17 | uses: shivammathur/setup-php@v2
18 | with:
19 | php-version: ${{ matrix.php-version }}
20 | tools: php-cs-fixer, cs2pr
21 |
22 | - name: PHP CS Fixer
23 | #run: php-cs-fixer fix --using-cache=no --dry-run --format=checkstyle | cs2pr
24 | # tmp fix for PHP 8.4
25 | run: PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix --using-cache=no --dry-run --format=checkstyle | cs2pr
26 |
27 | php-unit:
28 | name: PHP Unit Tests (php${{ matrix.php-versions }})
29 | runs-on: ubuntu-latest
30 | continue-on-error: ${{ matrix.experimental }}
31 | strategy:
32 | fail-fast: false
33 | matrix:
34 | php-versions: [ '8.3', '8.4' ]
35 | experimental: [ false ]
36 | #include:
37 | # - php-versions: '8.1'
38 | # experimental: true
39 | steps:
40 | - uses: actions/checkout@v4
41 |
42 | - name: Setup PHP with tools
43 | uses: shivammathur/setup-php@v2
44 | with:
45 | php-version: ${{ matrix.php-versions }}
46 | tools: composer
47 |
48 | - name: Get Composer Cache Directory
49 | id: composer-cache
50 | run: |
51 | echo "::set-output name=dir::$(composer config cache-files-dir)"
52 |
53 | - uses: actions/cache@v4
54 | with:
55 | path: ${{ steps.composer-cache.outputs.dir }}
56 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
57 | restore-keys: |
58 | ${{ runner.os }}-composer-
59 |
60 | - name: Setup problem matchers for PHPUnit
61 | run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
62 |
63 | - name: Install dependencies
64 | run: composer install --prefer-dist --no-progress
65 |
66 | - name: PHPUnit
67 | run: vendor/bin/phpunit
68 |
69 | psalm:
70 | name: PHP Static Analysis (php${{ matrix.php-versions }})
71 | runs-on: ubuntu-latest
72 | continue-on-error: ${{ matrix.experimental }}
73 | strategy:
74 | fail-fast: false
75 | matrix:
76 | php-versions: [ '8.3', '8.4' ]
77 | experimental: [ false ]
78 | #include:
79 | # - php-versions: '8.1'
80 | # experimental: true
81 | steps:
82 | - uses: actions/checkout@v4
83 |
84 | - name: Setup PHP with tools
85 | uses: shivammathur/setup-php@v2
86 | with:
87 | php-version: ${{ matrix.php-versions }}
88 | tools: composer, psalm
89 |
90 | - name: Get Composer Cache Directory
91 | id: composer-cache
92 | run: |
93 | echo "::set-output name=dir::$(composer config cache-files-dir)"
94 |
95 | - uses: actions/cache@v4
96 | with:
97 | path: ${{ steps.composer-cache.outputs.dir }}
98 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
99 | restore-keys: |
100 | ${{ runner.os }}-composer-
101 |
102 | - name: Install dependencies
103 | run: composer install --prefer-dist --no-progress
104 |
105 | - name: Psalm
106 | run: psalm --output-format=github
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | vendor
3 | composer.lock
4 | .phpunit.result.cache
5 | .php_cs.cache
6 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "banks-db"]
2 | path = banks-db
3 | url = https://github.com/ramoona/banks-db.git
4 |
--------------------------------------------------------------------------------
/.php-cs-fixer.dist.php:
--------------------------------------------------------------------------------
1 | in(__DIR__)
5 | ->exclude('vendor')
6 | ->exclude('banks-db');
7 |
8 | $config = new PhpCsFixer\Config();
9 |
10 | return $config->setUsingCache(true)
11 | ->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
12 | ->setCacheFile(__DIR__ . '/.php_cs.cache')
13 | ->setRules([
14 | '@PER-CS2.0' => true,
15 | 'align_multiline_comment' => true,
16 | 'blank_line_before_statement' => ['statements' => ['continue', 'declare', 'return', 'throw', 'try']],
17 | 'class_attributes_separation' => ['elements' => ['method' => 'one']],
18 | 'no_empty_statement' => true,
19 | 'no_leading_namespace_whitespace' => true,
20 | 'no_multiline_whitespace_around_double_arrow' => true,
21 | 'multiline_whitespace_before_semicolons' => false,
22 | 'no_unused_imports' => true,
23 | 'no_unneeded_import_alias' => true,
24 | 'no_whitespace_before_comma_in_array' => true,
25 | 'no_whitespace_in_blank_line' => true,
26 | 'single_import_per_statement' => true,
27 | 'ordered_imports' => [
28 | 'sort_algorithm' => 'alpha',
29 | 'imports_order' => ['class', 'function', 'const'],
30 | ],
31 | 'phpdoc_add_missing_param_annotation' => true,
32 | 'phpdoc_align' => true,
33 | 'phpdoc_annotation_without_dot' => true,
34 | 'phpdoc_indent' => true,
35 | 'phpdoc_no_empty_return' => true,
36 | 'phpdoc_no_useless_inheritdoc' => true,
37 | 'phpdoc_order' => true,
38 | 'phpdoc_return_self_reference' => ['replacements' => ['this' => 'self']],
39 | 'phpdoc_scalar' => true,
40 | 'phpdoc_separation' => ['skip_unlisted_annotations' => true],
41 | 'phpdoc_single_line_var_spacing' => true,
42 | 'phpdoc_trim' => true,
43 | 'phpdoc_trim_consecutive_blank_line_separation' => true,
44 | 'phpdoc_types_order' => true,
45 | 'phpdoc_var_annotation_correct_order' => true,
46 | 'phpdoc_var_without_name' => true,
47 | 'single_quote' => true,
48 | 'short_scalar_cast' => true,
49 | 'standardize_not_equals' => true,
50 | 'ternary_operator_spaces' => true,
51 | 'ternary_to_null_coalescing' => true,
52 | 'trim_array_spaces' => true,
53 | 'visibility_required' => ['elements' => ['property', 'method', 'const']],
54 | 'yoda_style' => false,
55 | 'no_trailing_comma_in_singleline' => true,
56 | 'single_line_after_imports' => true,
57 | 'global_namespace_import' => [
58 | 'import_classes' => true,
59 | 'import_constants' => true,
60 | 'import_functions' => true,
61 | ],
62 | 'clean_namespace' => true,
63 | ])
64 | ->setFinder($finder);
65 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.2
5 | - 7.3
6 | - 7.4
7 |
8 | install:
9 | - travis_retry composer self-update
10 | - travis_retry composer install --no-interaction --no-suggest --prefer-dist
11 |
12 | script:
13 | - composer test
14 |
15 | after_success:
16 | - bash <(curl -s https://codecov.io/bash)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Ilya Chekalskiy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP Banks DB
2 |
3 | [](https://github.com/chekalsky/php-banks-db/actions/workflows/ci.yml)
4 |
5 | > It is a PHP port of [ramoona's banks-db](https://github.com/ramoona/banks-db).
6 |
7 | Returns bank's name and brand color by bank card number's first digits (BIN, Issuer Identification Numbers, IIN).
8 |
9 | ### Installation
10 |
11 | ```
12 | composer require chekalskiy/php-banks-db
13 | ```
14 |
15 | ### Basic usage
16 |
17 | ```php
18 | $card_prefix = '5275 9400 0000 0000'; // we only need first 6 digits but it could be the whole card number
19 |
20 | try {
21 | $bank_db = new BankDb();
22 | $bank_info = $bank_db->getBankInfo($card_prefix);
23 |
24 | $result = [
25 | 'is_unknown' => $bank_info->isUnknown(), // is bank unknown
26 | 'name' => $bank_info->getTitle(true),
27 | 'color' => $bank_info->getColor(),
28 | 'type' => $bank_info->getCardType(),
29 | ];
30 |
31 | return $result;
32 | } catch (BankDbException $e) {
33 | // todo handle exception
34 | }
35 | ```
36 |
37 | ### About database
38 |
39 | We use simple PHP-file with an array inside (it's regenerates every time ramoona's repository is updated). It's very fast and simple way to work with data because of opcache enabled by default in PHP 7. But you can extend `BankDB` class to make it work with redis or something, but for most cases compiled php-file is OK.
40 |
41 | #### Database update
42 | Database updates from [original library](https://github.com/ramoona/banks-db) by me. To update php cache file after manual database change run `composer rebuild`.
43 |
44 | ### Contributions
45 |
46 | Feel free to open [an issue](https://github.com/chekalskiy/php-banks-db/issues) on every question you have. If you have new prefixes for database please commit them to [ramoona/banks-db repository](https://github.com/ramoona/banks-db) — I will update them once your PR will me merged there.
47 |
48 | ---
49 |
50 | > It's a community driven database, so it can potentially contains mistakes.
51 |
52 | For UI examples see the [original library](https://github.com/ramoona/banks-db).
53 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chekalskiy/php-banks-db",
3 | "description": "PHP bank cards IIN/BIN database. Get bank info by card number",
4 | "license": "MIT",
5 | "keywords": ["bin", "card", "creditcard", "iin", "issuer identification numbers"],
6 | "homepage": "https://github.com/chekalsky/php-banks-db",
7 | "authors": [
8 | {
9 | "name": "Ilya Chekalsky",
10 | "email": "ilya@chekalsky.com",
11 | "homepage": "https://chekalsky.com"
12 | }
13 | ],
14 | "require": {
15 | "php": ">=8.3"
16 | },
17 | "require-dev": {
18 | "ext-json": "*",
19 | "phpunit/phpunit": "^12.0",
20 | "rector/rector": "^2.0",
21 | "symfony/var-exporter": "^7.2"
22 | },
23 | "autoload": {
24 | "psr-4": {
25 | "BankDb\\": "src/"
26 | }
27 | },
28 | "scripts": {
29 | "test": [
30 | "vendor/bin/phpunit --coverage-clover=coverage.xml"
31 | ],
32 | "lint": [
33 | "vendor/bin/php-cs-fixer fix --config=.php_cs",
34 | "vendor/bin/phpcbf -w"
35 | ],
36 | "rebuild": [
37 | "php parse.php"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/parse.php:
--------------------------------------------------------------------------------
1 | [],
26 | 'banks' => [],
27 | ];
28 |
29 | $bank_id = 0;
30 | $max_length = 6;
31 |
32 | $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($banks_db_path));
33 |
34 | /** @var SplFileInfo $file */
35 | foreach ($rii as $file) {
36 | if ($file->isDir()) {
37 | continue;
38 | }
39 |
40 | if ($file->getExtension() !== 'json') {
41 | continue;
42 | }
43 |
44 | $json_file = $file->openFile();
45 |
46 | $contents = $json_file->fread($json_file->getSize());
47 |
48 | $bank_data = json_decode($contents, true);
49 |
50 | if (!isset($bank_data['prefixes'])) {
51 | printError('Corrupted file: ' . $file->getPathname());
52 |
53 | continue;
54 | }
55 |
56 | ++$bank_id;
57 |
58 | $bank_data_stored = $bank_data;
59 | unset($bank_data_stored['prefixes']);
60 |
61 | $database['banks'][$bank_id] = $bank_data_stored;
62 |
63 | foreach ($bank_data['prefixes'] as $prefix) {
64 | $len = strlen((string) $prefix);
65 |
66 | for ($i = $len; $i <= $len; $i++) {
67 | $len_diff = $max_length - $len;
68 |
69 | if ($len_diff > 0) {
70 | for ($l = 1; $l <= $len_diff; $l++) {
71 | $count_prefixes = 10 ** $l;
72 |
73 | for ($k = 0; $k < $count_prefixes; $k++) {
74 | $new_prefix = (int) sprintf('%d%d', $prefix, $k);
75 |
76 | addPrefix($new_prefix, $bank_id, $database);
77 | }
78 | }
79 | } else {
80 | addPrefix($prefix, $bank_id, $database);
81 | }
82 | }
83 | }
84 | }
85 |
86 | $database_export = sprintf(" %s)', $prefix, $bank_id, $database['prefixes'][$prefix]));
105 |
106 | return;
107 | }
108 |
109 | $database['prefixes'][$prefix] = $bank_id;
110 | }
111 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | parse.php
15 | src/
16 | tests/
17 |
18 |
19 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ./src
6 |
7 |
8 |
9 |
10 | tests
11 |
12 |
13 |
--------------------------------------------------------------------------------
/psalm.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/rector.php:
--------------------------------------------------------------------------------
1 | withPaths([
9 | __DIR__ . '/src',
10 | __DIR__ . '/tests',
11 | ])
12 | ->withPhpSets()
13 | ->withTypeCoverageLevel(0)
14 | ->withDeadCodeLevel(0)
15 | ->withCodeQualityLevel(0);
16 |
--------------------------------------------------------------------------------
/src/BankDb.php:
--------------------------------------------------------------------------------
1 | initializeDatabase($db_file_path);
29 | }
30 |
31 | /**
32 | * @param string $card_number
33 | *
34 | * @return BankInfo
35 | */
36 | public function getBankInfo(string $card_number): BankInfo
37 | {
38 | $card_number = preg_replace('/\D/', '', $card_number);
39 |
40 | $prefix = str_pad(substr((string) $card_number, 0, static::PREFIX_LENGTH), static::PREFIX_LENGTH, '0');
41 |
42 | $bank_id = $this->getBankIdByPrefix((int) $prefix);
43 |
44 | if ($bank_id > 0) {
45 | return new BankInfo($this->getBankInfoFromDatabase($bank_id), $prefix);
46 | }
47 |
48 | return new BankInfo([], $card_number);
49 | }
50 |
51 | /**
52 | * Database init
53 | *
54 | * @param null|string $file_path
55 | *
56 | * @throws BankDbException
57 | */
58 | protected function initializeDatabase(string $file_path = null): void
59 | {
60 | if ($file_path === null) {
61 | $file_path = __DIR__ . '/../db/bank_db.php';
62 | }
63 |
64 | if (!is_readable($file_path)) {
65 | throw new BankDbException('Cannot find DB file');
66 | }
67 |
68 | $this->database = include $file_path;
69 | }
70 |
71 | /**
72 | * @param int $prefix
73 | *
74 | * @return int `0` if not found
75 | */
76 | protected function getBankIdByPrefix(int $prefix): int
77 | {
78 | if (isset($this->database['prefixes'][$prefix])) {
79 | return (int) $this->database['prefixes'][$prefix];
80 | }
81 |
82 | return 0;
83 | }
84 |
85 | /**
86 | * @param int $id
87 | *
88 | * @return array
89 | */
90 | protected function getBankInfoFromDatabase(int $id): array
91 | {
92 | return $this->database['banks'][$id];
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/BankDbException.php:
--------------------------------------------------------------------------------
1 | '/^(4026|417500|4405|4508|4844|4913|4917)/',
34 | 'interpayment' => '/^636/',
35 | 'unionpay' => '/^(62|88)/',
36 | 'discover' => '/^6(?:011|4|5)/',
37 | 'maestro' => '/^(50|5[6-9]|6)/',
38 | 'visa' => '/^4/',
39 | '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]
40 | 'amex' => '/^3[47]/',
41 | 'diners' => '/^3(?:0([0-5]|95)|[689])/',
42 | 'jcb' => '/^(?:2131|1800|(?:352[89]|35[3-8][0-9]))/', // 3528-3589
43 | 'mir' => '/^220[0-4]/',
44 | ];
45 |
46 | public function __construct(protected array $data, string $prefix = '')
47 | {
48 | if (!isset($this->data['name'])) {
49 | $this->makeUnknown();
50 | }
51 |
52 | $prefix = substr($prefix, 0, static::PREFIX_LENGTH);
53 |
54 | foreach (static::$card_prefixes as $card_type => $card_prefix) {
55 | if (preg_match($card_prefix, $prefix)) {
56 | $this->card_type = $card_type;
57 | break;
58 | }
59 | }
60 | }
61 |
62 | public function getTitle(bool $is_local = true): string
63 | {
64 | if ($is_local && isset($this->data['localTitle'])) {
65 | return $this->data['localTitle'];
66 | }
67 |
68 | return $this->data['engTitle'] ?? $this->data['name'];
69 | }
70 |
71 | public function getCountryCode(): string
72 | {
73 | return $this->data['country'];
74 | }
75 |
76 | public function getUrl(): string
77 | {
78 | return $this->data['url'];
79 | }
80 |
81 | /**
82 | * @return string in hex format `#0088cf`
83 | */
84 | public function getColor(): string
85 | {
86 | return $this->data['color'];
87 | }
88 |
89 | /**
90 | * @return bool returns true for banks with revoked license
91 | */
92 | public function isDefunct(): bool
93 | {
94 | return isset($this->data['defunct']) && $this->data['defunct'];
95 | }
96 |
97 | /**
98 | * @return bool
99 | */
100 | public function isUnknown(): bool
101 | {
102 | return $this->is_unknown;
103 | }
104 |
105 | /**
106 | * Card type from prefix
107 | *
108 | * For possible types see `$card_prefixes`
109 | *
110 | * @return string
111 | */
112 | public function getCardType(): string
113 | {
114 | return $this->card_type;
115 | }
116 |
117 | /**
118 | * Make this bank object unknown
119 | */
120 | protected function makeUnknown(): void
121 | {
122 | $this->is_unknown = true;
123 | $this->data = [
124 | 'name' => 'unknown',
125 | 'localTitle' => 'Unknown Bank',
126 | 'engTitle' => 'Unknown Bank',
127 | 'country' => 'us',
128 | 'url' => '',
129 | 'color' => '#ffffff',
130 | ];
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/tests/BankDb/BankDbTest.php:
--------------------------------------------------------------------------------
1 | bankDb = new BankDb();
16 | }
17 |
18 | public function testCanBeConstructed(): void
19 | {
20 | $this->assertNotEmpty($this->bankDb);
21 | }
22 |
23 | public function testExceptionIfDatabaseNotFound(): void
24 | {
25 | $this->expectException(BankDbException::class);
26 |
27 | new BankDb('/unknown/path');
28 | }
29 |
30 | public function testGetBankInfoIsWorking(): void
31 | {
32 | $bank_info = $this->bankDb->getBankInfo('400000');
33 |
34 | $this->assertTrue($bank_info->isUnknown());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/BankDb/BankInfoTest.php:
--------------------------------------------------------------------------------
1 | bankDb = new BankDb();
18 | }
19 |
20 | #[DataProvider('anyInputProvider')]
21 | public function testAnyInput(string $input, bool $expectedUnknown, ?string $compareWith = null): void
22 | {
23 | $bankInfo = $this->bankDb->getBankInfo($input);
24 |
25 | $this->assertSame($expectedUnknown, $bankInfo->isUnknown());
26 |
27 | if ($compareWith !== null) {
28 | $this->assertSame(
29 | $this->bankDb->getBankInfo($compareWith)->getTitle(),
30 | $bankInfo->getTitle(),
31 | );
32 | }
33 | }
34 |
35 | public static function anyInputProvider(): array
36 | {
37 | return [
38 | 'spaced input' => ['5321 30', false, '532130'],
39 | 'clean input' => ['522319', false, '522319'],
40 | 'special chars' => ['5!3_2l1$3*0', false, '532130'],
41 | 'long number' => ['5321300000000000', false, '532130'],
42 | 'short valid number' => ['48153', false, '48153'],
43 | 'empty input' => ['', true, null],
44 | ];
45 | }
46 |
47 | #[DataProvider('cardTypesProvider')]
48 | public function testCardTypes(string $prefix, string $expectedType): void
49 | {
50 | $this->assertSame($expectedType, $this->bankDb->getBankInfo($prefix)->getCardType());
51 | }
52 |
53 | public static function cardTypesProvider(): array
54 | {
55 | return [
56 | 'amex 1' => ['340000', 'amex'],
57 | 'amex 2' => ['370000', 'amex'],
58 | 'unionpay 1' => ['620000', 'unionpay'],
59 | 'unionpay 2' => ['880000', 'unionpay'],
60 | 'discover 1' => ['601100', 'discover'],
61 | 'discover 2' => ['640000', 'discover'],
62 | 'discover 3' => ['650000', 'discover'],
63 | 'electron 1' => ['402600', 'electron'],
64 | 'electron 2' => ['417500', 'electron'],
65 | 'interpayment' => ['636000', 'interpayment'],
66 | 'maestro 1' => ['501800', 'maestro'],
67 | 'maestro 2' => ['561200', 'maestro'],
68 | 'maestro 3' => ['589300', 'maestro'],
69 | 'maestro 4' => ['630400', 'maestro'],
70 | 'maestro 5' => ['639000', 'maestro'],
71 | 'visa 1' => ['4', 'visa'],
72 | 'visa 2' => ['411111', 'visa'],
73 | 'visa 3' => ['400000', 'visa'],
74 | 'mastercard 1' => ['51', 'mastercard'],
75 | 'mastercard 2' => ['510000', 'mastercard'],
76 | 'mastercard 3' => ['520000', 'mastercard'],
77 | 'mastercard 4' => ['530000', 'mastercard'],
78 | 'mastercard 5' => ['540000', 'mastercard'],
79 | 'mastercard 6' => ['550000', 'mastercard'],
80 | 'mastercard 7' => ['222100', 'mastercard'],
81 | 'mastercard 8' => ['259000', 'mastercard'],
82 | 'mastercard 9' => ['272000', 'mastercard'],
83 | 'diners 1' => ['360000', 'diners'],
84 | 'diners 2' => ['300000', 'diners'],
85 | 'diners 3' => ['305000', 'diners'],
86 | 'diners 4' => ['309500', 'diners'],
87 | 'diners 5' => ['380000', 'diners'],
88 | 'diners 6' => ['390000', 'diners'],
89 | 'jcb 1' => ['352800', 'jcb'],
90 | 'jcb 2' => ['355000', 'jcb'],
91 | 'jcb 3' => ['358900', 'jcb'],
92 | 'mir 1' => ['220000', 'mir'],
93 | 'mir 2' => ['220400', 'mir'],
94 | ];
95 | }
96 |
97 | #[DataProvider('banksProvider')]
98 | public function testBanks(string $prefix, string $expectedTitle): void
99 | {
100 | $this->assertSame($expectedTitle, $this->bankDb->getBankInfo($prefix)->getTitle(false));
101 | }
102 |
103 | public static function banksProvider(): array
104 | {
105 | return [
106 | 'Bank Otkritie' => ['532130', 'Bank Otkritie'],
107 | 'Alfa-Bank' => ['428906', 'Alfa-Bank'],
108 | ];
109 | }
110 |
111 | #[DataProvider('prefixProvider')]
112 | public function testColor(string $prefix): void
113 | {
114 | $this->assertMatchesRegularExpression(
115 | '/^#[a-f0-9]{6}$/',
116 | $this->bankDb->getBankInfo($prefix)->getColor(),
117 | );
118 | }
119 |
120 | public static function prefixProvider(): array
121 | {
122 | return [
123 | 'valid prefix' => ['428906'],
124 | 'empty prefix' => [''],
125 | ];
126 | }
127 |
128 | public function testCountryCode(): void
129 | {
130 | $this->assertSame('ru', $this->bankDb->getBankInfo('428906')->getCountryCode());
131 | }
132 |
133 | public function testUrl(): void
134 | {
135 | $this->assertMatchesRegularExpression(
136 | '/^https?:\/\//',
137 | $this->bankDb->getBankInfo('428906')->getUrl(),
138 | );
139 | }
140 |
141 | public function testDefunct(): void
142 | {
143 | $this->assertFalse($this->bankDb->getBankInfo('428906')->isDefunct());
144 | }
145 | }
146 |
--------------------------------------------------------------------------------