Greg's Blog

helping me remember what I figure out

Validating Your Credit Card Number

| Comments

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):
  1. Double the value of every other digit starting with the next-to-rightmost digit.
  2. If any of the resulting values has more than two digits, then its digits must be added together to produce a single digit.
  3. Add the sum of all the digits not doubled in step 1 to the sum of all the digits resulting in step 2.
  4. 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.
So if the formula returns 0 (zero), the credit card submitted is correct. And the module sets local.cc_valid to 1, in turn caller.cc_valid is set to the value of local.cc_valid, as this is how you return values to the calling page in Cold Fusion. Now the next step would be to submit the information to your payment gateway to authorise the purchase and debit the credit from the card. So there’s still a way to go, but at least you can save yourself some processing and user frustration by validating the submitted information at your end first, before continuing down to the gateway. And that’s it! If you like you can download the full source here. While we are on the topic of credit cards I came across this resource that pretty much covered everything I have ever wanted to know about my plastic friend (and then some).