Ubuntu24系统PHP8.3安装并启用PDO_OCI扩展的方法

PDO_OCI 和 OCI8 是两个平行、独立的 Oracle 数据库驱动,都直接基于 Oracle Instant Client 的 OCI C API 实现,互不依赖,可以单独或同时使用。

如果你当前项目是基于 PDO 的现代应用,优先考虑 PDO_OCI(安装方式比 OCI8 简单一些);如果需要更强大的 Oracle 原生功能,再装 OCI8。

在 Ubuntu 24.04(Noble Numbat)上,PHP 8.3 的 PDO_OCI 扩展 没有预编译的 apt 包(php8.3-pdo-oci 或类似不存在),官方 Ubuntu 仓库和 Ondřej Surý PPA 都不提供它。

PDO_OCI 扩展需要从 PHP 源码中编译(或通过 pecl install pdo_oci,但 pecl 版本在 PHP 8.3+ 上已过时或不推荐),并且必须依赖 Oracle Instant Client(与 OCI8 相同)。

下面是在 Ubuntu 24.04 + PHP 8.3 上开启 PDO_OCI 的推荐、可行步骤。

先决条件(必须先完成)

安装 Oracle Instant Client,具体如何安装参见Ubuntu24系统PHP8.3安装oci8扩展(针对Oracle Database 23ai Free数据库)的方法

开启 PDO_OCI 的两种主要方式

方式一:、通过 pecl install pdo_oci(推荐先尝试,PHP 8.3+ 支持)

sudo pecl install pdo_oci

安装过程中会提示:

Please provide the prefix of Oracle installation:

输入你的 Instant Client 路径,例如:

instantclient,/opt/oracle/instantclient_23_26

如果成功,pecl 会自动安装并提示添加 extension=pdo_oci.so 到 php.ini。

启用扩展:

echo "extension=pdo_oci.so" | sudo tee /etc/php/8.3/mods-available/pdo_oci.ini
sudo phpenmod pdo_oci

重启服务(CLI 不需重启,但建议):

sudo systemctl restart php8.3-fpm   # 如果用 FPM
sudo systemctl restart apache2

验证pdo_oci扩展是否成功启用:

php -m | grep -i oci

在输出中应该看到 pdo_oci。

方式二、从 PHP 源码手动编译(如果 pecl 失败,成功率更高)

1 下载 PHP 8.3 源码(要与你当前PHP版本匹配,例如 8.3.6):

wget https://www.php.net/distributions/php-8.3.6.tar.gz
tar -xzf php-8.3.6.tar.gz
cd php-8.3.6/ext/pdo_oci

2 准备编译:

phpize

3 配置(关键:指定 Instant Client 路径):

./configure --with-pdo-oci=instantclient,/opt/oracle/instantclient_23_26

如果提示缺少头文件,确保 Instant Client 的 SDK 已解压(包含 include/ 目录)。

如果报错 oci.h not found:检查路径是否正确,或把 Instant Client 的 include 路径加到环境变量:

export CFLAGS="-I/opt/oracle/instantclient_23_4/sdk/include"
./configure --with-pdo-oci=instantclient,/opt/oracle/instantclient_23_4

4 编译并安装:

make
sudo make install

5 启用扩展:

echo "extension=pdo_oci.so" | sudo tee /etc/php/8.3/mods-available/pdo_oci.ini
sudo phpenmod pdo_oci
sudo systemctl restart php8.3-fpm apache2

6 验证pdo_oci扩展是否成功启用:

php -m | grep -i oci

在输出中应该看到 pdo_oci。

编写测试脚本测试PDO_OCI扩展是否可用

创建测试脚本 test_pdo_oci.php:

<?php
try {
    $dsn = 'oci:dbname=//127.0.0.1:1521/FREEPDB1;charset=AL32UTF8';
    $pdo = new PDO($dsn, 'system', '你的密码');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->query('SELECT name, open_mode FROM v$pdbs');
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        print_r($row);
    }
    
    echo "PDO_OCI 连接成功!\n";
} catch (PDOException $e) {
    echo "连接失败: " . $e->getMessage();
}

运行:

php test_pdo_oci.php

如果输出 PDB 状态信息,说明成功。

常见问题和注意事项

  • pecl install pdo_oci 报错:如果提示 “channel not found” 或版本过时,直接用方式 2 手动编译。
  • libaio / libnnz / libclntsh 等库找不到:回到 Instant Client 环境变量设置 + ldconfig + 符号链接。
  • PHP 版本不匹配:确保 phpize 来自 php8.3(phpize –version 应显示 8.3)。
  • 生产环境:PDO_OCI 功能比 OCI8 弱(不支持某些高级绑定、LOB 流等),建议只用于简单 CRUD。如果项目允许,优先 OCI8。

最佳实践

  • 企业级 / 复杂项目(涉及 PL/SQL、包、游标、大字段、分页优化):几乎 100% 用 OCI8。
  • 简单读写(只是查询/插入几张表):PDO_OCI 也能用,但稳定性不如 OCI8。如果你的项目已经用了 PDO 统一抽象层,且只做简单操作,可以试 PDO_OCI。
  • Oracle 官方和 PHP 社区也推荐 OCI8 作为 “premier interface” 用于 Oracle + PHP。

Ubuntu24系统PHP8.3安装oci8扩展(针对Oracle Database 23ai Free数据库)的方法

针对 Oracle Database 23ai Free(这是一个多租户架构的数据库,使用 Pluggable Database 或 PDB),PHP 最合适的 Oracle 扩展是 OCI8(Oracle Call Interface 8)。这是 Oracle 官方推荐的扩展,它提供高性能、全面的 Oracle 数据库交互功能,包括对 23ai 的完整支持(如 AI 向量搜索、JSON 等新特性)。

虽然 PDO_OCI(PDO 的 Oracle 驱动)也是一个选项,但它功能较 OCI8 有限(例如不支持 LOB 流式处理或某些高级绑定),且维护较少。OCI8 是首选,尤其在生产环境中。对于 PHP 8.3.6 和 Oracle 23ai Free,OCI8 3.4+ 版本完全兼容。

安装 OCI8 扩展的步骤

OCI8 依赖 Oracle Instant Client(客户端库)。对于 Oracle 23ai,推荐使用 Instant Client 23.x(最新版如 Version 23.26.1.0.0 (Requires glibc 2.28) 或更高,以确保最佳兼容性)。

以下是详细步骤(需要 root 权限,确保备份系统):

1 安装依赖包

sudo apt update
sudo apt install -y php8.3-dev php-pear libaio1 unzip build-essential

如果报错说“找不到libaio1”,解决方法参见Ubuntu24系统PHP8.3安装oci8扩展后启用报错:/usr/lib/php20230831/oci8.so (libaio.so.1 cannot open shared object file No such file or directory)的解决方法

2 下载 Oracle Instant Client

访问 Oracle 官网 Instant Client 下载页oracle.com/database/technologies/instant-client/downloads.html。

下载 Linux x86-64 的 Basic PackageSDK Package(如oracle-instantclient-basic-23.26.1.0.0-1.el10.x86_64.rpm和oracle-instantclient-devel-23.26.1.0.0-1.el10.x86_64.rpm)。如果 RPM 不便,用 ZIP 版(如instantclient-basic-linux.x64-23.26.1.0.0.zip 和 instantclient-sdk-linux.x64-23.26.1.0.0.zip)。

对于 ZIP 版,解压到如 /opt/oracle/instantclient_23_26/:

sudo mkdir -p /opt/oracle
cd /opt/oracle
sudo unzip /path/to/instantclient-basic-linux.x64-23.26.1.0.0.zip
sudo unzip /path/to/instantclient-sdk-linux.x64-23.26.1.0.0.zip

3 设置环境变量

编辑 /etc/profile.d/oracle.sh(新建如果不存在):

sudo nano /etc/profile.d/oracle.sh

添加:

export ORACLE_HOME=/opt/oracle/instantclient_23_26
export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
export PATH=$ORACLE_HOME:$PATH

使环境变量和Oracle Instant Client相关共享库立即生效、可用:

source /etc/profile.d/oracle.sh
sudo ldconfig

注意,如果有其他终端窗口开着,需要先登出系统再登录才能使上述使环境变量和Oracle Instant Client相关共享库生效、可用。

4 安装 OCI8 扩展

使用 pecl 安装(指定 Instant Client 版本):

sudo pecl install oci8

当提示 “instantclient,/path/to/client/lib” 时,输入instantclient,/opt/oracle/instantclient_23_26

如果提示 PHP 版本错误,确保 pecl 使用 PHP 8.3:sudo pear config-set php_bin /usr/bin/php8.3

5 配置 PHP

添加oci8扩展到 php.ini(CLI 和 FPM/Apache,根据你的 PHP 使用方式):

echo "extension=oci8.so" | sudo tee /etc/php/8.3/mods-available/oci8.ini
sudo phpenmod oci8

如果用 Apache,重启:

sudo systemctl restart apache2

如果用 PHP-FPM,重启:

sudo systemctl restart php8.3-fpm

验证oci8扩展是否启用成功:

php -m | grep oci8

在输出中应看到 oci8。

PHP 测试脚本(test_oracle_connection.php)

以下是一个简单脚本,使用 OCI8 扩展连接 Oracle 23ai Free数据库。保存为 .php 文件,在命令行运行 php test_oracle_connection.php 或通过 Web 服务器访问:

<?php
// 连接参数(调整为你的实际值)
$username = 'system';
$password = '密码';
$connection_string = '127.0.0.1:1521/FREEPDB1';  // EZCONNECT 格式:主机:端口/服务名

// 尝试连接
$conn = oci_connect($username, $password, $connection_string, 'AL32UTF8');  // 指定字符集,避免中文乱码

if (!$conn) {
    $error = oci_error();
    echo "连接失败: " . htmlentities($error['message'], ENT_QUOTES);
    exit;
}

// 连接成功,执行一个简单查询测试
$stmt = oci_parse($conn, 'SELECT name, open_mode FROM v$pdbs');
oci_execute($stmt);

echo "连接成功!PDB 状态:\n";
while ($row = oci_fetch_array($stmt, OCI_ASSOC + OCI_RETURN_NULLS)) {
    echo $row['NAME'] . " - " . $row['OPEN_MODE'] . "\n";
}

// 关闭连接
oci_free_statement($stmt);
oci_close($conn);

注意,脚本中用了 EZCONNECT 格式(无需 tnsnames.ora)。

如果脚本运行成功,会显示 “连接成功!PDB 状态:” 后跟 PDB 列表(如 FREEPDB1 – READ WRITE)。

兼容性说明

PHP 的 OCI8 扩展完全兼容 Oracle 11g(包括 11g Release 2,即 11.2.x 版本):

  • 很多遗留系统用 PHP 7/8 + OCI8 连接 Oracle 11g 运行多年。
  • Laravel + yajra/laravel-oci8 包也支持连接 11g。
  • 官方教程(如 Oracle 的 PHP + 11g 示例)直接使用 OCI8。

潜在小问题(极少见):

  • 如果你的 Oracle 11g 是非常早的 11.1(非 11.2),兼容性稍差,但 11.2 是主流版本,完全没问题。
  • 某些非常新的 OCI8 特性(如 oci_set_call_timeout,需要客户端 18c+)在 11g 上不可用,但基本 CRUD 操作、绑定、LOB、存储过程等全部正常。
  • 字符集:建议用 AL32UTF8,避免老的 WE8MSWIN1252 导致乱码。

测试兼容性的简单 PHP 脚本:

<?php
$conn = oci_connect('system', '你的密码', '127.0.0.1:1521/orcl');  // 替换为你的连接字符串,如 SID 或服务名

if (!$conn) {
    $e = oci_error();
    echo "连接失败: " . htmlentities($e['message'], ENT_QUOTES);
} else {
    echo "成功连接到 Oracle 11g!\n";
    
    $s = oci_parse($conn, 'SELECT * FROM v$version');
    oci_execute($s);
    
    while ($row = oci_fetch_array($s, OCI_ASSOC)) {
        print_r($row);
    }
    
    oci_close($conn);
}

运行后如果能看到数据库的版本信息(如 “Oracle Database 11g Release 2″),就证明兼容性没问题。

Ubuntu24系统PHP8.3安装oci8扩展后启用报错:/usr/lib/php20230831/oci8.so (libaio.so.1 cannot open shared object file No such file or directory)的解决方法

PHP Warning: PHP Startup: Unable to load dynamic library 'oci8.so' (... libaio.so.1: cannot open shared object file: No such file or directory ...)

这个报错说明 OCI8 扩展编译和安装都成功了,但运行时找不到 libaio.so.1 这个共享库。

libaio 是 Oracle Instant Client 和 OCI8 必须依赖的异步 I/O 库(libaio1 包提供),Ubuntu 上默认不一定预装,或者安装后路径/链接有问题。

解决方法是安装 libaio1 包:

sudo apt update
sudo apt install libaio1
正在读取软件包列表... 完成
正在分析软件包的依赖关系树... 完成
正在读取状态信息... 完成
没有可用的软件包 libaio1,但是它被其它的软件包引用了。
这可能意味着这个缺失的软件包可能已被废弃,
或者只能在其他发布源中找到
E: 软件包 libaio1 没有可安装候选

以上报错是因为 Ubuntu 24.04 (Noble Numbat) 引入了 64-bit time_t 迁移(time_t 从 32 位升级到 64 位,以避免 2038 年问题),导致许多库包名后缀改为 t64。

原来的 libaio1 包已被废弃/移除。替换包是 libaio1t64(提供相同的功能,共享库名为 libaio.so.1t64)。

Oracle Instant Client(例如 23.x 版本)的PHP扩展oci8仍然链接到旧的 libaio.so.1(SONAME 未更新),所以即使安装了 libaio1t64,OCI8 加载时还是找不到 libaio.so.1,报错 libaio.so.1: cannot open shared object file。

解决这个问题步骤如下:

1 安装正确的包(libaio1t64):

sudo apt update
sudo apt install libaio1t64

这会安装/usr/lib/x86_64-linux-gnu/libaio.so.1t64文件(或类似路径)。

2 创建符号链接,让系统/Instant Client 能找到旧名字 libaio.so.1

先确认共享库libaio.so的路径(通常在下面位置):

find /usr/lib /lib -name "libaio.so.1t64" 2>/dev/null

输出如下:

/usr/lib/x86_64-linux-gnu/libaio.so.1t64

然后创建软链接:

sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1

有些 Oracle Instant Client 可能还找 libaio.so,因此额外保险做法是:

sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so

如果你的 Instant Client 目录下也需要libaio.so.1和libaio.so(极少见,但可尝试),进入你的 Instant Client 目录(如 /opt/oracle/instantclient_23_26):

cd /opt/oracle/instantclient_23_26
sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 libaio.so.1
sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 libaio.so

3 更新动态链接器缓存(让系统立即识别新链接):

sudo ldconfig

4 验证是否解决了上述问题

检查库是否存在:

ldconfig -p | grep libaio

在输出信息中应该看到 libaio.so.1(或 libaio.so.1t64)。

测试 PHP 加载 OCI8扩展:

php -m | grep oci8

如果输出 oci8,表示加载成功!

补充说明

libaio1t64包和libaio1包是二进制兼容的,t64 迁移只改了 time_t 类型,不会破坏 libaio 的 API。