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

Credit Card Laravel Package

laravel-validation-rules/credit-card

Laravel validation rules for credit cards: validate card numbers with Luhn, detect major brands, and check expiration dates and CVV codes. Drop-in rules for form requests and validators, with clear error messages and support for common card types.

View on GitHub
Deep Wiki
Context7

Getting Started

  • composer require laravel-validation-rules/credit-card — Laravel package discovery registers the service provider, so no manual wiring is needed.
  • Look first at the README's rule table, then at the rule classes under src/Rules/ — that's the whole surface area of the package. There is essentially no configuration file to publish.
  • The canonical first use case is a checkout/payment form: validate the PAN with the credit_card rule, then constrain the network with credit_card_type.
// app/Http/Requests/StorePaymentMethodRequest.php
public function rules(): array
{
    return [
        'card_number' => ['required', 'string', 'credit_card'],
        'card_type'   => ['required', 'string', 'credit_card_type:visa,mastercard,amex'],
    ];
}

Return generic messages ("The card number is invalid.") rather than echoing the input back — you do not want a PAN in a validation error or log line.

Implementation Patterns

Form requests are the right home. Keep the rule strings in a FormRequest (or a dedicated PaymentMethodRequest) rather than in controllers, so the same rules can be reused by a JSON API endpoint and a Blade form.

Normalise before you validate. Users paste 4111 1111 1111 1111 or 4111-1111-1111-1111. Strip whitespace and dashes in prepareForValidation() so the rule sees a clean digits-only string, and store the normalised value, not the raw input:

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

Layer the rules. credit_card answers "is this a structurally valid number?" — it does not tell you the network, the expiry, or the CVV. Combine it with credit_card_type:* to enforce what you actually accept, and validate expiry/CVV as separate fields so the error messages point at the right input.

Gate on declared type only as a hint. Run credit_card_type against the detected number, not against a user-selected dropdown — otherwise a user can submit a valid Visa while claiming it's an Amex and you'll branch your payment gateway call incorrectly.

Test with known-good fixtures. Keep a small set of publicly documented test numbers (one per network) plus a deliberately bad Luhn checksum, and assert both the pass and the fail path in a Pest/PHPUnit feature test. After 1.12.3, also add a test that an array or null fails validation rather than blowing up.

Don't reinvent tokenisation. This package validates shape; it does not touch a gateway. In practice you validate, then immediately hand off to Stripe/Cashier and persist only the token plus last four digits.

Gotchas and Tips

  • 1.12.3 changed failure behaviour for non-string input. Previously a non-string value (array, null, int) could throw a TypeError and surface as a 500. It now fails validation normally. Two consequences: (a) any test that asserted an exception for malformed input must be updated to assert a validation error, and (b) if you were relying on the exception to mask a bug in your input handling, that bug is now silent — check your nullable/sometimes usage is deliberate.
  • Order your rules deliberately. Put nullable/required and string before credit_card so the intent is explicit and you don't rely on the rule's internal type coercion. ['nullable', 'string', 'credit_card'] on an optional field is the safe shape.
  • The rule validates the checksum (Luhn), not liveness. A passing credit_card rule means the digits are well-formed — nothing more. Never treat it as authorisation, and never persist the full PAN; keep it in memory, hand it to the gateway, discard it. Watch for card numbers leaking into Log::info($request->all()) or ->validate() exception payloads in debug output.
  • Formatting is not accepted. Spaces, dashes and unicode digits will fail. This is the single most common "the rule is broken" report — it's almost always un-normalised input.
  • Error messages are generic by default. Add an attributes()/messages() entry so the user sees "card number" rather than card_number, and keep the message non-revealing about why it failed.
  • Extension point: wrap, don't fork. If you need BIN-based type detection or network-specific length checks, write a small Rule class that delegates to the package's validator object and returns your own ValidationRule — that keeps you upgradeable.
  • Debugging tip: when a card that "should" pass fails, echo the normalised string length and run a Luhn check by hand before suspecting the package; nine times out of ten the input still contains a character you didn't strip.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource