private static bool ValidateCardNumber( string cardNumber )
{
try
{
// Array to contain individual numbers
System.Collections.ArrayList CheckNumbers = new ArrayList();
// So, get length of card
int CardLength = cardNumber.Length;
// Double the value of alternate digits, starting with the second digit
// from the right, i.e. back to front.
// Loop through starting at the end
for (int i = CardLength-2; i >= 0; i = i - 2)
{
// Now read the contents at each index, this
// can then be stored as an array of integers
// Double the number returned
CheckNumbers.Add( Int32.Parse(cardNumber[i].ToString())*2 );
}
int CheckSum = 0; // Will hold the total sum of all checksum digits
// Second stage, add separate digits of all products
for (int iCount = 0; iCount <= CheckNumbers.Count-1; iCount++)
{
int _count = 0; // will hold the sum of the digits
// determine if current number has more than one digit
if ((int)CheckNumbers[iCount] > 9)
{
int _numLength = ((int)CheckNumbers[iCount]).ToString().Length;
// add count to each digit
for (int x = 0; x < _numLength; x++)
{
_count = _count + Int32.Parse(
((int)CheckNumbers[iCount]).ToString()[x].ToString() );
}
}
else
{
// single digit, just add it by itself
_count = (int)CheckNumbers[iCount];
}
CheckSum = CheckSum + _count; // add sum to the total sum
}
// Stage 3, add the unaffected digits
// Add all the digits that we didn't double still starting from the
// right but this time we'll start from the rightmost number with
// alternating digits
int OriginalSum = 0;
for (int y = CardLength-1; y >= 0; y = y - 2)
{
OriginalSum = OriginalSum + Int32.Parse(cardNumber[y].ToString());
}
// Perform the final calculation, if the sum Mod 10 results in 0 then
// it's valid, otherwise its false.
return (((OriginalSum+CheckSum)%10)==0);
}
catch
{
return false;
}
}
//最后
protected override bool EvaluateIsValid()
{
if (_validateCardType) // should the length be validated also?
{
// Check the length, if the length is fine then validate the
// card number
if (IsValidCardType(_creditCardTextBox.Text))
return ValidateCardNumber( _creditCardTextBox.Text );
else
return false; // Invalid length
}
else
// Check that the text box contains a valid number using
// the ValidateCardNumber method
return ValidateCardNumber( _creditCardTextBox.Text );
}
Introduction
A while ago I started working on converting an eCommerce payment gateway's (DataCash) COM server to a native .NET assembly using their XML API. Once I had got a basic version working I decided to produce a simple web form to test it out, and so opened it up for all comers (and received some very generous donations from CP members -- thanks guys :). As part of this web form I wanted to include support to check that users had entered a card number, expiration date etc., and then wanted to extend it further to include support for checking that the card number was valid before issuing a request to the payment gateway's server. This is the result, a drop-in replacement for any of the other validation controls.
Incidentally, you can see a demo of the validator in use (as well as the card payment gateway assembly) at the following address: https://ssl500.securepod.com/oobaloo/DataCash/, besides this you may also be interested in the everything you ever wanted to know about CC's guide.
Before getting into any of the implementation details here is a simple UML class diagram to show the rough layout of the Control.
The diagram is missing information about parameter types since its not essential to understanding the model. For those who are not familiar with UML, it shows a specialisation relationship between the BaseValidator and CreditCardValidator classes - an is a relationship - demonstrating inheritance from BaseValidator to the more specialised CreditCardValidator class. New with the third incarnation of the control is the AcceptedCardTypes property which is used to specify what types of card should pass the validation using the CardType enumeration.
The control includes support for validating card numbers in two ways. Firstly, through checking the card number using Luhn's formula, the details of which are included in the next part of the article. Secondly, the card type itself is examined, and the length is checked. The card type can be determined through a prefix and each type has a specified length, by examining these an additional level of control can be added - the types of card to accept. The method that implements this is IsValidCardType, and whether this is used during the validation is set by the ValidateCardType property.
The main way the card number is going to be validated is through Luhn's formula, so firstly a little bit of background information and a demo of how the validation is performed.
Luhn's Formula
公式如下:
Double the value of alternating digits
The first step is to double each of the alternating digits in the number. But the trick is to start with the second digit from the right and work backwards. Say we have a credit card number 1234 5678 1234 5670. We'll start with the rightmost number 7, double it, and then do the same for every other digit.
1234 5678 1234 5670
This will give us the following values.
7 x 2 = 14
5 x 2 = 10
3 x 2 = 6
.
.
etc.
Add the separate digits of all the products
Now we'll the separate digits of all the products, and come up with a final sum.
(1 + 4) + (1 + 0) + 6 + 2 + (1 + 4) + (1 + 0) + 6 + 2 = 28
Be sure to add the digits, not just the number.
Add the unaffected digits
Now we'll go back to the original number and add all the digits that we didn't double. We'll still start from the right, but this time we'll start from the rightmost number.
1234 5678 1234 5670
0 + 6 + 4 + 2 + 8 + 6 + 4 + 2 = 32
Add the results and divide by 10
Finally, we'll add both the results and divide the answer by 10.
28 + 32 = 60
60 is evenly divided by 10, so the credit card number is well formed and ready for further processing.
Sub ValidateBtn_OnClick(sender As Object, e As EventArgs)
If (Page.IsValid) Then
lblOutput.Text = "页有效!"
Else
lblOutput.Text = "页无效!:-("
End If
End Sub
Sub ServerValidate (sender As Object, value As ServerValidateEventArgs)
Try
Dim num As Int32 = Int32.Parse(value.Value)
If num Mod 2 = 0 Then
value.IsValid = True
Exit Sub
End If
Catch E As Exception
' Do Nothing
End Try
value.IsValid = False
End Sub