<!--toc--> |
|
## Create form |
## Create a Form |
|
First we create our simple form, create `content.h` file and add header: |
First we create our simple form. Let's create `content.h` file and add header: |
|
#include <cppcms/view.h> |
#include <cppcms/form.h> |
|
Then create a form class derived from `cppcms::form`: |
|
namespace content { |
struct info_form : public cppcms::form { |
|
Then we add widgets to this form: |
|
cppcms::widgets::text name; |
cppcms::widgets::radio sex; |
cppcms::widgets::select marital; |
cppcms::widgets::numeric<double> age; |
cppcms::widgets::submit submit; |
|
Where, `text` is text input field, `radio` is multiple choice field, `select` is drop down list of choices, `number<>` is number of specific type and `submit` is submit button. |
Where, `text` is a text input field, `radio` is a multiple choice field, `select` is a drop down list of choices, `number<>` is a number of specific type and `submit` is a submit button. |
|
Now we create a constructor for our class: |
|
info_form() |
{ |
|
Then we setup an information messages for the form widgets: |
|
name.message("Your Name"); |
sex.message("Sex"); |
marital.message("Marital Status"); |
age.message("Your Age"); |
submit.value("Send"); |
|
Then we register all the widgets withing the form. |
This allows centralized rendering, loading and validation |
of the entire form. |
|
add(name); |
add(sex); |
add(marital); |
add(age); |
add(submit); |
|
Note, `cppcms::form::add` only registers the object |
to the form. It does not transfer ownership on the |
widget. |
|
Now lets setup some values for our selection widgets |
|
sex.add("Male","male"); |
sex.add("Female","female"); |
marital.add("Single","single"); |
marital.add("Married","married"); |
marital.add("Divorced","divorced"); |
|
Note, the first parameter is "display name" and the |
second one is a special key for the choice. |
Note: the first parameter is "display name" and the |
second one is a special key that defines our choice. |
|
Now, let's define some basic restrictions on the fields: |
|
name.non_empty(); |
age.range(0,120); |
|
We make sure that the name is filled and the age |
is in expected range. That's it for our constructor. |
|
And now we can add it to our content class (with some other fields for future use). |
|
struct message : public cppcms::base_content { |
std::string name,state,sex; |
double age; |
info_form info; |
}; |
|
## Form in templates |
|
First we create our output |
First we create our output: |
|
<% if not empty name %> |
<h1>Hello <%= name %></h1> |
<p>You are <%= sex %>, <%= state %></p> |
<p>Your age is <%= age %></p> |
<% else %> |
<h1>Input your details</h1> |
<% end %> |
|
Then we put our form using tag `<% form as_p info %>`: |
|
<form method="post" action="" > |
<% form as_p info %> |
</form> |
|
The flag `as_p` tells to render form `info` using paragraphs. |
|
## Working with form in code: |
|
First we create our content that contains required |
form. |
|
content::message c; |
|
Then we test, if something was send: |
|
if(request().request_method()=="POST") { |
|
If so we load our form and validate it: |
|
c.info.load(context()); |
if(c.info.validate()) { |
|
if the form is valid, we can do anything |
we want. For example setup our content |
fields with appropriate values from the form. |
|
c.name=c.info.name.value(); |
c.sex=c.info.sex.selected_id(); |
c.state=c.info.marital.selected_id(); |
c.age=c.info.age.value(); |
|
We clear it at the end, because we want user to |
put new values |
|
c.info.clear(); |
|
Now we can render our template as usual: |
|
} |
} |
render("message",c); |
|
## Additional Validation |
|
Let's assume that standard widgets checks are not good enough. We can extend our validation manually. |
|
We can add out own restrictions by overriding |
`cppcms::form::validate` member function by adding |
the following code to `content::info_form` |
|
virtual bool validate() |
{ |
if(!form::validate()) |
return false; |
if(marital.selected_id()!="single" |
&& age.value()<18) |
{ |
marital.valid(false); |
return false; |
} |
return true; |
} |
|
First of all we need to check that basic form validation |
is performed by calling `form::validate` then we add |
our own restrictions like for example, martial status |
can be only single for non-adult. |
|
When we detect such situation we mark our widget |
as invalid and return false for entire validation |
process. |
|
## Security Considerations: Cross Site Request Forgery |
|
The straight forward approach to the forms is vulnerable to [Cross Site Request Forgery](/wikipp/en/page/secure_programming#Cross.Site.Request.Forgery..CSRF.) an authorized person is tricked to |
perform an action that he was not expected to do (follow the link for more detail). |
|
In order prevent CSRF every POST form should include |
a special hidden field that holds a session |
specific CSRF token. |
|
So we need to add a small code `<% csrf %>` streight |
after `<form ...>` field to our template: |
|
<form method="post" action="" ><% csrf %> |
<% form as_p info %> |
</form> |
|
And enable `csrf` checks in the [configuration file](/wikipp/en/page/cppcms_1x_config#security.csrf.enable): |
|
"security" : { |
"csrf" : { |
"enable" : true |
} |
} |
|
The `<% csrf %>` command would generate a special hidden input field that inject session specific token |
and handle all tests for you. |
|
In case of detection of CSRF attack the `cppcms::form::load` would throw a `cppcms::request_forgery_error` exception |
|
That would be caught and reported to the logs at higher levels. |
|
**Note:** CSRF token should be used with POST fields only and never GET request method. |
|