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
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).
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.zipLe plan de développement est présenté ici.
Solution : masquer la 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
2
3
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 fonctionLes 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 ?
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 : masquer la 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 : masquer la 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&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 switchEnsuite, 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) :
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é :
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 *phpest 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 " *phpparce 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(" *phpComme 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_splitqui 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 82Il 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
à l'aide des changements suivants :
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).
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() ;.
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" <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 : masquer la 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.
Code-source PHP de cette page ; code Javascript associé.
Retour à la page principale de (gH)