Comment faire un forum en PHP

Avant de commencer quoi que ce soit, il faut savoir que réaliser un beau forum n'est pas une opération vraiment simple.
En revanche, avec un peu de travail et surtout beaucoup de réflexion, on peut arriver à faire quelque chose de sympathique en assez peu de temps.

En effet, réfléchissons deux minutes à la question suivante :

De combien de pages WEB (et quelles sont leurs fonctions) avons-nous besoin pour réaliser un forum ?

Apres une rapide réflexion, on peut dire que l'on aura besoin de :
  • une page d'accueil où l'on verra tous les sujets du forum (index.php)
  • une page de lecture où l'on pourra lire les différents messages composant un sujet (lire_sujet.php)
  • une page contenant un formulaire pour insérer un nouveau sujet (insert_sujet.php)
  • une page contenant un formulaire pour insérer une réponse à un sujet (insert_reponse.php)


Ce qui nous fait un total de 4 pages à écrire.

Autre question :

Combien de tables SQL avons-nous besoin pour réaliser notre forum ?

On peut également dire que l'on aura besoin de 2 tables :
  • une table contenant les sujets (que l'on nommera forum_sujets)
  • une table comprenant les réponses à ces différents sujets (que l'on nommera forum_reponses)


Demandons-nous maintenant quels sont les attributs qui composent nos tables.

La table forum_sujet comportera :
  • un attribut id (de type INT avec une option AUTO_INCREMENT) qui représentera la clé primaire de notre table, ce qui nous permettra de distinguer tous les sujets de notre forum (chaque sujet aura un id différent).
  • un attribut auteur de type VARCHAR qui comportera le nom de la personne qui a posté ce sujet.
  • un attribut titre de type text qui correspondra au titre du sujet.
  • un attribut date_derniere_reponse de type datetime qui nous permettra de connaître la date de la dernière réponse de ce sujet (et ce pour mettre ce sujet en tête dans l'affichage).


En effet, dans la majorité des forums, lorsque l'on répond à un sujet, celui-ci se place ensuite toujours automatiquement en tête lorsque l'on affiche le forum.

Voici alors la structure de la table forum_sujets :

table_forum_sujets.sql
CREATE TABLE forum_sujets (
id int(6) NOT NULL auto_increment,
auteur VARCHAR(30) NOT NULL,
titre text NOT NULL,
date_derniere_reponse datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (id)
) TYPE=MyISAM;



La table forum_reponses comportera elle :
  • un attribut id (de type INT avec une option AUTO_INCREMENT) qui représentera la clé primaire de notre table, ce qui nous permettra de distinguer toutes les réponses à chaque sujet de notre forum (chaque réponse aura un id différent).
  • un attribut auteur de type VARCHAR comportant le nom de la personne qui a posté cette réponse.
  • un attribut message de type text qui correspond au message (réponse) que l'on postera.
  • un attribut date_reponse de type datetime qui correspond à la date de postage de cette réponse.
  • un attribut correspondance_sujet de type INT qui nous permettra de faire la liaison entre les réponses et les sujets du forum (cet attribut nous servira de jointure afin de connaître le sujet auquel appartient telle ou telle réponse).


Voici la structure de la table :

table_forum_reponses.sql
CREATE TABLE forum_reponses (
id int(6) NOT NULL auto_increment,
auteur VARCHAR(30) NOT NULL,
message text NOT NULL,
date_reponse datetime NOT NULL default '0000-00-00 00:00:00',
correspondance_sujet int(6) NOT NULL,
PRIMARY KEY (id)
) TYPE=MyISAM;



Voila déjà une bonne chose de faite.
Reste ensuite à écrire les différentes pages.



Voyons tout d'abord la page index.php.
Apres une rapide réflexion, on peut se rendre compte que sur cette page, nous aurons besoin de :
  • un lien permettant d'insérer un nouveau sujet.
  • le nom de l'auteur du sujet.
  • le titre su sujet.
  • la date de la dernière réponse à ce sujet.
  • mais aussi l'id de ce sujet (afin de faire la jointure entre les deux tables).


Sur cette page, on veut également qu'un lien soit présent au niveau de chaque titre de sujet afin de lire les différentes réponses appartenant à chaque sujet (c'est là que l'on aura besoin de l'id).

On aura alors (page index.php):

index.php
<html>
<head>
<title>Index de notre forum</title>
</head>
<body>

<!-- on place un lien permettant d'accéder à la page contenant le formulaire d'insertion d'un nouveau sujet -->
<a href="./insert_sujet.php">Insérer un sujet</a>

<br /><br />

<?php
// on se connecte à notre base de données
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base) ;

// préparation de la requete
$sql = 'SELECT id, auteur, titre, date_derniere_reponse FROM forum_sujets ORDER BY date_derniere_reponse DESC';

// on lance la requête (mysql_query) et on impose un message d'erreur si la requête ne se passe pas bien (or die)
$req = mysql_query($sql) or die('Erreur SQL !<br />'.$sql.'<br />'.mysql_error());

// on compte le nombre de sujets du forum
$nb_sujets = mysql_num_rows ($req);

if ($nb_sujets == 0) {
echo 'Aucun sujet';
}
else {
?>
<table width="500" border="1"><tr>
<td>
Auteur
</td><td>
Titre du sujet
</td><td>
Date dernière réponse
</td></tr>
<?php
// on va scanner tous les tuples un par un
while ($data = mysql_fetch_array($req)) {

// on décompose la date
sscanf($data['date_derniere_reponse'], "%4s-%2s-%2s %2s:%2s:%2s", $annee, $mois, $jour, $heure, $minute, $seconde);

// on affiche les résultats
echo '<tr>';
echo '<td>';

// on affiche le nom de l'auteur de sujet
echo htmlentities(trim($data['auteur']));
echo '</td><td>';

// on affiche le titre du sujet, et sur ce sujet, on insère le lien qui nous permettra de lire les différentes réponses de ce sujet
echo '<a href="./lire_sujet.php?id_sujet_a_lire=' , $data['id'] , '">' , htmlentities(trim($data['titre'])) , '</a>';

echo '</td><td>';

// on affiche la date de la dernière réponse de ce sujet
echo $jour , '-' , $mois , '-' , $annee , ' ' , $heure , ':' , $minute;
}
?>
</td></tr></table>
<?php
}

// on libère l'espace mémoire alloué pour cette requête
mysql_free_result ($req);
// on ferme la connexion à la base de données.
mysql_close ();
?>
</body>
</html>



Si vous n'êtes pas déjà mort, on va s'intéresser maintenant à la page lire_sujet.php permettant de lire tous les messages d'un sujet.

D'après le code de la page index.php, on remarque déjà que grâce au lien mis sur le titre de chaque sujet, on aura une variable $_GET['id_sujet_a_lire'] dans la page lire_sujet.php qui correspondra à l'id du sujet dont nous souhaitons lire tous les messages.

Cette explication faite, la page lire_sujet.php ne pose aucun problème puisqu'il s'agit tout simplement de sélectionner les réponses d'un certain sujet et de les afficher (de quel sujet ? et bien tout simplement celui dont l'id est égal à $_GET['id_sujet_a_lire']).

Egalement, n'oublions pas de fournir un lien vers la page insert_reponse.php nous permettant de poster des réponses pour le sujet que nous sommes en train de lire.

On aura alors le code suivant (page lire_sujet.php) :

lire_sujet.php
<html>
<head>
<title>Lecture d'un sujet</title>
</head>
<body>

<?php
if (!isset($_GET['id_sujet_a_lire'])) {
echo 'Sujet non défini.';
}
else {
?>
<table width="500" border="1"><tr>
<td>
Auteur
</td><td>
Messages
</td></tr>
<?php
// on se connecte à notre base de données
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base) ;

// on prépare notre requête
$sql = 'SELECT auteur, message, date_reponse FROM forum_reponses WHERE correspondance_sujet="'.$_GET['id_sujet_a_lire'].'" ORDER BY date_reponse ASC';

// on lance la requête (mysql_query) et on impose un message d'erreur si la requête ne se passe pas bien (or die)
$req = mysql_query($sql) or die('Erreur SQL !<br />'.$sql.'<br />'.mysql_error());

// on va scanner tous les tuples un par un
while ($data = mysql_fetch_array($req)) {

// on décompose la date
sscanf($data['date_reponse'], "%4s-%2s-%2s %2s:%2s:%2s", $annee, $mois, $jour, $heure, $minute, $seconde);

// on affiche les résultats
echo '<tr>';
echo '<td>';

// on affiche le nom de l'auteur de sujet ainsi que la date de la réponse
echo htmlentities(trim($data['auteur']));
echo '<br />';
echo $jour , '-' , $mois , '-' , $annee , ' ' , $heure , ':' , $minute;

echo '</td><td>';

// on affiche le message
echo nl2br(htmlentities(trim($data['message'])));
echo '</td></tr>';
}

// on libère l'espace mémoire alloué pour cette reqête
mysql_free_result ($req);
// on ferme la connection à la base de données.
mysql_close ();
?>

<!-- on ferme notre table html -->
</table>
<br /><br />
<!-- on insère un lien qui nous permettra de rajouter des réponses à ce sujet -->
<a href="./insert_reponse.php?numero_du_sujet=<?php echo $_GET['id_sujet_a_lire']; ?>">Répondre</a>
<?php
}
?>
<br /><br />
<!-- on insère un lien qui nous permettra de retourner à l'accueil du forum -->
<a href="./index.php">Retour à l'accueil</a>

</body>
</html>



Et voila :)

Notre forum est à présent terminé en ce qui concerne l'affichage des titres des sujets et des différentes réponses.

Reste maintenant à faire les 4 dernières pages, celles qui vous nous permettre d'insérer des nouveaux sujets ainsi que des nouvelles réponses.

Prenons tout d'abord la page insert_sujet.php.
Cette page propose tout simplement un formulaire nous permettant de saisir notre nom (le nom de l'auteur du sujet), un titre de sujet ainsi qu'un message (soit en fait, le premier message de notre sujet).

On aura alors le code suivant (page insert_sujet.php) :

insert_sujet.php
<?php
// on teste si le formulaire a été soumis
if (isset ($_POST['go']) && $_POST['go']=='Poster') {
// on teste la déclaration de nos variables
if (!isset($_POST['auteur']) || !isset($_POST['titre']) || !isset($_POST['message'])) {
$erreur = 'Les variables nécessaires au script ne sont pas définies.';
}
else {
// on teste si les variables ne sont pas vides
if (empty($_POST['auteur']) || empty($_POST['titre']) || empty($_POST['message'])) {
$erreur = 'Au moins un des champs est vide.';
}

// si tout est bon, on peut commencer l'insertion dans la base
else {
// on se connecte à notre base
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base) ;

// on calcule la date actuelle
$date = date("Y-m-d H:i:s");

// préparation de la requête d'insertion (pour la table forum_sujets)
$sql = 'INSERT INTO forum_sujets VALUES("", "'.mysql_escape_string($_POST['auteur']).'", "'.mysql_escape_string($_POST['titre']).'", "'.$date.'")';

// on lance la requête (mysql_query) et on impose un message d'erreur si la requête ne se passe pas bien (or die)
mysql_query($sql) or die('Erreur SQL !'.$sql.'<br />'.mysql_error());

// on recupère l'id qui vient de s'insérer dans la table forum_sujets
$id_sujet = mysql_insert_id();

// lancement de la requête d'insertion (pour la table forum_reponses
$sql = 'INSERT INTO forum_reponses VALUES("", "'.mysql_escape_string($_POST['auteur']).'", "'.mysql_escape_string($_POST['message']).'", "'.$date.'", "'.$id_sujet.'")';

// on lance la requête (mysql_query) et on impose un message d'erreur si la requête ne se passe pas bien (or die)
mysql_query($sql) or die('Erreur SQL !'.$sql.'<br />'.mysql_error());

// on ferme la connexion à la base de données
mysql_close();

// on redirige vers la page d'accueil
header('Location: index.php');

// on termine le script courant
exit;
}
}
}
?>
<html>
<head>
<title>Insertion d'un nouveau sujet</title>
</head>

<body>

<!-- on fait pointer le formulaire vers la page traitant les données -->
<form action="insert_sujet.php" method="post">
<table>
<tr><td>
[b]Auteur :[/b]
</td><td>
<input type="text" name="auteur" maxlength="30" size="50" value="<?php if (isset($_POST['auteur'])) echo htmlentities(trim($_POST['auteur'])); ?>">
</td></tr><tr><td>
[b]Titre :[/b]
</td><td>
<input type="text" name="titre" maxlength="50" size="50" value="<?php if (isset($_POST['titre'])) echo htmlentities(trim($_POST['titre'])); ?>">
</td></tr><tr><td>
[b]Message :[/b]
</td><td>
<textarea name="message" cols="50" rows="10"><?php if (isset($_POST['message'])) echo htmlentities(trim($_POST['message'])); ?></textarea>
</td></tr><tr><td><td align="right">
<input type="submit" name="go" value="Poster">
</td></tr></table>
</form>
<?php
// on affiche les erreurs éventuelles
if (isset($erreur)) echo '<br /><br />',$erreur;
?>
</body>
</html>



A présent, le système permettant d'insérer un nouveau sujet, est terminé. Il ne nous reste plus qu'à réaliser 1 page : celle contenant le formulaire pour insérer une réponse à un sujet (la page insert_reponse.php).

D'après la page lire_sujet.php, on remarque que le lien présent dans cette page (lien permettant d'accéder au formulaire de réponses) comporte une variable numero_du_sujet qui prend la valeur de l'id du sujet dont on veut répondre.
Par conséquent, on va transporter cette variable dans notre page insert_reponse.php.

On aura alors le code suivant (page insert_reponse.php) :

insert_reponse.php
<?php
// on teste si le formulaire a été soumis
if (isset ($_POST['go']) && $_POST['go']=='Poster') {
// on teste le contenu de la variable $auteur
if (!isset($_POST['auteur']) || !isset($_POST['message']) || !isset($_GET['numero_du_sujet'])) {
$erreur = 'Les variables nécessaires au script ne sont pas définies.';
}
else {
if (empty($_POST['auteur']) || empty($_POST['message']) || empty($_GET['numero_du_sujet'])) {
$erreur = 'Au moins un des champs est vide.';
}
// si tout est bon, on peut commencer l'insertion dans la base
else {
// on se connecte à notre base de données
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base) ;

// on recupere la date de l'instant présent
$date = date("Y-m-d H:i:s");

// préparation de la requête d'insertion (table forum_reponses)
$sql = 'INSERT INTO forum_reponses VALUES("", "'.mysql_escape_string($_POST['auteur']).'", "'.mysql_escape_string($_POST['message']).'", "'.$date.'", "'.$_GET['numero_du_sujet'].'")';

// on lance la requête (mysql_query) et on impose un message d'erreur si la requête ne se passe pas bien (or die)
mysql_query($sql) or die('Erreur SQL !'.$sql.'<br />'.mysql_error());

// préparation de la requête de modification de la date de la dernière réponse postée (dans la table forum_sujets)
$sql = 'UPDATE forum_sujets SET date_derniere_reponse="'.$date.'" WHERE id="'.$_GET['numero_du_sujet'].'"';

// on lance la requête (mysql_query) et on impose un message d'erreur si la requête ne se passe pas bien (or die)
mysql_query($sql) or die('Erreur SQL !'.$sql.'<br />'.mysql_error());

// on ferme la connexion à la base de données
mysql_close();

// on redirige vers la page de lecture du sujet en cours
header('Location: lire_sujet.php?id_sujet_a_lire='.$_GET['numero_du_sujet']);

// on termine le script courant
exit;
}
}
}
?>

<html>
<head>
<title>Insertion d'une nouvelle réponse</title>
</head>

<body>

<!-- on fait pointer le formulaire vers la page traitant les données -->
<form action="insert_reponse.php?numero_du_sujet=<?php echo $_GET['numero_du_sujet']; ?>" method="post">
<table>
<tr><td>
[b]Auteur :[/b]
</td><td>
<input type="text" name="auteur" maxlength="30" size="50" value="<?php if (isset($_POST['auteur'])) echo htmlentities(trim($_POST['auteur'])); ?>">
</td></tr><tr><td>
[b]Message :[/b]
</td><td>
<textarea name="message" cols="50" rows="10"><?php if (isset($_POST['message'])) echo htmlentities(trim($_POST['message'])); ?></textarea>
</td></tr><tr><td><td align="right">
<input type="submit" name="go" value="Poster">
</td></tr></table>
</form>
<?php
if (isset($erreur)) echo '<br /><br />',$erreur;
?>
</body>
</html>



Et voila, notre forum est à présent terminé :)


Que faire en plus ?

En effet, ce forum, si vous l'avez testé, n'a pas vraiment une gueule super fun, malgré le fait qu'il fonctionne parfaitement.
Pour l'améliorer, vous pouvez par exemple améliorer grandement sa présentation en utilisant de belles feuilles de style (css).
Vous pouvez également tester le contenu des variables (voir si elles sont vides ou pas avec la fonction empty et ainsi éviter que des messages vides viennent pollués votre forum).
Ou bien, pourquoi ne pas tenter de faire une petite gestion de simleys ?

A vos claviers :)
LoadingChargement en cours