Le principal intérêt d'un langage Web dynamique est sa capacité à la gestion de bases de données SQL.
A cet effet, le langage PHP propose de nombreux outils permettant de travailler avec la plupart des SGBDR (Système de Gestion de Bases de données Relationnelles) tels que Oracle, Sybase, Microsoft SQL Server, PostgreSQL ou encore MySQL, son système de gestion de prédilection.
Avant d'aller plus loin dans ce cours, il est nécessaire de connaître non seulement la structure d'une base de données, mais également les notions élémentaires du langage SQL.
La connexion à un système de gestion de base de données s'effectue par l'entremise des fonctions spécialisées.
mysql_connect("nom_serveur","nom_utilisateur","mot_passe");
mssql_connect("nom_serveur","nom_utilisateur","mot_passe");
ocilogon("nom_utilisateur","mot_passe", "nom_base");
pg_connect("dbname=nom_base host=nom_serveur port=num_port "."user=nom_utilisateur password=mot_passe");
sybase_connect("nom_serveur","nom_utilisateur","mot_passe");
Il existe deux façons de se connecter à une base de données.
Les connexions non-persistantes (base_connect).
Les connexions persistantes (base_pconnect).
Tout d'abord, les deux types de connexions sont parfaitement identiques au niveau des fonctionnalités qu'elles apportent. Néanmoins, les connexions persistantes ne se referment pas automatiquement à la fin du script. Lorsqu'une telle connexion est demandée, PHP s'assure qu'il n'existe pas un processus semblable déjà ouvert, avec les noms de serveur et d'utilisateur ainsi que le mot de passe. Si tel est le cas, ce processus est réutilisé sinon un nouveau est ouvert.
Ainsi, le principal avantage des connexions persistantes et de leur réutilisation réside dans l'impossibilité d'ouvertures multiples de connexions à un SGBDR. Toutefois, il est impératif de s'assurer de la fermeture correcte des processus au terme de leur utilisation puisque si le serveur n'admet qu'un certain nombre de clients, alors une connexion inutilisée constituera une perte de capacités.
La déconnexion des bases de données s'effectue par l'intermédiaire des fonctions de fermeture.
mysql_close($id_connexion);
mssql_close($id_connexion);
ocilogoff($id_connexion);
pg_close($id_connexion);
sybase_connect($id_connexion);
Plusieurs fonctions PHP permettent de retourner des informations à propos de la connexion en cours.
$chaine_numero_version = mysql_get_client_info();
$type_connexion = mysql_get_host_info($id_connexion);
$protocole_connexion=mysql_get_proto_info($id_connexion);
$chaine_version_serv=mysql_get_server_info($id_connexion);
Suite à la connexion à un SGBDR, il faut soit sélectionner la base de données si elle existe déjà, soit la créer si ce n'est pas le cas.
La sélection de bases de données s'effectue par l’intermédiaire de fonctions adaptées.
mysql_select_db ($nom_base_donnee, $id_connexion);
La création des bases de données peut être réalisée par des fonctions PHP dévolues à cette tâche.
mysql_create_db ($nom_base_donnee, $id_connexion);
Si la création d'une base de données n'est pas possible à l'aide de fonctions, il est possible de créer une base à l'aide d'une requête SQL.
$requete = "CREATE DATABASE nom_base_donnee";
La suppression des bases de données est permise, de la même façon qu'il est possible de les créer.
mysql_drop_db ($nom_base_donnee, $id_connexion);
Certaines fonctions permettent de retourner la liste des bases de données et de leurs tables.
$id_connexion=
mysql_connect('localhost', 'administrateur', 'password'); echo "<h3>Liste des bases de données</h3>"; for($i = 0; $i
< $nb_bases; $i++) echo
"<h3>" . $nom_base_donnee . "</h3>"; for($j = 0; $j < $nb_tables;
$j++) |
Les requêtes SQL permettent d'accomplir une action sur une base de données comme la sélection d'informations, la création de tables, l'ajout, la suppression ou la modification des enregistrements.
$requete = "SELECT * FROM table WHERE champ = \"valeur\"" |
$id_resultat = mysql_query($requete, $id_connexion) |
*
remarquez le caratere anti-slash (\)
, pour signifier un "
significatif
Toutes ces fonctions prennent comme argument une requête SQL valide (select, update, create table, ...) qui sera envoyée à la base de données définie par un identificateur de connexion.
En cas de réussite, les fonctions retournent un identificateur, sinon la valeur est false.
L'identificateur représente le résultat produit par la requête dans la base de données en cours. La variable $id_resultat pourra par la suite être utilisée par d'autres fonctions afin d'exploiter les données disponibles.
Les requêtes doivent répondre à la syntaxe SQL (Structured Query Language) en général, et éventuellement aux singularités des différents éditeurs de SGBDR.
De nombreuses fonctions de bases de données permettent d'extraire des informations telles que des enregistrements ou des champs précis d'une ou plusieurs tables.
Subséquemment à l'exécution d'une requête, des fonctions spécialisées s'occupent de l'extraction de données ciblées.
$requete = "SELECT nom, prenom, adresse, cp, ville" |
. "FROM tbl_client"; |
Lorsque le résultat d'une requête devient disponible, le pointeur d'enregistrement se situe sur la première ligne de la table, soit à l'index '0'.
A partir de là, il suffit de déplacer le pointeur par une incrémentation de l'index ou de le placer directement à un index spécifié. Chaque ligne pourra alors délivrer la totalité de son contenu.
Le décompte total des enregistrements ou des champs d'une table peut être obtenu par l'intermédiaire de certaines fonctions.
$nb_champs = mysql_num_fields($id_resultat);
$nb_lignes = mysql_num_rows($id_resultat);
A partir des enregistrements, chacun des champs devient accessible aisément par des fonctions appropriées.
$id_connex =
mysql_connect("localhost","root","password"); $id_requete = mysql_query("select * from tbl_util", $id_connex); if($id_requete) while($ligne =
mysql_fetch_array($id_requete)) echo '</table>'; mysql_free_result($id_requete); mysql_close(); |
En outre, certaines fonctions sont capables d'extraire directement un champ déterminé avec exactitude.
$valeur = mysql_result($id_resultat, $num_ligne, $num_col);
Afin d'éviter une surcharge de la mémoire, des instructions PHP permettent de libérer les ressources suite au terme de leur utilisation.
mysql_free_result($id_resultat);
Le langage
PHP prend en charge la plupart des SGBDR courants, lui procurant ainsi
un panel impressionnant d'outils visant à exploiter pleinement
n'importe quel type de bases de données.
mais vous
pouvez, bien sur, accèder à votre base de
données
DB2/400 en utilisant les routines ODBC
(elles
sont présentes en natif
sous OS/400 sous le nom de CLI)
// If we report the OS as AIX or OS400, assume we're
running under PASE $isPase = (PHP_OS == "AIX" || PHP_OS == "OS400"); if (!$isPase) { $dsn = "DRIVER=iSeries Access ODBC Driver;SYSTEM=$isdb_system;DBQ=$isdb_database"; $db = odbc_pconnect($dsn, $user, $pwd); } else { $db = odbc_connect($isdb_system, $user, $pwd); odbc_setoption($db, 1, SQL_ATTR_DBC_DEFAULT_LIB, $isdb_database) } |
Vous remarquerez l'utilisation de odbc_pconnect dans le cas d'un serveur intel
et odbc_connect quand les pages php sont sur iSeries.
cet extrait de code est proposé avec
des exemples d'accès à DB2/400 en php sous linux, sur la page
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/rzatv/rzatvexodbc.htm
ATTENTION. Beaucoup de paramètres et de comportements sont dépendant de la convention d'appellation (Sql ou système)
|
Voyez la liste des propriétés pouvant être renseignées
dans la chaîne de connexion (Dsn) à l'adresse suivante
http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/topic/rzaik/connectkeywords.htm
et la liste des options de connexion CLI
(odbc_setoption() , quand ODBC
est sur l'AS400) à
Clé | signification | Choix | dft | odbc_setoption() | ||||||||||
DBQ | (voir plus haut) | Bibliothèque | "QGPL" | SQL_ATTR_DBC_DEFAULT_LIB | ||||||||||
NAM | Convention d'appellation. | 0 = "sql" ( schema.table) 1 = "system" ( schema/table) |
0 | SQL_ATTR_DBC_SYS_NAMING | ||||||||||
CMT | Niveau de transaction | 0 = Commit immediate (*NONE) 1 = Read committed (*CS) 2 = Read uncommitted (*CHG) 3 = Repeatable read (*ALL) 4 = Serializable (*RR) |
2 | SQL_ATTR_COMMIT Attention les valeurs sont différentes
|
DFT | Format de la Date | 0 = yy/ddd (*JUL) 1 = mm/dd/yy (*MDY) 2 = dd/mm/yy (*DMY) 3 = yy/mm/dd (*YMD) 4 = mm/dd/yyyy (*USA) 5 = yyyy-mm-dd (*ISO) 6 = dd.mm.yyyy (*EUR) 7 = yyyy-mm-dd (*JIS) |
5 | SQL_ATTR_DATE_FMT
|
||||||||||||||
DSP | Séparateur de la Date | 0 = "/" 1 = "-" 2 = "." 3 = "," 4 = " " |
1 | SQL_ATTR_DATE_SEP
|
||||||||||||||
DEC | Séparateur décimal | 0 = "." (point) 1 = "," (virgule) |
0 | SQL_ATTR_DECIMAL_SEP
|
||||||||||||||
TFT | Format des Heures | 0 = hh:mm:ss (*HMS) 1 = hh:mm AM/PM (*USA) 2 = hh.mm.ss (*ISO) 3 = hh.mm.ss (*EUR) 4 = hh:mm:ss (*JIS) |
0 | SQL_ATTR_TIME_FMT
|
||||||||||||||
TSP | Séparateur des Heures | 0 = ":" 1 = "." 2 = "," 3 = " " |
0 | SQL_ATTR_TIME_SEP (voir la date) |
le code suivant accède à des fichiers DB2/400 : |
<html>
<body> <p align="center"> <font size="5" face = "Arial"><b>LISTE des APPELLATIONS<br></b></font> </p> <?php // connexion à l'AS/400 $link = odbc_connect("AS400", $user, $pwd); if(!odbc_setoption($link, 1, SQL_ATTR_DBC_DEFAULT_LIB, "BDVIN1")) { echo "ERREUR : impossible de travailler avec BDVIN1" ; } // récupération de la saisie (variable du formulaire) $appel= $_POST['appel']; // construction de la requete $query = "select pr_nom, pr_commune from producteurs where appel_code = ".$appel." order by pr_nom"; ?> <hr> <?php $result = odbc_exec($link, $query); ?> Résultat:<br> <?php if ($result == 0): echo ("<B>Error " . odbc_error() . ": " . odbc_errormsg() . "</B>"); elseif (odbc_num_rows($result) == 0): echo("<B>Requete exécutée, mais vide</B>"); else: ?> </div> <TABLE BORDER=1> <TR> <?php // boucle sur les colonnes de la requête for ($i = 0; $i < odbc_num_fields($result); $i++) { echo("<TH>" . odbc_field_name($result,$i) . "</TH>"); } ?> </TR> <?php while(odbc_fetch_into($result , $prod) != FALSE) { { echo("<TR>"); // boucle sur les valeurs d'une ligne. for ($j = 0; $j < odbc_num_fields($result); $j++) { echo("<TD>" . $prod[$j] . "</TD>"); } echo("</TR>"); } ?> </TABLE> <?php endif; odbc_close(); ?> </body> </html> |
Voyez ici le résultat (sur le site volubis.fr)
Voyez la liste des fonctions ODBC à
http://fr.php.net/manual/fr/ref.uodbc.php .
Extrait :
la documentation dit la chose suivante
:
les connexions Persistantes peuvent améliorer grandement les performances
,mais doivent être utilisées avec prudence.
Le principal avantage à utiliser des connexions persistantes est
le gain de temps lors de la connexion à la base de données.
Quand on utilise odbc_close() , la fonction renvoi TRUE, mais ne fait rien.La
connexion reste active et attend la prochaine demande de connexion permanante
valide (même host, même profil).
Un des problemes majeur est l'utilisation du commitment control.
Vous ne devez utiliser les connexion persistantes que si vous êtes
Hors commitment control (dit aussi “autocommit”).
Utiliser conjointement les connexions persistantes et le contrôle
de validation peut engendrer des transactions à l'état instable.
Vous devez aussi considérer que le travail serveur sur le iSeries
risque de rester actif en permanence, donc les fichiers toujours ouverts.
[vendor][ODBC-component][data-source]
<?php if ($resultat == 0) { echo ("<BR><B>Erreur " . odbc_error() . " : " . odbc_errormsg() . "</B>"); } else { ... |
// entetes echo '<TABLE border="1">'; echo "<TR>"; // boucle sur les noms de colonnes de la requête ==> ATTENTION on commence à 1 for ($i = 1 ; $i <= odbc_num_fields($resultat) ; $i++) { echo("<TH>".odbc_field_name($resultat,$i)."</TH>"); } echo "</TR>"; |
$rc = odbc_fetch_row($result);
while($rc != FALSE) { echo("<TR>"); // for ($j = 1; $j <= odbc_num_fields($resultat); $j++) { echo("<TD>" . odbc_result($resultat, $j) . "</TD>"); } echo("</TR>"); $rc = odbc_fetch_row($resultat); } |
// lignes détail
while(odbc_fetch_into($resultat , $lignetbl) != FALSE) { echo("<TR>"); // boucle sur les valeurs d'une ligne. ==> ATTENTION, dans un tableau on commence à 0 for ($j = 0 ; $j < odbc_num_fields($resultat) ; $j++) { echo("<TD>" . lignetbl[$j] . "</TD>"); } echo("</TR>"); } echo "</TABLE>"; |
$lignetbl=odbc_fetch_array($resultat); if ($lignetbl != FALSE) { // tableau associatif, on utilise pas un indice numérique, mais le NOM de la colonne echo("<TD>" . $lignetbl["PAYS"] . "</TD>"); echo("<TD>" . $lignetbl["PAYS_CODE"] . "</TD>"); } |
ces deux fonctions n'ont de sens que si vous êtes
sous contrôle de validation
<? $isPase = (PHP_OS == "AIX" || PHP_OS == "OS400"); $system = "AS400"; $bib = "MABIBPF"; $user = "USER"; $pwd = "PWD"; //connexion, sans commitment control, convention d'appellation système(==> *libl) et date au format DMY // à adapter en fonction du contexte (fichiers journalisés ou pas, etc ...) if (!$isPase) { // sur PC $dsn = "DRIVER=iSeries Access ODBC Driver;SYSTEM=$system;CMT=0;NAM=1;DFT=2"; $db = odbc_connect($dsn, $user, $pwd); if ($db == 0){ echo ("<BR><B>Erreur Connexion " . odbc_error() . ": " . odbc_errormsg() . "</B>"); } if (PHP_OS == "Linux") { setlocale(LC_ALL, 'fr_FR') ; } } else { // sur I5 $db = odbc_connect($system, $user, $pwd); odbc_setoption($db, 1, SQL_ATTR_COMMIT, 1); odbc_setoption($db, 1, SQL_ATTR_DBC_SYS_NAMING, 1); odbc_setoption($db, 1, SQL_ATTR_DATE_FMT, 6); } //dans tous les cas |
str_replace("'" , "''" , variableAtraiter);
remplacez SetEnv="CCSID=819" par SetEnv="CCSID=1208" dans le fichier fastcgi.conf (ZendServer uniquement)
ajoutez :
odbc_setoption($link, 1, SQL_ATTR_UTF8, 1);
Extrait :
$option = array("i5_lib"=>"MABIB","i5_naming"=>DB2_I5_NAMING_ON,
"i5_commit"=>DB2_I5_TXN_NO_COMMIT); $db = db2_connect("AS400", "PROFIL", "MOTDEPASSE", $option); |
$requete = "CALL BIB.PROC1 (?)"; $result= db2_prepare($db, $requete); $parm = array('x'); if (db2_execute($result, $parm) ){ .../... } |
$requete = "CALL BIB.PROC2 (? , ?)";
$retour = ''; $rc = db2_bind_param($stmt, 1, 'info', DB2_PARAM_IN); $rc = db2_bind_param($stmt, 2, 'retour', DB2_PARAM_OUT); $rc = db2_execute($stmt); if ($rc == FALSE){ echo ("<BR><B>Erreur " . db2_stmt_error() . ": " . db2_stmt_errormsg() . "</B>"); } else { echo "Heure : " . $retour; } |
MONPF de type *FILE dans MABIB non trouvé. SQLCODE=-204
- db2_num_fields() indique le nombre de colonnes résultat
- db2_field_name() retourne le nom d'une colonne (dont on fournit le n°)
// entetes echo '<TABLE border="1">'; echo "<TR>"; // boucle sur les noms de colonnes de la requête ==> ATTENTION on commence à 0 avec db2 for ($i = 0 ; $i < db2_num_fields($resultat) ; $i++) { echo("<TH>".db2_field_name($resultat,$i)."</TH>"); } echo "</TR>"; |
- db2_fetch_row() se positionne sur la ligne suivante du curseur et retourne TRUE (l'accès aux données se fait par ensuite par db2_result)
- db2_result() accède aux données de la ligne en cours (db2_fetch_row) d'après le nom ou le N° de colonne (la première porte le n° 0)
vous pouvez indiquer un N° de ligne en 2ème argument, si l'option DB2_SCROLLABLE est active
$rc = db2_fetch_row($result);
while($rc != FALSE) {
echo("<TR>");
//
for ($j = 0; $j < db2_num_fields($result); $j++) {
echo("<TD>" . db2_result($result, $j) . "</TD>");
}
echo("</TR>");
$rc = db2_fetch_row($result);
}Sur IBM i, il est préférable d'utilisier db2_fetch_array() au lieu de db2_fetch_row()/db2_result().
En général db2_fetch_row()/db2_result() a plus de problèmes avec des types de colonne variés dans la traduction de EBCDIC/ASCII, en incluant de possibles troncatures dans les applications DBCS. db2_result ne fonctionne pas, non plus avec des BLOB. Vous pourriez enfin, aussi trouver de meilleures performances à utiliser db2_fetch_array().
- db2_fetch_array() retourne la ligne en cours dans un tableau indicé par N° de colonne (pas commeODBC) ou false en fin de fichier.
vous pouvez indiquer un N° de ligne en 2ème argument, si l'option DB2_SCROLLABLE est active
// lignes détail
|
- db2_fetch_assoc() retourne la ligne suivante dans un tableaux associatif (qui est la valeur retournée) ou false en fin de fichier
(la clé du tableau est le nom de la colonne)
$lignetbl=db2_fetch_assoc($resultat); if ($lignetbl != FALSE) { // tableau associatif, on utilise pas un indice numérique, mais le NOM de la colonne echo("<TD>" . $lignetbl["PAYS"] . "</TD>"); echo("<TD>" . $lignetbl["PAYS_CODE"] . "</TD>"); } |
- db2_close() ferme la connexion ODBC au serveur
- db2_commit() commit (confirme) la transaction en cours
- db2_rollback() invalide la transaction en cours
L'avenir des accès
base de données s'appelle
probablement PDO
et est
livré avec PHP 5.1
il s'agit d'un objet, masquant la complexité et les disparités des différents drivers.
il offre le grand avantage (pour nous) de proposer un accès
aux procédures cataloguées avec gestion des
paramètres en sortie ou en entrée/sortie (comme ADO sous
Windows)
Création d'une nouvelle instance de l'objet PDO
(cela créé la connexion)
|
Exécution d' une requête et affichage du résultat
$req = $db->prepare("select
* from fichier "); |
Deuxième exemple plus détaillé
<?php // Ouverture d'une connection PDO $bdd = new PDO('ibm:AS400', "user", "pwd"); // Requete $query= "select vin_code, vin_nom from bdvinA.vins order by vin_nom fetch first 10 rows only"; $request = $bdd->query($query); ?> <p>Résultat : </p> <table border ="1"> <tr> <th>ID</th> <th><b>Nom du vin</th> </tr> <?php while ($ligne = $request->fetch()) { echo("<TR>"); echo("<TD>" . $ligne['VIN_CODE'] . "</TD>"); echo("<TD>" . $ligne['VIN_NOM'] . "</TD>"); echo("</TR>"); } $request->closeCursor(); ?> |
$req =
$dbh->prepare("CALL procedure1(?)"); |
Voyez la liste des méthodes à http://php.net/manual/fr/book.pdo.php
et cette page IBM expliquant comment utiliser PDO avec DB2