Comment faire une messagerie interne en PHP

Voici un petit comment faire une messagerie interne basée sur le comment faire un espace membre.

En effet, car qui dit messagerie interne, dit forcément espace membre :)
Je me vois mal envoyer des messages à personne.

Pour la suite de ce comment faire, je vous suggère donc de récupérer d'une part, les pages PHP, et d'autre part, la table SQL de cet espace membre.
Nous allons apporter quelques modifications à ces pages PHP tout en ajoutant de nouvelles pages PHP.

Les premières modifications que nous allons apporter aux pages du comment faire un espace membre concernent les pages index.php et inscription.php.
En effet, pour plus de simplicité afin de gérer notre messagerie interne, et en fait, pour mieux reconnaître le membre connecté à l'espace membre, nous allons utiliser son id (qu'il a dans la table membre) plutôt que son login pour effectuer divers opérations

On aura alors le code suivant pour la page index.php :

index.php
<?php
if (isset($_POST['connexion']) && $_POST['connexion'] == 'Connexion') {
if ((isset($_POST['login']) && !empty($_POST['login'])) && (isset($_POST['pass']) && !empty($_POST['pass']))) {

$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base);

$sql = 'SELECT id FROM membre WHERE login="'.mysql_escape_string($_POST['login']).'" AND pass_md5="'.md5(mysql_escape_string($_POST['pass'])).'"';
$req = mysql_query($sql) or die('Erreur SQL !<br />'.$sql.'<br />'.mysql_error());
$nb = mysql_num_rows($req);

if ($nb == 1) {
$data = mysql_fetch_array($req);

session_start();
$_SESSION['login'] = $_POST['login'];
// on enregistre en plus l'id du membre dans une variable de session
$_SESSION['id'] = $data['id'];

mysql_free_result($req);
mysql_close();

header('Location: membre.php');
exit();
}
elseif ($nb == 0) {
$erreur = 'Compte non reconnu.';
}
else {
$erreur = 'Probème dans la base de données : plusieurs membres ont les mêmes identifiants de connexion.';
}
mysql_free_result($req);
mysql_close();
}
else {
$erreur = 'Au moins un des champs est vide.';
}
}
?>
<html>
<head>
<title>Accueil</title>
</head>

<body>
Connexion à l'espace membre :<br />
<form action="index.php" method="post">
Login : <input type="text" name="login" value="<?php if (isset($_POST['login'])) echo stripslashes(htmlentities(trim($_POST['login']))); ?>"><br />
Mot de passe : <input type="password" name="pass" value="<?php if (isset($_POST['pass'])) echo stripslashes(htmlentities(trim($_POST['pass']))); ?>"><br />
<input type="submit" name="connexion" value="Connexion">
</form>
<a href="inscription.php">Vous inscrire</a>
<?php
if (isset($erreur)) echo '<br /><br />',$erreur;
?>
</body>
</html>


Peu de commentaires à faire sur cette page, puisque nous avons en fait simplement ajouter une variable de session contenant l'id du membre qui se connecte.

Ensuite, cette modification doit également se répercuter sur la page inscription.php, puisque si le visiteur s'inscrit proprement, il est directement reconnu comme membre et il est directement redirigé vers l'espace membre.

Il faut donc également que les nouveaux inscris possèdent leur id en variable de session.



On aura alors le code suivant pour la page inscription.php :

inscription.php
<?php
if (isset($_POST['inscription']) && $_POST['inscription'] == 'Inscription') {
if ((isset($_POST['login']) && !empty($_POST['login'])) && (isset($_POST['pass']) && !empty($_POST['pass'])) && (isset($_POST['pass_confirm']) && !empty($_POST['pass_confirm']))) {
if ($_POST['pass'] != $_POST['pass_confirm']) {
$erreur = 'Les 2 mots de passe sont différents.';
}
else {
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base);

$sql = 'SELECT id FROM membre WHERE login="'.mysql_escape_string($_POST['login']).'"';
$req = mysql_query($sql) or die('Erreur SQL !<br />'.$sql.'<br />'.mysql_error());
$nb = mysql_num_rows($req);

if ($nb == 0) {
$sql = 'INSERT INTO membre VALUES("", "'.mysql_escape_string($_POST['login']).'", "'.md5(mysql_escape_string($_POST['pass'])).'")';
mysql_query($sql) or die('Erreur SQL !'.$sql.'<br />'.mysql_error());

// on récupère l'id de notre nouveau membre
$id = mysql_insert_id();

session_start();
$_SESSION['login'] = $_POST['login'];

// on stocke cet id dans une variable de session
$_SESSION['id'] = $id;
header('Location: membre.php');
exit();
}
else {
$erreur = 'Un membre possède déjà ce login.';
}
}
}
else {
$erreur = 'Au moins un des champs est vide.';
}
}
?>
<html>
<head>
<title>Inscription</title>
</head>

<body>
Inscription à l'espace membre :<br />
<form action="inscription.php" method="post">
Login : <input type="text" name="login" value="<?php if (isset($_POST['login'])) echo stripslashes(htmlentities(trim($_POST['login']))); ?>"><br />
Mot de passe : <input type="password" name="pass" value="<?php if (isset($_POST['pass'])) echo stripslashes(htmlentities(trim($_POST['pass']))); ?>"><br />
Confirmation du mot de passe : <input type="password" name="pass_confirm" value="<?php if (isset($_POST['pass_confirm'])) echo stripslashes(htmlentities(trim($_POST['pass_confirm']))); ?>"><br />
<input type="submit" name="inscription" value="Inscription">
</form>
<?php
if (isset($erreur)) echo '<br />',$erreur;
?>
</body>
</html>


Voila une bonne chose de faite :)

Concentrons maintenant sur le développement de notre messagerie interne, et réfléchissons à nos besoins (en terme de table SQL et de page PHP) pour amener à bien notre projet.

Qu'est ce qu'un message ?

Un message, c'est tout simplement :
  • deux utilisateurs A et B (A étant l'auteur du message qui écrit à B étant le destinataire du message).
  • un titre
  • une date d'émission
  • le message en lui-même :)


D'après cette petite réflexion, on peut décider de la structure de notre table SQL stockant les messages de notre messagerie interne.

Personnellement, je vous propose cette table :

table_messages.sql
CREATE TABLE messages (
id int(11) NOT NULL auto_increment,
id_expediteur int(11) NOT NULL default '0',
id_destinataire int(11) NOT NULL default '0',
date datetime NOT NULL default '0000-00-00 00:00:00',
titre text NOT NULL,
message text NOT NULL,
PRIMARY KEY (id)
) TYPE=MyISAM;


En effet, nous avons :
  • un attribut id qui nous permettra d'identifier chaque message de la messagerie
  • un attribut id_expediteur qui correspondra à l'id d'une des entrées de la table membre (jointure)
  • un attribut id_destinataire qui correspondra à l'id d'une des entrées de la table membre (jointure)
  • une date
  • un titre pour notre message
  • et le message en lui-même


Ensuite, en ce qui concerne les pages PHP à réaliser, nous devons :
  • modifier la page membre.php de l'espace membre afin qu'elle affiche les messages qu'a reçu le membre qui se connecte à l'espace membre
  • créer une page lire.php qui permettra de lire les messages
  • créer une page envoyer.php qui permettra au membre d'envoyer des messages privés aux autres membres du site
  • créer une page supprimer.php qui permettra de supprimer les messages de sa "boite" interne


Pour notre page membre.php, nous devons donc lancer une requête SQL qui ira chercher le titre, l'auteur mais aussi la date des messages qu'aura le membre qui se connecte à l'espace membre.
Et c'est là que va intervenir notre variable de session contenant l'id du membre qui se connecte.
En effet, cette variable va nous donner un énorme service puisque je vous le rappelle, dans notre table SQL messages, nous stockons les auteurs et les destinataires des messages avec l'id des membres et non leur login.

Nous aurons donc pour la page membre.php :

membre.php
<?php
session_start();
// on vérifie toujours qu'il s'agit d'un membre qui est connecté
if (!isset($_SESSION['login'])) {
// si ce n'est pas le cas, on le redirige vers l'accueil
header ('Location: index.php');
exit();
}
?>

<html>
<head>
<title>Espace membre</title>
</head>

<body>
Bienvenue <?php echo stripslashes(htmlentities(trim($_SESSION['login']))); ?> !<br /><br />
<?php
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base);

// on prépare une requete SQL cherchant tous les titres, les dates ainsi que l'auteur des messages pour le membre connecté
$sql = 'SELECT titre, date, membre.login as expediteur, messages.id as id_message FROM messages, membre WHERE id_destinataire="'.$_SESSION['id'].'" AND id_expediteur=membre.id ORDER BY date DESC';
// lancement de la requete SQL
$req = mysql_query($sql) or die('Erreur SQL !<br />'.$sql.'<br />'.mysql_error());
$nb = mysql_num_rows($req);

if ($nb == 0) {
echo 'Vous n\'avez aucun message.';
}
else {
// si on a des messages, on affiche la date, un lien vers la page lire.php ainsi que le titre et l'auteur du message
while ($data = mysql_fetch_array($req)) {
echo $data['date'] , ' - <a href="lire.php?id_message=' , $data['id_message'] , '">' , stripslashes(htmlentities(trim($data['titre']))) , '</a> [ Message de ' , stripslashes(htmlentities(trim($data['expediteur']))) , ' ]<br />';
}
}
mysql_free_result($req);
mysql_close();
?>
<br /><a href="envoyer.php">Envoyer un message</a>
<br /><br /><a href="deconnexion.php">Déconnexion</a>
</body>
</html>


Passons maintenant à la page lire.php.

La page lire.php est un peu particulière.
Cette page doit être sécurisée.

En effet, vous avez remarquez que dans la page membre.php, nous faisons un lien vers la page lire.php afin que les membres puissent lire les messages qu'ils ont reçu.
Or, afin d'identifier le message que le membre veut lire, nous passons en argument au script lire.php l'id du message.
Il est alors facile d'imaginer que les visiteurs pourront modifier simplement cet argument puisque celui-ci sera visible dans la barre d'adresse du navigateur.

Il est donc impératif de vérifier, à chaque lecture de message, si le message est bien destiné au membre qui est actuellement connecté à l'espace membre.

Sans tenir compte de ce problème, une requête SQL de la forme :

select.php
<?php
$sql = 'SELECT titre, date, message, membre.login as expediteur FROM messages, membre WHERE id_expediteur=membre.id AND messages.id="'.$_GET['id_message'].'"';
?>


aurait suffit.

Une méthode simple et qui ne coûte pas cher afin d'éviter ce problème est de carrément spécifier dans la requête SQL que l'id_destinataire doit avoir la même valeur que notre variable de session contenant l'id du membre connecté.

Nous aurons donc pour la page lire.php le code suivant :

lire.php
<?php
session_start();
// on vérifie toujours qu'il s'agit d'un membre qui est connecté
if (!isset($_SESSION['login'])) {
// si ce n'est pas le cas, on le redirige vers l'accueil
header ('Location: index.php');
exit();
}
?>

<html>
<head>
<title>Espace membre</title>
</head>

<body>
<a href="membre.php">Retour à l'accueil</a><br /><br />
<?php
// on teste si notre paramètre existe bien et qu'il n'est pas vide
if (!isset($_GET['id_message']) || empty($_GET['id_message'])) {
echo 'Aucun message reconnu.';
}
else {
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base);

// on prépare une requete SQL selectionnant la date, le titre et l'expediteur du message que l'on souhaite lire, tout en prenant soin de vérifier que le message appartient bien au membre connecté
$sql = 'SELECT titre, date, message, membre.login as expediteur FROM messages, membre WHERE id_destinataire="'.$_SESSION['id'].'" AND id_expediteur=membre.id AND messages.id="'.$_GET['id_message'].'"';
// on lance cette requete SQL à MySQL
$req = mysql_query($sql) or die('Erreur SQL !<br />'.$sql.'<br />'.mysql_error());
$nb = mysql_num_rows($req);

if ($nb == 0) {
echo 'Aucun message reconnu.';
}
else {
// si le message a été trouvé, on l'affiche
$data = mysql_fetch_array($req);
echo $data['date'] , ' - ' , stripslashes(htmlentities(trim($data['titre']))) , '</a> [ Message de ' , stripslashes(htmlentities(trim($data['expediteur']))) , ' ]<br /><br />';
echo nl2br(stripslashes(htmlentities(trim($data['message']))));

// on affiche également un lien permettant de supprimer ce message de la boite de réception
echo '<br /><br /><a href="supprimer.php?id_message=' , $_GET['id_message'] , '">Supprimer ce message</a>';
}
mysql_free_result($req);
mysql_close();
}
?>
<br /><br /><a href="deconnexion.php">Déconnexion</a>
</body>
</html>


Passons maintenant à la page envoyer.php.
Pour cette page, il n'y a aucune difficulté.

En effet, il s'agit juste de proposer un formulaire contenant 3 champs :
  • un menu déroulant avec tous les membres du site afin de spécifier le destinataire du message
  • un champ de type text pour donner le titre du message
  • une zone de texte permettant d'écrire son message


Nous ferons toutefois attention à ne pas mentionner le nom du membre connecté dans la liste des destinataires potentiels.
En effet, ça serait dommage que l'on puisse écrire à soit même :)

Nous aurons alors le code suivant pour la page envoyer.php :

envoyer.php
<?php
session_start();
// on vérifie toujours qu'il s'agit d'un membre qui est connecté
if (!isset($_SESSION['login'])) {
// si ce n'est pas le cas, on le redirige vers l'accueil
header ('Location: index.php');
exit();
}

// on teste si le formulaire a bien été soumis
if (isset($_POST['go']) && $_POST['go'] == 'Envoyer') {
if (empty($_POST['destinataire']) || empty($_POST['titre']) || empty($_POST['message'])) {
$erreur = 'Au moins un des champs est vide.';
}
else {
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base);

// si tout a été bien rempli, on insère le message dans notre table SQL
$sql = 'INSERT INTO messages VALUES("", "'.$_SESSION['id'].'", "'.$_POST['destinataire'].'", "'.date("Y-m-d H:i:s").'", "'.mysql_escape_string($_POST['titre']).'", "'.mysql_escape_string($_POST['message']).'")';
mysql_query($sql) or die('Erreur SQL !'.$sql.'<br />'.mysql_error());

mysql_close();

header('Location: membre.php');
exit();
}
}
?>

<html>
<head>
<title>Espace membre</title>
</head>

<body>
<a href="membre.php">Retour à l'accueil</a><br /><br />
Envoyer un message :<br /><br />

<?php
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base);

// on prépare une requete SQL selectionnant tous les login des membres du site en prenant soin de ne pas selectionner notre propre login, le tout, servant à alimenter le menu déroulant spécifiant le destinataire du message
$sql = 'SELECT membre.login as nom_destinataire, membre.id as id_destinataire FROM membre WHERE id <> "'.$_SESSION['id'].'" ORDER BY login ASC';
// on lance notre requete SQL
$req = mysql_query($sql) or die('Erreur SQL !<br />'.$sql.'<br />'.mysql_error());
$nb = mysql_num_rows ($req);

if ($nb == 0) {
// si aucun membre n'a été trouvé, on affiche tout simplement aucun formulaire
echo 'Vous êtes le seul membre inscrit.';
}
else {
// si au moins un membre qui n'est pas nous même a été trouvé, on affiche le formulaire d'envoie de message
?>
<form action="envoyer.php" method="post">
Pour : <select name="destinataire">
<?php
// on alimente le menu déroulant avec les login des différents membres du site
while ($data = mysql_fetch_array($req)) {
echo '<option value="' , $data['id_destinataire'] , '">' , stripslashes(htmlentities(trim($data['nom_destinataire']))) , '</option>';
}
?>
</select><br />
Titre : <input type="text" name="titre" value="<?php if (isset($_POST['titre'])) echo stripslashes(htmlentities(trim($_POST['titre']))); ?>"><br />
Message : <textarea name="message"><?php if (isset($_POST['message'])) echo stripslashes(htmlentities(trim($_POST['message']))); ?></textarea><br />
<input type="submit" name="go" value="Envoyer">
</form>
<?php
}
mysql_free_result($req);
mysql_close();
?>
</select>

<br /><br /><a href="deconnexion.php">Déconnexion</a>
<?php
// si une erreur est survenue lors de la soumission du formulaire, on l'affiche
if (isset($erreur)) echo '<br /><br />',$erreur;
?>
</body>
</html>


Reste enfin à nous concentrer sur la page supprimer.php.

Comme vous l'avez remarqué, dans la page lire.php, nous affichons un lien permettant de supprimer le message en cours de lecture.
Et comme pour la page lire.php, nous passons en argument au script supprimer.php l'id du message qui doit être effacé.
Nous devons alors donc bien vérifier dans la page supprimer.php que le message qui est en cours de suppression appartient bien au membre qui essaye de le supprimer.

Nous utiliserons la même technique que pour vérifier que le message en cours de lecture appartient bien au membre qui essaye de le lire, c'est-à-dire que nous utiliserons la variable de session contenant l'id du membre.

On aura alors pour supprimer.php :

supprimer.php
<?php
session_start();
// on vérifie toujours qu'il s'agit d'un membre qui est connecté

if (!isset($_SESSION['login'])) {
// si ce n'est pas le cas, on le redirige vers l'accueil
header ('Location: index.php');
exit();
}

// on teste si l'id du message a bien été fourni en argument au script envoyer.php
if (!isset($_GET['id_message']) || empty($_GET['id_message'])) {
header ('Location: membre.php');
exit();
}
else {
$base = mysql_connect ('serveur', 'login', 'password');
mysql_select_db ('nom_base', $base);

// on prépare une requête SQL permettant de supprimer le message tout en vérifiant qu'il appartient bien au membre qui essaye de le supprimer
$sql = 'DELETE FROM messages WHERE id_destinataire="'.$_SESSION['id'].'" AND id="'.$_GET['id_message'].'"';
// on lance cette requête SQL
$req = mysql_query($sql) or die('Erreur SQL !<br />'.$sql.'<br />'.mysql_error());

mysql_close();

header ('Location: membre.php');
exit();
}
?>


Voila :)

Que faire en plus ?

Je vous propose plusieurs améliorations :
  • faire une gestion de smiley
  • faire une gestion de BB-Code
  • rajouter un champ dans la table SQL afin d'identifier les messages lus ou non lus
  • faire une page repondre.php permettant de répondre à un message en reprenant le message reçu
  • n'afficher sur la page membre.php que le nombre de messages contenus dans la boite de chaque membre et de rajouter un lien vers la messagerie en elle-même
  • faire une petite gestion de contacts


A vos claviers :)
LoadingChargement en cours