Système de votes en AJAX

Attention, depuis PHP 5.5.0, certaines extensions SQL sans doute utilisées dans ce tutoriel peuvent être obsolètes et seront supprimées dans le futur, vous devez donc adapter les codes! Exemples ici.
Toujours dans l'optique de comprendre (du moins je l'espère) un peut plus comment fonctionne AJAX, nous allons réaliser un système de votes. L'utilisateur aura le choix entre  voter positivement (+1) ou négativement (-1) et verra son vote s'ajouter automatiquement sans rechargement de la page. Histoire de bien me faire comprendre, voici ce que ça donnera visuellement :
L'utilisateur peut voter vote
L'utilisateur a voté positivement vote positif
L'utilisateur a voté négativement vote négatif

Il va de soit que le total des votes est cumulé au fur et à mesure.

Vous pouvez tester la démo en suivant ce lien : Démo du système de votes AJAX

Etape 1 : création de la base de données

On fait simple, on créé une table "note" doté de 4 champs :

   1. id » chaque vote à un "id" unique.
   2. id_page » numéro de la page ou de l'article.
   3. note » note attribué par l'utilisateur.
   4. ip » ip de l'utilisateur.
--
-- Structure de la table `note`
--
 
CREATE TABLE IF NOT EXISTS `note` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_page` int(11) NOT NULL,
  `note` int(11) NOT NULL,
  `ip` varchar(15) COLLATE latin1_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=1 ;
Etape 2 : création du style CSS

Dans un fichier nommé "style-vote.css", insérez le code suivant :
#entoure{
width:65px;
height:60px;
border: 1px solid #DDD;
background-color: white;
font-size: 24px;
font-weight: bold;
text-align: center;
color: #999;padding:2px;
margin:5px;
float:left;
}
#resultat{
height:30px;
}
#spriteplus {
width:30px;
height:30px;
background:url(image-vote/vote.png) -0px -5px no-repeat;
float:left;
cursor:pointer
}
#spritemoins{
width:30px;
height:30px;
background:url(image-vote/vote.png) -38px -6px no-repeat;
float:right;
cursor:pointer
}
Créer un dossier nommé "image-vote" et récupérez l'image suivante image du vote que vous insérez dans ce dossier.

Etape 3 : mise en place du système de votes

Pour l'exemple, on va créer un simple fichier "index.php" dans lequel vous insérer le code suivant :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Language" content="fr" />
<title>Système de votes en AJAX</title>
<!-- style CSS du vote -->
<link rel="stylesheet" type="text/css" href="style-vote.css" />
</head>
 
<body>
<h1>Système de votes en AJAX</h1>
<!-- Système de votes -->
<div id="entoure">
<div id="resultat"></div>
<div onclick="ajax('1',idpage,ipclient)" id="spriteplus" title="Utile"></div>
<div onclick="ajax('-1',idpage,ipclient)" id="spritemoins" title="Pas utile"></div>
</div>
<!-- Fin du système de votes -->
 
<!-- Ip du client et identifiant de la page -->
<script type="text/javascript">
var ipclient = '<?php echo getenv("REMOTE_ADDR");?>';
var idpage = 7;
</script>
<!-- Appel au fonctions AJAX -->
<script type="text/javascript" src="fonctions-vote.js"></script>
 
</body>
</html>
Détaillons un peut cette page pour en comprendre la structure...

Dans l'entête du document nous faisons appel au fichier CSS.
Vient ensuite la mise en place du système de votes représenté par 4 "div" qui font chacune référence à un style CSS :
<div id="entoure">
<div id="resultat"></div>
<div onclick="ajax('1',idpage,ipclient)" id="spriteplus" title="Utile"></div>
<div onclick="ajax('-1',idpage,ipclient)" id="spritemoins" title="Pas utile"></div>
</div>
Le premier "div" englobe tout les autres et détermine les dimensions du système de votes.
Le second "div" sert à afficher le résultat du ou des votes.
Les 2 derniers "div" permettent l"affichage de l'image pour voter.

Les 2 derniers "div" font appel à une fonction nommé "ajax()" qui prend en compte 3 arguments :
  1. "1" et "-1" correspond à la notation (positif ou négatif).
  2. "idpage" correspond à l'identifiant de la page ou de l'article en cours.
  3. "ipclient" correspond à l'ip de l'utilisateur.
On donne ensuite une valeur au 2 derniers arguments de la fonction "ajax()" :
<script type="text/javascript">
var ipclient = '<?php echo getenv("REMOTE_ADDR");?>';
var idpage = 7;
</script>
ipclient récupère l'ip de l'utilisateur via une simple variable PHP.
idpage récupère l’identifiant de la page en cours symbolisé ici par le numéro "7".

Si l'identifiant de la page est une variable PHP vous devez adapter celle-ci comme ci-dessous :
<script type="text/javascript">
var ipclient = '<?php echo getenv("REMOTE_ADDR");?>';
var idpage = '<?php echo $mavariable;?>';
</script>
En résumé et pour comprendre les arguments passés en paramètre de la fonction "ajax()", c'est comme ci on écrivait :
<div onclick="ajax('1','7','127.0.0.1')" id="spriteplus" title="Utile"></div>
<div onclick="ajax('-1','7','127.0.0.1')" id="spritemoins" title="Pas utile"></div>
La dernière ligne :
<script type="text/javascript" src="fonctions-vote.js"></script>
...fait appel à un fichier nommé "fonctions-vote.js" qui contient diverses fonctions AJAX que nous allons à présent concevoir.

Etape 4 : création des fonctions AJAX

Créer un fichier nommé "fonctions-vote.js".

La première chose que l'on met en place, c'est la fonction d'instance :
//Fonction d'Instance
function objet_XMLHttpRequest()
{
    var xhr = null;
 
    if (window.XMLHttpRequest || window.ActiveXObject){
        if(window.ActiveXObject){
            try{
                xhr = new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch(e){
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
        }
        else{
            xhr = new XMLHttpRequest();
        }
    }
    else{
        alert("Votre navigateur ne supporte pas l'objet XMLHTTPRequest...");
        return null;
    }
    return xhr;
}
Ceci fait nous allons à présent créer la fonction "ajax()" qui va récupérer les 3 arguments passé en paramètres. Théoriquement et si vous avez suivit les précédents tutoriels, vous devez comprendre le code suivant qui est largement commenté ...
//Fonction permettant d'envoyer les données
function ajax(note,id,ip)
{
    //On déclare un objet
    var objet1 = objet_XMLHttpRequest();
 
    //On défini ce qu'on va faire quand on aura la réponse
    objet1.onreadystatechange = function(){
        //On ne fait quelque chose que si on a tout reçu et que le serveur est ok
        if(objet1.readyState == 4 && objet1.status == 200){
            //Données textuelles récupérées dans objet1.responseText
            document.getElementById('resultat').innerHTML = objet1.responseText;
            //On lance la fonction refresh
            setTimeout("refresh()", 10);
        }
        //côté ajax ça merde
        else{
            //on contrôle le statut. Si 404, le fichier ouvert par "open" n'existe pas
            if(objet1.status == 404){
                alert('Erreur ' +objet1.status + '! Le fichier php semble être absent...');
            }
        }
    }
    //Ouverture : méthode, fichier, mode (true=asynchrone | false=synchrone)
    objet1.open("POST", "vote-ajax.php" , true);   
    objet1.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    //envoie
    objet1.send("note=" + note + "&id=" + id + "&ip=" + ip);
}
Dans cette fonction 2 choses sont à prendre en considération :
setTimeout("refresh()", 10);
1-Ici une fonction nommé "refresh()" est lancé au bout de 10 millisecondes. Cette fonction que l'on va créer va entre autre permettre de rafraîchir le "div" contenant le vote.
objet1.open("POST", "vote-ajax.php" , true);
2-La page qui va recevoir et traiter les données se nomme "vote-ajax.php".

Nous passons maintenant à la création de la fonction "refresh()" qui va nous permettre de réaliser plusieurs choses. Cette fonction sera lancé automatiquement dès l'ouverture de la page pour vérifier si l'utilisateur à déjà voté ou pas.
Si l'utilisateur à déjà voté, une partie du système de vote sera caché et le "div" contenant le total des votes sera redimensionné.
Si un petit malin accède directement à la page de traitement "vote-ajax.php" autre que par l'intermédiaire du site, le traitement des données sera stoppé.
//Fonction permettant de vérifier si l'utilisateur à déjà voté
function refresh()
{
    //On déclare un objet
    var objet2 = objet_XMLHttpRequest();
 
    //On défini ce qu'on va faire quand on aura la réponse
    objet2.onreadystatechange = function(){
        //On ne fait quelque chose que si on a tout reçu et que le serveur est ok
        if(objet2.readyState == 4 && objet2.status == 200){
            //Cas ou le référent est vide ou que le HOST ne correspond pas
            if(objet2.responseText == 'Erreur de REFERER ou de HOST!'){
            //On cache le vote
            document.getElementById('entoure').style.display = 'none';
            //On informe
            alert(objet2.responseText);
            }
            //On vérifie si le mot "dv" est dans la réponse objet2.responseText. Si la variable renvoie "-1" c'est qu'il n'y est pas.
            var trouve_mot = objet2.responseText.indexOf("dv");
            if(trouve_mot == '-1'){
                //Données textuelles récupérées dans objet2.responseText
                document.getElementById('resultat').innerHTML = objet2.responseText;
            }
            //Si la variable renvoie autre chose que "-1"
            else{
                //On supprime le mot "dv"
                var remplace_mot = objet2.responseText.replace("dv", "");
                //Données textuelles récupérées dans objet2.responseText
                document.getElementById('resultat').innerHTML = remplace_mot;
                //On cache le système de votes
                document.getElementById('spriteplus').style.display = 'none';
                document.getElementById('spritemoins').style.display = 'none';
                //On réduit la taille du div qui entoure le système de vote
                document.getElementById('entoure').style.height = '30px';           
            }
        }
    }
    //On ouvre une connexion en méthode POST
    objet2.open("POST", "vote-ajax.php" , true);
     objet2.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    //On envoie
    objet2.send("id=" +idpage+ "&ip=" +ipclient);
}
//On lance la fonction refresh
setTimeout("refresh()", 1);
Détaillons certaines partie du code.

Partie 1 :
            //Cas ou le référent est vide ou que le HOST ne correspond pas
            if(objet2.responseText == 'Erreur de REFERER ou de HOST!'){
            //On cache le vote
            document.getElementById('entoure').style.display = 'none';
            //On informe
            alert(objet2.responseText);
            }

Dans le fichier de traitements des données (vote-ajax.php) que nous verrons après nous allons vérifier si l'utilisateur accède bien au système de votes par l'intermédiaire du site uniquement. Si ce n'est pas le cas, le texte "Erreur de REFERER ou de HOST!" sera renvoyé mot pour mot. Le système de vote sera caché, le traitement des données sera interrompu et l'utilisateur sera notifié d'une alerte.

Partie 2 :
            var trouve_mot = objet2.responseText.indexOf("dv");
            if(trouve_mot == '-1'){
                //Données textuelles récupérées dans objet2.responseText
                document.getElementById('resultat').innerHTML = objet2.responseText;
            }
            //Si la variable renvoie autre chose que "-1"
            else{
                //On supprime le mot "dv"
                var remplace_mot = objet2.responseText.replace("dv", "");
                //Données textuelles récupérées dans objet2.responseText
                document.getElementById('resultat').innerHTML = remplace_mot;
                //On cache le système de votes
                document.getElementById('spriteplus').style.display = 'none';
                document.getElementById('spritemoins').style.display = 'none';
                //On réduit la taille du div qui entoure le système de vote
                document.getElementById('entoure').style.height = '30px';           
            }
Toujours dans le fichier de traitements des données, une vérification va être effectué afin de déterminer si l'utilisateur a déjà voté ou pas. Pour ce faire, le fichier va renvoyer la note suivit de 2 lettres "dv" pour "déja voté". Le contenu étant récupérer dans "objet2.responseText", on vérifie si le mot "dv" existe par l'intermédiaire du code suivant :
var trouve_mot = objet2.responseText.indexOf("dv");
Si la variable "trouve_mot" renvoie "-1" c'est que le mot "dv" n'a pas été trouvé, donc l'utilisateur na pas encore voté. On lui affiche donc la note actuelle et le système de votes au complet.
Dans le cas contraire, si la variable "trouve_mot" renvoie autre chose que "-1" c'est que l'utilisateur à déjà voté, on supprime tout simplement le mot "dv" de la réponse avant d'afficher la note puis on cache le système de notation et pour finir on redimensionne le "div" contenant le résultat.

Partie 3 :
setTimeout("refresh()", 1);
On lance la fonction "refresh()" 1 milliseconde après l'ouverture de la page.

Etape 5 : création de la page de traitements

Nous allons à présent créer le dernier fichier qui va se nommer "vote-ajax.php" et qui va nous permettre de traiter les données.

Dans un premier temps on vérifie si le fichier à bien un référant et qu'il est bien utilisé depuis le site :
<?php
//Si le référant est vide ou que le nom de domaine est différent de ***, on éjecte
if(empty($_SERVER['HTTP_REFERER']) || $_SERVER['HTTP_HOST'] != 'localhost'){
    echo 'Erreur de REFERER ou de HOST!';
    exit();
}
Sous Wampserver, la variable d'environnement $_SERVER['HTTP_HOST'] renvoie "localhost". A vous de l'adapter en fonction de votre situation.
Ensuite on se connecte à la base de données puis on récupère l'id et l'ip :
//Variable de connexion BDD *
$nom_du_serveur ="localhost";
$nom_de_la_base ="note";
$nom_utilisateur ="root";
$passe ="";
 
//Connexion à la base de données
mysql_connect("$nom_du_serveur","$nom_utilisateur","$passe");
//Vérification d'accès à la base de données
mysql_select_db("$nom_de_la_base")  or die ('Erreur :'.mysql_error());
 
//On récupère les 2 variables qui transitent via la fonction ajax()
$id = (isset($_POST["id"])) ? $_POST["id"] : NULL;
$ip = (isset($_POST["ip"])) ? $_POST["ip"] : NULL;
*Adapter les variables de connexions à la BD.

Ceci fait, on calcul le total des notes et on l'affiche. Si le total des notes est positif, on insère le signe "+" devant la note :
//Note actuelle
$calcul_note = mysql_query("SELECT SUM(note) AS totalmoyenne FROM note WHERE id_page = '".mysql_real_escape_string($id)."'");
$data = mysql_fetch_array($calcul_note);
$note_actuelle = $data['totalmoyenne'];
//Si aucun vote
if($note_actuelle == NULL){
    $note_actuelle = 0;
}
//Si la note est supérieure ou égal à 1 on affiche le signe +
if($note_actuelle>=1){
    echo '+';
}
//On affiche la note actuelle
echo $note_actuelle;
 
//On affiche la note actuelle
echo $note_actuelle;
On vérifie ensuite si l'utilisateur à déjà voté ou pas. Si tel est le cas on affiche le mot ("dv" pour déjà voté)  à la suite de la note qui sera récupéré par objet2.responseText.indexOf de la fonction refresh() puis traité avant l'affichage.
//on vérifie si l'utilisateur à déjà voté
$deja_voter = mysql_query("SELECT ip FROM note WHERE ip = '".mysql_real_escape_string($ip)."' AND id_page = '".mysql_real_escape_string($id)."'");
$resultat = mysql_fetch_array($deja_voter);
/*Si tel est le cas on affiche un mot ("dv" pour déjà voté) qui sera récupéré par xhr.responseText de la fonction ajax. Cet élément permettra de montrer ou pas le système de vote à l'utilisateur*/
if($resultat != NULL){
    echo 'dv';
}
 
Si l'utilisateur peut voter, on insère son vote en BD :
//L'utilisateur peut voter
if(isset($_POST['note'])){
    //On récupère la note
    $note = (isset($_POST["note"])) ? $_POST["note"] : NULL;
 
    //Insertion en BDD
    $insert = mysql_query("INSERT INTO note VALUES ( '', '".mysql_real_escape_string($id)."', '".mysql_real_escape_string($note)."', '".mysql_real_escape_string($ip)."' ) ");
    //Si il y a une erreur
    if(!$insert) {
        die('Requête invalide : ' . mysql_error());
    }
}
?>
  Finit !
Voir/déposer un commentaire (5) | Signaler un problème