2009-04-01

Working PHP and Oracle under Redhat EL 5

众所周知,PHP对MySQL的接口做得很好,LAMP名声在外,但是对于其他数据库的支持貌似就差了点。以前试着用过一次PHP的SQLServer接口(mssql),感受是做得相当粗糙。但是考虑到SQLServer是windows阵营的,应用也仅限于windows操作系统,也就情有可原了。但是对于Oracle这个重量级&跨平台通吃的家伙,PHP的支持又怎样呢?

手册中有两个关于Oracle的函数库。其中一个名为Oracle Functions,是比较旧的哪个版本,已经废弃。第二个为OCI8 函数库,是当前使用的版本。基本上实现了OCI的功能(包括事务与LOB操作等),看起来还不错(没用过,因此性能有待考证)。

顾名思义,OCI8函数库使用OCI实现,而使用OCI是必须要安装Oracle提供的客户端的。虽然Oracle的客户端是免费软件,但并不是自由软件,所以一般的发行版在打包的时候不会包含进来。因此,需要自己动手配置一下才能使用。

下面的步骤在Redhat EL 5上测试通过,在其他发行版上应该也是大同小异,写在这里以供参考。

1、安装配置Oracle客户端

a) 下载Oracle Instant Client

下载basic,sdk,sqlplus三个包

        instantclient-basic-linux32-11.1.0.7.zip
        instantclient-sdk-linux32-11.1.0.7.zip
        instantclient-sqlplus-linux32-11.1.0.7.zip

b) 安装并配置

按照Oracle的传统,放在/opt下

        # mkdir /opt/oracle
        # unzip instantclient-basic-linux32-11.1.0.7.zip
        # unzip instantclient-sdk-linux32-11.1.0.7.zip
        # unzip instantclient-sqlplus-linux32-11.1.0.7.zip

解压完后都在一同个目录instantclient_11_1中

        # mv instantclient_11_1  /opt/oracle/instantclient


编写tnsnames.ora

        # mkdir -p /opt/oracle/instantclient/network/admin
        # cd /opt/oracle/instantclient/network/admin
        # vi tnsnames.ora

填入如下内容

ORCL =
(DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.101.251)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ORCL)
    )
)

其中HOST为Oracle服务器的IP,SERVICE_NAME为Oracle实例名。

在/etc/profile的最后中添加如下内容

export ORACLE_HOME=/opt/oracle/instantclient
export TNS_ADMIN=/opt/oracle/instantclient/network/admin
export LD_LIBRARY_PATH=/opt/oracle/instantclient

export ORACLE_SID=ORCL

使配置生效

        # source /etc/profile

将sqlplus放入bash寻找路径

        # cp sqlplus /usr/local/bin

测试一下:

        # sqlplus sys/sys@ORCL as sysdba

如果显示

SQL*Plus: Release 11.1.0.7.0 – Production on Wed Apr 1 20:47:27 2009Copyright (c) 1982, 2008, Oracle. All rights reserved.

Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 – Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 – Production

SQL>

表示Oracle Instant Client配置成功。

2、安装PHP相关组件

虽然手册中说OCI8 Functions是内建在PHP中的,不需要安装,但是运行oci_connect()时,提示

Fatal error: Call to undefined function oci_connect() ……

究其原因,是因为虽然“内建”,但在默认编译时时并没有包含。解决方法有两个:一是从源代码重新编译PHP,具体步骤可以看这里;二是使用PECL中的oci8扩展。
按方便程度来说,最好的选择自然是后者。过程如下:

PECL和PEAR使用同一套包管理系统,所以要先安装PEAR才能使用PECL。
至于PHP开发包么,是因为PECL取回的是源代码,需要开发包来编译扩展,所以也是必需的。
使用yum,可以很简单地搞定这些。

# yum install php-pear
# yum install php-devel

编译安装前,还需要做一项准备工作。(共享库文件是带版本号的,默认编译时无法找到,需要建立没有版本号的共享库文件。用符号连接即可解决问题)

# ln -s libclntsh.so.11.1 libclntsh.so
# ln -s libocci.so.11.1 libocci.so

安装oci8扩展:
# pecl install oci8
安装过程中会提示输入ORACLE_HOME的路径,也就是instant所在路径

Please provide the path to the ORACLE_HOME directory. Use ‘instantclient,/path/to/instant/client/lib’ if you’re compiling with Oracle Instant Client [autodetect] :

填写shared,instantclient,/opt/oracle/instantclient即可

最后,修改/etc/php.ini,在其中加入extension=oci8.so,重启apache,这样就OK了。

3、测试
只需要测试一下能不能连上数据库,如果oci_connect没问题的话,其余函数应该也是没有问题的。

<?php

$conn = oci_connect('hr', 'passwd', 'orcl');
if (!$conn) {
  $e = oci_error();
  print htmlentities($e['message']);
  exit;
}
else{
  print "successfully connect to oracle.";
}

?>

4、更新:

除了直接使用oci8函数外,还可以使用PEAR中的MDB2库来连接Oracle。
如果不知道PEAR是什么,请看这里:PEAR简介:用PEAR来写你的下一个php程序
关于MDB2,请看这里:http://pear.php.net/package/MDB2/
简单来说,MDB2对PHP内置的原始接口进行了抽象封装,为不同的数据库提供了统一的面向对象接口。MDB2涵盖了多种主流数据库,稳定性也不错。因此,如果喜欢用面向对象的方式写程序,又不想“重复发明轮子”,MDB2是个不错的选择。
这篇文章详细介绍了如何安装使用MDB2以及MDB2的oci8驱动,并且给出了范例程序(Oracle的文档服务很是贴心。不得不承认,还是商业软件的文档支持更好)。如果只想知道如何安装使用MDB2,下面是我的快速参考:
a) 安装PEAR
如果是从本文的第一段一步步走下来的话,那此时已经安装过PEAR了。如果不确定有没有安装过,运行

           # yum list | grep php-pear

若输出中包含类似
php-pear.noarch 1:1.4.9-4.el5.1 installed
的信息,那就是已经安装过了。
如果没有,则运行以下命令安装

           # yum install php-pear

b) 安装MDB2及MDB2的oci8驱动
PEAR内建了自己的包管理系统,就和yum一样,运行几个命令即可自动化下载安装。
安装MDB2

           # pear install MDB2

安装oci8驱动

           # pear install MDB2#oci8

安装过程中可能会警告

WARNING: channel “pear.php.net” has updated its protocols, use “channel-update pear.php.net” to update

这是因为PEAR包管理系统的协议升级了,客户端需要升级。按照提示,运行如下命令即可解决这个问题:

# pear channel-update pear.php.net

c) 测试(修改自Oracle例程中的init.inc.php)

<?php

require_once 'MDB2.php';

$dsn = array(
    // The type of database to connect to
    // OCI8 should be the most common for
    // connections to Oracle databases.
    'phptype'   => 'oci8',

    // Usually this is the database host
    // to connect to. Since oracle manages
    // this through connection identifiers, one
    // must be used here. If this variable is
    // not set, MDB2 will try to retrieve the
    // SID through the corresponding environment
    // variable.
    'hostspec'  => null,

    // The username to use when connecting to the
    // database.
    'username'  => 'hr',

    // The corresponding password.
    'password'  => 'passwd',

);

// Establish database connection
$db = MDB2::connect($dsn);

// Check if the connection was established successfully
// using PEAR errorhandling.
// More on PEAR error handling can be found here:
// http://pear.php.net/manual/en/core.pear.pear-error.php
if (PEAR::isError($db)) {
    die('Could not create database connection. "'.$db->getMessage().'"');
}
else{
    print "successfully connect to oracle.";
}

?>