YBET informatique

Rue Albert 1er, 7

6810 Pin - Chiny

Route Arlon - Florenville

(/fax: 061/32.00.15

Les formations sur Internet

YBET Forum webmaster Créer son site soi-même

24. Programmation et gestion des cookies avec PHP

1. Créer les cookies - 2. Exemple d'utilisation: login - mot de passe - 3. Vérification de l'utilisateur - 4. Gestion des utilisateurs dans les pages - 5. Pour conclure

Nous venons d'apprendre les différentes méthodes de suivi utilisateurs. Comme première partie, commençons par les cookies. La gestion est similaire à la méthode POST ou GET des formulaires. La fonction qui permet de créer des cookies en PHP: setcookie($nom,$valeur,$expiration)

D'autres options supplémentaires peuvent être utilisées depuis PHP5. La commande doit débuter le script PHP, avant tout affichage en utilisant les commandes print(), echo(), ... et avant le code HTML, sinon, le message d'erreur "Cannot send cookies -headers alredy sent by ..." est affiché. Sans date d'expiration, il est automatiquement supprimé en fermant la fenêtre du navigateur.

Si vous placez un cookie à l'aide de la fonction Setcookie, le prochain passage de l'utilisateur sur la page créera une variable tableau $_COOKIE, similaire aux constantes $_GET, $_POST ou $_SERVER déjà rencontrées. Pour récupérer le contenu d'un cookie créé, on va simplement utiliser $_COOKIE['nom_cookie'].

1. Créer les cookies

Les compteurs utiliseront cette variable pour distinguer les visiteurs, les sessions utilisateurs permettront de suivre un utilisateur une fois celui-ci connecté ou même de permettre la connexion automatique.

<?php
if(!isset($_COOKIE['ybet']))
{
Setcookie('ybet','site');
Print ("Première visite <br>");
}else{
Print ("Vous avez déjà visité la page<br>");

echo $_COOKIE['ybet']."<br>";
}
?>

Analysons le code ci-dessus. Lors du démarrage du fichier, nous testons l'existence de la variable $_COOKIE['ybet']. Si elle n'existe pas, nous créons le cookies. Sinon, nous affichons le message "Vous avez déjà visité la page". Remarquez que nous n'avons pas mis de date d'expiration. Dès lors, une fois le visiteur passé, il sera toujours renseigné comme "déjà visité".

Attention, le script suivant ne fonctionne pas et renvoie le message: Warning: Cannot modify header information - headers already sent by (output started at c:\program files\easyphp1-8\www\cookie.php puisque l'affichage est déjà démarré par une commande Print();.

<?php
if(!isset($_COOKIE['ybet']))
{
Setcookie('ybet','site');
Print ("Première visite");
}else{
Print ("Vous avez déjà visité la page");
Setcookie('ybet','site');
}
?>

La méthode la plus courante consiste à mettre une date d'expiration du cookies. C'est un paramètre optionnel de la commande.

Setcookie("ybet","site",time()+3600);

Cette option commence par la fonction time() pour récupérer la date courante au format timestamp (nombre de secondes depuis le 01/01/1970) et d'ajouter la durée du cookies en secondes. Dans le cas ci-dessus, l'expiration du cookies se fait après 1 heure (3600 secondes).

1.1. La gestion complète en pratique.

Pour un débutant en programmation PHP, le principal problème lié à la fonction setcookie est son envoi au navigateur AVANT tout affichage mais aussi avant d'envoyer l'entête HTML. C'est bien le comment faire que nous allons voire ici. Voyons le schéma ci-dessus qui reprend un formulaire de connexion intégré dans une page.

<?php
if (ISSET($_POST['login'])
{
  // boucle qui détecte la demande de connexion, vérifie les données de l'utilisateur et crée le cookie si les codes sont corrects
} ?>

<head>
<!-- contenu du header -->
</head>

<body>
// le contenu affiché

<form>
  // le formulaire de connexion (login)
</form>

// suite du contenu affiché

</body>

En tout début, on va vérifier si une variable $_POST de connexion est envoyée. Pour le premier affichage ou si le visiteur ne rentre pas de codes d'accès, cette boucle ne sera pas utilisée. Le programme va simplement afficher le contenu avec un formulaire. Si le visiteur entre un code d'accès (login + mot de passe), la variable $_POST existe et le tests est exécuté.

En pratique, prenons un petit exemple pour créer un simple cookie (sans vérification des données, juste que le formulaire est utilisé). On a simplement ajouté en fin de fichier un affichage du fichier s'il existe. Les commentaires sont suffisamment explicite pour comprendre les différentes parties

<?php

// --------------- début du tests de connexion, création du fichier le cas échéant
if (isset ($_POST["connexion"]))
{
$nom=ADDSLASHES($_POST['nom']);
$password=$_POST['mot_passe'];
setcookie ('ybet','connexion',time()+3600);
// on crée le cookie en cas de connexion
}
// --------------- Fin du du tests de connexion
?>

<!-- début du header en HTML -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta http-equiv="Content-Language" content="fr">
<title>Exercice sur les cookies</title>
</head>
<body>
<!-- fin du header en HTML, début du contenu -->
<p>Bonjour, bienvenu sur notre petit exercice</p>
<!--  ---------- Formulaire de connexion  -->
<form method="POST">
<p>Adresse mail (nom utilisateur): <input type="text" name="nom" size="30"><br>
Mot de passe: <input type="password" name="mot_passe" size="20"></p>
<input type="submit" value="Se connecter" name="Connexion"><br>
</form>
<!-- ----------- Fin du formulaire de connexion -->

<!-- ----------  Suite du contenu en html -->
<p>Pour vous connecter, remplissez le formulaire ci-dessus</p>
<?php
// ------------- test de la présence du cookie et affichage d'un petit message le cas échéant
if (ISSET($_COOKIE['ybet']))
{
echo "Cookie créé";
// on affiche un texte si le cookie existe
}
?>
</body>

Ici, le formulaire est auto invoquant, on revient au même fichier. Dans le cas ou le formulaire envoie vers un autre fichier, c'est strictement identique. Le premier test n'est pas effectué sur la page de départ mais bien sur la page d'arrivée

<!-- FICHIER de Départ: header et contenu en HTML -->
<?php
// ---------- Formulaire de connexion
$form="<form method=\"POST\" action=\"connexion.php\">
<p>Adresse mail (nom utilisateur): <input type=\"text\" name=\"nom\" size=\"30\">
Mot de passe: <input type=\"password\" name=\"mot_passe\" size=\"20\">
<input type=\"submit\" value=\"Se connecter\" name=\"Connexion\">
</form>";
echo $form;
// ----------- Fin du formulaire de connexion
?>
<!-- ----------  Suite du contenu en html -->
<p>Pour vous connecter, remplissez le formulaire ci-dessus</p>
</body>

Et sur le fichier d'arrivée, on affiche en fin de page le contenu du cookie

<?php
// ------------------------ fichier connexion.php, on récupère les valeurs par $_POST
if (isset ($_POST["Connexion"]))
{
$nom=ADDSLASHES($_POST['nom']);
$password=$_POST['mot_passe'];
setcookie ('ybet','connexion',time()+3600);
// on crée le cookie en cas de connexion
}
// --------------- Fin du du tests de connexion
?>
<!-- ----------  Contenu HTM et PHP -->
<?php
// ------------- test de la présence du cookie et affichage d'un petit message le cas échéant
if (ISSET($_COOKIE['ybet']))
{
echo "Cookie créé";
// on affiche un texte si le cookie existe
}
?>
</body>

1.2. Un petit problème courant.

Certains serveurs sont configuré en UFT-8 (c'est un standard Unicode pour encoder les caractères). Dans ce cas, le contenu est bien envoyé mais il n'est pas correctement récupéré par le serveur à cause de caractères supplémentaires. Normalement la commande Setcookie doit être exécutée AVANT l'header. En cas de serveur gérant l'UTF-8, l'envoi d'une ligne supplémentaire doit être exécutée avant:

<?PHP
Setcookie("ybet","site",time()+3600);
?>

<html>
<head>
<meta http-equiv="Content-Type" Content="text/html; charset= utf-8>

devient

<?PHP
header ("Content-Type:text/html; charset=utf-8>
Setcookie("ybet","site",time()+3600);
?>

<html>
<head>

1.3. Le cookie est bien créé?

Différents problèmes peuvent faire qu'il n'est pas créé (problème de programmation, configuration du php.ini sur le serveur ou même refus par le visiteur). Pour les refus, la méthode standard est d'envoyer simplement un cookie de tests et de le récupérer immédiatement après. S'il n'est pas présent, c'est le refus.

Il y a une méthode plus facile: la fonction setcookie renvoie une variable booléenne (True ou false).

<?PHP
$valeur= Setcookie("ybet","site",time()+3600);

if (!$valeur)
{
  // faux
  echo "Cookie non créé";

?>

<html>
<head>

3. Exemple d'utilisation: login - mot de passe

Nous allons utiliser les cookies pour sauvegarder un nom d'utilisateur suivi d'un mot de passe. Dans cet exemple, nous allons simplement envoyer dans un seul fichier $login."-pw-".mot_passe. Cette solution ne doit pas être utilisée dans une réel développement puisqu'il est très facile à un utilisateur (mais surtout à un programme parasite implanté dans le PC du visiteur) de lire le contenu de ces fichiers textes. L'utilisateur se connecte avec son login - mot de passe. Une case à cocher lui permet d'être reconnu directement par le site Internet à sa prochaine connexion. 

Débutons par un petit formulaire permettant à l'utilisateur de se connecter:

<form method="POST">

<p>Nom utilisateur: <input type="text" name="login" size="20"></p>

<p>Mot de passe: <input type="password" name="password" size="20"></p>

<p>Mémoriser la connexion: <input type="checkbox" name="memo[1]" value="ON"> </p>

<p><input type="submit" value="Envoyer" name="B1"></p>

</form>

Remarquez que le mots de passe n'est pas de type texte, mais password. Les caractères affichés seront "cachés" lors de la frappe. En deuxième, nous utilisons un champ de formulaire de type "checkbox". PHP les analyse comme des variables de type tableau, ils ne sont pas passés par $_POST mais bien comme valeur de matrice. En plus, si la case n'est pas cochée, la variable tableau n'est pas envoyée.

Nous allons l'insérer dans un fichier php auto-invocant.

<?php
if (isset($_POST['B1']))
{
// à ce stade, nous ne vérifions pas si l'utilisateur existe
$login=addslashes($_POST['login']);
$password= addslashes($_POST['password']);
if (isset($memo[0]))
{
$memo=$memo[0];
}else{
$memo="";
}
echo $login." ".$password." ".$memo;
}

$form="<form method=\"POST\"><p>Nom utilisateur: <input type=\"text\" name=\"login\" size=\"20\"></p>
<p>Mot de passe: <input type=\"password\" name=\"password\" size=\"20\"></p>
<p>Mémoriser la connexion: <input type=\"checkbox\" name=\"memo[]\" value=\"ON\"> </p>
<p><input type=\"submit\" value=\"Envoyer\" name=\"B1\"></p>
</form>";
echo $form;
?>

La partie checkbox vérifie si effectivement la matrice est définie. Dans le cas contraire, on lui donne valeur nulle.

Il nous reste à créer le cookies utilisateur. Si la case est cochée, nous lui donnons une durée de 10 jours (c'est un exemple), sinon, une heure, le temps de la navigation. Nous utilisons une simple fonction conditionnelle si.

<?php
if (isset($_POST['B1']))
{
// à ce stade, nous ne vérifions pas si l'utilisateur existe
$login=addslashes($_POST['login']);
$password= addslashes($_POST['password']);
if (isset($memo[0]))
{
$memo=$memo[0];
}else{
$memo="";
}
if ($memo=="")
{
Setcookie('ybet',$login."-pw-".$password,time()+3600);
}else{
Setcookie('ybet',$login."-pw-".$password,time()+864000);
}
}
$form="<form method=\"POST\"><p>Nom utilisateur: <input type=\"text\" name=\"login\" size=\"20\"></p>
<p>Mot de passe: <input type=\"password\" name=\"password\" size=\"20\"></p>
<p>Mémoriser la connexion: <input type=\"checkbox\" name=\"memo[]\" value=\"ON\"> </p>
<p><input type=\"submit\" value=\"Envoyer\" name=\"B1\"></p>
</form>";
echo $form;
?>

Remarque: la partie affichage va remplacer le cookies à chaque passage du nom utilisateur dans la partie suivante.

Il nous reste à récupérer le cookies sur chaque page pour vérifier l'utilisateur.

3. Vérification de l'utilisateur

Avant d'envoyer le cookies, nous allons vérifier si l'utilisateur existe. Pour cela, nous allons utiliser la table member créée dans le chapitre 14. Nous ne vérifions finalement que le login (champ username) et le mot de passe (champ password). Cette partie va s'insérer juste avant l'envoi des cookies.

De nouveau, nous utilisons le fichier start.php pour débuter la connexion sur la base de donnée. Un utilisateur doit être préalablement créé dans la table.

<?php
/* vérification login - mot de passe.

$login reprend le nom utilisateur
$password, le mot de passe
$memo, sauvegarde cookies 10 jours.

*/
$login="YBET";
$password="ybet";
require('include/start.php');
$requete="SELECT * FROM member where username='$login' and password='$password'";
$valeur=mysql_query($requete);
$ligne=mysql_num_rows($valeur);
if ($ligne==0)
{
echo"Utilisateur inconnu";
}else{
echo"Utilisateur connu";
}
?>

Ce petit programme ne fait qu'afficher "Utilisateur connu" s'il est déjà enregistré dans la table MySql et "Utilisateur inconnu s'il n'est pas encore enregistré. Il nous reste à l'insérer dans le programme ci-dessus de gestion des cookies. Remarque, nous utilisons également une variable Memo suivi d'un timestamp pour la durée de connexion.

<?php
if (isset($_POST['B1']))
{
// à ce stade, nous ne vérifions pas si l'utilisateur existe
$login=addslashes($_POST['login']);
$password= addslashes($_POST['password']);
if (isset($memo[0]))
{
$memo=$memo[0];
}else{
$memo="";
}
// echo $login." ".$password." ".$memo;
// Vérification dans la table member
if(!mysql_connect('localhost','root')){
Echo'Connection Impossible';
exit();
}
Mysql_select_db('ybet');
$requete="SELECT * FROM member where username='$login' and password='$password'";
$valeur=mysql_query($requete);
$ligne=mysql_num_rows($valeur);
if ($ligne==0)
{
echo"Utilisateur inconnu";
die('<meta http-equiv="refresh" content="3; URL=inscription.php">');
}else{
//echo"Utilisateur connu";
if ($memo=="")
{
Setcookie('ybet',$login."-pw-".$password."memo".$memo,time()+3600);
}else{
Setcookie('ybet',$login."-pw-".$password."memo".$memo,time()+864000);

}
echo"Bonjour ".$login.", vous êtes maintenant connecté";
die('<meta http-equiv="refresh" content="3; URL=index.php">');
}
}
$form="<form method=\"POST\"><p>Nom utilisateur: <input type=\"text\" name=\"login\" size=\"20\"></p>
<p>Mot de passe: <input type=\"password\" name=\"password\" size=\"20\"></p>
<p>Mémoriser la connexion: <input type=\"checkbox\" name=\"memo[]\" value=\"ON\"> </p>
<p><input type=\"submit\" value=\"Envoyer\" name=\"B1\"></p>
</form>";
echo $form;
?>

Si l'utilisateur est connu, nous insérons le cookies et le redirigeons vers la page d'entrée. Par contre, en cas d'erreur, il est renvoyé vers la page inscription. Remarque, le code inséré dans le cookies reprend le login, mot de masse et champ MEMO. 

4. Gestion des utilisateurs dans les pages.

Cette partie ne doit pas être utilisée telle qu'elle dans la pratique pour des questions de sécurité. Dernier petit développement, suivre l'utilisateur avec ses cookies. Pour cela, nous devons vérifier sur chaque page si le cookies est déjà implanté. S'il ne l'est pas, nous l'empêchons simplement d'exécuter quelques fonctions (comme inscrire une annonce). Si l'utilisateur est connu et suivi, nous mettons le cookies à jour et lui permettons différentes possibilités, comme la modification de son compte et l'inscription de nouvelles annonces. 

Dans cette formation, nous nous contentons de suivre l'utilisateur sur la partie enregistrement des annonces. Le développement complet est repris sur le site officiel du développement.

Nous allons tout simplement insérer le code suivante au tout début de notre fichier d'insertion des annonces

<?php
//Vérification de l'utilisateur
if(!isset($_COOKIE['ybet']))
{
echo"Vous ne pouvez pas poster d\'annonce, merci de vous connecter";
$login="";
}else{
$cookies=$_COOKIE['ybet'];
$cookies_array=array();
$cookies_array=Explode("-pw-",$cookies);
$login=$cookies_array[0];
$l=$cookies_array[1];
$cookies_array=explode("memo",$l);
$password=$cookies_array[0];
$memo=$cookies_array[1];
if(!mysql_connect('localhost','root')){
//Echo 'Connection Impossible';
exit();
}
Mysql_select_db('ybet');
$requete="SELECT * FROM member where username='$login' and password='$password'";
$valeur=mysql_query($requete);
$ligne=mysql_num_rows($valeur);

if ($ligne==0)
{
echo"Vous ne pouvez pas rentrer d'annonce, merci de vous connecter";
die('<meta http-equiv="refresh" content="3; URL=inscription.php">');
}else{
//echo"Utilisateur connu";
if ($memo=="")
{
Setcookie('ybet',$login."-pw-".$password."memo".$memo,time()+3600);
}else{
Setcookie('ybet',$login."-pw-".$password."memo".$memo,time()+864000);
}
while ($tableau=mysql_fetch_array($valeur)){
$mail=$tableau['email'];
$uid_util=$tableau['uid'];
}
}
}

?>
<html>

6. Pour conclure

Nous venons d'utiliser les cookies pour vérifier un utilisateur SANS sécurité, mot de passe n'est pas non plus crypté (utilisez ce chapitre comme partie théorique). En deuxième, il est possible d'envoyer plusieurs cookies du même nom (la fonction explode n'est pas nécessaire dans ce cas). Dans la pratique, on ne transmet pas le mot de passe à l'ordinateur client mais un code aléatoire qui va correspondre à un utilisateur enregistré ou une table de session qui lie (ou pas) la session à un compte utilisateur sans rien transférer sur le PC visiteur. En pratique, pour éviter les erreurs possibles, la gestion des cookies utilise une fonction intégrée dans un fichier externe, simplement appelé par chaque page du site. Nous en reparlerons dans les prochains chapitres.

Internet Explorer 8.0 (IE8) ne gère pas toujours correctement les cookies d'une manière aléatoire, il est bien créé mais ne peut pas être récupéré. C'est un bug de cette version (peut-être des versions suivantes) mais pas présent sur Explorer 6 et 7, ni sur Chrome, Firefox et Safari. Pour un développement, la gestion fonctionnait parfaitement en local et pas du tout sur l'hébergement (d'autres ont eut l'inverse ou des pertes régulières). Une méthode de correction est d'utiliser la commande Setcookie et $_COOOKIE dans des fichiers identiques ou différents mais dans le même dossier, par l'appel d'un dossier et la récupération par \includes\fonction.php par exemple.

> 26. Gestion des dossiers et fichiers
<24 . Gestion de communiqués

Modifié le 22/04/2012: mise à jour de la procédure théorique, suppression de parties répétitives.