retour
01/03
section 01
Validation cote serveur
Connectez-vous pour sauvegarder votre progression et acceder aux quiz
Se connecterLa validation cote serveur est la seule vraie validation. La validation JavaScript (cote client) ameliore l'experience utilisateur mais peut etre contournee. Le serveur est le dernier rempart.
Classe de validation
php<?php
namespace App\Service;
class Validator
{
private array $errors = [];
public function validate(array $data, array $rules): bool
{
$this->errors = [];
foreach ($rules as $field => $fieldRules) {
$value = $data[$field] ?? null;
foreach ($fieldRules as $rule) {
$error = $this->checkRule($field, $value, $rule);
if ($error !== null) {
$this->errors[$field][] = $error;
}
}
}
return empty($this->errors);
}
private function checkRule(string $field, mixed $value,
string $rule): ?string
{
// required
if ($rule === 'required' && (is_null($value)
|| trim((string)$value) === '')) {
return "Le champ $field est obligatoire.";
}
// email
if ($rule === 'email' && $value !== null
&& !filter_var($value, FILTER_VALIDATE_EMAIL)) {
return "Le champ $field doit etre un email valide.";
}
// min:N
if (str_starts_with($rule, 'min:')) {
$min = (int) substr($rule, 4);
if ($value !== null && strlen((string)$value) < $min) {
return "Le champ $field doit faire au moins $min caracteres.";
}
}
// max:N
if (str_starts_with($rule, 'max:')) {
$max = (int) substr($rule, 4);
if ($value !== null && strlen((string)$value) > $max) {
return "Le champ $field ne doit pas depasser $max caracteres.";
}
}
// numeric
if ($rule === 'numeric' && $value !== null
&& !is_numeric($value)) {
return "Le champ $field doit etre un nombre.";
}
return null;
}
public function getErrors(): array
{
return $this->errors;
}
public function getFirstError(string $field): ?string
{
return $this->errors[$field][0] ?? null;
}
}Utilisation dans un formulaire d'inscription
php<?php
session_start();
$validator = new Validator();
$errors = [];
$old = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$old = $_POST; // Garder les valeurs pour re-remplir le formulaire
$isValid = $validator->validate($_POST, [
'nom' => ['required', 'min:2', 'max:100'],
'email' => ['required', 'email'],
'password' => ['required', 'min:8'],
'confirm' => ['required'],
]);
// Validation supplementaire
if ($_POST['password'] !== $_POST['confirm']) {
$errors['confirm'] = 'Les mots de passe ne correspondent pas.';
$isValid = false;
}
if ($isValid && empty($errors)) {
// Nettoyer les donnees
$nom = htmlspecialchars(trim($_POST['nom']));
$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
// Verifier que l'email n'existe pas deja
$stmt = $pdo->prepare(
"SELECT id FROM users WHERE email = :email"
);
$stmt->execute(['email' => $email]);
if ($stmt->fetch()) {
$errors['email'] = 'Cet email est deja utilise.';
} else {
// Inserer en BDD
$stmt = $pdo->prepare(
"INSERT INTO users (nom, email, password)
VALUES (:nom, :email, :password)"
);
$stmt->execute([
'nom' => $nom,
'email' => $email,
'password' => $password,
]);
$_SESSION['success'] = 'Inscription reussie !';
header('Location: login.php');
exit;
}
} else {
$errors = array_merge($errors, $validator->getErrors());
}
}
?>
<form method="POST" novalidate>
<div>
<label for="nom">Nom</label>
<input type="text" name="nom" id="nom"
value="<?= htmlspecialchars($old['nom'] ?? '') ?>"
required minlength="2">
<?php if (isset($errors['nom'])): ?>
<p class="error">
<?= htmlspecialchars(
is_array($errors['nom'])
? $errors['nom'][0]
: $errors['nom']
) ?>
</p>
<?php endif; ?>
</div>
<div>
<label for="email">Email</label>
<input type="email" name="email" id="email"
value="<?= htmlspecialchars($old['email'] ?? '') ?>"
required>
<?php if (isset($errors['email'])): ?>
<p class="error">
<?= htmlspecialchars(
is_array($errors['email'])
? $errors['email'][0]
: $errors['email']
) ?>
</p>
<?php endif; ?>
</div>
<div>
<label for="password">Mot de passe</label>
<input type="password" name="password" id="password"
required minlength="8">
</div>
<div>
<label for="confirm">Confirmer le mot de passe</label>
<input type="password" name="confirm" id="confirm" required>
<?php if (isset($errors['confirm'])): ?>
<p class="error">
<?= htmlspecialchars($errors['confirm']) ?>
</p>
<?php endif; ?>
</div>
<button type="submit">S'inscrire</button>
</form>Pattern PRG : Apres un POST reussi, redirigez toujours avec
header('Location: ...') suivi de exit. C'est le pattern Post/Redirect/Get qui empeche la re-soumission du formulaire en cas de rechargement de page (F5).// voir aussi