Skip to content

Generation and verification of card numbers using Luhn's algorithm.

License

Notifications You must be signed in to change notification settings

TheDragonCode/card-number

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Card Number using Luhn's algorithm

Luhn-algorithm card-number

Stable Version Unstable Version Total Downloads License

Introduction

Generation and verification of card numbers using Luhn's algorithm: credit, customer loyalty and others.

Installation

To get the latest version of Card Number, simply require the project using Composer:

composer require dragon-code/card-number

Or manually update require block of composer.json and run composer update console command.

{
    "require": {
        "dragon-code/card-number": "^1.5"
    }
}

Usage

Validation

You can validate any numbers with the Luhn algorithm with any input format.

For example:

use DragonCode\CardNumber\CardNumber;

CardNumber::isValid(18); // true
CardNumber::isValid(12); // false

CardNumber::isValid('0018'); // true
CardNumber::isValid('0019'); // false

CardNumber::isValid('123-455'); // true
CardNumber::isValid('123-454'); // false

CardNumber::isValid('12-3456-1239'); // true
CardNumber::isValid('12-3456-1230'); // false

CardNumber::isValid('5580 4733 7202 4733'); // true
CardNumber::isValid('5580 4733 7202 4732'); // false

CardNumber::isValid('5580-4733x7202_47 33'); // true
CardNumber::isValid('5580-4733x7202_47 32'); // false

You can validate bank card numbers. To do this, pass the card type as the second argument:

use DragonCode\CardNumber\CardNumber;
use DragonCode\CardNumber\Enums\CardType;

CardNumber::isValid('4026 8434 8316 8683', CardType::visa); // true
CardNumber::isValid('4019 1404 0123 4567', CardType::visa); // true
CardNumber::isValid('2730 1684 6416 1841', CardType::visa); // false
CardNumber::isValid('2201 6868 4646 8444', CardType::visa); // false

CardNumber::isValid('4026 8434 8316 8683', 'visa'); // true
CardNumber::isValid('4019 1404 0123 4567', 'visa'); // true
CardNumber::isValid('2730 1684 6416 1841', 'visa'); // false
CardNumber::isValid('2201 6868 4646 8444', 'visa'); // false

You can also check for invalid numbers:

use DragonCode\CardNumber\CardNumber;

CardNumber::isInvalid(18); // false
CardNumber::isInvalid(12); // true

CardNumber::isInvalid('0018'); // false
CardNumber::isInvalid('0019'); // true

CardNumber::isInvalid('123-455'); // false
CardNumber::isInvalid('123-454'); // true

CardNumber::isInvalid('12-3456-1239'); // false
CardNumber::isInvalid('12-3456-1230'); // true

CardNumber::isInvalid('5580 4733 7202 4733'); // false
CardNumber::isInvalid('5580 4733 7202 4732'); // true

CardNumber::isInvalid('5580-4733x7202_47 33'); // false
CardNumber::isInvalid('5580-4733x7202_47 32'); // true

In addition to numerical values, you can also validate number-letter combinations. For example:

use DragonCode\CardNumber\CardNumber;
use DragonCode\CardNumber\Enums\CardType;

CardNumber::isValid('EKN-OSX', CardType::chars); // true
CardNumber::isValid('EKN-56X', CardType::chars); // true

CardNumber::isValid('ekn-osx', 'chars'); // true
CardNumber::isValid('ekn-56x', 'chars'); // true

CardNumber::isValid('EKN-OSX'); // false
CardNumber::isValid('EKN-56X'); // false

List of available validation types:

Type Code Enum
AmericanExpress amex DragonCode\CardNumber\Enums\CardType::americanExpress
Chars Number chars DragonCode\CardNumber\Enums\CardType::chars
Dankort dankort DragonCode\CardNumber\Enums\CardType::dankort
DinersClub dinersclub DragonCode\CardNumber\Enums\CardType::dinersClub
Discovery discovery DragonCode\CardNumber\Enums\CardType::discovery
Forbrugsforeningen forbrugsforeningen DragonCode\CardNumber\Enums\CardType::forbrugsforeningen
HiperCard hipercard DragonCode\CardNumber\Enums\CardType::hiperCard
Jcb jcb DragonCode\CardNumber\Enums\CardType::jcb
Maestro maestro DragonCode\CardNumber\Enums\CardType::maestro
MasterCard mastercard DragonCode\CardNumber\Enums\CardType::masterCard
Mir mir DragonCode\CardNumber\Enums\CardType::mir
Ralf Ringer ralfringer DragonCode\CardNumber\Enums\CardType::ralfRinger
Troy troy DragonCode\CardNumber\Enums\CardType::troy
Unionpay unionpay DragonCode\CardNumber\Enums\CardType::unionPay
Visa visa DragonCode\CardNumber\Enums\CardType::visa
VisaElectron visaelectron DragonCode\CardNumber\Enums\CardType::visaElectron
Yves Rocher yvesrocher DragonCode\CardNumber\Enums\CardType::yvesRocher

Custom Validators

In some cases there may not be enough built-in validators and therefore you can easily use your own. To do this, create a class and inherit it from the abstract DragonCode\CardNumber\Validators\CardValidator, and then pass a reference to it in the cardType parameter:

use DragonCode\CardNumber\CardNumber;
use DragonCode\CardNumber\Validators\CardValidator;

class SomeValidator extends CardValidator
{
    protected static ?string $pattern = '/^[3-5]{3}/';

    protected static array $numberLength = [4];
}

CardNumber::isValid(3459, SomeValidator::class); // true
CardNumber::isValid(2451, SomeValidator::class); // false

CardNumber::isInvalid(3459, SomeValidator::class); // false
CardNumber::isInvalid(2451, SomeValidator::class); // true

Generation

You can also easily generate any numbers using the Luhn algorithm:

use DragonCode\CardNumber\CardNumber;

CardNumber::generate(1);   // 18
CardNumber::generate(2);   // 26
CardNumber::generate(10);  // 109
CardNumber::generate(90);  // 901
CardNumber::generate(908); // 9084

You can also use the formatter to format the resulting value:

use DragonCode\CardNumber\CardNumber;
use DragonCode\CardNumber\Formatters\BankFormatter;
use DragonCode\CardNumber\Formatters\LoyaltyFormatter;

$loyalty = LoyaltyFormatter::create();
$bank    = BankFormatter::create();
 
CardNumber::generate(1, $loyalty); // 0018
CardNumber::generate(2, $loyalty); // 0026

CardNumber::generate(12345, $loyalty); // 123-455
CardNumber::generate(23456, $loyalty); // 234-567

CardNumber::generate(123456, $loyalty); // 123-4566
CardNumber::generate(234567, $loyalty); // 234-5676

CardNumber::generate(123456123, $loyalty); // 12-3456-1239
CardNumber::generate(234567123, $loyalty); // 23-4567-1230

CardNumber::generate(558047337202473, $bank); // 5580 4733 7202 4733
CardNumber::generate(529391143678555, $bank); // 5293 9114 3678 5557

Formatters

You can also create your own formatter. To do this, create a class and inherit it from the DragonCode\CardNumber\Formatters\Formatter abstract class:

use DragonCode\CardNumber\Formatters\Formatter;

class SomeFormatter extends Formatter
{
    protected int $splitLength = 6;

    protected string $delimiter = '/';
}

And use this one:

use App\Cards\Formatters\SomeFormatter;
use DragonCode\CardNumber\CardNumber;

$formatter = SomeFormatter::create();

CardNumber::generate(558047337202473, $formatter); // 5580/473372/024733

List of available formatters:

  • DragonCode\CardNumber\Formatters\DefaultFormatter
  • DragonCode\CardNumber\Formatters\BankFormatter
  • DragonCode\CardNumber\Formatters\LoyaltyFormatter
  • DragonCode\CardNumber\Formatters\LoyaltyCharFormatter

In addition to numeric formatters, you can also use number-letter combinations. For example, using the DragonCode\CardNumber\Formatters\LoyaltyCharFormatter formatter, you can generate a letter code instead of a numeric number, which will be valid when verified by the Luhn's algorithm:

use DragonCode\CardNumber\CardNumber;
use DragonCode\CardNumber\Formatters\LoyaltyCharFormatter;

$formatter = LoyaltyCharFormatter::create();

CardNumber::generate(345678123, $formatter); // KN-OSXY-AEKF

Factories

In addition, you can specify factories as an incoming identifier parameter. In this way, you can form unique identification rules using fluent methods.

This is useful when, for example, you create a customer loyalty card number and want to specify in its number the year of issue as well as its level.

use DragonCode\CardNumber\CardNumber;
use DragonCode\CardNumber\Factories\CustomerFactory;
use DragonCode\CardNumber\Formatters\LoyaltyFormatter;

$formatter = LoyaltyFormatter::create();

$customer = CustomerFactory::create()->level($user->loyalty_level)->customer($user->id);

return CardNumber::generate($customer, $formatter);
// For example, 230-4001-2348
//
//     23     - year
//     04     - loyalty level
//     001234 - user id
//     8      - control digit
use DragonCode\CardNumber\CardNumber;
use DragonCode\CardNumber\Factories\BankFactory;
use DragonCode\CardNumber\Formatters\BankFormatter;

$formatter = BankFormatter::create();

$customer = BankFactory::create()->paymentType(3)->bank(12, 45, 75)->client(12345);

return CardNumber::generate($customer, $formatter);
// 3012 4575 0012 3452
//
// 3       - payment type
// 012     - bank ID
// 45      - bank info
// 75      - bank's program
// 0012345 - client id
// 2       - control digit

List of available factories:

  • DragonCode\CardNumber\Factories\BankFactory
  • DragonCode\CardNumber\Factories\CustomerFactory

Laravel

If you use the Laravel framework, you can also use the validation rule:

use DragonCode\CardNumber\Laravel\Validation\Rules\CardNumberRule;
use Illuminate\Foundation\Http\FormRequest;

class SomeRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'number' => ['required', new CardNumberRule()]
        ];
    }
}

You can also check bank cards:

use DragonCode\CardNumber\Enums\CardType;
use DragonCode\CardNumber\Laravel\Validation\Rules\CardNumberRule;
use Illuminate\Foundation\Http\FormRequest;

class SomeRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'visa_card_1' => ['required', new CardNumberRule(CardType::visa)],
            'visa_card_2' => ['required', new CardNumberRule('visa')],
            
            'few_cards' => ['required', new CardNumberRule([CardType::visa, CardType::masterCard])],
            'few_cards' => ['required', new CardNumberRule(['visa', 'mastercard'])],
        ];
    }
}

License

This package is licensed under the MIT License.