<!--toc--> |
|
## Create a Form |
|
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 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 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: |
|
<% 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. |
<!--toc-->
|
|
## Create a Form
|
|
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 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 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:
|
|
<% 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.
|
|