Skip to content

Instantly share code, notes, and snippets.

@shlaikov
Created October 26, 2017 10:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shlaikov/71ea369fda5ba0f34220dce76c4b9b0c to your computer and use it in GitHub Desktop.
Save shlaikov/71ea369fda5ba0f34220dce76c4b9b0c to your computer and use it in GitHub Desktop.
ZendValidator validate and Card type detection with MIR.
<?php
class CardScheme
{
const CARD_TYPE_MASTERCARD = 'MASTERCARD';
const CARD_TYPE_MAESTRO = 'MAESTRO';
const CARD_TYPE_MIR = 'MIR';
const CARD_TYPE_VISA = 'VISA';
protected $panNumber;
protected $bin;
protected $binType = [
self::CARD_TYPE_MASTERCARD => [
'2221', '2222', '2223', '2224', '2225',
'2226', '2227', '2228', '2229', '223',
'224', '225', '226', '227', '228', '229',
'23', '24', '25', '26', '271', '2720',
'51', '52', '53', '54', '55'
],
self::CARD_TYPE_MAESTRO => [
'5018', '5020', '5038', '6304',
'6759', '6761', '6762', '6763',
'6764', '6765', '6766', '6772'],
self::CARD_TYPE_MIR => [
'2200', '2201', '2202', '2203', '2204'
],
self::CARD_TYPE_VISA => ['4'],
];
public function __construct($number)
{
if (strpos($number, '**') === false) {
$this->panNumber = $number;
} else {
$this->bin = substr($number, 0, 4);
}
}
public function detect()
{
foreach ($this->getCardTypes() as $type) {
$validator = $this->getCreditCardValidator($type);
$type = strtoupper($type);
if (!is_null($this->panNumber) && $validator->isValid($this->panNumber)) {
return $type;
}
foreach ($this->binType[$type] as $prefix) {
if (substr($this->bin, 0, strlen($prefix)) == $prefix) {
return $type;
}
}
}
throw new Exception(new Translatable('undefined_card_scheme'));
}
protected function getCreditCardValidator($cardType)
{
try {
return new CreditCard($cardType);
} catch (ProjectException $e) {
throw new ProjectException('Undefined card type in ZendValidator');
}
}
protected function getCardTypes()
{
return Project::getInstance()->getConfig()->constants->cardScheme->toArray();
}
}
<?php
class CardSchemeTest extends PHPUnit_Framework_TestCase
{
protected function getClass($number)
{
return new CardScheme($number);
}
protected static function callMethod($obj, $name, array $args = [])
{
$class = new ReflectionClass($obj);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method->invokeArgs($obj, $args);
}
public function testGetCreditCardValidator()
{
$object = $this->getClass('491699****707706');
$return = self::callMethod(
$object,
'getCreditCardValidator',
['example']
);
$this->assertInstanceOf('CreditCard', $return);
$this->assertNotEmpty($return);
}
public function testDetect()
{
$this->assertEquals('VISA', $this->getClass('4916995193707706')->detect());
$this->assertEquals('MASTERCARD', $this->getClass('5466816173389102')->detect());
$this->assertEquals('MAESTRO', $this->getClass('5020401701946068')->detect());
$this->assertEquals('MIR', $this->getClass('2201551236920281')->detect());
$this->assertEquals('VISA', $this->getClass('491699****707706')->detect());
$this->assertEquals('MASTERCARD', $this->getClass('546681****389102')->detect());
$this->assertEquals('MAESTRO', $this->getClass('502040****946068')->detect());
$this->assertEquals('MIR', $this->getClass('220155****920281')->detect());
}
public function testGetCardTypes()
{
$expected = Project::getInstance()->getConfig()->constants->cardScheme->toArray();
$object = $this->getClass('491699****707706');
$return = self::callMethod(
$object,
'getCardTypes'
);
$this->assertTrue(is_array($return));
$this->assertEquals($expected, $return);
}
}
<?php
use Zend\Validator\CreditCard as ZendCreditCard;
class CreditCard extends ZendCreditCard
{
const MIR = 'Mir';
public function __construct($options = [])
{
$this->addMir();
parent::__construct($options);
}
public function addType($type)
{
if (is_string($type)) {
$type = [$type];
}
foreach ($type as $typ) {
if (defined('self::' . strtoupper($typ)) && ! in_array($typ, $this->options['type'])) {
$this->options['type'][] = $typ;
}
if (($typ == self::ALL)) {
$this->options['type'] = array_keys($this->cardLength);
}
}
return $this;
}
protected function addMir()
{
$this->cardName[11] = self::MIR;
$this->cardLength[self::MIR] = [16];
$this->cardType[self::MIR] = ['2200', '2201', '2202', '2203', '2204'];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment