File Coverage

blib/lib/Paranoid/Input.pm
Criterion Covered Total %
statement 117 119 98.3
branch 59 72 81.9
condition 7 12 58.3
subroutine 12 12 100.0
pod 3 3 100.0
total 198 218 90.8


line stmt bran cond sub pod time code
1             # Paranoid::Input -- Paranoid Input functions
2             #
3             # $Id: lib/Paranoid/Input.pm, 2.10 2022/03/08 00:01:04 acorliss Exp $
4             #
5             # This software is free software. Similar to Perl, you can redistribute it
6             # and/or modify it under the terms of either:
7             #
8             # a) the GNU General Public License
9             # as published by the
10             # Free Software Foundation ; either version 1
11             # , or any later version
12             # , or
13             # b) the Artistic License 2.0
14             # ,
15             #
16             # subject to the following additional term: No trademark rights to
17             # "Paranoid" have been or are conveyed under any of the above licenses.
18             # However, "Paranoid" may be used fairly to describe this unmodified
19             # software, in good faith, but not as a trademark.
20             #
21             # (c) 2005 - 2020, Arthur Corliss (corliss@digitalmages.com)
22             # (tm) 2008 - 2020, Paranoid Inc. (www.paranoid.com)
23             #
24             #####################################################################
25              
26             #####################################################################
27             #
28             # Environment definitions
29             #
30             #####################################################################
31              
32             package Paranoid::Input;
33              
34 64     64   1420 use 5.008;
  64         193  
35              
36 64     64   629 use strict;
  64         148  
  64         1149  
37 64     64   257 use warnings;
  64         111  
  64         2052  
38 64     64   371 use vars qw($VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS);
  64         136  
  64         3680  
39 64     64   389 use base qw(Exporter);
  64         155  
  64         3981  
40 64     64   323 use Paranoid;
  64         351  
  64         2984  
41 64     64   745 use Paranoid::Debug qw(:all);
  64         115  
  64         8984  
42 64     64   412 use Carp;
  64         235  
  64         9787  
43              
44             ($VERSION) = ( q$Revision: 2.10 $ =~ /(\d+(?:\.\d+)+)/sm );
45              
46             @EXPORT = qw(detaint stringMatch pchomp);
47             @EXPORT_OK = ( @EXPORT, qw(NEWLINE_REGEX) );
48             %EXPORT_TAGS = ( all => [@EXPORT_OK], );
49              
50 64     64   393 use constant NEWLINE_REGEX => qr#(?:\15\12|\15|\12)#so;
  64         162  
  64         108905  
51              
52             #####################################################################
53             #
54             # Module code follows
55             #
56             #####################################################################
57              
58             sub pchomp (;\[$@%]) {
59              
60             # Purpose: Platform neutral chomping
61             # Returns: same as chomp
62             # Usage: $n = pchomp($string);
63              
64 53     53 1 2620 my ($ref) = @_;
65 53         98 my $rv = 0;
66 53         80 my $nl = NEWLINE_REGEX;
67 53         58 my $e;
68              
69             # If no args were passed work on $_
70 53 100       151 $ref = \$_ unless @_;
71              
72             # slurp-mode bypass
73 53 100       160 return $rv unless defined $/;
74              
75 52 100 66     324 if ( ref $ref eq 'SCALAR' and defined $$ref ) {
    100          
    50          
76 8 100       51 if ( $/ =~ /^$nl$/so ) {
77 5         9 $e = length $$ref;
78 5         47 $$ref =~ s/$nl$//so;
79 5         11 $rv = $e - length $$ref;
80             } else {
81 3         5 $rv = chomp $$ref;
82             }
83             } elsif ( ref $ref eq 'ARRAY' ) {
84 43 50       809 if ( $/ =~ /^$nl$/so ) {
85 43         191 foreach (@$ref) {
86 1898 50       2867 next unless defined;
87 1898         2334 $e = length $_;
88 1898         5774 $_ =~ s/$nl$//so;
89 1898         3712 $rv += $e - length $_;
90             }
91             } else {
92 0         0 $rv = chomp @$ref;
93             }
94             } elsif ( ref $ref eq 'HASH' ) {
95 1 50       26 if ( $/ =~ /^$nl$/so ) {
96 1         5 foreach ( keys %$ref ) {
97 4 50       7 next unless defined $$ref{$_};
98 4         6 $e = length $$ref{$_};
99 4         26 $$ref{$_} =~ s/$nl$//so;
100 4         9 $rv += $e - length $$ref{$_};
101             }
102             } else {
103 0         0 $rv = chomp %$ref;
104             }
105             }
106              
107 52         160 return $rv;
108             }
109              
110             our %regexes = (
111             alphabetic => qr/[a-z]+/si,
112             alphanumeric => qr/[a-z0-9]+/si,
113             alphawhite => qr/[a-z\s]+/si,
114             alnumwhite => qr/[a-z0-9\s]+/si,
115             email => qr/[a-z][\w\.\-]*\@(?:[a-z0-9][a-z0-9\-]*\.)*[a-z0-9]+/si,
116             filename => qr#[/ \w\-\.:,@\+]+\[?#s,
117             fileglob => qr#[/ \w\-\.:,@\+\*\?\{\}\[\]]+\[?#s,
118             hostname => qr#(?:[a-z0-9][a-z0-9\-]*)(?:\.[a-z0-9][a-z0-9\-]*)*\.?#s,
119             ipv4addr =>
120             qr/(?:(?:\d\d?|1\d\d|2[0-4][0-9]|25[0-5])\.){3}(?:\d\d?|1\d\d|2[0-4][0-9]|25[0-5])/s,
121             ipv4netaddr =>
122             qr#(?:(?:\d\d?|1\d\d|2[0-4][0-9]|25[0-5])\.){3}(?:\d\d?|1\d\d|2[0-4][0-9]|25[0-5])/(?:(?:\d|[12]\d|3[0-2])|(?:(?:\d\d?|1\d\d|2[0-4][0-9]|25[0-5])\.){3}(?:\d\d?|1\d\d|2[0-4][0-9]|25[0-5]))#s,
123             ipv6addr => qr/
124             :(?::[abcdef\d]{1,4}){1,7} |
125             [abcdef\d]{1,4}(?:::?[abcdef\d]{1,4}){1,7} |
126             (?:[abcdef\d]{1,4}:){1,7}:
127             /six,
128             ipv6netaddr => qr#(?::(?::[abcdef\d]{1,4}){1,7}|
129             [abcdef\d]{1,4}(?:::?[abcdef\d]{1,4}){1,7} |
130             (?:[abcdef\d]{1,4}:){1,7}:)/(?:\d\d?|1(?:[01]\d|2[0-8]))#six,
131             login => qr/[a-z][\w\.\-]*/si,
132             nometa => qr/[^\%\`\$\!\@]+/s,
133             number => qr/[+\-]?[0-9]+(?:\.[0-9]+)?/s,
134             'int' => qr/[-+]?\d+/s,
135             uint => qr/\d+/s,
136             float => qr/[-+]?\d+(?:\.\d+)/s,
137             ufloat => qr/\d+(?:\.\d+)/s,
138             bin => qr/[01]+/s,
139             octal => qr/[0-7]+/s,
140             'hex' => qr/[a-z0-9]+/si,
141             );
142              
143             sub detaint (\[$@%]$;\[$@%]) {
144              
145             # Purpose: Detaints and validates input in one call
146             # Returns: True (1) if detainting was successful,
147             # False (0) if there are any errors
148             # Usage: $rv = detaint($input, $dataType, $detainted);
149             # Usage: $rv = detaint(@input, $dataType, @detainted);
150             # Usage: $rv = detaint(%input, $dataType, %detainted);
151              
152 942     942 1 20634 my $iref = shift;
153 942         1402 my $type = shift;
154 942         1162 my $oref = shift;
155 942         1383 my $po = defined $oref;
156 942         1091 my $rv = 0;
157 942         1314 my ( $regex, $tmp );
158              
159 942         2419 subPreamble( PDLEVEL1, '\[$@%]$;\[$@%]', $iref, $type, $oref );
160              
161             # Make sure input and output data types match
162 942 50 66     2982 croak "$iref and $oref aren't compatible data types"
163             unless !defined $oref
164             or ref $iref eq ref $oref;
165              
166             # Warn on unknown regexes
167 942 100       1876 if ( ref $type eq 'Regexp' ) {
168 1         2 $regex = $type;
169 1         2 $type = 'custom';
170             } else {
171 941 100 66     3723 if ( defined $type and exists $regexes{$type} ) {
172 940         1930 $regex = $regexes{$type};
173             } else {
174 1         10 pdebug( 'unknown regex type requested: %s', PDLEVEL1, $type );
175             }
176             }
177              
178             # Create a reference structure under $oref if none was passed
179 942 100       1898 unless ( defined $oref ) {
180 586 100       1798 $oref =
    100          
181             ref $iref eq 'ARRAY' ? []
182             : ref $iref eq 'HASH' ? {}
183             : \$tmp;
184             }
185              
186             # Make sure $oref is empty
187 942 100       1784 if ( ref $oref eq 'SCALAR' ) {
    100          
188 934         1335 $$oref = undef;
189             } elsif ( ref $oref eq 'ARRAY' ) {
190 4         6 @$oref = ();
191             } else {
192 4         8 %$oref = ();
193             }
194              
195             # Start working
196 942 100       1769 if ( defined $regex ) {
197 941 100       1592 if ( ref $iref eq 'SCALAR' ) {
    100          
198 933         2308 pdebug( 'evaluating (%s)', PDLEVEL2, $$iref );
199 933 100       37649 ($$oref) = ( $$iref =~ /^($regex)$/s )
200             if defined $$iref;
201 933         3263 $rv = defined $$oref;
202             } elsif ( ref $iref eq 'ARRAY' ) {
203 4 50       8 if ( scalar @$iref ) {
204 4         5 $rv = 1;
205 4         7 foreach (@$iref) {
206 11         26 pdebug( 'evaluating (%s)', PDLEVEL2, $_ );
207 11 50       73 ( $$oref[ $#{$oref} + 1 ] ) =
  11         24  
208             defined $_ ? m/^($regex)$/s : (undef);
209 11 100       25 $rv = 0 unless defined $$oref[-1];
210 11         19 pdebug( 'got (%s)', PDLEVEL2, $$oref[-1] );
211             }
212             }
213 4         9 $rv = !scalar grep { !defined } @$oref;
  11         18  
214             } else {
215 4 50       10 if ( scalar keys %$iref ) {
216 4         6 $rv = 1;
217 4         9 foreach ( keys %$iref ) {
218 11         27 pdebug( 'evaluating (%s)', PDLEVEL2, $$iref{$_} );
219             ( $$oref{$_} ) =
220             defined $$iref{$_}
221 11 50       82 ? ( $$iref{$_} =~ m/^($regex)$/s )
222             : undef;
223 11 100       29 $rv = 0 unless defined $$oref{$_};
224             }
225             }
226             }
227             }
228              
229             # Copy everything back to $iref if needed
230 942 100       1937 unless ($po) {
231 586 100       1471 if ( ref $iref eq 'SCALAR' ) {
    100          
232 582         1086 $$iref = $$oref;
233             } elsif ( ref $iref eq 'ARRAY' ) {
234 2         6 @$iref = @$oref;
235             } else {
236 2         9 %$iref = %$oref;
237             }
238             }
239              
240 942         2689 subPostamble( PDLEVEL1, '$', $rv );
241              
242 942         3107 return $rv;
243             }
244              
245             sub stringMatch ($@) {
246              
247             # Purpose: Looks for occurrences of strings and/or regexes in the passed
248             # input
249             # Returns: True (1) any of the strings/regexes match,
250             # False (0), otherwise
251             # Usage: $rv = stringMatch($input, @words);
252              
253 2     2 1 4 my $input = shift;
254 2         5 my @match = splice @_;
255 2         4 my $rv = 0;
256 2         2 my @regex;
257              
258 2         8 subPreamble( PDLEVEL1, '$@', $input, @match );
259              
260 2 50 33     10 if ( defined $input and @match ) {
261              
262             # Populate @regex w/regexes
263 2 50       5 @regex = grep { defined $_ && ref $_ eq 'Regexp' } @match;
  6         18  
264              
265             # Convert remaining strings to regexes
266 2 50       5 foreach ( grep { defined $_ && ref $_ ne 'Regexp' } @match ) {
  6         17  
267 6 100       58 push @regex, m#^/(.+)/$#s ? qr#$1#si : qr#\Q$_\E#si;
268             }
269              
270             # Start comparisons
271 2         4 study $input;
272 2         3 foreach my $r (@regex) {
273 3 100       15 if ( $input =~ /$r/si ) {
274 1         2 $rv = 1;
275 1         3 last;
276             }
277             }
278             }
279              
280 2         7 subPostamble( PDLEVEL1, '$', $rv );
281              
282 2         10 return $rv;
283             }
284              
285             1;
286              
287             __END__