I used an approach like this in CGI::Search, which could be adapted to your situation CGI.
A series of subroutines are used to validate the input. The subs take in the data to validate and return a list of three values. The first value is a boolean value of wheather the data validated or not. The second is the data that was validated, but in untained form (see perlsec). The third is a string that can be used as an error message if the data didn't validate.
To preform the validation, you make a hash-of-arrays with three elements in the array portion. The key of the hash is the name of the field. The zeroth element of the array is the data to validate. The first element is a referance to a validation subroutine. The second element is a boolean value of wheather the given data is required or not. If that second element is false, than the field is allowed to be blank. If true, then the data still has to pass the validator.
Tieing it all together:
use CGI qw(:standard);
# Validation subroutines defined elsewhere
my %DATA = (
field1 => [ param('field1'), \&INTEGER, 1 ],
field2 => [ param('field2'), \&EMAIL, 1 ],
field3 => [ param('field3'), \&WORD, 0 ],
);
sub do_validation
{
foreach my $key (keys %DATA) {
if($DATA{$key}[2]) {
my @result = $DATA{$key}[1]->($DATA{$key}[0]);
die "Didn't validate: $result[2]" unless $result[0];
}
}
}
The advantage of this compared to a regex is flexibility. A subroutine can do whatever checks it wants to the data. For instance, a credit card validator can run Business::CreditCard on the data.
WWW::Form does something similar, but adds the ablity to put the subrountines in an array. This means that a single peice of data must pass more than one validation sub.
---- I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
-- Schemer
Note: All code is untested, unless otherwise stated
|