File Coverage

blib/lib/Data/FormValidator/Constraints.pm
Criterion Covered Total %
statement 273 347 78.6
branch 73 148 49.3
condition 61 153 39.8
subroutine 63 75 84.0
pod 19 32 59.3
total 489 755 64.7


line stmt bran cond sub pod time code
1             #
2             # Constraints.pm - Standard constraints for use in Data::FormValidator.
3             #
4             # This file is part of Data::FormValidator.
5             #
6             # Author: Francis J. Lacoste
7             # Maintainer: Mark Stosberg
8             #
9             # Copyright (C) 1999,2000 iNsu Innovations Inc.
10             # Copyright (C) 2001 Francis J. Lacoste
11             # Parts Copyright 1996-1999 by Michael J. Heins
12             # Parts Copyright 1996-1999 by Bruce Albrecht
13             #
14             # Parts of this module are based on work by
15             # Bruce Albrecht, contributed to MiniVend.
16             #
17             # Parts also based on work by Michael J. Heins
18             #
19             # This program is free software; you can redistribute it and/or modify
20             # it under the terms same terms as perl itself.
21             #
22             package Data::FormValidator::Constraints;
23 59     59   211 use base 'Exporter';
  59         64  
  59         5091  
24 59     59   209 use strict;
  59         65  
  59         2131  
25             our $AUTOLOAD;
26              
27             our $VERSION = 4.85;
28              
29 0         0 BEGIN {
30 59     59   198 use Carp;
  59         77  
  59         17130  
31 59     59   188 my @closures = (qw/
32             american_phone
33             cc_exp
34             cc_number
35             cc_type
36             email
37             ip_address
38             phone
39             postcode
40             province
41             state
42             state_or_province
43             zip
44             zip_or_postcode/);
45              
46             # This be optimized with some of the voodoo that CGI.pm
47             # uses to AUTOLOAD dynamic functions.
48 59         125 for my $func (@closures) {
49             # cc_number is defined statically
50 767 100       1568 unless ($func eq 'cc_number') {
51             # Notice we have to escape some characters
52             # in the subroutine, which is really a string here.
53              
54 708         2121 local $SIG{__DIE__} = \&confess;
55 708         1751 my $code = qq!
56             sub $func {
57             return sub {
58             my \$dfv = shift;
59             use Scalar::Util ();
60             die "first arg to $func was not an object. Must be called as a constraint_method."
61             unless ( Scalar::Util::blessed(\$dfv) && \$dfv->can('name_this') );
62              
63             \$dfv->name_this('$func') unless \$dfv->get_current_constraint_name();
64             no strict 'refs';
65             return &{"match_$func"}(\@_);
66             }
67             }
68             !;
69              
70 708 0 0 59 1 43001 eval "package Data::FormValidator::Constraints; $code";
  59 0 0 59 1 225  
  59 0 33 59 1 75  
  59 0 0 59 1 2617  
  59 50 0 59 1 235  
  59 50 0 59 1 72  
  59 0 0 59 1 2840  
  59 0 0 59 1 249  
  59 0 0 59 1 68  
  59 0 0 59 1 2629  
  59 0 0 59 1 198  
  59 0 0 59 1 75  
  59 0   59   2740  
  59 0   59   241  
  59 0   59   68  
  59 0   59   2445  
  59 0   59   183  
  59 0   59   60  
  59 0   59   2624  
  59 0   59   228  
  59 0   59   68  
  59 0   59   2421  
  59 0   59   180  
  59 0   59   61  
  59     0   2647  
  59     0   229  
  59     0   67  
  59     0   2311  
  59     1   178  
  59     0   62  
  59     0   3977  
  59     0   226  
  59     0   66  
  59     0   2321  
  59     0   179  
  59     0   68  
  59     0   2588  
  59         223  
  59         65  
  59         2431  
  59         809  
  59         79  
  59         5027  
  59         232  
  59         769  
  59         2421  
  59         192  
  59         61  
  59         2438  
  59         214  
  59         63  
  59         2345  
  59         194  
  59         76  
  59         2492  
  59         252  
  59         79  
  59         2320  
  59         183  
  59         81  
  59         2490  
  59         206  
  59         65  
  59         2305  
  59         178  
  59         64  
  59         2507  
  59         242  
  59         160  
  59         2266  
  59         175  
  59         1456  
  59         3108  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         1  
  1         13  
  1         4  
  1         1  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         40  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
71 708 50       2874 die "couldn't create $func: $@" if $@;
72             }
73             }
74              
75 59         2154 my @FVs = (qw/
76             FV_length_between
77             FV_min_length
78             FV_max_length
79             FV_eq_with
80             FV_num_values
81             FV_num_values_between
82             /);
83              
84 59         972 our @EXPORT_OK = (
85             @closures,
86             @FVs,
87             qw(
88             valid_american_phone
89             valid_cc_exp
90             valid_cc_number
91             valid_cc_type
92             valid_email
93             valid_ip_address
94             valid_phone
95             valid_postcode
96             valid_province
97             valid_state
98             valid_state_or_province
99             valid_zip
100             valid_zip_or_postcode
101             match_american_phone
102             match_cc_exp
103             match_cc_number
104             match_cc_type
105             match_email
106             match_ip_address
107             match_phone
108             match_postcode
109             match_province
110             match_state
111             match_state_or_province
112             match_zip
113             match_zip_or_postcode)
114             );
115              
116 59         6177 our %EXPORT_TAGS = (
117             # regexp common is correctly empty here, because we handle the case on the fly with the import function below.
118             regexp_common => [],
119             closures => [ @closures, @FVs ],
120             validators => [qw/
121             valid_american_phone
122             valid_cc_exp
123             valid_cc_number
124             valid_cc_type
125             valid_email
126             valid_ip_address
127             valid_phone
128             valid_postcode
129             valid_province
130             valid_state
131             valid_state_or_province
132             valid_zip
133             valid_zip_or_postcode
134             /],
135             matchers => [qw/
136             match_american_phone
137             match_cc_exp
138             match_cc_number
139             match_cc_type
140             match_email
141             match_ip_address
142             match_phone
143             match_postcode
144             match_province
145             match_state
146             match_state_or_province
147             match_zip
148             match_zip_or_postcode
149             /],
150             );
151              
152             sub import {
153             # This is Regexp::Common support.
154             # Here we are handling cases that look like this:
155             #
156             # my_field => FV_foo_bar(-zoo=>'queue'),
157 126 100   126   1296 if (grep { m/^:regexp_common$/ } @_) {
  373         874  
158 1         582 require Regexp::Common;
159 1         2364 import Regexp::Common 'RE_ALL';
160              
161 1         131615 for my $sub (grep { m/^RE_/} keys %Data::FormValidator::Constraints:: ) {
  236         207  
162 59     59   247 no strict 'refs';
  59         70  
  59         5339  
163 173         112 my $new_name = $sub;
164 173         274 $new_name =~ s/^RE_/FV_/;
165 173         490 *{caller() . "::$new_name"} = sub {
166 6     6   50 my @params = @_;
167             return sub {
168 9     9   13 my $dfv = shift;
169 9 50       23 $dfv->name_this($new_name) unless $dfv->get_current_constraint_name();
170              
171 59     59   221 no strict "refs";
  59         67  
  59         6831  
172 9         63 my $re = &$sub(-keep=>1,@params);
173 9         767 my ($match) = ($dfv->get_current_constraint_value =~ qr/^($re)$/);
174 9         51 return $dfv->untainted_constraint_value($match);
175             }
176 6         90 }
177 173         316 }
178             }
179              
180 126         41473 Data::FormValidator::Constraints->export_to_level(1,@_);
181             }
182              
183             }
184              
185              
186             # sub DESTROY {}
187              
188             =pod
189              
190             =head1 NAME
191              
192             Data::FormValidator::Constraints - Basic sets of constraints on input profile.
193              
194             =head1 SYNOPSIS
195              
196             use Data::FormValidator::Constraints qw(:closures);
197              
198             In an Data::FormValidator profile:
199              
200             constraint_methods => {
201             email => email(),
202             phone => american_phone(),
203             first_names => {
204             constraint_method => FV_max_length(3),
205             name => 'my_custom_name',
206             },
207             },
208             msgs => {
209             constraints => {
210             my_custom_name => 'My message',
211             },
212             },
213              
214              
215              
216             =head1 DESCRIPTION
217              
218             These are the builtin constraints that can be specified by name in the input
219             profiles.
220              
221             Be sure to check out the SEE ALSO section for even more pre-packaged
222             constraints you can use.
223              
224             =cut
225              
226             sub AUTOLOAD {
227 34     34   6364 my $name = $AUTOLOAD;
228              
229 59     59   214 no strict qw/refs/;
  59         65  
  59         118390  
230              
231 34         111 $name =~ m/^(.*::)(valid_|RE_)(.*)/;
232              
233 34         72 my ($pkg,$prefix,$sub) = ($1,$2,$3);
234              
235             #warn "hello! my ($pkg,$prefix,$sub) = ($1,$2,$3);";
236              
237             # Since all the valid_* routines are essentially identical we're
238             # going to generate them dynamically from match_ routines with the same names.
239 34 50 33     167 if ((defined $prefix) and ($prefix eq 'valid_')) {
240 34         33 return defined &{$pkg.'match_' . $sub}(@_);
  34         135  
241             }
242             }
243              
244             =head2 FV_length_between(1,23)
245              
246             =head2 FV_max_length(23)
247              
248             =head2 FV_min_length(1)
249              
250             use Data::FormValidator::Constraints qw(
251             FV_length_between
252             FV_min_length
253             FV_max_length
254             );
255              
256             constraint_methods => {
257              
258             # specify a min and max, inclusive
259             last_name => FV_length_between(1,23),
260              
261             }
262              
263             Specify a length constraint for a field.
264              
265             These constraints have a different naming convention because they are higher-order
266             functions. They take input and return a code reference to a standard constraint
267             method. A constraint name of C, C, or C will be set,
268             corresponding to the function name you choose.
269              
270             The checks are all inclusive, so a max length of '100' will allow the length 100.
271              
272             Length is measured in perl characters as opposed to bytes or anything else.
273              
274             This constraint I untaint your data if you have untainting turned on. However,
275             a length check alone may not be enough to insure the safety of the data you are receiving.
276             Using additional constraints to check the data is encouraged.
277              
278             =cut
279              
280             sub FV_length_between {
281 8     8 1 6 my ($min,$max) = @_;
282 8 50 33     26 if (not (defined $min and defined $max)) {
283 0         0 croak "min and max are required";
284             }
285             return sub {
286 8     8   6 my ($dfv,$value) = @_;
287 8 100       16 $dfv->name_this('length_between') unless $dfv->get_current_constraint_name();
288 8 100 100     1065 return undef if ( ( length($value) > $max ) || ( length($value) < $min) );
289             # Use a regexp to untaint
290 3         346 $value=~/(.*)/s;
291 3         8 return $dfv->untainted_constraint_value($1);
292             }
293 8         44 }
294              
295             sub FV_max_length {
296 6     6 1 999 my ($max) = @_;
297 6 50       12 croak "max is required" unless defined $max;
298             return sub {
299 6     6   8 my ($dfv,$value) = @_;
300 6 100       13 $dfv->name_this('max_length') unless $dfv->get_current_constraint_name();
301 6 100       698 return undef if ( length($value) > $max );
302             # Use a regexp to untaint
303 2         346 $value=~/(.*)/s;
304 2         7 return $dfv->untainted_constraint_value($1);
305             }
306 6         60 }
307              
308             sub FV_min_length {
309 5     5 1 5 my ($min) = @_;
310 5 50       6 croak "min is required" unless defined $min;
311             return sub {
312 4     4   3 my ($dfv,$value) = @_;
313 4 50       8 $dfv->name_this('min_length') unless $dfv->get_current_constraint_name();
314 4 100       724 return undef if ( length($value) < $min );
315             # Use a regexp to untaint
316 2         343 $value=~/(.*)/s;
317 2         5 return $dfv->untainted_constraint_value($1);
318             }
319 5         17 }
320              
321             =head2 FV_eq_with
322              
323             use Data::FormValidator::Constraints qw( FV_eq_with );
324              
325             constraint_methods => {
326             password => FV_eq_with('password_confirm'),
327             }
328              
329             Compares the current field to another field.
330             A constraint name of C will be set.
331              
332             =cut
333              
334             sub FV_eq_with {
335 2     2 1 486 my ($other_field) = @_;
336             return sub {
337 2     2   5 my $dfv = shift;
338 2 50       10 $dfv->name_this('eq_with') unless $dfv->get_current_constraint_name();
339              
340 2         8 my $curr_val = $dfv->get_current_constraint_value;
341              
342 2         6 my $data = $dfv->get_filtered_data;
343             # Sometimes the data comes through both ways...
344 2 50       7 my $other_val = (ref $data->{$other_field}) ? $data->{$other_field}[0] : $data->{$other_field};
345              
346 2         4 return ($curr_val eq $other_val);
347             }
348              
349 2         24 }
350              
351             =head2 FV_num_values
352              
353             use Data::FormValidator::Constraints qw ( FV_num_values );
354              
355             constraint_methods => {
356             attachments => FV_num_values(4),
357             }
358              
359             Checks the number of values in the array named by this param.
360             Note that this is useful for making sure that only one value was passed for a
361             given param (by supplying a size argument of 1).
362             A constraint name of C will be set.
363              
364             =cut
365              
366             sub FV_num_values {
367 2   33 2 1 22 my $size = shift || croak 'size argument is required';
368             return sub {
369 3     3   2 my $dfv = shift;
370 3         8 $dfv->name_this('num_values');
371 3         5 my $param = $dfv->get_current_constraint_field();
372 3         7 my $value = $dfv->get_filtered_data()->{$param};
373              
374             # If there's an arrayref of values provided, test the number of them found
375             # against the number of them of required
376 3 50 33     16 if (defined $value and ref $value eq 'ARRAY') {
    0          
377 3         2 my $num_values_found = scalar @$value;
378 3         6 return ($num_values_found == $size);
379             }
380             # If a size of 1 was requested, there was not an arrayref of values,
381             # there must be exactly one value.
382             elsif ($size == 1) {
383 0         0 return 1;
384             }
385             # Any other case is failure.
386             else {
387 0         0 return 0;
388             }
389             }
390 2         13 }
391              
392             =head2 FV_num_values_between
393              
394             use Data::FormValidator::Constraints qw ( FV_num_values_between );
395              
396             constraint_methods => {
397             attachments => FV_num_values_between(1,4),
398             }
399              
400             Checks that the number of values in the array named by this param is between
401             the supplied bounds (inclusively).
402             A constraint name of C will be set.
403              
404             =cut
405              
406             sub FV_num_values_between {
407 2     2 1 3 my ($min, $max) = @_;
408 2 50 33     9 croak 'min and max arguments are required' unless $min && $max;
409             return sub {
410 2     2   2 my $dfv = shift;
411 2         5 $dfv->name_this('num_values_between');
412 2         4 my $param = $dfv->get_current_constraint_field();
413 2         4 my $value = $dfv->get_filtered_data()->{$param};
414              
415 2         3 my $num_values = scalar @$value;
416              
417 2 50 66     11 return ($num_values >= $min) && ($num_values <= $max) if ref $value eq 'ARRAY';
418 0 0 0     0 return 1 if $min == 0 && $max >= 2; # scalar, size could be 1
419 0         0 return 0; # scalar, size can't be 1
420             }
421 2         16 }
422              
423             =head2 email
424              
425             Checks if the email LOOKS LIKE an email address. This should be sufficient
426             99% of the time.
427              
428             Look elsewhere if you want something super fancy that matches every possible variation
429             that is valid in the RFC, or runs out and checks some MX records.
430              
431             =cut
432              
433             # Many of the following validators are taken from
434             # MiniVend 3.14. (http://www.minivend.com)
435             # Copyright 1996-1999 by Michael J. Heins
436              
437             sub match_email {
438 36     36 0 1007 my $in_email = shift;
439              
440 36         6586 require Email::Valid;
441 36         1096362 my $valid_email;
442              
443             # The extra check that the result matches the input prevents
444             # an address like this from being considered valid: Joe Smith
445 36 100 100     179 if ( ($valid_email = Email::Valid->address($in_email) )
446             and ($valid_email eq $in_email)) {
447 10         7471 return $valid_email;
448             }
449             else {
450 26         11260 return undef;
451             }
452             }
453              
454             my $state = <
455             AL AK AZ AR CA CO CT DE FL GA HI ID IL IN IA KS KY LA ME MD
456             MA MI MN MS MO MT NE NV NH NJ NM NY NC ND OH OK OR PA PR RI
457             SC SD TN TX UT VT VA WA WV WI WY DC AP FP FPO APO GU VI
458             EOF
459              
460             my $province = <
461             AB BC MB NB NF NL NS NT NU ON PE QC SK YT YK
462             EOF
463              
464             =head2 state_or_province
465              
466             This one checks if the input correspond to an american state or a canadian
467             province.
468              
469             =cut
470              
471             sub match_state_or_province {
472 4     4 0 607 my $match;
473 4 50       7 if ($match = match_state(@_)) {
474 0         0 return $match;
475             }
476             else {
477 4         7 return match_province(@_);
478             }
479             }
480              
481             =head2 state
482              
483             This one checks if the input is a valid two letter abbreviation of an
484             American state.
485              
486             =cut
487              
488             sub match_state {
489 11     11 0 603 my $val = shift;
490 11 100       180 if ($state =~ /\b($val)\b/i) {
491 2         15 return $1;
492             }
493 9         34 else { return undef; }
494             }
495              
496             =head2 province
497              
498             This checks if the input is a two letter Canadian province
499             abbreviation.
500              
501             =cut
502              
503             sub match_province {
504 10     10 0 627 my $val = shift;
505 10 100       105 if ($province =~ /\b($val)\b/i) {
506 4         29 return $1;
507             }
508 6         33 else { return undef; }
509             }
510              
511             =head2 zip_or_postcode
512              
513             This constraints checks if the input is an American zipcode or a
514             Canadian postal code.
515              
516             =cut
517              
518             sub match_zip_or_postcode {
519 4     4 0 630 my $match;
520 4 100       11 if ($match = match_zip(@_)) {
521 2         15 return $match;
522             }
523             else {
524 2         9 return match_postcode(@_)
525             };
526             }
527             =pod
528              
529             =head2 postcode
530              
531             This constraints checks if the input is a valid Canadian postal code.
532              
533             =cut
534              
535             sub match_postcode {
536 6     6 0 685 my $val = shift;
537             #$val =~ s/[_\W]+//g;
538 6 100       48 if ($val =~ /^([ABCEGHJKLMNPRSTVXYabceghjklmnprstvxy][_\W]*\d[_\W]*[A-Za-z][_\W]*[- ]?[_\W]*\d[_\W]*[A-Za-z][_\W]*\d[_\W]*)$/) {
539 2         14 return $1;
540             }
541 4         25 else { return undef; }
542             }
543              
544             =head2 zip
545              
546             This input validator checks if the input is a valid american zipcode :
547             5 digits followed by an optional mailbox number.
548              
549             =cut
550              
551             sub match_zip {
552 12     12 0 610 my $val = shift;
553 12 100       47 if ($val =~ /^(\s*\d{5}(?:[-]\d{4})?\s*)$/) {
554 6         26 return $1;
555             }
556 6         24 else { return undef; }
557             }
558              
559             =head2 phone
560              
561             This one checks if the input looks like a phone number, (if it
562             contains at least 6 digits.)
563              
564             =cut
565              
566             sub match_phone {
567 6     6 0 611 my $val = shift;
568              
569 6 100       43 if ($val =~ /^((?:\D*\d\D*){6,})$/) {
570 4         22 return $1;
571             }
572 2         14 else { return undef; }
573             }
574              
575             =head2 american_phone
576              
577             This constraints checks if the number is a possible North American style
578             of phone number : (XXX) XXX-XXXX. It has to contains 7 or more digits.
579              
580             =cut
581              
582             sub match_american_phone {
583 5     5 0 852 my $val = shift;
584              
585 5 100       30 if ($val =~ /^((?:\D*\d\D*){7,})$/) {
586 2         14 return $1;
587             }
588 3         43 else { return undef; }
589             }
590              
591              
592             =head2 cc_number
593              
594             This constraint references the value of a credit card type field.
595              
596             constraint_methods => {
597             cc_no => cc_number({fields => ['cc_type']}),
598             }
599              
600              
601             The number is checked only for plausibility, it checks if the number could
602             be valid for a type of card by checking the checksum and looking at the number
603             of digits and the number of digits of the number.
604              
605             This functions is only good at catching typos. IT DOESN'T
606             CHECK IF THERE IS AN ACCOUNT ASSOCIATED WITH THE NUMBER.
607              
608             =cut
609              
610             # This one is taken from the contributed program to
611             # MiniVend by Bruce Albrecht
612              
613             # XXX raise exception on bad/missing params?
614             sub cc_number {
615 1     1 1 367 my $attrs = shift;
616             return undef unless $attrs && ref($attrs) eq 'HASH'
617 1 50 33     13 && exists $attrs->{fields} && ref($attrs->{fields}) eq 'ARRAY';
      33        
      33        
618              
619 1         1 my ($cc_type_field) = @{ $attrs->{fields} };
  1         2  
620 1 50       3 return undef unless $cc_type_field;
621              
622             return sub {
623 12     12   9 my $dfv = shift;
624 12         23 my $data = $dfv->get_filtered_data;
625              
626             return match_cc_number(
627             $dfv->get_current_constraint_value,
628 12         19 $data->{$cc_type_field}
629             );
630 1         7 };
631             }
632              
633             sub match_cc_number {
634 28     28 0 925 my ( $the_card, $card_type ) = @_;
635 28         33 my $orig_card = $the_card; #used for return match at bottom
636 28         18 my ($index, $digit, $product);
637 28         20 my $multiplier = 2; # multiplier is either 1 or 2
638 28         28 my $the_sum = 0;
639              
640 28 50       43 return undef if length($the_card) == 0;
641              
642             # check card type
643 28 50       65 return undef unless $card_type =~ /^[admv]/i;
644              
645 28 100 66     314 return undef if ($card_type =~ /^v/i && substr($the_card, 0, 1) ne "4") ||
      100        
      33        
      100        
      66        
      66        
      66        
      66        
646             ($card_type =~ /^m/i && substr($the_card, 0, 1) ne "5") ||
647             ($card_type =~ /^d/i && substr($the_card, 0, 4) ne "6011") ||
648             ($card_type =~ /^a/i && substr($the_card, 0, 2) ne "34" &&
649             substr($the_card, 0, 2) ne "37");
650              
651             # check for valid number of digits.
652 24         35 $the_card =~ s/\s//g; # strip out spaces
653 24 50       65 return undef if $the_card !~ /^\d+$/;
654              
655 24         28 $digit = substr($the_card, 0, 1);
656 24         24 $index = length($the_card)-1;
657 24 50 66     218 return undef if ($digit == 3 && $index != 14) ||
      66        
      66        
      33        
      66        
      33        
      66        
      66        
      33        
658             ($digit == 4 && $index != 12 && $index != 15) ||
659             ($digit == 5 && $index != 15) ||
660             ($digit == 6 && $index != 13 && $index != 15);
661              
662              
663             # calculate checksum.
664 24         47 for ($index--; $index >= 0; $index --)
665             {
666 354         245 $digit=substr($the_card, $index, 1);
667 354         232 $product = $multiplier * $digit;
668 354 100       309 $the_sum += $product > 9 ? $product - 9 : $product;
669 354         424 $multiplier = 3 - $multiplier;
670             }
671 24         29 $the_sum %= 10;
672 24 100       33 $the_sum = 10 - $the_sum if $the_sum;
673              
674             # return whether checksum matched.
675 24 100       37 if ($the_sum == substr($the_card, -1)) {
676 18 50       49 if ($orig_card =~ /^([\d\s]*)$/) { return $1; }
  18         81  
677 0         0 else { return undef; }
678             }
679             else {
680 6         19 return undef;
681             }
682             }
683              
684             =head2 cc_exp
685              
686             This one checks if the input is in the format MM/YY or MM/YYYY and if
687             the MM part is a valid month (1-12) and if that date is not in the past.
688              
689             =cut
690              
691             sub match_cc_exp {
692 4     4 0 619 my $val = shift;
693 4         5 my ($matched_month, $matched_year);
694              
695 4         11 my ($month, $year) = split('/', $val);
696 4 100       30 return undef if $month !~ /^(\d+)$/;
697 2         5 $matched_month = $1;
698              
699 2 50       9 return undef if $year !~ /^(\d+)$/;
700 2         4 $matched_year = $1;
701              
702 2 50 33     16 return undef if $month <1 || $month > 12;
703 2 50       9 $year += ($year < 70) ? 2000 : 1900 if $year < 1900;
    50          
704 2         44 my @now=localtime();
705 2         5 $now[5] += 1900;
706 2 50 33     14 return undef if ($year < $now[5]) || ($year == $now[5] && $month <= $now[4]);
      33        
707              
708 2         22 return "$matched_month/$matched_year";
709             }
710              
711             =head2 cc_type
712              
713             This one checks if the input field starts by M(asterCard), V(isa),
714             A(merican express) or D(iscovery).
715              
716             =cut
717              
718             sub match_cc_type {
719 4     4 0 604 my $val = shift;
720 4 100       17 if ($val =~ /^([MVAD].*)$/i) { return $1; }
  2         16  
721 2         14 else { return undef; }
722             }
723              
724             =head2 ip_address
725              
726             This checks if the input is formatted like a dotted decimal IP address (v4).
727             For other kinds of IP address method, See L which provides
728             several more options. L explains how we easily integrate
729             with Regexp::Common.
730              
731             =cut
732              
733             # contributed by Juan Jose Natera Abreu
734              
735             sub match_ip_address {
736 6     6 0 617 my $val = shift;
737 6 100       26 if ($val =~ m/^((\d+)\.(\d+)\.(\d+)\.(\d+))$/) {
738 4 100 66     94 if
      33        
      66        
      33        
      33        
      33        
      33        
739             (($2 >= 0 && $2 <= 255) && ($3 >= 0 && $3 <= 255) && ($4 >= 0 && $4 <= 255) && ($5 >= 0 && $5 <= 255)) {
740 3         23 return $1;
741             }
742 1         3 else { return undef; }
743             }
744 2         12 else { return undef; }
745             }
746              
747              
748             1;
749              
750             __END__