File Coverage

blib/lib/Business/CreditCard.pm
Criterion Covered Total %
statement 42 58 72.4
branch 39 58 67.2
condition 35 54 64.8
subroutine 4 6 66.6
pod 1 5 20.0
total 121 181 66.8


line stmt bran cond sub pod time code
1             package Business::CreditCard;
2              
3             require Exporter;
4 4     4   56600 use vars qw( @ISA $VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS $Country );
  4         5  
  4         5216  
5              
6             @ISA = qw( Exporter );
7              
8             $VERSION = "0.36";
9              
10             @EXPORT = qw( cardtype validate generate_last_digit );
11             @EXPORT_OK = qw( receipt_cardtype validate_card );
12             $EXPORT_TAGS{NEW} = [ qw( validate_card cardtype receipt_cardtype ) ];
13              
14             $Country = 'US';
15              
16             =head1 NAME
17              
18             C - Validate/generate credit card checksums/names
19              
20             =head1 SYNOPSIS
21              
22             use Business::CreditCard;
23            
24             print validate("5276 4400 6542 1319");
25             print cardtype("5276 4400 6542 1319");
26             print generate_last_digit("5276 4400 6542 131");
27              
28             Business::CreditCard is available at a CPAN site near you.
29              
30             =head1 DESCRIPTION
31              
32             These subroutines tell you whether a credit card number is
33             self-consistent -- whether the last digit of the number is a valid
34             checksum for the preceding digits.
35              
36             The validate() subroutine returns 1 if the card number provided passes
37             the checksum test, and 0 otherwise.
38              
39             The cardtype() subroutine returns a string containing the type of
40             card. The list of possible return values is more comprehensive than it used
41             to be, but additions are still most welcome.
42              
43             Possible return values are:
44              
45             VISA card
46             MasterCard
47             Discover card
48             American Express card
49             enRoute
50             JCB
51             BankCard
52             Switch
53             Solo
54             China Union Pay
55             Laser
56             Isracard
57             Unknown
58              
59             "Not a credit card" is returned on obviously invalid data values.
60              
61             Versions before 0.31 may also have returned "Diner's Club/Carte Blanche" (these
62             cards are now recognized as "Discover card").
63              
64             As of 0.30, cardtype() will accept a partial card masked with "x", "X', ".",
65             "*" or "_". Only the first 2-6 digits and the length are significant;
66             whitespace and dashes are removed. With two digits, Visa, MasterCard, Discover
67             and Amex are recognized (versions before 0.36 needed four digits to recognize
68             all Discover cards). With four digits, almost all cards except some
69             Switch cards are recognized. With six digits (the full "BIN" or "IIN"), all
70             cards are recognized. Six digits are also required for receipt_cardtype().
71              
72             The generate_last_digit() subroutine computes and returns the last
73             digit of the card given the preceding digits. With a 16-digit card,
74             you provide the first 15 digits; the subroutine returns the sixteenth.
75              
76             This module does I tell you whether the number is on an actual
77             card, only whether it might conceivably be on a real card. To verify
78             whether a card is real, or whether it's been stolen, or to actually process
79             charges, you need a Merchant account. See L.
80              
81             These subroutines will also work if you provide the arguments
82             as numbers instead of strings, e.g. C.
83              
84             =head1 PROCESSING AGREEMENTS
85              
86             Credit card issuers have recently been forming agreements to process cards on
87             other networks, in which one type of card is processed as another card type.
88              
89             By default, Business::CreditCard returns the type the card should be treated as
90             in the US. You can change this to return the type the card should
91             be treated as in a different country by setting
92             C<$Business::CreditCard::Country> to your two-letter country code. This
93             is probably what you want to determine if you accept the card, or which
94             merchant agreement it is processed through.
95              
96             You can also set C<$Business::CreditCard::Country> to a false value such
97             as the empty string to return the "base" card type. This is probably only
98             useful for informational purposes when used along with the default type.
99              
100             Here are the currently known agreements:
101              
102             =over 4
103              
104             =item Most Diner's club is now identified as Discover. (This supercedes the earlier identification of some Diner's club cards as MasterCard inside the US and Canada.)
105              
106             =item JCB cards in the 3528-3589 range are identified as Discover inside the US and territories.
107              
108             =item China Union Pay cards are identified as Discover cards in the US, Mexico and most Caribbean countries.
109              
110             =back
111              
112             =head1 RECEIPT REQUIREMENTS
113              
114             Discover requires some cards processed on its network to display "PayPal"
115             on receipts instead of "Discover". The receipt_cardtype() subroutine will
116             return "PayPal card" for these cards only, and otherwise the same output as
117             cardtype().
118              
119             Use this for receipt display/printing only.
120              
121             Note: this subroutine is not exported by default like the others.
122             Before 0.36, you needed to call this subroutine fully-qualified, as
123             Business::CreditCard::receipt_cardtype()
124              
125             In 0.36 and later, you can import it into your namespace:
126              
127             use Business::CreditCard qw( :DEFAULT receipt_cardtype );
128              
129              
130             =head1 ORIGINAL AUTHOR
131              
132             Jon Orwant
133              
134             The Perl Journal and MIT Media Lab
135              
136             =head1 MAINTAINER
137              
138             Current maintainer is Ivan Kohler .
139              
140             Lee Lawrence , Neale Banks and
141             Max Becker contributed support for additional card
142             types. Lee also contributed a working test.pl. Alexandr Ciornii
143             contributed code cleanups. Jason Terry
144             contributed updates for Discover BIN ranges.
145              
146             =head1 COPYRIGHT AND LICENSE
147              
148             Copyright (C) 1995,1996,1997 Jon Orwant
149             Copyright (C) 2001-2006 Ivan Kohler
150             Copyright (C) 2007-2016 Freeside Internet Services, Inc.
151              
152             This library is free software; you can redistribute it and/or modify
153             it under the same terms as Perl itself, either Perl version 5.8.8 or,
154             at your option, any later version of Perl 5 you may have available.
155              
156             =head1 BUGS
157              
158             (paraphrasing Neil Bowers) We export all functions by default. It would be
159             better to let the user decide which functions to import. And validate() is
160             a bit of a generic name.
161              
162             The question is, after almost 2 decades with this interface (inherited from
163             the original author, who probably never expected it to live half this long),
164             how to change things to behave in a more modern fashion without breaking
165             existing code? "use Business::CreditCard " turns it off?
166             Explicitly ask to turn it off and list that in the SYNOPSIS?
167              
168             =head2 validate() and @EXPORT transition plan
169              
170             First (done in 0.36):
171              
172             validate_card() is the new name for validate(). Both work for now.
173              
174             New-style usage (not recommended for code that needs to support B:CC before 0.36):
175              
176             use Business::CreditCard qw( :NEW );
177              
178             You get validate_card(), cardtype() and receipt_cardtype(). You can also ask
179             for them explicitly / individually:
180              
181             use Business::CreditCard qw( validate_card cardtype receipt_cardtype );
182              
183              
184             Second (we're at now now):
185              
186             Waiting for 0.36+ to become more prevalent.
187              
188              
189             Third:
190              
191             Recommend new-style usage. Maybe asking for a specific minimum version turns
192             it on too?
193              
194              
195             Fourth:
196             (this is the incompatible part):
197              
198             Don't export validate() (or anything else [separately?]) by default.
199              
200             This is the part that will break things and we probably won't do for a long
201             time, until new-style usage is the norm and the tradeoff of breaking old code
202             is worth it to stop or namespace pollution. Maybe do a 1.00 releaes with the
203             current API and 2.00 is when this happens (with a 1.99_01 pre-release)?
204              
205             =head1 SEE ALSO
206              
207             L is a wrapper around Business::CreditCard
208             providing an OO interface. Assistance integrating this into the base
209             Business::CreditCard distribution is welcome.
210              
211             L is a framework for processing online payments
212             including modules for various payment gateways.
213              
214             http://neilb.org/reviews/luhn.html is an excellent overview of similar modules
215             providing credit card number verification (LUHN checking).
216              
217             =cut
218              
219             ## ref http://neilb.org/reviews/luhn.html#Comparison it looks like
220             ## Business::CCCheck is 2x faster than we are. looking at their implementation
221             ## not entirely a fair comparison, we also do the equivalent of their CC_clean,
222             ## they don't recognize certain cards at all (i.e. Switch) which require
223             ## an expensive check before VISA, Diners doesn't exist anymore, Discover is
224             ## a lot more than just 6011*, they don't handle processing agreements, etc.
225              
226             sub cardtype {
227             # Allow use as a class method
228 42 50   42 0 1194 shift if UNIVERSAL::isa( $_[0], 'Business::CreditCard' );
229              
230 42         36 my ($number) = @_;
231              
232 42         61 $number =~ s/[\s\-]//go;
233 42         59 $number =~ s/[x\*\.\_]/x/gio;
234              
235 42 50       71 return "Not a credit card" if $number =~ /[^\dx]/io;
236              
237             #$number =~ s/\D//g;
238             {
239 42         29 local $^W=0; #no warning at next line
  42         77  
240 42 50 66     216 return "Not a credit card"
      33        
241             unless ( length($number) >= 13
242             || length($number) == 8 || length($number) == 9 #Isracard
243             )
244             && 0+$number;
245             }
246              
247 42 100       64 return "VISA card" if $number =~ /^4[0-8][\dx]{11,17}$/o;
248              
249 39 100 100     169 return "MasterCard"
      66        
250             if $number =~ /^5[1-5][\dx]{14}$/o
251             || $number =~ /^2 ( 22[1-9] | 2[3-9][\dx] | [3-6][\dx]{2} | 7[0-1][\dx] | 720 ) [\dx]{12}$/xo
252             || $number =~ /^2[2-7]xx[\dx]{12}$/o;
253              
254 36 100       68 return "American Express card" if $number =~ /^3[47][\dx]{13}$/o;
255              
256 34 100 33     503 return "Discover card"
      66        
      66        
      100        
      100        
      100        
      100        
      66        
      100        
      66        
257             if $number =~ /^30[0-5x][\dx]{13,16}$/o #diner's: 300-305, 30x
258             || $number =~ /^309[5x][\dx]{12}$/o # 3095, 309x
259             || $number =~ /^36[\dx]{12,17}$/o # 36
260             || $number =~ /^3[89][\dx]{14,17}$/o # 38 and 39
261             || $number =~ /^60[1x]{2}[\dx]{12,15}$/o #discover: 6011 601x 60xx
262             || $number =~ /^64[4-9x][\dx]{13,16}$/o # 644-649, 64x
263             || $number =~ /^65[\dx]{14,17}$/o # 65
264             || ( $number =~ /^62[24-68x][\dx]{13,16}$/o && $Country =~ /^(US|MX|AI|AG|AW|BS|BB|BM|BQ|VG|KY|CW|DM|DO|GD|GP|JM|MQ|MS|BL|KN|LC|VC|MF|SX|TT|TC)$/oi ) #China Union Pay identified as Discover in US, Mexico and Caribbean
265             || ( $number =~ /^35(2[89x]|[3-8][\dx]|xx)[\dx]{12,15}$/o && $Country =~ /^(US|PR|VI|MP|PW|GU)$/oi ); #JCB cards in the 3528-3589 range are identified as Discover in US, Puerto Rico, US Virgin Islands, Northern Mariana Islands, Palau and Guam
266              
267 22 50 33     114 return "Switch"
      33        
268             if $number =~ /^49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})[\dx]{10}([\dx]{2,3})?$/o
269             || $number =~ /^564182[\dx]{10}([\dx]{2,3})?$/o
270             || $number =~ /^6(3(33[0-4][0-9])|759[0-9]{2})[\dx]{10}([\dx]{2,3})?$/o;
271             #redunant with above, catch 49* that's not Switch
272 22 100       38 return "VISA card" if $number =~ /^4[\dx]{12,18}$/o;
273              
274             #"Diners Club enRoute"
275 21 100       34 return "enRoute" if $number =~ /^2(014|149)[\dx]{11}$/o;
276              
277 19 100       73 return "JCB" if $number =~ /^(3[\dx]{4}|2131|1800)[\dx]{11}$/o;
278              
279 8 100       21 return "BankCard" if $number =~ /^56(10[\dx][\dx]|022[1-5])[\dx]{10}$/o;
280              
281 7 50       14 return "Solo"
282             if $number =~ /^6(3(34[5-9][0-9])|767[0-9]{2})[\dx]{10}([\dx]{2,3})?$/o;
283              
284 7 100       16 return "China Union Pay"
285             if $number =~ /^62[24-68][\dx]{13}$/o;
286              
287 5 100       10 return "Laser"
288             if $number =~ /^6(304|7(06|09|71))[\dx]{12,15}$/o;
289              
290 4 100       10 return "Isracard"
291             if $number =~ /^[\dx]{8,9}$/;
292              
293 2         4 return "Unknown";
294             }
295              
296             sub receipt_cardtype {
297             # Allow use as a class method
298 0 0   0 0 0 shift if UNIVERSAL::isa( $_[0], 'Business::CreditCard' );
299              
300 0         0 my ($number) = @_;
301              
302 0         0 $number =~ s/[\s\-]//go;
303 0         0 $number =~ s/[x\*\.\_]/x/gio;
304              
305             #ref Discover IIN Bulletin Feb 2015_021715
306 0 0       0 return "PayPal card" if $number =~ /^6(01104|506[01]0)[\dx]{10,13}$/o;
307              
308 0         0 cardtype($number);
309             }
310              
311             sub generate_last_digit {
312             # Allow use as a class method
313 0 0   0 0 0 shift if UNIVERSAL::isa( $_[0], 'Business::CreditCard' );
314              
315 0         0 my ($number) = @_;
316              
317 0 0 0     0 die "invalid operation" if length($number) == 8 || length($number) == 9;
318              
319 0         0 my ($i, $sum, $weight);
320              
321 0         0 $number =~ s/\D//g;
322              
323 0         0 for ($i = 0; $i < length($number); $i++) {
324 0         0 $weight = substr($number, -1 * ($i + 1), 1) * (2 - ($i % 2));
325 0 0       0 $sum += (($weight < 10) ? $weight : ($weight - 9));
326             }
327              
328 0         0 return (10 - $sum % 10) % 10;
329             }
330              
331              
332             ## this (GPLed) code from Business::CCCheck is apparantly 4x faster than ours
333             ## ref http://neilb.org/reviews/luhn.html#Comparison
334             ## maybe see if we can speed ours up a bit
335             # my @ccn = split('',$ccn);
336             # my $even = 0;
337             # $ccn = 0;
338             # for($i=$#ccn;$i >=0;--$i) {
339             # $ccn[$i] *= 2 if $even;
340             # $ccn -= 9 if $ccn[$i] > 9;
341             # $ccn += $ccn[$i];
342             # $even = ! $even;
343             # }
344             # $type = '' if $ccn % 10;
345             # return $type;
346              
347 2     2 1 19 sub validate { validate_card(@_); }
348              
349             sub validate_card {
350             # Allow use as a class method
351 6 50   6 0 1049 shift if UNIVERSAL::isa( $_[0], 'Business::CreditCard' );
352              
353 6         10 my ($number) = @_;
354              
355 6         4 my ($i, $sum, $weight);
356            
357 6 50       13 return 0 if $number =~ /[^\d\s]/;
358              
359 6         20 $number =~ s/\D//g;
360              
361 6 100       22 if ( $number =~ /^[\dx]{8,9}$/ ) { # Isracard
362 2 100       5 $number = "0$number" if length($number) == 8;
363 2         5 for($i=1;$i
364 16         24 $sum += substr($number,9-$i,1) * $i;
365             }
366 2 50       5 return 1 if $sum%11 == 0;
367 0         0 return 0;
368             }
369              
370 4 50 33     19 return 0 unless length($number) >= 13 && 0+$number;
371              
372 4         9 for ($i = 0; $i < length($number) - 1; $i++) {
373 60         54 $weight = substr($number, -1 * ($i + 2), 1) * (2 - ($i % 2));
374 60 100       87 $sum += (($weight < 10) ? $weight : ($weight - 9));
375             }
376              
377 4 100       16 return 1 if substr($number, -1) == (10 - $sum % 10) % 10;
378 2         7 return 0;
379             }
380              
381             1;
382              
383