LEMONADE Documentation

Documentation.

Fifteen chapters covering installation, project structure, application development, CLI and production deployment.

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.

Detailed technical documentation on GitHub