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.08 2020/12/31 12:10:06 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 42     42   1281 use 5.008;
  42         169  
35              
36 42     42   233 use strict;
  42         80  
  42         801  
37 42     42   221 use warnings;
  42         101  
  42         1250  
38 42     42   251 use vars qw($VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS);
  42         70  
  42         2556  
39 42     42   241 use base qw(Exporter);
  42         73  
  42         3573  
40 42     42   284 use Paranoid;
  42         103  
  42         2331  
41 42     42   735 use Paranoid::Debug qw(:all);
  42         63  
  42         6923  
42 42     42   329 use Carp;
  42         81  
  42         7300  
43              
44             ($VERSION) = ( q$Revision: 2.08 $ =~ /(\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 42     42   326 use constant NEWLINE_REGEX => qr#(?:\15\12|\15|\12)#so;
  42         85  
  42         86904  
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 50     50 1 3108 my ($ref) = @_;
65 50         95 my $rv = 0;
66 50         93 my $nl = NEWLINE_REGEX;
67 50         91 my $e;
68              
69             # If no args were passed work on $_
70 50 100       152 $ref = \$_ unless @_;
71              
72             # slurp-mode bypass
73 50 100       144 return $rv unless defined $/;
74              
75 49 100 66     507 if ( ref $ref eq 'SCALAR' and defined $$ref ) {
    100          
    50          
76 8 100       74 if ( $/ =~ /^$nl$/so ) {
77 5         10 $e = length $$ref;
78 5         43 $$ref =~ s/$nl$//so;
79 5         11 $rv = $e - length $$ref;
80             } else {
81 3         8 $rv = chomp $$ref;
82             }
83             } elsif ( ref $ref eq 'ARRAY' ) {
84 40 50       944 if ( $/ =~ /^$nl$/so ) {
85 40         143 foreach (@$ref) {
86 1572 50       2991 next unless defined;
87 1572         2233 $e = length $_;
88 1572         5762 $_ =~ s/$nl$//so;
89 1572         3840 $rv += $e - length $_;
90             }
91             } else {
92 0         0 $rv = chomp @$ref;
93             }
94             } elsif ( ref $ref eq 'HASH' ) {
95 1 50       31 if ( $/ =~ /^$nl$/so ) {
96 1         6 foreach ( keys %$ref ) {
97 4 50       12 next unless defined $$ref{$_};
98 4         6 $e = length $$ref{$_};
99 4         31 $$ref{$_} =~ s/$nl$//so;
100 4         10 $rv += $e - length $$ref{$_};
101             }
102             } else {
103 0         0 $rv = chomp %$ref;
104             }
105             }
106              
107 49         167 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 385     385 1 25003 my $iref = shift;
153 385         754 my $type = shift;
154 385         538 my $oref = shift;
155 385         782 my $po = defined $oref;
156 385         529 my $rv = 0;
157 385         585 my ( $regex, $tmp );
158              
159 385         1185 pdebug( 'entering w/(%s)(%s)(%s)', PDLEVEL1, $iref, $type, $oref );
160 385         1041 pIn();
161              
162             # Make sure input and output data types match
163 385 50 66     1581 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 385 100       828 if ( ref $type eq 'Regexp' ) {
169 1         3 $regex = $type;
170 1         2 $type = 'custom';
171             } else {
172 384 100 66     1880 if ( defined $type and exists $regexes{$type} ) {
173 383         971 $regex = $regexes{$type};
174             } else {
175 1         5 pdebug( 'unknown regex type requested: %s', PDLEVEL1, $type );
176             }
177             }
178              
179             # Create a reference structure under $oref if none was passed
180 385 100       1087 unless ( defined $oref ) {
181 228 100       884 $oref =
    100          
182             ref $iref eq 'ARRAY' ? []
183             : ref $iref eq 'HASH' ? {}
184             : \$tmp;
185             }
186              
187             # Make sure $oref is empty
188 385 100       1005 if ( ref $oref eq 'SCALAR' ) {
    100          
189 377         643 $$oref = undef;
190             } elsif ( ref $oref eq 'ARRAY' ) {
191 4         8 @$oref = ();
192             } else {
193 4         7 %$oref = ();
194             }
195              
196             # Start working
197 385 100       853 if ( defined $regex ) {
198 384 100       783 if ( ref $iref eq 'SCALAR' ) {
    100          
199 376         1023 pdebug( 'evaluating (%s)', PDLEVEL2, $$iref );
200 376 100       15385 ($$oref) = ( $$iref =~ /^($regex)$/s )
201             if defined $$iref;
202 376         1582 $rv = defined $$oref;
203             } elsif ( ref $iref eq 'ARRAY' ) {
204 4 50       12 if ( scalar @$iref ) {
205 4         7 $rv = 1;
206 4         11 foreach (@$iref) {
207 11         26 pdebug( 'evaluating (%s)', PDLEVEL2, $_ );
208 11 50       95 ( $$oref[ $#{$oref} + 1 ] ) =
  11         27  
209             defined $_ ? m/^($regex)$/s : (undef);
210 11 100       32 $rv = 0 unless defined $$oref[-1];
211 11         23 pdebug( 'got (%s)', PDLEVEL2, $$oref[-1] );
212             }
213             }
214 4         10 $rv = !scalar grep { !defined } @$oref;
  11         23  
215             } else {
216 4 50       12 if ( scalar keys %$iref ) {
217 4         7 $rv = 1;
218 4         13 foreach ( keys %$iref ) {
219 11         28 pdebug( 'evaluating (%s)', PDLEVEL2, $$iref{$_} );
220             ( $$oref{$_} ) =
221             defined $$iref{$_}
222 11 50       109 ? ( $$iref{$_} =~ m/^($regex)$/s )
223             : undef;
224 11 100       38 $rv = 0 unless defined $$oref{$_};
225             }
226             }
227             }
228             }
229              
230             # Copy everything back to $iref if needed
231 385 100       923 unless ($po) {
232 228 100       604 if ( ref $iref eq 'SCALAR' ) {
    100          
233 224         460 $$iref = $$oref;
234             } elsif ( ref $iref eq 'ARRAY' ) {
235 2         7 @$iref = @$oref;
236             } else {
237 2         10 %$iref = %$oref;
238             }
239             }
240              
241 385         1246 pOut();
242 385         1000 pdebug( 'leaving w/rv: %s', PDLEVEL1, $rv );
243              
244 385         1758 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         7 my @match = splice @_;
257 2         4 my $rv = 0;
258 2         3 my @regex;
259              
260 2         8 pdebug( 'entering w/(%s)(%s)', PDLEVEL1, $input, @match );
261 2         6 pIn();
262              
263 2 50 33     10 if ( defined $input and @match ) {
264              
265             # Populate @regex w/regexes
266 2 50       4 @regex = grep { defined $_ && ref $_ eq 'Regexp' } @match;
  6         22  
267              
268             # Convert remaining strings to regexes
269 2 50       5 foreach ( grep { defined $_ && ref $_ ne 'Regexp' } @match ) {
  6         23  
270 6 100       65 push @regex, m#^/(.+)/$#s ? qr#$1#si : qr#\Q$_\E#si;
271             }
272              
273             # Start comparisons
274 2         5 study $input;
275 2         4 foreach my $r (@regex) {
276 3 100       16 if ( $input =~ /$r/si ) {
277 1         2 $rv = 1;
278 1         4 last;
279             }
280             }
281             }
282              
283 2         7 pOut();
284 2         7 pdebug( 'leaving w/rv: %s', PDLEVEL1, $rv );
285              
286 2         13 return $rv;
287             }
288              
289             1;
290              
291             __END__