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 Cards Laravel Package

jlorente/laravel-credit-cards

Laravel Credit Cards is a Laravel package that adds credit card validation rules, brand detection, and helper utilities to your app. Validate card numbers, identify Visa, Mastercard, Amex and other brands, and format or obfuscate numbers with framework-native tools.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer and let Laravel auto-discovery register the service provider:

composer require jlorente/laravel-credit-cards

If the package ships a config file, publish it once and commit it:

php artisan vendor:publish --provider="Jlorente\Laravel\CreditCards\CreditCardsServiceProvider"

Look first at three things, in this order: the published config/credit-cards.php (accepted brands, whether brand checks are enforced), the service provider (which validation rule aliases are registered), and the underlying jlorente/php-credit-cards card class that the rules delegate to. The Laravel package is a thin rule layer on top of that class — if you understand the card object's isValid()/brand methods, you understand the package.

First practical use case — a form request for a checkout step:

public function rules(): array
{
    return [
        'card_number'  => ['required', 'string', 'credit_card'],
        'expiry_month' => ['required', 'integer', 'between:1,12'],
        'expiry_year'  => ['required', 'integer', 'min:'.now()->year],
        'cvv'          => ['required', 'digits_between:3,4'],
    ];
}

That single credit_card rule gives you Luhn validation plus brand recognition in one pass. Confirm the exact alias in the README — small packages like this sometimes register credit_card_number or require a parameter list for allowed brands. Once it works in a form request, you have covered 80% of realistic usage.

Implementation Patterns

Use the rule at the HTTP boundary, not in the domain

Card validation is a request-shaping concern. Put it in form requests (or a dedicated PaymentRequest), not scattered across controllers or payment services. When the rule fires, the payload is already clean by the time it reaches your gateway integration.

Normalize input before the rule runs

Users paste numbers with spaces, hyphens, or a stray leading quote. Strip non-digits in prepareForValidation() so the rule sees a clean string:

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

Do this once. If you normalize inside every consumer, you will eventually miss one.

Restrict accepted brands explicitly

If you only take Visa and Mastercard, say so — either in config or as rule parameters — rather than validating the number and then rejecting the brand downstream. A rejected-brand error at the form level is far cheaper than a gateway round-trip:

'card_number' => ['required', 'string', 'credit_card:visa,mastercard'],

Check the README for the exact syntax; some builds read the accepted list from config instead of rule parameters.

Map brands to your gateway's vocabulary in one place

The package returns brand identifiers (visa, mastercard, amex, etc.). Your gateway may want master, american_express, or numeric codes. Wrap the mapping in a small service so a future gateway migration is a one-file change:

class CardBrandMapper
{
    public function toGateway(?string $brand): string
    {
        return match ($brand) {
            'visa'       => 'VISA',
            'mastercard' => 'MASTER',
            'amex'       => 'AMEX',
            default      => throw new \InvalidArgumentException("Unsupported brand: {$brand}"),
        };
    }
}

Prefer the rule, but keep a service for programmatic checks

Some flows (webhooks, admin retries, API endpoints) don't run through form requests. Wrap the underlying CreditCard object in a CardValidator service so both paths share one implementation and you can fake it in tests.

Test with known PANs

Maintain a fixture set: valid Visa/Mastercard/Amex test numbers, numbers that pass Luhn but are for unsupported brands, too-short/too-long numbers, digit-stripped inputs, and empty strings. These fixtures double as your contract test after any dependency bump — including the 1.0.3 release, which is a php-credit-cards version bump and can silently shift BIN tables.

Gotchas and Tips

  • Luhn validity is not authorization. A number that passes isValid() can still be declined, expired, stolen, or blocked. Never treat a green form request as a green charge.
  • Rule ordering matters. Put string before credit_card. Passing an integer or array into the rule can throw instead of failing gracefully.
  • Config caching bites. After editing card-brand config, run php artisan config:cache again (or config:clear in dev). Stale brand lists produce confusing "valid card rejected" reports.
  • Brand strings are the package's, not your gateway's. Centralize mapping (see above) instead of comparing 'mastercard' in five places.
  • Expiry and CVV are mostly yours. CVV length varies by brand; validate it in Laravel rules (digits_between:3,4) rather than assuming the package enforces brand-specific CVV lengths. Expiry needs a real future-date check — min:now()->year alone accepts a card that expired last month.
  • 2-digit vs 4-digit years. Normalize to one convention in prepareForValidation(); mismatch is the single most common expiry-validation bug.
  • Never log the PAN. Not in exception handlers, not in validation-failure logging, not in dd(). Log last-four plus brand only. The package does not reduce your PCI DSS obligations.
  • Do not store card numbers. Tokenize through your gateway; persist only the token, last four, brand, and expiry. If anyone proposes storing the PAN because "the package validates it," stop them.
  • 1.0.3 is a dependency refresh, not a feature release. The upstream php-credit-cards version is the product; a bump can change accepted BIN ranges, brand-detection outcomes, and possibly the PHP/Laravel floor. Review the lockfile diff and re-run your fixtures — don't assume behavior is unchanged because the release note is one line.
  • Upstream BIN tables age. New card ranges appear faster than these packages update. If you hit a legitimate card rejected on brand detection, add a small override in your wrapper rather than forking the vendor package.
  • Extension point is your wrapper, not the package. Normalization, brand mapping, gateway translation, and fixtures all belong in application code. That keeps future patch releases low-risk.
  • Rule aliases can shift across major versions. Pin a ^1.0 constraint, and if you upgrade majors, verify the alias strings in your form requests actually resolve before deploying.
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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox