# This is a demo NeoWebScript by Horace Vallas - 3-7-97 according to some info
# I found on the web that was attibuted to ICVERIFY by Hal Stiles hstiles@beachnet.com
# http://www.beachnet.com/~hstiles/cardtype.html
#
# You are welcome to use it; however, I make no warranty whatsoever about the
# accuracy or usefullness of this script. By using this script, you are agreeing that
# I am not responsible for any damage, of any kind whatsoever, to you or to any of
# your customers, clients, partners, friends, relatives, children born or unborne,
# pets, invisible friends, etc. etc. etc.
#===============================================================
# The valCC proc can be used to validate a credit card number as
# being legally formed.
#
# input is the entered card number
# return is the type of card (if validated)
# or "- unknown-" if it is an unknown or invalid number
#
# The validation applied (last known date 3/96) is the so called
# LUHN Formula (Mod 10) for Validation of Primary Account Number
# Validation criteria are:
#
# 1. number prefix
# 2. number of digits
# 3. mod10 (for all but enRoute which uses only 1 & 2)
#
# ... according to the following list of criteria requirements:
#
# Card Type Prefix Length Check-Digit Algoritm
#
# MC 51 - 55 16 mod 10
#
# VISA 4 13, 16 mod 10
#
# AMX 34, 37 15 mod 10
#
# Diners Club / 300 - 305, 36, 38 14 mod 10
# Carte Blanche
#
# Discover 6011 16 mod 10
#
# enRoute 2014, 2149 16 - any -
#
# JCB 3 16 mod 10
# JCB 2131, 1800 15 mod 10
#
proc valCC {numIn} {
regsub -all { } $numIn {} entered_number
set num [split $entered_number {}] ; # a list form of the number
set numLen [llength $num] ; # the number of digits in the entered number
set type "-unknown-"
# first determine the type of card: MC, VISA, AMX, etc.
# i.e. test prefix and then number of digits
switch -glob [string range $entered_number 0 3] {
"51??" - "52??" - "53??" - "54??" - "55??"
{if {$numLen == 16} {set type "MasterCard"}}
"4???"
{if {$numLen == 13 || $numLen == 16} {set type "VISA"}}
"34??" - "37??"
{if {$numLen == 15} {set type "American Express"}}
"300?" - "301?" - "302?" - "303?" - "304?" - "305?" - "36??" - "38??"
{if {$numLen == 14} {set type "Diner's Club / Carte Blanche"}}
"6011"
{if {$numLen == 16} {set type "Discover"}}
"2014" - "2149"
{if {$numLen == 15} {set type "enRoute"}; return $type ; # early exit for enRoute}
"3???"
{if {$numLen == 16} {set type "JCB"}}
"2131" - "1800"
{if {$numLen == 15} {set type "JCB"}}
default
{set type "-unknown-"}
}
if {$type == "-unknown-"} {
return $type} ; #early exit if we already know it is bad
# if prefix and number of digits are ok,
# then apply the mod10 check
set sum 0 ; # initialize the running sum
# sum every digit starting with the RIGHT-MOST digit
# on alternate digits (starting with the NEXT-TO-THE-RIGHT-MOST digit)
# sum all digits in the result of TWO TIMES the alternate digit
# RATHER than the original digit itself
# CATCH this summing loop in case there are non-digit values in the
# user supplied string
if {[catch { ;
for {set i [expr $numLen - 1]} {$i >= 0} {} {
incr sum [lindex $num $i]
if {[incr i -1] >= 0} {
foreach adigit [split [expr 2 * [lindex $num $i]] {}] {incr sum $adigit}
incr i -1
}
}
}] != 0} {
return "-unknown-"
}
# emulate a mod 10 (base 10) on the calculated number.
# if there is any remainder, then the number IS NOT VALID
# so reset type to -unknown-
set lsum [split $sum {}]
if {[lindex $lsum [expr [llength $lsum] - 1]]} {set type "-unknown-"}
return $type
}