views:

2017

answers:

8

Given a credit card number and no additional information, what is the best way in PHP to determine whether or not it is a valid number?

Right now I need something that will work with American Express, Discover, MasterCard, and Visa, but it might be helpful if it will also work with other types.

+1  A: 

This is only to make sure that the numbers are valid using some basic RegEX patterns.

Note, this does not check to see if the numbers are in-use by someone.

http://www.roscripts.com/How_to_validate_credit_card_numbers-106.html

Chad Moran
+3  A: 

PHP Code

function validateCC($cc_num, $type) {

 if($type == "American") {
 $denum = "American Express";
 } elseif($type == "Dinners") {
 $denum = "Diner's Club";
 } elseif($type == "Discover") {
 $denum = "Discover";
 } elseif($type == "Master") {
 $denum = "Master Card";
 } elseif($type == "Visa") {
 $denum = "Visa";
 }

 if($type == "American") {
 $pattern = "/^([34|37]{2})([0-9]{13})$/";//American Express
 if (preg_match($pattern,$cc_num)) {
 $verified = true;
 } else {
 $verified = false;
 }


 } elseif($type == "Dinners") {
 $pattern = "/^([30|36|38]{2})([0-9]{12})$/";//Diner's Club
 if (preg_match($pattern,$cc_num)) {
 $verified = true;
 } else {
 $verified = false;
 }


 } elseif($type == "Discover") {
 $pattern = "/^([6011]{4})([0-9]{12})$/";//Discover Card
 if (preg_match($pattern,$cc_num)) {
 $verified = true;
 } else {
 $verified = false;
 }


 } elseif($type == "Master") {
 $pattern = "/^([51|52|53|54|55]{2})([0-9]{14})$/";//Mastercard
 if (preg_match($pattern,$cc_num)) {
 $verified = true;
 } else {
 $verified = false;
 }


 } elseif($type == "Visa") {
 $pattern = "/^([4]{1})([0-9]{12,15})$/";//Visa
 if (preg_match($pattern,$cc_num)) {
 $verified = true;
 } else {
 $verified = false;
 }

 }

 if($verified == false) {
 //Do something here in case the validation fails
 echo "Credit card invalid. Please make sure that you entered a valid <em>" . $denum . "</em> credit card ";

 } else { //if it will pass...do something
 echo "Your <em>" . $denum . "</em> credit card is valid";
 }


}

Usage

echo validateCC("1738292928284637", "Dinners");

More theoric information can be found here:

Credit Card Validation - Check Digits

Checksum

Daok
That algorithm may identify the card issuer, roughly, it doesn't validate whether the number makes sense.. e.g. it doesn't check the checksum using the Luhn algorithm!
Ray Hayes
+37  A: 

There are three parts to the validation of the card number:

  1. PATTERN - does it match an issuers pattern (e.g. VISA/Mastercard/etc.)
  2. CHECKSUM - does it actually check-sum (e.g. not just 13 random numbers after "34" to make it an AMEX card number)
  3. REALLY EXISTS - does it actually have an associated account (you are unlikely to get this without a merchant account)

Pattern

There is a description here that describes many card types:

  • MASTERCARD Prefix=51 or 55, Length=16 (Mod10 checksummed)
  • VISA Prefix=4, Length=13 or 16 (Mod10)
  • AMEX Prefix=34 or 37, Length=15 (Mod10)
  • Diners Club/Carte Prefix=300-305, 36 or 38, Length=14 (Mod10)
  • Discover Prefix=6011, Length=16, (Mod10)
  • etc.

Checksum

Most cards use the Luhn algorithm for checksums:

Luhn Algorithm described on Wikipedia

There are links to many implementations on the Wikipedia link, including PHP:

<?
/* Luhn algorithm number checker - (c) 2005-2008 shaman - www.planzero.org *
 * This code has been released into the public domain, however please      *
 * give credit to the original author where possible.                      */

function luhn_check($number) {

  // Strip any non-digits (useful for credit card numbers with spaces and hyphens)
  $number=preg_replace('/\D/', '', $number);

  // Set the string length and parity
  $number_length=strlen($number);
  $parity=$number_length % 2;

  // Loop through each digit and do the maths
  $total=0;
  for ($i=0; $i<$number_length; $i++) {
    $digit=$number[$i];
    // Multiply alternate digits by two
    if ($i % 2 == $parity) {
      $digit*=2;
      // If the sum is two digits, add them together (in effect)
      if ($digit > 9) {
        $digit-=9;
      }
    }
    // Total up the digits
    $total+=$digit;
  }

  // If the total mod 10 equals 0, the number is valid
  return ($total % 10 == 0) ? TRUE : FALSE;

}
?>
Ray Hayes
Very thorough answer. Thank you!
Joe Lencioni
Under pattern, you could added "Discover", prefix = "6" (maybe "60"), Length=16
James Curran
MasterCard has a prefix of 51-55 not 51 or 55 according to http://www.beachnet.com/~hstiles/cardtype.html
Ben
+4  A: 

The luhn algorithm is a checksum that can used to validate the format of a lot of credit card formats (and also Canadian social insurance numbers...)

The wikipedia article also links to many different implementations; here's a PHP one:

http://planzero.org/code/bits/viewcode.php?src=luhn_check.phps

Dana
+6  A: 

From 10 regular expressions you can't live without in PHP:

function check_cc($cc, $extra_check = false){
    $cards = array(
        "visa" => "(4\d{12}(?:\d{3})?)",
        "amex" => "(3[47]\d{13})",
        "jcb" => "(35[2-8][89]\d\d\d{10})",
        "maestro" => "((?:5020|5038|6304|6579|6761)\d{12}(?:\d\d)?)",
        "solo" => "((?:6334|6767)\d{12}(?:\d\d)?\d?)",
        "mastercard" => "(5[1-5]\d{14})",
        "switch" => "(?:(?:(?:4903|4905|4911|4936|6333|6759)\d{12})|(?:(?:564182|633110)\d{10})(\d\d)?\d?)",
    );
    $names = array("Visa", "American Express", "JCB", "Maestro", "Solo", "Mastercard", "Switch");
    $matches = array();
    $pattern = "#^(?:".implode("|", $cards).")$#";
    $result = preg_match($pattern, str_replace(" ", "", $cc), $matches);
    if($extra_check && $result > 0){
        $result = (validatecard($cc))?1:0;
    }
    return ($result>0)?$names[sizeof($matches)-2]:false;
}

Sample input:

$cards = array(
    "4111 1111 1111 1111",
);

foreach($cards as $c){
    $check = check_cc($c, true);
    if($check!==false)
        echo $c." - ".$check;
    else
        echo "$c - Not a match";
    echo "<br/>";
}

This gives us

4111 1111 1111 1111 - Visa
ConroyP
+1  A: 

There is a PEAR package which handles the validation of many financial numbers, also credit card validation: http://pear.php.net/package/Validate_Finance_CreditCard

By the way, here are some Test Credit Card Account Numbers by PayPal.

powtac
A: 

See http://braemoor.co.uk/software/creditcard.php for a downloadable validation routine.

+3  A: 

It's probably better NOT to validate in code at your end. Send the card info right over to your payment gateway and then deal with their response. It helps them detect fraud if you don't do anything like Luhn checking first -- let them see the failed attempts.

Clayton