- 论坛徽章:
- 1
|
很久没发贴了,最近心得贴出以于大家共同分享。
PHP下调用oracle存储函数实现教程(To invoke stored functions or procedures of oracle in PHP)
参考资料:
oracle官方网站:http://www.oracle.com/
oracle官方文档:http://www.oracle.com/technology ... p-oracle-manual.pdf
PHP手册:http://cn2.php.net/manual/zh/ref.oci8.php
一.安装PHP的oracle扩展
PHP的oracle扩展网上资料还算比较多,最权威是是oracle官方的教程:《Installing PHP and the Oracle 10g Instant Client for Linux and Windows》,地址:http://www.oracle.com/technology ... te_php_instant.html
现在就我自己的亲身体会来谈一谈我是如何操作的。
Linux平台:
1.下载两个软件包:Instant Client Package - Basic和nstant Client Package - SDK,截止本文最新包版本是10.2.0.3
因为我的系统是redhat as4,所以需要下载Instant Client for Linux x86版本。
这两个文件分别是 racle-instantclient-basic-10.2.0.3-1.i386.rpm和oracle-instantclient-devel-10.2.0.3-1.i386.rpm
当然你也可以下载zip版本,将他们解压到同一目录,例如/usr/lib/oracle/10.2.0.3/client/。rpm包的话安装起来比较省心。
rpm -Uvh oracle-instantclient-basic-10.2.0.3-1.i386.rpm
rpm -Uvh oracle-instantclient-devel-10.2.0.3-1.i386.rpm
2.重新编译PHP,添加oracle扩展。
- ./configure --with-oci8-instant-client=/usr/lib/oracle/10.2.0.3/client/lib --enable-sigchild
复制代码
这里需要注意一点的是:
oracle官方说在php4.3.9-4.3.10由于存在一个bug,需要先下载一个补丁:http://www.oracle.com/technology ... i8ic_buildpatch.txt,将内容存为一个文件,例如php_oci8ic_buildpatch,然后给ext/oci8/config.m4文件打上补丁:
patch -u config.m4 php_oci8ic_buildpatch
如果在此之前系统上已有PHP4.3.9,那么还需要
- cd php-4.3.9
- rm -rf autom4te.cache config.cache
- ./buildconf --force
复制代码
再做./configure操作
完成后make && make install
3.设置oracle环境变量
- #!/bin/sh
- APACHEHOME=/home/apache
- LD_LIBRARY_PATH=/usr/lib/oracle/10.2.0.3/client/lib:${LD_LIBRARY_PATH}
- TNS_ADMIN=/home
- export LD_LIBRARY_PATH TNS_ADMIN
- echo Starting Apache
- $APACHEHOME/apachectl start
复制代码
4.验证是否安装成功
重新启动apache,然后在web目录下建立一个新的文件:info.php,内容如下
访问一下这个文件,看看是否有oci的扩展。如果有,则说明安装成功,否则失败。
[注意]我仅在php4下安装成功,在php5的怎么也安装不上。目前原因还不清楚。
Windows平台:
windows平台下的安装较为简单,如果是PHP5下的Instant Client 方式,请直接参考《Enabling the PHP OCI8 Extension on Windows》这一节,我没有试验。
对于PHP4,直接修改php.ini文件,将php_oci8.dll扩展打开(就是将它前面的;去掉)就行。然后重启apache(cgi模式可不用重启)
二.连接oracle
对于一个新手来说,oracle的安装使用难度非常高。很多概念与常用的mysql完全不同。
在PHP手册上,连接oracle的脚本非常简单:
- $conn = OCILogon('hr', 'hr', 'orcl');
- if (!$conn) {
- $e = ocierror();
- print htmlentities($e['message']);
- exit;
- }
复制代码
事实上,安装好PHP的oci扩展后,这个脚本完全不能工作,因为oci_connect()的第三个参数是连接字符串,需要得到一个文本文件nsnames.ora
形如:
- ORCL_130 =
- (DESCRIPTION =
- (ADDRESS_LIST =
- (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.12.130)(PORT = 1521))
- )
- (CONNECT_DATA =
- (SID = ORCL)
- )
- )
复制代码
Linux下,这个文件放在TNS_ADMIN指定的目录下,windows下,这个文件放在PHP安装目录下就可以。
需要指出的是:在windows下,你不可以使用
$conn = OCILogon('username', 'passwd', '//192.168.12.130:1521/ORCL');
这种方式连接到oracle,具体原因不明。
此外,PHP5开始使用新的oci扩展函数名,很多在php3和php4时代的函数名都做了更改,如果你使用的是php4,请使用老的函数名。这给很多初学者造成了不小的麻烦,因为很多的资料都是新的函数名了。
三.调用oracle的存储过程
本为调用oracle的存储过程是一件非常简单的事的,但,这里需要指出的是,oracle的stored procedures和stored functions是两种不同的方法,中文翻译时常有人认为是一样的,我们可以把它们分别称为存储过程和存储函数,对于pl/sql来说可能调用方法一致,没什么两样,但如果你使用php的oci扩展这类api时,会发现很大不同,如果你用存储过程的方法来调用一个存储函数,你可以会得到一个存储过程不存在或未定义的错误。
在oracle官方的手册上我们可以找到这两者调用的不同例子:
存储过程调用
- <?php
- $c = oci_connect('hr', 'hrpwd', '//localhost/XE');
- $s = oci_parse($c, "call myproc('Chris', 123)");
- oci_execute($s);
- ?>
复制代码
或
- <?php
- $c = oci_connect('hr', 'hrpwd', '//localhost/XE');
- $s = oci_parse($c, "begin myproc('Alison', 456); end;");
- oci_execute($s);
- ?>
复制代码
存储函数的调用如下
- <?php
- $c = oci_connect('hr', 'hrpwd', '//localhost/XE');
- $s = oci_parse($c, "begin :ret := mypack.myfunc(123); end;");
- oci_bind_by_name($s, ':ret', $r, 20);
- oci_execute($s);
- echo "Name is: ".$r;
- ?>
复制代码
我们可以看到,存储函数的调用使用了返回值=函数名(参数)这种方式(:ret := mypack.myfunc(123) 。
此外,
oci_bind_by_name()函数在使用时需要注意,如果要绑定一个抽象数据类型(LOB/ROWID/BFILE),需要先用 oci_new_descriptor() 函数分配空间,具体见PHP手册。
如果需要绑定的是SQLT_RSET(游标类型,则需要oci_new_cursor()在指定的连接上分配一个新的语句句柄,5.0之前用ocinewcursor())
附:PHP4下一个返回游标类型的例子
- <?php
- $conn = OCILogon('username', 'passwd', 'ORCL_130');
- $user = 'test01';
- $passwd = '000000';
- $zList = ocinewcursor($conn);
- $stmt = OCIParse($conn, "begin :n_RetCode := mypack.myfunc($user, $$passwd, :zList); end;");
- OCIBindByName($stmt, ':n_RetCode',$n_RetCode,-1);
- OCIBindByName($stmt, ':zList',$zList,-1,OCI_B_CURSOR);
- OCIExecute($stmt);
- OCIExecute($zList);
- $nrows = ocifetchstatement($zList, $results);
- if ($nrows > 0) {
- echo "<table border=\"1\">\n";
- echo "<tr>\n";
- foreach ($results as $key => $val) {
- echo "<th>$key</th>\n";
- }
- echo "</tr>\n";
- for ($i = 0; $i < $nrows; $i++) {
- echo "<tr>\n";
- foreach ($results as $data) {
- echo "<td>$data[$i]</td>\n";
- }
- echo "</tr>\n";
- }
- echo "</table>\n";
- } else {
- echo "No data found<br />\n";
- }
- OCIFreeStatement($stmt);
- OCILogoff($conn);
- ?>
复制代码 |
|