Last active
December 20, 2015 22:59
-
-
Save zahradil/6208954 to your computer and use it in GitHub Desktop.
corrected cc validation code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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