2005. április 21., csütörtök
Credit Card Validation (2)
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.
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése