Ajouter

Nous ajoutons un fichier utilisateur/create.php à la racine du site, contenant un formulaire permettant d’ajouter un nouvel utilisateur.
Méthode : utilisateur/create.php
Dans un premier temps, le fichier affiche un formulaire pour ajouter un utilisateur.
Ensuite, il vérifie si le formulaire a été soumis et traite l’ajout de l’utilisateur.
// ==============================// CONNEXION À LA BASE DE DONNÉES// ==============================$db = require '../bdd.php';
// ==============================// INCLUSION HELPERS// ==============================require '../helpers.php';
// ==============================// TRAITEMENT DU FORMULAIRE// ==============================if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['ajouter'])) {
// ------------------------------ // RÉCUPÉRATION DES DONNÉES // ------------------------------ // Nettoyage des champs texte - supprime les espaces superflus$nom = trim($_POST['nom'] ?? '');
$prenom = trim($_POST['prenom'] ?? '');
// Cast en entier pour le champ âge$age = (int) ($_POST['age'] ?? 0);
// Slug qui servira à la fois pour l’URL et le nom du fichier photo // La fonction slug() transforme une chaîne en format compatible URL // (par exemple : "Jean Dupont" → "jean-dupont") // On s’assure que ce slug est unique : si un enregistrement existe déjà, // un suffixe numérique sera ajouté pour créer un slug distinct$baseSlug = slug("$prenom-$nom");
$slug = $baseSlug;
$i = 1;
// Requête SQL avec paramètres nommés$sql = "SELECT * FROM utilisateurs WHERE slug = :slug";
// Préparation de la requête (sécurité contre les injections SQL)$stmt = $db->prepare($sql);
// Exécution de la requête avec le slug actuel$stmt->execute(['slug' => $slug]);
// Tant qu’un enregistrement existe avec ce slug, on ajoute un suffixe numériquewhile ($stmt->fetch()) {
$slug = "{$baseSlug}_{$i}";
$stmt->execute(['slug' => $slug]);
$i++;
}
// ------------------------------ // GESTION DE LA PHOTO // ------------------------------ // Dossier relatif de stockage des photos // par rapport à la racine du projet$relDir = '../';
// Dossier de stockage des photos$photoDir = 'images/photos/';
// Création du dossier s’il n’existe pasif (!is_dir($relDir . $photoDir)) {
mkdir($relDir . $photoDir, 0755, true);
}
// Cas 1 : une photo a été uploadée if (isset($_FILES['photo']) &&
is_uploaded_file($_FILES['photo']['tmp_name'])
) { // Récupération de l’extension du fichier (en minuscule)$extension = strtolower(
pathinfo($_FILES['photo']['name'], PATHINFO_EXTENSION)
);
// Nom final du fichier photo$photo = "{$photoDir}{$slug}.{$extension}";
// Déplacement du fichier temporaire vers le dossier photos move_uploaded_file($_FILES['photo']['tmp_name'],
"{$relDir}{$photo}"
);
// Cas 2 : aucune photo envoyée → image par défaut } else { // Nom de la photo par défaut$photo = "{$photoDir}{$slug}.png";
// Copie de l’image générique copy("{$relDir}{$photoDir}photo.png",
"{$relDir}{$photo}"
);
}
// ------------------------------ // INSERTION EN BASE DE DONNÉES // ------------------------------ // Requête SQL avec paramètres nommés$sql = "INSERT INTO utilisateurs
(nom, prenom, age, slug, photo) VALUES (:nom, :prenom, :age, :slug, :photo)"; // Préparation de la requête (sécurité SQL)$statement = $db->prepare($sql);
// Exécution avec liaison automatique des paramètres // compact() crée un tableau associatif : // ['nom' => $nom, 'prenom' => $prenom, ...]$statement->execute(compact('nom', 'prenom', 'age', 'slug', 'photo'));
// ------------------------------ // REDIRECTION // ------------------------------ // Redirection après succès (évite la resoumission du formulaire)header('location:../utilisateur/index.php');
exit;}
// ==============================// VARIABLES POUR LA VUE// ==============================$page_base = '../';
$page_title = 'Ajouter un utilisateur';
$page_styles = ['utilisateur', 'form'];
<html lang='fr'>
require "$page_base/head.php"
<body>
require "$page_base/header.php"
<main>
<h1>Ajouter</h1>
<form action='' method='post' enctype='multipart/form-data'>
<fieldset>
<legend>Identité</legend>
<ul>
<li>
<label for="nom">Nom</label>
<input type='text' name='nom' id='nom'>
</li>
<li>
<label for="prenom">Prénom</label>
<input type='text' name='prenom' id='prenom'>
</li>
<li>
<label for="age">Age</label>
<input type='text' name='age' id='age'>
</li>
</ul>
</fieldset>
<fieldset>
<legend>Photo</legend>
<ul>
<li>
<label for="photo">Photo</label>
<input type='file' name='photo' id='photo'>
</li>
</ul>
</fieldset>
<section class="form-buttons">
<button type="submit" name="ajouter">Ajouter</button>
<a href="utilisateur/index.php" class="btn-cancel">Annuler</a>
</section>
</form>
</main>
require "$page_base/footer.php"
</body>
</html>
<form action="" method="post" enctype="multipart/form-data">
Le formulaire transmet les données via la méthode POST et autorise l’envoi de fichiers grâce à l’attribut enctype.
La validation s’effectue sur la même URL que celle du fichier en cours, l’attribut action étant laissé vide.
<input type="text" name="nom">
L’attribut name définit le nom de la variable transmise lors de l’envoi du formulaire.
Dans la page de traitement, ces valeurs sont accessibles via la superglobale $_POST.
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['ajouter']))
Pour traiter les données, on commence par vérifier si le formulaire a été soumis en cliquant sur le bouton « Ajouter ».
$nom = $_POST['nom'] ?? ""
La valeur envoyée par le formulaire est récupérée depuis $_POST.
Si la clé 'nom' n’existe pas (par exemple si le formulaire n’a pas encore été soumis), une chaîne vide est utilisée par défaut.
INSERT INTO utilisateurs (nom, prenom, age, slug, photo) VALUES (:nom, :prenom, :age, :slug, :photo)
Requête SQL permettant d’ajouter un utilisateur.
compact('nom', 'prenom', 'age', 'slug', 'photo')
Crée un tableau associatif regroupant les informations de l’utilisateur : ['nom' => $nom, 'prenom' => $prenom, 'age' => $age, 'slug' => $slug, 'photo' => $photo].
Méthode : helpers.php
Un fichier helpers.php est un fichier qui contient des fonctions utilitaires globales réutilisables dans tout le projet.
Il permet :
d’éviter de répéter du code
de centraliser des fonctions communes
d’améliorer la lisibilité
d’organiser le projet proprement
On l’inclut généralement au début du projet et on y met uniquement des fonctions générales, indépendantes d’une page précise.
// permet de générer un slug à partir d'une chaîne de caractères// un slug doit être url-friendly, c'est à dire sans espaces ni caractères spéciaux// ex: "Jean Dupont" → "jean-dupont"function slug(string $string): string
{ // Supprimer les espaces inutiles$string = trim($string);
// Convertir en minuscules (UTF-8 compatible)$string = mb_strtolower($string, 'UTF-8');
// Remplacer les caractères accentués$string = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $string);
// Remplacer tout ce qui n’est pas lettre ou chiffre par un tiret$string = preg_replace('/[^a-z0-9]+/', '-', $string);
// Supprimer les tirets multiples$string = preg_replace('/-+/', '-', $string);
// Supprimer les tirets en début et finreturn trim($string, '-');
}
// permet d'afficher une ou plusieurs variables de manière lisible dans le navigateurfunction dumpVar(mixed $data): void
{if (is_null($data)) {
echo '<span class="dump-null">null</span>';
return;}
if (is_bool($data)) {
echo '<span class="dump-bool">' . ($data ? 'true' : 'false') . '</span>';
return;}
if (is_int($data) || is_float($data)) {
echo '<span class="dump-number">' . $data . '</span>';
return;}
if (is_string($data)) {
echo '<span class="dump-string">"' . htmlspecialchars($data) . '"</span>';
return;}
if (is_array($data)) {
echo '<details open>';
echo '<summary class="dump-type">array: ' . count($data) . '</summary>';
foreach ($data as $key => $value) {
echo '<div>';
echo '<span class="dump-key">' . htmlspecialchars((string)$key) . '</span> => ';
dumpVar($value);
echo '</div>';
}
echo '</details>';
return;}
if (is_object($data)) {
echo '<details open>';
echo '<summary class="dump-type">object: ' . get_class($data) . '</summary>';
dumpVar(get_object_vars($data));
echo '</details>';
return;}
var_dump($data);
}
function dump(mixed ...$data): void
{echo "<style>
.dump-wrapper { background: #2d2d2d; color: #f8f8f2; font-family: Consolas, Monaco, monospace; font-size: 14px; padding: 15px; border-radius: 6px; margin: 15px 0; overflow-x: auto;}.dump-wrapper hr { border: 0; border-top: 1px solid #444; margin: 10px 0;}.dump-wrapper details { margin-left: 15px;}.dump-wrapper summary { cursor: pointer; color: #66d9ef; font-weight: bold;}.dump-key { color: #a6e22e;}.dump-string { color: #e6db74;}.dump-number { color: #ae81ff;}.dump-bool { color: #fd971f;}.dump-null { color: #75715e; font-style: italic;}.dump-type { color: #66d9ef; font-style: italic;}</style><div class='dump-wrapper'>";foreach ($data as $item) {
dumpVar($item);
echo '<hr>';
}
echo '</div>';
}
function dd(mixed ...$data)
{dump(...$data);
die;}
La fonction slug()
Elle permet de transformer une chaîne de caractères en slug, c’est-à-dire un texte compatible avec une URL.
Exemple : "Jean Dupont" → "jean-dupont"
Suppression des espaces inutiles
trim($string);Passage en minuscules
mb_strtolower($string);
Suppression des accents
iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $string);
Remplacement des caractères non alphanumériques par des tirets
preg_replace('/[^a-z0-9]+/', '-', $string);Suppression des tirets multiples
preg_replace('/-+/', '-', $string);Suppression des tirets au début et à la fin
trim($string, '-');
La Fonction dumpVar()
Permet d'afficher proprement une variable dans le navigateur.
Elle améliore var_dump() en rendant l’affichage plus lisible, notamment pour les tableaux.
Exemple : dumpVar($value);
La fonction dump()
Elle permet d’afficher plusieurs variables en une seule fois.
Le ...$data signifie que la fonction accepte un nombre illimité d’arguments.
dump() est une fonction de confort qui repose sur dumpVar().
Exemple : dump($value, $liste);
La fonction dd()
Elle permet d'afficher une variable et arrêter immédiatement le script.
dd($user);
Equivalent à :
dump($user);
die;
Très utile pour le débogage.
Exemple : dd($value);
Méthode : css/utilisateur-form.css
/* ====== Formulaire - Mobile First ====== */form {display: flex;
flex-direction: column;
gap: 1rem;
align-items: center;
}
/* ====== Fieldset ====== */fieldset {border: 1px solid #ccc;
border-radius: 6px;
padding: 1rem;
width: 100%;
max-width: 350px;
display: flex;
flex-direction: column;
gap: 0.8rem;
}
legend {font-weight: bold;
}
/* ====== Liste de champs ====== */fieldset ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.6rem;
}
fieldset li {
display: flex;
flex-direction: column;
/* label au-dessus du champ */gap: 0.3rem;
align-items: flex-start;
}
label {font-weight: 500;
}
input[type="text"],
input[type="file"] {
padding: 0.4rem 0.5rem;
border: 1px solid #aaa;
border-radius: 4px;
font-size: 1rem;
width: 100%;
}
/* ====== Boutons empilés sur mobile ====== */.form-buttons {display: flex;
flex-direction: column;
gap: 0.5rem;
width: 80%;
max-width: 600px;
}
/* Boutons */button[type="submit"],
.btn-cancel {padding: 0.6rem 1.2rem;
font-size: 1rem;
border-radius: 4px;
cursor: pointer;
border: none;
text-decoration: none;
width: 100%;
}
button[type="submit"] {
background-color: #0066cc;
color: #fff;
}
button[type="submit"]:hover {
background-color: #004999;
}
.btn-cancel {background-color: #ccc;
color: #000;
}
.btn-cancel:hover {
background-color: #aaa;
}
/* ====== Desktop / Large Screens ====== */@media (min-width: 600px) {
fieldset li {
flex-direction: row;
/* label devant le champ */align-items: center;
}
label {width: 120px;
/* largeur fixe pour alignement */margin-bottom: 0;
}
input[type="text"],
input[type="file"] {
width: auto;
flex: 1 1 auto;
}
.form-buttons {flex-direction: row;
/* boutons côte à côte */gap: 1rem;
}
.form-buttons>* {margin: 1rem;
}
fieldset {width: 80%;
max-width: 600px;
}
}