mirror of
https://github.com/Respect/Validation.git
synced 2024-06-15 20:15:06 +02:00
Create "Luhn" rule
This commit is contained in:
parent
5f50541086
commit
8b3790103e
|
@ -44,3 +44,4 @@ See also:
|
|||
- [Bank](Bank.md)
|
||||
- [BankAccount](BankAccount.md)
|
||||
- [Bic](Bic.md)
|
||||
- [Luhn](Luhn.md)
|
||||
|
|
23
docs/Luhn.md
Normal file
23
docs/Luhn.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Luhn
|
||||
|
||||
- `Luhn()`
|
||||
|
||||
Validate whether a given input is a [Luhn][] number.
|
||||
|
||||
```php
|
||||
v::luhn()->validate('2222400041240011'); // true
|
||||
v::luhn()->validate('respect!'); // false
|
||||
```
|
||||
|
||||
## Changelog
|
||||
|
||||
Version | Description
|
||||
--------|-------------
|
||||
2.0.0 | Created
|
||||
|
||||
[Luhn]: https://en.wikipedia.org/wiki/Luhn_algorithm
|
||||
***
|
||||
See also:
|
||||
|
||||
- [CreditCard](CreditCard.md)
|
||||
- [Imei](Imei.md)
|
|
@ -187,6 +187,7 @@
|
|||
- [Imei](Imei.md)
|
||||
- [Ip](Ip.md)
|
||||
- [Json](Json.md)
|
||||
- [Luhn](Luhn.md)
|
||||
- [MacAddress](MacAddress.md)
|
||||
- [NfeAccessKey](NfeAccessKey.md)
|
||||
- [Nif](Nif.md)
|
||||
|
@ -286,6 +287,7 @@
|
|||
- [LeapYear](LeapYear.md)
|
||||
- [Length](Length.md)
|
||||
- [Lowercase](Lowercase.md)
|
||||
- [Luhn](Luhn.md)
|
||||
- [MacAddress](MacAddress.md)
|
||||
- [Max](Max.md)
|
||||
- [Mimetype](Mimetype.md)
|
||||
|
|
24
library/Exceptions/LuhnException.php
Normal file
24
library/Exceptions/LuhnException.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Respect\Validation\Exceptions;
|
||||
|
||||
class LuhnException extends ValidationException
|
||||
{
|
||||
public static $defaultTemplates = [
|
||||
self::MODE_DEFAULT => [
|
||||
self::STANDARD => '{{name}} must be a valid Luhn number',
|
||||
],
|
||||
self::MODE_NEGATIVE => [
|
||||
self::STANDARD => '{{name}} must not be a valid Luhn number',
|
||||
],
|
||||
];
|
||||
}
|
|
@ -64,40 +64,13 @@ class CreditCard extends AbstractRule
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!$this->verifyMod10($input)) {
|
||||
if (!(new Luhn())->validate($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;
|
||||
$input = strrev($input);
|
||||
for ($i = 0; $i < mb_strlen($input); ++$i) {
|
||||
$current = mb_substr($input, $i, 1);
|
||||
if ($i % 2 == 1) {
|
||||
$current *= 2;
|
||||
if ($current > 9) {
|
||||
$firstDigit = $current % 10;
|
||||
$secondDigit = ($current - $firstDigit) / 10;
|
||||
$current = $firstDigit + $secondDigit;
|
||||
}
|
||||
}
|
||||
$sum += $current;
|
||||
}
|
||||
|
||||
return $sum % 10 == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the input matches the defined credit card brand or not.
|
||||
*
|
||||
|
|
|
@ -33,12 +33,6 @@ class Imei extends AbstractRule
|
|||
return false;
|
||||
}
|
||||
|
||||
$sum = 0;
|
||||
for ($position = 0; $position < (self::IMEI_SIZE - 1); ++$position) {
|
||||
$number = $numbers[$position] * (($position % 2) + 1);
|
||||
$sum += ($number % 10) + intval($number / 10);
|
||||
}
|
||||
|
||||
return (ceil($sum / 10) * 10) - $sum == $numbers[14];
|
||||
return (new Luhn())->validate($numbers);
|
||||
}
|
||||
}
|
||||
|
|
49
library/Rules/Luhn.php
Normal file
49
library/Rules/Luhn.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* @link https://en.wikipedia.org/wiki/Luhn_algorithm
|
||||
*/
|
||||
class Luhn extends AbstractRule
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($input)
|
||||
{
|
||||
if (!(new Digit())->validate($input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isValid($input);
|
||||
}
|
||||
|
||||
private function isValid($input): bool
|
||||
{
|
||||
$sum = 0;
|
||||
$numDigits = strlen($input);
|
||||
$parity = $numDigits % 2;
|
||||
for ($i = 0; $i < $numDigits; ++$i) {
|
||||
$digit = substr($input, $i, 1);
|
||||
if ($parity == ($i % 2)) {
|
||||
$digit <<= 1;
|
||||
if (9 < $digit) {
|
||||
$digit = $digit - 9;
|
||||
}
|
||||
}
|
||||
$sum += $digit;
|
||||
}
|
||||
|
||||
return 0 == ($sum % 10);
|
||||
}
|
||||
}
|
|
@ -95,6 +95,7 @@ use Respect\Validation\Rules\Key;
|
|||
* @method static Validator leapYear()
|
||||
* @method static Validator length(int $min = null, int $max = null, bool $inclusive = true)
|
||||
* @method static Validator lowercase()
|
||||
* @method static Validator luhn()
|
||||
* @method static Validator macAddress()
|
||||
* @method static Validator max(mixed $maxValue, bool $inclusive = true)
|
||||
* @method static Validator mimetype(string $mimetype)
|
||||
|
|
43
tests/unit/Rules/LuhnTest.php
Normal file
43
tests/unit/Rules/LuhnTest.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* @group rule
|
||||
* @covers \Respect\Validation\Rules\Luhn
|
||||
*/
|
||||
class LuhnTest extends RuleTestCase
|
||||
{
|
||||
public function providerForValidInput()
|
||||
{
|
||||
$rule = new Luhn();
|
||||
|
||||
return [
|
||||
[$rule, '2222400041240011'],
|
||||
[$rule, '340316193809364'],
|
||||
[$rule, '6011000990139424'],
|
||||
[$rule, '2223000048400011'],
|
||||
];
|
||||
}
|
||||
|
||||
public function providerForInvalidInput()
|
||||
{
|
||||
$rule = new Luhn();
|
||||
|
||||
return [
|
||||
[$rule, '2222400041240021'],
|
||||
[$rule, '340316193809334'],
|
||||
[$rule, '6011000990139421'],
|
||||
[$rule, '2223000048400010'],
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue