Valid XHTML     Valid CSS2    

DECRA, T.P. 5 :

     Fonctions, cahier des charges et modification d'un gros programme

Décomposition, Conception et Réalisation d'Applications

                    gilles.hunault "at" univ-angers.fr

 

Table des matières cliquable

  1. Gérer la liste des fonctions d'une application

  2. Un cahier des charges pour la prise de rendez-vous

  3. Modifier un "gros" programme

  4. Réécrire un gros programme

 

Il est possible d'afficher toutes les solutions via ?solutions=1 et de les masquer via ?solutions=0.

 

1. Gérer la liste des fonctions d'une application

On trouvera dans l'archive shsp.zip une copie à peu près complète du site sHSPdb qui recense des petites protéines HSP. Cette archive a une taille un peu inférieure à 8 Mo et contient 266 fichiers, dont 52 fichiers PHP (mais qui ne sont pas tous utilisés dans le site).

               non su

On se propose ici de fournir une aide au programmeur sous forme d'une liste des fonctions utilisées à partir du fichier index.php. On voudrait produire dans un premier temps un fichier qui recense les fichiers inclus, les fonctions et l'endroit où elles sont définies, comme dans le fichier shspdb_fns.txt. Ecrire pour cela un script qui utilise un fichier de départ (ici index.php) passé en paramètre et qui construit une telle liste.

Fichier shspdb_fns.txt

Quelle charge de travail supplémentaire serait requise si on voulait produire une interface de ces fonctions comme pour le PHP conceptuel ? Pour mémoire, cette interface est ici.

On commencera bien sûr par se poser la question du langage de programmation à utiliser et par écrire un plan de développement.

Pour cet exercice, on pourra définir un répertoire Shspdb et y rapatrier l'archive comme suit :


     cd     ~/Mes_projets_web
     mkdir  Shspdb
     cd     Shspdb
     wget   http://forge.info.univ-angers.fr/~gh/Decra/shsp.zip
     unzip  shsp.zip
     

Le plan de développement est présenté ici.

Solution :  

1.1 Choix du langage

Un langage bien adapté serait sans doute AWK ou Perl. Toutefois, dans la mesure où peu de personnes dans la promotion connaissent ce langage, on propose ici une solution PHP. Les curieuses et curieux pourront lire la solution Perl disponible ici.

1.2 Plan de développement

Il est sans doute raisonnable de faire quelques «repérages» dans les fichiers PHP fournis avant de programmer quoi que ce soit, car PHP est permissif et a de nombreuses syntaxes possibles pour la même action d'inclusion de fichiers. Ainsi, mettre un espace avant la parenthèse ouvrante dans une définition de fonction n'est pas une erreur. Il y a deux problèmes distincts ici : trouver les fichiers inclus et lister les fonctions dans ces fichiers. C'est pourquoi nous proposons un plan de développement nommé tp5exo1.php en 5 étapes, 2 sous Unix et 3 en PHP.

1.3 Interface des fonctions

Ce n'est sans doute pas une bonne idée de produire une interface pour ces fonctions pour au moins deux raisons. Tout d'abord, il y a beaucoup trop de fichiers inclus et de fonctions en tout. Ensuite, certaines de ces fonctions ne sont pas génériques et ne servent qu'à fournir des parties facilement décomposables.

1.4 Détail des solutions

Etape Fichier principal Fichier inclus

1   

listefnsV1.php

listefnsV1-inc.php

2   

listefnsV2.php

listefnsV2-inc.php

3   

listefnsV3.php

listefnsV3-inc.php

Les commentaires qui utilisent trois dièses successifs dans la version 3 indique les étapes principales. On peut les consulter via la commande

         grep -a  "###" listefnsV3.php.


     ### 1. vérification des paramètres
     ### 2. on cherche les noms de fichiers via les fonctions include_once() et require_once()
     ### 3. affichage numéroté et trié des fichiers à lister avec nombre de lignes
     ### 4. recherche des définitions de fonction
     

Les commentaires qui utilisent au moins deux dièses successifs dans cette même version 3 indique les étapes principales ou secondaires. On peut les consulter via la commande

         grep -a  "##" listefnsV3.php.


     ### 1. vérification des paramètres
     ### 2. on cherche les noms de fichiers via les fonctions include_once() et require_once()
     ### 3. affichage numéroté et trié des fichiers à lister avec nombre de lignes
     ##     3.1 tri de la liste via explode/sort/implode
     ##     3.2 affichage de la liste des fichiers
     ### 4. recherche des définitions de fonction
     ##     4.1 on passe en revue tous les fichiers pour trouver function comme mot 1
     ##     4.2 on trie la liste des fonctions et on l'affiche
     ##     4.3 liste par fichier (algorihtme de parcours naif)
     

 

2. Un cahier des charges pour la prise de rendez-vous

On décide d'aider les enseignants à construire les oraux de présentation de rapport de stage. Ces oraux mettent en présence l'étudiant, le maitre de stage, l'enseignant référent et le directeur de la formation. Sachant que ces oraux se déroulent sur deux jours pour une plage horaire de 9 h à 12 h puis de 14 h à 18 h et que chaque oral occupe un créneau de 30 minutes (20 minutes d'exposé et questions plus 10 minutes de délibération), essayer de définir toutes les fonctionnalités qu'un site de réservation de créneaux devrait avoir, les classes d'objets et les tables de la base de données à créer. On justifiera les choix retenus.

Quel langage serait le plus adapté ?

Quel moteur de base de données serait le plus adapté ?

Seriez-vous capable de quantifier le temps nécessaire au développement de ce site ?

               non su

On essaiera aussi de choisir et de justifier les technologies à utiliser (serveur Lamp, architecture basée sur Node.js, application Django ou ROR...).

Pourrait-on envisager une solution SAAS ('qu'est-ce  ?) comme pour le tournoi de tennis de Roland-Garros ?

Solution :  

Il est sans doute raisonnable de commencer par essayer de lister les actions à effectuer avant d'effectuer des choix. Dans la mesure où il y a plusieurs types d'acteurs différents (étudiant, maitre de stage, enseignant référent...), le mieux est de séparer les actions, quitte à voir ensuite ce qui peut être factorisé. Après, il faut définir les classes d'objets à construire et penser aux petites tables de données annexes liées à des qualités/modalités liées aux personnes, aux stages et aux entreprises...

2.1 Acteurs et actions associées

Acteur étudiant

  • fixer une ou plusieurs dates de rendez-vous

  • annuler un rendez-vous

  • modifier un rendez-vous

  • lister les rendez-vous

  • recevoir une confirmation du rendez-vous dès la prise de rendez-vous

  • recevoir un rappel du rendez-vous quelques jours avant la soutenance

  • savoir où trouver toutes les informations sur les dates de rendez-vous, les fiches d'appréciation de stage

Acteur maitre de stage

  • disposer/éditer/transmettre la fiche d'appréciation du stage, volet maitre de stage

  • lister les rendez-vous

  • recevoir une confirmation du rendez-vous dès la prise de rendez-vous

  • recevoir un rappel du rendez-vous quelques jours avant la soutenance

Acteur enseignant référent

  • accéder à la fiche détaillée du stage

  • recevoir une confirmation du rendez-vous

  • lister les rendez-vous

  • recevoir un rappel du rendez-vous quelques jours avant la soutenance

  • disposer/éditer/transmettre la fiche d'appréciation du stage, volet enseignant

Acteur directeur de la formation

  • lister les rendez-vous

  • imprimer une liste officielle des rendez-vous

  • réinitialiser les rendez-vous

  • lister/imprimer/archiver les fiches d'appréciation de stage

  • réaliser des statistiques sur les stages de l'année, au fil des années, par catégorie de stage, d'entreprises...

Acteur administrateur du site (et donc de la base de données ???)

  • relancer les partenaires pour disposer des nouvelles informations chaque année

  • actualiser la base de données

  • tester les nouvelles informations

2.2 Choix et contraintes

Dates et heures

Le nombre de jours et la plage horaire des soutenances n'est pas un gros problème à traiter. Il faut simplement que les jours et les heures soient bien paramétrés pour que ce soit facile à gérer.

Nombre de rendez-vous

Le nombre de rendez-vous à autoriser est beaucoup plus problématique. La solution la plus simple et pratiquement toujours implémentée passe par un seul rendez-vous possible. Il n'est pas stupide d'essayer de penser à en mettre plusieurs, pour offrir plus de souplesse aux maitres de stage en entreprise. Cela suppose bien sûr de disposer de beaucoup de plages horaires, au moins deux fois plus que de stages. Il faudrait alors rajouter des relances s'il reste des rendez-vous multiples avant la date de publication des soutenances de stages.

2.3 Classes d'objets Stages, Personnes, Entreprises, Soutenances, Salles

Un stage comporte un intitulé (court), un descriptif (long), une catégorie de stage (programmation, analyse... ou "non détaillé"), un stagiaire (plusieurs ?), un maitre de stage, une entreprise, un enseignant référent, un niveau d'étude, une année de stage.

Une personne doit certainement être définie par un nom, un prénom et un code-sexe, un numéro de téléphone (deux pour un stagiaire, un maitre de stage ?), une (deux ?) adresse, un email. Pour le maitre de stage, il faudra rajouter un lien vers l'entreprise. Il n'y aura sans doute rien à rajouter pour l'enseignant référent ni pour le responsable de la formation.

Une entreprise doit certainement être définie via un numéro de téléphone (deux pour un stagiaire, un maitre de stage avec un fixe et un portable ?), une adresse (deux, trois pour le stagiaire, adresse étudiante, des parents, durant le stage ?). Pour le maitre de stage, il faudra rajouter un lien vers l'entreprise. Il n'y aura sans doute rien à rajouter pour l'enseignant référent ni pour le responsable de la formation.

Une soutenance est un objet qui doit être relié à un stage afin de disposer des ressources stagiaire, maitre de stage... Elle dispose en propre d'un lieu, d'une date et d'une heure. Si les soutenances doivent avoir lieu en parallèle, alors il faut associer une soutenance et une salle, après avoir défini une salle avec au minimum une localisation (description de batiment, numéro de salle, étage...) et éventuellement un numéro de téléphone de salle.

Remarque : pour la base de données, tous les objets ont toujours un id, un numéro de référence, etc. Nous n'en avons pas parlé ici pour des raisons de simplicité.

2.4 Petites tables de données annexes

Là encore, sans entrer dans le détail à moins de commencer à implémenter pour un type de stage particulier, il faut penser qu'il y aura à implémenter des listes de catégories pour le code-sexe, le type de stage, les différents cas de personnes et d'entreprises. En cas de soutenances multiples en parallèle, il faudra aussi une table de salles de soutenance.

2.5 Choix technologiques

Cette application est typique d'une technologie LAMP classique.

Toutefois, rien n'interdit de passer par un serveur Node, de développer le front-end et le back-end en Javascript avec Angular et Express.

2.6 Durée de développement

On est clairement dans la gamme des petites et moyennes applications, pour réaliser une analogie avec les PME. Il n'y a aucune difficulté conceptuelle ni algorithmique (sauf à vouloir optimiser le taux de remplissage des salles en cas de soutenances multiples en parallèle), seulement des choix à paramétrer en fonction du nombre de stages. Ainsi, pour une école d'ingénieurs avec plusieurs centaines de stages et des soutenances en parallèle, il y a une programmation plus importante à réaliser que dans le cadre de soutenances universitaires avec une vingtaine ou une trentaine de soutenances à organiser.

Il nous semble raisonnable de penser que pour une personne habituée à conceptualiser, modéliser, tester, documenter, une durée inférieure à une centaine d'heures est une durée acceptable. Ce qui signifie sans doute en temps réel plusieurs semaines de développement, notamment dans le cas d'allers et retours pour présentation, confirmation des choix et des interfaces.

2.7 Solution SAAS

Il n'est sans doute pas utile de passer en SAAS pour cette aplication. La première raison est que c'est une petite application qui demande peu de ressources. La seconde raison est qu'on aura sans doute besoin d'accéder aux données des stages des années précédentes en cours d'année.

 

3. Modifier un "gros" programme

On décide de compléter le site sHSPdb avec l'ajout d'un menu Users afin de fédérer les utilisateurs du site et les personnes intéressées par les petites protéines HSP. Après avoir rapidement tracé les contours d'un tel menu, indiquez quels fichiers doivent être modifiés et quels fichiers devraient être ajoutés. On trouvera dans l'archive shsp.zip une copie à peu près complète du site à modifier. Le fichier sql_hspdb_dump_16_06_06_janus.mysql de cette archive, une fois décompressé (20 Mo), permet de reconstruire la base de données et ses 13 tables.

Si vous deviez implémenter une copie fonctionnelle du site sur votre ordinateur personnel, à quelles contraintes matérielles et techniques seriez-vous confronté(e) ? Comment pourrriez-vous y répondre technologiquement ?

Ce site est-il fonctionnel pour PHP 7 ? Si non, quelles parties faudrait-il changer ?

Solution :  

Migrer une application n'est jamais simple. Heureusement la question 1 de ce T.P. nous a offert la possibilité de savoir comment le code est structuré.

3.1 Ajout d'utilisateurs recensés

Pour créer une entrée de menu gauche nommée Users, disons entre Export et Submit, il faut tout d'abord insérer un item de liste vers la ligne 265 du fichier design.php correspondant au code XHTML suivant :


     <!-- ##  bouton Users -->
     
       <li><abbr title='Community of users'>
             <a href="index.php?action=14&amp;mode=0">Users</a>
          </abbr>
      </li>
     
     

Il faudra ensuite écrire les fonctions associées, sans doute dans le fichier action14.php puis réaliser un "include" de ce fichier dans index.php aux environs de la ligne 90 et enfin ajouter le cas 14 aux environs de la ligne 180 de ce même fichier index.php.


     [ extrait avec lignes numérotées du nouveau fichier index.php ]
     
     0075 # les inclusions suivantes sont pour les actions
     0076
     0077 include("action0.php")        ;  // index = home
     0078 include("action1.php")        ;  // consult
     0079 include("action2.php")        ;  // search/blast
     0080 include("action3.php")        ;  // tools
     0081 include("action4.php")        ;  // admin/login/reblast
     0082 include("action5.php")        ;  // about (references)
     0083 include("action6.php")        ;  // help
     0084 include("action7.php")        ;  // contributors
     0085 include("action8.php")        ;  // pour gh
     0086 include("action9.php")        ;  // pour les exports
     0087 include("action10.php")       ;  // pour submit
     0088 include("action11.php")       ;  // pour predict
     0089 include("action12.php")       ;  // pour analyse statistique des classes
     0090 include("action13.php")       ;  // pour analyse statistique des classes
     0091 include("action14.php")       ;  // pour la communauté des utilisateurs       # AJOUT
     
     [...]
     
     0166 switch ($action) {
     0167   case (0)  : { lea_main($mode)              ; } ; break ;
     0168   case (1)  : { lea_consult($mode)           ; } ; break ;
     0169   case (2)  : { lea_search_main_page($mode)  ; } ; break ;
     0170   case (3)  : { lea_tools($mode)             ; } ; break ;
     0171   case (4)  : { lea_login_logout($mode)      ; } ; break ;
     0172   case (5)  : { lea_more_page()              ; } ; break ;
     0173   case (6)  : { lea_help($mode)              ; } ; break ;
     0174   case (7)  : { lea_contributors($mode)      ; } ; break ;
     0175   case (8)  : { lea_extra_main_page($mode)   ; } ; break ;
     0176   case (9)  : { lea_export($mode)            ; } ; break ;
     0177   case (10) : { lea_submit($mode)            ; } ; break ;
     0178   case (11) : { lea_predict($mode)           ; } ; break ;
     0179   case (12) : { lea_classes($mode)           ; } ; break ;
     0180   case (13) : { visiteGuidee()               ; } ; break ;
     0181   case (14) : { utilisateurs($mode)          ; } ; break ;  # AJOUT
     0182   default   : { lea_main_page($mode)         ; } ; break ;
     0183 } ; # fin de switch
     
     

Ensuite, la fonction utilisateurs() du fichier action14.php peut prendre le relais, comme ci-dessous :


     <?php
     #   # (gH)   -_-  action14.php  ;  TimeStamp (unix) : 21 Novembre 2017 vers 18:37
     
     ##############################################################################
     
     function utilisateurs($numMode=0) {
     
     ##############################################################################
     
     blockquote() ;
     h2("Community of users of the sHSP database") ;
     
     switch ($numMode) {
     
     
          [...]
     
     } ; # fin de switch
     
     finblockquote() ;
     
     } ; # fin de fonction utilisateurs
     
     
     ##############################################################################
     ?>
     

En voici le rendu (on vient juste de cliquer sur Users)  :

          non su

3.2 Contraintes matérielles et techniques

Une lecture des tailles de fichier mis en jeu, et notamment celui de la base de données HSP (20 Mo, avec 13 tables), montre qu'il n'y a pas besoin de beaucoup de ressources a priori pour afficher la page de départ. Par contre, si on rentre dans le détail de l'action Statistical analysis on voit qu'il faut exécuter du code R après export des données, ce qui demande plus de puissance, voire même de changer la valeur du TIME_OUT pour indiquer la fin d'exécution d'une page Web.

3.3 Support de PHP 7

Pour répondre à cette question, il faut rentrer dans le détail du code. Si on ne sait pas quelle version de PHP a été utilisée pour développer le code, on pourra penser qu'il s'agit de PHP 4 ou 5. Un tour sur le web avec les termes php 7 deprecated permet de trouver la liste des fonctions qui ne sont plus supportées ainsi que les autres choses à prendre en considération pour migrer et notamment le problème des constructeurs d'objets...

Au passage, on pourra aussi consulter ce qui est devenu deprecated et ce qui à changé :

entre PHP 4 et PHP 5

à partir de PHP 5.3

à partir de PHP 5.5

à partir de PHP 5.6

Donc on doit certainement «faire la chasse» aux problèmes liés aux constructeurs d'objets, aux fonctions comme split() -- mais pas explode() -- et à la gestion des bases de données. Il est assez simple d'aller rechercher ces différents éléments en ligne de commandes à l'aide de l'instruction grep sans doute avec des paramètres comme -i, -l, -n dans un premier temps pour l'ensemble des fichiers PHP du site, disponibles dans l'archive shsp.zip.

Partie objets et constructeurs

Il faut commencer par chercher quels fichiers sont suceptibles de contenir des problèmes liés aux objets. Une première commande comme

    grep -i -l class *php

est sans doute inadaptée car la chaine de caractères class est utilisée dans des balises XHTML pour définir des styles CSS.

Il vaut mieux utiliser la ou les commandes

   \grep -a -i -l -E "^\s*class " *php 
    grep    -i -l    "class "     *php

parce qu'elles fournissent la liste des fichiers dont au moins une ligne commence par (ou contient) le mot class.

La bonne nouvelle (quoique...), c'est qu'il ne semble pas y avoir de classes d'objets dans les fichiers PHP.

Partie fonctions obsolètes

Rechercher si la fonction split() est utilisée ne pose aucun problème, il suffit d'exécuter la commande

    grep -a -i "split(" *php 

Comme comme cette fonction renvoie aussi les lignes avec preg_split (qui est une fonction non obsolète), on écrira donc

    \grep -a -i "split(" *php | \grep -v preg_split 

qui retire de cet affichage les lignes avec preg_split.

Maintenant, le problème est plus compliqué qu'il n'y parait parce qu'il a de nombreuses fonctions à tester, comme par exemple spliti() en plus de split() et aussi sql_regcase(), ereg()... Même si grep admet -e "a | b" comme paramètre ce qui signifier rechercher a ou b, il resterait encore beaucoup de choses à rechercher vu la longue liste des fonctions obsolètes.

Utiliser un docker PHP 7 + MySql ne résoud sans doute pas le problème car avec un interpréteur seul le code interprété est testé... il faudrait plutôt essayer de lister toutes les fonctions utilisées puis filtrer avec la liste de celles interdites... mais là encore cela demande beaucoup plus de travail qu'un simple T.P. de deux heures.

Une consultation de phpinfo() sur la machine janus disponible ici semble indiquer que le site fonctionne actuellement sous PHP version 5.5.9, donc il n'y a sans doute pas grand chose à changer du coté de fonctions obsolètes, ce que montre aussi une recherche exhaustive des fonctions obsolètes (recherche non détaillée ici).

Partie base de données

Ici, les ennuis commencent... Avec un système sous PHP 5, si on exécute la commande php index.php alors on obtient le message d'erreur suivant qui indique juste un problème de mot de passe

SERVEUR HS Access denied for user 'root'@'localhost' (using password: YES)

Avec un système sous PHP 7, si on exécute la commande php index.php alors on obtient le message d'erreur

PHP Fatal error:  Uncaught Error: Call to undefined function mysql_connect() in fonction.php:82 
Stack trace:
#0 action4.php(208): connexion() 
#1 index.php(134): shsp_checkLogin() 
#2 {main} 
  thrown in /home/gh/public_html/tests/sh/fonction.php on line 82 

Il semblerait donc que le site utilise l'ancienne interface de programmation entre PHP et MySql via des fonctions mysql_*. Effectivement, une recherche de la chaine sql dans les fichiers *.php montre que seul MySql est utilisé, avec cette "vieille" interface. Après avoir fait «la chasse» aux lignes impliquées, il ne doit pas être trop difficile de remplacer le code écrit par du PDO.

A titre d'exemple, on peut facilement modifier le code de la page de départ pour afficher comme avant le nombre de protéines en haut et à gauche comme ci-dessous

          non su

à l'aide des changements suivants :

  1. On modifie la fonction connexion() dans le fichier fonction.php aux environs de la ligne 85.

    On utilise $bdd = new PDO('mysql:... au lieu de mysql_connect() et on ajoute return($bdd).

  2. Pour les fonctions

    - sp_checkLogin()

    dans le fichier action4.php

    aux environs de la ligne 210,

    - forceClasseProteine()

    dans le fichier action4.php

    aux environs de la ligne 3085,

    - forceClasse()

    dans le fichier action4.php

    aux environs de la ligne 3100,

    - compte_proteines()

    dans le fichier fonction.php

    aux environs de la ligne 135.

    on remplace les instructions

       $req  = "SELECT... "
       $res  = mysql_query($req) 
       $tdr  = mysql_fetch_array($res)
     

    par des instructions

       $req  = "SELECT... "
       $res  = $bdd->query($req) 
       $tdr  = $res->fetch()
     

    après avoir, bien sûr, rajouté $bdd = connexion() ;.

  3. Dans la fonction affich_header() du fichier design.php aux environs de la ligne 145 et dans la fonction affich_menu_gauche() de ce même fichier aux environs de la ligne 200, au lieu d'affecter directement $agent via $_SERVER["HTTP_USER_AGENT"], on ajoute un isset().

Voici la vérification en ligne de commandes qu'au moins la page index.php fonctionne :

$gh> php index.php | grep -E "[0-9]+ proteins"
&nbsp;<span class='small bleuf'>6222 proteins</span>

Nous avons écrit que ce n'est pas difficile de changer d'interface. Toutefois, on remarquera que c'est très long, car un grep et wc couplés montrent que la fonction mysql_query() est utilisée un peu plus de 200 fois dans l'ensemble du code. Cela signifie qu'en plus de 200 remplacements de code, il faudra sans doute exécuter au moins 200 tests pour vérifier que tous les cas d'utilisation ont bien été pris en compte. Donc armons-nous de patience et essayons d'atteindre une couverture de code de 100 %...

 

4. Réécrire un gros programme

Après réflexion, le site sHSP n'est pas bien conçu. On voudrait utiliser un framework PHP pour le réécrire. Quel "grand" framework PHP pourrait-on utiliser ?

Réécrire le site sHSP avec le framework PHP de votre choix. A votre avis, combien de temps faut-il pour le faire ?

Solution :  

Les grands frameworks de développement PHP qui suivent MVC ont été présentés en cours. La page wiki frameworks PHP liste les plus connus.

Que ce soit Joomla, Laravel, CakePHP ou CodeIgniter, par exemple, il faudra certainement compter de nombreux jours de travail, ne serait-ce que pour comprendre les termes métiers comme protéine, composition en acide aminés, alignement... De plus les fichiers scripts fournis ne contiennent aucun test, il sera difficile de savoir si ce qu'on programme est juste. Ce n'est pas parce qu'on affiche des données qu'elles correspondent à ce qu'il faut.

 

       retour au plan de cours  

 

Code-source PHP de cette page ; code Javascript associé.

 

retour gH    Retour à la page principale de   (gH)