line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package TUWF::Misc; |
3
|
|
|
|
|
|
|
# Yeah, just put all miscellaneous functions in one module! |
4
|
|
|
|
|
|
|
# Geez, talk about being sloppy... |
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
58722
|
use strict; |
|
1
|
|
|
|
|
9
|
|
|
1
|
|
|
|
|
24
|
|
7
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
23
|
|
8
|
1
|
|
|
1
|
|
4
|
use Carp 'croak'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
38
|
|
9
|
1
|
|
|
1
|
|
4
|
use Exporter 'import'; |
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
32
|
|
10
|
1
|
|
|
1
|
|
523
|
use Encode 'encode_utf8'; |
|
1
|
|
|
|
|
8437
|
|
|
1
|
|
|
|
|
55
|
|
11
|
1
|
|
|
1
|
|
7
|
use Scalar::Util 'looks_like_number'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
36
|
|
12
|
1
|
|
|
1
|
|
339
|
use TUWF::Validate; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1646
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '1.4'; |
16
|
|
|
|
|
|
|
our @EXPORT_OK = ('uri_escape', 'kv_validate'); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub uri_escape { |
20
|
0
|
|
|
0
|
1
|
0
|
local $_ = encode_utf8 shift; |
21
|
0
|
|
|
|
|
0
|
s/([^A-Za-z0-9._~-])/sprintf '%%%02X', ord $1/eg; |
|
0
|
|
|
|
|
0
|
|
22
|
0
|
|
|
|
|
0
|
return $_; |
23
|
|
|
|
|
|
|
} |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub _template_validate_num { |
29
|
13
|
|
|
13
|
|
28
|
$_[0] *= 1; # Normalize to perl number |
30
|
13
|
100
|
100
|
|
|
62
|
return 0 if defined($_[1]{min}) && $_[0] < $_[1]{min}; |
31
|
9
|
100
|
100
|
|
|
38
|
return 0 if defined($_[1]{max}) && $_[0] > $_[1]{max}; |
32
|
6
|
|
|
|
|
14
|
return 1; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my %default_templates = ( |
37
|
|
|
|
|
|
|
# JSON number format, regex from http://stackoverflow.com/questions/13340717/json-numbers-regular-expression |
38
|
|
|
|
|
|
|
num => { func => \&_template_validate_num, regex => qr/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/, inherit => ['min','max'] }, |
39
|
|
|
|
|
|
|
int => { func => \&_template_validate_num, regex => qr/^-?(?:0|[1-9]\d*)$/, inherit => ['min','max'] }, |
40
|
|
|
|
|
|
|
uint => { func => \&_template_validate_num, regex => qr/^(?:0|[1-9]\d*)$/, inherit => ['min','max'] }, |
41
|
|
|
|
|
|
|
ascii => { regex => qr/^[\x20-\x7E]*$/ }, |
42
|
|
|
|
|
|
|
email => { regex => $TUWF::Validate::re_email, maxlength => 254 }, |
43
|
|
|
|
|
|
|
weburl => { regex => $TUWF::Validate::re_weburl, maxlength => 65536 }, # the maxlength is a bit arbitrary, but better than unlimited |
44
|
|
|
|
|
|
|
); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub kv_validate { |
48
|
92
|
|
|
92
|
1
|
55520
|
my($sources, $templates, $params) = @_; |
49
|
92
|
|
|
|
|
537
|
$templates = { %default_templates, %$templates }; |
50
|
|
|
|
|
|
|
|
51
|
92
|
|
|
|
|
168
|
my @err; |
52
|
|
|
|
|
|
|
my %ret; |
53
|
|
|
|
|
|
|
|
54
|
92
|
|
|
|
|
148
|
for my $f (@$params) { |
55
|
|
|
|
|
|
|
# Inherit some options from templates. |
56
|
|
|
|
|
|
|
!exists($f->{$_}) && _val_from_tpl($f, $_, $templates, $f) |
57
|
92
|
|
100
|
|
|
279
|
for(qw|required default rmwhitespace multi mincount maxcount|); |
58
|
|
|
|
|
|
|
|
59
|
92
|
|
|
|
|
321
|
my $src = (grep $f->{$_}, keys %$sources)[0]; |
60
|
92
|
|
|
|
|
210
|
my @values = $sources->{$src}->($f->{$src}); |
61
|
92
|
100
|
|
|
|
859
|
@values = ($values[0]) if !$f->{multi}; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# check each value and add it to %ret |
64
|
92
|
|
|
|
|
124
|
for (@values) { |
65
|
97
|
|
100
|
|
|
137
|
my $errfield = _validate_early($_, $f) || _validate($_, $templates, $f); |
66
|
97
|
100
|
100
|
|
|
278
|
next if !$errfield || $errfield eq 'default'; |
67
|
45
|
|
|
|
|
106
|
push @err, [ $f->{$src}, $errfield, $f->{$errfield} ]; |
68
|
45
|
|
|
|
|
64
|
last; |
69
|
|
|
|
|
|
|
} |
70
|
92
|
100
|
|
|
|
206
|
$ret{$f->{$src}} = $f->{multi} ? \@values : $values[0]; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# check mincount/maxcount |
73
|
92
|
100
|
100
|
|
|
175
|
push @err, [ $f->{$src}, 'mincount', $f->{mincount} ] if $f->{mincount} && @values < $f->{mincount}; |
74
|
92
|
100
|
100
|
|
|
200
|
push @err, [ $f->{$src}, 'maxcount', $f->{maxcount} ] if $f->{maxcount} && @values > $f->{maxcount}; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
92
|
100
|
|
|
|
160
|
$ret{_err} = \@err if @err; |
78
|
92
|
|
|
|
|
336
|
return \%ret; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub _val_from_tpl { |
83
|
896
|
|
|
896
|
|
1024
|
my($top_rules, $field, $tpls, $rules) = @_; |
84
|
896
|
100
|
|
|
|
1539
|
return if !$rules->{template}; |
85
|
379
|
|
|
|
|
414
|
my $tpl = $tpls->{$rules->{template}}; |
86
|
379
|
100
|
|
|
|
510
|
if(exists $tpl->{$field}) { |
87
|
17
|
|
|
|
|
37
|
$top_rules->{$field} = $tpl->{$field}; |
88
|
|
|
|
|
|
|
} else { |
89
|
362
|
|
|
|
|
438
|
_val_from_tpl($top_rules, $field, $tpls, $tpl); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# Initial validation of a value. Same as _validate() below, but this one |
95
|
|
|
|
|
|
|
# validates options that need to be checked only once. (The checks in |
96
|
|
|
|
|
|
|
# _validate() may run several times when templates are used). |
97
|
|
|
|
|
|
|
sub _validate_early { # value, \%rules |
98
|
97
|
|
|
97
|
|
145
|
my($v, $r) = @_; |
99
|
|
|
|
|
|
|
|
100
|
97
|
100
|
|
|
|
188
|
$r->{required}++ if not exists $r->{required}; |
101
|
97
|
100
|
|
|
|
153
|
$r->{rmwhitespace}++ if not exists $r->{rmwhitespace}; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# remove whitespace |
104
|
97
|
100
|
100
|
|
|
276
|
if($v && $r->{rmwhitespace}) { |
105
|
75
|
|
|
|
|
152
|
$_[0] =~ s/\r//g; |
106
|
75
|
|
|
|
|
207
|
$_[0] =~ s/^[\s\n]+//; |
107
|
75
|
|
|
|
|
126
|
$_[0] =~ s/[\s\n]+$//; |
108
|
75
|
|
|
|
|
93
|
$v = $_[0] |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# empty |
112
|
97
|
100
|
100
|
|
|
283
|
if(!defined($v) || length($v) < 1) { |
113
|
9
|
100
|
|
|
|
25
|
return 'required' if $r->{required}; |
114
|
3
|
100
|
|
|
|
7
|
$_[0] = $r->{default} if exists $r->{default}; |
115
|
3
|
|
|
|
|
7
|
return 'default'; |
116
|
|
|
|
|
|
|
} |
117
|
88
|
|
|
|
|
191
|
return undef; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# Internal function used by kv_validate, checks one value on the validation |
122
|
|
|
|
|
|
|
# rules, the name of the failed rule on error, undef otherwise |
123
|
|
|
|
|
|
|
sub _validate { # value, \%templates, \%rules |
124
|
155
|
|
|
155
|
|
211
|
my($v, $t, $r) = @_; |
125
|
|
|
|
|
|
|
|
126
|
155
|
50
|
66
|
|
|
341
|
croak "Template $r->{template} not defined." if $r->{template} && !$t->{$r->{template}}; |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# length |
129
|
155
|
100
|
100
|
|
|
249
|
return 'minlength' if $r->{minlength} && length $v < $r->{minlength}; |
130
|
153
|
100
|
100
|
|
|
272
|
return 'maxlength' if $r->{maxlength} && length $v > $r->{maxlength}; |
131
|
|
|
|
|
|
|
# enum |
132
|
150
|
100
|
100
|
|
|
223
|
return 'enum' if $r->{enum} && !grep $_ eq $v, @{$r->{enum}}; |
|
3
|
|
|
|
|
23
|
|
133
|
|
|
|
|
|
|
# regex |
134
|
149
|
100
|
100
|
|
|
661
|
return 'regex' if $r->{regex} && (ref($r->{regex}) eq 'ARRAY' ? ($v !~ m/$r->{regex}[0]/) : ($v !~ m/$r->{regex}/)); |
|
|
100
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# template |
136
|
126
|
100
|
|
|
|
186
|
if($r->{template}) { |
137
|
67
|
|
|
|
|
99
|
my $in = $t->{$r->{template}}{inherit}; |
138
|
67
|
100
|
|
|
|
124
|
my %r = (($in ? (map exists($r->{$_}) ? ($_,$r->{$_}) : (), @$in) : ()), %{$t->{$r->{template}}}); |
|
67
|
100
|
|
|
|
213
|
|
139
|
67
|
100
|
|
|
|
145
|
return 'template' if _validate($_[0], $t, \%r); |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
# function |
142
|
96
|
100
|
100
|
|
|
187
|
return 'func' if $r->{func} && (ref($r->{func}) eq 'ARRAY' ? !$r->{func}[0]->($_[0], $r) : !$r->{func}->($_[0], $r)); |
|
|
100
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# passed validation |
144
|
86
|
|
|
|
|
228
|
return undef; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub TUWF::Object::formValidate { |
151
|
0
|
|
|
0
|
|
|
my($self, @fields) = @_; |
152
|
|
|
|
|
|
|
return kv_validate( |
153
|
0
|
|
|
0
|
|
|
{ post => sub { $self->reqPosts(shift) }, |
154
|
0
|
|
|
0
|
|
|
get => sub { $self->reqGets(shift) }, |
155
|
0
|
|
|
0
|
|
|
param => sub { $self->reqParams(shift) }, |
156
|
0
|
|
|
0
|
|
|
cookie => sub { $self->reqCookie(shift) }, |
157
|
|
|
|
|
|
|
}, $self->{_TUWF}{validate_templates} || {}, |
158
|
|
|
|
|
|
|
\@fields |
159
|
0
|
|
0
|
|
|
|
); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# A simple mail function, body and headers as arguments. Usage: |
165
|
|
|
|
|
|
|
# $self->mail('body', header1 => 'value of header 1', ..); |
166
|
|
|
|
|
|
|
sub TUWF::Object::mail { |
167
|
0
|
|
|
0
|
|
|
my $self = shift; |
168
|
0
|
|
|
|
|
|
my $body = shift; |
169
|
0
|
|
|
|
|
|
my %hs = @_; |
170
|
|
|
|
|
|
|
|
171
|
0
|
0
|
|
|
|
|
croak "No To: specified!\n" if !$hs{To}; |
172
|
0
|
0
|
|
|
|
|
croak "No Subject: specified!\n" if !$hs{Subject}; |
173
|
0
|
|
0
|
|
|
|
$hs{'Content-Type'} ||= 'text/plain; charset=\'UTF-8\''; |
174
|
0
|
|
0
|
|
|
|
$hs{From} ||= $self->{_TUWF}{mail_from}; |
175
|
0
|
|
|
|
|
|
$body =~ s/\r?\n/\n/g; |
176
|
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
|
my $mail = ''; |
178
|
0
|
|
|
|
|
|
foreach (keys %hs) { |
179
|
0
|
|
|
|
|
|
$hs{$_} =~ s/[\r\n]//g; |
180
|
0
|
|
|
|
|
|
$mail .= sprintf "%s: %s\n", $_, $hs{$_}; |
181
|
|
|
|
|
|
|
} |
182
|
0
|
|
|
|
|
|
$mail .= sprintf "\n%s", $body; |
183
|
|
|
|
|
|
|
|
184
|
0
|
0
|
|
|
|
|
if($self->{_TUWF}{mail_sendmail} eq 'log') { |
|
|
0
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
$self->log("tuwf->mail(): The following mail would have been sent:\n$mail"); |
186
|
|
|
|
|
|
|
} elsif(open(my $mailer, '|-:utf8', "$self->{_TUWF}{mail_sendmail} -t -f '$hs{From}'")) { |
187
|
0
|
|
|
|
|
|
print $mailer $mail; |
188
|
0
|
0
|
|
|
|
|
croak "Error running sendmail ($!)" |
189
|
|
|
|
|
|
|
if !close($mailer); |
190
|
|
|
|
|
|
|
} else { |
191
|
0
|
|
|
|
|
|
croak "Error opening sendail ($!)"; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub TUWF::Object::compile { |
197
|
0
|
|
|
0
|
|
|
TUWF::Validate::compile($_[0]{_TUWF}{custom_validations}, $_[1]); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub _compile { |
202
|
0
|
0
|
|
0
|
|
|
ref $_[0] eq 'TUWF::Validate' ? $_[0] : $TUWF::OBJ->compile($_[0]); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub TUWF::Object::validate { |
207
|
0
|
|
|
0
|
|
|
my $self = shift; |
208
|
0
|
|
|
|
|
|
my $what = shift; |
209
|
|
|
|
|
|
|
|
210
|
0
|
0
|
|
|
|
|
return _compile($_[0])->validate($self->reqJSON) if $what eq 'json'; |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# 'param' is special, and not really encouraged. Create a new hash based on |
213
|
|
|
|
|
|
|
# reqParam() and cache the result. |
214
|
|
|
|
|
|
|
$self->{_TUWF}{Req}{PARAM} ||= { |
215
|
0
|
0
|
0
|
|
|
|
map { my @v = $self->reqParams($_); +($_, @v > 1 ? \@v : $v[0]) } $self->reqParams() |
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
} if $what eq 'param'; |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
my $source = |
219
|
|
|
|
|
|
|
$what eq 'get' ? $self->{_TUWF}{Req}{GET} : |
220
|
|
|
|
|
|
|
$what eq 'post' ? $self->{_TUWF}{Req}{POST} : |
221
|
|
|
|
|
|
|
$what eq 'param' ? $self->{_TUWF}{Req}{PARAM} |
222
|
0
|
0
|
|
|
|
|
: croak "Invalid source type '$what'"; |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# Multi-value, schema hash or object |
225
|
0
|
0
|
|
|
|
|
return _compile($_[0])->validate($source) if @_ == 1; |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# Single value |
228
|
0
|
0
|
|
|
|
|
return _compile($_[1])->validate($source->{$_[0]}) if @_ == 2; |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# Multi-value, separate params |
231
|
0
|
|
|
|
|
|
_compile({ type => 'hash', keys => { @_ } })->validate($source); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
1; |