使用PHP訪問ORACLE?

Tags: 資料, 結構,

摘要:本文主要介紹瞭如何利用PHP的資料庫訪問技術實現對Oracle LOB資料物件的儲存。

  關鍵字:PHP;ORACLE; LOB;儲存;

  引言

   PHP,即“PHP: Hypertext Preprocessor”,是一種廣泛用於 Open Source(開放原始碼)並可以嵌入 HTML 的多用途指令碼語言。它的語法接近 C、Java 和 Perl,易於學習。該語言的主要目標是讓 Web 開發人員快速的書寫動態生成的網頁,然而,PHP 的功能並不侷限於此。PHP普遍被認為可以更快和更有效地實現複雜的程式設計任務,而且正是因為它的更穩定以及佔用更少資源的優點成為開發B/S結構系統的必備的WEB指令碼設計語言,扮演著類似中介軟體的角色,即語法解析與執行。

  ORACLE LOB資料模型

   在B/S(Browser/Server,瀏覽器/伺服器)應用系統中,需要儲存的已不僅僅是簡單的文字資訊,同時還包括一些圖片和音像資料或者是超長的文字。比如開發一套公文系統,公文中的圖表、附件等二進位制檔案或超長文字將無法使用普通的字元或其他型別的資料描述,這就要求後臺資料庫要有儲存這些資料的能力。運用Oracle LOB物件可實現該功能。

   Oracle LOB是用來儲存大量的二進位制和文字資料的一種資料型別(一個LOB欄位可儲存可多達4GB的資料)。目前,它又分為兩種型別:內部LOB和外部LOB。內部LOB將資料以位元組流的形式儲存在資料庫的內部。因而,內部LOB的許多操作都可以參與事務,也可以像處理普通資料一樣對其進行備份和恢復操作。Oracle8i支援三種類型的內部LOB:BLOB(二進位制資料)、CLOB(單位元組字元資料)、NCLOB(多位元組國家字元資料)。其中CLOB和NCLOB型別適用於儲存超長的文字資料,BLOB欄位適用於儲存大量的二進位制資料,如影象、視訊、音訊等。目前,Oracle8i只支援一種外部LOB型別,即BFILE型別。在資料庫內,該型別僅儲存資料在作業系統中的位置資訊,而資料的實體以外部檔案的形式存在於作業系統的檔案系統中。因而,該型別所表示的資料是隻讀的,不參與事務。該型別可幫助使用者管理大量的由外部程式訪問的檔案。

  PHP Oracle 8 函式分析

   PHP中有兩套ORACLE函式擴充套件庫,其中的ORACLE8函式允許訪問 Oracle8 和 Oracle7 資料庫,這些函式使用了Oracle8 Call-Interface(OCI8),支援向 Oracle 位置標誌符繫結區域性和全域性 PHP 變數,全面支援 LOB、FILE 和 ROWID,允許使用者使用使用者自定義的變數,即使用者資料庫的自定義物件類。

   Oracle8函式庫中函式OCIFetchInto用於取回一行資料記錄放入陣列中,該函式的語法描述如下:

int OCIFetchInto(array &result, int [mode])

   其中,引數mode可省略,內定值為OCI_NUM。在訪問Oracle LOB時,如果希望返回LOB物件,則mode應設為OCI_ASSOC+OCI_RETURN_LOBS。

   函式OCIBindByName用於將PHP變數與Oracle物件進行繫結,從而建立PHP與Oracle之間的資料通訊,該函式語法描述為:

boolean OCIBindByName(int stmt, string ph_name, mixed &variable, int length, int [type])

   其中:引數stmt是經過Oracle解析函式OCIParse解析後的字串指標。引數ph_name即需繫結的ORACLE返回變數名稱;引數variable前面一定要加&符號,表PHP變數地址。引數length為變數的長度,若設為-1則使用指定的variable變數的最大值;引數type可省略,其值有OCI_B_FILE(二進位制檔案)、OCI_B_CFILE(文字檔案)、OCI_B_CLOB(文字LOB)、OCI_B_BLOB(位元LOB)及OCI_B_ROWID(ROWID)等數種。值得注意的是,如使用Oracle8中特有的新資料型別LOB/ROWID/BFILE時,需要先執行 OCINewDescriptor()函式,同時必須要將length引數設成 -1。

   函式OCINewDescriptor用於初始化新的LOB/FILE描述。該函式語法描述為:

string OCINewDescriptor(int connection , int [type])

   其中的type同OCIBindByName函式中的type定義。

  必須的環境配置

   使用PHP的ORACLE8函式庫需要Oracle8客戶端庫。在使用這個擴充套件之前,請確認你已經為Oracle 使用者和WEB daemon 使用者正確設定了 Oracle 環境變數。下面列出了需要設定的環境變數:

ORACLE_HOME #ORACLE安裝路徑

ORACLE_SID # ORACLE資料庫ID

LD_LIBRARY_PATH #LD聯接庫路徑

NLS_LANG #ORALCE地區(語言)設定

ORA_NLS33 # ORA_NLS33路徑

  為Linux環境下驗證以上變數是否正確,最佳的辦法就是分別在oracle使用者與nobody下執行:

# env

   根據輸出的結果,判斷上述環境變數是否一致。

   在為WEB 伺服器使用者設定環境變數之後,你還需要將WEB 伺服器使用者(nobody、 www)加到oracle組中。

   有關ORACLE8客戶端和PHP安裝設定的詳細說明,請參考相關的技術手冊。

  應用範例

   在PHP中上載並將檔案儲存在ORACLE LOB欄位中的應用範例如下:

//LOB物件初始化,獲取PHP變數指標

$lob = OCINewDescriptor($conn, OCI_D_LOB);

//向有關的檔案記錄表新增紀錄,ORACLE SQL語法解釋

$stmt = OCIParse($conn,"update T_FILE set FILENAME='".$_FILES['FJ1']['name'].

"',FILETYPE='".$_FILES['F1']['type']."',FILES=EMPTY_BLOB() where FILEID=".$newid." returning FILES into :lob");

//繫結LOB變數

OCIBindByName($stmt, ':lob', &$lob, -1, OCI_B_BLOB);

OCIExecute($stmt, OCI_DEFAULT);//執行語句

if($lob->savefile($F1)){//將表單提交的檔案通過lob指標存入ORACLE資料庫

OCICommit($conn);

//成功上傳

}else{

//未能成功上傳

}

OCIFreeDesc($lob);

OCIFreeStatement($stmt);

//結束

  在PHP中將檔案從資料庫中提取並下載的應用範例如下:

$stmt = OCIParse($conn,"SELECT * FROM T_ FILE WHERE FILEID =$ID");

OCIExecute($stmt);

if(OCIFetchInto($stmt,$result,OCI_ASSOC+OCI_RETURN_LOBS)){

//輸出檔案型別資訊供瀏覽器判斷

header("Content-type: ".$result[FILETYPE]);

//輸出檔名,瀏覽器可提示是否開啟或下載該檔案

header("Content-Disposition: attachment; filename=".$result[FILENAME]);

//以上關於header函式的使用可參考PHP manual,HTML的檔案頭資訊請參考Internet RFC 2616。

//輸出檔案流,在此,瀏覽器獲取檔案內容,出現正在下載或直接開啟檔案的提示

echo $result[FILES];

}

OCIFreeStatement($stmt);

//結束

  以上範例僅是應用的關鍵語句,並在Linux+PHP+Apache+Oracle8i平臺上通過了驗證,讀者可根據自身需要進行完善和補充。

總結:

  本文探討PHP對ORACLE LOB訪問的實現,僅是PHP在B/S結構系統中基本運用技術所涉及的一個方面。筆者曾對比了JDBC與PHP-OCI兩者的執行效率,以JDBC為訪問引擎的OAS HTTP Server(HTTP Server為apache2.0)的響應速度要遜於建立在Linux+Aache+PHP-OCI平臺之上的WEB Server,這其中當然有Linux的出色表現,但不可否認的是,PHP與OCI的組合是非常優秀的。

  由於缺乏ORACLE LOB與PHP ORACLE8函式庫相結合運用的嘗試,在開發資訊管理系統中,為實現對大型資料檔案的管理,PHP在此方面的功能並未得到有效的利用,希望本文對從事PHP資料庫技術卻遇到此方面難題的程式設計師會有所幫助。

相關問題答案