File Coverage

blib/lib/HTML/FormBuilder/Validation.pm
Criterion Covered Total %
statement 162 173 93.6
branch 52 62 83.8
condition 38 57 66.6
subroutine 20 22 90.9
pod 4 8 50.0
total 276 322 85.7


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