Credit Card Validation (2) (Views: 300)
Problem/Question/Abstract: How can I know if a number is a valid credit card number? Answer: The following unit can be used to make credit card verification unit Creditc; {***************************************************************************** Credit Card Number Validator Unit for Delphi Version: 1.1 Date: December 20, 1996 This unit is based on the public domain program ccard by Peter Miller. It is released to the public for free of charge use, but the author reserves all rights. copyright 1996 by Shawn Wilson Harvell ( shawn@inet.net ) usage: Add this unit to the uses clause of any unit that needs access to the validation function. IsValidCreditCardNumber( CardNumber, ReturnMessage ) returns Boolean for example, use it in an if statement that Messages user if invalid. CardNumber is a string containing the number that you want to validate ReturnMessage is a string where the function can place any messages it may return ( meaning that it will overwrite whatever is in it ) returns true if valid, false otherwise. dashes and space in the input value are taken care of by the function, if other characters are possible, you may wish to remove them as well. The function RemoveChar will take care of this quite easily, simply pass the input string and the char you wish to delete. Users are free to modify this unit for their own use, but in distributing you should advise all users of the changes made. Use this unit at your own risk, it does not come with any warranties either express or implied. Damages resulting from the use of this unit are the sole responsibility of the user. This should work as is for Delphi versions 1 and 2, some slight modifications may be necessary for Turbo Pascal ( mainly due to use to conversion functions from the SysUtils unit ). If you do find this useful, have any comments or suggestions, please drop the author an email at shawn@inet.net Revision History version 1.1 -- December 20, 1996 blooper with Discover cards, added their length mask to the "database" version 1.0 -- October 26, 1996 initial release *****************************************************************************} interface uses SysUtils; function IsValidCreditCardNumber(CardNumber: string; var MessageText: string): Boolean; implementation const CardPrefixes: array[1..19] of string = ('2014', '2149', '300', '301', '302', '303', '304', '305', '34', '36', '37', '38', '4', '51', '52', '53', '54', '55', '6011'); CardTypes: array[1..19] of string = ('enRoute', 'enRoute', 'Diner Club/Carte Blanche', 'Diner Club/Carte Blanche', 'Diner Club/Carte Blanche', 'Diner Club/Carte Blanche', 'Diner Club/Carte Blanche', 'Diner Club/Carte Blanche', 'American Express', 'Diner Club/Carte Blanche', 'American Express', 'Diner Club/Carte Blanche', 'Visa', 'MasterCard', 'MasterCard', 'MasterCard', 'MasterCard', 'MasterCard', 'Discover'); function RemoveChar(const Input: string; DeletedChar: Char): string; var Index: Word; { counter variable } begin { all this function does is iterate through string looking for char, if found } { it deletes it } Result := Input; for Index := Length(Result) downto 1 do if Result[Index] = DeletedChar then Delete(Result, Index, 1); end; function ShiftMask(Input: Integer): Integer; begin { simply a wrapper for this left bit shift operation } result := (1 shl (Input - 12)); end; function ConfirmChecksum(CardNumber: string): Boolean; var CheckSum: Integer; { Holds the value of the operation } Flag: Boolean; { used to indicate when ready } Counter: Integer; { index counter } PartNumber: string; { used to extract each digit of number } Number: Integer; { used to convert each digit to integer } begin {************************************************************************** This is probably the most confusing part of the code you will see, I know that it is some of the most confusing I have ever seen. Basically, this function is extracting each digit of the number and subjecting it to the checksum formula established by the credit card companies. It works from the end to the front. **************************************************************************} { get the starting value for our counter } Counter := Length(CardNumber); CheckSum := 0; PartNumber := ''; Number := 0; Flag := false; while (Counter >= 1) do begin { get the current digit } PartNumber := Copy(CardNumber, Counter, 1); Number := StrToInt(PartNumber); { convert to integer } if (Flag) then { only do every other digit } begin Number := Number * 2; if (Number >= 10) then Number := Number - 9; end; CheckSum := CheckSum + Number; Flag := not (Flag); Counter := Counter - 1; end; result := ((CheckSum mod 10) = 0); end; function GetMask(CardName: string): Integer; begin { the default case } result := 0; if (CardName = 'MasterCard') then result := ShiftMask(16); if (CardName = 'Visa') then result := (ShiftMask(13) or ShiftMask(16)); if (CardName = 'American Express') then result := ShiftMask(15); if (CardName = 'Diner Club/Carte Blanche') then result := ShiftMask(14); if (CardName = 'Discover') then result := ShiftMask(16); end; function IsValidCreditCardNumber(CardNumber: string; var MessageText: string): Boolean; var StrippedNumber: string; { used to hold the number bereft of extra chars } Index: Integer; { general purpose counter for loops, etc } TheMask: Integer; { number we will use for the mask } FoundIt: Boolean; { used to indicate when something is found } CardName: string; { stores the name of the type of card } PerformChecksum: Boolean; { the enRoute type of card doesn't get it } begin { first, get rid of spaces, dashes } StrippedNumber := RemoveChar(CardNumber, ' '); StrippedNumber := RemoveChar(StrippedNumber, '-'); { if the string was zero length, then OK too } if (StrippedNumber = '') then begin result := true; exit; end; { initialize return variables } MessageText := ''; result := true; { set our flag variable } FoundIt := false; { check for invalid characters right off the bat } for Index := 1 to Length(StrippedNumber) do begin case StrippedNumber[Index] of '0'..'9': FoundIt := FoundIt; { non op in other words } else MessageText := 'Invalid Characters in Input'; result := false; exit; end; end; { now let's determine what type of card it is } for Index := 1 to 19 do begin if (Pos(CardPrefixes[Index], StrippedNumber) = 1) then begin { we've found the right one } FoundIt := true; CardName := CardTypes[Index]; TheMask := GetMask(CardName); end; end; { if we didn't find it, indicates things are already ary } if (not FoundIt) then begin CardName := 'Unknown Card Type'; TheMask := 0; MessageText := 'Unknown Card Type '; result := false; exit; end; { check the length } if ((Length(StrippedNumber) > 28) and result) then begin MessageText := 'Number is too long '; result := false; exit; end; { check the length } if ((Length(StrippedNumber) < 12) or ((shiftmask(length(strippednumber)) and themask) = 0)) then begin messagetext := 'number length incorrect'; result := false; exit; end; { check the checksum computation } if (cardname = 'enroute') then performchecksum := false else performchecksum := true; if (performchecksum and (not confirmchecksum(strippednumber))) then begin messagetext := 'bad checksum'; result := false; exit; end; { if result is still true, then everything is ok } if (result) then messagetext := 'number ok: card type: ' + cardname; { if the string was zero length, then ok too } if (strippednumber = '') then result := true; end; end. |