Chapter 10 of 15
Forms, validation, and CSRF.
Validate input once, escape output, and protect state-changing HTTP requests with a synchronizer token.
Input validation
Inject FormValidation, obtain an array from the parsed body, and build a small schema. After validate(), use isValid(), errors(), and validated().
Form validation
<?php
$payload = is_array($request->getParsedBody()) ? $request->getParsedBody() : [];
$result = $this->validator
->field('email', 'E-mail')
->required()
->email()
->maxLength(150)
->field('message', 'Message')
->required()
->maxLength(5000)
->validate($payload);
if (!$result->isValid()) {
return $this->responses->json(['errors' => $result->errors()], 422);
}The fluent schema resets after validation. Move repeated validation into an application service or an explicit ValidationSchema.
CSRF protection
Attach CsrfMiddleware to a state-changing route. Add the token to HTML forms with $this->csrfField(); AJAX requests use the X-CSRF-Token header.
Route and view
<?php
use Lemonade\Framework\Security\Csrf\CsrfMiddleware;
$router
->postNamed('contact.store', '/contact', ControllerAction::for(ContactController::class, 'store'))
->middleware(CsrfMiddleware::class);
?>
<form method="post" action="<?= e($this->url('contact.store')) ?>">
<?= $this->csrfField() ?>
<button type="submit">Send</button>
</form>An invalid token returns 419 without running the controller. Never transport the token in a query string.