jeudi 24 mars 2005

Forum


FORUM

Dans ce tutoriel, nous allons créer un forum compatible à norme xhtml 1.0. La création d'un forum n'est pas si complexe, il est seulement nécessaire de bien définir les fonctionnalités désirées et de bien modéliser sa base de données. Le forum qui sera créé sera assez complet.

Il y aura 3 niveaux d'accès pour le forum. Le premier sera pour un usager standard, le deuxième pour un modérateur et le troisième sera pour le webmestre. Ce dernier sera utile pour le tutoriel sur l'espace membre. Les fonctionnalités standards sont d'envoyer un message et de répondre à un message. Un usager peut aussi modifier et supprimer un message. Un modérateur peut modifier et supprimer les messages des autres membres. D'autres fonctionnalités seront expliquées en temps et lieu.

Base de donnée

Les données des membres et du forum seront entreposées dans une base de donnée MySQL. Il y a de nombreuses façons de modéliser la base de donnée nécessaire pour les fonctionnalités prévues. Afin de simplifier au minimum les requêtes, nous allons créer une table message, une table réponse, une table membre et une table section. La table section sert à déterminer à quelle section : delphi, c++, math, science.... que le message appartient. Un tel forum permettra ainsi d'avoir de multiples sections. Plusieurs sujets différents pourront donc y être traités. La table membre sert à spécifier les informations de l'usager. La table message est la question et la table réponse est une réponse à un message. Il y a donc un lien entre membre et question, question et section, et question et réponse.
Voici un petit schéma pour faciliter la compréhension.



Code sql

Table Membre

DROP TABLE IF EXISTS `membre`;
CREATE TABLE `membre` (
  `MEM_NOMEMBRE` int(11) NOT NULL auto_increment,
  `MEM_NOM` varchar(30) NOT NULL default '',
  `MEM_PRENOM` varchar(30) NOT NULL default '',
  `MEM_NOMUSAGER` varchar(30) NOT NULL default '',
  `MEM_MOTPASSE` varchar(30) NOT NULL default '',
  `MEM_COURRIEL` varchar(30) NOT NULL default '',
  `MEM_TYPE` int(11) NOT NULL default '0',
  `MEM_SITEWEB` varchar(100) default NULL,
  `MEM_SIGNATURE` varchar(50) default NULL,
  `MEM_NBMESSAGE` int(11) default '0',
  PRIMARY KEY  (`MEM_NOMEMBRE`)
) TYPE=MyISAM AUTO_INCREMENT=9 ;

Table Section

DROP TABLE IF EXISTS `section`;
CREATE TABLE `section` (
  `SEC_NOSECTION` int(11) NOT NULL auto_increment,
  `SEC_NOMSECTION` varchar(25) default NULL,
  `SEC_NBMESSAGE` int(11) default '0',
  `SEC_DATEDERNIERMSG` timestamp(14) NOT NULL,
  PRIMARY KEY  (`SEC_NOSECTION`),
  KEY `SEC_NOSECTION` (`SEC_NOSECTION`)
) TYPE=MyISAM AUTO_INCREMENT=5 ;

Table Message

DROP TABLE IF EXISTS `message`;
CREATE TABLE `message` (
  `MES_NOMESSAGE` int(11) NOT NULL auto_increment,
  `SEC_NOSECTION` int(11) NOT NULL default '0',
  `MEM_NOMEMBRE` int(11) NOT NULL default '0',
  `MES_MESSAGE` text,
  `MES_DATE` timestamp(14) NOT NULL,
  `MES_TITRE` varchar(100) default NULL,
  PRIMARY KEY  (`MES_NOMESSAGE`),
  FULLTEXT KEY `MES_MESSAGE` (`MES_MESSAGE`)
) TYPE=MyISAM AUTO_INCREMENT=43 ;

Table Réponse

DROP TABLE IF EXISTS `reponse`;
CREATE TABLE `reponse` (
  `REP_NOREPONSE` int(11) NOT NULL auto_increment,
  `MES_NOMESSAGE` int(11) NOT NULL default '0',
  `MEM_NOMEMBRE` int(11) NOT NULL default '0',
  `REP_REPONSE` text,
  `REP_DATE` timestamp(14) NOT NULL,
  PRIMARY KEY  (`REP_NOREPONSE`),
  FULLTEXT KEY `REP_REPONSE` (`REP_REPONSE`)
) TYPE=MyISAM AUTO_INCREMENT=22 ;

forum.php

Ce script, affichera les différentes sections du forum.
session_start();
  
  include("bd.php");
  include ("footer.php");
  
  //connexion à la base de données
  connectionbd();

Le fichier bd.php contient différentes fonctions reliées à la base de données. Nous expliquerons au fur à mesure de ce tutoriel les fonctions qu'on utilisera.
La fonction connectionbd(), sert à se connecter à la base de données.

$serveur = "localhost";
$utilisateur = "test";
$motDePasse  = "test";
$base        = "test";
$link        = "";

function connectionbd()
{
  global $serveur, $utilisateur, $motDePasse, $base, $link;
  $link = mysql_connect($serveur, $utilisateur, $motDePasse);
  mysql_select_db($base) or die("Connexion impossible");
}

Les variables $serveur, utilisateur... sont des variables globales, lorsque nous les utilisons au sein d'une fonction, nous devons utiliser le mot global.
 
  //si l'usager est déjà connecté
  if(session_is_registered("username")){
    include ("header2.php");
    entete("Forum","Forum programmation, Forum de développement");
    echo '<br/><div class="titresection">Forum</div>';
    echo'<div id="main">';
  }
  else{
    include ("header.php");
    entete("Forum","Forum programmation, Forum de développement");
    echo '<br/><div class="titresection">Forum</div>';
    echo'<div id="main">';
    echo'<div class="cmdforum"><a href="login">Connexion</a> | <a href="inscription">Inscription</a></div><br/>';
  }

Les fichiers: headers, headers2, footers ont été expliqué dans un article précédent. Cette portion de code sert à changer ce qui est affiché à l'écran selon que l'on s'est branché ou non. Si on est pas branché, il est possible de se connecter ou de s'inscrire si l'on n'est pas déjà membre.

//affiche la liste de forum
  $requete = mysql_query("SELECT sec_nosection, sec_nbmessage, sec_nomsection, DATE_FORMAT(sec_datederniermsg,'%d/%m/%Y %H:%i:%s') as datefr from section");
  
  echo'<table class="tabforum">';
  echo'<tr><td class="tabligntitre">:: Forum ::</td><td class="tabligntitre">:: Sujet ::</td><td class="tabligntitre">:: Derniers Message ::</td></tr>';
  $debut=0;
  while ($ligne = mysql_fetch_assoc($requete))
  {
   echo'<tr><td><a href="vueforum.php?sec_nosection='.$ligne['sec_nosection'].'&debut='.$debut.'">'.$ligne["sec_nomsection"].'</a></td><td>'.$ligne["sec_nbmessage"].'</td><td>'.$ligne["datefr"].'</td></tr>';  
  }
  echo'</table><br/>';
  
  echo'</div>';

Ce code affiche les différentes sections disponibles, par exemple sur ce site, ça serait Delphi, Génie logiciel....Il affiche le nom de la section, le nombre de messages de la section ainsi que la date du dernier message. En cliquant sur le nom de la section, le message lié à cette dernière s'affichera.

closebd();
piedpage(); 

Ce code ferme la base de données et affiche un pied de page.
function closebd()
{
  global $link;
  mysql_close($link);
}
Ce code utilise une variable globale définie plus haut et ferme la connexion à la base de données. Le pied de page utilisé est fort simple, le nom du webmestre est affiché ainsi que deux images liées au standard Web.

vueforum.php

Ce script, affichera les messages liés au forum qu'on a choisi. Au début de ce script, il y a une fonction qui permet d'afficher 20 messages par pages. Ce script a été inspiré de celui qu'on retrouve sur le site phpfacile. Ce script peut être trouvé à affichage page par page, des explications y sont données.

entete("Forum","Forum de programmation, Forum de programmation");
  connectionbd();
  
  $nb_affichage_par_page = 20; // on va afficher 20 résultats par page.
  
  echo '<br/><div class="titresection">Forum</div>';
  echo'<div id="main">';
  
  $sec_nosection = $_GET['sec_nosection'];
  
  //compte le nombre de message - utile pour l'affichage page par page
  $requete = mysql_query("SELECT count(mes_nomessage) FROM message where sec_nosection = $sec_nosection");
  $nb_total =  mysql_fetch_array($requete);

Nous nous connectons à la base de données, on affiche 20 résultats par page. Nous obtenons le numéro de la section à partir du script qu'on a vu précédemment. Nous comptons le nombre de messages disponible dans la section. Ce nombre sert à l'affichage. Par exemple si le nombre est 45, nous allons avoir 3 pages. Deux qui auront 20 données et une qui en aura 5.

if (!isset($_GET['debut'])) 
  $debut = 0;
else 
  $debut = $_GET['debut'];
echo'<div class="cmdforum"><a href="inserermsg'.$sec_nosection.'">Nouveau</a></div><br/>';
  
//affiche les informations dans un tableau
echo'<p class="tabforum">';
echo'<tr><td class="tabligntitre">:: Sujet ::</td><td class="tabligntitre">:: Auteur ::</td><td class="tabligntitre">:: Derniers Message ::</td><td class="tabligntitre">:: Nb ::</td></tr>';
   
// Préparation de la requête avec le LIMIT
$requete = mysql_query("SELECT mes_nomessage, mes_titre, mem_nomusager from message msg inner join membre m on m.mem_nomembre = msg.mem_nomembre where sec_nosection=$sec_nosection limit $debut, $nb_affichage_par_page");

Le début de ce code provient de lephpafacile. Cette variable est utile lorsqu'on a plus qu'une page à afficher. C'est la variable qui détermine où qu'on se situe. Nous avons ensuite une ligne qui permet d'insérer un message dans une section. L'affichage des messages (questions) débute, quelques informations sont affichées : le titre, l'auteur, la date du dernier message et le nombre de messages. Par la suite, la requête sélectionne les 20 messages à partir du lieu qu'on se trouve (à partir de la variable debut). Si on reprend l'exemple précédent, avec 45 réponses, la requête pourra avoir 3 valeurs : 0, 20 - 1, 20 - 2, 20.
while ($ligne = mysql_fetch_assoc($requete)) {
      
  $nbreponse= mysql_query("select count(rep_noreponse) as nbreponse from reponse where mes_nomessage=".$ligne['mes_nomessage']."");
      
  $maxdate= mysql_query("select max( DATE_FORMAT( rep_date, '%d/%m/%Y %H:%i:%s' ) ) AS datefr from reponse where mes_nomessage=".$ligne['mes_nomessage']."");
      
  $lignerep = mysql_fetch_assoc($nbreponse);
  $lignedate = mysql_fetch_assoc($maxdate);
      
       
  if ($lignerep["nbreponse"] !=0)
    $rep_noreponse = $lignerep["nbreponse"]; 
  else
    $rep_noreponse = 0;  

  if($lignedate["datefr"] != NULL){
    $rep_date = $lignedate["datefr"];
  }
  else
    $rep_date = "Aucun message";  

  echo '<tr><td><a href="liremsg.php?sec_nosection='.$sec_nosection.'&mes_nomessage='.$ligne["mes_nomessage"].'&debut='.$debut.'">'.$ligne["mes_titre"].'</a></td><td>'.$ligne["mem_nomusager"].'</td><td>'.$rep_date.'</td><td>'.$rep_noreponse.'</td></tr>';  
}
    
echo'</table><br/>';

À partir des résultats de la requête précédente, les informations sont affichées. Lorsqu'aucune réponse n'est trouvée au lieu de rien afficher, nous affichons 0 et aucun message. Lorsqu'on cliquera sur le titre d'un message, les réponses qui lui sont liées s'afficheront (à partir du script liremsg.php).

// on libère l'espace mémoire alloué pour cette requête
    mysql_free_result ($requete);
    mysql_free_result ($nbreponse);
    mysql_free_result ($maxdate);
  }
  
  // on lance la création de la barre de navigation à l'aide de notre fonction, le dernier argument de la fonction étant le nom de notre page WEB sur laquelle on va afficher les résultats de notre requête
  $barre = barre_navigation($nb_total, $nb_affichage_par_page, $debut);

   // on affiche enfin notre barre
  echo '<b>'.$barre.'</b>'; 
  
  echo'</div>';
  
  closebd();
  piedpage();

Ce code libère les ressources allouées pour les requêtes, affiche la barre de navigation, ferme la connexion à la base de données et affiche le pied de page.

liremsg.php

Ce script affiche la question et ses réponses. Le début de ce script est semblable au précédent, s'il y a plus de 20 réponses, il y a une barre de navigation.
entete("Forum","");
  
  connectionbd();
  
  $nb_affichage_par_page = 20; // on va afficher 20 réponses par page.
  
  echo '<br/><div class="titresection">Forum</div>';
  echo'<div id="main">';
  
  $sec_nosection = $_GET['sec_nosection'];
  $mes_nomessage = $_GET['mes_nomessage'];
  
  //compte le nombre de message - utile pour l'affichage page par page
  $requete = mysql_query("SELECT count( rep_noreponse ) FROM reponse rep INNER JOIN message mes ON mes.mes_nomessage = rep.mes_nomessage WHERE mes.mes_nomessage = $mes_nomessage");
  $nb_total =  mysql_fetch_array($requete);
  
  //inserer un nouveau message;
  echo'<div class="cmdforum"><a href="repondremsg'.$sec_nosection.''.$mes_nomessage.'">Répondre</a></div>';

  //afficher la question - requete
  $requete = mysql_query("SELECT mes_nomessage, DATE_FORMAT(mes_date,'%d/%m/%Y %H:%i:%s') AS datefr, mes_message, mes_titre, m.mem_nomembre, mem_nomusager, mem_siteweb, mem_nbmessage, mem_signature from message msg inner join membre m on m.mem_nomembre = msg.mem_nomembre where mes_nomessage=$mes_nomessage");
  
  echo'<table class="tabforum">';
  //info de l'usager
  echo'<tr><td class="membre">'.$ligne['mem_nomusager'].'<br/>'.$ligne['mem_nbmessage'].' messages<br/>'.$ligne["datefr"].'<br/>'.$ligne['mem_siteweb'].'<br/>'.$ligne['mem_signature'].'</td>';
  //sa question
  
  //(si membre de type 1 ou 2) ou c'est notre question
  if((( $_SESSION['type'] == 1) or ($_SESSION['type'] == 2)) or($_SESSION['mem_nomembre']==$ligne['mem_nomusager']))
  {
    //gérer la modification de la question et des réponses - géré avec les variables de session
    //message= 1 si une question
    
    echo'<td><div class="fctforum"><a href=modifiermsg.php?nosection='.$sec_nosection.'&nomessage='.$ligne['mes_nomessage'].'&message=1>Modifier </a>';
    
    echo'<a href=effacermsg.php?nosection='.$sec_nosection.'&nomessage='.$ligne['mes_nomessage'].'&message=1>Supprimer</a></div><br/>';
    echo ''.$ligne['mes_message'].'</td></tr>';
  }
  else
    echo'<td>'.$ligne['mes_message'].'</td></tr>';
  
  
  echo'</table><br/>';

Nous comptons le nombre de réponses au message, un lien est créé enfin d'ajouter une réponse au message existant. Le message et chaque réponse sont affichés chaque fois dans un tableau. Les informations de la question sont affichées. Selon le type du membre: un modérateur ou webmestre, il y a possibilité de d'effacer ou de modifier le message. Cette particularité est une mesure de sécurité.

if (($nb_total = $nb_total[0]) != 0){    
    // sinon, on regarde si la variable $debut (le x de notre LIMIT) n'a pas déjà été déclarée, et dans ce cas, on l'initialise à 0
    if (!isset($_GET['debut'])) 
      $debut = 0;
    else 
      $debut = $_GET['debut'];
  

    //afficher la ou les réponse - requete  DATE_FORMAT(mes_date,'%d/%m/%Y %H:%i:%s') AS datefr 
    $nbreponse = mysql_query("SELECT rep_noreponse, rep_reponse, DATE_FORMAT(rep_date,'%d/%m/%Y %H:%i:%s') AS datefr , m.mem_nomembre, mem_nomusager, mem_siteweb, mem_nbmessage, mem_signature from reponse rep inner join membre m on m.mem_nomembre = rep.mem_nomembre where mes_nomessage=$mes_nomessage limit $debut, $nb_affichage_par_page");
    
    if ( mysql_num_rows($nbreponse) != 0 ){
    //afficher les réponses
    while ($ligne = mysql_fetch_assoc($nbreponse))
    {
      echo'<table class="tabforum">';
      //info de l'usager
      echo'<tr><td class="membre">'.$ligne['mem_nomusager'].'<br/>'.$ligne['mem_nbmessage'].' messages<br/>'.$ligne["datefr"].'<br/>'.$ligne['mem_siteweb'].'<br/>'.$ligne['mem_signature'].'</td>';
      //sa réponse
      //(si membre de type 1 ou 2) ou c'est notre réponse
      if((( $_SESSION['type'] == 1) or ($_SESSION['type'] == 2)) or($_SESSION['mem_nomembre']==$ligne['mem_nomusager']))
      {
        //message= 0 si une réponse
        echo'<td><div class="fctforum"><a href=modifiermsg.php?nosection='.$sec_nosection.'&noreponse='.$ligne['rep_noreponse'].'&message=0>Modifier </a>';
        echo'<a href=effacermsg.php?nosection='.$sec_nosection.'&noreponse='.$ligne['rep_noreponse'].'&message=0>Supprimer</a></div><br/>';
        echo ''.$ligne['rep_reponse'].'</td></tr>';
        
      }
      else
        echo'<td>'.$ligne['rep_reponse'].'</td></tr>';
      
      echo'</table><br/>';
    }
    
    }
  }
  
  // on lance la création de la barre de navigation à l'aide de notre fonction, le dernier argument de la fonction étant le nom de notre page WEB sur laquelle on va afficher les résultats de notre requête

 $barre = barre_navigation($nb_total, $nb_affichage_par_page, $debut);

 // on affiche enfin notre barre
 echo '<b>'.$barre.'</b>'; 

  
 echo'</div>';
  
  closebd();
  piedpage();

Cette portion de code est semblable que la précédente à l'exception que ces les réponses du message qui sont affichées.

inserermsg.php

Le code de ce script ainsi que les prochains ne seront pas affichés, mais une description sera faite. Ce script sert à insérer un nouveau message à une section. Il y a un formulaire pour le message.

modifiermsg.php

Ce script sert à modifier une réponse ou un message. Il y a un formulaire pour le message. Les champs sont déjà remplis par le texte existant. L'usager peut modifier le message.

effacermsg.php

Ce script sert à effacer une réponse ou un message. Le numéro du message est donné à une requête afin d'effacer le message de la base de données.

Téléchargement

Tous les scripts de ce forum peuvent être téléchargé ici.