Oracle PHP Troubleshooting FAQ

By Christopher Jones

Updated April 2006

Here are some troubleshooting hints for users of Oracle and PHP. For a general Oracle/PHP FAQ see The Oracle/PHP FAQ by Frank Naudé.

If you use PHP's oci8 extension, I strongly recommend upgrading to the re-factored version. Although first shipped with PHP 5.1.2, the new code was designed to work with PHP 4 onwards and is available as source code in PECL for use with existing PHP installations. Windows binaries for various PHP versions are at php_oci8.dll.


Topics

Oracle not installed or not found

If Oracle support is enabled in PHP, but the Oracle client libraries can not be found, you will get an error when trying to start Apache. For example on Windows if php.ini has "extension=php_oci8.dll" but the Oracle home cannot be found, an alert "The dynamic link library OCI.dll could not be found in the specified path" is displayed.

Make sure that your php.ini file is being found correctly. Create the following script "phpinfo.php" where your web server can read it and load it in a browser:

        <?php
          phpinfo();
        ?>

If the "Configuration File (php.ini) Path" line shows only a directory path and does not end with "php.ini", then your configuration file is not being read. Move your php.ini to the directory shown and restart your web server.

Make sure the Oracle environment variables are set correctly before starting web server (see the next topic).

Linux users might see an Apache error about being unable to load libclntsh.so, but are more likely to notice the problem earlier when compiling PHP. The compiler will fail with the error 'Cannot find file "ocidfn.h"' or 'Cannot find file "oci.h"'. If you have Oracle installed but are missing the Oracle header files, do a "Client" install of Oracle. In Oracle 9i download the "Oracle9i Database Release 2", run the installer and choose the "Client" option. In Oracle 10g download the "Oracle Database 10g Client Release", run the installer and choose the "Administrator" option.

The Oracle directory that PHP links with needs to be readable by the owner of the web server process. If you configure PHP to use Oracle 10gR2 libraries and Apache crashes at startup, check the directory permissions on the Oracle software. Oracle 10gR2 is shipped with a more restrictive set of directory permissions than previous Oracle releases. The 10.2.0.2 patchset contains $ORACLE_HOME/install/changePerm.sh to re-set permissions on files required by external programs like PHP. With 10.2.0.2 you may need to add the directories lib32, ldap, ldap/adminm, and srvm/lib32 to the RELAX_DIR_ALL variable in this script before running it. If you don't want to change your ORACLE_HOME permissions, consider linking PHP with Oracle Instant Client.

Also see the OTN articles Installing PHP and the Oracle 10g Instant Client for Linux and Windows, Installing Oracle, PHP, and Apache on Windows 2000/XP and Installing Oracle, PHP, and Apache on Linux.


Setting Oracle environment variables prior to starting the web server

Setting all Oracle environment variables before the web server starts is the only safe way to get PHP talking to Oracle. Setting the variables in PHP scripts or the httpd.conf file mostly does not work. There are numerous mail list and forum posts because of general confusion about the environment. The behavior on Windows and Linux also differs.

The environment needs to be set so PHP can find Oracle's libraries and message files. Environment variables may also be needed to identify the default local database, needed for locating configuration files for remote database access, or needed to set Oracle's globalization parameters correctly.

An example shell script for starting Apache is "start_apache" :

        #!/bin/sh

        ORACLE_HOME=/u01/app/oracle/product/9.2
        ORACLE_SID=orcl
        export ORACLE_HOME ORACLE_SID
        export LD_LIBRARY_PATH=${ORACLE_HOME}/lib:${LD_LIBRARY_PATH}
        echo "Oracle Home: $ORACLE_HOME"
        echo "Oracle SID:  $ORACLE_SID"
        echo Starting Apache
        #export > /tmp/envvars
        ./apachectl start

Depending where your database server is and how you connect to it you may also want to set TWO_TASK or TNS_ADMIN (see the next topic).

Apache, PHP and Oracle error messages that use phrases like "could not load" or "could not resolve" all point to environment setup problems. If you think you are seeing this, try uncommenting the "export" line in "start_apache". After the script is run, the file /tmp/envvars will contain the environment variables Apache knows about. This is useful to solve problems starting Apache at machine boot time - the environment may be very different to starting Apache in your user shell.

If Apache starts but gives errors about Oracle libraries, and/or OCI8 function calls fail, try looking at PHP's environment by using the phpinfo() script.

Triple-check the environment and path configuration. On UNIX check that LD_LIBRARY_PATH (or equivalent) contains $ORACLE_HOME/lib. On Windows the PATH variable may need to contain %ORACLE_HOME%\bin.

Some messages like the runtime "Warning: ocilogon(): _oci_open_session: OCIHandleAlloc? OCI_HTYPE_SVCCTX: OCI_INVALID_HANDLE" are also symptoms of an incorrect ORACLE_HOME.

If OCILogon() gives "ORA-12705 The NLS parameter value specified in an alter session statement is not valid or not implemented", try setting ORA_NLS33 to the NLS data file directory in the ORACLE_HOME used to compile PHP, e.g. $ORACLE_HOME/ocommon/nls/admin/data.

I did some tests to see what effect the basic environment in a standard installation had on a PHP login call:

        $mycon = OCILogon("myusername", "mypassword", "MYDB");

I used Red Hat Linux AS 2.1, Apache 1.3 and PHP 4.3.3.

  1. With no ORACLE_HOME set prior to "apachectl start" and no "putenv('ORACLE_HOME=/usr/oracle/MYDB')" in the PHP script I got:

            Warning: ocilogon(): _oci_open_server: Error while trying to retrieve text for error ORA-12154
    

    This shows the connection failed, and the message files (which are located under the Oracle home directory) could not be found. The Oracle environment is incorrect.

  2. With "putenv('ORACLE_HOME=/usr/oracle/MYDB')" in the PHP script but no ORACLE_HOME set, I got:

            Warning: ocilogon(): _oci_open_server: ORA-12154: TNS:could not resolve service name
    

    The connection still failed, but now the correct message text could be read from the message file. The Oracle environment is incorrect.

  3. With ORACLE_HOME set prior to "apachectl start" but without "putenv()" the connection succeeded. This is the recommended configuration.

  4. With ORACLE_HOME set correctly prior to "apachectl start" and with "putenv()" using an invalid ORACLE_HOME directory, the connection succeeded. I also tried this on Windows. This time the connection failed with the same message as my first test above. Don't do this.

I had a similar set of results when I replaced the PHP putenv() call with an Apache httpd.conf directive "setenv ORACLE_HOME /usr/oracle/MYDB".

Having said all this, some variables used at run time can be set in your PHP scripts. After setting ORACLE_HOME correctly before starting Apache the following code changed my default connection and connected to MYDB:

       putenv("TWO_TASK=MYDB");
       $mycon = OCILogon("myusername", "mypassword");

The environment variables TNS_ADMIN, NLS_DATE_FORMAT (and there may be others) can probably be set in scripts too.


Connecting to a database

  1. If Oracle 10g libraries are used by PHP try the new Easy Connect syntax. No long connection string is needed. No tnsnames.ora file is required. To connect to the MYDB database service running on mymachine use:

        $c = OCILogon('myusername', 'mypassword', '//mymachine.mydomain/MYDB');
    

    If you are using the free Oracle XE database on the same machine as your web server, the connection string would be:

        $c = OCILogon('myusername', 'mypassword', '//127.0.0.1/XE');
    

    The Easy Connection syntax only works if PHP is linked with Oracle 10g libraries, and works even if the database is another version. If the database server is 10g but PHP is using Oracle 8i or 9i libraries it will not work. See Oracle's Using the Easy Connect Naming Method documentation for the Easy Connect syntax.

    If you see the error "ORA-12514: TNS:listener does not currently know of service requested in connect descriptor", then the service name component is incorrect. On the database server, run

            lsnrctl services
            

    to find the service names that will be recognized.

    The ORA-12514 error may occur in the scenarios below too.

  2. A user chosen net service name is often used to identify which database to connect to. By default it is read from the environment variable ORACLE_SID or it can be explicitly given in the connection call. The net service name MYDB that is used in Oracle's command-line SQL*Plus utility like:

            sqlplus myusername/mypassword@MYDB
    

    can be used in PHP like:

            $mycon = OCILogon("myusername", "mypassword", "MYDB");
    

    The net service name is commonly mapped to an actual database by an entry in a tnsnames.ora file :

            MYDB =
              (DESCRIPTION =
                (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.mydomain)(PORT = 1521))
                (CONNECT_DATA =
                  (SERVER = DEDICATED)
                  (SERVICE_NAME = MYDB)
                )
              )
    

    The default file location is $ORACLE_HOME/network/admin/tnsnames.ora. On some operating systems other locations (e.g. ~/.tnsnames.ora) will be checked too. If your tnsnames.ora is in a non-standard location you can set the environment variable TNS_ADMIN to the directory containing it. For example if you are using /home/myuser/tnsnames.ora, add these lines to start_apache (see the previous topic):

            TNS_ADMIN=/home/myuser
            export TNS_ADMIN
    

    If the net service name used in OCILogon() cannot be found in the tnsnames.ora, or the tnsnames.ora is not found at all by PHP, you may get an error when logging in:

            Warning: ocilogon(): _oci_open_server: ORA-12154: TNS:could not resolve service name
    

    The error ORA-12154 can also occur if you have a file $ORACLE_HOME/network/admin/sqlnet.ora and it specifies a NAMES.DEFAULT_DOMAIN value. Unqualified net service names in OCILogon() calls will have sqlnet.ora's value for NAMES.DEFAULT_DOMAIN appended to the alias. For example if sqlnet.ora had:

            NAMES.DEFAULT_DOMAIN = au.oracle.com
    

    then 'OCILogon("myusername", "mypassword", "mydb")' causes Oracle to look for the alias "MYDB.AU.ORACLE.COM = . . ." in tnsnames.ora. A quick solution is to change the tnsnames.ora entry to:

            MYDB.AU.ORACLE.COM =
              (DESCRIPTION =
                (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.mydomain)(PORT = 1521))
                (CONNECT_DATA =
                  (SERVER = DEDICATED)
                  (SERVICE_NAME = MYDB)
                )
              )
    
  3. If Easy Connect has been disabled or you are using Oracle 8i or 9i libraries, another alternative is to use the full connection string:

             $db = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)
                          (HOST = mymachine.mydomain)(PORT=1521))
                          (CONNECT_DATA=(SERVER=DEDICATED)
                          (SERVICE_NAME=MYDB)))";
    
             $mycon = OCILogon("myusername", "mypassword", $db);
    

Managing Connections

Connection management was greatly improved with the re-factored oci8 driver. Many bugs were fixed and there are new php.ini options for optimizing the behavior of persistent connections. Optimizing database connections in a frequently used script can improve performance and prevent resource problems.

If you are using the original oci8 extension these tips may still apply:

  • Avoid multiple connections to Oracle in a single script.

  • If you have to make multiple connections use different tnsnames.ora aliases, even when you want to connect to the same Oracle instance with a different user. This will avoid PHP context conflicts since each connection will use a distinct TCP link to the database.

  • Using the "persistent" OCIPLogon() call minimizes the number of physical connection requests to the database. It has some limitations. If the DBA terminates the session with ALTER SYSTEM KILL SESSION or worse, terminates the Oracle shadow process with an operating system kill command, OCIPLogon() may succeed but subsequent OCI8 calls may still fail. This can be timing dependent. When reusing a persistent connection always check its validity at the start of the script with an explicit query. If you receive an Oracle error then the connection is no longer valid and you may need to logoff and login again. Some developers give the user a message asking them to retry later and call PHP's apache_child_terminate() to clean up the session.

  • Use Oracle Database Resource Manager (which replaces User Profiles) to limit the resources used by any one connection.

  • Use Oracle Net configuration parameters such as SQLNET.EXPIRE_TIME to free up unused database resources.

  • Refresh the Apache processes after they have managed a certain number of requests, depending on site load. An Apache "graceful restart" nightly will clean up connections.

[Acknowledgment: Massimo Squillace contributed significantly to this section]


Echoing SQL statements to check they are well formed

Getting no, or incorrect, results is surprisingly often due to executing the wrong statement. During development, echo each complete SQL statement from PHP to check it is well formed and all variables are correctly expanded. Quoting errors or misunderstandings with PHP's variable syntax in strings can cause incorrect statements to be executed.

Testing SQL statements in SQL*Plus before executing them in PHP also helps confirm correctness.

When statements are entered in tools like SQL*Plus, a semi-colon is often used to tell the tool that the statement is complete and can now be executed. However the semi-colon is not considered part of the statement and is not sent to the database. In PHP do not add a semi-colon to a SQL statement otherwise an Oracle error will occur. This example is a valid query:

        $sql = "SELECT * FROM EMP_DETAILS_VIEW";

Oracle's inbuilt scripting language PL/SQL has different syntax to SQL and a final semi-colon is required:

        $plsql = "BEGIN DBMS_OUTPUT.PUT_LINE('Hello, World!'); END;";

Testing return codes from database function calls

Test all return values from OCI8 functions to prevent hidden problems and misleading results.

During development set php.ini's error_reporting directive to

         error_reporting = E_ALL | E_STRICT.

Set display_errors On, or configure the error log file (and remember to check it!). This will show Oracle errors as they occur, unless you have explicitly prefixed Oracle functions calls with "@".


Inserting strings containing quotes

Inserting strings containing single quotes can be handled in several ways:

  1. Use bind variables. This also protects against "SQL Injection" security issues and can greatly improve database performance:

            $name = "O'Reilly";
            $stmt = 'INSERT INTO CUSTOMERS (NAME) VALUES (:nm)';
            $stid = OCIParse($mycon, $stmt);
            OCIBindByName($stid, ':nm', $name, -1);
            OCIExecute($stid);
    

    This is the recommended method. It is also the least likely to cause coding errors.

  2. Double every single quote:

            $name = "O'Reilly";
            $name = str_replace("'", "''", $name);
            $stmt = "INSERT INTO CUSTOMERS (NAME) VALUES ('".$name."')";
    
  3. Turn on magic_quotes_sybase in php.ini and use addslashes():

            $name = addslashes("O'Reilly");
            $stmt = "INSERT INTO CUSTOMERS (NAME) VALUES ('".$name."')";
    

    This is not recommended for portability reasons.


Fetching results using associative arrays

Oracle column names are cases insensitive by default but when fetching into associative arrays specify the names in upper case:

        $query = 'select dname from dept';

        $stid = OCIParse($conn, $query);
        OCIExecute($stid);
        while (OCIFetchInto($stid, $row, OCI_ASSOC)) {
          echo $row['DNAME']."<br>\n";
        }

If the table was created with case sensitive column names this may not be true. Use var_dump($row) to see the column names and data structure actually returned by OCIFetchInto(). PHP has an array_change_key_case() function to change the case of array keys if needed.

Table name prefixes are not included in associative array keys. If a column name is used more than once in a query, use column aliases to distinguish the columns. Otherwise there will only be one associative array entry. If the aliases T1N and T2N were not used in the example below, only results from one of the NAME columns would be returned:

        $query = 'select myt1.name as t1n, myt2.name as t2n from myt1, myt2';

        $stid = OCIParse($conn, $query);
        OCIExecute($stid);
        while (OCIFetchInto($stid, $row, OCI_ASSOC)) {
          echo $row['T1N']." ".$row['T2N']."<br>\n";
        }

Pre-fetching in PHP to improve performance

There is no array fetch capability in PHP to return multiple rows in one operation and thus reduce network traffic, but setting the prefetch row count with OCISetPrefetch() is effectively the same. It can dramatically improve performance. The advantage of setting the prefetch row count instead of adjusting an array fetch size is that Oracle does the caching for you. Your data structures only have to handle one row at a time and your code can be simpler.

An example that sets the prefetch row count to 100 is:

        <?php

        $conn = OCILogon('myusername', 'mypassword', 'mydb');

        $query = 'SELECT * FROM EMP_DETAILS_VIEW';

        $stid = OCIParse($conn, $query);
        OCIExecute($stid);
        OCISetPrefetch($stid, 100);
        while ($succ = OCIFetchInto($stid, $row)) {
          foreach ($row as $item) {
            echo $item." ";
          }
          echo "<br>\n";
        }

        OCILogoff($conn);

        ?>

With the re-factored oci8 extension you can set the oci8.default_prefetch php.ini parameter to a suitable average value for your applications. By default the number of rows prefetched is 10. You can also tune statement caching with oci8.statement_cache_size to improve performance.


Using Oracle bind variables in PHP

Bind variables are strongly recommended because they help database performance and can improve application security.

  1. Problems with binding are often caused because the data value needs to be accessible at the time when OCIExecute() is called, not just when OCIBindByName() is executed.

    If OCIBindByName() is called inside a wrapper function or method and the PHP variable passed to OCIBindByName() is local to the wrapper function there may be a problem. The variable needs to be in scope when OCIExecute() is later called. Otherwise an Oracle error such as "OCIStmtExecute: ORA-01460: unimplemented or unreasonable conversion requested" may occur or, confusingly, it can appear as if no value was set for an "OUT" variable.

    The sample below is a variation on this. The variable "$val" is local to the "foreach" command. The code returns no records:

            <?php
    
            $qs = 'SELECT * FROM DEPARTMENTS WHERE DEPARTMENT_NAME = :dname AND LOCATION_ID = :loc';
    
            $dn = 'IT Support';
            $lc = '1700';
            $ba = array(':dname' => $dn, ':loc' => $lc);
    
            $conn = OCILogon('myusername', 'mypassword', 'mydb');
            $stmt = OCIParse($conn, $qs);
    
            foreach ($ba as $key => $val)
            {
              OCIBindByName($stmt, $key, $val, -1);
            }
    
            OCIExecute($stmt);
    
            while ($succ = OCIFetchInto($stmt, $o)) {
              foreach ($o as $mv) {
                echo $mv." ";
              }
              echo "<br>\n";
            }
    
            ?>
    

    Changing the OCIBindByName() call fixes the problem:

            . . .
            foreach ($ba as $key => $val)
            {
              OCIBindByName($stmt, $key, $ba[$key], -1);
            }
            . . .
    
  2. PHP numbers are converted to and from strings when they are bound. This means the length parameter must generally be given to OCIBindByName() when returning a numeric data value in a bind variable. The length is the number of digits that will be returned.

  3. Don't pass variables to OCIBindByName() by reference. This is obsolete PHP syntax and can cause problems. Sometimes you see this in older articles or documentation.

              OCIBindByName($stmt, ":mybindvar", &$val, 12);
            
    If you have set the E_STRICT error reporting level, then you will get an error if you attempt this.

Uploading LOBS

Here is an example script that uploads a JPG image into a BLOB column is. It uses PHP5 function names:

        <?php

        // Sample form to upload and insert an image into an ORACLE BLOB
        // column using PHP5's OCI8 API.
        //
        // Before running this script, execute these statements in SQL*Plus:
        //   drop table btab;
        //   create table btab (blobid number, blobdata blob);
        //
        // This example uploads an JPG file and inserts it into a BLOB
        // column.  The image is retrieved back from the column and displayed.
        // Make sure there is no whitespace before "<?php" else the wrong HTTP
        // header will be sent and the image won't display properly.
        //
        // Based on a sample originally found in
        //     http://www.php.net/manual/en/function.ocinewdescriptor.php

        $myblobid = 1;  // should really be a unique id e.g. a sequence number

        define("ORA_CON_UN", "hr");             // username
        define("ORA_CON_PW", "hr");             // password
        define("ORA_CON_DB", "//localhost/XE"); // connection string

        if (!isset($_FILES['lob_upload'])) {
        ?>

        <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST"
           enctype="multipart/form-data">
        Image filename: <input type="file" name="lob_upload">
        <input type="submit" value="Upload">
        </form>

        <?php
        }
        else {

          $conn = oci_connect(ORA_CON_UN, ORA_CON_PW, ORA_CON_DB);

          // Delete any existing BLOB so the query at the bottom
          // displays the new data

          $query = 'DELETE FROM BTAB WHERE BLOBID = :MYBLOBID';
          $stmt = oci_parse ($conn, $query);
          oci_bind_by_name($stmt, ':MYBLOBID', $myblobid);
          $e = oci_execute($stmt, OCI_COMMIT_ON_SUCCESS);
          if (!$e) {
            die;
          }
          oci_free_statement($stmt);

          // Insert the BLOB from PHP's tempory upload area

          $lob = oci_new_descriptor($conn, OCI_D_LOB);
          $stmt = oci_parse($conn, 'INSERT INTO BTAB (BLOBID, BLOBDATA) '
                 .'VALUES(:MYBLOBID, EMPTY_BLOB()) RETURNING BLOBDATA INTO :BLOBDATA');
          oci_bind_by_name($stmt, ':MYBLOBID', $myblobid);
          oci_bind_by_name($stmt, ':BLOBDATA', $lob, -1, OCI_B_BLOB);
          oci_execute($stmt, OCI_DEFAULT);

          // The function $lob->savefile(...) reads from the uploaded file.
          // If the data was already in a PHP variable $myv, the
          // $lob->save($myv) function could be used instead.
          if ($lob->savefile($_FILES['lob_upload']['tmp_name'])) {
            oci_commit($conn);
          }
          else {
            echo "Couldn't upload Blob\n";
          }
          $lob->free();
          oci_free_statement($stmt);

          // Now query the uploaded BLOB and display it

          $query = 'SELECT BLOBDATA FROM BTAB WHERE BLOBID = :MYBLOBID';

          $stmt = oci_parse ($conn, $query);
          oci_bind_by_name($stmt, ':MYBLOBID', $myblobid);
          oci_execute($stmt, OCI_DEFAULT);
          $arr = oci_fetch_assoc($stmt);
          $result = $arr['BLOBDATA']->load();

          // If any text (or whitespace!) is printed before this header is sent,
          // the text won't be displayed and the image won't display properly.
          // Comment out this line to see the text and debug such a problem.
          header("Content-type: image/JPEG");
          echo $result;

          oci_free_statement($stmt);

          oci_close($conn); // log off
        }
        ?>

Watch out for size limitations either in the HTML script:

        <input type="hidden" name="MAX_FILE_SIZE" value="3000">

or in the LimitRequestBody directive in httpd.conf, or in php.ini's upload_max_filesize directive.


Upgrading to PHP 5

  1. The OCI8 extension function names were standardized in PHP 5. Most changes were the addition of underscores, for example OCIBindByName() is now oci_bind_by_name(). A couple of function names are very different e.g. OCILogoff() is now an alias for the new oci_close(). The biggest changes were to data fetching functions. Refer to the manual for their new syntax.

    Both old and new names can be used so your scripts do not need to be recoded. The OCI8 Documentation has entries for old and new names. User contributed comments for the same functionality may be under either one.

    This FAQ mostly uses the old function names so examples work with PHP 4 and PHP 5.

  2. Another name that has changed in PHP 5 on Windows is the name of the directory containing the extension DLLs. If starting the web server gives you the error "Unable to load dynamic library 'c:\PHP\extension\php_oci8.dll'" edit your php.ini file and change the value of the "extension_dir" directive from "extension" to "ext".

  3. If you are upgrading to PHP 5.1.2 onwards and using the re-factored oci8 extension for the first time, check the documentation on the new oci8 php.ini directives. In particular check oci.old_oci_close_semantics. In the re-factored extension the OCILogoff()/oci_close() function will actually close a connection unless the directive is set. Previously the call was a no-op.


Oracle error messages in PEAR DB

The PEAR DB interface is a database abstraction layer that uses the same syntax for different database brands. The standard PEAR DB error function $db->getMessage() returns a simple PEAR error description. For example if connection fails for any reason, the message is always:

        DB Error: connect failed

You can get the exact Oracle error number and message by using:

         $db->getDebugInfo()

It includes the Oracle error and the complete statement like:

        [nativecode=ORA-01017: invalid username/password; logon denied ] ** oci8://myusername:wrongpassword@mydb

The Oracle message text can be extracted from this string with a wrapper function. An example is:

        require_once('DB.php');

        PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'PrintOCIError');

        // Display PEAR DB error
        function PrintOCIError($e)
        {
          if (is_object($e)) {
            $s = preg_match('/.*\[nativecode=(.*)/', $e->getDebugInfo(), $r);
            $etxt = $s ? $r[1] : $e->getDebugInfo();
          }
          else {
            $etxt = "Unknown Error";
          }
          echo "<p><b>Error</b>:</p>\n<pre>" .
            htmlspecialchars($etxt)."</pre>\n";
        }

        $db = DB::connect("oci8://myusername:wrongpassword@mydb");

        if (!DB::isError($db)) {
          .
          .
          .
        }

The output from PrintPEARDBError() is:

        Error:

        ORA-01017: invalid username/password; logon denied

Operating system authentication

Allowing externally authenticated database connections (where the username is "/" and the password an empty string) over the web would be a potential security risk for most configurations. Luckily PHP's OCI8 extension will not allow external authentication. The call in PHP's oci8.c to Oracle's OCISessionBegin() always sets the credential flag to OCI_CRED_RDBMS. To support operating system authentication the PHP source code would have to be changed to pass Oracle the OCI_CRED_EXT flag when appropriate.


Authentication with AS SYSDBA or AS SYSOPER

It is possible to connect AS SYSDBA or AS SYSOPER in PHP only with the re-factored oci8 extension. The oci8.privileged_connect parameter must also first be set On. Connection can be made with:

        $c = oci_connect("/", "", null, null, OCI_SYSDBA);

I don't recommend you allow this in external sites as it removes a layer of security. If anyone can execute arbitrary oci_connect() commands they may be able to gain privileged access to your database. It is most likely to be useful when PHP is used as a command-line script language.


NCHAR and NCLOB support in PHP

There is no NCHAR or NCLOB support in the OCI8 extension.

The current PHP implementations of oci8.c always use SQLCS_IMPLICIT for the character set form when it calls Oracle's OCI. The character set form would need to be SQLCS_NCHAR to support NCHAR and NCLOB, and other data handling changes may be needed in PHP's code.


Getting More Help

If you have questions or problems using Oracle and PHP, post details to the PHP Discussion Forum on OTN.

E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy