File Coverage

blib/lib/HTML/FormBuilder/Validation.pm
Criterion Covered Total %
statement 161 172 93.6
branch 52 62 83.8
condition 39 57 68.4
subroutine 20 22 90.9
pod 8 8 100.0
total 280 321 87.2


line stmt bran cond sub pod time code
1              
2             use strict;
3 2     2   76021 use warnings;
  2         13  
  2         59  
4 2     2   10  
  2         5  
  2         46  
5             use Carp;
6 2     2   11 use Class::Std::Utils;
  2         3  
  2         100  
7 2     2   899  
  2         5763  
  2         11  
8             use Encode;
9 2     2   1201 use URI::Escape;
  2         20149  
  2         145  
10 2     2   802 use HTML::Entities;
  2         2951  
  2         121  
11 2     2   483  
  2         5554  
  2         143  
12             use Moo;
13 2     2   527 use namespace::clean;
  2         11082  
  2         14  
14 2     2   2440 extends qw(HTML::FormBuilder);
  2         11115  
  2         18  
15              
16             our $VERSION = '0.13'; ## VERSION
17              
18             has has_error_of => (
19             is => 'rw',
20             default => 0,
21             isa => sub {
22             croak('has_error_of should be 0 or 1') unless $_[0] == 0 || $_[0] == 1;
23             },
24             );
25              
26             has custom_server_side_check_of => (
27             is => 'rw',
28             isa => sub {
29             croak('custom_server_side_check_of should be code')
30             unless ref $_[0] eq 'CODE';
31             });
32              
33             has onsubmit_js_error => (
34             is => 'rw',
35             default => '',
36             );
37              
38             ########################################################################
39             # Usage : $form_validation_obj->set_input_fields(\%input);
40             # Purpose : Set input fields value based on last submit form.
41             # Returns : none
42             # Parameters : \%input: HASH ref to %input
43             # Comments : Public
44             # NOTE: This subroutine can use only if fields have same
45             # name and id.
46             # (i.e. <input id="name" name="name" type="text" />)
47             # See Also : n / a
48             ########################################################################
49             my $self = shift;
50             my $input = shift;
51 3     3 1 13  
52 3         7 for my $element_id (keys %{$input}) {
53             if ($element_id eq 'csrftoken') {
54 3         6 $self->{__input_csrftoken} = $input->{$element_id};
  3         12  
55 8 100       21 } else {
56 2         7 $self->set_field_value($element_id, $input->{$element_id});
57             }
58 6         17 }
59             return;
60             }
61 3         18  
62             my $self = shift;
63             my $print_fieldset_index = shift;
64              
65 2     2 1 44 my $javascript_validation = '';
66 2         5  
67             # build the fieldset, if $print_fieldset_index is specifed then we only generate that praticular fieldset with that index
68 2         6 my @fieldsets;
69             if (defined $print_fieldset_index) {
70             push @fieldsets, $self->{'fieldsets'}->[$print_fieldset_index];
71 2         5 } else {
72 2 50       9 @fieldsets = @{$self->{'fieldsets'}};
73 0         0 }
74              
75 2         5 # build the form fieldset
  2         7  
76             foreach my $fieldset (@fieldsets) {
77             foreach my $input_field (@{$fieldset->{'fields'}}) {
78              
79 2         8 # build inputs javascript validation
80 2         4 my $validation = $self->_build_javascript_validation({'input_field' => $input_field})
  2         6  
81             || '';
82             $javascript_validation .= $validation;
83 7   100     25 }
84             }
85 7         25  
86             my $onsubmit_js_error = $self->onsubmit_js_error;
87             if ($onsubmit_js_error) {
88             $onsubmit_js_error = "if (bResult == false) { $onsubmit_js_error; }";
89 2         10 }
90 2 100       6 $self->{data}{'onsubmit'} = "return (function () { var bResult = true; $javascript_validation; $onsubmit_js_error return bResult; })();";
91 1         5  
92             return $self->SUPER::build();
93 2         36 }
94              
95 2         20 ########################################################################
96             # Usage : $form_validation_obj->validate();
97             # Purpose : Validate form input
98             # Returns : true (No ERROR) / false
99             # Parameters : none
100             # Comments : Public
101             # See Also : n / a
102             ########################################################################
103             my $self = shift;
104              
105             if ($self->csrftoken) {
106             $self->validate_csrf() or return 0;
107 10     10 1 110 }
108              
109 10 100       39 my @fieldsets = @{$self->{'fieldsets'}};
110 2 100       6 foreach my $fieldset (@fieldsets) {
111             INPUT_FIELD:
112             foreach my $input_field (@{$fieldset->{'fields'}}) {
113 9         16 my $data = $input_field->{data};
  9         23  
114 9         21 if ($data->{'input'} and $data->{'error'}->{'id'}) {
115             foreach my $input_element (@{$data->{'input'}}) {
116 9         15 if (eval { $input_element->{'input'}->can('value') }
  9         19  
117 49         82 and (not defined $self->get_field_value($input_element->{'id'})))
118 49 100 100     161 {
119 32         49 $self->set_field_error_message($input_element->{'id'}, $self->_localize('Invalid amount'));
  32         74  
120 40 50 33     61 next INPUT_FIELD;
  40         325  
121             }
122             }
123 0         0 }
124 0         0  
125             # Validate each field
126             if ( defined $data->{'validation'}
127             and $data->{'input'}
128             and $data->{'error'}->{'id'})
129             {
130 49 50 66     210 $self->_validate_field({
      33        
131             'validation' => $data->{'validation'},
132             'input_element' => $data->{'input'},
133             });
134             }
135             }
136 32         137 }
137              
138             if ($self->custom_server_side_check_of) {
139             $self->custom_server_side_check_of->();
140             }
141              
142 9 50       179 return ($self->get_has_error) ? 0 : 1;
143 0         0 }
144              
145             my ($self) = @_;
146 9 100       78  
147             if (($self->{__input_csrftoken} // '') eq $self->csrftoken) {
148             return 1;
149             }
150 2     2 1 5  
151             $self->_set_has_error();
152 2 100 50     9 return 0;
153 1         4 }
154              
155             my $self = shift;
156 1         4 my $input_element_id = shift;
157 1         6  
158             return $self->get_field_error_message($input_element_id);
159             }
160              
161 0     0 1 0 ########################################################################
162 0         0 # Usage : $self->_set_has_error();
163             # Purpose : Set has error to indicate form has error and should be
164 0         0 # rebuild again.
165             # Returns : none
166             # Parameters : none
167             # Comments : Private
168             # See Also : n / a
169             ########################################################################
170             my $self = shift;
171              
172             $self->has_error_of(1);
173             return;
174             }
175              
176             ########################################################################
177 11     11   18 # Usage : $form_validation_obj->get_has_error();
178             # Purpose : Check if form has error
179 11         230 # Returns : 0 / 1
180 11         77 # Parameters : none
181             # Comments : Public
182             # See Also : n / a
183             ########################################################################
184             my $self = shift;
185             return $self->has_error_of;
186             }
187              
188             my $self = shift;
189             my $element_id = shift;
190             my $error_message = shift;
191              
192 11     11 1 19 $self->SUPER::set_field_error_message($element_id, $error_message);
193 11         203 if ($error_message) {
194             $self->_set_has_error();
195             }
196             return;
197 10     10 1 16 }
198 10         18  
199 10         16 ########################################################################
200             # Usage : $self->_build_javascript_validation
201 10         39 # ({
202 10 50       23 # 'validation' => $input_field->{'validation'},
203 10         22 # 'input_element' => $input_field->{'input'},
204             # 'error_element_id' => $input_field->{'error'}->{'id'},
205 10         16 # });
206             # Purpose : Create javascript validation code.
207             # Returns : text (Javascript code)
208             # Parameters : $arg_ref:
209             # {
210             # 'validation': ARRAY ref to $input_field->{'validation'}
211             # 'input_element': HASH ref to input element
212             # 'error_element_id': error element id
213             # }
214             # Comments : Private
215             # See Also : build()
216             ########################################################################
217             my $self = shift;
218             my $arg_ref = shift;
219             my $javascript;
220              
221             my $input_field = $arg_ref->{'input_field'};
222              
223             my $data = $input_field->{data};
224             if ( defined $data->{'validation'}
225             and $data->{'input'}
226             and $data->{'error'}->{'id'})
227 7     7   13 {
228 7         12  
229 7         11 my @validations = @{$data->{'validation'}};
230             my $input_element = $data->{'input'};
231 7         14 my $error_element_id = $data->{'error'}->{'id'};
232              
233 7         13 my $input_element_id;
234 7 100 66     47 my $input_element_conditions;
    100 33        
      66        
235              
236             foreach my $input_field (@{$input_element}) {
237             if (defined $input_field->{'id'}) {
238             $input_element_id = $input_field->{'id'};
239 4         7 $javascript .= "var input_element_$input_element_id = document.getElementById('$input_element_id');";
  4         11  
240 4         9 $input_element_conditions .= "input_element_$input_element_id && ";
241 4         7 }
242             }
243 4         8  
244             $javascript .=
245             "var error_element_$error_element_id = document.getElementById('$error_element_id');"
246 4         5 . "document.getElementById('$error_element_id').innerHTML = '';"
  4         9  
247 5 50       12 . "if ($input_element_conditions error_element_$error_element_id) {"
248 5         9 . 'var regexp;'
249 5         13 . 'var bInputResult = true;';
250 5         59  
251             foreach my $validation (@validations) {
252             next
253             unless ($validation->{'type'} =~ /(?:regexp|min_amount|max_amount|checkbox_checked|custom)/);
254             $javascript .= $self->_build_single_javascript_validation($validation, $input_element_id, $error_element_id);
255 4         24 }
256              
257             $javascript .= 'if (!bInputResult)' . '{' . 'bResult = bInputResult;' . '}' . '}';
258              
259             }
260              
261 4         39 # get the general error field (contain only error message without input)
262             elsif ( defined $data->{'error'}
263 10 50       58 and defined $data->{'error'}->{'id'})
264 10         24 {
265             my $error_id = $data->{'error'}->{'id'};
266              
267 4         8 $javascript = "var error_element_$error_id = document.getElementById('$error_id');" . "document.getElementById('$error_id').innerHTML = '';";
268             }
269              
270             return $javascript;
271             }
272              
273             ########################################################################
274             # Usage : $self->_build_single_validation
275 1         4 # ($validation, $input_element_id, $error_element_id);
276             # Purpose : Create javascript validation code for a validation.
277 1         7 # Returns : text (Javascript code)
278             # Parameters : validation, input_element_id, error_element_id
279             # Comments : Private
280 7         29 # See Also : build()
281             ########################################################################
282             my $self = shift;
283             my $validation = shift;
284             my $input_element_id = shift;
285             my $error_element_id = shift;
286              
287             my $javascript = '';
288             my $err_msg = _encode_text($validation->{'err_msg'});
289              
290             # if the id define in the validation hash, meaning input has more than 1 fields, the validation is validated against the id
291             if ($validation->{'id'} and length $validation->{'id'} > 0) {
292             $input_element_id = $validation->{'id'};
293 10     10   18 }
294 10         12  
295 10         15 my $error_if_true = $validation->{error_if_true} ? '' : '!';
296 10         16 my $test = '';
297             if ($validation->{'type'} eq 'regexp') {
298 10         14 my $regexp = $validation->{'regexp'};
299 10         20 $regexp =~ s/(\\|')/\\$1/g;
300             $javascript .=
301             ($validation->{'case_insensitive'})
302 10 100 66     46 ? "regexp = new RegExp('$regexp', 'i');"
303 3         5 : "regexp = new RegExp('$regexp');";
304              
305             $test = qq[${error_if_true}regexp.test(input_element_$input_element_id.value)];
306 10 50       21 }
307 10         15  
308 10 100       37 # Min Max amount checking
    100          
    100          
    50          
309 5         10 elsif ($validation->{'type'} =~ /^(min|max)_amount$/) {
310 5         26 my $op = $1 eq 'min' ? '<' : '>';
311             $test = qq[input_element_$input_element_id.value $op $validation->{amount}];
312 5 100       21 }
313              
314             # checkbox checked checking
315             elsif ($validation->{'type'} eq 'checkbox_checked') {
316 5         13 $test = qq[input_element_$input_element_id.checked === false];
317             }
318              
319             # Custom checking
320             elsif ($validation->{'type'} eq 'custom') {
321 3 100       9 $test = qq[${error_if_true}$validation->{function}];
322 3         11 }
323             $javascript .= qq[if (bInputResult && $test){error_element_$error_element_id.innerHTML = decodeURIComponent('$err_msg');bInputResult = false;}];
324              
325             return $javascript;
326             }
327 1         3  
328             ########################################################################
329             # Usage : $form_validation_obj->set_server_side_checks($custom_server_side_sub_ref);
330             # Purpose : Set custom server side validation
331             # Returns : none
332 1         3 # Parameters : $server_side_check_sub_ref: sub ref
333             # Comments : Public
334 10         31 # See Also : n / a
335             ########################################################################
336 10         44 my $self = shift;
337             my $server_side_check_sub_ref = shift;
338             $self->custom_server_side_check_of($server_side_check_sub_ref);
339             return;
340             }
341              
342             ########################################################################
343             # Usage : $self->_validate_field({
344             # 'validation' => $input_field->{'validation'},
345             # 'input_element' => $input_field->{'input'},
346             # });
347             # Purpose : Server side validation base on type of validation
348 0     0 1 0 # Returns : none
349 0         0 # Parameters : $arg_ref:
350 0         0 # {
351 0         0 # 'validation': ARRAY ref to $input_field->{'validation'}
352             # 'input_element': HASH ref to input element
353             # }
354             # Comments : Private
355             # See Also : validate()
356             ########################################################################
357             my $self = shift;
358             my $arg_ref = shift;
359              
360             my @validations = @{$arg_ref->{'validation'}};
361             my $input_element = $arg_ref->{'input_element'};
362             my $input_element_id;
363             my $field_value;
364              
365             foreach my $validation (@validations) {
366             if ( $validation->{'type'}
367             and $validation->{'type'} =~ /(?:regexp|min_amount|max_amount|checkbox_checked)/)
368             {
369              
370 32     32   50 # The input_element must be an array. so if validation no 'id', then we use the first element's id
371 32         46 # because the array should be just one element.
372             $input_element_id = $validation->{id} || $input_element->[0]{id};
373 32         47  
  32         75  
374 32         53 # Check with whitespace trimmed from both ends to make sure that it's reasonable.
375 32         52 $field_value = $self->get_field_value($input_element_id) || '';
376             # $field_value =~ s/^\s+|\s+$//g;
377             $field_value =~ s/\A\s+//;
378 32         56 $field_value =~ s/\s+\z//;
379 65 100 66     415  
380             if ($validation->{'type'} eq 'regexp') {
381             my $regexp =
382             ($validation->{'case_insensitive'})
383             ? qr{$validation->{'regexp'}}i
384             : qr{$validation->{'regexp'}};
385 61   66     180 if ($validation->{error_if_true} && $field_value =~ $regexp
386             || !$validation->{error_if_true} && $field_value !~ $regexp)
387             {
388 61   100     165 $self->set_field_error_message($input_element_id, $validation->{'err_msg'});
389             return 0;
390 61         507 }
391 61         116 }
392              
393 61 100 100     265 # Min amount checking
    100 100        
    100 66        
      100        
394             elsif ($validation->{'type'} eq 'min_amount' && $field_value < $validation->{'amount'}
395 37 100       300 || $validation->{'type'} eq 'max_amount' && $field_value > $validation->{'amount'})
396             {
397             $self->set_field_error_message($input_element_id, $validation->{'err_msg'});
398 37 100 33     349 return 0;
      66        
      66        
399              
400             } elsif ($validation->{'type'} eq 'checkbox_checked' && !$field_value) {
401 6         20 $self->set_field_error_message($input_element_id, $validation->{'err_msg'});
402 6         21 return 0;
403             }
404             }
405             }
406             return 1;
407             }
408              
409             my $text = shift;
410 3         14  
411 3         9 return unless ($text);
412              
413             # javascript cant load html entities
414 1         4 $text = Encode::encode("UTF-8", HTML::Entities::decode_entities($text));
415 1         4 $text = URI::Escape::uri_escape($text);
416             $text =~ s/(['"\\])/\\$1/g;
417              
418             return $text;
419 22         66 }
420              
421             1;
422              
423 10     10   16 =head1 NAME
424              
425 10 50       18 HTML::FormBuilder::Validation - An extension of the Form object, to allow for javascript-side validation of inputs
426             and also server-side validation after the form is POSTed
427              
428 10         53 =head1 SYNOPSIS
429 10         584  
430 10         244 First, create the Form object. The keys in the HASH reference is the attributes
431             of the form.
432 10         19  
433             # Form attributes require to create new form object
434             my $form_attributes =
435             {
436             'name' => 'name_test_form',
437             'id' => 'id_test_form',
438             'method' => 'post',
439             'action' => "http://www.domain.com/contact.cgi",
440             'class' => 'formObject',
441             };
442             my $form_obj = new HTML::FormBuilder::Validation(data => $form_attributes);
443              
444             my $fieldset = $form_obj->add_fieldset({});
445              
446              
447             =head2 Create the input fields with validation
448              
449             This is quite similar to creating input field in Form object. Likewise you can
450             add validation to HASH reference as the attribute of input field.
451              
452             Below you can see the sample included four types of validation:
453              
454             1. regexp: Just write the reqular expression that should be apply to the value
455              
456             2. min_amount: Needs both type=min_amount and also minimum amount that declared
457             in amount
458              
459             3. max_amount: Just like min_amount
460              
461             4. checkbox_checked: Ensure checkbox is checked by user
462              
463             5. custom: Just the javascript function call with parameters should be given to.
464             It only specifies client side validation.
465              
466             my $input_field_amount =
467             {
468             'label' =>
469             {
470             'text' => 'Amount',
471             'for' => 'amount',
472             'optional' => '0',
473             },
474             'input' =>
475             {
476             'type' => 'text',
477             'id' => 'amount',
478             'name' => 'amount',
479             'maxlength' => 40,
480             'value' => '',
481             },
482             'error' =>
483             {
484             'text' => '',
485             'id' => 'error_amount',
486             'class' => 'errorfield',
487             },
488             'validation' =>
489             [
490             {
491             'type' => 'regexp',
492             'regexp' => '\w+',
493             'err_msg' => 'Not empty',
494             },
495             {
496             'type' => 'regexp',
497             'regexp' => '\d+',
498             'err_msg' => 'Must be digit',
499             },
500             {
501             'type' => 'min_amount',
502             'amount' => 50,
503             'err_msg' => 'Too little',
504             },
505             {
506             'type' => 'max_amount',
507             'amount' => 500,
508             'err_msg' => 'Too much',
509             },
510             {
511             'type' => 'custom',
512             'function' => 'custom_amount_validation()',
513             'err_msg' => 'It is not good',
514             },
515             ],
516             };
517              
518             my $terms_and_condition_checkbox =
519             {
520             'label' =>
521             {
522             'text' => 'I have read & agree to the terms & condition of the site',
523             'for' => 'tnc',
524             },
525             'input' =>
526             {
527             'type' => 'checkbox',
528             'id' => 'tnc',
529             'name' => 'tnc',
530             'value' => '1', # optional
531             },
532             'error' =>
533             {
534             'id' => 'error_tnc',
535             'class' => 'errorfield',
536             },
537             'validation' =>
538             [
539             {
540             'type' => 'checkbox_checked',
541             'err_msg' => 'In order to proceed, you need to agree to the terms & condition',
542             },
543             ],
544             };
545              
546             Below is another example with two different fields. In this matter we need to
547             indicate the id of each field in validation attributes.
548              
549             my $select_curr =
550             {
551             'id' => 'select_text_curr',
552             'name' => 'select_text_curr',
553             'type' => 'select',
554             'options' => '<option value=""></option><option value="USD">USD</option><option value="EUR">EUR</option>',
555             };
556             my $input_amount =
557             {
558             'id' => 'select_text_amount',
559             'name' => 'select_text_amount',
560             'type' => 'text',
561             'value' => ''
562             };
563             my $input_field_select_text =
564             {
565             'label' =>
566             {
567             'text' => 'select_text',
568             'for' => 'select_text',
569             },
570             'input' => [ $select_curr, $input_amount ],
571             'error' =>
572             {
573             'text' => '',
574             'id' => 'error_select_text',
575             'class' => 'errorfield',
576             },
577             'validation' =>
578             [
579             {
580             'type' => 'regexp',
581             'id' => 'select_text_curr',
582             'regexp' => '\w+',
583             'err_msg' => 'Must be select',
584             },
585             {
586             'type' => 'regexp',
587             'id' => 'select_text_amount',
588             'regexp' => '\d+',
589             'err_msg' => 'Must be digits',
590             },
591             {
592             'type' => 'min_amount',
593             'id' => 'select_text_amount',
594             'amount' => 50,
595             'err_msg' => 'Too little',
596             },
597             ],
598             };
599              
600             my $general_error_field =
601             {
602             'error' =>
603             {
604             'text' => '',
605             'id' => 'error_general',
606             'class' => 'errorfield'
607             },
608             };
609              
610             =head2 Adding input fields to form object
611              
612             Here is just add fields to the form object like before.
613              
614             $form_obj->add_field($fieldset_index, $general_error_field);
615             $form_obj->add_field($fieldset_index, $input_field_amount);
616             $form_obj->add_field($fieldset_index, $input_field_select_text);
617              
618             =head2 Define Javascript code to be run, during onsubmit input validation error
619              
620             This javascript code will be run before onsubmit return false
621              
622             $form_obj->onsubmit_js_error("\$('#residence').attr('disabled', true);");
623             $form_obj->onsubmit_js_error('onsubmit_error_disable_fields()');
624              
625             =head2 Custom javascript validation
626              
627             Custom javascript validation should be defined and assigned to the form object.
628             Note that, the name and parameters should be the same as the way you indicate
629             function call in validation attributes.
630              
631             You can see a sample below:
632              
633             my $custom_javascript = qq~
634             function custom_amount_validation()
635             {
636             var input_amount = document.getElementById('amount');
637             if (input_amount.value == 100)
638             {
639             return false;
640             }
641             return true;
642             }~;
643              
644             =head2 Custom server side validation
645              
646             The custom server side validation is quite similar to javascript. A reference to
647             a subrotine should be pass to form object.
648              
649             my $custom_server_side_sub_ref = sub {
650             if ($form_obj->get_field_value('name') eq 'felix')
651             {
652             $form_obj->set_field_error_message('name', 'felix is not allow to use this page');
653             $form_obj->set_field_error_message('error_general', 'There is an error !!!');
654             }
655             };
656              
657             $form_obj->set_server_side_checks($custom_server_side_sub_ref);
658              
659             =head2 Use form object in cgi files
660              
661             Somewhere in cgi files you can just print the result of build().
662              
663             print $form_obj->build();
664              
665             In submit you need to fill form values, use set_input_fields(\%input) and pass
666             %input HASH and then show what ever you want in result of validation. Just like
667             below:
668              
669             if (not $form_obj->validate())
670             {
671             print '<h1>Test Form</h1>';
672             print $form_obj->build();
673             }
674             else
675             {
676             print '<h1>Success !!!</h1>';
677             }
678              
679             code_exit();
680              
681             =head1 Attributes
682              
683             =head2 has_error_of
684              
685             The tag that error happened during validation
686              
687             =head2 custom_server_side_check_of
688              
689             The custom server side subroutine that will be run on server side.
690              
691             =head2 onsubmit_js_error
692              
693             javasript code to run during onsubmit error by javasript validation
694              
695             =head1 METHODS
696              
697             =head2 set_input_fields
698              
699             $form_validation_obj->set_input_fields({username => $username});
700              
701             assign value to the input fields
702              
703             =head2 validate
704              
705             $form_validation_obj->validate();
706              
707             validate form input and return true or false
708              
709             =head2 is_error_found_in
710              
711             $form_validation_obj->is_error_found_in($input_element_id);
712              
713             check the erorr is founded in the input element or not
714              
715             =head2 get_has_error
716              
717             =head2 set_field_error_message
718              
719             =head2 set_server_side_checks
720              
721             =head2 validate_csrf
722              
723             =head1 CROSS SITE REQUEST FORGERY PROTECTION
724              
725             for plain CGI or other framework, read Dancer example below.
726              
727             =head2 CSRF and Dancer
728              
729             =over 4
730              
731             =item * create form HTML and store csrftoken in session
732              
733             my $form = HTML::FormBuilder::Validation->new(data => $form_attributes, csrftoken => 1);
734             ...
735             my $html = $form->build;
736              
737             # save csrf token in session or cookie
738             session(__csrftoken => $form->csrftoken);
739              
740             =item * validate csrftoken on form submit
741              
742             my $csrftoken = session('__csrftoken');
743             my $form = HTML::FormBuilder::Validation->new(data => $form_attributes, csrftoken => $csrftoken);
744             $form->validate_csrf() or die 'CSRF failed.';
745             # or call
746             if ( $form->validate() ) { # it calls validate_csrf inside
747             # Yap! it's ok
748             } else {
749             # NOTE we do not have error for csrf on form HTML build
750             # show form again with $form->build
751             }
752              
753             =back
754              
755             =head2 CSRF and Mojolicious
756              
757             if you're using Mojolicious and have DefaultHelpers plugin enabled, it's simple to add csrftoken in Validation->new as below:
758              
759             my $form = HTML::FormBuilder::Validation->new(data => $form_attributes, csrftoken => $c->csrf_token);
760              
761             Mojolicious $c->csrf_token will handle the session part for you.
762              
763             =head1 AUTHOR
764              
765             Chylli L<mailto:chylli@binary.com>
766              
767             =head1 CONTRIBUTOR
768              
769             Fayland Lam L<mailto:fayland@binary.com>
770              
771             Tee Shuwn Yuan L<mailto:shuwnyuan@binary.com>
772              
773             =head1 COPYRIGHT AND LICENSE
774              
775             =cut