Credit and debit card numbers contain information that can help identify the card network, such as Visa, Mastercard, American Express, Discover, and JCB. This identification is commonly called card type detection or card brand detection.
A card number is also known as a Primary Account Number (PAN). Its opening digits are associated with an Issuer Identification Number (IIN), historically called a Bank Identification Number (BIN). These digits help identify the card network and issuer.
In this tutorial, you will learn how to recognize common card brands using PHP regular expressions, clean user input before checking it, and understand the limitations of prefix-based detection.
Understanding Credit Card Number Formats
Payment card numbers do not all begin with the same digits or have the same length. Each card network uses assigned number ranges. By checking the beginning of a card number, you can often determine which network it belongs to.
However, checking only the first digit or a short prefix is not always enough. Some networks use multiple ranges, and those ranges can change. For this reason, the regular expressions below should be treated as simplified examples rather than a complete or authoritative list of card-number ranges.
Common Credit Card Types and Their Number Prefixes
1. Visa
Visa card numbers start with the digit 4.
^ 4[0- 9] {
6,
}
$
2. Mastercard
Mastercard uses two main starting ranges:
51through552221through2720
A simplified regular expression for these ranges is:
^ (5[1- 5] [0- 9] {
4
}
| 2(?: 2[2- 9] [0- 9] {
3
}
| [3- 6] [0- 9] {
4
}
| 7(?: [01] [0- 9] {
3
}
| 20[0- 9] {
2
}
))) [0- 9]+$
For production use, prefer a maintained card-brand detection library because a manually maintained expression can become outdated or miss valid ranges.
3. American Express
American Express card numbers commonly begin with 34 or 37.
^ 3[47] [0- 9] {
5,
}
$
4. Diners Club
Diners Club cards commonly use prefixes in the 300 to 305 range, as well as 36 and 38.
^ 3(?: 0[0- 5]| [68] [0- 9]) [0- 9] {
4,
}
$
Some card products and co-branded arrangements may use different ranges, so this expression does not cover every possible card associated with Diners Club.
5. Discover
Discover uses several number ranges. Common prefixes include 6011, 65, parts of the 644 to 649 range, and the 622126 to 622925 range.
The following expression checks these commonly recognized ranges:
^ (?: 6011| 65[0- 9] {
2
}
| 64[4- 9] [0- 9]| 622(?: 12[6- 9]| 1[3- 9] [0- 9]| [2- 8] [0- 9] {
2
}
| 9[01] [0- 9]| 92[0- 5])) [0- 9]+$
6. JCB
JCB card numbers commonly use prefixes in the 3528 to 3589 range.
^ 35(?: 2[89]| [3- 8] [0- 9]) [0- 9] {
4,
}
$
PHP Example: Detect the Card Type
You can combine the patterns into one PHP function. This example first removes spaces and common separators, then checks the number against the supported card-brand patterns.
function detect_card_type( $card_number ) {
// Remove spaces and common separators.
$card_number = preg_replace( '/[\s-]+/', '', $card_number );
// Reject anything that is not numeric.
if ( ! preg_match( '/^[0-9]+$/', $card_number ) ) {
return 'Invalid';
}
$card_types = array(
'Visa' => '/^4[0-9]{6,}$/',
'Mastercard' => '/^(5[1-5][0-9]{4}|2(?:2[2-9][0-9]{3}|[3-6][0-9]{4}|7(?:[01][0-9]{3}|20[0-9]{2})))[0-9]+$/',
'American Express' => '/^3[47][0-9]{5,}$/',
'Diners Club' => '/^3(?:0[0-5]|[68][0-9])[0-9]{4,}$/',
'Discover' => '/^(?:6011|65[0-9]{2}|64[4-9][0-9]|622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[01][0-9]|92[0-5]))[0-9]+$/',
'JCB' => '/^35(?:2[89]|[3-8][0-9])[0-9]{4,}$/',
);
foreach ( $card_types as $type => $pattern ) {
if ( preg_match( $pattern, $card_number ) ) {
return $type;
}
}
return 'Unknown';
}
// Example usage:
echo detect_card_type( '4111 1111 1111 1111' );
This example identifies a likely card brand from the number prefix. It does not confirm that the card is genuine, active, or eligible for payment.
Why You Should Clean the Card Number Before Processing
Customers often enter card numbers with spaces or hyphens to make them easier to read. For example, a user might enter a number in this format:
4111 1111 1111 1111
Before checking the prefix, remove spaces and common separators. This prevents formatting characters from interfering with the pattern match.
Do not remove arbitrary characters and then accept the result without validation. Reject unexpected characters and follow the payment provider’s input requirements.
Important Notes About Card Number Length and Validation
- Card lengths vary: Do not assume that every payment card has exactly 16 digits. Different networks and card products can use different lengths.
- Prefix detection is not payment validation: Matching a regular expression only suggests a card brand. It does not prove that the card number is valid or usable.
- Use the Luhn algorithm where appropriate: A Luhn check can detect many common card-number entry errors, but it does not verify that an account exists or that a payment will succeed.
- Keep card data secure: Avoid storing or logging full card numbers. Use a PCI-compliant payment provider and its hosted fields, tokenization, or checkout integration instead of handling raw card details yourself.
- Do not assume unknown cards are Mastercard: If a number does not match one of your patterns, return an unknown result rather than assigning it to another network.
Conclusion
You can identify common credit card brands by checking their starting digits with PHP regular expressions. The examples in this tutorial cover common Visa, Mastercard, American Express, Diners Club, Discover, and JCB prefixes.
For a real payment form, do not rely on these simplified patterns as your only validation method. Use a maintained card-brand detection library or your payment provider’s tools, and let the payment processor handle sensitive card information securely.