mirror of
https://github.com/Respect/Validation.git
synced 2024-05-29 11:52:34 +02:00
Allow the define brands for credit card validation
This commit is contained in:
parent
7a907e6795
commit
46541c7e46
|
@ -1,13 +1,30 @@
|
|||
# CreditCard
|
||||
|
||||
- `v::creditCard()`
|
||||
- `v::creditCard(string $brand)`
|
||||
|
||||
Validates a credit card number.
|
||||
|
||||
```php
|
||||
v::creditCard()->validate('5376 7473 9720 8720'); // true
|
||||
|
||||
v::creditCard('American Express')->validate('340316193809364'); // true
|
||||
v::creditCard('Diners Club')->validate('30351042633884'); // true
|
||||
v::creditCard('Discover')->validate('6011000990139424'); // true
|
||||
v::creditCard('JCB')->validate('3566002020360505'); // true
|
||||
v::creditCard('Master')->validate('5376747397208720'); // true
|
||||
v::creditCard('Visa')->validate('4024007153361885'); // true
|
||||
```
|
||||
|
||||
The current supported brands are:
|
||||
|
||||
- American Express
|
||||
- Diners Club
|
||||
- Discover
|
||||
- JCB
|
||||
- MasterCard
|
||||
- Visa
|
||||
|
||||
It ignores any non-digit chars, so use `->digit()` when appropriate.
|
||||
|
||||
```php
|
||||
|
|
|
@ -13,12 +13,25 @@ namespace Respect\Validation\Exceptions;
|
|||
|
||||
class CreditCardException extends ValidationException
|
||||
{
|
||||
const BRANDED = 1;
|
||||
|
||||
public static $defaultTemplates = [
|
||||
self::MODE_DEFAULT => [
|
||||
self::STANDARD => '{{name}} must be a valid Credit Card number',
|
||||
self::BRANDED => '{{name}} must be a valid {{brand}} Credit Card number',
|
||||
],
|
||||
self::MODE_NEGATIVE => [
|
||||
self::STANDARD => '{{name}} must not be a valid Credit Card number',
|
||||
self::BRANDED => '{{name}} must not be a valid {{brand}} Credit Card number',
|
||||
],
|
||||
];
|
||||
|
||||
public function chooseTemplate()
|
||||
{
|
||||
if (!$this->getParam('brand')) {
|
||||
return static::STANDARD;
|
||||
}
|
||||
|
||||
return static::BRANDED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,18 +11,73 @@
|
|||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ComponentException;
|
||||
|
||||
class CreditCard extends AbstractRule
|
||||
{
|
||||
const AMERICAN_EXPRESS = 'American Express';
|
||||
const DINERS_CLUB = 'Diners Club';
|
||||
const DISCOVER = 'Discover';
|
||||
const JCB = 'JCB';
|
||||
const MASTERCARD = 'MasterCard';
|
||||
const VISA = 'Visa';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $brand;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $brands = [
|
||||
self::AMERICAN_EXPRESS => '/^3[47]\d{13}$/',
|
||||
self::DINERS_CLUB => '/^3(?:0[0-5]|[68]\d)\d{11}$/',
|
||||
self::DISCOVER => '/^6(?:011|5\d{2})\d{12}$/',
|
||||
self::JCB => '/^(?:2131|1800|35\d{3})\d{11}$/',
|
||||
self::MASTERCARD => '/^5[1-5]\d{14}$/',
|
||||
self::VISA => '/^4\d{12}(?:\d{3})?$/',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string $brand Optional credit card brand.
|
||||
*/
|
||||
public function __construct($brand = null)
|
||||
{
|
||||
if (null !== $brand && !isset($this->brands[$brand])) {
|
||||
$brands = implode(', ', array_keys($this->brands));
|
||||
$message = sprintf('"%s" is not a valid credit card brand (Available: %s).', $brand, $brands);
|
||||
throw new ComponentException($message);
|
||||
}
|
||||
|
||||
$this->brand = $brand;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($input)
|
||||
{
|
||||
$input = preg_replace('([^0-9])', '', $input);
|
||||
if (!empty($input)) {
|
||||
return $this->verifyMod10($input);
|
||||
|
||||
if (empty($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!$this->verifyMod10($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->verifyBrand($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the input matches the Luhn algorithm or not.
|
||||
*
|
||||
* @param string $input
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function verifyMod10($input)
|
||||
{
|
||||
$sum = 0;
|
||||
|
@ -40,6 +95,24 @@ class CreditCard extends AbstractRule
|
|||
$sum += $current;
|
||||
}
|
||||
|
||||
return ($sum % 10 == 0);
|
||||
return $sum % 10 == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the input matches the defined credit card brand or not.
|
||||
*
|
||||
* @param string $input
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function verifyBrand($input)
|
||||
{
|
||||
if (null === $this->brand) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$pattern = $this->brands[$this->brand];
|
||||
|
||||
return preg_match($pattern, $input) > 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ use Respect\Validation\Rules\Key;
|
|||
* @method static Validator countryCode()
|
||||
* @method static Validator currencyCode()
|
||||
* @method static Validator cpf()
|
||||
* @method static Validator creditCard()
|
||||
* @method static Validator creditCard(string $brand = null)
|
||||
* @method static Validator date(string $format = null)
|
||||
* @method static Validator digit(string $additionalChars = null)
|
||||
* @method static Validator directory()
|
||||
|
|
16
tests/integration/rules/creditCard_4.phpt
Normal file
16
tests/integration/rules/creditCard_4.phpt
Normal file
|
@ -0,0 +1,16 @@
|
|||
--FILE--
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Respect\Validation\Exceptions\CreditCardException;
|
||||
use Respect\Validation\Validator as v;
|
||||
|
||||
try {
|
||||
v::creditCard('Visa')->check(3566002020360505);
|
||||
} catch (CreditCardException $e) {
|
||||
echo $e->getMainMessage().PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
3566002020360505 must be a valid "Visa" Credit Card number
|
|
@ -14,57 +14,85 @@ namespace Respect\Validation\Rules;
|
|||
/**
|
||||
* @group rule
|
||||
* @covers Respect\Validation\Rules\CreditCard
|
||||
* @covers Respect\Validation\Exceptions\CreditCardException
|
||||
*/
|
||||
class CreditCardTest extends \PHPUnit_Framework_TestCase
|
||||
class CreditCardTest extends RuleTestCase
|
||||
{
|
||||
protected $creditCardValidator;
|
||||
|
||||
protected function setUp()
|
||||
public function testShouldHaveNoCreditCardBrandByDefault()
|
||||
{
|
||||
$this->creditCardValidator = new CreditCard();
|
||||
$rule = new CreditCard();
|
||||
|
||||
$this->assertNull($rule->brand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerForCreditCard
|
||||
*/
|
||||
public function testValidCreditCardsShouldReturnTrue($input)
|
||||
public function testShouldAcceptCreditCardBrandOnConstructor()
|
||||
{
|
||||
$this->assertTrue($this->creditCardValidator->__invoke($input));
|
||||
$this->assertTrue($this->creditCardValidator->assert($input));
|
||||
$this->assertTrue($this->creditCardValidator->check($input));
|
||||
$rule = new CreditCard(CreditCard::VISA);
|
||||
|
||||
$this->assertSame(CreditCard::VISA, $rule->brand);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerForNotCreditCard
|
||||
* @expectedException Respect\Validation\Exceptions\CreditCardException
|
||||
*/
|
||||
public function testInvalidCreditCardsShouldThrowCreditCardException($input)
|
||||
public function testShouldThrowExceptionWhenCreditCardBrandIsNotValid()
|
||||
{
|
||||
$this->assertFalse($this->creditCardValidator->__invoke($input));
|
||||
$this->assertFalse($this->creditCardValidator->assert($input));
|
||||
$class = 'Respect\Validation\Exceptions\ComponentException';
|
||||
$message = '"RespectCard" is not a valid credit card brand';
|
||||
$message .= ' (Available: American Express, Diners Club, Discover, JCB, MasterCard, Visa).';
|
||||
|
||||
$this->setExpectedException($class, $message);
|
||||
|
||||
new CreditCard('RespectCard');
|
||||
}
|
||||
|
||||
public function providerForCreditCard()
|
||||
public function providerForValidInput()
|
||||
{
|
||||
$general = new CreditCard();
|
||||
$amex = new CreditCard(CreditCard::AMERICAN_EXPRESS);
|
||||
$diners = new CreditCard(CreditCard::DINERS_CLUB);
|
||||
$discover = new CreditCard(CreditCard::DISCOVER);
|
||||
$jcb = new CreditCard(CreditCard::JCB);
|
||||
$master = new CreditCard(CreditCard::MASTERCARD);
|
||||
$visa = new CreditCard(CreditCard::VISA);
|
||||
|
||||
return [
|
||||
['5376 7473 9720 8720'], // MasterCard
|
||||
['4024.0071.5336.1885'], // Visa 16
|
||||
['4024 007 193 879'], // Visa 13
|
||||
['340-3161-9380-9364'], // AmericanExpress
|
||||
['30351042633884'], // Dinners
|
||||
[$general, '5376 7473 9720 8720'], // MasterCard
|
||||
[$master, '5376 7473 9720 8720'],
|
||||
[$general, '4024.0071.5336.1885'], // Visa 16
|
||||
[$visa, '4024.0071.5336.1885'],
|
||||
[$general, '4024 007 193 879'], // Visa 13
|
||||
[$visa, '4024 007 193 879'],
|
||||
[$general, '340-3161-9380-9364'], // American Express
|
||||
[$amex, '340-3161-9380-9364'],
|
||||
[$general, '30351042633884'], // Diners Club
|
||||
[$diners, '30351042633884'],
|
||||
[$general, '6011000990139424'], // Discover
|
||||
[$discover, '6011000990139424'],
|
||||
[$general, '3566002020360505'], // JBC
|
||||
[$jcb, '3566002020360505'],
|
||||
];
|
||||
}
|
||||
|
||||
public function providerForNotCreditCard()
|
||||
public function providerForInvalidInput()
|
||||
{
|
||||
$general = new CreditCard();
|
||||
$amex = new CreditCard(CreditCard::AMERICAN_EXPRESS);
|
||||
$diners = new CreditCard(CreditCard::DINERS_CLUB);
|
||||
$discover = new CreditCard(CreditCard::DISCOVER);
|
||||
$jcb = new CreditCard(CreditCard::JCB);
|
||||
$master = new CreditCard(CreditCard::MASTERCARD);
|
||||
$visa = new CreditCard(CreditCard::VISA);
|
||||
|
||||
return [
|
||||
[''],
|
||||
[null],
|
||||
['it isnt my credit card number'],
|
||||
['&stR@ng3|) (|-|@r$'],
|
||||
['1234 1234 1234 1234'],
|
||||
['1234.1234.1234.1234'],
|
||||
[$general, ''],
|
||||
[$general, null],
|
||||
[$general, 'it isnt my credit card number'],
|
||||
[$general, '&stR@ng3|) (|-|@r$'],
|
||||
[$general, '1234 1234 1234 1234'],
|
||||
[$general, '1234.1234.1234.1234'],
|
||||
[$master, '6011111111111117'], // Discover
|
||||
[$visa, '3530111333300000'], // JCB
|
||||
[$amex, '5555555555554444'], // MasterCard
|
||||
[$diners, '4012888888881881'], // Visa
|
||||
[$discover, '371449635398431'], // American Express
|
||||
[$jcb, '38520000023237'], // Diners Club
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue