PHP / Oracle & MySQL : interfacage

par Rachid EL HADDARI & christophe

Objectif du document

Il s’agit de rendre le code de l’application écrit en PHP indépendant du choix du serveur de bases de données sous-jacent en développant une interface de connexion afin de pouvoir dialoguer avec plusieurs types de serveurs de bases de données différents, cela dans le but de ne pas être tributaire d’une technologie et d’assurer une pérennité à l’application développée. Les serveurs de bases de données cibles possibles seront Oracle 8i et MySQL, mais il sera possible d’enrichir l’interface en respectant certaines règles afin de pouvoir se connecter à d’autres SGBD.

PHP et bases de données

PHP est un langage de script côté serveur très utilisé aujourd’hui dans la conception de site web dynamique, et dont la popularité est dû en grande partie à sa facilité d’interfaçage avec un serveur de bases de données.

Avantage

Il supporte un nombre important de serveurs de bases de données comme Oracle, MySQL, PostgreSQL, Microsoft SQL Server, Informix, etc…les connexions à travers ODBC sont aussi possibles. Le support de ces bases de données se fait grâce à un ensemble d’APIs livrées en standard avec PHP. Grâce à ces APIs il est très facile de se connecter à un serveur de bases de données. Le dialogue avec un serveur de bases de données se fait toujours selon le même principe :

1-Ouverture d’une connexion sur le serveur,
2-Traitement,
3-Fermeture de la connexion.

Les exemples ci-après décrivent la procédure générale d’utilisation de PHP avec deux bases de données de technologie différente, Oracle d’une part, et MySQL d’autre part.

      $lk = mysql_connect($Host,$User,$Passwd);
      $sql = ‘select ENAME from EMP’;
      $stmt = mysql_query($query,$lk);
      while ($ligne = mysql_fetch_assoc($stmt))
      {
      echo ‘Nom : ’ . $ligne[² ENAME² ] . ‘<BR>’;
      }
      mysql_close($lk);

      Listing 1 - pour mysql

      $lk = ociplogon($User,$Passwd,$Host);
      $sql = ‘select ENAME from EMP’;
      $stmt = ociparse($lk,$sql);
      ociexecute($stmt);
      while (ocifetchinto($stmt,&$ligne,OCI_ASSOC))
      {
      echo ‘Nom : ’ . $ligne[² ENAME² ] . ‘<BR>’;
      }
      ocilogoff($lk);

      Listing 2 - Pour Oracle 8i

Les problèmes soulevés

A la lumière des deux exemples proposés (cf. listing 1 et 2), on s’aperçoit qu’une grande partie du code est intimement lié au type de serveur de bases de données que l’on souhaite interroger, ce qui rend l’application dépendante d’une technologie, la portabilité de celle-ci se trouvant ainsi réduite à son stricte minimum : nulle.

L'interface

Au vue des problèmes soulevés, la nécessité de développer une interface entre l’application et le SGBD s’impose, cette interface rendra le code de l’application indépendant du choix du SGBD, l’interface assurant une traduction auprès du SGBD cible.

Comparatif Mysql / Oracle

Voici un tableau comparatif des fonctions de bases disponibles sous PHP 4.1.2 pour Mysql 3.22.32 et Oracle 8i :

      Descriptif

      Fonctions MySQL

      Fonctions Oracle 8i

      Ouvre une connexion persistante sur le serveur.

      resource mysql_pconnect
      ([string hostname [:port] [:/path/to/socket]
      [, string username[, string password]]])

      resource ociplogon(string username, string password [, string db])

      Ouvre une connexion sur le serveur.

      resource mysql_connect([string hostname [:port] [:/path/to/socket][, string username [, string password]]])

      resource ocilogon(string username,string password [, string db])

      Sélectionne une base de donnée

      int mysql_select_db(string database_name ,resource link_identifier])

      -

      Analyse une requête,

       

      int ociparse (ocifreedesc conn, string query) 

      Exécute la requête.

      resource mysql_query(string query [, resource link_identifier])

      int ociexecute(resource statement [, int mode])

      Valide toutes les transactions en cours sur la connexion Oracle connection

      Note : Le support des transactions n’est fourni qu’avec certaines versions de Mysql dont nous ne disposions pas lors de cette étude.

      Dans le cas d’une modif de maj/insert :
      int ocicommit (resource connection)

      Lit une ligne de résultat et la place dans un tableau associatif.

      array mysql_fetch_assoc (resource result_identifier)

      int ocifetchinto (resource stmt, array &result [, int mode])
      Note : mettre mode à OCI_ASSOC (Retourne un tableau associatif)

      Libère toutes les ressources occupées par une commande.

      int mysql_free_result (resource result_identifier)

      int ocifreestatement (resource stmt)

      Ferme la connexion.

      int mysql_close(resource connection)

      int ocilogoff(resource connection)

     

Implémentation de l’interface

L’élaboration de l’interface a été réalisée en regroupant les fonctions de bases proposées par PHP pour chaque SGBD. En effet certaines fonctions ont été regroupé car elles sont utilisées conjointement au sein de l’application, ce qui est le cas la plupart du temps. Le tableau suivant rend compte du regroupement effectué et propose la liste des fonctions mises en œuvre dans l’interface.  

      Descriptifs

      Fonctions de l’interface

      Fonctions MySQL

      Fonctions Oracle 8i

      Ouvrir une connexion persistante sur le serveur.

      Ressource db_pconnect (String hostname, String username,String password,String base)
      Note : base doit être fixé à null pour Oracle

      resource mysql_pconnect ([string hostname [:port] [:/path/to/socket] [, string username [, string password]]])

      resource ociplogon(string username, string password [, string db])

      int mysql_select_db(string database_name [,resource link_identifier])

      Ouvrir une connexion sur le serveur.

      Ressource db_connect (String hostname, String user, String password, String base)

      Note : base doit être fixé à null pour Oracle

      resource mysql_connect ([string hostname [:port] [:/path/to/socket] [, string username [, string password]]])

      resource ocilogon (string username, string password [, string db])

      int mysql_select_db(

      string database_name [,resource link_identifier])

      Exécuter de la requête, retourner le résultat

      resource db_query (String query , resource link_identifier)

      resource mysql_query (string query , resource link_identifier)

      int ociparse (ocifreedesc conn,string query)

      int ociexecute(resource statement [, int mode])

      Dans le cas d’une modif de maj/insert : int ocicommit (resource connection)

      Récupérer le résultat et le placer dans un tableau à deux dimensions

      Int db_fetch_assoc(Resource result_identifier/stmt,array result)

      array mysql_fetch_assoc (resource result_identifier)

      int ocifetchinto(resource stmt, array &result[, int mode])
      Note :mettre mode à OCI_ASSOC (Retourne un tableau associatif)

      Retourner les enregistrement compris entre $debut et $fin

      Ressource db_query_limit ($sql,$id_connec, int $debut,int $fin);

      Pas de fonction proposée par PHP.
      Note : $debut n’est pas pris en compte sous Oracle (cf 3.5 les limites de l’interface)

      Libérer toutes les ressources occupées par resultat.

      db_free_result(Resource result_identifier/stmt)

      int mysql_free_result (resource result_identifier)

      int ocifreestatement (resource stmt)

      Fermer la connexion.

      db_logoff (resource id_conexion)

      int mysql_close (resource connection)

      int ocilogoff (resource connection)


Complément d’information concernant les tableaux multidimensionnels retournés par la fonction db_fetch_assoc()La fonctions db_fetch_assoc() retourne un tableau à deux dimensions qui se présente comme suit :

      Deuxième dimension du tableau : Clés du tableau associatif
      Première dimension du tableau : numéro de la ligne retourné par db_fetch_assoc() Titre Description

      0 Titre 1 Desc 1

      1 Titre 2 Desc 2

    Remarque : Les clés du tableau associatif correspondent aux noms des champs récupérés issus de la requête. Important : les clés du tableau associatif doivent être référencées en majuscule.
    Exemple :

      … Echo $row[0][TITRE]; //retourne titre 1 …

     

Organisation de l’interface du point de vue fichier

L’interface se compose de deux fichiers, le fichier de configuration " config.inc.php " d’une part, et le fichier réalisant l’interface d’autre part portant le nom type " interface_$database.inc.php ", ce dernier pouvant prendre plusieurs formes selon le type de SGBD choisie dans le fichier de configuration renseigné dans la variable $database. Par exemple, pour pour Oracle 8i, il se nommera " interface_oci8.inc.php ".

      Fichier

      Emplacement

      Description

      config.inc.php

      /topn/includes/

      Fichier de configuration

      Interface_$database.inc.php

      /topn/includes/interfaces/

      L’interface proprement dite, enssemble de fonctions

     

Utilisation de l’interface

Il n’y a qu’un seul fichier à inclure dans tous les scripts souhaitant communiquer avec un serveur de base de donnée au travers de l’interface, le fichier " config.inc.php " (cf. annexe 1). Ce dernier contient l’ensemble des paramètres de configuration nécessaires à l’application " topn ", comme les paramètres de connexion au serveur de base de donnée (login, password, serveur hôte) ainsi que le type de base de donnée choisie renseignée dans la variable " $database ". Mysql et Oracle 8i sont les seuls SGBD supportés actuellement.

Les limites de l’interface

Connections à deux types de bases différentes
La connexion à deux types de SGBDs de technologies différentes (Mysql et Oracle par exemple) est impossible. Cela est inhérent à l’architecture même de l’interface. En effet, l’interface fonctionnant selon le principe d’inclusion d’un fichier, selon que l’on souhaite utiliser tel ou tel SGBD, il n’est pas possible d’inclure dans un même script deux fichier " interface_$database.inc.php ", les fonctions déclarées dans ces différents fichiers étant les même.

L’écriture de requêtes SQL portables
La plupart des éditeurs de SGBDs fournissent des systèmes plus ou moins fermés. La meilleur façon de faire mieux et plus vite étant d’implémenter des extensions propriétaires à SQL. Cela rend assez difficile l’écriture d’un code SQL portable et fonctionnant sur toutes les plates-formes.

Database SQL Syntax
DB2 select * from table fetch first 10 rows only
Informix select first 10 * from table
Microsoft SQL Server and Access select top 10 * from table
MySQL and PostgreSQL select * from table limit 10
Oracle select * from (select * from table) where rownum <= 10

L’interface propose cette possibilité grâce à la fonction db_query_limit($query,$id_connexion,$debut,$fin) qui ne récupèrent que les enregistrements compris entre $debut et $fin de la requête $query. Il est à noter que le paramètre $debut n’est pas pris en compte dans le cas de l’utilisation d’une base Oracle et qu’il doit être fixé à null.

$sql="select * from top"; $stmt=db_query_limit($sql,$id_connec,0,10); //pour Oracle $debut est mis à null : //$stmt=db_query_limit($sql,$id_connec,null,10); $nbligne = db_fetch_assoc($stmt,&$row); $i = 0; while ($row[$i]) { echo "<br><br><br>TITRE <=> ".$row[$i][TITRE]; $i++; }

Utilisation de la fonction db_query_limit(). Lorsque vous créer des enregistrements, vous avez besoin de générer un identifiant unique pour chaque enregistrement. Il est à noter que sous certains SGBD comme MySQL, cela peut-être gérée en ajoutant l’attribut auto-increment sur la clé primaire, mais beaucoup d’autre bases de données ne le supportent pas, ce qui est le cas d’Oracle notamment. Vous veillerez donc dans le cas d’Oracle à ne pas utiliser auto-increment lors de l’appel de la fonction db_query() pour la création de tables, d’autant que cela peut facilement être contourné comme suit :

 
$sqlmax = SELECT max(categnum) AS MAXCATEGNUM FROM categ ;
$stmt = db_query($sqlmax,$connec);
$nbcat = db_fetch_assoc($stmt,&$row);
$maxtopnum = $row[0][MAXTOPNUM]+1 ;
$sqlinsert = "INSERT INTO categ VALUES('".$Max."', 'titre_categorie', 'description_categorie' ; $stmt = db_query($sqlinsert,$connec);

  Elles doivent être formatées dans un format compréhensible par la base de donnée cible, de nombreuses fonctions sous PHP sont disponibles à cette effet.
(c) 2002- 2006 Didier Deléglise


modifié
le 20/11/2006

Ecrire a DD
ecris
moi


les forums techniques Oracle

mon BLOG Oracle,
en Francais
connaitre DD
l'autre vie
de DD

mon CV

trucs
et astuces

JOBs Oracle
du jour
Homepage "Tout sur Oracle"
Mon site :
Tout sur Oracle (et le web)
Copyright (C) 2002
Utilisation de ces documents