Le Petit Journal du Linuxien Novice
© 1999-2007 César Alexanian. Hébergé officiellement chez Linux-France. Serveur principal tournant sous GNU/Linux chez NFrance Conseil
À SUIVRE...
STATS

[ Nedstat ]
Dernière mise à jour : vendredi 30 novembre 2007

Mise en oeuvre de MySQL

Version 1.0
par Jean-Michel Oltra

Sommaire

Avertissement d'usage : point ne suis-je un professionnel de MySQL, ni de php3 d'ailleurs. Mais je suis têtu et, avec un peu de bonne volonté, on arrive à créer des trucs vraiment pratiques (plus pratiques que MS Access, mais oui !), bien faits (mieux faits que...) et avec des logiciels libres... Aussi, pourquoi se priver ; j'encourage chacun à tenter sa chance.

Les lecteurs n'ayant aucune idée des bases de données relationnelles pourront débuter par la lecture de mon article sur Adabas sur ce même site.

1 Objectifs et moyens

1.1 Ce qu'on veut faire

On va se monter une petite base de données avec une interface graphique qui sera constituée de pages web. En effet, grâce au serveur Apache, il est possible de se fabriquer des formulaires pour entrer les données dans les tables, mais aussi pour générer des résultats de requêtes (c'est de l'intranet, quoi !).

Les formulaires et autres pages web sont créés par du code html généré par php (php3 en ce qui me concerne). Le php3 va traiter également avec les bases de données.

1.2 Ce qu'il nous faut

  1. Évidemment, il faut le serveur de base de données MySQL. Etant sur Mandrake 7.1, j'ai utilisé les paquetages MySQL, MySQL-client et MySQL-shared-libs (version 3.22.32).
  2. On va installer le serveur Apache (un paquetage, j'ai la version 1.3.12).
  3. On va installer les modules php :mod_php3, mod_php3-mysql, mod_php3-manual.
  4. Un navigateur : je délaisse un peu Lynx (qu'il me pardonne) pour revenir à Netscape (4.75).

Les utilisateurs plus confirmés préféreront compiler Apache et PHP pour y inclure les modules à leur convenance : le 'PHP professionnel' des éditions Eyrolles commente largement les options de compilation. Personnellement, quand je débute, j'aime bien faire simplement.

1.3 La documentation

On ne va pas couper à un peu de doc car la syntaxe du SQL (Structured Query Language) et du PHP (Personal Home Page) ne s'invente pas !

  • Sur nexen.net on trouvera de la doc sur MySQL et php à télécharger. Je me sers tous les jours de la doc MySQL trouvée sur Nexen. C'est très bien fait, et en français pour la majeure partie.
  • de la doc sur la toile sur le code HTML :

http://brahma.imag.fr/Multimedia/miroirs/manuelhtml

http://www.w3schools.com

  • en livres : j'utilise HTML4-XML de chez MicroApplication et Programmation en PHP de Leon Atkinson (Campus Press). J'ai depuis peu PHP professionnel éditions Eyrolles peut-être plus complet mais au premier abord plus touffu (je suis content donc d'avoir eu le premier en main pour aborder PHP).

2 MySQL

http://www.mysql.com

2.1 Administrateur et droits

Vous avez installé MySQL vous allez pouvoir définir en premier lieu le mot de passe root. Le terme prête à confusion puisqu'il s'agit de l'administrateur du serveur de base de données. La littérature recommande de ne pas donner le même mot de passe qu'au SU de notre machine mais c'est tellement plus simple (ça n'engage que moi, ce que je dis là !).

On le définit par la commande au shell :

[root@espinasse root]# mysqladmin -u root password mot-de-passe-du-root-mysql

Et vous pouvez tester l'installation de MySQL par :

[root@espinasse root]# mysqladmin version 

qui doit vous raconter sa vie...

Pour ajouter l'utilisateur 'oltra' mon root a du entrer :

[root@espinasse root]# mysql -u root -p

cette commande à la console introduit la connexion de l'utilisateur (-u) root avec la demande de mot de passe (-p). Le shell vous répond alors :

enter password :

vous entrez mot-de-passe-du-root-mysql et vous voilà connecté au serveur en tant que root-mysql avec l'invite :

mysql>

mysql>CREATE DATABASE troupeau;

root-mysql crée une base de données nommée troupeau.

mysql>GRANT SELECT,INSERT,DELETE,UPDATE,ALTER,DROP,CREATE

      ON troupeau.*

      TO oltra@localhost

      IDENTIFIED BY mot-de-passe-utilisateur-oltra;

root a donné des droits de création (create), suppression (drop), insertion de données (insert), mise à jour de tables (update), modification de table (alter), requête (select) à l'utilisateur 'oltra' sur la base 'troupeau' (avec ses tables quand elles seront créées, d'où le troupeau.*) à partir de la machine locale (@localhost), et qui sera identifié par mot-de-passe-utilisateur-oltra.

mysql>quit

quitte le serveur. Root-mysql a fait son boulot, Oltra va pouvoir bosser...

2.2 Se connecter au serveur

  • [1.]Commande complète à la console :
[oltra@espinasse oltra] mysql -u oltra -p
enter password:

La première commande demande la connexion de l'utilisateur oltra. L'option -p indique une connexion avec mot de passe, qui sera demandé (enter password) après la validation de la commande.

  • [2.]Pour simplifier, on peut éditer le fichier de configuration /.my.cnf, qui comportera dans ce cas les quatre lignes suivantes :
[client]
host=localhost

user=oltra

password=mon-mot-de-passe

L'utilisateur oltra se connecte par la machine localhost avec le mot de passe mon-mot-de-passe.

La connexion au serveur sera plus rapide, car ce fichier est lu par MySQL : la commande

[oltra@localhost oltra]mysql
mysql>use troupeau;

permet la connexion au serveur puis l'entrée sur la base 'troupeau'.

2.3 Créer et charger des tables

Tout ce que je vous raconte, je ne l'ai pas inventé mais je le sors du manuel MySQL téléchargé sur nexen.net. Celui-ci est quasiment en permanence ouvert avec Lynx sur mon bureau (virtuel). Ce qui va suivre est forcément sommaire, pour vous donner des bases de travail. Une documentation plus poussée est nécessaire.

2.3.1 Instruction CREATE TABLE

On va créer deux tables :

  1. create table individus (tatouage varchar(5) not null, boucle varchar(4), sexe enum('f','m') not null, cornes enum('oui','non') not null, sortie date, cause_sortie enum('mort','réforme'), primary key(tatouage));
  2. create table mises_bas (id smallint unsigned not null auto_increment, tatouage varchar(5) not null, boucle varchar(4), date date, nb_chevreaux tinyint unsigned not null, obs varchar(15), foreign key(tatouage) references individus(tatouage), primary key(id));

On va voir pas mal de choses sur ces deux tables :

  • vous avez remarqué que les instructions peuvent être écrites en minuscules et qu'on finit une instruction avec un point-virgule. Si le point-virgule est omis on obtiendra l'invite : > . On retape alors ; et [Entrée].
  • On a créé des champs de type chaîne, varchar et enum. Varchar(x) est un champ de longueur variable x, enum permet de rentrer les données qui sont dans la liste. Enum('option1','option2') not null donne option1 par défaut car c'est la première entrée de la liste et que le champ est déclaré not null. C'est équivalent à enum('option1','option2') not null default 'option1'.
  • on a un champ de type date. Il faudra rentrer la date sous forme 2001-02-23, année-mois-jour. Les fonctions de mySQL permettent de ressortir la date sous un format différent.
  • on a créé des champs de nombre. Ce sont des entiers non signés (positifs) ; tinyint et smallint sont les plus petites spécifications pour des entiers. Il existe des types pour des champs de nombre décimaux, double(m,n) par exemple.
  • l'un de ces champs est autoincrémenté (id).
  • il y a une clé primaire dans chaque table. La clé doit être sur un champ not null. MySQL demande une clé primaire ou un index associé à chaque table.
  • on a créé une clé externe dans la table mises_bas, tatouage, clé externe de individus.tatouage. Notez la syntaxe table.champ qui permet de pointer un champ précis dans une table, en cas d'ambiguïté avec un autre champ du même nom. La clé primaire à laquelle on fait référence doit déjà avoir été créée. En fait ce que je dis là est un peu ambigu car MySQL ne gère pas les clés externes, elles sont possibles uniquement dans un souci de compatibilité... Mais une bonne habitude n'est jamais une mauvaise chose !

2.3.2 Remplir des tables : INSERT INTO et LOAD DATA

Pour remplir des tables à la console il y a deux possibilités :

  • l'instruction INSERT INTO individus VALUES ('94418','130','f','oui',","); va remplir une ligne de la table individus avec les valeurs mises entre guillemets simples. Les champs sortie et cause_sortie seront remplis avec respectivement 0000-00-00 et... rien ! (en fait avec une chaîne vide). L'instruction insert into individus (tatouage,boucle) values ('94418','130'); remplira la ligne avec les valeurs entre guillemets sur les colonnes précisées (tatouage,boucle), les autres colonnes étant remplies avec les valeurs par défaut : f,oui,0000-00-00,NULL. Notez que le défaut d'un champ de type date c'est son zéro ('0') qui s'écrit aussi 0000-00-00, le défaut d'un champ qui n'est pas déclaré NOT NULL (cas du champ cause_sortie) c'est par conséquent la valeur NULL.

Si on avait voulu entrer une donnée dans la table mise_bas (la mise-bas est l'accouchement d'un animal !) : insert into mises_bas values (null,'94418','130','2001-02-22','2',");

On peut mettre null avant la première virgule dans l'expression entre parenthèses car le champ id s'autoincrémente.

Une valeur par défaut est insérée lorsqu'elle n'est pas précisée dans la liste des champs.

  1. le défaut d'un entier(nombre i.e) not null est 0
  2. le défaut d'un entier (nombre i.e), et d'un varchar (chaîne) qui n'est pas not null est null
  3. le défaut d'une chaîne not null est 'chaîne vide' (' ')
  4. la valeur d'un entier (i.e nombre) (not null ou non) non précisée ou précisée par une chaîne vide est 0
  5. une chaîne vide sur une chaîne not null est ' '

C'est un peu du détail mais c'est utile lorsqu'on entre les données par formulaire, car tous les champs du formulaire ne seront pas forcément renseignés : cas du champ 'mises_bas.obs'.

On pourra entrer autant de lignes que l'on mettra de données entre parenthèses : insert into individus values (;;;;;;;),(;;;;;;;)....;

  • l'instruction LOAD DATA LOCAL INFILE /home/oltra/troupeau.txt INTO TABLE individus fields terminated by ";" ; va charger le fichier troupeau.txt dans la table citée. On édite un fichier texte avec VI ou autre et on place les données ligne par ligne, chaque champ étant séparé des autres par un point-virgule. Ainsi :

    94418;130;f;oui;0;\N;
    95507;13;f;oui;0;\N;

    77776;126;m;oui;2000-01-05;réforme;

chargera 3 lignes dans la table (après que le fichier ait été sauvegardé) si on utilise l'instruction précédente.

\N est équivalent à NULL, mais si on veut charger NULL avec INSERT INTO, ce n'est pas \N qu'il faut mettre mais bien NULL en entier.On peut, comme il a été montré avec INSERT INTO, préciser des colonnes à remplir, ce qui permet de raccourcir des saisies en utilisant des valeurs par défaut.

2.3.3 modifier des tables : alter table

Le champ mises_bas.obs est trop petit : ALTER TABLE mises_bas modify obs varchar(25); augmente sa taille.

Au début on fait souvent des petites erreurs : alter table permet de renommer des colonnes, de supprimer et de rajouter clés primaires et index, de modifier le type des colonnes.

2.3.4 obtenir des informations sur les tables

  • [show tables;]montre les tables de la base courante.
  • [describe individus;]donne des informations sur la table individus.

2.4 Les requêtes : instructions SELECT et WHERE

2.4.1 syntaxe

SELECT champ FROM table WHERE clause [clause additionnelle];

  • j'ai utilisé les crochets pour ajouter la clause optionnelle. Dans la doc SQL tout ce qui est optionnel est entre crochets.
  • si il y a ambiguïté entre les noms de champs, on notera table.champ.
  • la valeur de la clause est toujours entre guillemets simples
    • [exemple :]where cause_sortie = 'réforme';
    • [exemple :]where date = '2001-02-23';
    • [exemple :]where date between '2001-01-01' and '2001-02-23';
    • [exemple :]where tatouage like '97%' (le % indique tout caractère)
  • toutes les tables contenant des champs mentionnés dans leSELECT doivent être incluses dans la clause FROM
  • on peut s'alléger un peu la saisie en tapant : select t.champ from table t where clause;
    • [exemple :]select i1.tatouage, i1.boucle from individus i1 where sortie = '0'; ce qui me donne les animaux vivants au jour de la requête car ils ne sont pas sortis de l'effectif.

2.4.2 que mettre dans une instruction select...where

Vaste question... dont vous trouverez des réponses plus complètes dans la doc !

  • [1.]on peut ne pas mettre where : il n'y a donc pas de tri.
    • select tatouage from individus; me donnera toutes les entrées... ce qui est peu utilisable
  • [2.]on peut y affecter un opérateur, '=' ou '>' ou '<', ainsi que nous l'avons vu dans les exemples précédents.
  • [3.]on peut y affecter des opérateurs sous forme d'expression comme between, like, regexp, and, or :
    • exemple : where sortie > '2001-01-01';
    • exemple : where cause_sortie like 'ré%'; donnera les formes car % signifie tous caractères. Mais cause_sortie like '%or%' donnera 'réformes' mais aussi 'mort'.
    • exemple : where sortie regexp '2001.*'; donnera toutes les sorties de l'année 2001 .
    • where sortie regexp '2001.*' or sortie regexp '1998.*'; donnera les sorties de 2001 et de 1998 car il s'agit d'un 'OU '. Si j'avais utilisé 'AND' j'aurais obtenu le message 'EMPTY SET' car bien évidemment un animal n'est sorti qu'une fois !
  • [3.]on peut y affecter des fonctions :
    • where year(sortie) = '1997'; fonction qui extrait l'année.
    • where left(sortie,4) = '1997'; fonction de chaîne qui extrait les 4 premiers caractères gauches de la chaîne.
    • ou bien l'inverse : where champ = 'fonction($variable)'; on passe une variable par une fonction et on recherche les correspondances dans le champ précisé.
    • une fonction utile pour une sortie des champs de date : date_format(). date_format(sortie,'%d-%m-%Y') me sortira la date de sortie d'un animal sous la forme : jj-mm-aa
  • [4.]on peut compléter la clause where
    • select tatouage, boucle from individus where sortie > '2000-01-01' ORDER BY tatouage; va ordonner la sortie en ordre croissant de tatouage
    • select tatouage,boucle from individus where sortie > '2000-01-01' ORDER BY tatouage DESC; le contraire de précedemment.
  • [5.]on peut utiliser des fonctions d'agrégats : count, sum, max, min, avg, sont les plus courantes
    • select sexe, count(tatouage) from individus GROUP BY sexe; . On utilise comme indiqué la fonction d'agrégat avec la clause GROUP BY qui permet de grouper par type d'enregistrement : ici les femelles (f) et les mâles (m). J'aurai alors un effectif (count) des entrées sans condition regroupé par sexe. J'aurais pu ajouter where sortie = '0' pour avoir un effectif des animaux vivants.
    • select count(tatouage) from mises_bas where date > '2001-01-01'; me donne le nombre de bêtes ayant mis-bas depuis le 1er janvier 2001.
    • select max(id) from mises_bas; me donne le dernier numéro de mise-bas enregistré.
  • [6.]on peut travailler avec la valeur NULL, qui est en fait une valeur spéciale. A l'origine de ma table individus j'avais rentré les valeurs avec LOAD DATA et les animaux non sortis avaient une date de sortie (champ sortie) NULL. Ensuite, ayant fait mon premier formulaire, je n'opérais aucune saisie (pour les animaux encore présents évidemment) dans mon champ sortie du formulaire et par conséquent les valeurs suivantes de 'sortie' étaient fixées à 0000-00-00. Je me suis retrouvé donc avec des sorties='0000-00-00' et sortie=null. C'était peu homogène et il me fallait l'instruction where sortie='0000-00-00' or sortie is null; . J'ai changé tout ça ave UPDATE, nous verrons comment plus loin.

2.4.3 select avec plusieurs tables

en fait j'ai une autre table dans ma base de donnée troupeau. Elle s'appelle 'identification' et me sert à noter la boucle d'oreille numérotée (qu'on appelle tip-tag) que j'appose, à la naissance, sur les jeunes femelles (chevrettes) qui seront plus tard des reproductrices.

mysql> CREATE TABLE identification (id smallint unsigned not null, entrée date, tip_tag varchar(4), sexe enum('f','m'), cornes char(3) default 'oui', cause_entrée enum('naissance','achat') not null, tatouage varchar(5), boucle varchar(4), foreign key(id) references mises_bas(id));

Maintenant, si je veux connaître les femelles dont j'ai gardé des filles en l'an 2000 :

mysql> SELECT m.tatouage,m.boucle from mises_bas m, identification i WHERE m.id = i.id AND m.date REGEXP '2000.*';

ce qui cherche les tatouages et boucles des femelles ayant une entrée dans la table mises_bas (car il y a existence de m.id) en l'en 2000 (date regexp '2000.*) et dont il y a une correspondance avec ma table identification (m.id = i.id) prouvant ainsi qu'à la suite de cette mise-bas j'ai conservé une femelle que j'ai identifiée.

Un autre exemple :

mysql> SELECT i1.tatouage, i1.boucle FROM individus i1,mises_bas m, identification i2 WHERE i2.tatouage='$tatouage' AND m.id=i2.id AND i1.tatouage=m.tatouage';

Lorsque ces chevrettes ont un peu moins d'un an, elles ont une boucle définitive (qu'elles perdent ensuite parfois... mais grâce à php il est aisé de réactualiser une valeur dans plusieurs tables !) ainsi qu'un tatouage pour faire bon poids (et ça c'est vieux mais efficace) et elles sont identifiées par leur couple boucle, tatouage dans la table d'identification (dans la ligne où il y avait leur tip-tag et leur date de naisance) ainsi que dans la table individus où je suis susceptible de leur attribuer des notes personnelles sur des critères que je n'ai pas mentionnés ici pour ne pas alourdir le CREATE TABLE INDIVIDUS.

La requête précédente permet, à partir d'un numéro de tatouage entré dans un champ de formulaire (ce numéro peut être variable d'où le $tatouage, signe de variable en php), de retrouver les coordonnées (et notes perso si je rajoute les champs nécessaires à la requête) de la mère de la bestiole en question : la requête repère le tatouage de la fille (que l'on a entré sous forme de $tatouage) dans la table 'identification'. La condition suivante (m.id = i2.id) permet de remonter de la valeur 'm.id' correspondant à l'enregistrement comportant la valeur '$tatouage' de la table 'identification' à sa valeur équivalente (i2.id) dans la table mises_bas car c'est cette table qui donne, en fait, le numéro d'enregistrement de la mise_bas (i2.id). La requête repère alors la valeur du tatouage correspondant à cet enregistrement numéroté i2.id (c'est le numéro de tatouage de la mère de la bête $tatouage). Et pour finir elle recherche la correspondance entre cette bête (caractérisée par i2.tatouage) et l'équivalent (i1.tatouage) dans la table individus. Lorsque i1.tatouage est repéré il est possible d'obtenir toutes les caractéristiques de l'animal qui sont enregistrées dans la table individus. C'est plus compliqué à expliquer à des gens externes à mon élevage qu'à réaliser, en fait !

J'ai fait là une requête sur trois tables. Et grâce à php je peux faire la recherche sur la boucle, et la même chose pour rechercher la descendance d'une bête.

2.5 Mettre les tables à jour

deux instructions :

  • [1.]Pour supprimer des lignes : delete from table where='condition';

par exemple ayant fait des essais avec un nouveau script php je me retrouve avec des mises-bas 'bidon' que je veux donc supprimer lorsque le script est abouti. J'ai mis ces mises-bas au 1er avril 2001...

mysql> delete from mises_bas where date = '2001-04-01';

cette ligne me supprimera toutes les entrées qui correspondent à une date égale au 1er avril 2001. Attention, sans clause where c'est toute la table qui est effacée !

  • [2.]Pour mettre à jour des lignes de table : update nom-table set colonne='valeur' where='condition';
    • j'ai déjà dit qu'à la création de ma table 'individus' j'avais entré une valeur NULL dans le champ sortie (champ de type date) lorsqu'un animal était toujours vivant (il n'était donc pas sorti). Pour mettre les anciennes lignes en conformité avec les nouvelles données insérées à partir du formulaire il me faut transformer ces valeurs NULL en zéro : UPDATE INDIVIDUS SET SORTIE = '0' WHERE SORTIE IS NULL;
    • lorsque j'identifie une chevrette à la naissance je ne regarde pas si elle est cornue ou non (certaines chèvres sont sans cornes, on dit qu'elles sont mottes). Par la suite, alors que son cornage se verra mieux, il se peut que j'aie à modifier sa fiche dans la table 'identification' dans le cas où elle serait motte : UPDATE IDENTIFICATION SET CORNES = 'NON' WHERE TIP_TAG = '342'; la chevrette au tip-tag 342 est motte, en définitive. Je modifie son cornage de 'oui' à 'non'.
    • il est possible de mettre plusieurs champs à jour : UPDATE NOM-TABLE SET COLONNE1='VALEUR1', COLONNE2='VALEUR2....

2.6 Changer de base, effacer tables et bases

J'ai une deuxième base de données que j'ai appelé 'nos_clients'. Si je suis sur 'troupeau' et que je veux passer sur 'nos_clients' :

mysql> use nos_clients;

Il peut m'arriver de créer une table temporaire (sur MySQL 3.23 on peut utiliser create temporary table) que je vais détruire après manipulation par : drop table nom-table;

Pour détruire une base : drop database nom-bd;

2.7 Autres commandes ?

MySQL c'est 'un peu' plus que ce que je vous en ai dit, il n'y a qu'à voir la documentation disponible sur le sujet. Mais avec ces premières pistes on arrive à faire pas mal de trucs...

3 Apache

http://www.apache.org

3.1 installation

Je l'ai installé à partir d'un paquetage et j'ai la version 1.3.12.

Le serveur va créer un répertoire /home/httpd, lequel comprendra les sous-répertoires /html, /cgi-bin, /icons. L'adresse /home/httpd/html/ c'est http://localhost (ou http://127.0.0.1).

Personnellement, j'ai créé deux sous-répertoires à html, /php qui contient mes scripts php3, et /include qui contient les fichiers à inclure (fonctions php3 que l'on adresse avec 'include()', feuilles de styles, images éventuelles).

On doit modifier la directive ServerName dans /etc/httpd/conf/httpd.conf

ServerName localhost

On démarre la bête la première fois par /etc/rc.d/init.d/httpd ou /etc/rc.d/rc5.d/S85httpd (celui-ci est un lien vers celui-là, au niveau 5 de démarrage)

3.2 protections

Non, non, je ne vais pas faire un cours sur la sécurité du serveur Apache, je vais juste installer une protection basique avec le fichier .htaccess.

On va utiliser la commande, au shell et en root :

[root@espinasse root] htpasswd -c fichier-mot-de-passe nom-utilisateur

puis taper le mot de passe choisi à l'invite.

Dans mon cas :

[root@espinasse root] htpasswd -c /etc/httpd/conf/.pass_oltra oltra

Root a créé pour l'utilisateur oltra un fichier mot de passe (crypté) dans /etc/httpd/conf/, répertoire qui regroupe les fichiers de config apache et php3. Ce fichier s'appelle .pass_oltra.

Ensuite il s'agit d'éditer un fichier .htaccess (ne pas oublier le 'point') dans le répertoire à protéger. Ce fichier protège alors tous le répertoire contenant .htaccess ainsi que ses sous-répertoires.

AuthType Basic
AuthName "répertoire protégé"
AuthUserFile /etc/httpd/conf/.pass_oltra

require user oltra

Evidemment vous pouvez mettre autre chose que "répertoire protégé" (protected directory par exemple...), votre nom d'utilisateur n'est certainement pas 'oltra', et vous indiquerez le chemin de votre fichier mot-de-passe que vous aurez choisi dans htpasswd.

J'ai copié ce fichier .htaccess dans /home/httpd/html/php/ et /home/httpd/html/include/ car je suis parano et que ça m'ennuierait qu'un jour un de mes gamins me mette le souk dans mes bases de données...

Puis il s'agit d'éditer (en root) /etc/httpd/conf/httpd.conf. Vous vérifiez que vous avez la directive

AccessFileName .htaccess

puis dans le paragraphe commençant par :

#this controls which options the .htaccess file in directories can override.

vous indiquerez :

AllowOverride AuthConfig

Ca devrait fonctionner...

La doc en français sur la configuration d'Apache se trouve au :

http://www.eisti.fr/doc/apache

4 HTML

http://www.w3c.com

L'objectif de cette section est juste d'expliciter un petit peu de code html de manière à fabriquer quelques formulaires simples avec un peu de texte dedans pour renseigner ce qu'on a fait et afficher quelques messages de temps en temps, surtout quand on a fait une bêtise...

4.1 un peu de code...

Commençons donc par le formulaire qui entre les données dans ma table identification : ce formulaire s'appelle 'identification.php3' et se situe dans /home/httpd/html/php/. Je vais en indiquer le principal. Ce n'est peut-être pas un modèle de clarté syntaxique...Vous pouvez recréer ce formulaire avec un éditeur de texte dans votre /home et le visualiser avec un navigateur. Bien sûr vous ne pourrez pas le soumettre.

<html>
 <head>
  <title>formulaire identification</title>
  <link rel="stylesheet" type="text/css"     href="http://localhost/include/styles_formulaires.css>
 </head>

 <body bgcolor=olive>
  <h2>identification></h2>
  <br><br>
  < p class="info">
  <nobr>
  utiliser ce formulaire <u><font color=red>après</font></u> l'entrée de la mise bas
  </nobr>
  </p>
  <br><br>

  <form method="post" action="http://localhost/php/identification.php3">
   <table>
    <tr>
     <td align=left width="90">
     <label for="entrée">
     <font size=5><b>
     date de naissance
     </b></font>
     </td>

     <td align=left width="100">
     <font size=+2>
     <input type="date" name="entrée" size="10">
     </font>
     </td>
    </tr>
    <tr>
     <td align=left width="90">
     <label for="sexe">
     <font size=5><b>
     sexe
     </b></font>
     </td>
     <td align=left width="100">
     <font size=+2>
     <select name="sexe">
     <option>m</option> 
     <option selected>f</option>
     </select>
     </font>
     </td>
    </tr>
    <tr>
     <td align=middle width="90" bgcolor=burlywood>
     <font size=+1>
     <input type="reset" value="annuler"   size="12"> 
     </font>
     </td>
     <td></td>
     <td align=middle width="90" bgcolor=forestgreen>
     <font size=+1>
     <input type="submit"  name="soumettre" value="insérer"   size="12"> 
     </font>

     </td>

    </tr>

   </table>

  </form>

 </body>

</html>

Si vous avez suivi depuis le début, vous remarquerez qu'il manque des champs pour renseigner les colonnes 'id', 'tip_tag', 'cornes', 'cause_d'entrée', 'tatouage', 'boucle'. Je ne les ai pas mis pour ne pas alourdir, quoique le champ 'id' ne soit pas renseigné dans le formulaire car php va le chercher tout seul dans la table 'mises_bas' (select max(id) from mises_bas;). Les champs 'cornes' et 'cause_d'entrée' sont constitués de zone de liste (balise <select>) comme le champ 'sexe' tandis que les champs 'boucle' et 'tatouage' sont des zones de texte comme 'entrée' (balise <input>). Il manque ici, pour avoir un inventaire plus exhaustif, des cases à cocher (<input type="checkbox">, <input type="radio">).

En réalité ce formulaire, qui s'appelle 'identification.php3', est réalisé en php3 et comporte en plus le traitement des données insérées dans le formulaire. Du fait que le code html est généré par php l'ensemble est un peu différent.

4.2 un peu d'explications...

Je vais tenter de détailler les balises en partant du début du script. Le lecteur qui désire approfondir n'a que l'embarras du choix dans la littérature et sur la toile. http://www.brahma.imag.fr/Multimedia/miroirs/manuelhtml est pas mal, dans le style.

4.2.1 <html>, <head>, <body>

Le script débute par la balise <html> et se ferme par </html>. En général il y aura une balise d'ouverture puis une balise de fermeture lorsqu'on n'est plus dans la configuration qui a nécéssité la balise d'ouverture.

La deuxième balise est <head>. Entre <head> et </head> on va mettre des choses comme le titre de la fenêtre (car n'oublions pas que c'est un navigateur qui va afficher le formulaire) entre <title> et </title> ainsi que la référence à une feuille de style éventuelle (<link...>) dont l'adresse est, dans mon cas, /home/httpd/html/include/styles_formulaires.css. Un fichier de feuilles de style est un fichier tout bête (j'en donnerai un exemple) dont l'extention est 'css'.

Après la tête du script (head) vient le corps (body) balisé par <body> et fermé par </body>. La balise 'body' possède certains attributs dont la couleur. BGCOLOR fixe la couleur de fond (back-ground color). J'aime bien le vert olive mais je conçois que ça ne plaise pas à tout le monde...

4.2.2 mise en forme de texte : <h2>, <br>, <nobr>, <p>, <u>, <font>, <b>...

  • [1.]les balises <h1> à <h6> (headers) mettent en forme des titres, de moins en moins gros dans cet ordre. Mais avec une feuille de style on peut définir des propriétés propres à une balise. Voici enfin un extrait de ma feuille de style :

h2 {

font-family: Palatino;

font-weight: bold;

font-size: 25px;

color: blue;

position: absolute;

top: 0px;

left: 430px;

}

Notez bien la syntaxe de ce paragraphe. J'ai défini une police (Palatino), d'une certaine taille (font-size), d'une certaine graisse (font-weight), une couleur, une position définie de manière absolue en pixels dans la fenêtre du navigateur, tout en haut (car top: 0px;) et à 430 pixels du bord gauche.

  • [2.]la balise <br> (border row) initialise un saut de ligne. Elle ne se ferme pas. Mais lorsque je fais afficher 2 formulaires dans la même fenêtre (balise <frameset>, dans un fichier qui s'appelle groupe_mises_bas.php3) le texte 'utiliser ce formulaire après l'entrée de la mise bas' passe sur plusieurs colonnes si je réduis la taille de la fenêtre. C'est pourquoi j'ai introduit la balise <nobr> qui, elle, se ferme.
  • [3.]la balise <p> (paragraph) introduit un paragraphe. Il est possible de définir des classes de paragraphes dans la feuille de style en indiquant <p class="ma_classe">. Ainsi je vous livre ma classe 'info' :
p.info {
font-family: Palatino;

font-size: 20px;

color: white;

position:absolute;

left: 40px;

}

Quand on définit une classe il ne doit pas y avoir d'accentuation dans le nom de la classe. Je ne suis pas un spécialiste, loin s'en faut, mais, par exemple, je me suis cassé les dents un moment sur la définition 'p.détail' qui ne fonctionne pas alors que 'p.detail' marche très bien. Une histoire de compatibilité entre les norme ascii et latin sans doute.

J'ai donc défini <p class="info"> , puis introduit <nobr>, puis j'ai débuté mon texte par 'utiliser ce formulaire'. Ensuite vient <u><font color=red>. <u> (underscore) initialise le soulignement du texte (balise désuète parait-il) et <font> définit les caractéristiques de la police en fonction des attributs qu'on y rajoute. Ainsi <font color=red> va écrire... en rouge. Le mot 'après' ainsi encadré sera rouge et souligné ce qui fait que je le vois bien... Ces deux balise se ferment par </u> et </font>.

  • [4.]la balise <b> écrit du texte en gras (bold).

4.2.3 initialiser un formulaire, champs de saisie.

La balise <form> introduit le formulaire. L'attribut 'method' est obligatoire et définit le type de requête. La methode 'post' est utilisée dans le cas où une requête modifie des données dans le serveur. Ce qui n'est pas tout à fait le cas puisque les données sont dans /var/lib/mysql/. On aurait donc pu mettre method="get". L'attribut 'action' définit quel script la soumission va évoquer. Vous remarquez qu'en fin de formulaire on a fabriqué un bouton avec <input type="submit"...>. Lorsqu'on clique sur ce bouton, c'est l'URL définie dans 'action' qui est appelée. Ici le script s'appelle tout seul. Pas de feuille de style entre les balises <form> et </form>.

Un formulaire est créé pour y rentrer des valeurs, qui sont stockées dans des variables, et qui seront traitées par un script sur le serveur. On ne voit pas dans le code que j'ai donné la partie traitement qui est écrite en php3 après la balise </html>. Ce traitement vise à insérer les données écrites dans la table 'identification' de ma base 'troupeau'.

On va donc créer des champs de saisie adaptés à notre travail. La signification de <table>, <tr>, <td> sera vue un peu plus loin.

  • [1.]la balise <label> fabrique l'étiquette du champ. En théorie, on n'est pas obligé de faire une étiquette avec <label for="nom-du-champ">. Mais si on définit, comme on le verra plus tard, une variable $nom-du-champ dans une fonction php, la création du champ de formulaire se réduit à une ligne avec l'appel de la fonction.

Ici encore, on a mis le texte en forme avec <font> et <b>, en définissant ici une taille de police avec l'attribut size=5.

  • [2.]la balise <input> va créer un champ de texte avec les attributs type="text" , type="date", type="int", type="float" (respectivement pour saisir une chaîne, une date, un entier, un décimal). L'attribut 'name' fixe le nom de la variable. Size fixe la taille du champ, en nombre de caractères. Chaque entrée dans le champ défini par <input type="date" name="entrée" size="10"> donnera donc une valeur à la variable $entrée. Les types liés à <input> peuvent être 'text', 'float'(décimal), 'int'(entier), 'date'.
  • [3.]la balise input peut initialiser deux autres types : les boutons-radio et les cases à cocher. On ne peut sélectionner qu'un seul bouton radio dans un groupe.

J'ai, par exemple, défini, dans un formulaire me permettant de modifier le numéro de boucle d'un animal, les boutons suivants :

<input type="radio" name="identifiant" value="son_tatouage">son tatouage
<input type="radio" name="identifiant" value="ancienne_boucle">son ancienne boucle

Ce sont deux boutons radio appartenant au groupe 'identifiant' mais possédant des valeurs différentes. On définit après la balise le libellé de l'étiquette (ici 'son tatouage' et 'son ancienne boucle'). Les cases à cocher se génèrent de la même manière.

  • [4.]la balise <select> va créer une zone de liste. On utilisera l'attribut 'name' pour définir le nom de la variable. Ainsi chaque entrée dans mon formulaire dans la zone de liste telle que définie dans le script présenté donnera une valeur à la variable $sexe. Lorsque le champ proprement dit est défini, on va pouvoir indiquer ce qu'on y met dedans avec les balises <option> et </option> : l'entrée retenue est insérée entre les deux balises tandis que l'entrée retenue pour l'affichage est insérée entre <option selected> et </option>. Si on laisse un espace vide entre ces deux dernières, la zone de liste n'affiche rien à l'affichage initial du formulaire et la valeur par défaut de la variable (avant sélection par l'utilisateur) est donc une chaîne vide. Php résout une chaîne vide en 'false'.
  • [5.]les deux dernières balises <input> génèrent des boutons qui permettent d'annuler la saisie (<input type="reset">) ou de soumettre les données (<input type="submit">). Au clic sur le bouton 'insérer' (value="insérer"), le script dont le nom figure dans <form action="....."> est appelé. Une page peut s'appeller elle-même ou peut appeler un autre script si la sortie demandée est différente du formulaire. Ici la page s'appelle elle-même car je veux réobtenir le formulaire pour saisir d'autres données. Par conséquent, le script php de traitement des variables est à la suite du formulaire.

4.2.4 présenter le formulaire ou la sortie : les tableaux, <table>, <tr>, <th>, <td>.

Pour présenter un formulaire proprement, on peut mettre les étiquettes, les champs de saisie ainsi que les boutons dans les cases d'un tableau qui ne comporterait aucune séparation entre ligne et entre colonnes. D'autre part, il peut se révéler nécessaire d'obtenir une sortie sous forme de tableau.

  • [1.]les balises <caption> et </caption> encadrent le titre d'un tableau (il n'y en a pas dans la script présenté). L'attribut valign définira la position du titre ('top' pour en haut, 'bottom' pour en bas), l'attribut align définira la position du titre par rapport au tableau. Ainsi :
<caption valign=top align=center>effectifs animaux</caption>

nous donnera le titre d'un tableau dédié aux effectifs d'animaux.

  • [2.]la balise <table> initialise un tableau. Elle se fermera avec </table>. Elle possède des attributs comme border='nombre' (définit l'épaisseur de l'encadrement), cellspacing='nombre' (définit le quadrillage), cellpadding='nombre' (définit l'écartement du contenu des cellules par rappport au bord de celles-ci).

Mais, ici, il n'est pas question de définir un quelconque quadrillage, donc c'est <table> tout simplement.

  • [3.]la balise <tr> (table row) initialise une ligne de tableau. Elle se ferme avec </tr> lorsque toute la définition de la ligne est achevée. Une ligne de tableau peut contenir des cellules d'en-tête de colonne ou des cellules de données. Les premières seront initialisées par <th> (table header), les secondes par <td> (table data).
  • [4.]les balises <td> acceptent, comme on peut le voir dans le script, les attributs 'align' - pour aligner le texte dans la cellule -, 'width' - qui définit la largeur de la cellule -, 'bgcolor' - qui définit la couleur de fond. En fait, la largeur de la cellule s'adapte aux données qui sont dedans si 'width' n'est pas précisé. Vous remarquerez dans le script qu'une ligne du tableau comporte deux cellules, l'une pour l'étiquette, l'autre pour le champ.

5 PHP

http://www.php.net

Je vais tenter d'expliciter un peu de code de manière à pouvoir entrer des données dans une table. Ce n'est pas très difficile, cependant php est un langage de programmation, donc une certaine rigueur dans la syntaxe est nécessaire.

Le livre 'php professionnel' fait 900 pages. Autant vous dire que ce que je vais vous montrer ne vous dispense pas de posséder un peu de documentation...

Je vais, ainsi que je l'ai fait pour montrer html, fournir du code tiré de mes formulaires et tenter de le détailler.

5.1 un formulaire

<?
include("/home/httpd/html/include/fonctions_formulaires.php3");
generateHead("formulaire immobilisations");
print "<body bgcolor=olive>
<h2>immobilisations</h2>
<br><br>
<p class=\"info\">
utiliser ce formulaire pour entrer les immobilisations à l'achat
</p>
<br><br>
<form method=\"post\" action=\"http://localhost/php/immobilisations.php3\">\n";

print(" <table>\n");

print("<tr>\n");
printRow("exercice","date","exrecice","10");
print("</tr>\n");

print("<tr>\n");
printToClick("burlywood","reset","","annuler","12");
print("<td></td>\n");
printToClick("forestgreen","submit","soumettre","insérer","12");
print("</tr>\n");

print" </table>
</form>
</body>
</html>";
if($nom_matériel)
{
$mysql_link = mysql_connect("localhost","oltra","mon_pass");
mysql_select_db("nos_clients",$mysql_link);
$query = "INSERT INTO immobilisations ";
$query .= "(date_achat,nom_matériel,durée,valeur_acq,compte) ";
$query .= "VALUES ('$date_achat','$nom_matériel',
'$durée','$valeur_acq','$compte')";
$mysql_result = mysql_query($query,$mysql_link);
$maj = mysql_affected_rows($mysql_link);
print "<p class=\"message\">
$maj mises à jour
</p>";
}
else
{
print "<p class=\"message\">
en attente de données
</p>";
}

?>

5.2 un script à inclure

Voici maintenant mon /home/httpd/include/fonctions_formulaires.php3. Ce fichier que l'on inclut dans le script principal par la fonction include() permet de regrouper des parties semblables à plusieurs scripts de formulaires et de générer ces parties en modifiant juste les variables appelées en arguments de la fonction.

<?
function printRow($label,$type,$name,$size)
{
print("<TD ALIGN=left WIDTH=\"150\">");
print("<LABEL FOR=\"$name\">");
print("<FONT SIZE=5><B>");
print("$label");
print("</B></FONT></LABEL>");
print("</TD>");
print("<TD ALIGN=left WIDTH=\"200\">");
print("<FONT SIZE=+2>");
print("<INPUT TYPE=\"$type\" ");
print("NAME=\"$name\" ");
print("SIZE=\"$size\">");
print("</FONT>");
print("</TD>\n");
}


function generateHead($title)
{
print("<html>\n");
print("<head>\n");
print("<title>$title</title>\n");
print("<link rel=\"stylesheet\" type=\"text/css\"
href=\"http://localhost/include/styles_formulaires.css\">\n");
print("</head>\n");
}

?>

5.3 un peu d'explications

5.3.1 quelques bricoles en vrac

  • On commence un script php par <? et on le finit par ?> (ou <?php et ?>, ça dépend des options de compilation).
  • on finit une commande par un point-virgule. Mais il n'y a pas de point-virgule à l'appel d'une instruction conditionnelle if, for ou while.
  • une chaîne de caractères s'encadre par des guillemets doubles. <html> est une chaîne, $variable1 $variable2 en est une autre qui s'écrira print("$variable1 $variable2");
  • une variable commence par le signe dollar :$name
  • on peut grouper l'écriture de code html sur plusieurs lignes en commençant par print".... et en finissant par ....";
    voyez dans mon fichier de fonctions les deux écritures différentes, mais qui donnent la même chose, des fonctions printRow et generateHead (attention, dans ce cas il n'y a pas de parenthèses).
  • les caractères spéciaux sont précédés du caractère d'échappement \ (backslash) : ainsi " s'écrit \", et le saut de ligne s'écrit \n.
  • une fonction est souvent appelée avec des arguments entre parenthèses séparés par des virgules.

5.3.2 les variables

On va faire un petit tour vers les variables car c'est quelque chose qui sert...

1. opérateur d'affectation :

si j'écris :

$tatouage = "94412";

on a paramétré l'expression de gauche - la variable - avec la chaîne "94412"

$valeur_acq = 22000.00;

paramètre la variable avec le double 22000.00.

Dans l'expression $variable = valeur; on paramètre l'expression de gauche ($variable) avec l'expression de droite (valeur).

Je pourrais également écrire :

$montant_ht = $pu_ht*$qté;

ce qui multiplie les deux variables de droite pour fourrer le résultat dans la variable de gauche, $montant_ht. Le signe 'égale' (=) est ici un opérateur d'affectation de variable.

2. opérateurs de comparaison :
l'opérateur de comparaison à l'égalité est le 'double égal' (= =).
if($vnc_fin == 0)

cette expression if va regarder si la variable $vnc_fin est égale à zéro. Pour être égale à zéro, elle devra avoir été paramétrée avec la valeur zéro d'une manière ou d'une autre. Il faut faire très attention aux significations différentes du 'égal' et du 'double égal'.

Les autres opérateurs de comparaison ressemblent aux opérateurs sql :

  • != différent de
  • <> différent de
  • <, <=, >, >= inférieur à, inférieur ou égal à, supérieur à, supérieur ou égal à
  • . (le point) est un opérateur de concaténation. Par exemple :
$boucle = 130;
$tatouage = 94418;

$test = $boucle.$tatouage;

print($test);

donnera :13094418 car les deux variables ont été concaténées (assemblées l'une à la suite de l'autre).

3. opérateurs logiques :
  • && (s'écrit aussi : and) l'expression est vraie lorsque les valeurs liées sont toutes vraies
  • || (s'écrit aussi : or) expression vraie si une valeur au moins est vraie
  • xor est le 'ou' exclusif. L'expression sera vraie si une valeur seulement de l'expression est vraie
  • ! c'est le 'n'est pas' qui nie l'expression. !$variable est vrai lorsque $variable est faux.

5.3.3 les tableaux

Pour php un tableau c'est une variable à tiroirs.

valeur 1 valeur 2 valeur 3 valeur 4 valeur 5
$tableau[0] $tableau[1] $tableau[2] $tableau[3] $tableau[4]

Si on définit :

$tableau = array("valeur 1","valeur 2","valeur 3","valeur 4","valeur 5");

on aura :

$tableau[0] == valeur 1
$tableau[1] == valeur 2

et ainsi de suite comme indiqué dans le tableau.

La fonction 'array' a créé une variable indexée, dont l'indexation commence à zéro. Ce type de tableau à une ligne ressemble à s'y méprendre à une ligne de table ou de requête dans une base de donnée...

On peut bien sûr avoir un tableau multidimensionnel :

$tableau[] = array($valeur_1,$valeur_2);

Si on possède là-dessus plusieurs couples $valeur_1,$valeur_2, on obtiendra un tableau multidimensionnel. Si pour notre troisième couple $valeur_1 = = 25, alors $tableau[2][0] = = 25, car $tableau[] commence son indexation à zéro (donc le troisième couple est l'index 2) et $valeur_1 est toujours indexée à zéro (si on n'a pas fixé d'index particulier, ce qui est possible, mais ne nous égarons pas...).

Pour les tableaux le remède est simple : pratiquer ! Au bout d'un moment, ça vient !

5.3.4 insérer des commentaires

On insère un commentaire avec un double-slash (//) ou entre les balises /* et */. Les commentaires ne sont pas superflus, ils permettent de reprendre un script en s'y retrouvant ou de mettre en place des morceaux de script pour plus tard.

if($année_achat==$my_exercice) //on teste si le matériel est acheté
                               //l'année d'exercice clôturé 

{

morceau de code

}

else

{

/*

cette partie est en développement

autre morceau de code

*/

5.3.5 fonction print()

C'est la fonction de base qui renvoie ce qu'on y entre vers le navigateur. En fait php ne se prend pas la tête : quand il ne comprend pas, il renvoie tel quel (si la syntaxe est bonne cependant).

print("<html>\n");
print("<head>\n");
print("<title>");

renvoie:

<html>
<head><title>

la sequence \n renvoie un saut de ligne.

C'est une fonction qui inclut, dans le fichier où elle est appelée, le code du fichier passé en argument.

En php3 include() doit être appelée avant que les fonctions situées dans le bloc à inclure soient elles-même appelées.

Ainsi dans le script principal include() est en deuxième ligne car sa fonction generateHead() est demandée juste après.

Une fonction peut être définie dans le script lui même (si par exemple elle ne va servir que dans ce script là). Elle sera écrite de la même manière, en inscrivant le bloc de code entre accolades.

    function ma_fonction(mes-arguments)
    {

    code

    }

Vous constaterez aisément que generateHead($title) est une fonction qui génère le début du script html en passant le nom de la page en argument. printRow($label,$type,$name,$size) génère le code d'un champ de texte de formulaire dans une cellule de tableau (td), tandis que printToClick($color,$type,$name,$value) génère des boutons de couleur, type, nom et valeur différents (toujours dans une cellule de tableau). Lorsqu'on appelle la fonction, on passe les arguments entre guillemets doubles.

5.3.7 évaluation du début du script

Si on revient au script, on s'aperçoit que php3 a tout simplement fabriqué un formulaire en renvoyant du html au navigateur. On n'est pas obligé, en fait, de tout écrire en php. Il serait suffisant éventuellement d'écrire du html et d'inclure, par endroits, du code php entre ses deux balises <? et ?>. Par exemple :

    <table>
    <tr>
    <? 
    printRow("valeur d'acquisition","float","valeur_acq","10");
    printRow("exercice","date","exercice","10");
    ?>

    </tr>

Ici, j'ai appelé la fonction printRow() 2 fois ce qui me crée deux champs de texte sur la même ligne. Le code avant et après les appels de fonction est du html.

Notez, afin de comprendre la suite, que ce script de formulaire ne comprend qu'un champ de texte pour la variable $exercice. En réalité, j'ai également des champs de texte pour mes champs code, achat, nom_matériel, durée, valeur_acq.

Ce formulaire se finit sur la balise </html>.

5.3.8 les instructions conditionnelles et les boucles

[1.]La première instruction qui suit </html> est une instruction if(). if() teste l'expression entre parenthèses. Si le test renvoie 'true' (vrai) le bloc de code suivant est lu. Si la réponse est 'false' (faux), ce bloc est ignoré et c'est le bloc situé après 'else' qui est exécuté. Rappelez-vous qu'une variable égale à zéro ou vide renvoie false. Donc, à mon premier appel du formulaire, la variable $nom_matériel n'est pas paramétrée. Le formulaire imprime à la fin en dessous des champs "en attente de données". Si je ne prends pas une telle précaution, le script m'envoie des chaînes vides ou des zéros dans la table choisie dans l'instruction sql INSERT INTO qui suit. En revanche, si j'ai paramétré la variable (en remplissant le champ du formulaire) et envoyé les données en cliquant sur 'insérer', le script s'exécute à nouveau, if(nom_matériel) renvoie 'true' et le bloc de code qui suit est examiné.

[2.]Une variante de if-else est l'instruction if()-elseif()-else : si if() renvoie 'faux' alors elseif() est examiné. Si elseif() renvoie vrai, c'est le bloc situé juste après elseif() qui est exécuté, sinon c'est le dernier bloc, qui se situe après else, qui est exécuté. Les blocs après if(), elseif() et else sont entre accolades.

[3.]Une autre possibilité est donnée par l'instruction switch() qui étudie une variable et qui compare sa valeur aux possibilités offertes par les sous-instructions case.
J'ai, par exemple, défini deux boutons radio :

    <input type="radio" name="type_résultats" value="partiels">
    <input type="radio" name="type_résultats" value="clôture">

Je peux tester la valeur de $type_résultats dans une instruction switch() et affecter un bloc de code différent en fonction de ladite valeur.

    switch($type_résultats)
    {
           case "partiels":
           ici on met du code approprié à "partiels" 
           break; 

           case "clôture":
           ici on met aussi du code approprié à "clôture"
           break;

           default: 
           encore du code si il y a possibilité de ne pas cocher de bouton(ni "partiels" ni "clôture") 
           break;

    }

  après la deuxième accolade qui ferme l'instruction le code redevient commun. 

Après case, on peut mettre une variable, pour tester une variable à une autre variable :

    switch($exercice){
                      case $my_exercice:

    }

[4.]L'instruction while() permet de réaliser des boucles et de parcourir des lignes de résultat de requête sql. while() examine l'expression entre parenthèses : si l'expression est vraie, le bloc situé en dessous est exécuté et while() réexamine l'expression, jusqu'à ce qu'elle renvoie 'faux'. Alors la boucle s'arrête. La fonction mysql_fetch_row() extrait les lignes d'un résultat et les présente sous forme de tableau comme je l'ai indiqué plus haut. La fonction extrait les rangs du résultat tant qu'il en reste. Voici ce qu'on pourrait faire avec la table précédente.

    $query = "SELECT code, nom_materiel, amt_exercice ";
    $query .= "FROM immobilisations ";
    $query .= "ORDERBY code";
    $mysql_result = mysql_query($query,$mysql_link);
    while($row = mysql_fetch_row($mysql_result))
    {
    $code = $row[0];
    $nom_materiel = $row[1];
    $amt_exercice = $row[2];
    print("<tr>\n");
    print("<td>$code</td>\n");
    print("<td>$nom_materiel</td>\n");
    print("<td>$amt_exercice</td>\n");
    print("</tr>\n");
    }

    si on a précédemment défini un champ <select>

    $query = "SELECT nom_materiel ";
    $query ;= "FROM immobilisations ";
    $query .= "ORDER BY nom_materiel";
    $mysql_result = mysql_query($query,$mysql_link);
    while($row = mysql_fetch_row($mysql_result))
    {
    $nom_materiel = $row[0];
    print " <option>
    $nom_materiel
    </option\n";
    }
    print("<option selected> </option>\n");
    print("<select>\n");

Entre parenthèses, on peut mettre trois expresions séparées par un point virgule.

la première initialise la variable qui contrôle le nombre d'exécutions de la boucle :

    for($index = 0;............)

on a défini une valeur de départ pour la variable $index. Cette expression n'est lue qu'au tout premier départ de la boucle.

la seconde expression est lue avant chaque nouvelle itération de la boucle. Si c'est vrai, l'itération est lancée. Si c'est faux, la boucle s'arrête.

    $maxindex = count($option);
    for($index = 0; $index < $maxindex; ........)

on a défini une valeur, $maxindex. Tant que $index est inférieur strictement à $maxindex, la boucle subit une nouvelle itération.

la troisième expression est lue et exécutée à la fin de chaque itération. Elle sert à incrémenter le compteur $index, car c'est bien d'un compteur qu'il s'agit.

    for($index = 0; $index < $maxindex; $index++)

Voici une application pratique adaptée à un formulaire :

    $option = array("caprins","caillé","fromages","var anx cyc long");
    $maxindex = count($option);
    print("<select name=\"compte\">\n");
    for($index = 0; $index < $maxindex; $index++)
    {
    $my_option = current($option);
    print("<option>");
    print($my_option);
    print("</option>\n");
    next($option);
    }
    print("<option selected> </option>\n");
    print("</select>\n");

J'ai défini une zone de liste avec la balise <select>. Puis je fais faire une boucle : la fonction current() me sort la valeur du tableau sur laquelle est positionné le pointeur de tableau. Je sors cette valeur entre les balises <option> et </option>. Enfin je demande à la fonction next() d'aller positionner le pointeur sur la prochaîne valeur. Tant qu'il reste des valeurs à pointer, la boucle subit une itération. A la fin, on atteint le compte ($maxindex) et la boucle s'arrête.

Vous pouvez définir une fonction php printSelectedRow($label,$name,$option,$selected). Si, dans le script, vous définissez le tableau $option, l'appel de la fonction peut élaborer une zone de liste à partir de valeurs que vous avez définies. La variable $selected sert à inclure une valeur d'affichage, entre <option selected> et </option>.

5.3.9 les fonctions de base de donnée MySQL

Nous y voilà : php nous donne toutes les fonctions nécessaires à la connexion puis à l'extraction de données.

[1.]Regardons le bloc situé dans la boucle if(). La première instruction est :
$mysql_link = mysql_connect("localhost","oltra","mon_pass");

Cette première instruction utilise la fonction mysql_connect(). Elle permet de connecter l'utilisateut "oltra" avec la machine "localhost", identifié par le mot de passe "mon_pass". Ce qui rappelle la définition des droits MySQL. Cette fonction renvoie un entier que j'ai appelé $mysql_link. C'est l'identifiant de connexion (certains l'appellent 'entier lien'). J'aurais pu le nommer $toto. Le tout est de s'en souvenir !... mysql_connect() ouvre une connexion temporaire avec le serveur. Cette connexion sera fermée à l'issue du script.

[2.]La seconde instruction sélectionne la base de donnée sur laquelle on veut travailler. Elle utilise la fonction mysql_select_db(). Elle demande en arguments le nom de la base et l'identifiant de connexion.

mysql_select_db("nos_clients",$mysql_link);

[3.]Puis vient l'entier requête $query. La syntaxe est la même qu'en mode console. J'ai concaténé les différentes parties de l'expression pour m'y retrouver, avec l'opérateur .=. Mais attention :

$query = "INSERT INTO immobilisations";
$query .= "(code,date_achat)";
$query .= "VALUES('$code','$date_achat')";

n'est pas bon du tout ! Car les guillemets doubles viennent juste après 'immobilisations' et '(code,date_achat)'. Ce qui fait qu'à la concaténation on obtient : 'immobilisations(code,date_achat)values' ce qui n'est pas une bonne syntaxe car il manque les espaces ! Il faut écrire :

$query = "INSERT INTO immobilisations ";
$query .= "(code,date_achat) ";
$query .= "VALUES ('$code','$date_achat');

en laissant les espaces nécessaires avant les guillemets de fin.

[4.]Ensuite on apppelle l'entier résultat $mysql_result (on peut également l'appeler comme on veut). L'entier résultat est calculé par la fonction mysql_query() qui accepte en arguments l'entier requête $query et l'entier lien $mysql_link.

[5.]La dernière étape me sert à l'affichage du nombre de lignes concernées par la requête, grâce à la fonction mysql_affected_rows(). Cette fonction sort un entier que j'ai appelé $maj (pour mise à jour). Lorsque j'envoie les données, le nombre de lignes concernées par la requête s'affiche sous le formulaire (en rouge puisque je vais chercher le style "message"). Si il y a un problème j'obtiens '-1 mises à jour'. Il existe des fonctions pour les erreurs, mysql_error() et mysql_errno() (que je n'utilise pas).

5.4 Autres fonctions

5.4.1 fonctions SQL

En fait l'entier requête peut représenter toute requête sql : delete, update et bien sûr select. On a vu un exemple de SELECT dans le passage sur les boucles.

J'ai fait quelques scripts utilisant une instruction update : lorsqu'une bête perd une boucle d'oreille, il faut la reboucler (mesure obligatoire pour la traçabilité des animaux). Par conséquent, il m'a fallu un script qui permette de modifier le numéro de boucle d'un animal possédant tel numéro de tatouage (ou par rapport à l'ancien numéro de boucle). Plusieurs instructions UPDATE mettent à jour mes tables de la base de donnée 'troupeau'.

Une instruction DELETE peut être utilisée lorsqu'un champ prend une certaine valeur dans un enregistrement : lorsqu'un matériel est amorti, sa valeur nette comptable de fin d'exercice (comptable) est égale à zéro ($vnc_fin = = 0). Alors une instruction le sortira de mon tableau d'amortissement en fin d'exercice suivant.

A partir du moment où une connexion est ouverte avec le serveur, il est possible de faire plusieurs requêtes les unes à la suite des autres (ou les unes dans les autres). Dans ces cas-là, on peut définir des entiers requêtes différents. Lorsque j'enregistre une mise-bas, il y a création d'un numéro de mise_bas dans le champ id (ce champ est auto-incrémenté) de la table mises_bas. Si cette mise-bas a donné une chevrette à laquelle je mets un tip-tag, je vais utiliser mon formulaire 'identification'. Il ne m'est pas nécessaire, dans celui-ci, de renseigner le champ id (clé externe du champ 'id' de la table mises_bas). En effet, je définis :

$query = "SELECT max(id) ";
$query .= "FROM mises_bas";
$mysql_result = mysql_query($query,$mysql_link);

while($row = mysql_fetch_row($mysql_result))

{

$my_no = $row[0];

}

alors $my_no me servira comme valeur de identification.id lorsque je ferai mon INSERT INTO.

5.4.2 autres fonctions php

Il y en a quelques douzaines... Je vais présenter certaines qui m'ont été utiles. Les chaînes passées en arguments sont toujours entre guillemets doubles. Le bouquin d'Atkinson est mieux fait pour obtenir des détails sur les fonctions.

empty()
teste si une variable est paramétrée. Elle renvoie vrai si la variable est vide, égale à zéro ou à une chaîne vide. if(empty($variable)) est un peu comme if($variable)
unset()
détruit la mémoire associée à une variable.
list() et each()
permettent de récupérer des enregistrements d'un tableau (i.e. de le parcourir avec une boucle).
list($index,$valeur) = each($tableau);

quand each() pointe sur $tableau[1] par exemple, list() sort $index= = 1 et $valeur = =$tableau[1].

strtoupper(chaine)
convertit une chaîne en majuscules
substr(chaîne,pos,taille)
récupère dans 'chaîne' une sous-chaîne de 'taille' caractères à partir de la position définie par 'pos' (du début ou de la fin si 'pos' est négatif).
split(séparateur de chaîne,chaîne)
élabore un tableau à partir de bouts de chaîne séparés par le séparateur passé en argument. par exemple :
$date = "2001-03-23";
$date_array = split("-",$date);

on obtiendra :

$date_array[0] == 2001
$date_array[1] == 03

$date_array[2] == 23

En effet, le séparateur, c'est le tiret (-). C'est une fonction très utile.

ereg(modèle,chaine à tester,$tableau)
petite fonction amusante (!) pour qui connaît les expressions régulières. ereg() teste 'chaîne à tester' et ses sous-chaînes en fonction de l'expression régulière 'modèle'. Si 'modèle' comporte des sous-modèles mis entre parenthèses, $tableau stockera les concordances de 'chaîne à tester' avec 'modèles'. On aura $tableau[0] qui contiendra la chaîne entière et les autres valeurs de $tableau[] qui contiendront les sous-chaînes éventuelles. Si il n'y a pas de concordance, ereg() renvoie faux. Voici un exemple : j'ai fabriqué une zone de liste dont le nom est 'facture'. La variable $facture est en réalité la concaténation d'un nom de société et d'un numéro d'ordre (un entier) de pièce comptable, séparés par une virgule. ereg() va tester la concordance de $facture avec un modèle et sortir le nom de la société et le numéro d'ordre.
if(ereg("(.+ ?),([0-9]+)$",$facture,$concordance))
{
print("ma sélection: $concordance[0]<br>\n");
print("société: $concordance[1]<br>\n");
print("numéro de pièce: $concordance[2]<br>\n");
}

car la première sous-expression entre parenthèses teste des caractères éventuellement séparés par des espaces, tandis que la seconde teste un numéro à un chiffre au moins ! Le caret en début de modèle signifie que la recherche débute en début d'expression, le signe $ indique la fin de l'expression. J'aurais pu utiliser split(), mais il faut bien s'amuser un peu !

Téléchargement des formulaires...

6 Et pour conclure

Je vous ai transmis la majeure partie de mon maigre savoir ! J'espère que ce ne fut pas trop aride. En réalité ce ne l'est pas du tout. Et c'est très, très puissant et convivial si on fait ce qu'il faut pour. Je prends beaucoup de plaisir à utiliser php, par conséquent je ferai tout mon possible pour renseigner les lecteurs qui me contacteront : lapagedudebutant@libertysurf.fr.

Depuis le début de la rédaction de cette rubrique, j'ai eu la nécessité d'utiliser les fonctions pdf de php. Impossible ! Je vais donc devoir recompiler l'affaire et en profiter pour passer à php4. Comme quoi, compiler peut se révéler nécessaire plus tôt que prévu pour pouvoir utiliser toutes les fonctionnalités d'un outil.

[ Retour ]

Remonter

Site réalisé sous Gnu-Linux en PHP mis en forme avec Quanta et mis en ligne grâce à gFTP sous la Mandrake 9.1