PDA

View Full Version : Credit Card Validation



Ian Telfer
27-Jul-2005, 05:33 PM
Hi Guys,

Here is a couple of functions that do credit card validations, including
making sure the number entered is correct, is valid for the card type
entered, checking expiry date etc.

It better to check all the data before sending off for processing with
Verisign etc.

Thought it might be useful.

Ian


Function DoValidateCard String sCardNo String sCardType String sExpiry String sCvv Number nAmt String sName Returns Integer
Number n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 n12 n13 n14 n15 n16
Number nCashAud nCashUsd nBalAud
Integer i iLen iCheckNum iTemp i1 iErr
String sComm sError sCardTypeCheck


Move (Length(sCardNo)) to iLen
If (iLen = 0) Function_return 0

//Note Diners & AMEX use 15 numbers, so change if they are accepted
If ((iLen < 15) or (iLen > 16)) Begin
Error 399 "Card number is incorrect length, must be 16 Characters"
Move 1 to iErr
End

If (Not(iErr)) Begin
For i from 1 to iLen //put into the array backwards
Move (Mid(sCardNo, 1, i)) to iTemp
Set value of oCardNumberArray item (iLen - i) to iTemp
Loop

For i from 1 to iLen
Get value of oCardNumberArray item (i - 1) to iTemp
Move i to n1
Move (n1 / 2) to n1
Move n1 to i1
If (n1 = i1) Begin
Move (iTemp * 2) to iTemp
If (iTemp >9) add ((iTemp -10) + 1) to iCheckNum
Else Add iTemp to iChecknum
End
Else Add iTemp to iCheckNum
End

Send delete_data of oCardNumberArray
//End total must be divisible by 10
Move iChecknum to n1
Move (n1 / 10) to n1
Move n1 to i1
If (i1 <> n1) Begin
Error 399 "Card number is incorrect"
Move 1 to iErr
End
End

Get DoCardType sCardNo to sCardTypeCheck
If (sCardTypeCheck <> sCardType) Begin
Case Begin
Case (sCardTypeCheck = "A")
Error 399 "Sorry we do not accept American Express"
Case Break
Case (sCardTypeCheck = "D")
Error 399 "Sorry we do not accept Diners"
Case Break
Case (sCardTypeCheck = "")
Error 399 "Sorry the numbers indicate the Card Type is unknown"
Case Break
Case Else
Error 399 "The numbers do not match the selected card type"
Case End
Increment iErr
End

Get DoCheckExpiryDate sExpiry to sError
If (sError <> "Card OK") Begin
Error 399 "Card Expired"
Increment iErr
End

If ((Length(sCvv)) <> 3) Begin
Error 399 "Card security number must be 3 characters long"
Increment iErr
End

//Get DoCheckName sName to sError
If (sName = "") Begin
Error 399 "Most Fill in a CardName"
Increment iErr
End

//Finally the Amount
If (nAmt =< 0) Begin
Error 399 "Amount must be greater then Zero"
Increment iErr
End

Function_return iErr
End_Function //DoValidateCardNum

Function DoCardType String sOutput returns String
Integer iCardNumLength
String sChar sChar2 sCardType
Move (Length(sOutput)) To iCardNumLength
Move (Left(sOutput, 1)) To sChar //test the first character to see what type of card
Move (Mid(sOutput, 1, 2)) to sChar2
Case Begin
Case ((sChar = "4") And (iCardNumLength = 16))
Move "V" To sCardType //Visa
Case Break
Case ((sChar = "5") And ((sChar2 = "1") OR ;
(sChar2 = "2") OR ;
(sChar2 = "3") OR ;
(sChar2 = "4") OR ;
(sChar2 = "5")) AND(iCardNumLength = 16))
Move "M" To sCardType //MasterCard
Case Break
Case ((sChar = 3) AND (sChar2 = "4") And (iCardNumLength = 15))
Move "A" To sCardType //Amex
Case Break
Case ((sChar = 3) And (sChar2 = "0") And (iCardNumLength = 14))
Move "D" To sCardType //Diners
Case Break
Case Else
Move "" To sCardType
Case End
Function_Return sCardType
End_Function //DoCardType

Function DoCheckExpiryDate String sExpiry returns String
String s1 s2 s3 s4 sCardYear sCardMonth sResult
Integer iCardOk iRetVal iCardYear iCardMonth iYear iMonth
Date dDate
Sysdate4 dDate

Move (Mid(sExpiry, 1, 1)) To s1
Move (Mid(sExpiry, 1, 2)) To s2
Move (Mid(sExpiry, 1, 3)) To s3
Move (Mid(sExpiry, 1, 4)) To s4
//need to check the exipry date of the card to make sure that it is not expired.
//note entry will be mmyy, whereas the card scan reads yymm
Move (S3 + s4) to sCardYear
Move sCardYear to iCardYear
Move (s1 + S2) to sCardMonth
Move sCardMonth to iCardMonth

Get DateSegment dDate DS_Year to iYear
Move (iYear - 2000) To iYear //cards only use 2 digit
Get DateSegment dDate DS_Month to iMonth

Case Begin
Case (iCardYear > iYear)
Move "Card OK" to sResult
Case Break
Case ((iCardYear = iYear) AND (iCardMonth >= iMonth))
Move "Card OK" to sResult
Case Break
Case (iCardYear < iYear)
Move "Card Expired" to sResult
Case Break
Case ((iCardYear = iYear) AND (iCardMonth < iMonth))
Move "Card Expired" to sResult
Case Break
Case End

Function_Return sResult
End_Function //DoCheckExpiryDate

Bernhard Mandl
28-Jul-2005, 10:44 AM
Your check is incomplete (i.e. some valid credit cards are refused)

See http://www.beachnet.com/~hstiles/cardtype.html

Regards,
Bernhard

"Ian Telfer" <ian@informatica.com.au> schrieb im Newsbeitrag
news:KH8BItvkFHA.5928@dacmail.dataaccess.com...
> Hi Guys,
>
> Here is a couple of functions that do credit card validations, including
> making sure the number entered is correct, is valid for the card type
> entered, checking expiry date etc.
>
> It better to check all the data before sending off for processing with
> Verisign etc.
>
> Thought it might be useful.
>
> Ian
>


--------------------------------------------------------------------------------


>
> Function DoValidateCard String sCardNo String sCardType String sExpiry
> String sCvv Number nAmt String sName Returns Integer
> Number n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 n12 n13 n14 n15 n16
> Number nCashAud nCashUsd nBalAud
> Integer i iLen iCheckNum iTemp i1 iErr
> String sComm sError sCardTypeCheck
>
>
> Move (Length(sCardNo)) to iLen
> If (iLen = 0) Function_return 0
>
> //Note Diners & AMEX use 15 numbers, so change if they are accepted
> If ((iLen < 15) or (iLen > 16)) Begin
> Error 399 "Card number is incorrect length, must be 16 Characters"
> Move 1 to iErr
> End
>
> If (Not(iErr)) Begin
> For i from 1 to iLen //put into the array backwards
> Move (Mid(sCardNo, 1, i)) to iTemp
> Set value of oCardNumberArray item (iLen - i) to iTemp
> Loop
>
> For i from 1 to iLen
> Get value of oCardNumberArray item (i - 1) to iTemp
> Move i to n1
> Move (n1 / 2) to n1
> Move n1 to i1
> If (n1 = i1) Begin
> Move (iTemp * 2) to iTemp
> If (iTemp >9) add ((iTemp -10) + 1) to iCheckNum
> Else Add iTemp to iChecknum
> End
> Else Add iTemp to iCheckNum
> End
>
> Send delete_data of oCardNumberArray
> //End total must be divisible by 10
> Move iChecknum to n1
> Move (n1 / 10) to n1
> Move n1 to i1
> If (i1 <> n1) Begin
> Error 399 "Card number is incorrect"
> Move 1 to iErr
> End
> End
>
> Get DoCardType sCardNo to sCardTypeCheck
> If (sCardTypeCheck <> sCardType) Begin
> Case Begin
> Case (sCardTypeCheck = "A")
> Error 399 "Sorry we do not accept American Express"
> Case Break
> Case (sCardTypeCheck = "D")
> Error 399 "Sorry we do not accept Diners"
> Case Break
> Case (sCardTypeCheck = "")
> Error 399 "Sorry the numbers indicate the Card Type is
> unknown"
> Case Break
> Case Else
> Error 399 "The numbers do not match the selected card type"
> Case End
> Increment iErr
> End
>
> Get DoCheckExpiryDate sExpiry to sError
> If (sError <> "Card OK") Begin
> Error 399 "Card Expired"
> Increment iErr
> End
>
> If ((Length(sCvv)) <> 3) Begin
> Error 399 "Card security number must be 3 characters long"
> Increment iErr
> End
>
> //Get DoCheckName sName to sError
> If (sName = "") Begin
> Error 399 "Most Fill in a CardName"
> Increment iErr
> End
>
> //Finally the Amount
> If (nAmt =< 0) Begin
> Error 399 "Amount must be greater then Zero"
> Increment iErr
> End
>
> Function_return iErr
> End_Function //DoValidateCardNum
>
> Function DoCardType String sOutput returns String
> Integer iCardNumLength
> String sChar sChar2 sCardType
> Move (Length(sOutput)) To iCardNumLength
> Move (Left(sOutput, 1)) To sChar //test the first character to see what
> type of card
> Move (Mid(sOutput, 1, 2)) to sChar2
> Case Begin
> Case ((sChar = "4") And (iCardNumLength = 16))
> Move "V" To sCardType //Visa
> Case Break
> Case ((sChar = "5") And ((sChar2 = "1") OR ;
> (sChar2 = "2") OR ;
> (sChar2 = "3") OR ;
> (sChar2 = "4") OR ;
> (sChar2 = "5")) AND(iCardNumLength = 16))
> Move "M" To sCardType //MasterCard
> Case Break
> Case ((sChar = 3) AND (sChar2 = "4") And (iCardNumLength = 15))
> Move "A" To sCardType //Amex
> Case Break
> Case ((sChar = 3) And (sChar2 = "0") And (iCardNumLength = 14))
> Move "D" To sCardType //Diners
> Case Break
> Case Else
> Move "" To sCardType
> Case End
> Function_Return sCardType
> End_Function //DoCardType
>
> Function DoCheckExpiryDate String sExpiry returns String
> String s1 s2 s3 s4 sCardYear sCardMonth sResult
> Integer iCardOk iRetVal iCardYear iCardMonth iYear iMonth
> Date dDate
> Sysdate4 dDate
>
> Move (Mid(sExpiry, 1, 1)) To s1
> Move (Mid(sExpiry, 1, 2)) To s2
> Move (Mid(sExpiry, 1, 3)) To s3
> Move (Mid(sExpiry, 1, 4)) To s4
> //need to check the exipry date of the card to make sure that it is not
> expired.
> //note entry will be mmyy, whereas the card scan reads yymm
> Move (S3 + s4) to sCardYear
> Move sCardYear to iCardYear
> Move (s1 + S2) to sCardMonth
> Move sCardMonth to iCardMonth
>
> Get DateSegment dDate DS_Year to iYear
> Move (iYear - 2000) To iYear //cards only use 2 digit
> Get DateSegment dDate DS_Month to iMonth
>
> Case Begin
> Case (iCardYear > iYear)
> Move "Card OK" to sResult
> Case Break
> Case ((iCardYear = iYear) AND (iCardMonth >= iMonth))
> Move "Card OK" to sResult
> Case Break
> Case (iCardYear < iYear)
> Move "Card Expired" to sResult
> Case Break
> Case ((iCardYear = iYear) AND (iCardMonth < iMonth))
> Move "Card Expired" to sResult
> Case Break
> Case End
>
> Function_Return sResult
> End_Function //DoCheckExpiryDate

Ian Telfer
28-Jul-2005, 06:00 PM
Bernard,

What do you mean some cards are refused? The algorithm can be used for
any cards, and works with them all. The sample I copied only takes Visa
& Mastercard, so the length check is 16. There used to be 13 digit
Visa, but not for a long time according to Verisign.

The Mod 10 calc is used by all that use a card number validation.

This algorithm processes some 3-5000 card transactions using keyboard
scanners over a 2 day period quite often, and we have yet to have
someone say a valid card was rejected by the system.

The prefix check needs expanding if you handle more than the standard 4,
but the function's there to do it, in Aust we don't use Discover,enRoute
or JCB cards...

Ian



Bernhard Mandl wrote:
> Your check is incomplete (i.e. some valid credit cards are refused)
>
> See http://www.beachnet.com/~hstiles/cardtype.html
>
> Regards,
> Bernhard
>
> "Ian Telfer" <ian@informatica.com.au> schrieb im Newsbeitrag
> news:KH8BItvkFHA.5928@dacmail.dataaccess.com...
>
>>Hi Guys,
>>
>>Here is a couple of functions that do credit card validations, including
>>making sure the number entered is correct, is valid for the card type
>>entered, checking expiry date etc.
>>
>>It better to check all the data before sending off for processing with
>>Verisign etc.
>>
>>Thought it might be useful.
>>
>>Ian
>>
>
>
>
> --------------------------------------------------------------------------------
>
>
>
>>Function DoValidateCard String sCardNo String sCardType String sExpiry
>>String sCvv Number nAmt String sName Returns Integer
>> Number n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 n12 n13 n14 n15 n16
>> Number nCashAud nCashUsd nBalAud
>> Integer i iLen iCheckNum iTemp i1 iErr
>> String sComm sError sCardTypeCheck
>>
>>
>> Move (Length(sCardNo)) to iLen
>> If (iLen = 0) Function_return 0
>>
>> //Note Diners & AMEX use 15 numbers, so change if they are accepted
>> If ((iLen < 15) or (iLen > 16)) Begin
>> Error 399 "Card number is incorrect length, must be 16 Characters"
>> Move 1 to iErr
>> End
>>
>> If (Not(iErr)) Begin
>> For i from 1 to iLen //put into the array backwards
>> Move (Mid(sCardNo, 1, i)) to iTemp
>> Set value of oCardNumberArray item (iLen - i) to iTemp
>> Loop
>>
>> For i from 1 to iLen
>> Get value of oCardNumberArray item (i - 1) to iTemp
>> Move i to n1
>> Move (n1 / 2) to n1
>> Move n1 to i1
>> If (n1 = i1) Begin
>> Move (iTemp * 2) to iTemp
>> If (iTemp >9) add ((iTemp -10) + 1) to iCheckNum
>> Else Add iTemp to iChecknum
>> End
>> Else Add iTemp to iCheckNum
>> End
>>
>> Send delete_data of oCardNumberArray
>> //End total must be divisible by 10
>> Move iChecknum to n1
>> Move (n1 / 10) to n1
>> Move n1 to i1
>> If (i1 <> n1) Begin
>> Error 399 "Card number is incorrect"
>> Move 1 to iErr
>> End
>> End
>>
>> Get DoCardType sCardNo to sCardTypeCheck
>> If (sCardTypeCheck <> sCardType) Begin
>> Case Begin
>> Case (sCardTypeCheck = "A")
>> Error 399 "Sorry we do not accept American Express"
>> Case Break
>> Case (sCardTypeCheck = "D")
>> Error 399 "Sorry we do not accept Diners"
>> Case Break
>> Case (sCardTypeCheck = "")
>> Error 399 "Sorry the numbers indicate the Card Type is
>>unknown"
>> Case Break
>> Case Else
>> Error 399 "The numbers do not match the selected card type"
>> Case End
>> Increment iErr
>> End
>>
>> Get DoCheckExpiryDate sExpiry to sError
>> If (sError <> "Card OK") Begin
>> Error 399 "Card Expired"
>> Increment iErr
>> End
>>
>> If ((Length(sCvv)) <> 3) Begin
>> Error 399 "Card security number must be 3 characters long"
>> Increment iErr
>> End
>>
>> //Get DoCheckName sName to sError
>> If (sName = "") Begin
>> Error 399 "Most Fill in a CardName"
>> Increment iErr
>> End
>>
>> //Finally the Amount
>> If (nAmt =< 0) Begin
>> Error 399 "Amount must be greater then Zero"
>> Increment iErr
>> End
>>
>> Function_return iErr
>>End_Function //DoValidateCardNum
>>
>>Function DoCardType String sOutput returns String
>> Integer iCardNumLength
>> String sChar sChar2 sCardType
>> Move (Length(sOutput)) To iCardNumLength
>> Move (Left(sOutput, 1)) To sChar //test the first character to see what
>>type of card
>> Move (Mid(sOutput, 1, 2)) to sChar2
>> Case Begin
>> Case ((sChar = "4") And (iCardNumLength = 16))
>> Move "V" To sCardType //Visa
>> Case Break
>> Case ((sChar = "5") And ((sChar2 = "1") OR ;
>> (sChar2 = "2") OR ;
>> (sChar2 = "3") OR ;
>> (sChar2 = "4") OR ;
>> (sChar2 = "5")) AND(iCardNumLength = 16))
>> Move "M" To sCardType //MasterCard
>> Case Break
>> Case ((sChar = 3) AND (sChar2 = "4") And (iCardNumLength = 15))
>> Move "A" To sCardType //Amex
>> Case Break
>> Case ((sChar = 3) And (sChar2 = "0") And (iCardNumLength = 14))
>> Move "D" To sCardType //Diners
>> Case Break
>> Case Else
>> Move "" To sCardType
>> Case End
>> Function_Return sCardType
>>End_Function //DoCardType
>>
>>Function DoCheckExpiryDate String sExpiry returns String
>> String s1 s2 s3 s4 sCardYear sCardMonth sResult
>> Integer iCardOk iRetVal iCardYear iCardMonth iYear iMonth
>> Date dDate
>> Sysdate4 dDate
>>
>> Move (Mid(sExpiry, 1, 1)) To s1
>> Move (Mid(sExpiry, 1, 2)) To s2
>> Move (Mid(sExpiry, 1, 3)) To s3
>> Move (Mid(sExpiry, 1, 4)) To s4
>>//need to check the exipry date of the card to make sure that it is not
>>expired.
>> //note entry will be mmyy, whereas the card scan reads yymm
>> Move (S3 + s4) to sCardYear
>> Move sCardYear to iCardYear
>> Move (s1 + S2) to sCardMonth
>> Move sCardMonth to iCardMonth
>>
>> Get DateSegment dDate DS_Year to iYear
>> Move (iYear - 2000) To iYear //cards only use 2 digit
>> Get DateSegment dDate DS_Month to iMonth
>>
>> Case Begin
>> Case (iCardYear > iYear)
>> Move "Card OK" to sResult
>> Case Break
>> Case ((iCardYear = iYear) AND (iCardMonth >= iMonth))
>> Move "Card OK" to sResult
>> Case Break
>> Case (iCardYear < iYear)
>> Move "Card Expired" to sResult
>> Case Break
>> Case ((iCardYear = iYear) AND (iCardMonth < iMonth))
>> Move "Card Expired" to sResult
>> Case Break
>> Case End
>>
>> Function_Return sResult
>>End_Function //DoCheckExpiryDate
>
>
>

Peter A Donovan
14-Jan-2006, 03:40 PM
Hi Ian,
Your code makes mention of "oCardNumberArray" and doesn't compile therefore,
do you feel you could share that array with us too?
TIA,
Peter Donovan

Ian Telfer
15-Jan-2006, 10:18 PM
Hi Peter,

Its just a declared object that is used to reverse the string of card
numbers (123 to 321), so at the top of the view it just ;

object oCardNumberArray is an array
End_Object.

Cheers

Ian

Peter A Donovan wrote:
> Hi Ian,
> Your code makes mention of "oCardNumberArray" and doesn't compile therefore,
> do you feel you could share that array with us too?
> TIA,
> Peter Donovan
>
>