mercredi 30 mars 2005

Modèle de cycle de développement


MODÈLE DE CYCLE DE DÉVELOPPEMENT

Dans le précédent article, nous avons vu un cycle de façon générale qui ne s'apparente pas réellement à un modèle en particulier. Chaque phase des cycles doivent être soumis à des tests afin d'assurer une certaine qualité qui est déterminante pour le génie logiciel. De nombreux modèles existent, nous allons discuter des plus populaires.

Modèle en cascade

C'est un des premiers modèles qui a été proposé. Il date des années 70. Ce modèle est strict et lourd. Chaque phase doit être approuvée avant de pouvoir commencer l'autre.




Tel que le suggère l'image, chaque étape doit être terminée avant dans entamé une autre. Plus on avance dans les étapes, moins il devrait avoir de risque. On avance donc par pas.

L'avantage de ce modèle est que chaque phase est finie, elle est donc gérable tant au niveau du temps que des ressources. Le code est créé assez tardivement, il y a donc une bonne compréhension du système. Au niveau des inconvénients, on peut noter que ce modèle ne représente pas la réalité. Il est possible de revenir en arrière, car des erreurs ont été découvertes, car on doit créer des tests ce qui implique du code. Il y a des risques de découvrir des erreurs qu'a la fin et qui nécessiteront de refaire toutes les étapes. L'ajout de nouvelle exigence implique qu'il faille refaire toutes les étapes. Plus un problème ou un changement doit être fait tard, plus il coûtera cher.

Ce modèle est encore très utilisé, mais a été revu dans sa version initiale. Dans la nouvelle version, il est possible de revenir en arrière et des prototypes sont créé à chaque phase. Il est ainsi dans cette nouvelle version, plus près de la réalité.

Modèle en V

Le principe de ce modèle, est que chaque étape de décomposition du système possède une phase de test. Chaque phase du projet à une phase de test qui lui est associé. Beaucoup de tests sont ainsi créés, ce qui implique une réflexion. On sait progressivement si on s'approche de ce que le client désire.



Ce modèle est convenable pour les projets complexes. C'est un modèle dérivé du modèle en cascade.

Modèle par incrément

Dans ce modèle, un seul composant est développé à la fois. On débute par définir les exigences et on les décompose en sous-système. À chaque version du logiciel, de nouvelles fonctionnalités venant combler les exigences sont ajoutées. On continue de la sorte jusqu'à ce que toutes les fonctionnalités demandées soient comblées par le système. Chaque incrément peut utiliser un autre modèle (v, en cascade...).



L'image n'affiche que deux incrémentations, mais il peut y en avoir plusieurs.
Le développement sont ainsi moins complexe, l'intégration est moins brutal et le client a plus rapidement un système même s'il n'est pas complet. Par contre, le coeur du système peut être à revoir lorsqu'on passe à une autre incrémentation du système. Il peut ainsi s'avérer complexe d'ajouter certaines fonctionnalités.
Ce modèle convient au projet de grande envergure. L'architecture doit être bien pensée dès le départ afin de réduire les risques par la suite.

Modèle en spirale

Ce modèle est plus récent, il date du milieu des années 80. L'emphase de ce modèle et mise sur la réduction des risques. Ce modèle est adapté pour les gros projets complexes. Les risques sont sans cesse évalués à chaque cycle. Un cycle est décomposé en étapes.
  • Analyse préliminaire pour le premier cycle, pour les autres cycles, on détermine les objectifs, contrainte à partir du résultat du cycle antérieur.
  • Analyse des risques, création de prototype
  • Développement et test
  • Planification du cycle suivant


Les prototypes créés à chaque cycle permettent de réduire les risques et de guider la conception pour obtenir un système qui répond au besoin du client. Chaque cycle de la spirale fait en sorte que le système est de plus en plus complet.

Modèle UP

Unified Process est une méthode générique de développement. C'est une méthode qui permet l'évolution telle que le fait le modèle en spirale. Cette méthode impose la création de beaucoup de documentations. Cette méthode est beaucoup liée au produit que propose cette compagnie Rational Rose (appartenant maintenant à IBM). L'automatisation fait partie de UP. Cette méthode tente de mettre en oeuvre différentes pratiques afin d'obtenir un produit de qualité



  • Modèle de développement itératif

    Fréquemment, une version du logiciel est présentée au client. Une telle approche permet de réduire les risques de ne pas répondre aux à ses besoins. La qualité peut être ainsi vérifiée à chaque fois.
  • Gestion des exigences

    Énormément d'importance est mise au niveau des exigences afin qu'elle soit prise en compte complètement.
  • Utilisation de composant

    La création du système en assemblant des composants est privilégié. L'achat de composant permet une certaine garantie de test.
  • Diagramme des exigences

    Beaucoup de diagrammes sont disponibles, le client peut ainsi plus aisément comprendre. La grande quantité de diagrammes permettent de voir le système sous différentes facettes.
  • Vérification de la qualité

    La qualité est constamment vérifiée à chaque version du logiciel. On s'approche progressivement des besoins du client. Le risque d'erreur est moindre.
  • Gestion des changements

    Les demandes de changement sont enregistrées ensuite on passe par une phase d'acceptation. Les changements sont ainsi mieux maîtrisé.
Quelques disciplines font parties de UP, ce sont les éléments à gauche de l'image.
  • Besoin
  • Analyse
  • Conception
  • Implémentation
  • Test

Besoin

Cette activité permet de connaître le domaine du système qui doit être construit. Ces informations permettront de créer des cas d'utilisation. Une liste d'entité et d'objets-métier sont saisit.

Analyse

Les besoins et exigences du client doivent être minutieusement compris afin de pouvoir arriver à faire une conception du système. On raffine ces informations afin d'arriver à une analyse plus précise. Cette analyse permet de faciliter davantage les étapes suivantes.

Conception

Cette activité permet de comprendre de façon plus approfondie le système. Les contraintes du système doivent être définies : langage de programmation, système d'exploitation, technologie utilisée. Des interfaces entre les sous-sytèmes doivent être déterminées. C'est l'endroit où tout le système est pensé et analysé en vue de son implémentation. Une excellente planification du système doit être faite.

Implémentation

Cette activité utilise les étapes précédentes afin de construire un système au niveau du code. À chaque itération, une intégration est faite. Des tests unitaires sont faits. Les classes identifiées à la phase conception sont implémentées.

Test

Cette activité permet de vérifier les résultats de la phase précédente. Les tests doivent spécifier ce qui doit être testé, les résultats attendu et obtenu.
Quatre phases composent UP:
  • Création
  • Élaboration
  • Construction
  • Transition


Création

Une idée du système est donnée. On identifie ce que le système va faire, on établit l'architecture, on définit l'échéancier, les coûts et ressources nécessaires. Une liste des risques est identifiée. Les limites du système sont définies : ce que le système fait et ce qu'il ne fait pas.

Élaboration

Cette phase permet de concevoir et valider l'architecture du système. Les cas d'utilisations sont précisés.

Construction

La construction du système est faite. Les exigences définies doivent être comblées.

Transition

Cette étape vérifie ce qui a été fait. Le produit est installé chez le client. Les anomalies de dernières minutes sont corrigées. Le système est configuré.

UP est un modèle itératif et incrémental. Une itération est un sous-projet dérivé du projet informatique. Le découpage du projet en plus petite entité réduit la complexité et les risques. Un incrément est une version du système.

Ce modèle, comme tous les autres présentent quelques défauts. Il est coûteux à mettre en oeuvre et à personnaliser. L'emphase est mise au processus, peu de place est accordée au développement. Le codage ainsi que la technologie n'occupent pas assez de place. Les systèmes ayant majoritairement que des algorithmes, peu d'interaction avec des utilisateurs ne conviennent pas à ce modèle.

samedi 26 mars 2005

Les conditions

LES CONDITIONS
Les conditions sous Bash sont très différentes de ce qu'on peut retrouver dans les autres langages de programmation telle que le C, pascal, Java... Les espaces sont importants, s'ils ne sont pas pris en considérations, il est possible que le script ne puisse fonctionner. Une autre particularité est qu'il existe différents paramètres selon ce qu'on désire tester.

Tableau des opérateurs

Opérateur Description (retourne vrai si..)
-d si le répertoire existe
-e si le fichier existe
-f si le fichier (pas un répertoire ou fichier de périphérique: /dev/sda1...)
-r si le fichier peut être lu
-w si le fichier peut être écrit
-x si le fichier peut être exécuté
-L si le fichier est un lien symbolique
-z si la chaine de caractère est nulle
-n si la chaine de caractère n'est pas nulle
-eq s'ils sont équivalents (nombre)
-neq s'ils ne sont pas équivalents
= ou == si les chaines de caractère ou nombre sont égaux
!= s'ils ne sont pas égaux
-lt est plus petit que
-gt est plus grand que
-le est plus petit ou égale
-ge est plus grand ou égale
-a ou && et logique
-o ou || ou logique

Quelques exemples

On vérifie ci-dessous si le fichier qemu.htm existe. S'il existe, nous affichons un message.
if [ -e qemu.htm ]; then
  echo "Qemu.htm existe";
fi
On vérifie ci-dessous si le contenu de la variable X est plus petit que Y.
X=3
Y=12
if [ $X -lt $Y ]
then
  echo "\$X=$X, est plus grand ou égale \$Y=${Y}"
fi
Notez que si on ne met pas de ";" à la fin du if, le then doit être sur la prochaine ligne. En mettant "\" devant le nom de la variable existante, c'est le nom de la variable qui est affiché.
On vérifie si les chaînes de caractères sont identiques
X="allo"
Y="aillo"
if [ $X = $Y ]; then
 echo "les chaines sont identiques";
else
 echo "les chaines ne sont pas identiques";
fi
Il est possible de savoir si une chaîne de caractère débute ou se termine par un certain caractère.
X="allo"
if [[ $X == a* ]]; then
 echo "$X commence par a";
fi

X="allo2"
if [[ $X == *2 ]]; then
 echo "$X fini par 2";
fi
Les comparaisons binaires peuvent être faites de deux façons avec les opérateurs. Soit, on utilise -a ou && pour le et binaire. Soit on utilise -o ou || pour le ou binaire.
X=33
Y=23
A=12
B=23
if [ $X -gt $Y ] && [ $A -lt $B ]; then
 echo "$X est plus grand que $Y et $A est plus petit que $B ";
fi
Notez que si vous utilisez directement -a (ou -o) vous devez écrire:
X=33
Y=23
A=12
B=23
if [ $X -gt $Y -a $A -lt $B ]; then
 echo "$X est plus grand que $Y et $A est plus petit que $B ";
fi

Imbrication de if

Lorsqu'on a plusieurs de suites, on doit utiliser elif.
X=20
Y=30
Z=40
if [ $Z -lt $X ]; then
 echo "$Z est plus petit que $X";
elif [ $Z -lt $Y ]; then
 echo "$Z est plus petit que $Y";
else
 echo "$Z est plus petit que 50";
fi

Case

Au lieu d'utiliser de nombreux if et else, il peut être pratique d'utiliser un case afin de simplifier le code et de le rendre plus lisible.
echo "Fait t'il soleil ? [oui or non]: "
read reponse
    case $reponse in
        o* | O*)
                echo "vous avez repondu qu'il faisait soleil";
                ;;
        n* | N*)
                echo "vous avez repondu qu'il ne faisait pas soleil";
                ;;
        *)
                echo "vous avez mal répondu à la question";
                ;;
    esac
Vous pouvez noter que chaque condition se termine par ")", qu'à la fin de chaque commande on a ";;" et qu'on inscrit esac à la fin. Il arrive souvent qu'on inscrive la commande à l'envers en bash. Au début de ce script, on pose une question à l'usager. Lorsque l'utilisateur tapera sur une touche et appuiera sur entrée, cette touche sera lu (grâce à la fonction read) et une action sera faite selon sa valeur.

Nous avons completé la partie traitant des conditions. Un script avec tous les exemples peut être téléchargé ici

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.

samedi 19 mars 2005

Espace membre

ESPACE MEMBRE

Dans cet article, nous allons voir comment créer un espace membre. Il y a plusieurs raisons de créer un espace membre, la première peut être la sécurité. Il peut être intéressant de laisser tout le monde lire des messages sur notre forum, mais seulement ceux qui sont membres d'y écrire. Nous avons ainsi de moyen de savoir qui a écrit le message, son adresse IP...
Dans cet article, nous allons voir:
  • Inscription
  • Authentification
  • Oublie de mot de passe
  • Déconnection

Inscription

L'inscription d'un membre est l'occasion d'obtenir diverses informations sur l'usager. Voici une structure de table possible :

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',
  `MEM_ENREGISTRE` int(11) default '0',
  PRIMARY KEY  (`MEM_NOMEMBRE`)
) TYPE=MyISAM AUTO_INCREMENT=9 ;
Au niveau du code, il suffit de créer un formulaire. Afin de limiter les inscriptions automatiques par des scripts malicieux, il est possible d'ajouter une série de lettres dans une image. L'usager devra taper ces lettres. De nombreux sites utilisent cette technique.

Protection

Tel que dit précédemment, il est important d'ajouter une protection afin d'éviter des inscriptions multiples. Afin de mettre en oeuvre cette protection, nous allons générer une suite de lettre de façon aléatoire et ensuite créer une image avec ces lettres. Il est ainsi beaucoup plus complexe d'obtenir la valeur des lettres.
function gen_reg_key() {

   //on initialise la variable $key à "vide"

   $key = "";

   //on définit la taille de la chaine (6 caractères ca suffit ;))

   $max_length_reg_key = 6;

   //on définit le type de caractères ascii de la chaine (l'alphabet suffit amplement, mais libre a vous)

   $chars = array(

      "a","b","c","d","e","f","g","h","i","j","k","l","m",

      "n","o","p","q","r","s","t","u","v","w","x","y","z");

   //on comptabilise le nombre total de caractères possibles (26 pour l'alphabet)

   $count = count($chars) - 1;

   //on initialise la fonction rand pour le tirage aléatoire

   srand((double)microtime()*1000000);

   //on tire aléatoirement les $max_length_reg_key caracteres de la chaine

   for($i = 0; $i < $max_length_reg_key; $i++) $key .= $chars[rand(0, $count)];

   //on renvois la clé générée

   return($key);

} 
Maintenant que la chaîne est générée, nous allons créer une image cette chaîne. Noter que la source ci-dessus provient d'une source inconnue.
//En-tête définissant le format png header

header ("Content-type: image/png"); 

//Crée une nouvelle image à palette d'une taille de 100 pixels de largeur par 50 pixels de hauteur

$im = @ImageCreate (100, 50) or die ("Erreur lors de la création de l'image");

//Alloue une couleur pour le fond de l'image

$bgcolor = ImageColorAllocate ($im, 0xC0, 0xC0, 0xC0); //Ca correspond à #C0C0C0

//Alloue une couleur pour le texte de l'image

$font = ImageColorAllocate ($im, 0x00, 0x00, 0x00);

ImageString ($im, 5, 20, 15,base64_decode($_GET['code']),$font);

//Envoie l'image PNG vers le navigateur

ImagePng ($im);

//Désalloue la mémoire de l'image
ImageDestroy($im);

La chaîne générée est passée à ce script d'où le $_Get. La protection ainsi que les données entrées par l'usager doivent être validées afin d'insérer des données uniquement valides dans la base de données. Au niveau des validations, vous pouvez vérifier si le courriel est valide, si le nom de l'utilisateur est déjà présent.

Envoie du courriel

Il est très aisé d'envoyer un courrier en PHP. Le code ci-dessous est employé pour activer le mot compte de l'usager lors de son inscription. Il faut s'assurer d'avoir la fonction PHP mail().
function envoiecourrielvalidation($nom, $nomusager, $to, $motpasse, $nomembre)
  {
    /* sujet */
    $subject = "Inscription: La boîte à prog";
  
    /* message */
    $message = "Bonjour, ".$nom." ! \n\nMerci de vous être enregistré.   Vous êtes priés de conserver cet e-mail dans vos archives. \nVoici les informations concernant votre compte : \n \nNom d'utilisation : ".$nomusager." \nMot de passe: ".$motpasse." \n \nPour activer votre compte, veuillez cliquer sur ce lien :  http://www.laboiteaprog.com/activation.php?mem_nomembre=$nomembre  \n\nL'équipe Forum La boîte à prog";
  
    $headers = "From: La boite à prog <collinm@laboiteaprog.com>\r\n";
    /* and now mail it */
    mail($to, $subject, $message, $headers);
 }

Validation du courriel

Une manière de limiter les abus est de valider le compte de l'usager en lui envoyant un courriel. Cette façon permet de savoir si le courriel inscrit par l'usager est valide et assure de pouvoir retracer l'usager si nécessaire. La validation du courriel se fait si toutes les données entrées par l'usager sont valides. Utiliser la fonction mail de PHP pour envoyer un courriel. Utiliser un gabarit tel que:

Bonjour, Paul Newman !
Merci de vous être enregistré.   
Vous êtes priés de conserver ce courriel dans vos archives.

Voici les informations concernant votre compte : 
Nom d'utilisation : pauln
Mot de passe: arlvlr

Pour activer votre compte, veuillez cliquer sur ce lien :  http://www.laboiteaprog.com/activation.php?mem_nomembre=1

L'équipe Forum La boîte à prog";

Dans le script activation, on vérifie si l'usager à déjà activer son compte. Le champ MEM_ENREGISTRE sert à savoir si l'usager a déjà activé son compte. Si la valeur est 0, son compte n’est pas actif.

connectionbd();
    entete("Activation","");
    
    $mem_nomembre = $_GET['mem_nomembre'];
    
    
    $requete = mysql_query("SELECT mem_nomembre, mem_motpasse, mem_type, mem_enregistre from membre where mem_nomembre=$mem_nomembre ");
    
    $ligne = mysql_fetch_assoc($requete);
    
    //verifier dans la bd si le compte est déjà actif... si oui on affiche un message
    if($ligne["mem_enregistre"] == 1){
    
      echo '<div>Activation</div>';
      echo'<div>';
        
      echo"Votre compte a déjà été activé. Merci";
        
      echo'</div>';
    
    }
    else{
    
      $_SESSION['username'] = $username;
      $_SESSION['password'] = $password;
      $_SESSION['mem_nomembre'] = $mem_nomembre;
      
      mysql_query("update membre set mem_enregistre = 1 where  mem_nomembre= $mem_nomembre ");
      
      echo '<div >Activation</div>';
      echo'<br/><div>';
      echo"Vous venez d'activer votre compte, vous pouvez maintenant envoyez des messages et participer au site. Merci";
        
      echo'</div>';
      
    }
    closebd();
    piedpage();
  }
Si le compte de l'usager n'est pas encore actif, il le devient et on enregistre des variables de session afin que l'usager puise avoir accès aux fonctions réservées au membre.

Authentification

Cette partie consiste à vérifier le nom d'utilisateur ainsi que le mot de passe entrée par l'usager, si les informations sont valides, l'usager à accès au site et on enregistre dans des variables de session quelques informations (tel que vue précédemment). Le code nécessaire pour vérifier les données est identique à celui montré précédemment. Si les données sont valides, nous pouvons rediriger l'usager par exemple dans une section spéciale du site.

Oublie de mot de passe

Il est possible, qu'un usager oublie son mot de passe pour de multiples raisons. Un script qui génèrera un mot de passe aléatoire permettra de nouveau à l'usager de se connecter au site.

Le script pour générer un mot aléatoire qui a été utilisé lors d'un l'inscription de l'usager peut être réutilisé de nouveau pour l'oublie d'un mot de passe. Le nouveau mot de passe est envoyé par courriel à l'usager. Un gabarit qui pourrait ressembler à celui montré dans la section Validation du courriel peut être utilisé.

Déconnection

Cette fonctionnalité supprime les variables de session créée lors de la connexion de l'usager et redirige l'usager sur la page principale du site.

session_start();
if(session_is_registered("username")){
  session_destroy();
$url="/index";
header("location: $url");

Fonctionnalité

Une fois que l'utilisateur est connecté, tous vous est permis. Prenons exemple sur ce site, une fois connecté, vous pouvez participer au site, modifiez votre profil...
Nous avons vu quelques fonctionnalités de base pour gérer un espace membre sur un site.

D'autres fonctionnalités peuvent être ajoutées, un chat en ligne, amélioration de la sécurité... afin d'avoir un espace membre encore plus riche.