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

Php Credit Cards Laravel Package

jlorente/php-credit-cards

A PHP package for validating credit card numbers and detecting card brands using length checks, Luhn algorithm, and issuer patterns. Includes Laravel validation support, making it easy to reject invalid payment details and identify Visa, Mastercard, Amex, and more.

Deep Wiki
Context7

Getting Started

Install the package with Composer:

composer require jlorente/php-credit-cards

Where to look first:

  1. src/CreditCardValidator.php — the main entry point (isValid, isValidType, getType, getTypes, formatting).
  2. src/Cards/ — one class per brand, each defining prefix patterns and length rules. This is where brand behavior actually lives.
  3. tests/ — the fastest source of truth for accepted test numbers, argument order, and edge cases (e.g., Amex, Maestro, Elo, Hipercard).
  4. composer.json — confirm required PHP version before adding it to an older application.

First use case — validate a card number and detect its brand at checkout:

use Jlorente\CreditCards\CreditCardValidator;

$validator = new CreditCardValidator();

$number = preg_replace('/\D+/', '', $request->input('card_number')); // "4111 1111 1111 1111" -> digits

if ($validator->isValid($number)) {
    $type = $validator->getType($number); // e.g. "Visa"
}

The validator is stateless and dependency-free, so a single instance can be reused across a request. It does not perform network calls, BIN lookups, or authorization — it only validates structure and brand.

Implementation Patterns

Normalize once, validate everywhere. Card input arrives with spaces, hyphens, or mixed formatting. Strip non-digits at the boundary (form request, controller, or a small CardNumber value object) and pass a clean digit string into the validator. This makes storage, logging, and re-validation consistent.

Brand whitelisting for a payment provider. Most processors accept only a subset of brands. Validate structurally, then check the detected brand against an allow-list:

$validator = new CreditCardValidator();
$number = preg_replace('/\D+/', '', $input);
$type = $validator->getType($number);

$accepted = ['Visa', 'MasterCard', 'AmericanExpress'];

if ($validator->isValid($number) && in_array($type, $accepted, true)) {
    // proceed to tokenization
}

isValidType('Visa', $number) is the direct alternative when you already know the expected brand. Confirm the argument order against the tests before committing it to a custom rule.

Laravel custom rule. Wrap the package so validation messages and normalization live in one place:

use Illuminate\Contracts\Validation\Rule;
use Jlorente\CreditCards\CreditCardValidator;

class ValidCardNumber implements Rule
{
    public function passes($attribute, $value): bool
    {
        $number = preg_replace('/\D+/', '', (string) $value);

        return strlen($number) >= 12
            && (new CreditCardValidator())->isValid($number);
    }

    public function message(): string
    {
        return 'The :attribute is not a valid card number.';
    }
}

Use it as 'card_number' => ['required', 'string', new ValidCardNumber]. If you also need brand enforcement, add a second rule that checks getType().

Service-layer wrapper. In larger applications, hide the package behind your own CardValidator service. This gives you a stable API if the library is swapped, and a single place to add metrics, logging, or brand policy. Avoid sprinkling new CreditCardValidator() through controllers.

Formatting for display. Use the package’s formatting support for readable output, but treat formatting as presentation only — never re-validate a formatted string without normalizing first. For masking, keep a prefix and the last four digits:

$masked = substr($number, 0, 6)
    . str_repeat('*', max(0, strlen($number) - 10))
    . substr($number, -4);

Group digits according to brand when displaying (Amex 4-6-5, Diners 4-6-4, most others 4-4-4-4, with 19-digit variants needing a trailing group).

Testing. Keep a fixture set of known-good and known-bad numbers per brand and test your wrapper, not just the package. Include boundary lengths (shortest and longest valid per brand), separators, and near-miss prefixes that should not match.

Gotchas and Tips

  • Luhn is a checksum, not proof of validity. A passing Luhn check only means the digits are internally consistent; it says nothing about whether the card exists, is active, or has funds. Never treat isValid() as authorization.
  • Brand detection is prefix- and length-based and can be ambiguous. Ranges overlap between brands (notably Maestro/MasterCard, and regional brands such as Elo and Hipercard). For critical flows, verify the detected brand with your processor and decide which brand wins on conflict.
  • Normalize before validating. If your input may contain spaces or hyphens, strip them explicitly rather than assuming the validator handles every format. This also prevents surprises when storing or comparing numbers.
  • Length varies by brand and can exceed 16 digits. Visa and Mastercard can issue 19-digit numbers, and Maestro spans a wide range. Don’t hard-code strlen($number) === 16 in your own wrapper — rely on the brand rules and only add a sanity bound.
  • Type names are strings and comparisons can be case-sensitive. Use the exact names returned by getType() (e.g., Visa, MasterCard, AmericanExpress) in allow-lists, and compare with strict in_array(..., true).
  • Keep card data out of logs and error trackers. Validation failures frequently get logged with the offending value. Sanitize or mask the number before it reaches any logger, queue payload, or exception context.
  • The package does not handle expiry or CVV. Validate those separately; they have their own format and range rules and must not be inferred from the card number.
  • Formatting is display-only. Don’t persist formatted strings or use them as keys. Store digits (ideally tokenized by your processor) and format at render time.
  • Extension points live in src/Cards/. Adding a brand generally means adding a card class with prefix/length rules and registering it alongside the existing ones. Check the validator’s configuration and the tests for the expected registration mechanism before extending.
  • Version pinning. The last release is from October 2024. Pin the version in composer.json and run your fixture tests after any upgrade, since brand prefix tables and supported-brand lists evolve.
  • Laravel users may prefer the dedicated rule package. If you only need validation rules inside Laravel, check whether a companion validation package is a better fit than wiring this library manually; keep the wrapper approach either way so the rest of the app is insulated from the choice.
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.
abbasudo/artisan-route
mirvan/ippanel
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