Les groupes
Environnement de développement
Pour cet exercice, vous allez publier vos pages dans le contexte suivant.
FTP
- Protocole : FTP Chiffrement TLS
- Nom d’hôte : b2.binr.fr
- Nom d’utilisateur : ftp-b2
- Mot de passe : ftp-ecvb2!!33$
- Répertoire personnel : le répertoire qui porte votre prénom (sans majuscule ni accent)
MySQL
phpMyAdmin
- URL : https://db.binr.fr/
- Utilisateur : ecvb2
- Mot de passe : DBecvb2!!
- Nom de la base de données : formations_ecv_[prenom]
PHP
- Hôte : localhost
- Utilisateur : ecvb2
- Mot de passe : DBecvb2!!
- Nom de la base de données : formations_ecv_[prenom]
URL
Pour voir votre site, vous pouvez passer par cette page d’index :
https://b2.binr.fr/
Vous pouvez accèderez à votre site dans un navigateur directement grâce à l’URL :
https://b2.binr.fr/[prenom]/
Fonctionnalités d’un espace membres
C’est la première question que nous devons nous poser : qu’est-ce que nous souhaitons faire concrètement ?
Vous êtes probablement habitués aux espaces membres sur d’autres sites.
Vous savez donc qu’un espace membres nécessite au minimum les éléments suivants :
- une page d’inscription,
- une page de connexion,
- une page de déconnexion.
Auxquels s’ajouteront :
- une page de récupération de mot de passe,
- une page de modification des informations personnelles.
Côté base de données
Pour commencer, nous allons créer la table MySQL qui stockera les membres de notre site.
La table des membres
Qu’est-ce qui caractérise un membre ? Essayons de voir ce que nous avons besoin de stocker au minimum pour créer la table :
- un pseudonyme,
- un mot de passe,
- une adresse e-mail,
- une date d’inscription.
Je vous propose donc de créer une table nommée membres
avec les champs suivants :
id (int 11, primary, auto_increment)
;pseudo (varchar 255)
;pass (varchar 255)
;email (varchar 255)
;date_inscription (date)
.
Ces champs sont résumés sur la figure suivante qui présente la table une fois créée sous phpMyAdmin.

La problématique du mot de passe
Un de ces champs mérite une attention particulière : celui qui stocke le mot de passe. En effet, lorsqu’ils s’inscriront, vos visiteurs enverront en toute confiance un mot de passe à votre site.
Il est très probable qu’ils utilisent le même mot de passe sur de nombreux autres sites. Bien que ce soit une très mauvaise habitude en matière de sécurité (idéalement, il faudrait utiliser un mot de passe différent par site), ce cas de figure est hélas extrêmement fréquent.
Sachant cela, vous avez une certaine obligation morale et éthique en tant que webmasters : vous ne devez pas stocker les mots de passe de vos visiteurs en clair dans la base. Si celle-ci tombait entre de mauvaises mains (cela pourrait arriver dans un cas critique, comme le piratage de votre site, ce que je ne vous souhaite pas), une personne aurait accès à tous les mots de passe de vos membres et pourrait s’en servir pour voler leurs comptes sur d’autres sites !
La solution sera d’utiliser le hachage. C’est une fonction qui transforme n’importe quel texte en un nombre hexadécimal qui représente le mot de passe mais qui est illisible, comme le montre la figure suivante.

La particularité du hachage est qu’il fonctionne dans un seul sens : il est impossible de retrouver le mot de passe d’origine une fois qu’il a été haché. De plus, un hash (nom donné à la version hachée du mot de passe) est unique : il correspond à un et un seul mot de passe.
Vous stockerez la version hachée du mot de passe, qui sera donc passé à la moulinette par la fonction password_hash
. Lorsqu’un visiteur voudra se connecter, il vous enverra son mot de passe que vous hacherez à nouveau et que vous comparerez avec celui stocké dans la base de données. Si les deux mots de passe hachés sont identiques, alors cela signifie que le visiteur a rentré le même mot de passe que lors de son inscription.
Les pages
Nous n’allons pas écrire le code de ces pages mais nous allons passer en revue ce qu’il faut savoir pour les réaliser correctement.
La page d’inscription
La page d’inscription sera un formulaire constitué de quatre champs :
- pseudonyme souhaité ;
- mot de passe ;
- confirmation du mot de passe (pour éviter les erreurs de saisie) ;
- adresse e-mail.
Il est recommandé de limiter autant que possible le nombre d’informations demandées. Le visiteur souhaite pouvoir s’inscrire très rapidement. S’il tombe sur une page avec de nombreux champs à remplir, il y a de fortes chances qu’il laisse tomber. Laissez-le remplir les autres champs (comme sa signature, sa messagerie instantanée et sa date de naissance) dans un second temps, lorsqu’il sera inscrit.
Avant d’enregistrer l’utilisateur dans la base de données, il faudra penser à faire un certain nombre de vérifications.
- Le pseudonyme demandé par le visiteur est-il libre ? S’il est déjà présent en base de données, il faudra demander au visiteur d’en choisir un autre.
- Les deux mots de passe saisis sont-ils identiques ? S’il y a une erreur, il faut inviter le visiteur à rentrer à nouveau le mot de passe.
- L’adresse e-mail a-t-elle une forme valide ? Vous pouvez utiliser une expression régulière pour le vérifier.
Si toutes ces conditions sont remplies, on peut insérer l’utilisateur dans la base de données.
Dans l’idéal, on passerais par une étape supplémentaire : la confirmation par email de la création du compte .
La page de connexion
Une fois le membre créé, il doit pouvoir se connecter sur votre site. Pour cela, nous utiliserons le système de sessions qui est mis à notre disposition par PHP et que nous avons appris à utiliser plus tôt dans ce cours.
Habituellement, on demande au moins le pseudonyme (ou login) et le mot de passe du membre. Pour lui faciliter la vie, on peut lui proposer une option de connexion automatique qui lui évitera d’avoir à se connecter de nouveau à chaque visite du site (figure suivante).
La page qui reçoit les données du formulaire de connexion doit vérifier le mot de passe en le comparant à celui stocké dans la base avec la fonction password_verify
. Cette fonction va en fait hasher le mot de passe de l’utilisateur qui vient de se connecter et le comparer à celui qui était stocké en base de données.
S’il existe un membre qui a le même pseudonyme et le même mot de passe haché, alors on autorise la connexion et on peut créer les variables de session. Sinon, on renvoie une erreur indiquant que le pseudonyme ou le mot de passe est invalide.
Désormais, sur toutes les pages du site, on pourra vérifier que l’utilisateur est connecté grâce à la présence des variables $_SESSION
.
Si le membre souhaite être reconnecté automatiquement (ce qu’il est conseillé de faire uniquement sur un ordinateur personnel, et non sur un ordinateur partagé avec d’autres personnes !), je vous invite à créer deux cookies qui stockeront respectivement :
- le pseudonyme ;
- le mot de passe haché.
Ainsi, si un visiteur non connecté qui possède ces deux cookies se présente, vous n’aurez qu’à vérifier si un membre correspond à ces informations en base de données et vous pourrez le connecter automatiquement, sans qu’il ait eu à utiliser le formulaire de connexion. Là encore, on prend une certaine mesure de sécurité en stockant le mot de passe haché dans un cookie et non le vrai mot de passe.
La page de déconnexion
Au bout d’un certain temps d’inactivité, la session du membre est automatiquement détruite et il se retrouve déconnecté. S’il charge à nouveau une page du site, il apparaîtra donc déconnecté, à moins qu’il ait activé la connexion automatique qui aura pour effet de le reconnecter immédiatement et de manière transparente grâce à ses cookies.
Si la déconnexion est automatique au bout d’un certain temps (le timeout), il faut quand même proposer un lien de déconnexion. La page de déconnexion devra supprimer le contenu de $_SESSION
, mettre fin au système de sessions (en appelant session_destroy()
) et supprimer les cookies de connexion automatique s’ils existent.
Déroulement des développements
Organisation des fichiers
- www [Répertoire web racine]
- _inc [Répertoire des fichiers de configuration et d’initialisation]
- init.php [Session, Base de données, Droits de l’utilisateur]
- _partials [Répertoire des inclusions PHP correspondants à des « morceaux » de page]
- footer.php
- header.php
- traitements [Répertoire des scripts de traitements php (données des formulaires…)]
- inscription.php
- identification.php
- informations.php
- deconnexion.php
- contenu.php [Page de contenu réservé aux membres]
- deconnexion.php [Page de succès de déconnexion]
- identification.php [Page du formulaire de login]
- index.php [Page d’accueil]
- information.php [Page d’édition des données personnelles]
- inscription.php [Page du formulaire d’inscription]
- succes.php [Page de succès d’inscription]
- _inc [Répertoire des fichiers de configuration et d’initialisation]
Bootstrap
Pour intégrer le front-office nous allons nous appuyer sur la bibliothèque bootstrap.
Dans la page index.php, on va ajouter les appels à la feuille de style et au JavaScript de bootstrap, comme indiqué dans la documentation : https://getbootstrap.com/docs/5.3/getting-started/introduction
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Accueil – TP Espace Membres</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
</body>
</html>
Ensuite, nous ajoutons le code HTML correspondant à notre menu de navigation, issu de code proposé sur la page dédiée de la doc : https://getbootstrap.com/docs/5.3/components/navbar/
Le code proposé dans la doc :
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
</li>
</ul>
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
Le code adapté à notre projet et intégré à notre page index.php :
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Accueil – TP Espace Membres</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<header>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="index.php">Espace membres</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#menu_principal" aria-controls="menu_principal" aria-expanded="false" aria-label="Navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="menu_principal">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="index.php">Accueil</a>
</li>
<li class="nav-item">
<a class="nav-link" href="inscription.php">Inscription</a>
</li>
<li class="nav-item">
<a class="nav-link" href="identification.php">Connexion</a>
</li>
<li class="nav-item">
<a class="nav-link" href="contenu.php">Page réservée</a>
</li>
<li class="nav-item">
<a class="nav-link" href="informations.php">Modifier mes informations</a>
</li>
<li class="nav-item">
<a class="nav-link" href="deconnexion.php">Déconnexion</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container mt-5">
<h1>Page d'accueil</h1>
<p>Contenu de la page d'accueil</p>
</div>
<footer class="py-1 border-top fixed-bottom bg-body">
<p class="text-muted mb-0 text-center">© 2024-2025 ECV Bordeaux</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
</body>
</html>
Les inclusions
Certaines parties de cette page seront communes à toutes les pages du site. Afin d’en faciliter la compréhension et la maintenance, nous allons extraire ces portions de code communes dans des fichiers dédiés, que nous intègrerons ensuite dans nos pages.
Le header
On crée par exemple un fichier header.php qu’on positionne dans un sous dossier « _partials » :
<header>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="index.php">Espace membres</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#menu_principal" aria-controls="menu_principal" aria-expanded="false" aria-label="Navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="menu_principal">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="index.php">Accueil</a>
</li>
<li class="nav-item">
<a class="nav-link" href="inscription.php">Inscription</a>
</li>
<li class="nav-item">
<a class="nav-link" href="identification.php">Connexion</a>
</li>
<li class="nav-item">
<a class="nav-link" href="contenu.php">Page réservée</a>
</li>
<li class="nav-item">
<a class="nav-link" href="informations.php">Modifier mes informations</a>
</li>
<li class="nav-item">
<a class="nav-link" href="deconnexion.php">Déconnexion</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
Le footer
Idem pour le footer :
<footer class="py-1 border-top fixed-bottom bg-body">
<p class="text-muted mb-0 text-center">© 2024-2025 ECV Bordeaux</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
La page index.php
On peut alors inclure ces pages « partielles » dans notre page principale index.php, qui devienyt alors :
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Accueil – TP Espace Membres</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<?php include ('_partials/header.php'); ?>
<div class="container mt-5">
<h1>Page d'accueil</h1>
<p>Contenu de la page d'accueil</p>
</div>
<?php include ('_partials/footer.php'); ?>
</body>
</html>
Le problème de la page active dans le menu
Les variables globales de PHP nous permettent de connaitre la page en cours de consultation :
<?php
$page = $_SERVER['PHP_SELF'];
?>
On peut donc conditionner l’utilisation de la classe css « active
» et l’attribut aria-current
dans les liens de notre menu :
<?php
if ( str_contains($page, 'index.php') ) {
echo 'class="active"';
}
?>
Notre fichier _partials/header.php menu devient donc :
<?php
$page = $_SERVER['PHP_SELF'];
?>
<header>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="index.php">Espace membres</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#menu_principal" aria-controls="menu_principal" aria-expanded="false" aria-label="Navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="menu_principal">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link <?php if (str_contains($page, 'index')) echo 'active'; ?>" <?php if (str_contains($page, 'index')) echo 'aria-current="page"'; ?> href="index.php">Accueil</a>
</li>
<li class="nav-item">
<a class="nav-link <?php if (str_contains($page, 'inscription')) echo 'active'; ?>" <?php if (str_contains($page, 'inscription')) echo 'aria-current="page"'; ?> href="inscription.php">Inscription</a>
</li>
<li class="nav-item">
<a class="nav-link <?php if (str_contains($page, 'identification')) echo 'active'; ?>" <?php if (str_contains($page, 'identification')) echo 'aria-current="page"'; ?> href="identification.php">Connexion</a>
</li>
<li class="nav-item">
<a class="nav-link <?php if (str_contains($page, 'contenu')) echo 'active'; ?>" <?php if (str_contains($page, 'contenu')) echo 'aria-current="page"'; ?> href="contenu.php">Page réservée</a>
</li>
<li class="nav-item">
<a class="nav-link <?php if (str_contains($page, 'informations')) echo 'active'; ?>" <?php if (str_contains($page, 'informations')) echo 'aria-current="page"'; ?> href="informations.php">Modifier mes informations</a>
</li>
<li class="nav-item">
<a class="nav-link <?php if (str_contains($page, 'deconnexion')) echo 'active'; ?>" <?php if (str_contains($page, 'deconnexion')) echo 'aria-current="page"'; ?> href="deconnexion.php">Déconnexion</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
Le formulaire d’inscription
Côté HTML
On s’appuie encore une fois sur bootstrap : https://getbootstrap.com/docs/5.3/forms/overview/
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Inscription – TP Espace Membres</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body class="mb-5">
<?php include ('_partials/header.php'); ?>
<div class="container mt-5 tinyform text-center">
<h1>Inscription</h1>
<p><a href="identification.php">Vous avez déjà un compte ? Identifiez-vous !</a></p>
</div>
<div class="container pb-5 tinyform">
<form action="traitements/inscription.php" method="post">
<p class="form-group">
<label for="email">Votre adresse e-mail</label>
<input type="email" class="form-control" id="email" aria-describedby="emailHelp" placeholder="exemple@domaine.com" name="email" required value="">
</p>
<p class="form-group">
<label for="pseudo">
Choisissez un pseudo
</label>
<span class="input-group">
<span class="input-group-text">@</span>
<input type="text" class="form-control" id="pseudo" placeholder="Pseudonyme" name="pseudo" value="" required>
</span>
</p>
<p class="form-group">
<label for="pass">Choisissez un mot de passe</label>
<input type="password" class="form-control" id="pass" name="pass" required value="">
</p>
<p class="form-group">
<label for="pass_confirm">Confirmez le mot de passe</label>
<input type="password" class="form-control" id="pass_confirm" name="pass_confirm" required value="">
</p>
<p>
<button type="submit" class="btn btn-primary">Confirmer mon inscription</button>
</p>
<p>
<small class="text-muted">
Tous les champs sont obligatoires.<br>
<strong>Vos données personnelles sont importantes. Nous ne les partageons avec personne.</strong>
</small>
</p>
</form>
</div>
<?php include ('_partials/footer.php'); ?>
</body>
</html>
Le traitement du formulaire
<?php
/*
* 1. Récupérer les données
* 2. Effectuer les contrôles
* 3. Si KO →
* 3.1 : stocker les informations saisies par l'internaute en variables de session
* 3.2 : stocker les erreurs en variables de session
* 3.3 : rediriger vers le formulaire
* 4. Si OK →
* 4.1 : Enregistrer en base de données
* 4.2 : Identifier l'utilisateur
* 4.2 : Rediriger l'internaute
*/
/*
* Initialisation de la session
*/
session_start();
/*
* Connexion à la base de données
*/
$servername = 'localhost';
$username = 'espace_membre';
$password = 'espace_membre33!';
$dbname = 'espace_membres';
try {
$conn = new PDO('mysql:host=' . $servername . ';dbname=' . $dbname . ';', $username, $password);
} catch (PDOException $e) {
echo 'Connexion échouée : ' . $e->getMessage();
}
/*
* 1. récupération des données saisies (et mise en session)
*/
foreach($_POST as $key => $value) {
$$key = $value;
$_SESSION[$key] = $value;
}
/*
* 2. Contrôles
*/
unset($_SESSION['erreur']);
$error = [];
// Contrôles de surface
if ( empty($pseudo) ) { $error['pseudo'] = 'Veuillez choisir un pseudo.'; }
if ( empty($pass) ) { $error['pass'] = 'Veuillez choisir un mot de passe.'; }
if ( empty($pass_confirm) ) { $error['pass_confirm'] = 'Veuillez confirmer le mot de passe.'; }
if ( empty($email) ) { $error['email'] = 'Veuillez fournir une adresse e-mail.'; }
if ( !empty( $error ) ) {
$_SESSION['erreur'] = $error;
header('Location: ../inscription.php');
exit();
}
// Contrôles de cohérence
if( $pass != $pass_confirm ) {
$error['pass_confirm'] = 'Le mot de passe et sa confirmation ne correspondent pas.';
}
if ( !preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/", $email) ) {
$error['email'] = 'L\'adresse email indiquée ne semble pas conforme, merci de vérifier qu\'elle est bien de la forme "exemple@domaine.com".';
}
if ( !empty( $error ) ) {
$_SESSION['erreur'] = $error;
header('Location: ../inscription.php');
exit();
}
// Contrôles d'unicité du membre (e-mail)
$sql = "SELECT * FROM `membres` WHERE `email` = :email";
$pdoStatement = $conn->prepare($sql);
$pdoStatement->bindParam(':email', $email, PDO::PARAM_STR);
$res = $pdoStatement->execute();
if ( $res ) {
$result = $pdoStatement->fetchAll();
if ( count( $result ) > 0 ) {
$error['email'] = 'Cet email est déjà pris. Si c\'est vous, vous pouvez <a href="identification.php">vous identifier</a>. Sinon veuillez en choisir un autre.';
}
}
// Contrôles d'unicité du membre (pseudo)
$sql = "SELECT * FROM `membres` WHERE `pseudo` = :pseudo";
$pdoStatement = $conn->prepare($sql);
$pdoStatement->bindParam(':pseudo', $pseudo, PDO::PARAM_STR);
$res = $pdoStatement->execute();
if ( $res ) {
$result = $pdoStatement->fetchAll();
if ( count( $result ) > 0 ) {
$error['pseudo'] = 'Cet identifiant est déjà pris. Si c\'est vous, vous pouvez <a href="identification.php">vous identifier</a>. Sinon veuillez en choisir un autre.';
}
}
if ( !empty( $error ) ) {
$_SESSION['erreur'] = $error;
header('Location: ../inscription.php');
exit();
}
// Si tous les contrôles sont ok, on insère l'utilisateur dans notre base de données
$sql = "INSERT INTO `membres` (`pseudo`, `email`, `pass`, `date_inscription`) VALUES (:pseudo, :email, :pass, NOW())";
$pdoStatement = $conn->prepare($sql);
$encrypted_pass = password_hash($pass, PASSWORD_DEFAULT);
$pdoStatement->bindParam(':pseudo', $pseudo, PDO::PARAM_STR);
$pdoStatement->bindParam(':email', $email, PDO::PARAM_STR);
$pdoStatement->bindParam(':pass', $encrypted_pass, PDO::PARAM_STR);
$pdoStatement->execute();
// puis on l'identifie, pour qu'il n'ai pas à le faire via le formulaire d'identification
$_SESSION['pseudoUtilisateur'] = $pseudo;
$_SESSION['passwordUtilisateur'] = $encrypted_pass;
// on efface les données de session liées à la saisie de l'internaute
foreach($_POST as $key => $value) {
unset($_SESSION[$key]);
}
unset($_SESSION['erreur']);
// enfin on le redirige vers un message de succès
header('Location: ../succes.php');
exit;
Le retour sur le formulaire, en cas d’erreur
La reprise des informations déjà saisies dans le formulaire par l’utilisateur
Une fois les données issues du formulaire traitées, les données issues du formulaire sont stockées en variable de session. On peut donc les retrouver en utilisant les variables de session, du type $_SESSION['email']
:
<input type="email" name="email" value="<?php if ( isset($_SESSION['email']) ) { echo $_SESSION['email']; } ?>">
L’affichage des erreurs dans le formulaire
Une fois les données issues du formulaire traitées, les erreurs et les messages associés sont stockées dans la variable de session $_SESSION['erreur']
.
S’il y en a, on peut donc afficher un message d’erreur en haut du formulaire :
<?php
if ( isset($_SESSION['erreur']) && !empty($_SESSION['erreur']) ) {
echo '<div class="alert" role="alert">'
. '<h5>Erreur, le formulaire n\'a pas été envoyé.</h5>'
. '</div>';
}
?>
Et, champ par champ, mettre en exergue les champs qui sont en erreur :
- en ajoutant une classe css qui permettra de les distinguer graphiquement,
- en ajoutant un message explicite, indiquant l’erreur à l’utilisateur, et aussi la manière dont il peut la corriger
<p class="form-group <?php if ( isset($_SESSION['erreur']) && !empty($_SESSION['erreur']) && array_key_exists('email', $_SESSION['erreur']) ) { ?>alert alert-danger<?php } ?>">
<label for="email">Votre adresse e-mail <?php if ( isset($_SESSION['erreur']) && !empty($_SESSION['erreur']) && array_key_exists('email', $_SESSION['erreur']) ) { echo '<br><span class="erreur">' . $_SESSION['erreur']['email'] . '</span>'; } ?></label>
<input type="email" class="form-control" id="email" aria-describedby="emailHelp" placeholder="exemple@domaine.com" name="email" required value="<?php if ( isset($_SESSION['email']) ) echo $_SESSION['email']; ?>">
</p>
Authentification d’un utilisateur
Connaitre le statut de l’utilisateur
Afin de savoir si l’utilisateur est connecté, nous allons nous appuyer sur deux variables de session, le pseudo et le mot de passe, qui sera stocké chiffré :
$_SESSION['pseudoUtilisateur']
$_SESSION['passwordUtilisateur']
Plusieurs conditions pour que le visiteur soit considéré comme identifié sur le site :
- Les variables de session doivent exister
- Le pseudo enregistré en variable de session existe bien dans notre base
- Le mot de passe stocké en variable de session correspond bien ç celui stock en base de données
Ce qui peut se traduire en PHP :
$is_logged = false;
if ( isset( $_SESSION['pseudoUtilisateur'] ) && isset( $_SESSION['passwordUtilisateur'] ) ) {
$sql = "SELECT * FROM `membres` WHERE `pseudo` = :pseudo";
$pdoStatement = $conn->prepare($sql);
$pdoStatement->bindParam(':pseudo', $_SESSION['pseudoUtilisateur'], PDO::PARAM_STR);
$res = $pdoStatement->execute();
if ( $res ) {
$result = $pdoStatement->fetchAll();
if ( count( $result ) > 0 ) {
$DBpass = $result[0]['pass'];
if ($_SESSION['passwordUtilisateur'] == $DBpass ) {
$is_logged = true;
}
}
}
}
L’état de la variable PHP $is_logged
nous indique le statut du visiteur :
false
: s’il n’est pas connectétrue
: s’il est correctement identifié et connecté
Utiliser ce statut à bon escient
Pour adapter le menu
Utilisateur non connectés :
- Accueil
- Inscription
- Connexion
Utilisateurs connectés :
- Accueil
- Page de contenu réservé
- Modifier mes informations
- Déconnexion
On peut donc ajuster le menu en conditionnant l’affichage des liens :
<?php if ( !isset($is_logged) || !$is_logged ) { ?>
<li>
<a href="inscription.php">Inscription</a>
</li>
<li>
<a href="identification.php">Connexion</a>
</li>
<?php } else { ?>
<li>
<a href="contenu.php">Page réservée</a>
</li>
<li>
<a href="informations.php">Modifier mes informations</a>
</li>
<li>
<a href="deconnexion.php">Déconnexion</a>
</li>
<?php } ?>
Pour rediriger le visiteur si nécessaire
Si l’utilisateur n’est pas connecté et qu’il atterrit par hasard sur la page du formulaire de modification de ses informations personnelles, c’est alors une erreur et il doit être redirigé, par exemple vers la page d’identification.
<?php
if ( ! $is_logged ) {
header( 'Location: ./identification.php');
exit;
}
?>
Connecter un internaute
Lorsqu’un internaute s’inscrit ou s’identifie, il faut enregistrer ses données en variable de session :
$_SESSION['pseudoUtilisateur'] = $pseudo;
$_SESSION['passwordUtilisateur'] = password_hash($pass, PASSWORD_DEFAULT);
Déconnecter un internaute
Pour déconnecter un internaute, il suffit de supprimer ces variables de session :
unset( $_SESSION['pseudoUtilisateur'] );
unset( $_SESSION['passwordUtilisateur'] );
Traitement des données issues du formulaire d’identification
<?php
include ('../_inc/init.php');
/*
* 1. récupération des données saisies (et mise en session)
*/
foreach($_POST as $key => $value) {
$$key = $value;
$_SESSION[$key] = $value;
}
/*
* 2. Contrôles
*/
unset($_SESSION['erreur']);
$error = [];
// Contrôles de surface
if ( empty($pseudo) ) { $error['pseudo'] = 'Veuillez saisir votre pseudo.'; }
if ( empty($pass) ) { $error['pass'] = 'Veuillez saisir votre mot de passe.'; }
if ( !empty( $error ) ) {
$_SESSION['erreur'] = $error;
header('Location: ../identification.php');
exit();
}
/*
* 3. Vérification et identification
*/
$sql = "SELECT * FROM `membres` WHERE `pseudo` = :pseudo";
$pdoStatement = $conn->prepare($sql);
$pdoStatement->bindParam(':pseudo', $pseudo, PDO::PARAM_STR);
$res = $pdoStatement->execute();
if ( $res ) {
$result = $pdoStatement->fetchAll();
if ( count( $result ) > 0 ) {
$DBpass = $result[0]['pass'];
if (password_verify($pass, $DBpass)) {
$_SESSION['pseudoUtilisateur'] = $pseudo;
$_SESSION['passwordUtilisateur'] = $DBpass;
$is_logged = true;
// on efface les données de session liées à la saisie de l'internaute
foreach($_POST as $key => $value) {
unset($_SESSION[$key]);
}
unset($_SESSION['erreur']);
// enfin on le redirige vers un message de succès
header('Location: ../index.php');
exit;
}
}
}
$_SESSION['erreur'] = ['Erreur d\'identification. <br>Veuillez vérifier vos informations.'];
header('Location: ../identification.php');
exit();
Fichier de paramétrage et d’initialisation
/_inc/_init.php
<?php
/*
* Initialisation de la session
*/
session_start();
/*
* Connexion à la base de données
*/
$servername = 'localhost';
$username = 'espace_membre';
$password = 'espace_membre33!';
$dbname = 'espace_membres';
try {
$conn = new PDO('mysql:host=' . $servername . ';dbname=' . $dbname . ';', $username, $password);
} catch (PDOException $e) {
echo 'Connexion échouée : ' . $e->getMessage();
}
/*
* Vérification des droits de l'utilisateur
*/
$is_logged = false;
if ( isset( $_SESSION['pseudoUtilisateur'] ) && isset( $_SESSION['passwordUtilisateur'] ) ) {
$sql = "SELECT * FROM `membres` WHERE `pseudo` = :pseudo";
$pdoStatement = $conn->prepare($sql);
$pdoStatement->bindParam(':pseudo', $_SESSION['pseudoUtilisateur'], PDO::PARAM_STR);
$res = $pdoStatement->execute();
if ( $res ) {
$result = $pdoStatement->fetchAll();
if ( count( $result ) > 0 ) {
$DBpass = $result[0]['pass'];
if ( $_SESSION['passwordUtilisateur'] == $DBpass ) {
$is_logged = true;
}
}
}
}