I. Prérequis et configuration

Pour accéder à une base de données Oracle, il y a en PHP les « vieilles » fonctions (qui commencent par ora_) et les nouvelles : les OCI (Oracle Call Interface) à partir de Oracle 8i (8.1.5).

L'interface OCI peut être utilisée avec beaucoup de langages de programmation par exemple en Pro_Cobol ou en Pro_C.

Si vous programmez en PHP3 ou avec Oracle < 8i, seules les fonctions ora_ sont accessibles.

Il se peut aussi que le script de configuration de PHP ne détecte pas la bonne version d'Oracle (à cause du changement de nom du répertoire orainst…). C'est ce qui s'est produit pour moi. Oracle 8.1.7 était détecté en version 7.3 par PHP.

Donc, pour une question de compatibilité avec Oracle 7 et PHP3, les codes de ce tutorial utilisent les fonctions ora_, d'autant plus que les fonctions ora_ sont supportées par les versions récentes d'Oracle.

Oracle fonctionne en client/serveur, c'est-à-dire qu'un serveur contient les données et que tous les ordinateurs de l'entreprise possèdent la version « client » : les utilitaires tels que SQL*Plus (pour faire des requêtes).

Le serveur web Apache est installé sur une machine possédant le client.

I-A. Configuration sous Linux

Pour connaître plus de détails sur l'installation d'Apache et PHP, vous pouvez jeter un œil à l'excellent tutorial d'Olivier Népomiachty.

I-A-1. Utilisateurs et variables d'environnement

Oracle utilise des « variables d'environnement ». Il peut se poser des problèmes d'utilisateurs.

Sur une machine on va trouver par exemple :

  • root, le maître de la machine qui possède tous les droits ;
  • oracle, l'utilisateur qui a installé la base Oracle et qui est y accède ;
  • apache, un utilisateur qui a souvent des droits plus limités, puisque c'est le serveur web.

Lorsqu'on appelle un page web de cette machine, c'est le serveur Apache qui nous répond, et il travaille sous le nom d'utilisateur « apache ».

Or notre objectif est qu'Apache (et plus particulièrement le module PHP) accède à Oracle. Mais l'utilisateur qui accède à Oracle est oracle.

On résout le problème en créant des variables d'environnement pour l'utilisateur apache.

Les variables suivantes sont à ajouter dans le fichier .bashrc. Pour prendre les valeurs exactes, cherchez ces variables dans le .bashrc de l'utilisateur oracle.

 
Sélectionnez
#----------------------------------------
#Variables pour Oracle
#----------------------------------------
export ORACLE_BASE=/home/oracle/app/oracle
export ORACLE_HOME=$ORACLE_BASE/product/8.1.7
export ORACLE_DOC=$ORACLE_HOME/odoc
export PATH=$ORACLE_HOME/bin:/home/oracle/outil:$PATH
export NLS_LANG=FRENCH_FRANCE.WE8ISO8859P1
export NLS_DATE_FORMAT=dd/mm/yyyy_hh24:mi:ss
export NLS_SORT=BINARY
export NLS_NUMERIC_CHARACTERS=".,"

Grâce à ces variables d'environnement, l'utilisateur apache peut se connecter à la base et donc les pages PHP y faisant appel fonctionnent.

I-A-2. Compilation Apache et PHP

Olivier Népomiachty a très bien expliqué cette étape dans son tutorial.

Je vous conseille d'y jeter un œil même si je reprends les lignes essentielles ici.

I-A-2-a. Installation apache simple

Pour de la documentation et pour télécharger Apache, visitez sur http://httpd.apache.org/.

Téléchargez dans le répertoire /usr/local/, décompressez-le tar.gz dans un répertoire que vous renommerez apache.

Dans un shell, placez-vous dans le répertoire /usr/local/apache.

Tapez successivement les lignes suivantes :

Installation d'Apache sans paramètres
Sélectionnez
cd /usr/local/apache 
./configure --prefix=/usr/local/apache 
make 
make install

Maintenant lancez le démon Apache :

Lancer le démon Apache
Sélectionnez
/usr/local/apache/bin/apachectl start

Et connectez-vous à http://IP_DE_LA_MACHINE/. Si vous obtenez un résultat semblable à l'image ci-dessous, Apache fonctionne :-)

Image non disponible

Pour continuer on arrête le démon Apache.

Arrêter le démon Apache
Sélectionnez
/usr/local/apache/bin/apachectl stop

I-A-2-b. Installation PHP

Pour de la documentation et pour télécharger PHP, tout se trouve sur le site sur http://fr.php.net/.

Téléchargez dans le répertoire /usr/local/, décompressez-le tar.gz dans un répertoire que vous renommerez php.

Installation de PHP
Sélectionnez
cd /usr/local/php
./configure --with-oracle=$ORACLE_HOME \
            --with-oci8=$ORACLE_HOME \
            --with-config-file=/usr/local/apache/conf \
            --with-apache=/usr/local/apache \
            --enable-track-vars
make
make install

Le « ./configure » est une seule commande, les \ (backslash) en fin de ligne permettent d'aller à la ligne pour rendre le code plus lisible. Si vous n'êtes pas sûr, enlever les \ et les retours à la ligne, la commande marchera.

Notez bien les paramètres --with-oracle et -with-oci8.

Pour ce tutorial, seul le paramètre --with-oracle est utile vu que je ne parlerai pas des fonctions OCI.

I-A-2-c. Recompilation d'Apache

Maintenant nous allons dire à Apache de supporter le PHP.

Recompilation d'Apache pour supporter PHP
Sélectionnez
cd /usr/local/apache
./configure --activate-module=src/modules/php4/libphp4.a \
            --enable-module=so
make
make install

Pour d'autres options intéressantes, reportez-vous au cours d'Olivier Népomiachty.

I-B. 1.2. Configuration sous Windows

Sous Windows c'est plus simple, il suffit d'enlever le point-virgule de l'une de ces deux lignes du fichier c:\winnt\php.ini :

 
Sélectionnez
;extension=php_oci8.dll
;extension=php_oracle.dll

Maintenant il ne reste plus qu'à démarrer Apache et passer au code PHP.

II. Connexion/Déconnexion : ora_logon et ora_logoff

Documentation PHP : ora_logon - ora_logoff.

Nous allons créer deux fichiers appelés connexion.php et deconnexion.php, qui auront pour seule fonction l'ouverture et la fermeture de la connexion à la base de données.

Petit aparté à propos des connexions permanentes :

Personnellement je n'utilise pas les connexions permanentes en PHP pour les raisons suivantes :

  • une connexion permanente veut dire que la connexion n'est pas fermée pendant que l'utilisateur lit la page, et quand il demande une autre page la connexion est déjà ouverte. C'est bien, mais le serveur est vite encombré si plusieurs utilisateurs surfent en même temps sur le site !
  • de même, comment savoir si le surfeur est toujours là où il est parti ? Impossible, donc on ferme arbitrairement la connexion au bout de quelques minutes…

Le système des classes de Java permet de faire des connexions permanentes, une classe instanciée au démarrage ouvre plusieurs connexions, et quand un page en a besoin, elle la prend, puis la rend.

Peut-être qu'en PHP5 on pourra faire ça ?

Aller on attaque le code :-p

Voici le fichier connexion.php :

connexion.php
Sélectionnez
<?php
// connexion.php se connecte à la base.
$ora_conn = ora_logon("NomDeLaBase@service","pass");
?>

NomDeLaBase et pass, ça ne devrait pas poser trop de problèmes ;)

Le service (ou TNS) est un nom du service utilisé par les applications « client » d'Oracle installées sur la même machine. Il est donc nécessaire de connaître ces infos (demandez ça à votre DBA Oracle).

Voici maintenant le fichier deconnexion.php qui ferme libère la connexion $ora_conn :

deconnexion.php
Sélectionnez
<?php
// Se déconnecter de la base
ora_logoff($ora_conn);
?>

En cas d'erreur ORA-12545, vérifiez les variables d'environnement, le fichier tnsnames.ora (votre DBA Oracle connais mieux ce fichier que moi !).

Dans chaque page PHP devant se connecter à la base Oracle, il faut faire un include() de connexion.php au début et un include() de déconnexion à la fin :

include() dans chaque page
Sélectionnez
<?php
include("connexion.php");
// traitement...
include("deconnexion.php");
?>

III. Requête SELECT : comment simplifier ?

Documentation PHP : ora_do - ora_numcols - ora_columnname - ora_getcolumn - ora_fetch.
Notez que ora_do est la combinaison de ora_parse, ora_exec et ora_fetch.

Faire une requête « SELECT … » sur Oracle via PHP n'est pas tout simple.

Le but est de rendre le code le plus lisible… et le requêtage plus facile à faire (gain de temps dans le développement).

Il est possible de faire un fichier inclus, appelé select.php, et qui va réaliser tout le travail, pourvu qu'on lui indique la requête.

Voici donc comment faire une requête de sélection :

Une page qui fait une requête
Sélectionnez
<?
include("connexion.php");
echo "Liste des people";
 
$query = "SELECT nom, prenom FROM people WHERE...";
include("select.php");
 
// Parcours du tableau $results pour afficher les résultats :
if (count($results)) // Si y'a des résultat
{
    reset($results); // se placer à la première ligne du tableau $results
    while($res = each($results)) // Parcourir le tableau $results
    {
        echo $res[1]["NOM"];    // nom
        echo $res[1]["PRENOM"]; // prenom
        // Attention, il faut bien mettre les noms de colonnes en MAJUSCULE
        // et entre " et "
 
        // Traitement...
        echo "<br />";
    }
}
else // Pas de résultat
{
    echo "Y'a personne";
}
 
include("deconnexion.php");
?>

Ce code est assez lisible :-)

Ça serait trop simple si ce n'était que ça… donc sans plus tarder, voici le code du fichier select.php :

select.php
Sélectionnez
<?
// Il suffit de mette en commentaire error_reporting pour faire du
// débogage - voir quand il n'y a aucun résultat "NO DATA FOUND" par exemple.
error_reporting(0);
 
// Crée un tableau, un curseur, compte les colonnes,
// fait le fetch en insérant dans le tableau.
$results = array();
// ora_do analyse (ora_parse) $query, l'exécute (ora_exec)
// et lit la première ligne du résultat (ora_fetch).
$ora_cur = ora_do($ora_conn, $query);
 
if ($ora_cur)
{
    // Nombre de colonnes
    $numCols = ora_numcols($ora_cur);
 
    // Prends la première ligne et la met dans le tableau...
    $row = array();
    for($i=0; $i<$numCols; $i++)
    {
        // Parcours des colonnes
        $row[ora_columnname($ora_cur, $i)] = ora_getcolumn($ora_cur, $i);
    }
    array_push($results, $row);
 
    // "Fetch" des lignes, une par une, en créant un tableau pour chaque ligne.
    // Chaque tableau est inséré à la suite du tableau $results.
    while (ora_fetch($ora_cur))
    {
        // Pour chaque ligne
        $row = array();
        for($i=0; $i<$numCols; $i++)
        {
            // Chaque colonne
            $row[ora_columnname($ora_cur, $i)] = ora_getcolumn($ora_cur, $i);
        }
        array_push($results, $row);
    }
}
 
// Le fameux error_reporting. Mettre en commentaire pour voir les no data found.
error_reporting(1);
?>

Pour comprendre comment afficher les résultats, l'array $result ressemble à :

rang champs rapportés par la requête, sous forme d'un tableau
1 array("NOM" => "Machefert", "PRENOM" => "Sylvain")
2 array("NOM" => "Brubeck", "PRENOM" => "Dave")
3 array("NOM" => "Desmond", "PRENOM" => "Paul")

… ou si vous préférez, un print_r($results) donne à peu près ceci :

print_r($results)
Sélectionnez
array(
 0 => array(
      "NOM" => "Machefert",
      "PRENOM" => "Sylvain"),
 1 => array(
      "NOM" => "Brubeck",
      "PRENOM" => "Dave"),
 2 => array(
      "NOM" => "Desmond",
      "PRENOM" => "Paul")
)

L'instruction while($res = each($results)) parcours ligne par ligne l'array $results. La variable $res équivaut à une ligne du tableau ci-dessus.

Donc $res[0] contient le numéro du rang qui a peu d'importance, et $res[1] contient un array…

D'où les echo $res[1]['NOM_DE_LA_COLONNE']

IV. Autres requêtes (UPDATE, INSERT, DELETE…)

Documentation PHP : ora_open - ora_parse - ora_exec - ora_commit - ora_close.

On a fait le plus dur :-) Voici donc maintenant des choses plus simples :

Requêtes UPDATE, INSERT, DELETE
Sélectionnez
<?
include("connexion.php");
$query = "UPDATE people SET nom='O''chon' where prenom='Paul'";
 
// Les lignes suivantes peuvent être placées dans un fichier
// requete.php, et remplacées par un include("requete.php");
$curseur = ora_open($ora_conn); // Créer un curseur
if($curseur) // Si ça créé
{
    // Parse la requête = vérifie si elle est correcte syntaxiquement
    $resultat = ora_parse($curseur,$query);
    $resultat = ora_exec($curseur); // Exécute la requête
    $a = ora_commit($ora_conn); // Fait le COMMIT pour valider
    $b = ora_close($curseur); // Ferme le curseur
}
else
    echo "Oups! problem...";
// Ici s'arrêtent les lignes qui peuvent être mises dans le fichier requete.php
 
// Il ne reste plus qu'à faire un test sur $a.
if ($a==false)
{
    echo "Problème...";
}
 
include("deconnexion.php");
?>

En conclusion…

J'espère que ma première contribution sur Developpez.com vous sera utile, qu'elle vous permettra de gagner du temps dans le développement PHP/Oracle.

Après avoir construit ces quelques fichiers j'ai gagné un temps considérable pour faire mes requêtes ;-).