The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

HTML::FormBuilder::Validation - An extension of the Form object, to allow for javascript-side validation of inputs and also server-side validation after the form is POSTed

SYNOPSIS

First, create the Form object. The keys in the HASH reference is the attributes of the form.

    # Form attributes require to create new form object
    my $form_attributes =
    {
        'name'     => 'name_test_form',
        'id'       => 'id_test_form',
        'method'   => 'post',
        'action'   => "http://www.domain.com/contact.cgi",
        'class'    => 'formObject',
    };
    my $form_obj = new HTML::FormBuilder::Validation(data => $form_attributes);

    my $fieldset = $form_obj->add_fieldset({});

Create the input fields with validation

This is quite similar to creating input field in Form object. Likewise you can add validation to HASH reference as the attribute of input field.

Below you can see the sample included four types of validation:

1. regexp: Just write the reqular expression that should be apply to the value

2. min_amount: Needs both type=min_amount and also minimum amount that declared in amount

3. max_amount: Just like min_amount

4. checkbox_checked: Ensure checkbox is checked by user

5. custom: Just the javascript function call with parameters should be given to. It only specifies client side validation.

    my $input_field_amount =
    {
        'label' =>
        {
            'text'     => 'Amount',
            'for'      => 'amount',
            'optional' => '0',
        },
        'input' =>
        {
            'type'      => 'text',
            'id'        => 'amount',
            'name'      => 'amount',
            'maxlength' => 40,
            'value'     => '',
        },
        'error' =>
        {
            'text' => '',
            'id'    => 'error_amount',
            'class' => 'errorfield',
        },
        'validation' =>
        [
            {
                'type'    => 'regexp',
                'regexp'  => '\w+',
                'err_msg' => 'Not empty',
            },
            {
                'type'    => 'regexp',
                'regexp'  => '\d+',
                'err_msg' => 'Must be digit',
            },
            {
                'type'    => 'min_amount',
                'amount'  => 50,
                'err_msg' => 'Too little',
            },
            {
                'type'    => 'max_amount',
                'amount'  => 500,
                'err_msg' => 'Too much',
            },
            {
                'type' => 'custom',
                'function' => 'custom_amount_validation()',
                'err_msg' => 'It is not good',
            },
        ],
    };

    my $terms_and_condition_checkbox =
    {
        'label' =>
        {
            'text'     => 'I have read & agree to the terms & condition of the site',
            'for'      => 'tnc',
        },
        'input' =>
        {
            'type'      => 'checkbox',
            'id'        => 'tnc',
            'name'      => 'tnc',
            'value'     => '1',             # optional
        },
        'error' =>
        {
            'id'    => 'error_tnc',
            'class' => 'errorfield',
        },
        'validation' =>
        [
            {
                'type'    => 'checkbox_checked',
                'err_msg' => 'In order to proceed, you need to agree to the terms & condition',
            },
        ],
    };

Below is another example with two different fields. In this matter we need to indicate the id of each field in validation attributes.

    my $select_curr =
    {
        'id'      => 'select_text_curr',
        'name'    => 'select_text_curr',
        'type'    => 'select',
        'options' => '<option value=""></option><option value="USD">USD</option><option value="EUR">EUR</option>',
    };
    my $input_amount =
    {
        'id'    => 'select_text_amount',
        'name'  => 'select_text_amount',
        'type'  => 'text',
        'value' => ''
    };
    my $input_field_select_text =
    {
        'label' =>
        {
            'text'     => 'select_text',
            'for'      => 'select_text',
        },
        'input' => [ $select_curr, $input_amount ],
        'error' =>
        {
            'text'  => '',
            'id'    => 'error_select_text',
            'class' => 'errorfield',
        },
        'validation' =>
        [
            {
                'type' => 'regexp',
                'id'   => 'select_text_curr',
                'regexp'  => '\w+',
                'err_msg' => 'Must be select',
            },
            {
                'type' => 'regexp',
                'id'   => 'select_text_amount',
                'regexp'  => '\d+',
                'err_msg' => 'Must be digits',
            },
            {
                'type' => 'min_amount',
                'id'   => 'select_text_amount',
                'amount'  => 50,
                'err_msg' => 'Too little',
            },
        ],
    };

    my $general_error_field =
    {
        'error' =>
        {
            'text' => '',
            'id' => 'error_general',
            'class' => 'errorfield'
        },
    };

Adding input fields to form object

Here is just add fields to the form object like before.

    $form_obj->add_field($fieldset_index, $general_error_field);
    $form_obj->add_field($fieldset_index, $input_field_amount);
    $form_obj->add_field($fieldset_index, $input_field_select_text);

Define Javascript code to be run, during onsubmit input validation error

This javascript code will be run before onsubmit return false

    $form_obj->onsubmit_js_error("\$('#residence').attr('disabled', true);");
    $form_obj->onsubmit_js_error('onsubmit_error_disable_fields()');

Custom javascript validation

Custom javascript validation should be defined and assigned to the form object. Note that, the name and parameters should be the same as the way you indicate function call in validation attributes.

You can see a sample below:

    my $custom_javascript = qq~
        function custom_amount_validation()
        {
            var input_amount = document.getElementById('amount');
            if (input_amount.value == 100)
            {
                return false;
            }
            return true;
        }~;

Custom server side validation

The custom server side validation is quite similar to javascript. A reference to a subrotine should be pass to form object.

    my $custom_server_side_sub_ref = sub {
        if ($form_obj->get_field_value('name') eq 'felix')
        {
            $form_obj->set_field_error_message('name', 'felix is not allow to use this page');
            $form_obj->set_field_error_message('error_general', 'There is an error !!!');
        }
    };

    $form_obj->set_server_side_checks($custom_server_side_sub_ref);

Use form object in cgi files

Somewhere in cgi files you can just print the result of build().

    print $form_obj->build();

In submit you need to fill form values, use set_input_fields(\%input) and pass %input HASH and then show what ever you want in result of validation. Just like below:

    if (not $form_obj->validate())
    {
        print '<h1>Test Form</h1>';
        print $form_obj->build();
    }
    else
    {
        print '<h1>Success !!!</h1>';
    }

    code_exit();

Attributes

has_error_of

The tag that error happened during validation

custom_server_side_check_of

The custom server side subroutine that will be run on server side.

onsubmit_js_error

javasript code to run during onsubmit error by javasript validation

METHODS

set_input_fields

    $form_validation_obj->set_input_fields({username => $username});

assign value to the input fields

validate

    $form_validation_obj->validate();

validate form input and return true or false

is_error_found_in

    $form_validation_obj->is_error_found_in($input_element_id);

check the erorr is founded in the input element or not

get_has_error

set_field_error_message

set_server_side_checks

validate_csrf

CROSS SITE REQUEST FORGERY PROTECTION

for plain CGI or other framework, read Dancer example below.

CSRF and Dancer

  • create form HTML and store csrftoken in session

        my $form = HTML::FormBuilder::Validation->new(data => $form_attributes, csrftoken => 1);
        ...
        my $html = $form->build;
    
        # save csrf token in session or cookie
        session(__csrftoken => $form->csrftoken);
  • validate csrftoken on form submit

        my $csrftoken = session('__csrftoken');
        my $form = HTML::FormBuilder::Validation->new(data => $form_attributes, csrftoken => $csrftoken);
        $form->validate_csrf() or die 'CSRF failed.';
        # or call
        if ( $form->validate() ) { # it calls validate_csrf inside
            # Yap! it's ok
        } else {
            # NOTE we do not have error for csrf on form HTML build
            # show form again with $form->build
        }

CSRF and Mojolicious

if you're using Mojolicious and have DefaultHelpers plugin enabled, it's simple to add csrftoken in Validation->new as below:

    my $form = HTML::FormBuilder::Validation->new(data => $form_attributes, csrftoken => $c->csrf_token);

Mojolicious $c->csrf_token will handle the session part for you.

AUTHOR

Chylli mailto:chylli@binary.com

CONTRIBUTOR

Fayland Lam mailto:fayland@binary.com

Tee Shuwn Yuan mailto:shuwnyuan@binary.com

COPYRIGHT AND LICENSE