Site hosted by Angelfire.com: Build your free website today!
# 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
}