File Coverage

blib/lib/Paranoid/Input.pm
Criterion Covered Total %
statement 121 123 98.3
branch 59 72 81.9
condition 7 12 58.3
subroutine 12 12 100.0
pod 3 3 100.0
total 202 222 90.9


line stmt bran cond sub pod time code
1             # Paranoid::Input -- Paranoid Input functions
2             #
3             # $Id: lib/Paranoid/Input.pm, 2.09 2021/12/28 15:46:49 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 63     63   1819 use 5.008;
  63         321  
35              
36 63     63   334 use strict;
  63         130  
  63         1289  
37 63     63   292 use warnings;
  63         124  
  63         2084  
38 63     63   338 use vars qw($VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS);
  63         93  
  63         4372  
39 63     63   419 use base qw(Exporter);
  63         158  
  63         5612  
40 63     63   446 use Paranoid;
  63         136  
  63         3929  
41 63     63   949 use Paranoid::Debug qw(:all);
  63         187  
  63         11106  
42 63     63   477 use Carp;
  63         135  
  63         11955  
43              
44             ($VERSION) = ( q$Revision: 2.09 $ =~ /(\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 63     63   622 use constant NEWLINE_REGEX => qr#(?:\15\12|\15|\12)#so;
  63         147  
  63         133134  
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 4040 my ($ref) = @_;
65 53         136 my $rv = 0;
66 53         99 my $nl = NEWLINE_REGEX;
67 53         99 my $e;
68              
69             # If no args were passed work on $_
70 53 100       280 $ref = \$_ unless @_;
71              
72             # slurp-mode bypass
73 53 100       391 return $rv unless defined $/;
74              
75 52 100 66     464 if ( ref $ref eq 'SCALAR' and defined $$ref ) {
    100          
    50          
76 8 100       73 if ( $/ =~ /^$nl$/so ) {
77 5         11 $e = length $$ref;
78 5         41 $$ref =~ s/$nl$//so;
79 5         13 $rv = $e - length $$ref;
80             } else {
81 3         10 $rv = chomp $$ref;
82             }
83             } elsif ( ref $ref eq 'ARRAY' ) {
84 43 50       865 if ( $/ =~ /^$nl$/so ) {
85 43         230 foreach (@$ref) {
86 1898 50       3538 next unless defined;
87 1898         2966 $e = length $_;
88 1898         6962 $_ =~ s/$nl$//so;
89 1898         4760 $rv += $e - length $_;
90             }
91             } else {
92 0         0 $rv = chomp @$ref;
93             }
94             } elsif ( ref $ref eq 'HASH' ) {
95 1 50       32 if ( $/ =~ /^$nl$/so ) {
96 1         5 foreach ( keys %$ref ) {
97 4 50       9 next unless defined $$ref{$_};
98 4         7 $e = length $$ref{$_};
99 4         34 $$ref{$_} =~ s/$nl$//so;
100 4         10 $rv += $e - length $$ref{$_};
101             }
102             } else {
103 0         0 $rv = chomp %$ref;
104             }
105             }
106              
107 52         183 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 936     936 1 31322 my $iref = shift;
153 936         1923 my $type = shift;
154 936         1456 my $oref = shift;
155 936         1693 my $po = defined $oref;
156 936         1385 my $rv = 0;
157 936         1643 my ( $regex, $tmp );
158              
159 936         2786 pdebug( 'entering w/(%s)(%s)(%s)', PDLEVEL1, $iref, $type, $oref );
160 936         2553 pIn();
161              
162             # Make sure input and output data types match
163 936 50 66     3814 croak "$iref and $oref aren't compatible data types"
164             unless !defined $oref
165             or ref $iref eq ref $oref;
166              
167             # Warn on unknown regexes
168 936 100       2012 if ( ref $type eq 'Regexp' ) {
169 1         3 $regex = $type;
170 1         2 $type = 'custom';
171             } else {
172 935 100 66     4331 if ( defined $type and exists $regexes{$type} ) {
173 934         2164 $regex = $regexes{$type};
174             } else {
175 1         3 pdebug( 'unknown regex type requested: %s', PDLEVEL1, $type );
176             }
177             }
178              
179             # Create a reference structure under $oref if none was passed
180 936 100       2106 unless ( defined $oref ) {
181 582 100       2138 $oref =
    100          
182             ref $iref eq 'ARRAY' ? []
183             : ref $iref eq 'HASH' ? {}
184             : \$tmp;
185             }
186              
187             # Make sure $oref is empty
188 936 100       2050 if ( ref $oref eq 'SCALAR' ) {
    100          
189 928         1835 $$oref = undef;
190             } elsif ( ref $oref eq 'ARRAY' ) {
191 4         9 @$oref = ();
192             } else {
193 4         8 %$oref = ();
194             }
195              
196             # Start working
197 936 100       2231 if ( defined $regex ) {
198 935 100       2019 if ( ref $iref eq 'SCALAR' ) {
    100          
199 927         2362 pdebug( 'evaluating (%s)', PDLEVEL2, $$iref );
200 927 100       42116 ($$oref) = ( $$iref =~ /^($regex)$/s )
201             if defined $$iref;
202 927         3975 $rv = defined $$oref;
203             } elsif ( ref $iref eq 'ARRAY' ) {
204 4 50       11 if ( scalar @$iref ) {
205 4         5 $rv = 1;
206 4         9 foreach (@$iref) {
207 11         26 pdebug( 'evaluating (%s)', PDLEVEL2, $_ );
208 11 50       89 ( $$oref[ $#{$oref} + 1 ] ) =
  11         27  
209             defined $_ ? m/^($regex)$/s : (undef);
210 11 100       27 $rv = 0 unless defined $$oref[-1];
211 11         23 pdebug( 'got (%s)', PDLEVEL2, $$oref[-1] );
212             }
213             }
214 4         9 $rv = !scalar grep { !defined } @$oref;
  11         27  
215             } else {
216 4 50       11 if ( scalar keys %$iref ) {
217 4         8 $rv = 1;
218 4         11 foreach ( keys %$iref ) {
219 11         32 pdebug( 'evaluating (%s)', PDLEVEL2, $$iref{$_} );
220             ( $$oref{$_} ) =
221             defined $$iref{$_}
222 11 50       102 ? ( $$iref{$_} =~ m/^($regex)$/s )
223             : undef;
224 11 100       39 $rv = 0 unless defined $$oref{$_};
225             }
226             }
227             }
228             }
229              
230             # Copy everything back to $iref if needed
231 936 100       2583 unless ($po) {
232 582 100       1866 if ( ref $iref eq 'SCALAR' ) {
    100          
233 578         1297 $$iref = $$oref;
234             } elsif ( ref $iref eq 'ARRAY' ) {
235 2         7 @$iref = @$oref;
236             } else {
237 2         10 %$iref = %$oref;
238             }
239             }
240              
241 936         2845 pOut();
242 936         2345 pdebug( 'leaving w/rv: %s', PDLEVEL1, $rv );
243              
244 936         4188 return $rv;
245             }
246              
247             sub stringMatch ($@) {
248              
249             # Purpose: Looks for occurrences of strings and/or regexes in the passed
250             # input
251             # Returns: True (1) any of the strings/regexes match,
252             # False (0), otherwise
253             # Usage: $rv = stringMatch($input, @words);
254              
255 2     2 1 5 my $input = shift;
256 2         6 my @match = splice @_;
257 2         4 my $rv = 0;
258 2         4 my @regex;
259              
260 2         6 pdebug( 'entering w/(%s)(%s)', PDLEVEL1, $input, @match );
261 2         20 pIn();
262              
263 2 50 33     13 if ( defined $input and @match ) {
264              
265             # Populate @regex w/regexes
266 2 50       5 @regex = grep { defined $_ && ref $_ eq 'Regexp' } @match;
  6         23  
267              
268             # Convert remaining strings to regexes
269 2 50       5 foreach ( grep { defined $_ && ref $_ ne 'Regexp' } @match ) {
  6         24  
270 6 100       66 push @regex, m#^/(.+)/$#s ? qr#$1#si : qr#\Q$_\E#si;
271             }
272              
273             # Start comparisons
274 2         17 study $input;
275 2         5 foreach my $r (@regex) {
276 3 100       18 if ( $input =~ /$r/si ) {
277 1         3 $rv = 1;
278 1         3 last;
279             }
280             }
281             }
282              
283 2         7 pOut();
284 2         6 pdebug( 'leaving w/rv: %s', PDLEVEL1, $rv );
285              
286 2         13 return $rv;
287             }
288              
289             1;
290              
291             __END__