]>
Dogcows Code - chaz/p5-CGI-Ex/blob - lib/CGI/Ex/Validate.pm
1 package CGI
::Ex
::Validate
;
5 CGI::Ex::Validate - another form validator - but it does javascript in parallel
9 ###----------------------------------------------------------------###
10 # Copyright 2007 - Paul Seamons #
11 # Distributed under the Perl Artistic License without warranty #
12 ###----------------------------------------------------------------###
28 $QR_EXTRA = qr/^(\w+_error|as_(array|string|hash)_\w+|no_\w+)/;
29 @UNSUPPORTED_BROWSERS = (qr/MSIE\s+5.0\d/i);
31 ###----------------------------------------------------------------###
35 my $self = ref($_[0]) ? shift : {@_};
37 $self = {%DEFAULT_OPTIONS, %$self} if scalar keys %DEFAULT_OPTIONS;
39 return bless $self, $class;
42 ###----------------------------------------------------------------###
46 return $self->{'cgix'} ||= do {
52 ### the main validation routine
54 my $self = (! ref($_[0])) ? shift-
>new # $class->validate
55 : UNIVERSAL
::isa
($_[0], __PACKAGE__
) ? shift # $self->validate
56 : __PACKAGE__-
>new; # &validate
57 my $form = shift || die "Missing form hash";
58 my $val_hash = shift || die "Missing validation hash";
59 my $what_was_validated = shift; # allow for extra arrayref that stores what was validated
61 ### turn the form into a form hash if doesn't look like one already
62 die "Invalid form hash or cgi object" if ! ref $form;
63 if (ref $form ne 'HASH') {
64 local $self->{cgi_object
} = $form;
65 $form = $self->cgix->get_form($form);
68 ### make sure the validation is a hashref
69 ### get_validation handle odd types
70 if (ref $val_hash ne 'HASH') {
71 $val_hash = $self->get_validation($val_hash) if ref $val_hash ne 'SCALAR' || ! ref $val_hash;
72 die "Validation groups must be a hashref" if ref $val_hash ne 'HASH';
75 ### parse keys that are group arguments - and those that are keys to validate
77 my @field_keys = grep { /^(?:group|general)\s+(\w+)/
78 ? do {$ARGS{$1} = $val_hash->{$_} ; 0}
82 ### only validate this group if it is supposed to be checked
83 return if $ARGS{'validate_if'} && ! $self->check_conditional($form, $ARGS{'validate_if'});
85 ### Look first for items in 'group fields' or 'group order'
87 if ($fields = $ARGS{'fields'} || $ARGS{'order'}) {
88 my $type = $ARGS{'fields'} ? 'group fields' : 'group order';
89 die "Validation '$type' must be an arrayref when passed"
90 if ! UNIVERSAL
::isa
($fields, 'ARRAY');
92 foreach my $field (@$fields) {
93 die "Non-defined value in '$type'" if ! defined $field;
95 die "Found nonhashref value in '$type'" if ref($field) ne 'HASH';
96 die "Element missing \"field\" key/value in '$type'" if ! defined $field->{'field'};
98 } elsif ($field eq 'OR') {
101 die "No element found in '$type' for $field" if ! exists $val_hash->{$field};
102 die "Found nonhashref value in '$type'" if ref($val_hash->{$field}) ne 'HASH';
103 push @temp, { %{ $val_hash->{$field} }, field
=> $field }; # copy the values to add the key
108 ### limit the keys that need to be searched to those not in fields or order
109 my %found = map { $_->{'field'} => 1 } @temp;
110 @field_keys = grep { ! $found{$_} } @field_keys;
113 ### add any remaining field_vals from our original hash
114 ### this is necessary for items that weren't in group fields or group order
115 foreach my $field (@field_keys) {
116 die "Found nonhashref value for field $field" if ref($val_hash->{$field}) ne 'HASH';
117 if (defined $val_hash->{$field}->{'field'}) {
118 push @$fields, $val_hash->{$field}->{'field'};
120 push @$fields, { %{$val_hash->{$field}}, field
=> $field };
125 ### Finally we have our arrayref of hashrefs that each have their 'field' key
126 ### now lets do the validation
129 my $hold_error; # hold the error for a moment - to allow for an "OR" operation
130 foreach (my $i = 0; $i < @$fields; $i++) {
131 my $ref = $fields->[$i];
132 if (! ref($ref) && $ref eq 'OR') {
133 $i++ if $found; # if found skip the OR altogether
138 die "Missing field key during normal validation" if ! $ref->{'field'};
139 local $ref->{'was_validated'} = 1;
140 my $err = $self->validate_buddy($form, $ref->{'field'}, $ref);
141 if ($ref->{'was_validated'} && $what_was_validated) {
142 push @$what_was_validated, $ref;
145 ### test the error - if errors occur allow for OR - if OR fails use errors from first fail
147 if ($i < $#$fields && ! ref($fields->[$i + 1]) && $fields->[$i + 1] eq 'OR') {
150 push @errors, $hold_error ? @$hold_error : @$err;
157 push(@errors, @$hold_error) if $hold_error; # allow for final OR to work
160 ### optionally check for unused keys in the form
161 if ($ARGS{no_extra_fields
} || $self->{no_extra_fields
}) {
162 my %keys = map { ($_->{'field'} => 1) } @$fields; # %{ $self->get_validation_keys($val_hash) };
163 foreach my $key (sort keys %$form) {
165 push @errors, [$key, 'no_extra_fields', {}, undef];
169 ### return what they want
171 my @copy = grep {/$QR_EXTRA/o} keys %$self;
172 @ARGS{@copy} = @{ $self }{@copy};
173 unshift @errors, $ARGS{'title'} if $ARGS{'title'};
174 my $err_obj = $self->new_error(\
@errors, \
%ARGS);
175 die $err_obj if $ARGS{'raise_error'};
184 return CGI
::Ex
::Validate
::Error-
>new(@_);
187 ### allow for optional validation on groups and on individual items
188 sub check_conditional
{
189 my ($self, $form, $ifs, $ifs_match) = @_;
191 ### can pass a single hash - or an array ref of hashes
193 die "Need reference passed to check_conditional";
194 } elsif (! ref($ifs)) {
196 } elsif (UNIVERSAL
::isa
($ifs,'HASH')) {
200 local $self->{'_check_conditional'} = 1;
202 ### run the if options here
203 ### multiple items can be passed - all are required unless OR is used to separate
205 foreach (my $i = 0; $i <= $#$ifs; $i ++) {
206 my $ref = $ifs->[$i];
209 $i ++ if $found; # if found skip the OR altogether
213 if ($ref =~ s/^\s*!\s*//) {
214 $ref = {field
=> $ref, max_in_set
=> "0 of $ref"};
216 $ref = {field
=> $ref, required
=> 1};
222 ### get the field - allow for custom variables based upon a match
223 my $field = $ref->{'field'} || die "Missing field key during validate_if (possibly used a reference to a main hash *foo -> &foo)";
224 $field =~ s/\$(\d+)/defined($ifs_match->[$1]) ? $ifs_match->[$1] : ''/eg if $ifs_match;
226 my $errs = $self->validate_buddy($form, $field, $ref);
233 ### this is where the main checking goes on
236 my ($form, $field, $field_val, $ifs_match) = @_;
238 local $self->{'_recurse'} = ($self->{'_recurse'} || 0) + 1;
239 die "Max dependency level reached 10" if $self->{'_recurse'} > 10;
242 my $types = [sort keys %$field_val];
244 ### allow for not running some tests in the cgi
245 if ($field_val->{'exclude_cgi'}) {
246 delete $field_val->{'was_validated'};
250 ### allow for field names that contain regular expressions
251 if ($field =~ m/^(!\s*|)m([^\s\w])(.*)\2([eigsmx]*)$/s) {
252 my ($not,$pat,$opt) = ($1,$3,$4);
254 die "The e option cannot be used on validation keys on field $field" if $opt =~ /e/;
255 foreach my $_field (sort keys %$form) {
256 next if ($not && $_field =~ m/(?$opt:$pat)/) || (! $not && $_field !~ m/(?$opt:$pat)/);
257 my @match = (undef, $1, $2, $3, $4, $5); # limit to the matches
258 my $errs = $self->validate_buddy($form, $_field, $field_val, \
@match);
259 push @errors, @$errs if $errs;
261 return @errors ? \
@errors : 0;
264 my $values = UNIVERSAL
::isa
($form->{$field},'ARRAY') ? $form->{$field} : [$form->{$field}];
265 my $n_values = $#$values + 1;
267 ### allow for default value
268 if (exists $field_val->{'default'}) {
269 if ($n_values == 0 || ($n_values == 1 && (! defined($values->[0]) || ! length($values->[0])))) {
270 $form->{$field} = $values->[0] = $field_val->{'default'};
274 ### allow for a few form modifiers
276 foreach my $value (@$values) {
277 next if ! defined $value;
278 if (! $field_val->{'do_not_trim'}) { # whitespace
283 if ($field_val->{'trim_control_chars'}) {
285 $value =~ y/\x00-\x1F//d;
288 if ($field_val->{'to_upper_case'}) { # uppercase
291 } elsif ($field_val->{'to_lower_case'}) { # lowercase
296 # allow for inline specified modifications (ie s/foo/bar/)
297 foreach my $type (grep {/^replace_?\d*$/} @$types) {
298 my $ref = UNIVERSAL
::isa
($field_val->{$type},'ARRAY') ? $field_val->{$type}
299 : [split(/\s*\|\|\s*/,$field_val->{$type})];
300 foreach my $rx (@$ref) {
301 if ($rx !~ m/^\s*s([^\s\w])(.+)\1(.*)\1([eigsmx]*)$/s) {
302 die "Not sure how to parse that replace ($rx)";
304 my ($pat, $swap, $opt) = ($2, $3, $4);
305 die "The e option cannot be used in swap on field $field" if $opt =~ /e/;
306 my $global = $opt =~ s/g//g;
309 foreach my $value (@$values) {
310 $value =~ s
{(?$opt:$pat)}{
311 my @match = (undef, $1, $2, $3, $4, $5, $6); # limit on the number of matches
313 $copy =~ s/\$(\d+)/defined($match[$1]) ? $match[$1] : ""/ge;
315 $copy; # return of the swap
319 foreach my $value (@$values) {
320 next if ! defined $value;
321 $value =~ s
{(?$opt:$pat)}{
322 my @match = (undef, $1, $2, $3, $4, $5, $6); # limit on the number of matches
324 $copy =~ s/\$(\d+)/defined($match[$1]) ? $match[$1] : ""/ge;
326 $copy; # return of the swap
332 ### put them back into the form if we have modified it
334 if ($n_values == 1) {
335 $form->{$field} = $values->[0];
336 $self->{cgi_object
}->param(-name
=> $field, -value
=> $values->[0])
337 if $self->{cgi_object
};
339 ### values in @{ $form->{$field} } were modified directly
340 $self->{cgi_object
}->param(-name
=> $field, -value
=> $values)
341 if $self->{cgi_object
};
345 ### only continue if a validate_if is not present or passes test
348 foreach my $type (grep {/^validate_if_?\d*$/} @$types) {
350 my $ifs = $field_val->{$type};
351 my $ret = $self->check_conditional($form, $ifs, $ifs_match);
352 $needs_val ++ if $ret;
354 if (! $needs_val && $n_vif) {
355 delete $field_val->{'was_validated'};
359 ### check for simple existence
360 ### optionally check only if another condition is met
361 my $is_required = $field_val->{'required'} ? 'required' : '';
362 if (! $is_required) {
363 foreach my $type (grep {/^required_if_?\d*$/} @$types) {
364 my $ifs = $field_val->{$type};
365 next if ! $self->check_conditional($form, $ifs, $ifs_match);
366 $is_required = $type;
371 && ($n_values == 0 || ($n_values == 1 && (! defined($values->[0]) || ! length $values->[0])))) {
372 return [] if $self->{'_check_conditional'};
373 return [[$field, $is_required, $field_val, $ifs_match]];
377 my $n = exists($field_val->{'min_values'}) ? $field_val->{'min_values'} || 0 : 0;
378 if ($n_values < $n) {
379 return [] if $self->{'_check_conditional'};
380 return [[$field, 'min_values', $field_val, $ifs_match]];
384 $field_val->{'max_values'} = 1 if ! exists $field_val->{'max_values'};
385 $n = $field_val->{'max_values'} || 0;
386 if ($n_values > $n) {
387 return [] if $self->{'_check_conditional'};
388 return [[$field, 'max_values', $field_val, $ifs_match]];
391 ### max_in_set and min_in_set checks
392 my @min = grep {/^min_in_set_?\d*$/} @$types;
393 my @max = grep {/^max_in_set_?\d*$/} @$types;
394 foreach ([min
=> \
@min],
396 my ($minmax, $keys) = @$_;
397 foreach my $type (@$keys) {
398 $field_val->{$type} =~ m/^\s*(\d+)(?i:\s*of)?\s+(.+)\s*$/
399 || die "Invalid in_set check $field_val->{$type}";
401 foreach my $_field (split /[\s,]+/, $2) {
402 my $ref = UNIVERSAL
::isa
($form->{$_field},'ARRAY') ? $form->{$_field} : [$form->{$_field}];
403 foreach my $_value (@$ref) {
404 $n -- if defined($_value) && length($_value);
407 if ( ($minmax eq 'min' && $n > 0)
408 || ($minmax eq 'max' && $n < 0)) {
409 return [] if $self->{'_check_conditional'};
410 return [[$field, $type, $field_val, $ifs_match]];
415 ### at this point @errors should still be empty
416 my $content_checked; # allow later for possible untainting (only happens if content was checked)
418 ### loop on values of field
419 foreach my $value (@$values) {
421 ### allow for enum types
422 if (exists $field_val->{'enum'}) {
423 my $ref = ref($field_val->{'enum'}) ? $field_val->{'enum'} : [split(/\s*\|\|\s*/,$field_val->{'enum'})];
426 $found = 1 if defined($value) && $_ eq $value;
429 return [] if $self->{'_check_conditional'};
430 push @errors, [$field, 'enum', $field_val, $ifs_match];
432 $content_checked = 1;
435 ### field equality test
436 foreach my $type (grep {/^equals_?\d*$/} @$types) {
437 my $field2 = $field_val->{$type};
438 my $not = ($field2 =~ s/^!\s*//) ? 1 : 0;
440 if ($field2 =~ m/^([\"\'])(.*)\1$/) {
442 $success = (defined($value) && $value eq $test);
443 } elsif (exists($form->{$field2}) && defined($form->{$field2})) {
444 $success = (defined($value) && $value eq $form->{$field2});
445 } elsif (! defined($value)) {
446 $success = 1; # occurs if they are both undefined
448 if ($not ? $success : ! $success) {
449 return [] if $self->{'_check_conditional'};
450 push @errors, [$field, $type, $field_val, $ifs_match];
452 $content_checked = 1;
456 if (exists $field_val->{'min_len'}) {
457 my $n = $field_val->{'min_len'};
458 if (! defined($value) || length($value) < $n) {
459 return [] if $self->{'_check_conditional'};
460 push @errors, [$field, 'min_len', $field_val, $ifs_match];
465 if (exists $field_val->{'max_len'}) {
466 my $n = $field_val->{'max_len'};
467 if (defined($value) && length($value) > $n) {
468 return [] if $self->{'_check_conditional'};
469 push @errors, [$field, 'max_len', $field_val, $ifs_match];
473 ### now do match types
474 foreach my $type (grep {/^match_?\d*$/} @$types) {
475 my $ref = UNIVERSAL
::isa
($field_val->{$type},'ARRAY') ? $field_val->{$type}
476 : UNIVERSAL
::isa
($field_val->{$type}, 'Regexp') ? [$field_val->{$type}]
477 : [split(/\s*\|\|\s*/,$field_val->{$type})];
478 foreach my $rx (@$ref) {
479 if (UNIVERSAL
::isa
($rx,'Regexp')) {
480 if (! defined($value) || $value !~ $rx) {
481 push @errors, [$field, $type, $field_val, $ifs_match];
484 if ($rx !~ m/^(!\s*|)m([^\s\w])(.*)\2([eigsmx]*)$/s) {
485 die "Not sure how to parse that match ($rx)";
487 my ($not,$pat,$opt) = ($1,$3,$4);
489 die "The e option cannot be used on validation keys on field $field" if $opt =~ /e/;
490 if ( ( $not && ( defined($value) && $value =~ m/(?$opt:$pat)/))
491 || (! $not && (! defined($value) || $value !~ m/(?$opt:$pat)/))
493 return [] if $self->{'_check_conditional'};
494 push @errors, [$field, $type, $field_val, $ifs_match];
498 $content_checked = 1;
501 ### allow for comparison checks
502 foreach my $type (grep {/^compare_?\d*$/} @$types) {
503 my $ref = UNIVERSAL
::isa
($field_val->{$type},'ARRAY') ? $field_val->{$type}
504 : [split(/\s*\|\|\s*/,$field_val->{$type})];
505 foreach my $comp (@$ref) {
508 if ($comp =~ /^\s*(>|<|[><!=]=)\s*([\d\.\-]+)\s*$/) {
509 my $val = $value || 0;
511 if ($1 eq '>' ) { $test = ($val > $2) }
512 elsif ($1 eq '<' ) { $test = ($val < $2) }
513 elsif ($1 eq '>=') { $test = ($val >= $2) }
514 elsif ($1 eq '<=') { $test = ($val <= $2) }
515 elsif ($1 eq '!=') { $test = ($val != $2) }
516 elsif ($1 eq '==') { $test = ($val == $2) }
518 } elsif ($comp =~ /^\s*(eq|ne|gt|ge|lt|le)\s+(.+?)\s*$/) {
519 my $val = defined($value) ? $value : '';
520 my ($op, $value2) = ($1, $2);
521 $value2 =~ s/^([\"\'])(.*)\1$/$2/;
522 if ($op eq 'gt') { $test = ($val gt $value2) }
523 elsif ($op eq 'lt') { $test = ($val lt $value2) }
524 elsif ($op eq 'ge') { $test = ($val ge $value2) }
525 elsif ($op eq 'le') { $test = ($val le $value2) }
526 elsif ($op eq 'ne') { $test = ($val ne $value2) }
527 elsif ($op eq 'eq') { $test = ($val eq $value2) }
530 die "Not sure how to compare \"$comp\"";
533 return [] if $self->{'_check_conditional'};
534 push @errors, [$field, $type, $field_val, $ifs_match];
537 $content_checked = 1;
540 ### server side sql type
541 foreach my $type (grep {/^sql_?\d*$/} @$types) {
542 my $db_type = $field_val->{"${type}_db_type"};
543 my $dbh = ($db_type) ? $self->{dbhs
}->{$db_type} : $self->{dbh
};
545 die "Missing dbh for $type type on field $field" . ($db_type ? " and db_type $db_type" : "");
546 } elsif (UNIVERSAL
::isa
($dbh,'CODE')) {
547 $dbh = &$dbh($field, $self) || die "SQL Coderef did not return a dbh";
549 my $sql = $field_val->{$type};
550 my @args = ($value) x
$sql =~ tr/?//;
551 my $return = $dbh->selectrow_array($sql, {}, @args); # is this right - copied from O::FORMS
552 $field_val->{"${type}_error_if"} = 1 if ! defined $field_val->{"${type}_error_if"};
553 if ( (! $return && $field_val->{"${type}_error_if"})
554 || ($return && ! $field_val->{"${type}_error_if"}) ) {
555 return [] if $self->{'_check_conditional'};
556 push @errors, [$field, $type, $field_val, $ifs_match];
558 $content_checked = 1;
561 ### server side custom type
562 foreach my $type (grep {/^custom_?\d*$/} @$types) {
563 my $check = $field_val->{$type};
564 next if UNIVERSAL
::isa
($check, 'CODE') ? &$check($field, $value, $field_val, $type) : $check;
565 return [] if $self->{'_check_conditional'};
566 push @errors, [$field, $type, $field_val, $ifs_match];
567 $content_checked = 1;
570 ### do specific type checks
571 foreach my $type (grep {/^type_?\d*$/} @$types) {
572 if (! $self->check_type($value,$field_val->{'type'},$field,$form)){
573 return [] if $self->{'_check_conditional'};
574 push @errors, [$field, $type, $field_val, $ifs_match];
576 $content_checked = 1;
580 ### allow for the data to be "untainted"
581 ### this is only allowable if the user ran some other check for the datatype
582 if ($field_val->{'untaint'} && $#errors == -1) {
583 if (! $content_checked) {
584 push @errors, [$field, 'untaint', $field_val, $ifs_match];
586 ### generic untainter - assuming the other required content_checks did good validation
587 $_ = /(.*)/ ? $1 : die "Couldn't match?" foreach @$values;
588 if ($n_values == 1) {
589 $form->{$field} = $values->[0];
590 $self->{cgi_object
}->param(-name
=> $field, -value
=> $values->[0])
591 if $self->{cgi_object
};
593 ### values in @{ $form->{$field} } were modified directly
594 $self->{cgi_object
}->param(-name
=> $field, -value
=> $values)
595 if $self->{cgi_object
};
600 ### all done - time to return
601 return @errors ? \
@errors : 0;
604 ###----------------------------------------------------------------###
606 ### used to validate specific types
610 my $type = uc(shift);
612 ### do valid email address for our system
613 if ($type eq 'EMAIL') {
614 return 0 if ! $value;
615 my($local_p,$dom) = ($value =~ /^(.+)\@(.+?)$/) ? ($1,$2) : return 0;
617 return 0 if length($local_p) > 60;
618 return 0 if length($dom) > 100;
619 return 0 if ! $self->check_type($dom,'DOMAIN') && ! $self->check_type($dom,'IP');
620 return 0 if ! $self->check_type($local_p,'LOCAL_PART');
622 ### the "username" portion of an email address
623 } elsif ($type eq 'LOCAL_PART') {
624 return 0 if ! defined($value) || ! length($value);
625 return 0 if $value =~ m/[^a-z0-9.\-!&+]/;
626 return 0 if $value =~ m/^[\.\-]/;
627 return 0 if $value =~ m/[\.\-\&]$/;
628 return 0 if $value =~ m/(\.\-|\-\.|\.\.)/;
630 ### standard IP address
631 } elsif ($type eq 'IP') {
632 return 0 if ! $value;
633 return (4 == grep {!/\D/ && $_ < 256} split /\./, $value, 4);
635 ### domain name - including tld and subdomains (which are all domains)
636 } elsif ($type eq 'DOMAIN') {
637 return 0 if ! $value;
638 return 0 if $value =~ m/[^a-z0-9.\-]/;
639 return 0 if $value =~ m/^[\.\-]/;
640 return 0 if $value =~ m/(\.\-|\-\.|\.\.)/;
641 return 0 if length($value) > 255;
642 return 0 if $value !~ s/\.([a-z]+)$//;
645 if ($ext eq 'name') { # .name domains
646 return 0 if $value !~ /^[a-z0-9][a-z0-9\-]{0,62} \. [a-z0-9][a-z0-9\-]{0,62}$/x;
647 } else { # any other domains
648 return 0 if $value !~ /^([a-z0-9][a-z0-9\-]{0,62} \.)* [a-z0-9][a-z0-9\-]{0,62}$/x;
652 } elsif ($type eq 'URL') {
653 return 0 if ! $value;
654 $value =~ s
|^https
?://([^/]+)||i
|| return 0;
656 return 0 if ! $self->check_type($dom,'DOMAIN') && ! $self->check_type($dom,'IP');
657 return 0 if $value && ! $self->check_type($value,'URI');
659 ### validate a uri - the path portion of a request
660 } elsif ($type eq 'URI') {
661 return 0 if ! $value;
662 return 0 if $value =~ m/\s+/;
664 } elsif ($type eq 'CC') {
665 return 0 if ! $value;
666 ### validate the number
667 return 0 if $value =~ /[^\d\-\ ]/
668 || length($value) > 16
669 || length($value) < 13;
671 ### simple mod10 check
675 foreach my $digit ( reverse split //, $value ){
676 $switch = 1 if ++ $switch > 2;
677 my $y = $digit * $switch;
681 return 0 if $sum % 10;
688 ###----------------------------------------------------------------###
693 require CGI
::Ex
::Conf
;
694 return CGI
::Ex
::Conf
::conf_read
($val, {html_key
=> 'validation', default_ext
=> $DEFAULT_EXT});
697 ### returns all keys from all groups - even if group has validate_if
698 sub get_validation_keys
{
700 my $val_hash = shift;
701 my $form = shift; # with optional form - will only return keys in validated groups
703 ### turn the form into a form hash if doesn't look like one already
705 die "Invalid form hash or cgi object" if ! ref $form;
706 if (ref $form ne 'HASH') {
707 local $self->{cgi_object
} = $form;
708 $form = $self->cgix->get_form($form);
712 ### make sure the validation is a hashref
713 ### get_validation handle odd types
714 if (ref $val_hash ne 'HASH') {
715 $val_hash = $self->get_validation($val_hash) if ref $val_hash ne 'SCALAR' || ! ref $val_hash;
716 die "Validation groups must be a hashref" if ref $val_hash ne 'HASH';
719 ### parse keys that are group arguments - and those that are keys to validate
721 my @field_keys = grep { /^(?:group|general)\s+(\w+)/
722 ? do {$ARGS{$1} = $val_hash->{$_} ; 0}
724 sort keys %$val_hash;
726 ### only validate this group if it is supposed to be checked
727 return if $form && $ARGS{'validate_if'} && ! $self->check_conditional($form, $ARGS{'validate_if'});
729 ### Look first for items in 'group fields' or 'group order'
731 if (my $fields = $ARGS{'fields'} || $ARGS{'order'}) {
732 my $type = $ARGS{'fields'} ? 'group fields' : 'group order';
733 die "Validation '$type' must be an arrayref when passed"
734 if ! UNIVERSAL
::isa
($fields, 'ARRAY');
735 foreach my $field (@$fields) {
736 die "Non-defined value in '$type'" if ! defined $field;
738 die "Found nonhashref value in '$type'" if ref($field) ne 'HASH';
739 die "Element missing \"field\" key/value in '$type'" if ! defined $field->{'field'};
740 $keys{$field->{'field'}} = $field->{'name'} || 1;
741 } elsif ($field eq 'OR') {
743 die "No element found in '$type' for $field" if ! exists $val_hash->{$field};
744 die "Found nonhashref value in '$type'" if ref($val_hash->{$field}) ne 'HASH';
745 $keys{$field} = $val_hash->{$field}->{'name'} || 1;
750 ### add any remaining field_vals from our original hash
751 ### this is necessary for items that weren't in group fields or group order
752 foreach my $field (@field_keys) {
753 next if $keys{$field};
754 die "Found nonhashref value for field $field" if ref($val_hash->{$field}) ne 'HASH';
755 if (defined $val_hash->{$field}->{'field'}) {
756 $keys{$val_hash->{$field}->{'field'}} = $val_hash->{$field}->{'name'} || 1;
758 $keys{$field} = $val_hash->{$field}->{'name'} || 1;
765 ###----------------------------------------------------------------###
767 ### spit out a chunk that will do the validation
769 ### allow for some browsers to not receive the validation js
770 return "<!-- JS validation not supported in this browser $_ -->"
771 if $ENV{'HTTP_USER_AGENT'} && grep {$ENV{'HTTP_USER_AGENT'} =~ $_} @UNSUPPORTED_BROWSERS;
774 my $val_hash = shift || die "Missing validation";
775 my $form_name = shift || die "Missing form name";
776 my $js_uri_path = shift || $JS_URI_PATH;
777 $val_hash = $self->get_validation($val_hash);
779 ### store any extra items from self
781 $EXTRA{"general $_"} = $self->{$_} for grep {/$QR_EXTRA/o} keys %$self; # add 'general' to be used in javascript
783 my $js_uri_path_validate = $JS_URI_PATH_VALIDATE || do {
784 die "Missing \$js_uri_path" if ! $js_uri_path;
785 "$js_uri_path/CGI/Ex/validate.js";
788 if (! $self->{'no_jsondump'} && eval { require CGI
::Ex
::JSONDump
}) {
789 my $json = CGI
::Ex
::JSONDump-
>new({pretty
=> 1})->dump($val_hash);
790 return qq{<script src="$js_uri_path_validate"></script>
792 document.validation = $json;
793 if (document.check_form) document.check_form("$form_name");
797 } elsif (! $self->{'no_json'} && eval { require JSON
}) {
798 my $json = JSON-
>new(pretty
=> 1)->objToJson($val_hash);
800 return qq{<script src="$js_uri_path_validate"></script>
802 document.validation = $json;
803 if (document.check_form) document.check_form("$form_name");
807 } elsif (eval { require YAML
}) {
809 my $str = YAML
::Dump
((scalar keys %EXTRA) ? (\
%EXTRA) : () , $val_hash);
810 $str =~ s/(?<!\\)\\(?=[sSdDwWbB0-9?.*+|\-\^\${}()\[\]])/\\\\/g; # fix some issues with YAML
811 $str =~ s/\n/\\n\\\n/g; # allow for one big string that flows on multiple lines
812 $str =~ s/\"/\\\"/g; # quotify it
815 my $js_uri_path_yaml = $JS_URI_PATH_YAML || do {
816 die "Missing \$js_uri_path" if ! $js_uri_path;
817 "$js_uri_path/CGI/Ex/yaml_load.js";
820 ### return the string
821 return qq{<script src="$js_uri_path_yaml"></script>
822 <script src="$js_uri_path_validate"></script>
824 document.validation = "$str";
825 if (document.check_form) document.check_form("$form_name");
829 return '<!-- no JSON or YAML support found for JS validation -->';
833 ###----------------------------------------------------------------###
834 ### How to handle errors
836 package CGI
::Ex
::Validate
::Error
;
839 use overload
'""' => \
&as_string
;
842 my ($class, $errors, $extra) = @_;
843 die "Missing or invalid errors arrayref" if ref $errors ne 'ARRAY';
844 die "Missing or invalid extra hashref" if ref $extra ne 'HASH';
845 return bless {errors
=> $errors, extra
=> $extra}, $class;
850 my $extra = $self->{extra
} || {};
851 my $extra2 = shift || {};
853 ### allow for formatting
854 my $join = defined($extra2->{as_string_join
}) ? $extra2->{as_string_join
}
855 : defined($extra->{as_string_join
}) ? $extra->{as_string_join
}
857 my $header = defined($extra2->{as_string_header
}) ? $extra2->{as_string_header
}
858 : defined($extra->{as_string_header
}) ? $extra->{as_string_header
} : "";
859 my $footer = defined($extra2->{as_string_footer
}) ? $extra2->{as_string_footer
}
860 : defined($extra->{as_string_footer
}) ? $extra->{as_string_footer
} : "";
862 return $header . join($join, @{ $self->as_array($extra2) }) . $footer;
865 ### return an array of applicable errors
868 my $errors = $self->{errors
} || die "Missing errors";
869 my $extra = $self->{extra
} || {};
870 my $extra2 = shift || {};
872 my $title = defined($extra2->{as_array_title
}) ? $extra2->{as_array_title
}
873 : defined($extra->{as_array_title
}) ? $extra->{as_array_title
}
874 : "Please correct the following items:";
876 ### if there are heading items then we may end up needing a prefix
888 my $prefix = defined($extra2->{as_array_prefix
}) ? $extra2->{as_array_prefix
}
889 : defined($extra->{as_array_prefix
}) ? $extra->{as_array_prefix
}
890 : $has_headings ? ' ' : '';
892 ### get the array ready
894 push @array, $title if length $title;
898 foreach my $err (@$errors) {
903 my $text = $self->get_error_text($err);
904 next if $found{$text};
906 push @array, "$prefix$text";
913 ### return a hash of applicable errors
916 my $errors = $self->{errors
} || die "Missing errors";
917 my $extra = $self->{extra
} || {};
918 my $extra2 = shift || {};
920 my $suffix = defined($extra2->{as_hash_suffix
}) ? $extra2->{as_hash_suffix
}
921 : defined($extra->{as_hash_suffix
}) ? $extra->{as_hash_suffix
} : '_error';
922 my $join = defined($extra2->{as_hash_join
}) ? $extra2->{as_hash_join
}
923 : defined($extra->{as_hash_join
}) ? $extra->{as_hash_join
} : '<br />';
925 ### now add to the hash
928 foreach my $err (@$errors) {
931 my ($field, $type, $field_val, $ifs_match) = @$err;
932 die "Missing field name" if ! $field;
933 if ($field_val->{delegate_error
}) {
934 $field = $field_val->{delegate_error
};
935 $field =~ s/\$(\d+)/defined($ifs_match->[$1]) ? $ifs_match->[$1] : ''/eg if $ifs_match;
938 my $text = $self->get_error_text($err);
939 next if $found{$field}->{$text};
940 $found{$field}->{$text} = 1;
943 $return{$field} ||= [];
944 $return{$field} = [$return{$field}] if ! ref($return{$field});
945 push @{ $return{$field} }, $text;
948 ### allow for elements returned as
950 my $header = defined($extra2->{as_hash_header
}) ? $extra2->{as_hash_header
}
951 : defined($extra->{as_hash_header
}) ? $extra->{as_hash_header
} : "";
952 my $footer = defined($extra2->{as_hash_footer
}) ? $extra2->{as_hash_footer
}
953 : defined($extra->{as_hash_footer
}) ? $extra->{as_hash_footer
} : "";
954 foreach my $key (keys %return) {
955 $return{$key} = $header . join($join,@{ $return{$key} }) . $footer;
962 ### return a user friendly error message
966 my $extra = $self->{extra
} || {};
967 my ($field, $type, $field_val, $ifs_match) = @$err;
968 my $dig = ($type =~ s/(_?\d+)$//) ? $1 : '';
969 my $type_lc = lc($type);
971 ### allow for delegated field names - only used for defaults
972 if ($field_val->{delegate_error
}) {
973 $field = $field_val->{delegate_error
};
974 $field =~ s/\$(\d+)/defined($ifs_match->[$1]) ? $ifs_match->[$1] : ''/eg if $ifs_match;
977 ### the the name of this thing
978 my $name = $field_val->{'name'} || "The field $field";
979 $name =~ s/\$(\d+)/defined($ifs_match->[$1]) ? $ifs_match->[$1] : ''/eg if $ifs_match;
981 ### type can look like "required" or "required2" or "required100023"
982 ### allow for fallback from required100023_error through required_error
983 my @possible_error_keys = ("${type}_error");
984 unshift @possible_error_keys, "${type}${dig}_error" if length($dig);
986 ### look in the passed hash or self first
988 foreach my $key (@possible_error_keys){
989 $return = $field_val->{$key} || $extra->{$key} || next;
990 $return =~ s/\$(\d+)/defined($ifs_match->[$1]) ? $ifs_match->[$1] : ''/eg if $ifs_match;
991 $return =~ s/\$field/$field/g;
992 $return =~ s/\$name/$name/g;
993 if (my $value = $field_val->{"$type$dig"}) {
994 $return =~ s/\$value/$value/g if ! ref $value;
999 ### set default messages
1001 if ($type eq 'required' || $type eq 'required_if') {
1002 $return = "$name is required.";
1004 } elsif ($type eq 'min_values') {
1005 my $n = $field_val->{"min_values${dig}"};
1006 my $values = ($n == 1) ? 'value' : 'values';
1007 $return = "$name had less than $n $values.";
1009 } elsif ($type eq 'max_values') {
1010 my $n = $field_val->{"max_values${dig}"};
1011 my $values = ($n == 1) ? 'value' : 'values';
1012 $return = "$name had more than $n $values.";
1014 } elsif ($type eq 'enum') {
1015 $return = "$name is not in the given list.";
1017 } elsif ($type eq 'equals') {
1018 my $field2 = $field_val->{"equals${dig}"};
1019 my $name2 = $field_val->{"equals${dig}_name"} || "the field $field2";
1020 $name2 =~ s/\$(\d+)/defined($ifs_match->[$1]) ? $ifs_match->[$1] : ''/eg if $ifs_match;
1021 $return = "$name did not equal $name2.";
1023 } elsif ($type eq 'min_len') {
1024 my $n = $field_val->{"min_len${dig}"};
1025 my $char = ($n == 1) ? 'character' : 'characters';
1026 $return = "$name was less than $n $char.";
1028 } elsif ($type eq 'max_len') {
1029 my $n = $field_val->{"max_len${dig}"};
1030 my $char = ($n == 1) ? 'character' : 'characters';
1031 $return = "$name was more than $n $char.";
1033 } elsif ($type eq 'max_in_set') {
1034 my $set = $field_val->{"max_in_set${dig}"};
1035 $return = "Too many fields were chosen from the set ($set)";
1037 } elsif ($type eq 'min_in_set') {
1038 my $set = $field_val->{"min_in_set${dig}"};
1039 $return = "Not enough fields were chosen from the set ($set)";
1041 } elsif ($type eq 'match') {
1042 $return = "$name contains invalid characters.";
1044 } elsif ($type eq 'compare') {
1045 $return = "$name did not fit comparison.";
1047 } elsif ($type eq 'sql') {
1048 $return = "$name did not match sql test.";
1050 } elsif ($type eq 'custom') {
1051 $return = "$name did not match custom test.";
1053 } elsif ($type eq 'type') {
1054 my $_type = $field_val->{"type${dig}"};
1055 $return = "$name did not match type $_type.";
1057 } elsif ($type eq 'untaint') {
1058 $return = "$name cannot be untainted without one of the following checks: enum, equals, match, compare, sql, type, custom";
1060 } elsif ($type eq 'no_extra_fields') {
1061 $return = "$name should not be passed to validate.";
1065 die "Missing error on field $field for type $type$dig" if ! $return;
1070 ###----------------------------------------------------------------###
1079 use CGI::Ex::Validate;
1083 my $errobj = CGI::Ex::Validate->new->validate($form, $val_hash);
1087 my $form = CGI->new;
1089 my $form = CGI::Ex->new; # OR CGI::Ex->get_form;
1091 my $form = {key1 => 'val1', key2 => 'val2'};
1099 field => 'username',
1100 # field is optional in this case - will use key name
1107 validate_if => 'email',
1114 'group order' => [qw(username email email2)],
1115 username => {required => 1, max_len => 30},
1122 'group fields' => [{
1123 field => 'username', # field is not optional in this case
1132 validate_if => 'email',
1138 my $vob = CGI::Ex::Validate->new;
1139 my $errobj = $vob->validate($form, $val_hash);
1141 my $errobj = $vob->validate($form, "/somefile/somewhere.val"); # import config using yaml file
1143 my $errobj = $vob->validate($form, "/somefile/somewhere.pl"); # import config using perl file
1145 my $errobj = $vob->validate($form, "--- # a yaml document\n"); # import config using yaml str
1149 my $error_heading = $errobj->as_string; # OR "$errobj";
1150 my $error_list = $errobj->as_array; # ordered list of what when wrong
1151 my $error_hash = $errobj->as_hash; # hash of arrayrefs of errors
1153 # form passed validation
1156 ### will add an error for any form key not found in $val_hash
1157 my $vob = CGI::Ex::Validate->new({no_extra_keys => 1});
1158 my $errobj = $vob->validate($form, $val_hash);
1162 CGI::Ex::Validate is one of many validation modules. It aims to have
1163 all of the basic data validation functions, avoid adding all of the
1164 millions of possible types, while still giving the capability for the
1165 developer to add their own types.
1167 It also has full support for providing the same validation in javascript.
1168 It provides methods for attaching the javascript to existing forms.
1170 As opposed to other kitchen sync validation modules, CGI::Ex::Validate
1171 offers the simple types of validation, and makes it easy to add your
1180 Used to instantiate the object. Arguments are either a hash, or hashref,
1181 or nothing at all. Keys of the hash become the keys of the object.
1183 =item C<get_validation>
1185 Given a filename or YAML string will return perl hash. If more than one
1186 group is contained in the file, it will return an arrayref of hashrefs.
1188 my $ref = $self->get_validation($file);
1190 =item C<get_validation_keys>
1192 Given a filename or YAML string or a validation hashref, will return all
1193 of the possible keys found in the validation hash. This can be used to
1194 check to see if extra items have been passed to validate. If a second
1195 argument contains a form hash is passed, get_validation_keys will only
1196 return the keys of groups that were validated.
1198 my $key_hashref = $self->get_validation_keys($val_hash);
1200 The values of the hash are the names of the fields.
1204 Arguments are a form hashref or cgi object, a validation hashref or
1205 filename, and an optional what_was_validated arrayref (discussed
1206 further later on). If a CGI object is passed, CGI::Ex::get_form will
1207 be called on that object to turn it into a hashref. If a filename is
1208 given for the validation, get_validation will be called on that
1209 filename. If the what_was_validated_arrayref is passed - it will be
1210 populated (pushed) with the field hashes that were actually validated
1211 (anything that was skipped because of validate_if will not be in the
1214 If the form passes validation, validate will return undef. If it
1215 fails validation, it will return a CGI::Ex::Validate::Error object.
1216 If the 'raise_error' option has been set, validate will die
1217 with a CGI::Ex::validate::Error object as the value.
1219 my $err_obj = $self->validate($form, $val_hash);
1223 $self->{raise_error} = 1; # can also be listed in the val_hash
1224 eval { $self->validate($form, $val_hash) };
1225 if ($@) { my $err_obj = $@; }
1227 =item C<generate_js>
1229 Works with CGI::Ex::JSONDump, but can also work with JSON or YAML
1230 if desired (see L<JSON> or L<YAML>).
1232 Takes a validation hash, a form name, and an optional javascript uri
1233 path and returns Javascript that can be embedded on a page and will
1234 perform identical validations as the server side. The form name must be
1235 the name of the form that the validation will act upon - the name is
1236 used to register an onsubmit function. The javascript uri path is
1237 used to embed the locations of javascript source files included
1238 with the CGI::Ex distribution.
1240 The javascript uri path is highly dependent upon the server
1241 configuration and therefore must be configured manually. It may be
1242 passed to generate_js, or it may be specified in $JS_URI_PATH. There
1243 are two files included with this module that are needed -
1244 CGI/Ex/yaml_load.js and CGI/Ex/validate.js. When generating the js
1245 code, generate_js will look in $JS_URI_PATH_YAML and
1246 $JS_URI_PATH_VALIDATE. If either of these are not set, generate_js
1247 will default to "$JS_URI_PATH/CGI/Ex/yaml_load.js" and
1248 "$JS_URI_PATH/CGI/Ex/validate.js" (Note: yaml_load is only needed
1249 if the flags no_jsondump and no_json have been set).
1251 $self->generate_js($val_hash, 'my_form', "/cgi-bin/js")
1253 # would generate something like the following...
1255 <script src="/cgi-bin/js/CGI/Ex/validate.js"></script>
1256 ... more js follows ...
1258 $CGI::Ex::Validate::JS_URI_PATH = "/stock/js";
1259 $self->generate_js($val_hash, 'my_form')
1261 # would generate something like the following...
1263 <script src="/stock/js/CGI/Ex/validate.js"></script>
1264 ... more js follows ...
1266 Referencing yaml_load.js and validate.js can be done in any of
1267 several ways. They can be copied to or symlinked to a fixed location
1268 in the server's html directory. They can also be printed out by a cgi.
1269 The method C<-E<gt>print_js> has been provided in CGI::Ex for printing
1270 js files found in the perl hierarchy. See L<CGI::Ex> for more details.
1271 The $JS_URI_PATH of "/cgi-bin/js" could contain the following:
1278 ### path_info should contain something like /CGI/Ex/yaml_load.js
1279 my $info = $ENV{PATH_INFO} || '';
1280 die "Invalid path" if $info !~ m|^(/\w+)+.js$|;
1283 CGI::Ex->new->print_js($info);
1286 The print_js method in CGI::Ex is designed to cache the javascript in
1287 the browser (caching is suggested as they are medium sized files).
1291 Returns a CGI::Ex object. Used internally.
1295 =head1 VALIDATION HASH
1297 The validation hash may be passed as a hashref or as a
1298 filename, or as a YAML document string. If it is a filename, it will
1299 be translated into a hash using the %EXT_HANDLER for the extension on
1300 the file. If there is no extension, it will use $DEFAULT_EXT as a
1301 default. CGI::Ex::Conf is used for the reading of files.
1303 Keys matching the regex m/^(general|group)\s+(\w+)$/ are reserved and
1304 are counted as GROUP OPTIONS. Other keys (if any, should be field names
1305 that need validation).
1307 If the GROUP OPTION 'group validate_if' is set, the validation will only
1308 be validated if the conditions are met. If 'group validate_if' is not
1309 specified, then the validation will proceed.
1311 Each of the items listed in the validation will be validated. The
1312 validation order is determined in one of three ways:
1316 =item Specify 'group fields' arrayref.
1318 # order will be (username, password, 'm/\w+_foo/', somethingelse)
1320 'group title' => "User Information",
1322 {field => 'username', required => 1},
1323 {field => 'password', required => 1},
1324 {field => 'm/\w+_foo/', required => 1},
1326 somethingelse => {required => 1},
1329 =item Specify 'group order' arrayref.
1331 # order will be (username, password, 'm/\w+_foo/', somethingelse)
1333 'group title' => "User Information",
1334 'group order' => [qw(username password), 'm/\w+_foo/'],
1335 username => {required => 1},
1336 password => {required => 1},
1337 'm/\w+_foo/' => {required => 1},
1338 somethingelse => {required => 1},
1341 =item Do nothing - use sorted order.
1343 # order will be ('m/\w+_foo/', password, somethingelse, username)
1345 'group title' => "User Information",
1346 username => {required => 1},
1347 password => {required => 1},
1348 'm/\w+_foo/' => {required => 1},
1349 somethingelse => {required => 1},
1354 Optionally the 'group fields' or the 'group order' may contain the
1355 word 'OR' as a special keyword. If the item preceding 'OR' fails
1356 validation the item after 'OR' will be tested instead. If the item
1357 preceding 'OR' passes validation the item after 'OR' will not be
1360 'group order' => [qw(zip OR postalcode state OR region)],
1362 Each individual field validation hashref will operate on the field contained
1363 in the 'field' key. This key may also be a regular expression in the
1364 form of 'm/somepattern/'. If a regular expression is used, all keys
1365 matching that pattern will be validated. If the field key is
1366 not specified, the key from the top level hash will be used.
1368 foobar => { # "foobar" is not used as key because field is specified
1369 field => 'real_key_name',
1376 Each of the individual field validation hashrefs should contain the
1377 types listed in VALIDATION TYPES.
1379 =head1 VALIDATION TYPES
1381 This section lists the available validation types. Multiple instances
1382 of the same type may be used for some validation types by adding a
1383 number to the type (ie match, match2, match232, match_94). Multiple
1384 instances are validated in sorted order. Types that allow multiple
1401 =item C<validate_if>
1403 If validate_if is specified, the field will only be validated
1404 if the conditions are met. Works in JS.
1406 validate_if => {field => 'name', required => 1, max_len => 30}
1407 # Will only validate if the field "name" is present and is less than 30 chars.
1409 validate_if => 'name',
1411 validate_if => {field => 'name', required => 1},
1413 validate_if => '! name',
1415 validate_if => {field => 'name', max_in_set => '0 of name'},
1417 validate_if => {field => 'country', compare => "eq US"},
1418 # only if country's value is equal to US
1420 validate_if => {field => 'country', compare => "ne US"},
1421 # if country doesn't equal US
1423 validate_if => {field => 'password', match => 'm/^md5\([a-z0-9]{20}\)$/'},
1424 # if password looks like md5(12345678901234567890)
1427 field => 'm/^(\w+)_pass/',
1428 validate_if => '$1_user',
1431 # will validate foo_pass only if foo_user was present.
1433 The validate_if may also contain an arrayref of validation items. So that
1434 multiple checks can be run. They will be run in order. validate_if will
1435 return true only if all options returned true.
1437 validate_if => ['email', 'phone', 'fax']
1439 Optionally, if validate_if is an arrayref, it may contain the word
1440 'OR' as a special keyword. If the item preceding 'OR' fails validation
1441 the item after 'OR' will be tested instead. If the item preceding 'OR'
1442 passes validation the item after 'OR' will not be tested.
1444 validate_if => [qw(zip OR postalcode)],
1446 =item C<required_if>
1448 Requires the form field if the condition is satisfied. The conditions
1449 available are the same as for validate_if. This is somewhat the same
1452 validate_if => 'some_condition',
1455 required_if => 'some_condition',
1457 If a regex is used for the field name, the required_if
1458 field will have any match patterns swapped in.
1461 field => 'm/^(\w+)_pass/',
1462 required_if => '$1_user',
1465 This example would require the "foobar_pass" field to be set
1466 if the "foobar_user" field was passed.
1470 Requires the form field to have some value. If the field is not present,
1471 no other checks will be run.
1473 =item C<min_values> and C<max_values>
1475 Allows for specifying the maximum number of form elements passed.
1476 max_values defaults to 1 (You must explicitly set it higher
1477 to allow more than one item by any given name).
1479 =item C<min_in_set> and C<max_in_set>
1481 Somewhat like min_values and max_values except that you specify the
1482 fields that participate in the count. Also - entries that are not
1483 defined or do not have length are not counted. An optional "of" can
1484 be placed after the number for human readability.
1486 min_in_set => "2 of foo bar baz",
1487 # two of the fields foo, bar or baz must be set
1489 min_in_set => "2 foo bar baz",
1491 min_in_set => "2 OF foo bar baz",
1493 validate_if => {field => 'whatever', max_in_set => '0 of whatever'},
1494 # only run validation if there were zero occurrences of whatever
1498 Allows for checking whether an item matches a set of options. In perl
1499 the value may be passed as an arrayref. In the conf or in perl the
1500 value may be passed of the options joined with ||.
1503 field => 'password_type',
1504 enum => 'plaintext||crypt||md5', # OR enum => [qw(plaintext crypt md5)],
1509 Allows for comparison of two form elements. Can have an optional !.
1512 field => 'password',
1513 equals => 'password_verify',
1517 equals => '!domain2', # make sure the fields are not the same
1520 =item C<min_len and max_len>
1522 Allows for check on the length of fields
1532 Allows for regular expression comparison. Multiple matches may
1533 be concatenated with ||. Available in JS.
1537 match => 'm/^\d{1,3}(\.\d{1,3})3$/',
1538 match_2 => '!/^0\./ || !/^192\./',
1543 Allows for custom comparisons. Available types are
1544 >, <, >=, <=, !=, ==, gt, lt, ge, le, ne, and eq. Comparisons
1545 also work in the JS.
1548 field => 'my_number',
1549 match => 'm/^\d+$/',
1550 compare1 => '> 100',
1551 compare2 => '< 255',
1552 compare3 => '!= 150',
1557 SQL query based - not available in JS. The database handle will be looked
1558 for in the value $self->{dbhs}->{foo} if sql_db_type is set to 'foo',
1559 otherwise it will default to $self->{dbh}. If $self->{dbhs}->{foo} or
1560 $self->{dbh} is a coderef - they will be called and should return a dbh.
1563 field => 'username',
1564 sql => 'SELECT COUNT(*) FROM users WHERE username = ?',
1565 sql_error_if => 1, # default is 1 - set to 0 to negate result
1566 # sql_db_type => 'foo', # will look for a dbh under $self->{dbhs}->{foo}
1571 Custom value - not available in JS. Allows for extra programming types.
1572 May be either a boolean value predetermined before calling validate, or may be
1573 a coderef that will be called during validation. If coderef is called, it will
1574 be passed the field name, the form value for that name, and a reference to the
1575 field validation hash. If the custom type returns false the element fails
1576 validation and an error is added.
1579 field => 'username',
1581 my ($key, $val, $type, $field_val_hash) = @_;
1589 Custom value - only available in JS. Allows for extra programming types.
1590 May be either a boolean value pre-determined before calling validate, or may be
1591 section of javascript that will be eval'ed. The last value (return value) of
1592 the eval'ed javascript will determine if validation passed. A false value indicates
1593 the value did not pass validation. A true value indicates that it did. See
1594 the t/samples/js_validate_3.html page for a sample of usage.
1599 match => 'm|^\d\d\d\d/\d\d/\d\d$|',
1600 match_error => 'Please enter date in YYYY/MM/DD format',
1603 var y=t.getYear()+1900;
1604 var m=t.getMonth() + 1;
1606 if (m<10) m = '0'+m;
1607 if (d<10) d = '0'+d;
1608 (value > ''+y+'/'+m+'/'+d) ? 1 : 0;
1610 custom_js_error => 'The date was not greater than today.',
1615 Allows for more strict type checking. Currently supported types
1616 include CC (credit card). Other types will be added upon request provided
1617 we can add a perl and a javascript version.
1620 field => 'credit_card',
1626 =head1 SPECIAL VALIDATION TYPES
1632 Specify which field to work on. Key may be a regex in the form 'm/\w+_user/'.
1633 This key is required if 'group fields' is used or if validate_if or required_if
1634 are used. It can optionally be used with other types to specify a different form
1635 element to operate on. On errors, if a non-default error is found, $field
1636 will be swapped with the value found in field.
1638 The field name may also be a regular expression in the
1639 form of 'm/somepattern/'. If a regular expression is used, all keys
1640 matching that pattern will be validated.
1644 Name to use for errors. If a name is not specified, default errors will use
1645 "The field $field" as the name. If a non-default error is found, $name
1646 will be swapped with this name.
1648 =item C<delegate_error>
1650 This option allows for any errors generated on a field to delegate to
1651 a different field. If the field name was a regex, any patterns will
1652 be swapped into the delegate_error value. This option is generally only
1653 useful with the as_hash method of the error object (for inline errors).
1657 match => 'm/^\d{5}/',
1660 field => 'zip_plus4',
1661 match => 'm/^\d{4}/',
1662 delegate_error => 'zip',
1665 field => 'm/^(id_[\d+])_user$/',
1666 delegate_error => '$1',
1671 This allows the cgi to do checking while keeping the checks from
1672 being run in JavaScript
1680 =item C<exclude_cgi>
1682 This allows the js to do checking while keeping the checks from
1683 being run in the cgi
1693 =head1 MODIFYING VALIDATION TYPES
1695 The following types will modify the form value before it is processed.
1696 They work in both the perl and in javascript as well. The javascript
1697 version changes the actual value in the form on appropriate form types.
1701 =item C<do_not_trim>
1703 By default, validate will trim leading and trailing whitespace
1704 from submitted values. Set do_not_trim to 1 to allow it to
1707 {field => 'foo', do_not_trim => 1}
1709 =item C<trim_control_chars>
1711 Off by default. If set to true, removes characters in the
1712 \x00 to \x31 range (Tabs are translated to a single space).
1714 {field => 'foo', trim_control_chars => 1}
1718 Pass a swap pattern to change the actual value of the form.
1719 Any perl regex can be passed but it is suggested that javascript
1720 compatible regexes are used to make generate_js possible.
1722 {field => 'foo', replace => 's/(\d{3})(\d{3})(\d{3})/($1) $2-$3/'}
1726 Set item to default value if there is no existing value (undefined
1727 or zero length string).
1729 {field => 'country', default => 'EN'}
1731 =item C<to_upper_case> and C<to_lower_case>
1733 Do what they say they do.
1737 Requires that the validated field has been also checked with
1738 an enum, equals, match, compare, custom, or type check. If the
1739 field has been checked and there are no errors - the field is "untainted."
1741 This is for use in conjunction with perl's -T switch.
1747 Failed validation results in an error an error object created via the
1748 new_error method. The default error class is CGI::Ex::Validate::Error.
1750 The error object has several methods for determining what the errors were.
1756 Returns an array or arrayref (depending on scalar context) of errors that
1757 occurred in the order that they occurred. Individual groups may have a heading
1758 and the entire validation will have a heading (the default heading can be changed
1759 via the 'as_array_title' group option). Each error that occurred is a separate
1760 item and are pre-pended with 'as_array_prefix' (which is a group option - default
1761 is ' '). The as_array_ options may also be set via a hashref passed to as_array.
1762 as_array_title defaults to 'Please correct the following items:'.
1764 ### if this returns the following
1765 my $array = $err_obj->as_array;
1767 # ['Please correct the following items:', ' error1', ' error2']
1769 ### then this would return the following
1770 my $array = $err_obj->as_array({
1771 as_array_prefix => ' - ',
1772 as_array_title => 'Something went wrong:',
1775 # ['Something went wrong:', ' - error1', ' - error2']
1779 Returns values of as_array joined with a newline. This method is used as
1780 the stringification for the error object. Values of as_array are joined with
1781 'as_string_join' which defaults to "\n". If 'as_string_header' is set, it will
1782 be pre-pended onto the error string. If 'as_string_footer' is set, it will be
1783 appended onto the error string.
1785 ### if this returns the following
1786 my $string = $err_obj->as_string;
1787 # $string looks like
1788 # "Please correct the following items:\n error1\n error2"
1790 ### then this would return the following
1791 my $string = $err_obj->as_string({
1792 as_array_prefix => ' - ',
1793 as_array_title => 'Something went wrong:',
1794 as_string_join => '<br />',
1795 as_string_header => '<span class="error">',
1796 as_string_footer => '</span>',
1798 # $string looks like
1799 # '<span class="error">Something went wrong:<br /> - error1<br /> - error2</span>'
1803 Returns a hash or hashref (depending on scalar context) of errors that
1804 occurred. Each key is the field name of the form that failed
1805 validation with 'as_hash_suffix' added on as a suffix. as_hash_suffix
1806 is available as a group option and may also be passed in via a
1807 hashref as the only argument to as_hash. The default value is
1808 '_error'. The values of the hash are arrayrefs of errors that
1809 occurred to that form element.
1811 By default as_hash will return the values of the hash as arrayrefs (a
1812 list of the errors that occurred to that key). It is possible to also
1813 return the values as strings. Three options are available for
1814 formatting: 'as_hash_header' which will be pre-pended onto the error
1815 string, 'as_hash_footer' which will be appended, and 'as_hash_join'
1816 which will be used to join the arrayref. The only argument required
1817 to force the stringification is 'as_hash_join'.
1819 ### if this returns the following
1820 my $hash = $err_obj->as_hash;
1822 # {key1_error => ['error1', 'error2']}
1824 ### then this would return the following
1825 my $hash = $err_obj->as_hash({
1826 as_hash_suffix => '_foo',
1827 as_hash_join => '<br />',
1828 as_hash_header => '<span class="error">'
1829 as_hash_footer => '</span>'
1832 # {key1_foo => '<span class="error">error1<br />error2</span>'}
1836 =head1 GROUP OPTIONS
1838 Any key in a validation hash matching the pattern
1839 m/^(group|general)\s+(\w+)$/ is considered a group option (the reason
1840 that either group or general may be used is that CGI::Ex::Validate
1841 used to have the concept of validation groups - these were not
1842 commonly used so support has been deprecated as of the 2.10 release).
1843 Group options will also be looked for in the Validate object ($self)
1844 and can be set when instantiating the object ($self->{raise_error} is
1845 equivalent to $valhash->{'group raise_error'}). The current know
1848 Options may also be set globally before calling validate by
1849 populating the %DEFAULT_OPTIONS global hash.
1855 Used as a group section heading when as_array or as_string is called
1856 by the error object.
1858 'group title' => 'Title of errors',
1862 Order in which to validate key/value pairs of group.
1864 'group order' => [qw(user pass email OR phone)],
1868 Arrayref of validation items to validate.
1870 'group fields' => [{
1878 =item C<validate_if>
1880 If specified - the entire hashref will only be validated if
1881 the "if" conditions are met.
1883 'group validate_if => {field => 'email', required => 1},
1885 This group would only validate all fields if the email field
1888 =item C<raise_error>
1890 If raise_error is true, any call to validate that fails validation
1891 will die with an error object as the value.
1893 =item C<no_extra_fields>
1895 If no_extra_fields is true, validate will add errors for any field found
1896 in form that does not have a field_val hashref in the validation hash.
1897 Default is false. If no_extra_fields is set to 'used', it will check for
1898 any keys that were not in a group that was validated.
1900 An important exception to this is that field_val hashrefs or field names listed
1901 in a validate_if or required_if statement will not be included. You must
1902 have an explicit entry for each key.
1906 These items allow for an override of the default errors.
1908 'group required_error' => '$name is really required',
1909 'group max_len_error' => '$name must be shorter than $value characters',
1911 my $self = CGI::Ex::Validate->new({
1912 max_len_error => '$name must be shorter than $value characters',
1915 =item C<as_array_title>
1917 Used as the section title for all errors that occur, when as_array
1918 or as_string is called by the error object.
1920 =item C<as_array_prefix>
1922 Used as prefix to individual errors that occur, when as_array
1923 or as_string is called by the error object. Each individual error
1924 will be prefixed with this string. Headings will not be prefixed.
1927 =item C<as_string_join>
1929 When as_string is called, the values from as_array will be joined with
1930 as_string_join. Default value is "\n".
1932 =item C<as_string_header>
1934 If set, will be pre-pended onto the string when as_string is called.
1936 =item C<as_string_footer>
1938 If set, will be pre-pended onto the string when as_string is called.
1940 =item C<as_hash_suffix>
1942 Added on to key names during the call to as_hash. Default is '_error'.
1944 =item C<as_hash_join>
1946 By default, as_hash will return hashref values that are errors joined with
1947 the default as_hash_join value of <br />. It can also return values that are
1948 arrayrefs of the errors. This can be done by setting as_hash_join to a non-true value
1951 =item C<as_hash_header>
1953 If as_hash_join has been set to a true value, as_hash_header may be set to
1954 a string that will be pre-pended on to the error string.
1956 =item C<as_hash_footer>
1958 If as_hash_join has been set to a true value, as_hash_footer may be set to
1959 a string that will be postpended on to the error string.
1963 If set to true, the javascript validation will not attempt to generate inline
1964 errors. Default is true. Inline errors are independent of confirm and alert
1967 'general no_inline' => 1,
1971 If set to true, the javascript validation will try to use an alert instead
1972 of a confirm to inform the user of errors. Alert and confirm are independent
1973 or inline errors. Default is false.
1975 'general no_confirm' => 1,
1979 If set to true, the javascript validation will not show an alert box
1980 when errors occur. Default is false. This option only comes into
1981 play if no_confirm is also set. This option is independent of inline
1982 errors. Although it is possible to turn off all errors by setting
1983 no_inline, no_confirm, and no_alert all to 1, it is suggested that at
1984 least one of the error reporting facilities is left on.
1986 'general no_alert' => 1,
1992 CGI::Ex::Validate provides for having duplicate validation on the
1993 client side as on the server side. Errors can be shown in any
1994 combination of inline and confirm, inline and alert, inline only,
1995 confirm only, alert only, and none. These combinations are controlled
1996 by the group options no_inline, no_confirm, and no_alert.
1997 Javascript validation can be generated for a page using the
1998 C<-E<gt>generate_js> Method of CGI::Ex::Validate. It is also possible
1999 to store the validation inline with the html. This can be done by
2000 giving each of the elements to be validated an attribute called
2001 "validation", or by setting a global javascript variable called
2002 "document.validation" or "var validation". An html file containing this
2003 validation will be read in using CGI::Ex::Conf::read_handler_html.
2005 All inline html validation must be written in yaml.
2007 It is anticipated that the html will contain something like either of the
2010 <script src="/cgi-bin/js/CGI/Ex/yaml_load.js"></script>
2011 <script src="/cgi-bin/js/CGI/Ex/validate.js"></script>
2013 // \n\ allows all browsers to view this as a single string
2014 document.validation = "\n\
2015 general no_confirm: 1\n\
2016 general no_alert: 1\n\
2017 group order: [username, password]\n\
2025 if (document.check_form) document.check_form('my_form_name');
2028 Alternately we can use element attributes:
2030 <form name="my_form_name">
2032 Username: <input type=text size=20 name=username validation="
2036 <span class=error id=username_error>[% username_error %]</span><br>
2038 Password: <input type=text size=20 name=password validation="
2042 <span class=error id=password_error>[% password_error %]</span><br>
2048 <script src="/cgi-bin/js/CGI/Ex/yaml_load.js"></script>
2049 <script src="/cgi-bin/js/CGI/Ex/validate.js"></script>
2051 if (document.check_form) document.check_form('my_form_name');
2054 The read_handler_html from CGI::Ex::Conf will find either of these
2055 types of validation.
2057 If inline errors are asked for, each error that occurs will attempt
2058 to find an html element with its name as the id. For example, if
2059 the field "username" failed validation and created a "username_error",
2060 the javascript would set the html of <span id="username_error"></span>
2061 to the error message.
2063 It is suggested to use something like the following so that you can
2064 have inline javascript validation as well as report validation errors
2065 from the server side as well.
2067 <span class=error id=password_error>[% password_error %]</span><br>
2069 If the javascript fails for some reason, the form should still be able
2070 to submit as normal (fail gracefully).
2072 If the confirm option is used, the errors will be displayed to the user.
2073 If they choose OK they will be able to try and fix the errors. If they
2074 choose cancel, the form will submit anyway and will rely on the server
2075 to do the validation. This is for fail safety to make sure that if the
2076 javascript didn't validate correctly, the user can still submit the data.
2080 Thanks to Eamon Daly for providing bug fixes for bugs in validate.js
2081 caused by HTML::Prototype.
2085 This module may be distributed under the same terms as Perl itself.
2089 Paul Seamons <perl at seamons dot com>
This page took 0.198359 seconds and 5 git commands to generate.