| 函數 | 作用 |
OCINewDescriptor($conn, $type) | 創建 LOB/FILE 描述符,返回句柄 |
OCIBindByName($stmt, $ph, &$var, $len, $type) | 綁定 PHP 變量到 Oracle 佔位符 |
OCIFetchInto($stmt, &$arr, $mode) | 取行,`OCI_ASSOC+OCI_RETURN_LOBS` 返回 LOB 對象 |
$lob->savefile($path) | 將文件內容寫入 LOB |
$lob->load() | 讀取 LOB 內容為字符串 |
環境變量配置 (Linux/Unix)
ORACLE_HOME=/u01/app/oracle
ORACLE_SID=ORCL
LD_LIBRARY_PATH=$ORACLE_HOME/lib
NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data
# 驗證:分別在 oracle 用戶與 nobody/apache 用戶下執行 env 對比
Web 服務器用戶 (nobody/www) 必須加入 `oinstall`/`dba` 組。
上傳文件存入 BLOB
<?php
$conn = OCILogon('user', 'pass', 'ORCL');
// 1. 初始化 LOB 描述符
$lob = OCINewDescriptor($conn, OCI_D_LOB);
// 2. SQL: EMPTY_BLOB() 初始化 + RETURNING INTO 綁定
$stmt = OCIParse($conn,
"UPDATE t_file
SET filename = :fname, filetype = :ftype, files = EMPTY_BLOB()
WHERE fileid = :fid
RETURNING files INTO :lob"
);
// 3. 綁定參數
OCIBindByName($stmt, ':fname', $_FILES['fj1']['name']);
OCIBindByName($stmt, ':ftype', $_FILES['fj1']['type']);
OCIBindByName($stmt, ':fid', $newid);
OCIBindByName($stmt, ':lob', $lob, -1, OCI_B_BLOB); // -1 表示最大長度
// 4. 執行並寫入文件
OCIExecute($stmt, OCI_DEFAULT);
if ($lob->savefile($_FILES['fj1']['tmp_name'])) {
OCICommit($conn);
echo '上傳成功';
} else {
echo '上傳失敗';
}
OCIFreeDesc($lob);
OCIFreeStatement($stmt);
?>
從 BLOB 下載文件
<?php
$conn = OCILogon('user', 'pass', 'ORCL');
$stmt = OCIParse($conn, "SELECT * FROM t_file WHERE fileid = :id");
OCIBindByName($stmt, ':id', $id);
OCIExecute($stmt);
if (OCIFetchInto($stmt, $row, OCI_ASSOC + OCI_RETURN_LOBS)) {
// 關鍵:設置 HTTP 頭,觸發瀏覽器下載/打開
header('Content-Type: ' . $row['FILETYPE']);
header('Content-Disposition: attachment; filename="' . $row['FILENAME'] . '"');
// 輸出二進制流
echo $row['FILES']->load(); // 或 $row['FILES']->read($size)
}
OCIFreeStatement($stmt);
?>
關鍵最佳實踐
- 大文件分塊讀寫:`$lob->write($chunk)` / `$lob->read($size)` 避免內存溢出
- 臨時 LOB:`OCINewDescriptor($conn, OCI_D_TEMP_LOB)` 用於中間處理,會話結束自動清理
- 流式輸出:下載大文件時分塊 `echo` + `flush()`,降低 PHP 內存佔用
- 錯誤處理:檢查 `OCIError()`,記錄 Oracle 錯誤碼
- 權限最小化:數據庫用戶僅授予必要表的 DML 權限
性能對比結論
作者實測:Linux + Apache + PHP-OCI8 響應速度優於 Windows + OAS (JDBC)。PHP 輕量進程模型 + OCI 直接調用,減少中間層開銷。
現代化遷移建議
- 新項目使用 **PDO_OCI** 或 **oci8** (PHP 7/8 仍維護)
- PDO 示例:`$stmt->bindParam(':lob', $lob, PDO::PARAM_LOB)`
- 考慮對象存儲 (S3/MinIO/OSS) + 數據庫存 URL,分離靜態資源與業務數據
- 上一篇文章: Apache 下 PHP 以 CGI 與模塊兩種模式運行的配置差異
- 下一篇文章: PHP 5 新特性深度解析:抽象類、魔術方法、類型提示、靜態成員、異常處理、命名空間
Copyright ©
程式碼之家 All Rights Reserved