PHP


Accès aux bases de données



BoTTom


Bases de données

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.



1.La connexion à un SGBDR (ici, MYSQL)

La connexion à un système de gestion de base de données s'effectue par l'entremise des fonctions spécialisées.



Il existe deux façons de se connecter à une base de données.

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.

Plusieurs fonctions PHP permettent de retourner des informations à propos de la connexion en cours.



2.L'accès aux bases de données

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');
$liste_bases = mysql_list_dbs();
$nb_bases = mysql_num_rows($liste_bases);

echo "<h3>Liste des bases de données</h3>";

for($i = 0; $i < $nb_bases; $i++)
{
$nom_base_donnee = mysql_db_name($liste_bases, $i) .
"<br>";
$liste_tables=mysql_list_tables($nom_base_donnee,$id_connexion);
$nb_tables = mysql_num_rows($liste_tables);

echo "<h3>" . $nom_base_donnee . "</h3>";
echo "<h4>Liste des tables :</h4>";

for($j = 0; $j < $nb_tables; $j++)
{
echo mysql_tablename($liste_tables, $j) .
"<br>";
}
}



3.Les requêtes SQL

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.



4.Exploiter les données retournées

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_select = mysql_select_db("utilisateur") or die ("La sélection de la base a échoué !");

$id_requete = mysql_query("select * from tbl_util", $id_connex);

if($id_requete)
{
echo '<table border="0">'
. '<tr bgcolor="#000000" style="color:#FFFFFF">'
. '<th>Date</th><th>eMail</th><th>Nom</th></tr>';

while($ligne = mysql_fetch_array($id_requete))
{

echo '<tr bgcolor ="#FFFF00">'<td>' .
$ligne['date'] . '</td>';
echo ‘<td>' .
$ligne['email'] . '</td>'<td>' . $ligne['nom'] . '</td>';
echo '<tr>';
}

echo '</table>';

mysql_free_result($id_requete);
}

else
{
echo "<h3>Impossible d'exécuter la requête de sélection !</h3>";
}

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.

 

5.ODBC / CLI

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)

les fonctions ODBC sont implémentées sur la même logique que celles vues pour MYSQL

la connexion ODBC se fait avec les attributs suivants :


IBM, propose le code suivant pour définir un accès universel (plateforme Windows/Linux et OS/400)

 // 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)

 

  • Convention d'appellation SQL

    Sur Windows/Linux
     vous pouvez fournir une liste de bibliothèques, celle ci sera utilisée pour la recherche des types de données utilisateur (UDT), des fonctions (UDF) et des procédures cataloguées. La première de ces bibliothèques sera considérée comme la bibliothèque par défaut.

    Sur I5
    vous ne pouvez fournir qu'un seul nom de bibliothèque qui sera la bibliothèque par défaut

    La bibliothèque par défaut est automatiquement utilisée lors d'une requête SQL non qualifiée pour l'accès aux tables

    Si vous n'indiquez pas de bibliothèque par défaut, c'est le AUTHORIZATION ID qui est utilisé

    l'authorization ID est par défaut le nom de l'utilisateur en cours, peut être modifié par SET AUTHORIZATION ID et doit être un nom de profil.


  • Convention d'appellation système

    Vous utilisez *LIBL.

    La liste de bibliothèques est celle de l'utilisateur connecté (application de la JOBD incluse) ou par défaut de l'utilisateur du serveur Apache.

    Vous pouvez la compléter en passant les ordres suivants :
       $addlible = "call qcmdexc ('addlible bdvin9' , 0000000015.00000)";
       $result = odbc_exec($db, $addlible);


  • Dans tous les cas, vous pouvez passer en plus l'ordre SQL SET PATH pour fournir une liste de bibliothèques à utiliser pour vos références à :
    •vos UDT (types de données définis par l'utilisateur)
    •vos procédures cataloguées
    •vos fonctions (UDF), si la liste des paramètres est correcte


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) à

http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Fcli%2Frzadpfnsenva.htm

Liste partielle :

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
*NONE 1
*CHG 2
*cs 3
*ALL 4
*RR 5

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

*ISO 1
*USA 2
*EUR 3
*JIS 4
*MDY 5
*DMY 6
*YMD 7
DSP Séparateur de la Date
0 = "/" 
1 = "-"  
2 = "."  
3 = ","  
4 = " "  
1 SQL_ATTR_DATE_SEP

/ 1
- 2
. 3
, 4
espace 5
format du job 7
DEC Séparateur décimal

0 = "." (point)
1 = "," (virgule)
0 SQL_ATTR_DECIMAL_SEP
. 3
, 4
format du job 7
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
*ISO 1
*USA 2
*EUR 3
*HMS 9
TSP Séparateur des Heures 0 = ":" 
1 = "." 
2 = "," 
3 = " " 
0 SQL_ATTR_TIME_SEP

                       (voir la date)


Exemple :

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&eacute;sultat:<br>                                                                      
<?php                                                                                       
  if ($result == 0):                                                      
   echo ("<B>Error " . odbc_error() . ": " . odbc_errormsg() . "</B>");
 elseif (odbc_num_rows($result) == 0):                                                                                      
    echo("<B>Requete ex&eacute;cut&eacute;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 :


ces deux fonctions n'ont de sens que si vous êtes sous contrôle de validation

Remarques concernant les mises à jour (update) et les insertions (insert)

  1. Si vous travaillez sur des fichiers (Tables) non journalisé, vous devez être hors commitment control (CMT à 0 ou SQL_ATTR_COMMIT à 1) ce qui n'est jamais la valeur par défaut.Si vous travaillez sur des tables journalisées et sous commitment control, pensez à valider (Commit)

  2. Si vous êtes sur une version récente de Linux, elle fonctionne (ainsi que Apache) en UTF-8, (basé sur Unicode) et le driver ODBC de Client Access traduit les données en utilisant la routine iconv(). Cette dernière pose un problème avec nos caractères (Latin-1, soit ISO-8859-1 ou 8859-15 avec l'Euro)

    Vous recevez alors le message
    [unixODBC][IBM][iSeries Access ODBC Driver][DB2 UDB]SQL0104 - Error message text unavailable. Message can not be translated successfully.


    pour résoudre ce problème, passez la locale en Français, par setlocale(LC_ALL, 'fr_FR') lors de la connexion.


    Nous vous proposons donc, comme code de connexion universel et implémentant nos règles habituelles de fonctionnement :
    <?
    $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
    // mise en place *LIBL
    $lg = '00000000' . number_format(strlen($bib) + 9, 5 , ".", ""); $addlible = "call qsys/qcmdexc ('ADDLIBLE " . $bib . "' , $lg)"; $result = odbc_exec($db, $addlible); if ($result == 0){ echo "Erreur mise en place *LIBL " . $addlible; echo ("<BR><B>Erreur " . odbc_error() . ": " . odbc_errormsg() . "</B>"); } // mise en place des bibliothèques pour les fonctions et les procédures $setpath = "set path='QSYS,QSYS2,BIBFCT1,BIBFCT2'"; $result = odbc_exec($db, $setpath); if ($result == 0){ echo "Erreur SETPATH " . $setpath; echo ("<BR><B>Erreur " . odbc_error() . ": " . odbc_errormsg() . "</B>"); } ?>

  3. Mise à jour de données contenant une apostrophe (quote) comme dans 'pomme d'api'

    • Si vous avez activé l'option magic_quotes_runtime (dans php.ini) l'apostrophe est protégée par un \ ('pomme d\'api') Ca marche avec certaines bases, mais pas avec DB2, sauf à ajouter magic_quotes_sybase qui ajoute ' (donc, double la quote) et non \.

    la fonction get_magic_quotes_runtime() permet de connaitre la valeur en cours, set_magic_quotes_runtime() de la modifier.

    • Doublez la quote manuellement, par :
    str_replace("'" , "''" , variableAtraiter);
  4. Si vos données sont en Unicode sur le system i

remplacez SetEnv="CCSID=819" par SetEnv="CCSID=1208" dans le fichier fastcgi.conf (ZendServer uniquement)

ajoutez :

odbc_setoption($link, 1, SQL_ATTR_UTF8, 1);
     

6.Autres accès base de données


	MONPF de type *FILE dans MABIB non trouvé. SQLCODE=-204

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().



 

L'avenir des accès base de données s'appelle probablement PDO et est livré avec PHP 5.1

(c'est disponible avec php 5.0 en mode expérimental)


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)


<?php
   $db 
= new PDO("ibm:AS400', 'user', 'pwd' );
   echo "Connecté !"
?>

 

Exécution d' une requête et affichage du résultat


$req = $db->prepare("select * from fichier ");

if ($req->execute()) {
while (($row = $req->fetch()) !== false) {
print_r($row);
}
}

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();
?>



Appel à une procédure cataloguée (le paramètre a été déclaré en sortie, c.a.d retourné par la procédure)

$req = $dbh->prepare("CALL procedure1(?)");
$req->bindParam(1, $retour, PDO_PARAM_STR, 4000); // N° , $variable, type, lg

// exécution
$req->execute();

print "valeur retourn&eacute;e $retour\n";


Voyez la liste des méthodes à http://php.net/manual/fr/book.pdo.php

et cette page IBM expliquant comment utiliser PDO avec DB2

 

 

BoTTom

 

©AF400