three3
three3

Reputation: 2846

How to determine which number in a series is the invalid credit card number

I am needing help with a credit card validation script. I have figured out how to determine if a credit card is valid/invalid but what I am needing is this:

If someone enters an invalid credit card number, is there a way to determine which number is invalid?

Here is my current code to determine if a card is valid/invalid:

function validateCreditcard_number($credit_card_number) {
    //Get the first digit
    $firstnumber = substr($credit_card_number, 0, 1);
    //Make sure it is the correct amount of digits. Account for dashes being present.
    switch ($firstnumber) {
        case 3:
            if (!preg_match('/^3\d{3}[ \-]?\d{6}[ \-]?\d{5}$/', $credit_card_number)) {
               return '<li>This is not a valid American Express card number. Please use a different credit/debit card or re-enter your credit/debit card details.</li>';
            }
            break;
        case 4:
            if (!preg_match('/^4\d{3}[ \-]?\d{4}[ \-]?\d{4}[ \-]?\d{4}$/', $credit_card_number)) {
                return '<li>This is not a valid Visa card number. Please use a different credit/debit card or re-enter your credit/debit card details.</li>';
            }
            break;
        case 5:
            if (!preg_match('/^5\d{3}[ \-]?\d{4}[ \-]?\d{4}[ \-]?\d{4}$/', $credit_card_number)) {
                 return '<li>This is not a valid MasterCard card number. Please use a different credit/debit card or re-enter your credit/debit card details.</li>';
            }
            break;
        case 6:
            if (!preg_match('/^6011[ \-]?\d{4}[ \-]?\d{4}[ \-]?\d{4}$/', $credit_card_number)) {
                return '<li>This is not a valid Discover card number. Please use a different credit/debit card or re-enter your credit/debit card details.</li>';
            }
            break;
        default:
            return '<li>This is not a valid credit card number. Please use a different credit/debit card or re-enter your credit/debit card details.</li>';
    } //END Switch statement

    //Luhn Algorithm
    $credit_card_number = str_replace('.', '', $credit_card_number);
    $credit_card_number = str_replace('-', '', $credit_card_number);
    $credit_card_number = str_replace(' ', '', $credit_card_number);
    $map = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                0, 2, 4, 6, 8, 1, 3, 5, 7, 9);
    $sum = 0;
    $last = strlen($credit_card_number) - 1;

    for ($i = 0; $i <= $last; $i++) {
        $sum += $map[$credit_card_number[$last - $i] + ($i & 1) * 10];
    }

    if ($sum % 10 != 0) {
       return '<li>This is not a valid credit card number. Please use a different credit/debit card or re-enter your credit/debit card details.</li>';
    } else {
       //If we made it this far the credit card number is in a valid format
       return 'This is a valid credit card number' ;
    }

} //END validateCreditcard_number

Upvotes: 1

Views: 3314

Answers (3)

user229044
user229044

Reputation: 239311

You could go a long way by not assuming the first number is correct. As it stands, somebody who typos the very first number of their Visa as a 3 instead of a 4 gets told they're entering an invalid American Express. That's brutal, from a usability stand point. If the credit card number is invalid, it's simply invalid. It's not an invalid American Express unless they explicitly choose American Express from another drop-down.

Besides that small improvement, what you ask is impossible. The mod10 checksum algorithm cannot tell you which digit is incorrect.

By way of trying to explain why, consider the following simplified scenario:

  • I have 5 digits, I don't know what they are
  • The sum of the 5 digits is 50
  • One of the following digits is off-by-one

Which of the following digits is incorrect?

9 + 11 + 8 + 9 + 12 = 49

It is impossible to tell. It could be any of those digits, any one of them might be off by -1. But that doesn't begin to describe our trouble. I told you that only one digit is wrong. In your situation, you don't know how many are wrong. One digit might be off by -2, and another image might be off by +1. There are literally an infinite number of "wrong" states. Maybe all five numbers are wrong! Maybe the correct 5 numbers are 0 0 0 0 50. This is the problem you face with mod10/Luhn validation. It is absolutely impossible to tell which number/numbers is/are incorrect.

You asked in response to another answer if there is some other algorithm to tell if an individual digit is incorrect; that doesn't make any sense. Luhn is the algorithm, like it or not. The numbers weren't generated to fit any other algorithm, and you don't get to change the algorithm after it's in use by the entire world.


As an unrelated critique, your function shouldn't be returning human-readable error messages/success messages. It is horrible practice, and leads to unmaintainable, unlocalizable apps.

Upvotes: 2

outis
outis

Reputation: 77400

The Luhn checksum can't detect which digit is incorrect, it can only detect single-digit errors and some multi-digit errors. It's entirely possible to mistype two digits and get a number with a valid checksum.

Upvotes: 2

O&#39;Rooney
O&#39;Rooney

Reputation: 3090

You cannot. The credit card numbers have a checksum (error checking code) which allows detecting errors, but they do not have any error correction code.

Upvotes: 2

Related Questions