Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Credit Card Validator Laravel Package

rap2hpoutre/laravel-credit-card-validator

Laravel validator rule for credit card numbers that checks card validity and detects the brand (Visa, Mastercard, Amex, and more). Drop it into validation rules to verify cards with Luhn checks and type detection.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require rap2hpoutre/laravel-credit-card-validator

Laravel 5.5+ auto-discovers the service provider — there is no config file to publish and nothing to register manually. If you are on an older Laravel, or discovery is disabled, add the provider in config/app.php.

Where to look first

Open vendor/rap2hpoutre/laravel-credit-card-validator/src/ and read the service provider. Two things to confirm before you build on it:

  1. The exact rule name it registers (the README/description uses credit_card).
  2. Whether the type-checking argument is supported in your pinned version, and the exact brand strings it expects (case and spelling vary — Visa vs visa, MasterCard vs Mastercard).

Because the package is small and last released in 2020, the source is short enough to audit in a few minutes — do that once rather than guessing at behavior.

First use case — a checkout FormRequest:

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class CheckoutRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'card_number'  => ['required', 'string', 'credit_card'],
            'name_on_card' => ['required', 'string', 'max:255'],
        ];
    }
}
public function store(CheckoutRequest $request)
{
    // $request->validated('card_number') is now Luhn-valid
}

Invalid or mistyped numbers return a normal ValidationException (HTTP 422 / redirect with errors), so it drops straight into existing form flows.

Implementation Patterns

Type-checked numbers. Where supported, pass the expected brand as an argument so a Visa number submitted to a "Mastercard" flow is rejected:

'card_number' => ['required', 'credit_card:Visa'],

Confirm the argument syntax against the package source, then centralize brand strings in a constant or enum so they don't drift across requests.

Normalize input before validating. Card fields get pasted with spaces and dashes. Strip them in prepareForValidation() rather than trusting users:

protected function prepareForValidation(): void
{
    if ($this->filled('card_number')) {
        $this->merge([
            'card_number' => preg_replace('/\D+/', '', (string) $this->input('card_number')),
        ]);
    }
}

Pair it with the non-number checks. The rule only covers the number. Add expiry and CVC as separate rules:

'card_number' => ['required', 'credit_card'],
'exp_month'   => ['required', 'integer', 'between:1,12'],
'exp_year'    => ['required', 'integer', 'min:' . now()->year],
'cvc'         => ['required', 'digits_between:3,4'],

Custom messages. Either per-request:

public function messages(): array
{
    return [
        'card_number.credit_card' => 'That card number doesn\'t look right — please check it.',
    ];
}

…or globally in lang/en/validation.php with a credit_card key, so every form inherits the copy. Use the per-request override where the wording differs (e.g., "Please re-enter the card number").

API / Livewire reuse. The rule is just a string, so it works identically in $request->validate([...]), Livewire component rules(), or a queued job's validator. Extract a shared trait or rules class so the checkout form and the API endpoint cannot diverge.

Test with known numbers. In feature tests, exercise both sides of the check:

// Luhn-valid
$this->post('/checkout', ['card_number' => '4242424242424242'])->assertSessionHasNoErrors();
$this->post('/checkout', ['card_number' => '5555555555554444'])->assertSessionHasNoErrors();
$this->post('/checkout', ['card_number' => '378282246310005'])->assertSessionHasNoErrors();

// Bad checksum
$this->post('/checkout', ['card_number' => '4242424242424241'])->assertSessionHasErrors('card_number');

// Formatted input, after normalization
$this->post('/checkout', ['card_number' => '4242 4242 4242 4242'])->assertSessionHasNoErrors();

Integration tip with a payment provider. Validate locally before you call Stripe/PayPal. You get an instant, cheap 422 with a field-level error instead of a provider round-trip and an opaque decline — and you keep obviously malformed numbers out of your gateway logs. The gateway remains authoritative; this rule is just a pre-filter.

Gotchas and Tips

  • It is a checksum, not an authorization. The Luhn algorithm catches typos and transpositions; it says nothing about whether the card is live, has funds, or matches the cardholder. Never gate fulfillment on it. Expiry and CVC are not checked by this rule.
  • Formatting will fail it. If you skip prepareForValidation(), 4242 4242 4242 4242 and 4242-4242-4242-4242 will be rejected even though they're valid cards. Normalize first; this is the single most common source of "the rule is broken" bug reports.
  • All-zero numbers can slip through. Some Luhn implementations accept 0000000000000000. Add digits_between:13,19 and/or an explicit non-zero check if your UI can submit junk like that.
  • Type strings are exact-match. Mastercard vs MasterCard vs mastercard will silently reject valid cards. Read the package's brand map once and use those literals.
  • The release is old (October 2020). The Laravel validator API it hooks into (Validator::extend / rule registration) has been stable, so it generally still works on modern Laravel — but verify it loads on your PHP/Laravel combination before committing to it, and add a feature test that pins the behavior. If a future Laravel breaks it, the rule is a dozen lines of Luhn logic — fork it or inline the rule rather than waiting for upstream.
  • "Unknown rule" errors mean the provider didn't load. On manual registration, run composer dump-autoload and confirm the provider is listed in config/app.php. With auto-discovery, clear bootstrap/cache/packages.php and config.php.
  • Empty values are not caught. Rules only run when the field is present and non-empty; keep required alongside credit_card unless the field is genuinely optional.
  • PCI scope is unchanged. The rule does not make you compliant. Don't log the raw number or the failed input — log the detected type and last four digits only, or nothing at all in production. If you can, prefer provider-hosted fields (Stripe Elements etc.) so the PAN never hits your server.
  • Extension points. Compose this with a custom Rule object when you need brand-plus-gateway logic in one place, and consider adding a small card_type rule that reuses the package's detector to persist the brand (visa, mastercard) alongside the last four — useful for display and for routing.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings