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.
Vous
pouvez, bien sur, accèder à votre base de
données
DB2/400 en utilisant les routines ODBC ou DB2
(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
il s'agit d'un objet, masquant la complexité et les disparités des différents drivers.
il offre le grand avantage de proposer un accès
transparent aux base de données y compris l'appel aux procédures cataloguées.
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(); ?> |
Gestion d'une transaction (commit/rollback)
try { $db->beginTransaction(); $db->exec("insert into BDVIN1.appellations values (998 , 'Priorat')"); $db->exec("insert into BDVIN1.appellations values (999 , 'DAO Penedes')"); $db->commit(); } catch (Exception $e) { $db->rollBack(); echo "Erreur : " . $e->getMessage(); } |
$req
= $db->prepare("CALL BDVIN1.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