Mac OS X Snow Leopard: PHP 5.3 + OCI8

Il sottoscritto, come altre migliaia di persone che lavorano nell’ambito IT, ha fatto un voto a Apple consacrandolo come proprio compagno di lavoro inseparabile, mi riferisco in particolar modo a Mac OS X. Il mio MacBook Pro e prima ancora il mio PowerBook G4 e quì mi fermo, sono stati e sono sempre con me, non solo per scrivere documentazione, leggere e inviare email, ma soprattuto quando si tratta di creare software.

Attraverso un percorso “Step By Step” e non troppo articolato, arriveremo alla fine del viaggio soddisfatti di essere nelle condizioni di porter sviluppare il nostro software scritto in PHP (5.x) e con il supporto del modulo OCI8 per l’accesso a RDBMS Oracle. La nostra piattaforma di riferimento è la seguente:

  • Mac OS X Leopard (10.5.x) o Snow Leopard (10.6)
  • Apache 2.2
  • PHP 5.3

Mac OS X, sia Leopard sia Snow Leopard, montano di serie Apache e PHP, vedremo questi due componenti più avanti, nella fase di configurazione. I componenti software da installare e configurare sono:

  • Oracle 10g R2 (10.2.0.4) o Oracle Instant Client Basic + SDK 10.2.0.4
  • Modulo PECL OCI8 1.3.5

1. Installazione di Oracle 1og R2 o Oracle Instant Client

L’installazione del modulo OCI8 per PHP richiede le librerie Oracle OCI, è necessario quindi procedere con l’installazione di Oracle 10g R2 o Oracle Instant Client Basic + SDK. A questo punto abbiamo a disposizione due possibili strade che possiamo seguire, a meno che non desiderate installare proprio il data base Oracle, consiglio l’installazione dell’Oracle Instant Client. In questo articolo faremo a meno d’illustrare il procedimento d’installazione per l’uno o per l’altro componente, rimandiamo la responsabilità ai seguenti riferimenti:

2. Installazione modulo OCI8

L’ultima versione stabile delle OCI8 è la 1.3.5 e disponibile per il download direttamente dal repository PECL . In genere l’installazione dei moduli PHP attraverso il comando pecl può avenire in due modalità, online o offline. Per l’installazione offline, i sorgenti del modulo OCI8 sono disponibili all’indirizzo http://pecl.php.net/get/oci8-1.3.5.tgz.
Avviamo il nostro amato Terminal e iniziamo il percorso. Onde evitare di ricevere errori in fase di configure o compilazione, dedichiamo un attimo alla verifica delle variabili di ambiente di Oracle, dal nostro Terminal basta il comando:

env | grep -E "(ORACLE)|(DYLD)"

Le nostre principali environment d’interesse sono:

  • ORACLE_HOME (esempio: /u01/app/oracle/product/10.2.0/db_1)
  • DYLD_LIBRARY_PATH (esempio: /u01/app/oracle/product/10.2.0/db_1/lib:/u01/app/oracle/product/10.2.0/db_1/rdbms/lib)

Nel caso in cui qualcuno di voi abbia installato l’Oracle Instant Client e non intende ricevere un errore in fase di configure, occorre creare un link simbolico, in questo modo (il comando deve essere eseguito dalla directory d’installazione dell’Oracle Instant Client):

ln -s libclntsh.dylib.10.1 libclntsh.dylib

A questo punto siamo pronti per effettuare l’installazione del modulo OCI8 utilizzando il comando pecl :

pecl install oci8 (modalità d'installazione online)
pecl install oci8-1.3.5.tgz (modalità offline)

Dato che il comando comando pecl installa dei file di “sistema”, dobbiamo comunque esegurilo con i diritti di root, potremmo per esempio utilizzare il comando sudo.
L’installazione del modulo OCI8 genera il file oci8.so posizionandolo in /usr/lib/php/extensions/no-debug-non-zts-20090626/oci8.so. A questo punto non resta altro che procedere con l’attivazione del modulo OCI8.

3. Attivazione modulo OCI8 e verifica

Passato lo step d’installazione, il modulo non è ancora attivo e quanto meno caricato all’interno del motore PHP. L’attivazione del modulo OCI8 comporta la modifica del file di configurazione di PHP, aggiungendo la direttiva:

extension=oci8.so

Questa direttiva deve essere aggiunta al file php.ini, si trova in /etc/php.ini. Per la modifica al file occorre avere i diritti di root, al solito utilizziamo il comando sudo:

sudo vi /etc/php.ini

Salvata la nuova configurazione di PHP è possibile verifcare il corretto load del modulo OCI8 eseguendo il comando:

php -i|grep -E -i "(oci8)"

Se tutto va come deve, dovremmo ricevere un output del tipo:

OCI8 Support => enabled
oci8.connection_class => no value => no value
oci8.default_prefetch => 100 => 100
oci8.events => Off => Off
oci8.max_persistent => -1 => -1
oci8.old_oci_close_semantics => Off => Off
oci8.persistent_timeout => -1 => -1
oci8.ping_interval => 60 => 60
oci8.privileged_connect => Off => Off
oci8.statement_cache_size => 20 => 20

Non sempre le cose vanno per il verso giusto, è probabile che il comando visto in precedenza restituisca un errore del tipo illustrato più in avanti. Questo tipo di errore, indica che PHP non è riuscito a caricare il modulo OCI8 in quanto non riesce a trovare delle librerie dipendenti. La risoluzione del problema è abbastanza semplice, occore verificare che librerie Oracle abbiano impostati i corretti permessi di accesso, ovvero, deve essere consentito l’accesso in lettura/esecuzione anche a tutti gli altri utenti (esempio: -rwxr-xr-x 1 oracle oinstall 25491240 26 Ott 21:23 /u01/app/oracle/product/10.2.0/db_1/lib/libclntsh.dylib.10.1).

PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php/extensions/no-debug-non-zts-20090626/oci8.so' -
dlopen(/usr/lib/php/extensions/no-debug-non-zts-20090626/oci8.so, 9): Library not loaded: /u01/app/oracle/product/10.2.0/db_1/lib/libclntsh.dylib.10.1
Referenced from: /usr/lib/php/extensions/no-debug-non-zts-20090626/oci8.so
Reason: no suitable image found. Did find:
/u01/app/oracle/product/10.2.0/db_1/lib/libclntsh.dylib.10.1: stat() failed with errno=13
/u01/app/oracle/product/10.2.0/db_1/rdbms/lib/libclntsh.dylib.10.1: stat() failed with errno=13
/u01/app/oracle/product/10.2.0/db_1/lib/libclntsh.dylib.10.1: stat() failed with errno=13 in Unknown on line 0

4. Configurazione Apache

Il modulo OCI8, come abbiamo avuto modo di vedere, necessita di almeno due variabili di ambiente settate correttamente. Senza apportare nessuna modifica alla configurazione attuale di Apache, rischiamo di ottenere un fallimento al successivo riavvio del servizio Apache, il motivo potrebbe essere senza dubbio quello evindenziato dal file di log (/var/log/apache2/error_log) di Apache, riportiamo un breve estratto.

PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php/extensions/no-debug-non-zts-20090626/oci8.so' -
dlopen(/usr/lib/php/extensions/no-debug-non-zts-20090626/oci8.so, 9): Library not loaded: /b/227/rdbms/lib/libclntsh.dylib.10.1n
Referenced from: /usr/lib/php/extensions/no-debug-non-zts-20090626/oci8.son Reason: image not found in Unknown on line 0

In Mac OS X dalla versione 10.4 (Tiger), Apple ha introdotto un nuovo sistema per l’avvio dei servizi base, questo sistema si chiama Launchd. Apache è quindi governato da questo componente, che per motivi di sicurezza azzera le varibili di ambiente allo stretto indispensabile, motivo per cui il modulo OCI8 fallisce il caricamento, le variabili di ambiente Oracle non sono visibili al processo Apache.
Bisogna quindi istruire Launchd affinche il processo Apache sia messo nelle condizioni di poter accedere alle variabili di ambiente Oracle necessarie al modulo OCI8. La configurazione di Launchd, o meglio, del processo da gestire, avviene per mezzo di un file di tipo plist, mentre il file /etc/launchd.conf contiene delle direttive (esempio: comandi per il set di variabili di ambiente) per Launchd.

Il nostro obiettivo è quindi quello di aggiungere le variabili di ambiente Oracle al servizio Apache. Riassumiamo quali sono le variabili di ambiente:

  • DYLD_LIBRARY_PATH
  • ORACLE_HOME
  • ORACLE_SID
  • TNS_ADMIN

Sul file di configurazione /etc/launchd.conf aggiungiamo le seguenti direttive:


setenv TNS_ADMIN /u01/app/oracle/product/10.2.0/db_1/network/admin
setenv ORACLE_SID SHIRUS
setenv ORACLE_HOME /u01/app/oracle/product/10.2.0/db_1
setenv DYLD_LIBRARY_PATH /u01/app/oracle/product/10.2.0/db_1/lib:/u01/app/oracle/product/10.2.0/db_1/rdbms/lib

Con le direttive appena inserite, abbiamo fatto in modo che Launchd metta a disposizione le variabili di ambiente Oracle ai processi da esso controllati. I path indicati devono essere ovviamente adeguati in base alla propria installazione. Per il processo di Apache è indispensabile la sola direttiva che imposta la variabile di ambiente DYLD_LIBRARY_PATH, neccessaria per “reperire” le librerie di dipendenze del modulo OCI8.

A questo punto passiamo al raffinamento della configurazione di Apache, facciamo ciò, agendo su due file di configurazione:

  • /System/Library/LaunchDaemons/org.apache.httpd.plist: PList file di configurazione per il processo Apache via Launchd
  • /etc/apache2/httpd.conf: File di configurazione del servizio Apache

Apache consente di impostare delle definizioni attraverso il parametro o flag -D in input al file di processo /usr/sbin/httpd, utilizzeremo questa caratteristica per definire un nome ORACLE, e su questa definizione impostare una determinata configurazione. Come primo passo dobbiamo aggiungere il flag -D ORACLE come argomento di /usr/sbin/httpd e in seguito, aggiungere la configurazione (su /etc/apache2/httpd.conf) per la definizione ORACLE.
Sul file PList del processo Apache devono essere aggiunti i seguenti elementi:

<string>-D</string>
<string>ORACLE</string>

Il file completo è invece:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Disabled</key>
<true/>
<key>Label</key>
<string>org.apache.httpd</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/httpd</string>
<string>-D</string>
<string>FOREGROUND</string>
<string>-D</string>
<string>ORACLE</string>

</array>
<key>OnDemand</key>
<false/>
<key>SHAuthorizationRight</key>
<string>system.preferences</string>
</dict>
</plist>

Sul file /etc/apache2/httpd.con deve essere aggiunto il seguente blocco di configurazione:

##

Check if setting Oracle env

##
<IfDefine ORACLE>

SetEnv TNS_ADMIN /u01/app/oracle/product/10.2.0/db_1/network/admin
SetEnv DYLD_LIBRARY_PATH /u01/app/oracle/product/10.2.0/db_1/lib:/u01/app/oracle/product/10.2.0/db_1/rdbms/lib
SetEnv ORACLE_BASE /u01/app/oracle
SetEnv ORACLE_SID SHIRUS
SetEnv ORACLE_HOME /u01/app/oracle/product/10.2.0/db_1
</IfDefine>

La sezione <IfDefine ORACLE>…</IfDefine> è utilizzata per marcare le direttive che sono condizionate. Le direttive SetEnv sono processate se e solo se la definizione indicata è vera (esempio: httpd -DORACLE), in caso contrario le direttive all’interno della sezione vengono ignorate. La direttiva SetEnv imposta una variabile di ambiente che viene poi trasmessa o resa disponibile agli script CGI, SSI, PHP, etc… Uno script PHP che utilizza la funzione oci_connect(), utilizza la variabile di ambiente ORACLE_SID per determinare il nome dell’istanza Oracle a cui connettersi.

Siamo praticamente arrivati alla fine, per verificare che la configurazione applicata al servizio Apache funzioni, dobbiamo riavviare il servizio. E’ possibile utilizzare, Preferenze di Sistema -> Condivisione -> Condivisione Web per eseguire un stop e un successivo start di Apache, altrimenti, sempre dal nostro amato Terminal, lanciare il comando:

apachectl restart

La verifica che il modulo OCI8 e le variabili di ambiente correttamente caricate dal processo Apache, può essere fatta attraverso un banale script PHP con all’interno l’istruzione phpinfo(). Posizioniamo lo script PHP in /Users/$vostra_username$/Sites e facciamo puntare il browser (Safari, Firefox o perchè no curl) all’indirizzo http://localhost/~$vostra_username$/phpinfo.php, in questo modo verifichiamo la presenza delle seguenti sezioni:

Apache Environment

Variable Value
DYLD_LIBRARY_PATH /u01/app/oracle/product/10.2.0/db_1/lib:/u01/app/oracle/product/10.2.0/db_1/rdbms/lib
ORACLE_BASE /u01/app/oracle
ORACLE_SID SHIRUS
ORACLE_HOME /u01/app/oracle/product/10.2.0/db_1

OCI8

OCI8 Support enabled
Version 1.3.5
Revision $Revision: 1.269.2.16.2.38.2.32 $
Active Persistent Connections 0
Active Connections 0
Oracle Version no value
Compile-time ORACLE_HOME /u01/app/oracle/product/10.2.0/db_1
Libraries Used -Wl,-rpath,/u01/app/oracle/product/10.2.0/db_1/lib -L/u01/app/oracle/product/10.2.0/db_1/lib -lclntsh
Temporary Lob support enabled
Collections support enabled

5. Nuove caratteristiche del modulo OCI8

Nella major release 1.3 sono state introdotte parecchie novità con l’intento di fruttare al meglio le funzionalità avanzate di Oracle. Le novità in questione sono:

  • Supporto per il Fast Application Notification (FAN)
  • Supporto per il Database Resident Connection Pooling (DRCP)

Solo per introdurre i due argomenti riguardo FAN e DRCP non basterebbe un solo articolo, cercherò di fare una breve overview sulle due caratteristiche.
Con il FAN si evita che uno script PHP rimanga bloccato in attesa di una risposta (fin quando arriva un TCP Timeout expires) da parte di una istanza del server Oracle bloccata.  Attraverso un sistema di notifiche lo script PHP non va in time out ma può richiedere una nuova connessione in modo trasparente per l’utente che utilizza l’applicazione. Affinché l’applicazione PHP possa ricevere eventi FAN, il parametro di configurazione oci8.events del modulo OCI8 deve essere impostato in questo modo:

oci8.events = On

Il supporto FAN è disponibile solo se il modulo OCI8 è stato compilato con le librerie Oracle Database 10g Release 2 o 11g e connessione a Oracle Database 10g Release 2 o 11g.

Invece, attraverso il DRCP è possibile creare un pool di connessioni al database da assegnare agli script che ne fanno richiesta. In questo modo viene ridotto l’overhead generato dal processo di connessione garantendo maggiore scalabilità all’applicazione.

Prima di utilizzare DRCP, il parametro di configurazione oci8.connection_class dovrebbe essere impostato per specificare la classe di connessione utilizzata da tutte le richieste per i server in pool con l’applicazione PHP.

oci8.connection_class = MYPHPAPP

La modifica dei parametri di configurazione del modulo OCI8 può essere eseguita sul file di configurazione di PHP (/etc/php.ini), per particolari esigenze è possibile utilizzare le funzioni PHP ini_set() e ini_get().

L’applicazione PHP deve indicare sulla stringa di connessione al data base Oracle che il tipo di server è POOLED. A seguire due esempi di connessioni, il primo utilizza la sintassi Oracle’s Easy Connect, il secondo utilizza il network name così come specificato sulla configurazione Oracle Network (vedi tnsnames.ora)

$c = oci_pconnect('myuser', 'mypassword', 'myhost/sales:POOLED');

$c = oci_pconnect(‘myuser’, ‘mypassword’, ‘salespool’);

Subito sotto l’estratto dal file tnsnames.ora per il network name salespool

salespool=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)
(HOST=myhost.dom.com)
(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=sales)
(SERVER=POOLED)))

Il supporto DRCP è disponibile solo se il modulo OCI8 è stato compilato con le librerie  Oracle Database 11g e connessione a Oracle Database 11g.

Per maggiori approfondimenti sull’argomento consiglio di partire con la visione del sito PHP Developer Center on Oracle Technology Network (OTN) raggiungibile all’indirizzo http://www.oracle.com/technology/tech/php/index.html.

5. Conclusioni

E’ probabile che qualcuno di voi alla fine di tutto si aspettava un esempio di connessione al db Oracle, prometto che a breve mi rifarò con un altro articolo dedicato a questo aspetto, aggiungendo però un qualcosa d’interessante: Oracle XMLQuery e SimpleXML.
Con questo breve articolo abbiamo visto come sia possibile e semplice fare della nostra Mela un ambiente adatto ad ogni tipo di situazione ed esigenza.

Antonio Musarra

I began my journey into the world of computing from an Olivetti M24 PC (http://it.wikipedia.org/wiki/Olivetti_M24) bought by my father for his work. Day after day, quickly taking control until … Now doing business consulting for projects in the enterprise application development using web-oriented technologies such as J2EE, Web Services, ESB, TIBCO, PHP.

You may also like...

  • Pingback: Mac OS X Snow Leopard: PHP 5.3 + OCI8 | BNotizie Magazine()

  • Celso Coutinho

    Have you already translated this? I read in the oracle foruns that you would do so!

    I tried everything that’s on the web about this matter, and my last hope relies on your site…

    Greetings from Portugal!

  • Andrea

    Passato a Snow Leopard, mi ritrovo con PHP 5.3 e milioni di warnings che gremiscono il mio sito!!!
    Aiuto!

    • http://musarra.wordpress.com Antonio Musarra

      Ciao Andrea, non è stata una buona idea migrate al nuovo Mac OS X, in particolar modo quando quando
      usato in ambienti di produzione. La versione PHP 5.3 introduce parecchie novità che possono create problemi a applicazioni e/o siti che prima funzionavano correttamente.

      Che tipo di warning ricevi ? Forse è possibile rendere la versione 5.3 in modalità compatibile alla versione precedente.

      Ti posso consigliare di fare un downgrade alla versione precedente di PHP se le nuove funzionalità introdotte con la versione 5.3 di PHP non ti
      servono.

      Bye,
      Antonio.

  • Vlad from .ru

    Thanx a lot Antonio!
    I was almost throwing away my new macbook. Every other blog, even Oracle’s recommend recompile ALL php, apache and the staff.

    Your solution is the best!!!

    • http://musarra.wordpress.com Antonio Musarra

      Hi,
      Thank you very much for the appreciation of my article. I am happy that your MacBook is safe!
      Merry Christmas and Happy New Year.

      Bye,
      Antonio.

  • Pingback: 2010 in review | Antonio Musarra's Blog()

  • Franki

    Hello Antonio,
    Thanks for your article.
    I have a zend server CE installed with OCI8 extension enabled that works fine! But I should connet to an Oracle 8i and thw oci_connect says that the version is no longer supported. I use the instantclient 10.2 and I have read that with this client is still possible to connect to Oracle 8i but the extension ¡must be recompiled with the client libraries. So I execute /usr/local/zend/bin/pecl install oci8 and follow your steps but without success.
    In ZendServer logs I have:
    [27-May-2011 10:29:04] PHP Warning: PHP Startup: Unable to load dynamic library ‘/usr/local/zend/lib/php_extensions/oci8.so’ – dlopen(/usr/local/zend/lib/php_extensions/oci8.so, 9): no suitable image found. Did find:
    /usr/local/zend/lib/php_extensions/oci8.so: mach-o, but wrong architecture in Unknown on line 0

    Have you ever try to recompile oci8 with zend server tools?
    Thanks

    Franki

    • http://musarra.wordpress.com Antonio Musarra

      Hi Franki,
      sorry if I answer only now, but I was on vacation.

      I have not tried to build the OCI8 module with Zend Server CE on OS X. What kind of errors you receive when you compile?

      Let me know.

      Bye,
      Antonio

      • Franki

        Hi Antonio,

        The pecl command works well. But the new compiled oci8.so fails to load.
        In the Zend Server logs: “PHP Warning: PHP Startup: Unable to load dynamic library ‘/usr/local/zend/lib/php_extensions/oci8.so’ – (null) in Unknown on line 0″

        I have use otool -L and the output is:
        oci8.so:
        /b/227/rdbms/lib/libclntsh.dylib.10.1 (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.10)

        With the oci8.so distributed with ZendServer the output is:
        oci8.so:
        /b/32_216/rdbms/lib/libclntsh.dylib.10.1 (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.1)

        • http://musarra.wordpress.com Antonio Musarra

          Hi Franki,
          The error you get is just weird. Anyway I attached the compatibility matrix oracle instant client.
          I suggest you read the post http://blog.whitehorses.nl/2010/02/19/database-version-compatibility-and-support-matrix/
          I believe that there should be an updated version of Oracle, at least to version 9.

          Bye,
          Antonio.

          Server Version
          Client Version 10.1.0 9.2.0 9.0.1 8.1.7 8.1.6 8.1.5 8.0.6 8.0.5 7.3.4
          10.1.0(#4) Yes Yes Was EMS #2 No #3 No #3 No #3 No #3 No #3
          9.2.0 Yes Yes Was EMS No No Was No No #1
          9.0.1 Was Was Was Was Was No Was No Was
          8.1.7 EMS EMS Was EMS Was Was Was Was Was
          8.1.6 No No Was Was Was Was Was Was Was
          8.1.5 No No No Was Was Was Was Was Was
          8.0.6 No Was Was Was Was Was Was Was Was
          8.0.5 No No No Was Was Was Was Was Was
          7.3.4 No Was Was Was Was Was Was Was Was

          Yes Supported
          EMS Supported for customers under Extended Maintenance (EMS) only.
          Was Was a supported combination but one of the releases is no longer
          covered by Primary Error Correct support or Extended Maintenance Support
          so fixes are no longer possible.
          No Has never been Supported

          #1 - See
          #2 - An ORA-3134 error is incorrectly reported if a 10.1.0.2 client tries
          to connect to an 8.1.7.3 or lower server. See .
          #3 - An ORA-3134 error is correctly reported when attempting to connect to this version.
          #4 - There are problems connecting from a 10g client to 8i/9i
          where one is EBCDIC based. See