File Coverage

blib/lib/Data/Validate/Domain.pm
Criterion Covered Total %
statement 63 64 98.4
branch 44 46 95.6
condition 8 12 66.6
subroutine 10 10 100.0
pod 4 4 100.0
total 129 136 94.8


line stmt bran cond sub pod time code
1             package Data::Validate::Domain;
2              
3 1     1   67748 use strict;
  1         1  
  1         22  
4 1     1   3 use warnings;
  1         1  
  1         31  
5              
6             our $VERSION = '0.13';
7              
8 1     1   623 use Net::Domain::TLD qw(tld_exists);
  1         7331  
  1         105  
9              
10 1     1   8 use Exporter qw( import );
  1         1  
  1         531  
11              
12             ## no critic (Modules::ProhibitAutomaticExportation)
13             our @EXPORT = qw(
14             is_domain
15             is_hostname
16             is_domain_label
17             );
18              
19             sub new {
20 5     5 1 5 my $class = shift;
21              
22 5   33     30 return bless {@_}, ref($class) || $class;
23             }
24              
25             # -------------------------------------------------------------------------------
26              
27             sub is_domain {
28 58     58 1 11739 my ( $value, $opt ) = _maybe_oo(@_);
29              
30 58         83 my ( $hostname, $bits ) = _domain_labels( $value, $opt );
31              
32 58 100       125 return unless $bits;
33              
34 44         46 my $tld = $bits->[-1];
35              
36             # domain_allow_single_label set to true disables this check
37 44 100       67 unless ( $opt->{domain_allow_single_label} ) {
38              
39             # All domains have more then 1 label (neely.cx good, com not good)
40 39 100       24 return if @{$bits} < 2;
  39         81  
41             }
42              
43 35 100       56 return $hostname if $opt->{domain_disable_tld_validation};
44              
45             # If the option to enable domain_private_tld is enabled
46             # and a private domain is specified, then we return if that matches
47 34 100 66     78 if ( exists $opt->{domain_private_tld}
48             && ref( $opt->{domain_private_tld} ) ) {
49 13         15 my $lc_tld = lc($tld);
50 13 100       38 if ( ref( $opt->{domain_private_tld} ) eq 'HASH' ) {
51 8 100       15 if ( exists $opt->{domain_private_tld}->{$lc_tld} ) {
52 6         25 return $hostname;
53             }
54             }
55             else {
56 5 100       22 if ( $tld =~ $opt->{domain_private_tld} ) {
57 3         15 return $hostname;
58             }
59             }
60             }
61              
62             # Verify domain has a valid TLD
63 25 100       48 return unless tld_exists($tld);
64              
65 18         149 return $hostname;
66             }
67              
68             # -------------------------------------------------------------------------------
69              
70             sub is_hostname {
71 11     11 1 2926 my ( $value, $opt ) = _maybe_oo(@_);
72              
73 11         14 my ($hostname) = _domain_labels( $value, $opt );
74              
75             # We do not verify TLD for hostnames, as hostname.subhost is a valid hostname
76              
77 11         39 return $hostname;
78             }
79              
80             sub _domain_labels {
81 69     69   65 my ( $value, $opt ) = @_;
82              
83 69 100       117 return unless defined($value);
84              
85 67         48 my $length = length($value);
86 67 100 66     231 return if $length < 0 || $length > 255;
87              
88 65 100       124 my $trailing_dot = $value =~ s/\.\z// ? q{.} : q{};
89              
90 65         43 my @bits;
91 65         136 foreach my $label ( split /\./, $value, -1 ) {
92 111         123 my $bit = is_domain_label( $label, $opt );
93 111 100       145 return unless defined $bit;
94 99         119 push( @bits, $bit );
95             }
96              
97 53 100       89 return unless @bits;
98              
99 50         129 return ( join( '.', @bits ) . $trailing_dot, \@bits );
100             }
101              
102             sub is_domain_label {
103 123     123 1 4395 my ( $value, $opt ) = _maybe_oo(@_);
104              
105 123 100       173 return unless defined($value);
106              
107             # Fix Bug: 41033
108 122 100       172 return if ( $value =~ /\n/ );
109              
110             # bail if we are dealing with more then just a hostname
111 121 50       141 return if ( $value =~ /\./ );
112 121         88 my $length = length($value);
113 121         65 my $hostname;
114 121 100 100     332 if ( $length == 1 ) {
    100          
115 8 50       14 if ( $opt->{domain_allow_underscore} ) {
116 0         0 ($hostname) = $value =~ /^([0-9A-Za-z\_])$/;
117             }
118             else {
119 8         16 ($hostname) = $value =~ /^([0-9A-Za-z])$/;
120             }
121             }
122             elsif ( $length > 1 && $length <= 63 ) {
123 109 100       133 if ( $opt->{domain_allow_underscore} ) {
124 9         27 ($hostname)
125             = $value =~ /^([0-9A-Za-z\_][0-9A-Za-z\-\_]*[0-9A-Za-z])$/;
126             }
127             else {
128 100         300 ($hostname)
129             = $value =~ /^([0-9A-Za-z][0-9A-Za-z\-]*[0-9A-Za-z])$/;
130             }
131             }
132             else {
133 4         8 return;
134             }
135 117         164 return $hostname;
136             }
137              
138             sub _maybe_oo {
139 192 100   192   239 if ( ref $_[0] ) {
140 15         26 return @_[ 1, 0 ];
141             }
142             else {
143 177 100       334 return ( $_[0], ( defined $_[1] ? $_[1] : {} ) );
144             }
145             }
146              
147             1;
148              
149             # ABSTRACT: Domain and host name validation
150              
151             __END__