mirror of
https://github.com/vlucas/valitron.git
synced 2025-12-31 07:01:54 +00:00
Merge pull request #44 from willishq/feature/credit-card-validation
Added credit card validation for Visa, Mastercard, American Express, Din...
This commit is contained in:
commit
2678a9c586
36
README.md
36
README.md
@ -113,6 +113,42 @@ V::lang('ar');
|
|||||||
* `dateBefore` - Field is a valid date and is before the given date
|
* `dateBefore` - Field is a valid date and is before the given date
|
||||||
* `dateAfter` - Field is a valid date and is after the given date
|
* `dateAfter` - Field is a valid date and is after the given date
|
||||||
* `contains` - Field is a string and contains the given string
|
* `contains` - Field is a string and contains the given string
|
||||||
|
* `creditCard` - Field is a valid credit card number
|
||||||
|
|
||||||
|
|
||||||
|
## Credit Card Validation usage
|
||||||
|
|
||||||
|
Credit card validation currently allows you to validate a Visa `visa`,
|
||||||
|
Mastercard `mastercard`, Dinersclub `dinersclub`, American Express `amex`
|
||||||
|
or Discover `discover`
|
||||||
|
|
||||||
|
This will check the credit card against each card type
|
||||||
|
|
||||||
|
```php
|
||||||
|
$v->rule('creditCard', 'credit_card');
|
||||||
|
```
|
||||||
|
|
||||||
|
To optionally filter card types, add the slug to an array as the next parameter:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$v->rule('creditCard', 'credit_card', ['visa', 'mastercard']);
|
||||||
|
```
|
||||||
|
|
||||||
|
If you only want to validate one type of card, put it as a string:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$v->rule('creditCard', 'credit_card', 'visa');
|
||||||
|
```
|
||||||
|
|
||||||
|
If the card type information is coming from the client, you might also want to
|
||||||
|
still specify an array of valid card types:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$cardType = 'amex';
|
||||||
|
$v->rule('creditCard', 'credit_card', $cardType, ['visa', 'mastercard']);
|
||||||
|
$v->validate(); // false
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Adding Custom Validation Rules
|
## Adding Custom Validation Rules
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,8 @@ return array(
|
|||||||
'dateAfter' => "must be date after '%s'",
|
'dateAfter' => "must be date after '%s'",
|
||||||
'contains' => "must contain %s",
|
'contains' => "must contain %s",
|
||||||
'boolean' => "must be a boolean",
|
'boolean' => "must be a boolean",
|
||||||
'lengthBetween' => "must be between %d and %d characters"
|
'lengthBetween' => "must be between %d and %d characters",
|
||||||
|
'creditCard' => "must be a valid credit card number"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -472,6 +472,116 @@ class Validator
|
|||||||
return (is_bool($value)) ? true : false;
|
return (is_bool($value)) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that a field contains a valid credit card
|
||||||
|
* optionally filtered by an array
|
||||||
|
*
|
||||||
|
* @param string $field
|
||||||
|
* @param string $value
|
||||||
|
* @param array $params
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function validateCreditCard($field, $value, $params)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* I there has been an array of valid cards supplied, or the name of the users card
|
||||||
|
* or the name and an array of valid cards
|
||||||
|
*/
|
||||||
|
if (!empty($params)) {
|
||||||
|
/**
|
||||||
|
* array of valid cards
|
||||||
|
*/
|
||||||
|
if (is_array($params[0])) {
|
||||||
|
$cards = $params[0];
|
||||||
|
} else if (is_string($params[0])){
|
||||||
|
$cardType = $params[0];
|
||||||
|
if (isset($params[1]) && is_array($params[1])) {
|
||||||
|
$cards = $params[1];
|
||||||
|
if (!in_array($cardType, $cards)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Luhn algorithm
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
$numberIsValid = function () use ($value) {
|
||||||
|
$number = preg_replace('/[^0-9]+/', '', $value);
|
||||||
|
$sum = 0;
|
||||||
|
|
||||||
|
$strlen = strlen($number);
|
||||||
|
if ($strlen < 13) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for ($i = 0; $i < $strlen; $i++) {
|
||||||
|
$digit = (int) substr($number, $strlen - $i - 1, 1);
|
||||||
|
if ($i % 2 == 1) {
|
||||||
|
$sub_total = $digit * 2;
|
||||||
|
if ($sub_total > 9) {
|
||||||
|
$sub_total = ($sub_total - 10) + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$sub_total = $digit;
|
||||||
|
}
|
||||||
|
$sum += $sub_total;
|
||||||
|
}
|
||||||
|
if ($sum > 0 && $sum % 10 == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($numberIsValid()) {
|
||||||
|
if (!isset($cards)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
$cardRegex = array(
|
||||||
|
'visa' => '#^4[0-9]{12}(?:[0-9]{3})?$#',
|
||||||
|
'mastercard' => '#^5[1-5][0-9]{14}$#',
|
||||||
|
'amex' => '#^3[47][0-9]{13}$#',
|
||||||
|
'dinersclub' => '#^3(?:0[0-5]|[68][0-9])[0-9]{11}$#',
|
||||||
|
'discover' => '#^6(?:011|5[0-9]{2})[0-9]{12}$#',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($cardType)) {
|
||||||
|
// if we don't have any valid cards specified and the card we've been given isn't in our regex array
|
||||||
|
if (!isset($cards) && !in_array($cardType, array_keys($cardRegex))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we only need to test against one card type
|
||||||
|
return (preg_match($cardRegex[$cardType], $value) === 1);
|
||||||
|
|
||||||
|
} else if (isset($cards)) {
|
||||||
|
// if we have cards, check our users card against only the ones we have
|
||||||
|
foreach($cards as $card) {
|
||||||
|
if (in_array($card, array_keys($cardRegex))) {
|
||||||
|
// if the card is valid, we want to stop looping
|
||||||
|
if (preg_match($cardRegex[$card], $value) === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// loop through every card
|
||||||
|
foreach($cardRegex as $regex) {
|
||||||
|
// until we find a valid one
|
||||||
|
if (preg_match($regex, $value) === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we've got this far, the card has passed no validation so it's invalid!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get array of fields and data
|
* Get array of fields and data
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -654,6 +654,58 @@ class ValidateTest extends BaseTestCase
|
|||||||
$v->rule('boolean', 'test');
|
$v->rule('boolean', 'test');
|
||||||
$this->assertFalse($v->validate());
|
$this->assertFalse($v->validate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCreditCardValid()
|
||||||
|
{
|
||||||
|
$visa = array(4539511619543489, 4532949059629052, 4024007171194938, 4929646403373269, 4539135861690622);
|
||||||
|
$mastercard = array(5162057048081965, 5382687859049349, 5484388880142230, 5464941521226434, 5473481232685965);
|
||||||
|
$amex = array(371442067262027, 340743030537918, 345509167493596, 343665795576848, 346087552944316);
|
||||||
|
$dinersclub = array(30363194756249, 30160097740704, 38186521192206, 38977384214552, 38563220301454);
|
||||||
|
$discover = array(6011712400392605, 6011536340491809, 6011785775263015, 6011984124619056, 6011320958064251);
|
||||||
|
|
||||||
|
foreach (compact('visa', 'mastercard', 'amex', 'dinersclub', 'discover') as $type => $numbers) {
|
||||||
|
foreach($numbers as $number) {
|
||||||
|
$v = new Validator(array('test' => $number));
|
||||||
|
$v->rule('creditCard', 'test');
|
||||||
|
$this->assertTrue($v->validate());
|
||||||
|
$v->rule('creditCard', 'test', array($type, 'mastercard', 'visa'));
|
||||||
|
$this->assertTrue($v->validate());
|
||||||
|
$v->rule('creditCard', 'test', $type);
|
||||||
|
$this->assertTrue($v->validate());
|
||||||
|
$v->rule('creditCard', 'test', $type, array($type, 'mastercard', 'visa'));
|
||||||
|
$this->assertTrue($v->validate());
|
||||||
|
unset($v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testcreditCardInvalid()
|
||||||
|
{
|
||||||
|
$visa = array(3539511619543489, 3532949059629052, 3024007171194938, 3929646403373269, 3539135861690622);
|
||||||
|
$mastercard = array(4162057048081965, 4382687859049349, 4484388880142230, 4464941521226434, 4473481232685965);
|
||||||
|
$amex = array(271442067262027, 240743030537918, 245509167493596, 243665795576848, 246087552944316);
|
||||||
|
$dinersclub = array(20363194756249, 20160097740704, 28186521192206, 28977384214552, 28563220301454);
|
||||||
|
$discover = array(5011712400392605, 5011536340491809, 5011785775263015, 5011984124619056, 5011320958064251);
|
||||||
|
|
||||||
|
foreach (compact('visa', 'mastercard', 'amex', 'dinersclub', 'discover') as $type => $numbers) {
|
||||||
|
foreach($numbers as $number) {
|
||||||
|
$v = new Validator(array('test' => $number));
|
||||||
|
$v->rule('creditCard', 'test');
|
||||||
|
$this->assertFalse($v->validate());
|
||||||
|
$v->rule('creditCard', 'test', array($type, 'mastercard', 'visa'));
|
||||||
|
$this->assertFalse($v->validate());
|
||||||
|
$v->rule('creditCard', 'test', $type);
|
||||||
|
$this->assertFalse($v->validate());
|
||||||
|
$v->rule('creditCard', 'test', $type, array($type, 'mastercard', 'visa'));
|
||||||
|
$this->assertFalse($v->validate());
|
||||||
|
$v->rule('creditCard', 'test', 'invalidCardName');
|
||||||
|
$this->assertFalse($v->validate());
|
||||||
|
$v->rule('creditCard', 'test', 'invalidCardName', array('invalidCardName', 'mastercard', 'visa'));
|
||||||
|
$this->assertFalse($v->validate());
|
||||||
|
unset($v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sampleFunctionCallback($field, $value, array $params) {
|
function sampleFunctionCallback($field, $value, array $params) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user