- Double the value of every other digit starting with the next-to-rightmost digit.
- If any of the resulting values has more than two digits, then its digits must be added together to produce a single digit.
- Add the sum of all the digits not doubled in step 1 to the sum of all the digits resulting in step 2.
- If the result is exactly divisible by 10 (that is, if the result ends in a zero), then the number is valid–providing of course that it’s of the correct length and bears a correct prefix for that type of card–and can now be submitted for authorisation of a sale.
Validating Your Credit Card Number
One of the items that recently caught my attention was a series of articles on WebReference.com about Usable shopping carts. This serie essentially was an excerpt from a set of chapters taken from a book by the same name. One item in particular caught my eye and that centered around validating Credit Card numbers using the Luhn formula. The article focused on developing the validation server side making use of PHP, so I decided to build a module in Cold Fusion to handle the same thing. I will not go too much into the nitty gritty as you can read up on it at the WebReference site. So without further ado the form and code.
So let’s start of with the template, which includes the form for passing your credit card details and on submission will call the module to perform the validation.
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>
<html>
<head>
<title>Credit card number validation</title>
</head>
<body>
<cfif NOT isdefined(“form.fieldnames”)>
<form action=”” method=”post” name=”frm_cc” id=”frm_cc” enctype=”application/x-www-form-urlencoded”>
Type: <select name=”r_type” id=”r_type”>
<option value=”“>Specify a cc type</option>
<option value=”“>——————–</option>
<option value=”visa”>Visa</option>
<option value=”mastercard”>Master Card</option>
<option value=”amex”>American Express</option>
<option value=”discovery”>Discovery</option>
<option value=”diners”>Diners Club</option>
</select><br />
CC Number: <input type=”Text” name=”r_cc_number” id=”r_cc_number” value=”” size=”20” /><br />
<input type=”Submit” name=”btn_submit” id=”btn_submit” value=”Validate” />
</form>
<cfelse>
<cfmodule template=”cc_validation.cfm” attribute_1=”#form.r_type#” attribute_2=”#form.r_cc_number#” />
<cfif cc_valid eq 0>
Your credit card number is incorrect.<br />
<cfelse>
Card verified successfully.<br />
</cfif>
</cfif>
</body>
</html>
The first thing the template does is check if the form has not been submitted. If this is the case then it displays the form. However if on the other hand it has, then it will call the module. The module itself takes two attributes, which correspond to the card type and the credit card number. No rocket science here, so onto the module.
<cfset local.cc_number = attributes.attribute_2 />
<cfset local.cc_type = attributes.attribute_1 />
<!— -strip out any dashes or spaces- —>
<cfset local.cc_number = rereplace(local.cc_number, “-|[[:space:]]”, “”, “all”) />
<cfif isNumeric(local.cc_number)>
<!— -OK test for length first
if true length_valid = 1 else it’s equal 0
Second test for the prefix if true prefix_valid = 1 and 0 if not
- —>
<cfset local.submitted_len = len(local.cc_number) />
<cfset local.length_valid = 0 />
<cfset local.prefix_valid = 0 />
<cfswitch expression=”#local.cc_type#”>
<cfcase value=”mastercard”>
<cfif local.submitted_len eq 16>
<cfset local.length_valid = 1 />
</cfif>
<cfset local.submitted_prefix = mid(local.cc_number, 1, 2) />
<cfif (local.submitted_prefix gte 51) AND (local.submitted_prefix lte 55)>
<cfset local.prefix_valid = 1 />
</cfif>
</cfcase>
<cfcase value=”visa”>
<cfif (local.submitted_len eq 13) OR (local.submitted_len eq 16)>
<cfset local.length_valid = 1 />
</cfif>
<cfset local.submitted_prefix = mid(local.cc_number, 1, 1) />
<cfif local.submitted_prefix eq 4>
<cfset local.prefix_valid = 1 />
</cfif>
</cfcase>
<cfcase value=”amex”>
<cfif local.submitted_len eq 15>
<cfset local.length_valid = 1 />
</cfif>
<cfset local.submitted_prefix = mid(local.cc_number, 1, 2) />
<cfif (local.submitted_prefix eq 34) OR (local.submitted_prefix eq 37)>
<cfset local.prefix_valid = 1 />
</cfif>
</cfcase>
<cfcase value=”discover”>
<cfif local.submitted_len eq 16>
<cfset local.length_valid = 1 />
</cfif>
<cfset local.submitted_prefix = mid(local.cc_number, 1, 4) />
<cfif local.submitted_prefix eq 6011>
<cfset local.prefix_valid = 1 />
</cfif>
</cfcase>
<cfcase value=”diners”>
<cfif local.submitted_len eq 14>
<cfset local.length_valid = 1 />
</cfif>
<cfset local.submitted_prefix = mid(local.cc_number, 1, 3) />
<cfif ((local.submitted_prefix gte 300) AND (local.submitted_prefix lte 305)) OR find(“36”, mid(local.submitted_prefix, 1, 2), 1) OR find(“38”, mid(local.submitted_prefix, 1, 2), 1)>
<cfset local.prefix_valid = 1 />
</cfif>
</cfcase>
</cfswitch>
<cfif (local.length_valid AND local.prefix_valid) eq 1>
<!— -now we check the Luhn formula- —>
<cfscript>
y = 0;
for (i=1; i lte local.submitted_len; setvariable(“i”,i+1)) {
x = mid(local.cc_number,i,1);
if (i mod 2) {
x = x*2;
if (x gt 9) {
z = (x \ 10) + (x - 10);
y = y + z;
} else {
y = y + x;
}
} else {
y = y + x;
}
}
y = y mod 10;
//WriteOutput(y&”<br />”);
</cfscript>
<cfif y neq 0>
<cfset local.cc_valid = 0 />
<!— -Your credit card number is incorrect.<br />- —>
<cfelse>
<cfset local.cc_valid = 1 />
<!— -Card verified successfully.<br />- —>
</cfif>
<cfelse>
<cfset local.cc_valid = 0 />
<!— -Your credit card number is incorrect.<br />- —>
</cfif>
<cfelse>
<cfset local.cc_valid = 0 />
<!— -Your credit card number is incorrect.<br />- —>
</cfif>
<cfset caller.cc_valid = local.cc_valid />
<!— -debug
CC type: <cfoutput>#local.cc_type#</cfoutput><br />
CC number: <cfoutput>#local.cc_number#</cfoutput><br />
Length valid: <cfoutput>#local.length_valid#</cfoutput>
(<cfoutput>#local.submitted_len#</cfoutput>)<br />
Prefix valid: <cfoutput>#local.prefix_valid#</cfoutput>
(<cfoutput>#local.submitted_prefix#</cfoutput>)<br />
- —>
In the first instance we are setting the attributes passed by the call ot the module to local variables. Then I remove all spaces and dashes that user may have submitted and check that the number passed by the form is actually a number, if it passes this then the real work begins. Another step you might want to build in is to check whether or not values have actually been submitted. Anyway back to the actual processing.
Each credit card type follows a set of rules, i.e. each type has a varying length prefix and a set number of digits. The summary of these can be found on the aforementioned webreference site. The script then proceeds to determine the type and check that the number submitted fulfills the prefix and digit length requirements. If it passes it moves on to the Luhn formula and if not the script exits and returns 0 for local.cc_valid which is the variable that is returned by the module to verify the success of the evaluation.
The luhn formula helps to determine whether or not the number submitted is actually a valid credit card number. Listed below are the rules (lifted straight from the webreference site):