<!--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
|
Note: the first parameter is the text that will be displayed, 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.
|
|
---
|
|
← [Views Inheritance][prev]
|
| [Top](#maincontent)
|
| [Sessions][next] →
|
|
[toc]: /wikipp/en/page/cppcms_1x
|
[prev]: /wikipp/en/page/cppcms_1x_tut_templates_inheritance
|
[next]: /wikipp/en/page/cppcms_1x_sessions |