-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8456d08
commit b4cc5f1
Showing
6 changed files
with
282 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,3 @@ | ||
composer.phar | ||
composer.lock | ||
vendor |
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,22 @@ | ||
{ | ||
"name": "ariselseng/norwegianbanks", | ||
"autoload": { | ||
"psr-4": { | ||
"Ariselseng\\NorwegianBanks\\": "src/" | ||
} | ||
}, | ||
"require": { | ||
"phpoffice/phpspreadsheet": "^1.9", | ||
"komakino/modulus11": "^1.0", | ||
"desarrolla2/cache": "^3.0", | ||
"guzzlehttp/guzzle": "^6.5" | ||
}, | ||
"require-dev": { | ||
"phpunit/phpunit": "4.*" | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"Ariselseng\\NorwegianBanks\\Tests\\": "tests/" | ||
} | ||
} | ||
} |
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,19 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phpunit backupGlobals="false" | ||
backupStaticAttributes="false" | ||
bootstrap="vendor/autoload.php" | ||
colors="true" | ||
convertErrorsToExceptions="true" | ||
convertNoticesToExceptions="true" | ||
convertWarningsToExceptions="true" | ||
processIsolation="false" | ||
stopOnFailure="false" | ||
syntaxCheck="false" | ||
verbose="true" | ||
> | ||
<testsuites> | ||
<testsuite name="Package Test Suite"> | ||
<directory suffix=".php">./tests/</directory> | ||
</testsuite> | ||
</testsuites> | ||
</phpunit> |
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,21 @@ | ||
<?php | ||
|
||
namespace Ariselseng\NorwegianBanks; | ||
|
||
|
||
class NorwegianBank | ||
{ | ||
public $bankCode; | ||
public $bankName; | ||
public $prefixes; | ||
|
||
function __construct(string $bankCode, string $bankName, array $prefixes = []) | ||
{ | ||
$this->bankCode = $bankCode; | ||
$this->bankName = $bankName; | ||
$this->prefixes = $prefixes; | ||
} | ||
public function addPrefix(string $prefix) { | ||
$this->prefixes[] = $prefix; | ||
} | ||
} |
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,139 @@ | ||
<?php | ||
|
||
namespace Ariselseng\NorwegianBanks; | ||
|
||
use Komakino\Modulus11\Modulus11; | ||
use Desarrolla2\Cache\File as FileCache; | ||
|
||
class NorwegianBanks | ||
{ | ||
private const XlsFileUrl = 'https://www.finansnorge.no/contentassets/cc4fabf26cea4569aa447aa9ae671efa/norwegian-iban-bic-table.xls'; | ||
private const xlsFileTtl = 1440; | ||
|
||
private $xlsFilePath; | ||
private $banks; | ||
private $prefixToBankCode; | ||
|
||
public function __construct() | ||
{ | ||
$this->xlsFilePath = sys_get_temp_dir() . '/.cache-norwegianbanks-norwegian-iban-bic-table.xls'; | ||
$this->processData(); | ||
} | ||
|
||
private function downloadData() | ||
{ | ||
|
||
$xlsFileExists = file_exists($this->xlsFilePath); | ||
if ($xlsFileExists && filemtime($this->xlsFilePath) <= (time() - self::xlsFileTtl)) { | ||
$headers = [ | ||
'If-Modified-Since' => gmdate('D, d M Y H:i:s T', filemtime($this->xlsFilePath)), | ||
]; | ||
} else if (!$xlsFileExists) { | ||
$headers = null; | ||
|
||
} else { | ||
return; | ||
} | ||
|
||
$response = (new \GuzzleHttp\Client())->get(self::XlsFileUrl, [ | ||
'headers' => $headers, | ||
]); | ||
|
||
if ($response->getStatusCode() === 200 && $response->getBody()->getSize() > 0) { | ||
file_put_contents($this->xlsFilePath, $response->getBody()->getContents(), LOCK_EX); | ||
} | ||
} | ||
|
||
private function processData() | ||
{ | ||
$this->downloadData(); | ||
$cacheDir = sys_get_temp_dir() . '/phpcache-norwegianbanks-' . filemtime($this->xlsFilePath); | ||
$hasCacheDir = file_exists($cacheDir); | ||
if (!$hasCacheDir) { | ||
$hasCacheDir = mkdir($cacheDir); | ||
} | ||
|
||
if ($hasCacheDir) { | ||
$cache = new FileCache($cacheDir); | ||
$banks = $cache->get('banks'); | ||
} | ||
|
||
if (!$hasCacheDir || !isset($banks)) { | ||
$banks = []; | ||
$prefixToBankCode = []; | ||
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader("Xls"); | ||
$reader->setReadDataOnly(true); | ||
|
||
$spreadsheet = $reader->load($this->xlsFilePath); | ||
$worksheet = $spreadsheet->getActiveSheet(); | ||
$rows = $worksheet->toArray(null, false, false, false); | ||
|
||
for ($i = 0; $i < count($rows); $i++) { | ||
if (is_null($rows[$i][1])) { | ||
continue; | ||
} | ||
if (!isset($banks[$rows[$i][1]])) { | ||
$banks[$rows[$i][1]] = new NorwegianBank($rows[$i][1], $rows[$i][2], [$rows[$i][0]]); | ||
} else { | ||
$banks[$rows[$i][1]]->addPrefix($rows[$i][0]); | ||
} | ||
$prefixToBankCode[$rows[$i][0]] = $rows[$i][1]; | ||
} | ||
|
||
if ($hasCacheDir) { | ||
$cache->set('banks', $banks, self::xlsFileTtl); | ||
$cache->set('prefixToBankCode', $prefixToBankCode, self::xlsFileTtl); | ||
} | ||
|
||
$this->banks = $banks; | ||
$this->prefixToBankCode = $prefixToBankCode; | ||
} else { | ||
$this->banks = $banks; | ||
$this->prefixToBankCode = $cache->get('prefixToBankCode'); | ||
} | ||
} | ||
public function getBankCodeByPrefix(string $prefix) | ||
{ | ||
|
||
if (!isset($this->prefixToBankCode[$prefix])) { | ||
return null; | ||
} | ||
return $this->prefixToBankCode[$prefix]; | ||
} | ||
|
||
public function getBankByAccountNumber(string $account) | ||
{ | ||
$prefix = substr($account, 0, 4); | ||
$bankCode = $this->getBankCodeByPrefix($prefix); | ||
if (is_null($bankCode)) { | ||
return null; | ||
} | ||
return $this->banks[$this->getBankCodeByPrefix($prefix)]; | ||
} | ||
|
||
public function getFormattedAccountNumber(string $unformattedAccount, string $delimiter = '.') | ||
{ | ||
$onlyDigits = preg_replace('/[^0-9]/', '', $unformattedAccount); | ||
return substr($onlyDigits, 0, 4) . $delimiter . substr($onlyDigits, 4, 2) . $delimiter . substr($onlyDigits, 6); | ||
} | ||
|
||
public function validateAccountNumber(string $account) | ||
{ | ||
$mod11 = Modulus11::validate($account); | ||
|
||
if (!$mod11) { | ||
return false; | ||
} | ||
|
||
return !is_null($this->getBankByAccountNumber(substr($account, 0, 4))); | ||
} | ||
} | ||
|
||
class NorwegianBanksStatic | ||
{ | ||
public static function __callStatic($method, $args) | ||
{ | ||
$obj = new NorwegianBanks(); | ||
return $obj->$method(...$args); | ||
} | ||
} |
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,78 @@ | ||
<?php | ||
|
||
namespace Ariselseng\NorwegianBanks\Tests; | ||
|
||
use Ariselseng\NorwegianBanks\NorwegianBanks; | ||
use Ariselseng\NorwegianBanks\NorwegianBanksStatic; | ||
|
||
class NorwegianBanksTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
protected $accounts = [ | ||
[ | ||
'bankCode' => 'DNBANOKK', | ||
'number' => '1594 22 87248' | ||
], | ||
[ | ||
'bankCode' => 'NDEANOKK', | ||
'number' => '61050659274' | ||
], | ||
[ | ||
'bankCode' => 'SPSONO22', | ||
'number' => '3000.27.79419' | ||
], | ||
]; | ||
protected $notRealAccountNumber = '1234.56.78903'; | ||
protected $notRealAccountNumberWithSpaces = '1234 56 78903'; | ||
protected $notRealAccountNumberUnformatted = '12345678903'; | ||
|
||
private $norwegianBanks; | ||
|
||
public function __construct() | ||
{ | ||
$this->norwegianBanks = new NorwegianBanks(); | ||
} | ||
|
||
public function testGetFormattedAccountNumber() | ||
{ | ||
$this->assertEquals($this->notRealAccountNumber, $this->norwegianBanks->getFormattedAccountNumber($this->notRealAccountNumberUnformatted)); | ||
$this->assertEquals($this->notRealAccountNumber, NorwegianBanksStatic::getFormattedAccountNumber($this->notRealAccountNumberUnformatted)); | ||
$this->assertEquals($this->notRealAccountNumberWithSpaces, $this->norwegianBanks->getFormattedAccountNumber($this->notRealAccountNumberUnformatted, ' ')); | ||
$this->assertEquals($this->notRealAccountNumberWithSpaces, NorwegianBanksStatic::getFormattedAccountNumber($this->notRealAccountNumberUnformatted, ' ')); | ||
} | ||
|
||
public function testGetBankCodeByPrefix() | ||
{ | ||
foreach ($this->accounts as $account) { | ||
$this->assertEquals($account['bankCode'], $this->norwegianBanks->getBankCodeByPrefix(substr($account['number'], 0, 4))); | ||
$this->assertEquals($account['bankCode'], NorwegianBanksStatic::getBankCodeByPrefix(substr($account['number'], 0, 4))); | ||
} | ||
$this->assertEquals(null, $this->norwegianBanks->getBankCodeByPrefix('0000')); | ||
$this->assertEquals(null, NorwegianBanksStatic::getBankCodeByPrefix('0000')); | ||
} | ||
|
||
public function testGetBankByAccountNumber() | ||
{ | ||
|
||
foreach ($this->accounts as $account) { | ||
$this->assertAttributeEquals($account['bankCode'], 'bankCode', $this->norwegianBanks->getBankByAccountNumber($account['number'])); | ||
$this->assertAttributeEquals($account['bankCode'], 'bankCode', NorwegianBanksStatic::getBankByAccountNumber($account['number'])); | ||
} | ||
|
||
$this->assertEquals(null, $this->norwegianBanks->getBankByAccountNumber($this->notRealAccountNumber)); | ||
$this->assertEquals(null, NorwegianBanksStatic::getBankByAccountNumber($this->notRealAccountNumber)); | ||
} | ||
|
||
public function testValidate() | ||
{ | ||
|
||
foreach ($this->accounts as $account) { | ||
$this->assertTrue($this->norwegianBanks->validateAccountNumber($account['number'])); | ||
$this->assertTrue(NorwegianBanksStatic::validateAccountNumber($account['number'])); | ||
|
||
} | ||
|
||
$this->assertFalse($this->norwegianBanks->validateAccountNumber($this->notRealAccountNumber)); | ||
$this->assertFalse(NorwegianBanksStatic::validateAccountNumber($this->notRealAccountNumber)); | ||
|
||
} | ||
} |