Skip to content

Instantly share code, notes, and snippets.

@zahradil
Last active December 20, 2015 22:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zahradil/6208954 to your computer and use it in GitHub Desktop.
Save zahradil/6208954 to your computer and use it in GitHub Desktop.
corrected cc validation code
# original code: http://code.activestate.com/recipes/578202-credit-card-number-check/
cc_patterns = { # '<cc_type>' : { dict of valid lengths : [list of associated prefixes] }
'amex' : { (15) : ('34', '37') },
'carteblanche' : { (14) : ('300', '301', '302', '303', '304', '305', '36', '38') },
'dinersclub' : { (14) : ('300', '301', '302', '303', '304', '305', '36', '38') },
'discover' : { (16) : ('6011') },
'enroute' : { (15) : ('2014', '2149') },
'jcb' : { (15) : ('2131', '1800'), (16) : ('3') },
'mastercard' : { (16) : ('51', '52', '53', '54', '55') },
'visa' : { (13, 16) : ('4') }
}
def cc_check( cc_num, cc_type ):
'''
Returns a touple of (isValidated, strReason)
* All doctest cc#s are random and do not reflect real world numbers *
>>> result = cc_check('5235235879456682', 'MASTERCARD')
>>> result[0]
True
>>> result = cc_check('5235235879456683', 'MASTERCARD')
>>> result[0]
False
>>> result[1].find('Invalid check sum')
0
>>> result = cc_check('523523583', 'MASTERCARD')
>>> result[0]
False
>>> result[1].find('Invalid length')
0
>>> result = cc_check('3235235879456683', 'MASTERCARD')
>>> result[0]
False
>>> result[1].find('Invalid prefix')
0
'''
cc_type = cc_type.strip().lower().replace(' ', '')
cc_num = str(cc_num)
if cc_type in cc_patterns.keys():
# Perform length check
valid_lengths = cc_patterns[cc_type].keys()
if len(cc_num) not in valid_lengths:
return (False, 'Invalid length (%s) for %s' % \
(str(valid_lengths).strip('[]'), cc_type))
# Perform prefix check
valid_prefixes = cc_patterns[cc_type][len(cc_num)]
prefix_match = False
for prefix in valid_prefixes:
prefix_length = len(prefix)
if cc_num[:prefix_length] == prefix:
prefix_match = True
if not prefix_match:
return (False, 'Invalid prefix (not in %s)' % \
','.join(valid_prefixes))
# Perform mod 10 check
if cc_type == 'enroute':
pass # Only cc_type that doesn't do a mod 10 check
else:
check_digits = []
is_even = False
for i, digit in enumerate(cc_num):
is_even = (i % 2 == 1)
if is_even:
check_digits.append(int(digit))
else:
mult_digits = str(int(digit) * 2)
check_digits.append(int(mult_digits[0]))
if len(mult_digits) == 2:
check_digits.append(int(mult_digits[1]))
# print cc_num
# print ",".join(str(i) for i in check_digits)
check_sum = sum(check_digits)
if check_sum % 10 != 0:
return (False, 'Invalid check sum (%d)' % check_sum)
return (True, '')
else:
return (False, 'Invalid cc type (%s)' % cc_type)
if __name__ == "__main__":
import doctest
doctest.testmod()
# USAGE:
# import sys
# print cc_check(sys.argv[1], sys.argv[2])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment