主题
Oracle 没有安装或没有找到
在启动 Apache 之前在 shell 或环境中设置所有的 Oracle 环境变量
与数据库连接
回显 SQL 语句以检查它们是否得到正确设计
始终测试来自数据库函数调用的返回代码
插入包含引号的字符串
在 PHP 中使用 Oracle 赋值变量
上载 LOBS
PHP 中的数组获取
PEAR DB 中的 Oracle 错误消息
OCI 线程安全
使用 AS SYSDBA 或 AS SYSOPER 进行连接
PHP 中的 NCHAR 和 NCLOB 支持
Oracle 没有安装或没有找到
如果在 PHP 中启用了 Oracle 支持但未能找到 Oracle 客户端资料库那么当您试图启动 Apache 时将得到一个错误例如在 Windows 上如果 phpini 有 extension=php_ocidll但未能找到 Oracle 主页则一条警告 The dynamic link library OCIdll could not be found in the specified path 将被显示出来
在启动 Apache 之前确保 Oracle 环境变量被正确设置(参见下一主题)此外请参考由 Rob Clevenger 提供的 OTN 文章 在 Windows /XP 上安装 OraclePHP 和 Apache
Linux 用户可能看到一个关于不能加载 libclntshso 的 Apache 错误但更可能在之前编译 PHP 时注意到这个问题编译器将以一个错误 Cannot find file ocidfnh 或 Cannot find file ocih 而失败
确保 Oracle 目录对编译 PHP 的 OS 用户是可读的如果您安装了 Oracle但丢失了 Oracle 头文件请执行一次 Oracle 的 Client 安装Client 安装指的是 Oraclei Database Release 安装器中那个名称的选项(给出的其它三个选项是 DatabaseManagement and Integration和 Cluster Management)此外还请参考 OTN 文章在 Linux 上安装 OraclePHP 和 Apache
在启动 Apache 之前在 shell 或环境中设置所有的 Oracle 环境变量
在 Apache 启动之前设置所有的 Oracle 环境变量是使 PHP 能够与 Oracle 通信的一种安全的方法在 PHP 脚本或 文件中设置变量通常不起作用由于通常对环境的混淆存在许多邮件列表和论坛帖子在 Windows 和 Linux 上的行为也不同
OTN 文章 在 Linux 上安装 OraclePHP 和 Apache 给出了一个名为 start_apache 的用来设置环境和启动 Apache 的例子
#!/bin/sh
ORACLE_HOME=/u/app/oracle/product/
ORACLE_SID=orcl
export ORACLE_HOME ORACLE_SID
echo Oracle Home: $ORACLE_HOME
echo Oracle SID:$ORACLE_SID
echo Starting Apache
/apachectl start
我做了一些测试来查看该环境对 PHP 调用有什么影响
$mycon = OCILogon(myusername mypassword MYDB);
我用了 RedHat Linux AS Apache 和 PHP
在 apachectl start 之前没有设置 ORACLE_HOME 并且在 PHP 脚本中没有 putenv(ORACLE_HOME=/usr/oracle/MYDB) 的情况下我得到
Warning:ocilogon():_oci_open_server:
Error while trying to retrieve text for error ORA
这显示连接失败未能找到消息文件(这些文件位于 Oracle 主目录下)
在 PHP 脚本中有 putenv(ORACLE_HOME=/usr/oracle/MYDB)但没有设置 ORACLE_HOME 的情况下我得到
Warning:ocilogon():_oci_open_server:
ORA:TNS:could not resolve service name
连接仍然没有成功但在错误出现之后能够从消息文件中读出消息正文
在 apachectl start 之前设置了 ORACLE_HOME 但没有 putenv() 的情况下连接成功了这是推荐的配置
在 apachectl start 之前正确设置 ORACLE_HOME 同时 putenv() 使用一个无效 ORACLE_HOME 目录的情况下连接成功我也在 Windows 上试验了这种情况这次连接失败了出现和我上面的第一次测试同样的消息
当我用一条 Apache 指令 setenv ORACLE_HOME /usr/oracle/MYDB 来替换 PHP putenv() 调用时得到了一组类似的结果
一些变量可以在 PHP 脚本中设置在启动 Apache 之前正确设置 ORACLE_HOME 之后以下操作改变了我的默认连接并连接到 MYDB
putenv(TWO_TASK=MYDB);
$mycon = OCILogon(myusername mypassword);
环境变量 TNS_ADMINNLS_DATE_FORMAT(可能还有其它变量)也可以用这种方式来设置
与数据库连接
用户选择的网络服务名称常常用来识别要与哪个数据库连接它被默认从环境变量 ORACLE_SID 中读出或者它可以在连接调用中显式地给出网络服务名称 MYDB 可以用在 Oracle 的命令行 SQL*Plus 实用程序中如
sqlplus myusername/mypassword@MYDB
或用在 PHP 中如
$mycon = OCILogon(myusername mypassword MYDB);
网络服务名称通常通过 tnsnamesora 文件中的一个项目映射到一个实际的数据库上
MYDB =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = mymachinemydomain)(PORT = ))
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = MYDBmydomain)
)
)
$ORACLE_HOME/network/admin/tnsnamesora 文件被默认使用在一些操作系统上如果默认文件不存在则将检查其它的位置
如果在 tnsnamesora 中找不到被用在 OCILogon() 中的网络服务名称或者 PHP 根本没找到 tnsnamesora那么您在登录时可能得到一个错误
Warning:ocilogon():_oci_open_server:ORA:TNS:could not resolve service name
在启动 Apache web server 之前检查环境变量 ORACLE_HOME 是否正确设置(参见之前的主题)
如果您的 tnsnamesora 在一个非默认的位置您可以将环境变量 TNS_ADMIN 设置为包含它的目录例如如果您在使用 /tmp/tnsnamesora将这些行添加到 start_apache 中(同样参见之前的主题)
TNS_ADMIN=/tmp
export TNS_ADMIN
另一种解决办法是在 OCILogon() 调用中使用完整的连接字符串
$db = (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)
(HOST = mymachinemydomain)(PORT=)))
(CONNECT_DATA=(SERVER=DEDICATED)
(SERVICE_NAME=MYDBmydomain)));
$mycon = OCILogon(myusername mypassword $db);
如果 $ORACLE_HOME/network/admin/sqlnetora 与 tnsnamesora 不同步且一个域名被隐式地添加到了别名中那么错误 ORA 也可能发生OCILogon() 调用中的不合格网络服务名称将添加 sqlnetora 的 NAMESDEFAULT_DOMAIN 值例如如果 sqlnetora 有
NAMESDEFAULT_DOMAIN =
那么 OCILogon(myusername mypassword mydb) 将使 Oracle 在 tnsnamesora 中寻找别名 MYDBAUORACLECOM = 一种快速的解决办法是将 tnsnamesora 项目改变为
MYDBAUORACLECOM =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = mymachinemydomain)(PORT = ))
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = MYDBmydomain)
)
)
回显 SQL 语句检查它们是否得到正确设计
令人意外的是没有得到结果或者得到错误的结果常常归因于执行了错误的语句在开发期间从 PHP 回显每一条完整的 SQL 语句检查它是否得到正确设计所有变量是否得到了正确扩展引用错误或者对字符串中 PHP 的变量语法的错误理解可能导致不正确的语句被执行
在执行它们之前测试 SQL*Plus 中的 SQL 语句也有助于确认正确性
当语句被输入到诸如 SQL*Plus 之类的工具中时通常用一个分号来告诉工具这个语句完成了现在可以被执行不过分号不被认为是语句的一部分并且不会被发送到数据库中在 PHP 中不要向 SQL 语句中添加分号否则将出现一个 Oracle 错误这个例子是一次有效的查询
$sql =