Lesson 6.4: Forms and actions in a view
Views that change something receive a form. The kernel turns a pressed button into a named action, hands the
view the posted values, and protects every form against cross-site request forgery with a form token. In this
lesson learners add a small form to the greet view: a visitor types a name, the view validates it and redirects
to the greeting.
At a glance
| Course | Developers |
| Module | Module 6: Modules and views |
| Duration | 55 minutes (15 presenting, 40 exercise) |
| Level | Intermediate |
| Audience | Developers |
| Prerequisites | Lesson 6.3 |
Learning objectives
After this lesson, learners can:
- map a button to an action with
single_post_actionsand its values withpost_action_parameters; - test the action with
$Module->isCurrentAction()and read values with$Module->actionParameter(); - validate input in the view and show an error in the template;
- redirect after a successful post with
$Module->redirectTo(); - explain what the form token (
ezformtoken) does and what the "form has expired" page means.
Trainer's notes
How to present it
Sources: kernel/content/module.php (single_post_actions of edit and copy), the methods isCurrentAction(),
actionParameter() and redirectTo() in lib/ezutils/classes/ezmodule.php, and
"This form has expired".
- Actions (4 minutes). In
module.php,'single_post_actions' => array( 'GreetButton' => 'Greet' )means: a POST with a fieldGreetButtonis the actionGreet.'post_action_parameters' => array( 'Greet' => array( 'Name' => 'GreetName' ) )makes the posted fieldGreetNameavailable as the action parameterName. - In the view (4 minutes).
if ( $Module->isCurrentAction( 'Greet' ) ), then$Module->actionParameter( 'Name' ). Validate; on successreturn $Module->redirectTo( ... ); on failure set an error for the template. - Post, redirect, get (2 minutes). Redirecting after a successful post means a reload does not post again.
- The form token (3 minutes).
ezformtokenadds a hidden fieldezxform_tokento every HTML form the kernel outputs and checks it on every POST. A post without it is refused with the "form has expired" page: nothing is saved. JavaScript that posts must send the token too. - Never trust the input (2 minutes). Trim and check length and characters in PHP; wash in the template.
Common questions
Do I add the token field myself? No, the output filter adds it to forms in the HTML. Ajax code must send it; the
ezformtoken README explains how.
Why redirectTo and not just showing the result? A reload of a page that came from a POST asks the browser to
post again; a redirect turns it into a normal page view.
Can I use $_POST directly? Use eZHTTPTool::instance()->postVariable() or the action parameters; they are what
the rest of the kernel uses and what other developers expect.
Pitfalls
- A button name that is not in
single_post_actions. The view sees no action; nothing happens. - Testing with a page opened before a restart. An old page may carry an old token: reload the form first.
- A redirect to an address built from input. Redirect to your own view; never to an address taken from the form (Safe redirects).
Hands-on exercise
On the training installation, in extension/mysite_hello. Signed in as an administrator, or with the Anonymous
policy of lesson 6.3.
Extend the view in
modules/hello/module.php:$ViewList['greet'] = array( 'functions' => array( 'greet' ), 'script' => 'greet.php', 'params' => array( 'Name' ), 'unordered_params' => array( 'times' => 'Times' ), 'single_post_actions' => array( 'GreetButton' => 'Greet' ), 'post_action_parameters' => array( 'Greet' => array( 'Name' => 'GreetName' ) ) );Add the action handling at the start of
modules/hello/greet.php, after the opening comment:$error = false; if ( $Module->isCurrentAction( 'Greet' ) ) { $posted = trim( (string)$Module->actionParameter( 'Name' ) ); if ( $posted === '' || mb_strlen( $posted ) > 40 ) { $error = 'Please type a name of 1 to 40 characters.'; } else { return $Module->redirectTo( '/hello/greet/' . rawurlencode( $posted ) ); } }and pass it to the template:
$tpl->setVariable( 'error', $error );.Add the form to
design/standard/templates/hello/greet.tpl:if $error<p class="error">$error|wash</p>/if <form method="post" action='/hello/greet'|ezurl> <label for="greet-name">Name</label> <input id="greet-name" type="text" name="GreetName" value="" /> <input type="submit" name="GreetButton" value="Greet" /> </form>Check the files with
php -landeztemplatecheck.php; clear theini,global_iniand template caches.Open
/hello/greet, type a name and press Greet.Send the form empty; read the error.
View the page source of the form and find the hidden field
ezxform_token.In the browser's developer tools, delete the hidden token field, then send the form: read the "form has expired" page.
Commit the changes.
Expected result
- Step 5 redirects to
/hello/greet/<name>and greets the name. - Step 6 shows "Please type a name of 1 to 40 characters." above the form.
- Step 7: an
<input type="hidden" name="ezxform_token" ...>inside the form. - Step 8: the form expired page; nothing is processed.
- The trainer checks one learner's form in the browser's developer tools.
Quiz
- What does
'single_post_actions' => array( 'GreetButton' => 'Greet' )do? - Which method tells the view that the action
Greetwas posted? A.actionParameter()B.isCurrentAction()C.redirectTo()D.currentAction()only - Why redirect after a successful post?
- What does the form token protect against?
- Where must the error message be washed?
Answers
- A POST with the field
GreetButtonbecomes the actionGreet. - B.
$Module->isCurrentAction( 'Greet' ). - So a reload does not post the form again (post, redirect, get).
- Cross-site request forgery: another site making the browser post a form to yours.
- In the template, where it is printed:
{$error|wash}.
Further reading
- "This form has expired": form token refusals.
- Safe redirects: redirect targets from user input.
- Security standard: the project's security rules for code.
Related pages
- Module 6: Modules and views
- Developers: course overview
- Trainers: start here
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.