Search code examples
phpvalidatione-commercenumberscredit-card

What is the best way to validate a credit card in PHP?


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.


Solution

  • 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

    • MASTERCARD Prefix=51-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,622126-622925,644-649,65, Length=16, (Mod10)
    • etc. (detailed list of prefixes)

    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;
    
    }
    ?>