PHP ADODB 1.99版手冊中文翻譯(Tripc)
感謝
記事


PHP ADODB 1.99版手冊中文翻譯
翻譯作者:Tripc
------------------

ADODB

PHP在資料庫的支援上是很令人稱道的,幾乎所有的知名資料庫系統都有對應的函數群支援,而且支援的很完整。但很不幸的,每一群資料庫支援函數無論在名稱或參數結構上,都有很大的差異,這使得PHP的系統開發者在面臨更換資料庫時,總會覺得痛苦萬分。難道這個問題就沒有解決方法嗎?呵呵,當然有,答案就是我現在要介紹的 ADODB 這個PHP物件。

ADODB提供了完整的方法和屬性讓工程師去控制資料庫系統,更棒的是你只要記得它的功能就好了,因為不同的資料庫系統,只要修改一個屬性值就可以了,ADODB會自動依據設定取用正確的PHP函數。此外,最多再配合資料庫系統修改修改SQL指令,你的PHP系統就可以在最短的時間內更換到另一個資料庫系統了,如果在撰寫程式時,對SQL指令能做妥善規劃,那就更快了。

經過以上的介紹,相信你已經對ADODB的功用有所瞭解,以下為ADODB的詳細介紹。

取得ADODB

你可以在 http://php.weblogs.com/ADOdb 取得最新版的ADODB。我在撰寫本文時,最新版本是1.99版,版權採BSD-Style及LGPL雙軌制,換句話就是Freeware,沒有什麼限制。但在取得ADODB後,最好還是要看一下相關版權說明及用法,並和本文對照一下,以免錯誤。

使用ADODB

基本上使用ADODB是相當容易的,取得壓縮檔後解開,我建議將整個內容都解到ADODB的目錄裡。然後你可以一邊參考本文,一邊研究裡面的範例,就放在裡面的test目錄下。

由於ADODB附上的說明十分完整詳實,以下的說明大部份來自ADODB的readme.htm,這裡不是全部的內容,我把一些我認為沒有用的內容都去掉了,像版本差異說明、何撰寫支援ADODB的驅動程式等與應用無關的部份。想要瞭解全部內容的讀者還是可以自己去參考 readme.htm。


簡介

由於PHP的資料庫存取函數沒有標準化,所以我們需要一組函數庫或是類別來隱藏不同資料庫函數介面間的差異,讓我們可以很簡單的去切換資料庫,而這,就是ADODB的目的。

ADODB目前支援MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, Informix, PostgreSQL, FrontBase, Interbase (Firebird 及 Borland 版本), Foxpro, Access, ADO 和 ODBC。ADODB也有透過ODBC成功連結Progress及DB2的報告,我們希望能有更的人提供驅動介面來支援更多的資料庫。

PHP4支援連結變數(session variables),使用者可以透過ADODB儲存連結資訊,以達成真正的可攜性及彈性,相關的用法及資訊請自行參考ADOdb-session.php這個範例。

另外,如果要撰寫一個具有高度可移植性的SQL碼,也可以參閱 http://php.weblogs.com/portable_sql 這篇文章。

特色

  • 對熟悉Windows的工程師而言,ADODB很容易使用,因為ADODB裡的很多功能和Microsoft的ADO很像。

  • 與其它的PHP資料庫類別不同,它們大多集中在處理與 select 指令有關的東西,而ADODB對於 inserts 及 update 也提供額外的支援,並且可以很快的連結到多資料庫。所提供的方法更擴及日期的掌握,字串的連結及字串標記字元差異處理(在某些資料庫間字串的連結和標記符號是有差異的)

  • 型別對照系統是內建的,所以我們可以設定或描述像CHAR,TEXT及STRING在不同的資料庫間其實是相同的資料型別。

  • 更容易去移植,因為所有與資料庫相依的程式碼被都隱藏在後端,所以使用者不再需要去移植類別裡的邏輯。

  • 支援 PHP4 連結變數,請參考 ADOdb-session.php。

安裝

首先要確定你所使用的PHP版本是 4.01pl2 或是之後的版本(因為ADODB使用到了 require_once及include_once兩個函數)。解壓縮全部的檔案到你的Web伺服器可以存取的一個目錄裡。

要測試ADODB你需要一個資料庫,開啟 testdatabase.inc.php 這個檔案,並且修改連結參數,以適合你所使用的資料庫。這個程式會建立一個新的資料表在你的資料庫中,以支援我們提供的測試程式及範例。

就這樣,你安裝好了。

啟動ADODB

當要執行ADODB時,至少有兩個檔案要被載進來,第一個是 ADOdb.inc.php ,這裡面包含了所有資料庫類中要被使用的函數。而對資料庫實作的程式碼則被置放在ADOdb-????.inc.php檔案裡。

例如說,要連結一個mysql資料庫:

include('/path/to/set/here/ADOdb.inc.php');
$conn = &ADONewConnection('mysql');

無論何時你需要連結到一個資料庫時,你必需使用ADONewConnection()函數建立了一個連結物件。ADONewConnection接受一個選擇性參數, <database-name-here>。如果沒有參數被指定,它將會使用被 ADOLoadCode() 所載入的最後一個資料庫。 NewADOConnection() 是另一個相同的函數。

當你建立好一個連結物件時,你並沒有真的連結上你的資料庫。你仍需要使用 $conn->Connect() 或者 $conn->PConnect() 兩個方法來完成真正的連結。

你可以參考教學手冊裡的範例,對上面的說明做更深入的瞭解。

支援的資料庫

名稱

測試狀態

資料庫

RecordCount() 支援與否

需安裝的驅動程式

作業系統

access

B

Microsoft Access/Jet. 需要建立一個 ODBC/DSN。

Y/N

ODBC

Windows only

ado

B

一般未經特別指定的資料庫系統, 透過ADO,允許不設定 DSN連結,使用OLEDB以提供較佳的效能。

? 視資料庫而定

ADO or OLEDB provider

Windows only

ado_access

B

Microsoft Access/Jet 透過ADO,允許不設定 DSN連結,使用OLEDB以提供較佳的效能。

Y/N

ADO or OLEDB provider

Windows only

ado_mssql

B

Microsoft SQL Server 透過ADO,允許不設定 DSN連結,使用OLEDB以提供較佳的效能。

Y/N

ADO or OLEDB provider

Windows only

db2

C

DB2. 可以透過ODBC獲得可以信賴的運作效果。

Y/N

DB2 CLI/ODBC interface

Unix and Windows. Unix install hints.

vfp

A

Microsoft Visual FoxPro,需要建立一個ODBC/DSN

Y/N

ODBC

Windows only

fbsql

C

FrontBase.

Y

?

Unix and Windows

ibase

B

Interbase 6或更早的版本。有些使用者報告必需使用如下的方式連結
$db->PConnect('localhost:c:/ibase/employee.gdb', "sysdba", "masterkey")目前沒有支援 Affected_Rows 方法

Y/N

Interbase client

Unix and Windows

firebird

C

interbase的Firebird版本

Y/N

Interbase client

Unix and Windows

borland_ibase

C

Borland 的Interbase 6.5 或更新版

Y/N

Interbase client

Unix and Windows

informix

C

Informix

Y/N

Informix client

Unix and Windows

mssql

A

Microsoft SQL Server 7.也可以和Microsoft SQL Server 2000運作的很好。但在日期格式上仍有一些問題。例如在日期時間的回傳值上,就不會回傳秒數數值。

Y/N

Mssql client

Unix and Windows.
Unix install howto
.

mysql

A

MySQL 不支援交易處理

Y/N

MySQL client

Unix and Windows

mysqltmaxsql

A

MySQL 支援交易處理

Y/N

MySQL client

Unix and Windows

oci8

A

Oracle 8/9. 支援比 oracle 驅動程式還多的功能 (例如: Affected_Rows). 在連結之前,你可能需要先配好環境變數('ORACLE_HOME=...')

有兩個方式進行連結,用伺服器的IP或服務名稱:
PConnect('serverip:1521','scott','tiger','service')
PConnect('', 'scott', 'tiger', 'tnsname').

Y/N

Oracle client

Unix and Windows

oci8po

A

Oracle 8/9 可攜式驅動程式

Y/N

Oracle client

Unix and Windows

odbc

A

標準 ODBC

用 PConnect('DSN','user','pwd').連結。

? depends on database

ODBC

Unix and Windows. Unix hints.

odbc_mssql

C

用 ODBC 連接 MSSQL

Y/N

ODBC

Unix and Windows.

odbc_oracle

C

用 ODBC 連接 ORACLE

Y/N

ODBC

Unix and Windows.

oracle

C

支援舊的 Oracle 7 client API. 不支援 $ADODB_FETCH_MODE.

Y/N

Oracle client

Unix and Windows

postgres

A

PostgreSQL 不支援 LIMIT 指令.

Y

PostgreSQL client

Unix and Windows.

postgres7

A

PostgreSQL 支援 LIMIT 及其它版本 7 功能

Y

PostgreSQL client

Unix and Windows.

sqlanywhere

C

Sybase SQL Anywhere. 

Y/N

SQL Anywhere ODBC client

?

sybase

C

Sybase.

Y/N

Sybase client

Unix and Windows. Unix hints.

 

測試狀態欄的代碼說明如下:

A=已經經過很多人驗證及測試,可靠度最高。
B=已經測試並使用了,但可能仍有一些功能沒有達成。
C=使用者自行配置或試用的驅動程式,可能沒有完全支援ADODB的功能。

"RecordCount()支援與否",指的是RecordCount()函數是否會回傳用SELECT指令取得的記錄筆數(不支援時傳回-1)。如果這個欄位的值出現了 Y/N ,那表示當全域變數 $ADODB_COUNTER=true 時,會以模擬的方式取得,而這是預設值。要注意的是,如果你預測記錄筆數會很大時,最好把這個值設為false,也就是關掉這個模擬功能,因為這會耗掉非常多的記憶體,以做為快取之用。由於這個變數在每次執行時都會檢查,所以你可以選擇性的使用或不使用。

所有支援$ADODB_FETCH_MODE的資料庫都支援 ADODB_FETCH_NUM(以欄位順序存取) 及 ADODB_FETCH_ASSOC(以欄位名稱存取),兩種模式。而將值設為 ADODB_FETCH_DEFAULT(資料庫預設模式存取),則是由資料庫的功能來決定的,所以不具備可攜性,而 ADODB_FETCH_BOTH(雙模式存取) 也一樣。


學習手冊

範例 1: Select 指令

任務:連結到 Access 的 Northwind DSN,然後在每一列顯示頭2個欄位。(Northwind 北風資料庫,在ODBC設定的DSN,是Access的標準範例資料庫)

在這個範例中,我們建立一個 ADOConnection 物件,它代表了和資料庫的連結。連結是以 PConnect 函數來初始化的,然後會持續的連結著。任何時候我們要查詢資料庫時,我們就呼叫 ADOConnection.Execute() 函數,這將會回傳一個 ADORecordSet物件。事實上它只是一個指向在fields[]陣列中,目前記錄的指標,我們使用MoveNext()來在記錄間移動。

注意:另一個很有用的函數 SelectLimit 並沒有在這個範例裡使用,這個函數允許我們去限制顯示的資料筆數。

<?
include('ADOdb.inc.php');       # 載入ADODB
$conn = &ADONewConnection('access');    # 建立一個連結
$conn->PConnect('northwind');   # 連結到 MS-Access 北風資料庫
$recordSet = &$conn->Execute('select * from products');
if (!$recordSet) 
        print $conn->ErrorMsg();
else
while (!$recordSet->EOF) {
        print $recordSet->fields[0].' '.$recordSet->fields[1].'<BR>';
        $recordSet->MoveNext();
}

$recordSet->Close(); # 選擇性執行
$conn->Close(); # 選擇性執行

?>

在這個例子中,$recordSet回傳了存在$recordSet->fields陣列裡,目前所指向的記錄。以欄位編號為索引,起始值為0。我們使用MoveNext()函數來移動到下一筆記錄,當到了最後一筆時,EOF屬性會被設定為true。當Execute()函數執行有錯誤時,會回傳一個false值,而不是一個recordset物件。

$recordSet->fields[]陣列是由PHP資料庫擴充函數庫所產生的。有一些資料庫擴充函數庫僅支援以編號來進行索引,而不支援以欄位名為索引。要強迫使用欄位名索引,也就是要使用關連式陣列,請使用 $ADODB_FETCH_MODE 全域變數來設定。當一個資料集被Execute()或是SelectLimit()函數建立時,都會儲存而且使用儲如此類的設定模式。

       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
        $rs1 = $db->Execute('select * from table');
        $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
        $rs2 = $db->Execute('select * from table');
        print_r($rs1->fields); # shows array([0]=>'v0',[1] =>'v1')
        print_r($rs2->fields); # shows array(['col1']=>'v0',['col2'] =>'v1')

上面的範例說明,如果要以順序來存取欄位,就將 $ADODB_FETCH_MODE 的值設為 ADODB_FETCH_NUM,要以關連式陣列(以欄位名)存取欄位,就要將值設為 ADODB_FETCH_ASSOC。

要取得在被選到的記錄筆數,你可以使用$recordSet->RecordCount()方法。注意,如果不能確定得到的記錄筆數,會回傳 -1 。

範例 2: 進階的 Select 指令(使用 Field 物件)

任務:選取一個資料表,顯示最前面的二欄。如果第二欄是一個日期或時間型態欄位,將它格式化成US格式。

<?
include('ADOdb.inc.php');       
$conn = &ADONewConnection('access');    
$conn->PConnect('northwind');   
$recordSet = &$conn->Execute('select CustomerID,OrderDate from Orders');
if (!$recordSet) 
        print $conn->ErrorMsg();
else
while (!$recordSet->EOF) {
        $fld = $recordSet->FetchField(1);
        $type = $recordSet->MetaType($fld->type);

        if ( $type == 'D' || $type == 'T')
                print $recordSet->fields[0].' '.
                        $recordSet->UserDate($recordSet->fields[1],'m/d/Y').'<BR>';
        else 
                print $recordSet->fields[0].' '.$recordSet->fields[1].'<BR>';

        $recordSet->MoveNext();
}
$recordSet->Close(); # optional
$conn->Close(); # optional

?>

在這個例子中,我們使用 FetchField() 函數來檢查第二個欄位的資料型別。這將會回傳一個至少有三個欄位的物件,欄位說明如下:

  • name: 欄位名

  • type: 欄位的資料原生型別native field type of column

  • max_length: 欄位的最大長度,部份資料庫像MySQL,並不回傳欄位的正確值,以這個例子而言,就會回傳 -1 。

然後我們使用 MetaType() 去轉換原生型別成通用型別,目前通用型別定義如下:

  • C:  character 欄位,應該使用 <input type="text"> 標記來取值。

  • X: 文字欄位(Text) , 長文字欄位,使用 <textarea> 標記來顯示資料。

  • B: Blob 欄位或者大型的二位元物件(像程式,圖檔等)。

  • D: 日期欄位

  • T: 時間欄位

  • L: 邏輯欄位(真假值)或位元欄位

  • N: 數字欄位,包含自動進位、編號、整數、浮點數、實數等。

  • R: 序列欄位,包含了序列、自動增進整數,只對被選擇的資料庫作用。

如果對應型別是日期或時間,那你可以使用 UserDate() 函數來設定輸出的日期格式。這個函數會轉換 PHP SQL 日期字串格式為使用者定義的格式。 另一個使用MetaType()的時機是在進行SQL新增或更新指令時,資料格式驗證用。

範例 3: 新增

新增一筆記錄到訂單資料表,裡面包含了日期和字串,為了能被資料庫正常存取,字串必需校正,以避免部份標記字元。例如:有單引號的字串,John's。

<?
include('ADOdb.inc.php');       # load code common to ADOdb
$conn = &ADONewConnection('access');    # create a connection

$conn->PConnect('northwind');   # connect to MS-Access, northwind dsn
$shipto = $conn->qstr("John's Old Shoppe");

$sql = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";
$sql .= "values ('ANATR',2,".$conn->DBDate(time()).",$shipto)";

if ($conn->Execute($sql) === false) {
        print 'error inserting: '.$conn->ErrorMsg().'<BR>';
}
?>

在這個範例中,我們看見了ADODB更進一步的日期及標點符號的處理方式。Unix 日期時間標示(長整數)被DBDate()格式化成Access可以接受的格式,而帶了縮寫符號的 John's Old Shoppe 則被 qstr() 函數處理成 John''s Old Shoppe 字串,以被資料庫合法存取。

觀察 Execute 指令的錯誤處理。如果 Execute() 執行有錯誤發生時,會傳回 False 值。而最後的錯誤訊息可以由  ErrorMsg() 來顯示。

附記:php_track_errors旗標可以被啟動,以便將錯誤訊息儲存起來。

範例 4: 除錯

<?
include('ADOdb.inc.php');       # load code common to ADOdb
$conn = &ADONewConnection('access');    # create a connection
$conn->PConnect('northwind');   # connect to MS-Access, northwind dsn
$shipto = $conn->qstr("John's Old Shoppe");
$sql = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) ";
$sql .= "values ('ANATR',2,".$conn->FormatDate(time()).",$shipto)";
$conn->debug = true;
if ($conn->Execute($sql) === false) print 'error inserting';
?>

在上面的例子中,我們藉由設定 debug=true 來啟動除錯模式。這將會在執行指令時會先將SQL指令顯示,並且會顯示所有的錯誤訊息,而不需要去呼叫 ErrorMsg() 。顯示資料集的部份,可以參考 rs2html() 範例。

其它的請參考自定錯誤處理的說明。

範例 5: MySQL及選單

連結到MySQL資料庫 agora ,並且從SQL命令中建立一個 <select> 選單,<option>的標題是第一個欄位,回傳值是第二個欄位。

<?
include('ADOdb.inc.php'); # load code common to ADOdb
$conn = &ADONewConnection('mysql');  # create a connection
$conn->PConnect('localhost','userid','','agora');# connect to MySQL, agora db
$sql = 'select CustomerName, CustomerID from customers';
$rs = $conn->Execute($sql);
print $rs->GetMenu('GetCust','Mary Rosli');
?>

Here we define a menu named GetCust, with the menu option 'Mary Rosli' selected. See GetMenu(). We also have functions that return the recordset as an array: GetArray(), and as an associative array with the key being the first column: GetAssoc().

這裡,我們定義了一個名為GetCust的選單,預設值是'Mary Rosli'。相關說明請參考 GetMenu() 。我們也將資料集以陣列回傳的方式寫在 GetArray()方法裡。而另外回傳關聯式陣列的方法則使用 GetAssoc() ,其中第一個欄位是這個欄位的鍵值。

在 1.50 版以後的 ADODB 裡,是使用公共變數 $ADODB_FETCH_MODE 來設定回傳的陣列是以編號或是關連式字串做索引。

範例 6: 一次連結兩個資料庫

<?
include('ADOdb.inc.php');     # 載入 ADOdb
$conn1 = &ADONewConnection('mysql');  # 建立一個 mysql 連結
$conn2 = &ADONewConnection('oracle');  # 建立一個 oracle 連結

$conn1->PConnect($server, $userid, $password, $database);
$conn2->PConnect(false, $ora_userid, $ora_pwd, $tnsname);

$conn1->Execute('insert ...');
$conn2->Execute('update ...');
?>

範例 7: 產生 Update 及 Insert 的SQL指令

ADODB 1.31版起,新增了兩個資料集函數:GetUpdateSQL()及GetInsertSQL()。這允許你在執行了像"SELECT * FROM table query WHERE..."這樣的查詢函數後,建立一個 $rs->fields複本,改變這些欄位,然後自動產生出更新或是新增的SQL指令。

以下我們展示如何運用這些函數,我們將存取一個資料表,帶有下列欄位:(ID,FirstName,LastName,Created)。在這些函數被執行前,你需要藉由一個對資料表的查詢指令(select)來初始化一個資料集。

<?
#==============================================
#  GetUpdateSQL() 及 GetInsertSQL() 範例碼
#==============================================
include('ADOdb.inc.php');
include('tohtml.inc.php');

#==========================
# 以下的程式碼測試新增狀態

$sql = "SELECT * FROM ADOXYZ WHERE id = -1"; 
# 從資料庫中查詢出一個空的資料集

$conn = &ADONewConnection("mysql");  # 建立一個連結
$conn->debug=1;
$conn->PConnect("localhost", "admin", "", "test"); # 連結到 MySQL, 資料庫名稱為 test
$rs = $conn->Execute($sql); # 執行查詢,並取得一個空的資料集

$record = array(); # 初始化一個陣列,以便存放記錄資料供新增用

# 設定記錄中的欄位值
$record["firstname"] = "Bob";
$record["lastname"] = "Smith";
$record["created"] = time();

# 傳入空的資料集及欄位資料陣列到GetInsertSQL函數中,以執行功能
# 這個函數將會依傳入的資料,回傳一個全格式的 INSERT SQL指令

$insertSQL = $conn->GetInsertSQL($rs, $record);

$conn->Execute($insertSQL); # 將記錄挿入資料庫中

#==========================
# 以下的程式碼測試更新狀態

$sql = "SELECT * FROM ADOXYZ WHERE id = 1"; 
# 選擇一筆記錄以便更新

$rs = $conn->Execute($sql); # 執行這個查詢,並取得一個存在的記錄來更新

$record = array(); # 初始化一個陣列,以存放要更新的資料

# 設定欄位裡的值
$record["firstname"] = "Caroline";
$record["lastname"] = "Smith"; # 更新 Caroline的姓由 Miranda 變成 Smith

# 傳入這個只有單一記錄的資料集以及含有資料的陣列到 GetUpdateSQL函數裡
# 函數將會回傳一個具有正確 WHERE 條件的 UPDATE(更新) SQL 指令
$updateSQL = $conn->GetUpdateSQL($rs, $record);

$conn->Execute($updateSQL); # 更新資料庫中的記錄
$conn->Close();
?>

範例 8: 使用上一筆及下一筆實作捲動

我們使用HTTP取得 $next_page 變數,以追踪要跳去那一頁並且儲存目前頁碼在 session 變數 $curr_page 裡。

我們呼叫連結物件的 PageExecute()函收去取得我們要的資料集,然後我們使用資料集的 AtFirstPage() 及 AtLastPage() 函數去決定是否顯示下一頁和上一頁按鈕。

<?php
include_once('ADOdb.inc.php');
include_once('tohtml.inc.php');
session_register('curr_page');

$db = NewADOConnection('mysql');
$db->Connect('localhost','root','','xphplens');
$num_of_rows_per_page = 10;
$sql = 'select * from products';

if (isset($HTTP_GET_VARS['next_page']))
        $curr_page = $HTTP_GET_VARS['next_page'];
if (empty($curr_page)) $curr_page = 1; ## at first page

$rs = $db->PageExecute($sql, $num_of_rows_per_page, $curr_page);
if (!$rs) die('Query Failed');

if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage())) {
        if (!$rs->AtFirstPage()) {
?>
<a href="<?php echo $PHPSELF,'?next_page=',$rs->AbsolutePage() - 1 ?>">Previous page</a>
<?php
        }
        if (!$rs->AtLastPage()) {
?>
<a href="<?php echo $PHPSELF,'?next_page=',$rs->AbsolutePage() + 1 ?>">Next page</a>
<?php
        }
        rs2html($rs);
}
?>

以上的程式碼可以在 testpaging.php 範例裡找到。

使用自定錯誤處理及 PEAR_Error

在之前的版本,你可以使用像 $con->debug=true ; 這樣的設定來進行除錯。但在 1.50 版後,我們提供了另一種方法來處理錯誤狀態。我們讓工程師可以使用 ADODB 的自訂錯誤處理程序功能。

ADODB 提供了兩種自訂處理方式,你可以配合你的的需要而修訂。第一個方法放在 ADOdb-errorhandler.inc.php 檔案裡。這讓你可以使用標準的 PHP 函數 err_reporting 去控制要顯示怎樣的錯誤訊息及 trigger_error 去呼叫 PHP 預設的錯誤處理程序。

引入了上述檔案後(ADOdb-errorhandler.inc.php),當發生了下列的錯誤後,將會使得 trigger_error($errorstring,E_USER_ERROR)被呼叫。

  1. Connect() 或 PConnect() 執行失敗時。

  2. 執行 SQL 指令的函數失敗時,如 Execute() 或 SelectLimin() 。

  3. GenID() 進入了無限迴圈時。

這裡的 $errorstring 變數是由 ADODB 所產生的。而且會包含了有用的除錯訊息,類似於隨後會建立的 error.log 資料。所以,為了要能正確提供除錯訊息,你要在建立 ADOConnection 物件前,就把 ADOdb-errorhandler.inc.php 引入到程式碼中。

If you define error_reporting(0), no errors will be shown. If you set error_reporting(E_ALL), all errors will be displayed on the screen.

如果你設定了 error_reporting(0) 的話,將不會有任何錯誤被顯示。如果你設定了 error_reporting(E_ALL),那將會顯示所有的錯誤訊息。

以下是一個簡單的範例:

<?php
error_reporting(E_ALL); # 顯示所有的錯誤訊息
include('ADOdb-errorhandler.inc.php');
include('ADOdb.inc.php');
include('tohtml.inc.php');
$c = NewADOConnection('mysql');
$c->PConnect('localhost','root','','northwind');
$rs=$c->Execute('select * from productsz'); #不正確的資料表 productsz');
if ($rs) $rs2html($rs);
?>

如果你要把錯誤訊息記錄下來,你可以定義兩個選擇性常數 ADODB_ERROR_LOG_TYPE, ADODB_ERROR_LOG_DEST。有關於 ADODB_ERROR_LOG_TYPE 的值,你可以去參考 PHP 使用手冊中有關於 error_log 的說明。在以下的範例中,我使將它設為 3,意思是指將訊息記錄到常數 ADODB_ERROR_LOG_DEST 所設定的檔案中。

<?php
error_reporting(0); # 不顯示任何的錯誤訊息
define('ADODB_ERROR_LOG_TYPE',3);
define('ADODB_ERROR_LOG_DEST','C:/errors.log');
include('ADOdb-errorhandler.inc.php');
include('ADOdb.inc.php');
include('tohtml.inc.php');

$c = NewADOConnection('mysql');
$c->PConnect('localhost','root','','northwind');
$rs=$c->Execute('select * from productsz'); ## 不正確的資料表 productsz
if ($rs) $rs2html($rs);
?>

以下則是寫在 error.log 檔的錯誤訊息:

(2001-10-28 14:20:38) mysql error: [1146: Table 'northwind.productsz' doesn't exist] in
 EXECUTE("select * from productsz")

第二種錯誤處理方法是 ADOdb-errorpear.inc.php 。使用這種方式,在錯誤發生時會產生 PEAR_Error 衍生物件,而最後產生的 PEAR_Error 物件可以被 ADODB_Pear_Errir() 函數取回。

<?php
include('ADOdb-errorpear.inc.php');
include('ADOdb.inc.php');
include('tohtml.inc.php');
$c = NewADOConnection('mysql');
$c->PConnect('localhost','root','','northwind');
$rs=$c->Execute('select * from productsz'); #不正確的資料表 productsz');
if ($rs) $rs2html($rs);
else {
        $e = ADODB_Pear_Error();
        echo '<p>',$e->message(),'</p>';
}
?>

在引入 ADOdb-errorpear.inc.php 檔之前,藉由定義 ADODB_PEAR_ERROR_CLASS 常數,你可以使用一個 PEAR_Error 衍生類別。為了方便除錯,你可以在 PHP 程式碼的最前面定義預設的錯誤理方式為 PEAR_ERROR_DIE,這將會使得程式一出錯,馬上就輸出錯誤訊息,並且停止執行。

include('PEAR.php');
PEAR::setErrorHandling('PEAR_ERROR_DIE');

注意,當錯誤產生時,ADODB並沒有明確的回傳一個 PEAR_Error 物件給你。你必需要去呼叫 ADODB_Pear_Error() 函數去取回最後的錯誤內容。或者,你可以使用 PEAR_ERROR_DIE 這個技巧。

資料集快取

現在,ADODB使用 CacheExecute(),CachePageExecute()及CacheSelectLimit()函數來支援資料集快取。用法類似於沒有快取的函數,除了要加上一個新的參數 $secs2cache。

以下是一個範例 :

include('ADOdb.inc.php'); # 載入ADODB
$ADODB_CACHE_DIR = '/usr/ADODB_cache';
$conn = &ADONewConnection('mysql');  # 建立一個連結
$conn->PConnect('localhost','userid','','agora');# 連結到 MySQL, agora 資料庫
$sql = 'select CustomerName, CustomerID from customers';
$rs = $conn->CacheExecute(15,$sql);

第一個參數是設定查詢的快取秒數。隨後呼叫的查詢將會使用存放在由  $ADODB_CACHE_DIR 變數指定的快取資料。要強迫查訊執行,並且更新快取記錄,使用 CacheExecute() 函數,並且將第一個參數設為 0 。或者,使用 CacheFlush($sql) 也行。

基於安全的考量,如果你要使用 $ADODB_CACHE_DIR,我們建議你將在 php.ini 裡的 register_globals 設成 off。 

在 ADODB 1.80版以後,在 CacheSelectLimit() 及 CacheExecute() 中,參數 secs2cache 是選擇性的。如果你不填上去,系統將會使用 $connection->cacheSecs 屬性的值,它的預設值是 60 分鐘。

       $conn->Connect(...);
        $conn->cacheSecs = 3600*24; // 快取24小時
        $rs = $conn->CacheExecute('select * from table');

參考手冊

以[]包起來的參數為選用參數,可有可無。

共用變數

$ADODB_COUNTRECS

當本變數($ADODB_COUNTRECS)被設為 true 時,如果資料庫驅動程式介面(API)不支援回傳被 SELECT 指令所選取的資料筆數,那麼 RecordCount() 函數將會自動模擬,並回傳正確的資料筆數,預設值即為 true。模擬方式是建立一個記憶體暫存區來放置這些資料,因此當取回的資料筆數很大時,會佔用很大量的記憶體。當設定本變數值為 false 時,會有最好的效能。本變數在每次執行查訊時都會自動檢查,所以你可以依實際需要在每次查詢前進行設定。

$ADODB_CACHE_DIR

如果你使用了資料集快取功能,那麼那些快取資料都會被置放到這個變數所指定的目錄裡。所以當你要使用諸如 CacheExecute() 函數前,你應該要先設定好本變數。期於安全的考量,如果你要使用 $ADODB_CACHE_DIR,我們建議你將在 php.ini 裡的 register_globals 設成 off。 

$ADODB_FETCH_MODE

這個共用變數決定了資料集以那種方式將資料傳給陣列。資料集在被建立時(如 Execute()或SelectLimit())會把本變數($ADODB_FETCH_MODE)的值保存下來,而隨後本變數($ADODB_FETCH_MODE)的任何改變都不會影響到現存的資料集,只有在以後資料集被建立起來時才會改變。

以下為為已定義的常數:

define('ADODB_FETCH_DEFAULT',0);
define('ADODB_FETCH_NUM',1);
define('ADODB_FETCH_ASSOC',2);
define('ADODB_FETCH_BOTH',3);

以下為一個使用的例子:

       $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
        $rs1 = $db->Execute('select * from table');
        $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
        $rs2 = $db->Execute('select * from table');
        print_r($rs1->fields); # 顯示 array([0]=>'v0',[1] =>'v1')
        print_r($rs2->fields); # 顯示 array(['col1']=>'v0',['col2'] =>'v1')

在本範例中,如你所見兩個資料集在被Execute()建立時,會依據 $ADODB_FERCH_MODE 的值來決定儲存及使用的存取模式。

如果沒有任何的模式被設定,預設值則是 ADODB_FETCH_DEFAULT。呈現的模式則依據資料庫驅動程式而有所不同。為了可攜性,我們建議你固定為 ADODB_FETCH_NUM 及 ADODB_FETCH_ASSOC,因為有許多驅動程式並不支援 ADODB_FETCH_BOTH 。


ADOConnection

提供連結資料庫,執行SQL指令以及一組準格式化的SQL相關函數等功能的物件。

ADOConnection 屬性

databaseType: 要連結的資料庫系統名稱,如 odbc,mssql,mysql…等。詳細內容請參考上表。

dataProvider: 下層的資料庫結結機制,除了使用 odbcado 外,一般正常會設為  native

host: 資料庫主機名稱,可用IP或來源名稱(DSN)進行連結。如203.74.225.22 , dbs1.nukepro.com , "localhost" , "odbc_dsn1"

database: 資料庫或連結名稱,如果使用了 ado,則會控制 ado 資料提供驅動程式(ado data provider)。

user: 登入時的 ID,密碼則基於安全考量沒有保留。

raiseErrorFn: 允許你定義一個錯誤處理函數,請參考 ADOdb-errorhandler.inc.php 的範例.

debug: 被設定為 true 時,會顯示除錯訊息。

concat_operator: 連結運算元,一般會設為 '+' 或 '||'。這個運算元是為了在 SQL 裡連結字串的。會在 Concat 函數中被用到。

fmtDate: 日期格式,在DBDate函數中會使用到,做為送日期資料到資料庫的依據。在Access格式為'#Y-m-d#',在MySQL格式為"\Y-m-d\"。

fmtTimeStamp: 時間格式,在 DBTimeStamp 函數中要送時間資料到資料庫時會使用到。

true: 資料中真值的表現方式,如在Foxpro用'T',MS SQL用'1'。

false: 資料中假值的表現方式,如在Foxpro用'F',MS SQL用'0'。

replaceQuote: 這個字串用來處理逸出符號。例如在 Microsoft SQL 裡的雙引號,MySQL裡的反斜線符號。主要使用於 qstr

autoCommit: 設定是否啟動自動交易模式,預設值為 true。

charSet: 設定使用的字元集,目前只有 interbase 支援。

metaTablesSQL: 使用SQL指令,以回傳一份可用的資料表清單。例如在 MySQL 裡的 SHOW TABLES。

genID: 如果資料庫有支援的話,這裡會存放由GetID()所取得的最後值。

cacheSecs: 快取資料集的秒數。用於當使用者利用 CacheExecute() 或 CacheSeletLimit() 函數,又沒有設定 $secs2cache 參數時的預設值。

sysDate: 利用資料庫函數去取得目前的日期和時間。會使用到原生的日期時間標記格式。


ADOConnection 主要函數

ADOConnection( )

建構函數,請不要直接呼叫,使用 ADONewConnection() 來代替。

Connect($host,[$user],[$password],[$database])

對伺服器或資料來源 $host 非持續性連結,使用者認證代碼為 $user ,密碼為 $password ,如果伺服器支援多資料庫,則指定連結到資料庫 $database

連結成功回傳 true , 失敗則回傳 false 。

注意:如果你使用的是 Microsoft ADO,而非 OLEDB,你可以設定 $database 參數為你正在使用的 OLEDB 資料供應器。

PostgreSQL:另一種選擇性的連結方法是將標準的PostgreSQL連結字串放在 $host 參數裡,那麼其它的參數都會被呼略。

對於 Oracle 及 Oci8,有兩個方法可以連結。第一,使用你定義的區域 tnsnames.ora 裡的 TNS 名稱,將這個名稱放在 $database 參數裡,然後將 $host 設為 false。另一種方法,設定 $host 為伺服器,而 $database 則設成資料庫 SID ,這將會不透過 tnsnames.ora 連結。

範例:

 $conn->Connect(false, 'scott', 'tiger', 'name_in_tnsnames'); # 使用 tnsnames.ora
 $conn->Connect('server:1521', 'scott', 'tiger', 'OracleSID'); # 不使用 tnsnames.ora

還有許多的資料庫連結範例在網站 php.weblogs.com/ADOdb 以及在本版所附的 testdatabase.inc.php 檔案裡。

PConnect($host,[$user],[$password],[$database])

對伺服器或資料來源 $host 持續性連結,使用者認證代碼為 $user ,密碼為 $password ,如果伺服器支援多資料庫,則指定連結到資料庫 $database

連結成功回傳 true , 失敗則回傳 false 。其它資料請參考 Connect()。

Execute($sql,$inputarr=false)

執行 SQL 指令 $sql ,如果成功,就回傳一個對應的 ADORecordSet 物件。要注意的是這個指令如果執行成功時,一定會回傳一個資料集,即使是執行 insert 或 update 指令也一樣。

回傳對應的 ADORecordSet 物件。例如,如果連結的是 mysql ,那麼 ADORecordSet_mysql 將會被回傳。當SQL指令執行失敗時會回傳 false 值。

$inputarr 參數則用來做為傳入的結合變數。以下是 Oracle 的範例:

 $conn->Execute("SELECT * FROM TABLE WHERE COND=:val", array('val'=> $val));
 

另一個例子,使用 ODBC ,以 '?' 符號做為協定。

  $conn->Execute("SELECT * FROM TABLE WHERE COND=?", array($val));

結合變數(Binding variables)
變數的結合可以加速SQL指令編譯及快取的速度,產生較佳的效能。目前只有 Oracle 及 ODBC 支援變數結合。 ODBC 類的 ? 結合在不支援的資料庫裡,是以模擬的方式來做到的。

變數結合在 odbc 及 oci8po 驅動程式裡的用法。

$rs = $db->Execute('select * from table where val=?', array('10'));

變數結合在 oci8 驅動程式裡的用法。

$rs = $db->Execute('select name from table where val=:key',array('key' => 10));

CacheExecute($secs2cache,$sql,$inputarr=false)

類似於 Execute 函數,除了將資料集暫存在 $ADODB_CACHE_DIR 指定的目錄裡 $secs2cache 秒外。如果 CacheExecute() 被相同的參數、資料庫、使用者ID及密碼,而且快取也沒有過期,那麼快取中的資料集將會被傳回。

  include('ADOdb.inc.php'); 
  include('tohtml.inc.php');
  $ADODB_CACHE_DIR = '/usr/local/ADOdbcache';
  $conn = &ADONewConnection('mysql'); 
  $conn->PConnect('localhost','userid','password','database');
  $rs = $conn->CacheExecute(15, 'select * from table'); # 快取15秒
  rs2html($rs); /* recordset to html table */  

另外,從ADODB 1.80 版起,$secs2cache 參數成為選擇性(也就是可以不加)

       $conn->Connect(...);
        $conn->cacheSecs = 3600*24; // cache 24 hours
        $rs = $conn->CacheExecute('select * from table');

如果 CacheExecute() 被多次呼叫,而且資料集也持續在快取中,$secs2cache 參數不會延長被快取的資料集保留時間(因為會被呼略掉),CacheExecute()只能使用在 SELECT 指令上。

效能備註:曾經作了一些效能測試,並且發現這些快取的效益極為顯著。尤其是在資料庫伺服器運作效率慢於WEB伺服器或資料庫的負荷非常重的時候。ADODB的快取好在它減少了資料庫伺服器的負荷。當然,如果你的資料庫伺服器負荷不大,而且運作速度也比WEB伺服器快,那快取反而會降低效能。

SelectLimit($sql,$numrows=-1,$offset=-1,$inputarr=false)

執行成功會回傳一個資料集。完成一個SELECT指令,類似於 PostgreSQL中 SELECT 指令裡的LIMIT $numrows OFFSET $offset 宣告。

在 PostgreSQL,SELECT * FROM TABLE LIMIT 3 將會只傳回從頭開始的三筆記錄。相同的,$connection->SelectLimit('SELECT * FROM TABLE',3)也有同樣的意思。

而 SELECT * FROM TABLE LIMIT 3 OFFSET 2 將會回傳記錄 3,4及5三筆(也就是在記錄2之後,回傳三筆記錄)。相同的,在ADODB裡是以 $connection->SelectLimit('SELECT * FROM TABLE',3,2) 來做的。

要注意,LIMIT宣告,在MySQL裡是相反位置的。你可以設定 $connection->SelectLimit('select * from table',-1,10) 去取得從第11筆起到最後一筆的記錄。

最後一個參數 $inputarr 是針對支援變數結合功能的資料庫,像 Oracle oci8。這個大大的減少了 SQL 編譯的負荷。底下是 Oracle 範例:

 $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=:val", 100,-1,array('val'=> $val));
 

oci8po 驅動程式(oracle portable driver)使用更為標準的變數結合:

 $conn->SelectLimit("SELECT * FROM TABLE WHERE COND=?", 100,-1,array('val'=> $val));

Ron Wilson 報告說 SelectLimit 在SQL指令有含 UNION 時會無效,並且建議了針對 mssql 的對策:

> 事實上,我發現一個可以立即最佳化的建構 Select Union 方法。這適用於 MS-SQL,至於
其它資料庫是否適合,就不確定了。當更新求助檔時,你可以參考這個範例。注意,這個方
法不適用於 MySQL。
>
> 改變:
>  Select column1 From table1
>  Union
>  Select column2 From table2
> 
> 成為:
>  Select * From (
>   Select column1 From table1
>   Union
>   Select column2 From table2
>   )
>  As dummytable
> 
> Ron

CacheSelectLimit($secs2cache, $sql, $numrows=-1,$offset=-1,$inputarr=false)

類似於 SelectLimit,除了將資料集暫存在 $ADODB_CACHE_DIR 指定的目錄裡 $secs2cache 秒外。

自 1.80版起,$secs2cache成為了選擇性參數:

 $conn->Connect(...);
        $conn->cacheSecs = 3600*24; // 快取24小時
        $rs = $conn->CacheSelectLimit('select * from table',10);

CacheFlush($sql)

更新(刪除)以 $sql 指令存放在 $ADODB_CACHE_DIR 指定目錄內的全部快取資料集。如果你企圖更新所有的快取資料集,請執行如下的PHP指令碼(僅針對 Unix 有效):system("rm -f find ".ADODB_CACH_DIR." -name ADODB_*.cache") ;

ErrorMsg()

回傳最後狀態或是錯誤訊息。即使沒有錯誤發生,本函數也會回傳一個字串。一般情況下,你不需要呼叫這個函數,除非ADODB函數因為錯誤狀態回傳了false值。

注意:如果 debug 旗標被啟動了,SQL 錯誤訊息將會在Execute函數被呼叫時發生錯誤後出現。

ErrorNo()

回傳最後的錯誤號碼。注意一點,舊版本的 PHP(4.0.6以前),不支援ODBC的錯誤編號。一般情況下,你不需要呼叫這個函數,除非ADODB函數因為錯誤狀態回傳了false值。

GenID($seqName = 'ADOdbseq',$startID=1)

產生一個順序號碼(在mssql是一個整數值)。對 interbase,mysql,postgresql,oci8,oci8po,ODBC核心類驅動程式(如 access,vfp,db2等等) 都支援。使用 $seqName做為順序名。如果資料庫沒有值,那麼GenID()將會自動為你產生一個序號(產生使用者 id 時允許如此),換句話說,你必需自行建立序號。

如果你的資料庫驅動程式要模擬序號,資料表的名稱就是序號名(sequence name),而這個資料表必需有一個欄位"id",而其資料型別為整數,或你需要更大些的 numeric(16)。

對於沒有支援序號原生功能的ODBC及資料庫(如 mssql,mysql),我們對每一個序號建立一個資料表。如果序號沒有被預先定義,那啟如的號碼值就設定成 $startID。

注意,mssql驅動程式的 GenID()會產生一個16位元的GUID。自1.90版起,我們將回傳整數。

UpdateBlob($table,$column,$val,$where)

允許你以 $where 條件儲存一個BLOB(存在 $val裡的)值到 $table 裡的 $column 欄位。

例:

 

       # for oracle
        $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, empty_blob())');
        $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');

        # non oracle databases
        $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
        $conn->UpdateBlob('blobtable','blobcol',$blobvalue,'id=1');

如果成功,會回傳 true ,否則回傳 false 值。目前有 MySQL, PostgreSQL, Oci8, Oci8po 及 Interbase 支援。其它驅動程式可能有效,仍在持續開發中。

要注意,在PHP 4.1.0 以前的版本,當 Interbase的 blob 值被 SELECT 取回值時,它仍需要被解碼,請使用 $connection->DecodeBlob($blob); 以還原它的內容。

UpdateClob($table,$column,$val,$where)

允許你以 $where 條件儲存一個BLOB(存在 $val裡的)值到 $table 裡的 $column 欄位。類似於 UpdateBlog,但主要針對文字大型檔案物件。

例:

 

       # for oracle
        $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, empty_clob())');
        $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');

        # non oracle databases
        $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');
        $conn->UpdateBlob('clobtable','clobcol',$clobvalue,'id=1');

UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')

如同 UpdateBlob ,但我們將值改成一個檔案路徑,將整個檔案存入。

成功回傳 true 否則為 false。

GetUpdateSQL(&$rs, $arrFields, $forceUpdate=false,$magicq=false)

建立一個 SQL 以更新一個被給予的資料集 $rs ,被修改的欄位存放在陣列 $arrFields中(這個陣列必需是具名陣列,欄位名為索引,值為修正值),會與原來的資料集做一個比較,如果 $forceUpdate被設為 true,那麼即使 $arrFields與 $rs->fields完全相同,也會產生出更新的SQL指令。資料集必需在連結狀態。$magicq 被用於指出魔術引號功能是否被啟動。

GetInsertSQL(&$rs, $arrFields,$magicq=false)

建立一個 SQL 以新增一筆記錄到被給予的資料集 $rs。這個查詢必需是在連結狀態。$magicq 被用於指出魔術引號功能是否被啟動。

PageExecute($sql, $nrows, $page, $inputarr=false)

使用資料集的頁碼功能,參數 $page 是以 1 為啟使值,請參考範例 8.

CachePageExecute($secs2cache, $sql, $nrows, $page, $inputarr=false)

使用資料集的頁碼功能,參數 $page 是以 1 為啟使值,請參考範例 8.PageExecute 的快取版。

Close( )

關閉資料庫的連結。PHP4 以資料庫連結結束時不需要特別去清除而享有盛名,因為其參考計數機制會自動幫我們清除掉。

BeginTrans( )

啟始一筆交易。會關閉自動結案功能。執行成功會回傳 true 。如果不支援交易功能,部份資料庫會一直傳回 false 值。Interbase,Oracle 及 MSSQL 支援交易機制。請注意,因為 PHP 4.02 版的臭蟲,交易支援在微軟的 ADO 上是無效的。你必需使用你關連式資料庫的原生交易支援功能。當連結結束時,任何開啟的交易都會被還原。

CommitTrans( )

成功的結束一次交易。如果成功,回傳 true。如果資料庫並不支援交易功能,那麼就只會傳回 true ,以表示資料總是交易成功的。

RollbackTrans( )

結束一次交易,恢復所有改變。執行成功會回傳 true 。如果資料庫並不支援交易功能,那麼就只會傳回 false ,以表示資料總是不能恢復。

GetOne($sql)

Executes the SQL and returns the first field of the first row as an array. The recordset and remaining rows are discarded for you automatically. If an error occur, false is returned.

執行SQL指令,並且以陣列的方式回傳第一筆記錄的第一個欄位。資料集及其餘的記錄將會被自動清除,如果發生錯誤,就回傳 false 值。

譯者注:這個功能在驗證某筆記錄在不在特別有用,可以減少系統記憶體及資源的用量。

GetRow($sql)

執行SQL指令,並且以陣列的方式回傳第一筆記錄。資料集及其餘的記錄將會被自動清除,如果發生錯誤,就回傳 false 值。

Prepare($sql )

預先編譯一個SQL查詢,以便於重覆執行。如果有任何語法錯誤,Prepare()不會顯示任合錯誤,但允許 Execute() 去取得及顯示錯誤。內部實作支援 interbase ,oci8 及選擇性的 ODBC-based 驅動程式。其餘的都是以模擬的方式支援。在模擬的情況下,使用 Prepare() 對效能的增進沒有任何效果。

回傳一個包含了原始描述為第一個陣列元素的陣列,其餘的元素內容則視驅動程式而定。如果有錯誤或是模擬方式的 Prepare(),會回傳原來的 $sql 字串。那是因為所有的錯誤處理都被集中到 Execute() 裡去了。

範例 :

$stmt = $DB->Prepare('insert into table (col1,col2) values (?,?)');
for ($i=0; $i < $max; $i++)
 $DB->Execute($stmt,array((string) rand(), $i));

PrepareSP($sql)

在 mssql 驅動程式裡,預編譯預儲程式必需要透過一個特別的函數來呼叫 mssql_init(),這個動作目前由本函數來處理了。PrepareSP() 可以在所有的驅動程式由被呼叫,而且以呼叫 Prepare() 的方式來模擬。使用範例請參考以下的 Parameter() 說明。

和上面的 Prepare() 回傳一樣的陣列或 $sql 字串。

Parameter($stmt, $var, $name, $isOutput=false, $maxLen = 4000, $type = false )

在運作中增加一個結合參數。目前相容於 Microsoft SQL 及 Oracle oci8。以下是參數說明:


$stmt  由 Prepare() 或 PrepareSP() 回傳的指令。
$var 要結合的 PHP 變數。
$name 要結合的預儲程序的變數名。
[$isOutput] 設定參數傳導的方向,0/false = IN 1=OUT 2= IN/OUT 。 在 oci8 中這個參數會被忽略,因為驅動程式會自動偵測。 
[$maxLen] 參數變數的最大長度。
[$type] 參考 mssql_bindocibindbyname 在 PHP.NET 的文件說明以取得更多正確值的資訊。

在 mssql,$opt 可以被下列的元素所影響:mssql_bind and ocibindbyname 。 例如 ;

# @RETVAL = SP_RUNSOMETHING @myid,@group
$stmt = $db->PrepareSP('SP_RUNSOMETHING'); 
# note that the parameter name does not have @ in front!
$db->Parameter($stmt,$id,'myid'); 
$db->Parameter($stmt,$group,'group',false,64);
# return value in mssql - RETVAL is hard-coded name 
$db->Parameter($stmt,$ret,'RETVAL',true); 
$db->Execute($stmt); 

一個 oci8 的例子:

# 對於 oracle, Prepare 及 PrepareSP 是相同的
$stmt = $db->PrepareSP(
        "declare ret integer;
     begin 
                :RETVAL := SP_RUNSOMETHING(:myid,:group);
     end;");
$db->Parameter($stmt,$id,'myid');
$db->Parameter($stmt,$group,'group',false,64);
$db->Parameter($stmt,$ret,'RETVAL',true);
$db->Execute($stmt);

請注意,在 oci8 及 mssql 間只有語法上的不同,那是各資料庫實作 SQL 語法問題,ADODB 對於這一部份無能為力。

如果 $type 參數被設定成 false 。在 mssql ,$type 將會動態的由 PHP 變數傳來的型別決定(string => SQLCHAR, boolean =>SQLINT1, integer =>SQLINT4 或  float/double=>SQLFLT8),在 oci8,$type 可以被設成 OCI_B_FILE (Binary-File), OCI_B_CFILE (Character-File), OCI_B_CLOB (Character-LOB), OCI_B_BLOB (Binary-LOB) 及 OCI_B_ROWID (ROWID)。如果要傳入空值,使用  $db->Parameter($stmt, $null=null, 'param')。

最後,在 oci8,結合參數可以重覆被使用,而無需再一次呼叫 PrepareSP() 或 Parameters。但這對 mssql 是不行的。一個 oci8 的範例如下:

$id = 0; $i = 0;
$stmt = $db->PrepareSP( "update table set val=:i where id=:id");
$db->Parameter($stmt,$id,'id');
$db->Parameter($stmt,$i, 'i');
for ($cnt=0; $cnt < 1000; $cnt++) {
        $id = $cnt;
        $i = $cnt * $cnt; # oci8 下可以運作
        $db->Execute($stmt);
}

Bind($stmt, $var, $size=4001, $type=false, $name=false)

這是一個低階函數,只有 oci8 驅動程式支援。只有你確定系統僅支援 Oracle 否則請避免使用它。Parameter() 函數是使用結合變數的另一個建議方式。

Bind() 允許你使用結合變數在你的 sql 敘述中。這裡結合一個PHP變數給一個在之前被 Prepare() 預先編譯的 Oracle sql 敘述裡定義的名稱。Oracle 以一個冒號為開頭來命名一個變數,而且 ADODB 需要一個被命名的變數去對應 :0,:1,:2,:3,等等。第一次被 Bind() 取得的將會代入 :0,而第二次將會代入 :1,依此類推。對 insert , select 及 update 指令,結合可以提供 100% 的效能提昇。

在其餘的參數裡,$size 設定資料儲存的暫存區大小,$type 是 OCI_B_FILE (Binary-File), OCI_B_CFILE (Character-File), OCI_B_CLOB (Character-LOB), OCI_B_BLOB (Binary-LOB) 及 OCI_B_ROWID (ROWID) 的類別選項。最後,代替使用預設的 :0,:1 等等名稱,你可以使用 $name 來定義你自己的連結名稱。

接下來的例子展示3個連結變數,使用 p1,p2及p3來結合。這些變數將會配到 :0 , :1 及 :2 。

$stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
$DB->Bind($stmt, $p1);
$DB->Bind($stmt, $p2);
$DB->Bind($stmt, $p3);
for ($i = 0; $i < $max; $i++) { 
   $p1 = ?; $p2 = ?; $p3 = ?;
   $DB->Execute($stmt);
}

你也可以使用名稱變數:

$stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:name0, :name1, :name2)");
$DB->Bind($stmt, $p1, "name0");
$DB->Bind($stmt, $p2, "name1");
$DB->Bind($stmt, $p3, "name2");
for ($i = 0; $i < $max; $i++) { 
   $p1 = ?; $p2 = ?; $p3 = ?;
   $DB->Execute($stmt);
}

ADOConnection 公用函數

BlankRecordSet([$queryid])

不再使用,本版已移除。

Concat($s1,$s2,....)

產生一個結合 $s1,$s2,..等 sql 字串的字串,使用了在 concat_operator 欄位定義的結合運算符號。如果結合運算符號不被使用,那這個函數將無效,例如 MySQL 。

本函數回傳含結合符號的字串。

DBDate($date)

格式化 $date 成資料庫可以接收的格式,這可以是一個 Unix 整數時間記錄格式或是一個 ISO 格式的 Y-m-d。使用 fmtDate 欄位所定義的格式。如果傳入的是 null 或是 false 或是 '' ,那將會轉成一個 SQL 的 null。

回傳一個日期字串。

DBTimeStamp($ts)

格式化時間記錄格式的 $ts 成資料庫可接受的格式。這可以是一個 Unix 整數時間記錄格式或是一個 ISO 格式的 Y-m-d。使用 fmtDate 欄位所定義的格式。如果傳入的是 null 或是 false 或是 '' ,那將會轉成一個 SQL 的 null。

回傳一個時間字串。

qstr($s,[$magic_quotes_enabled=false])

將一個字串放在引號內,以送到資料庫中。$magic_quotes_enabled 參數可能看起來很有趣,但這個想法是假設你已經用一個引號來處理了從 POST/GET 變數取來的字串後,然後以 get_magic_quotes_gpc() 做為第二個參數。這會確定這個變數不會被引號處理二次,一次被 qstr 處理,一次被 magic_quotes_gqc

例如:  $s = $db->qstr(HTTP_GET_VARS['name'],get_magic_quotes_gpc());

回傳值是一個被引號處理過的字串。

Affected_Rows( )

回傳被SQL指令更新或被刪除掉的資料筆數。如果資料庫不支援,回傳一個 false 值。

目前 interbase/firebird 不支援本函數。

Insert_ID( )

回傳最後插入時的自動增進值 ID。如果系統不支援,回傳 false。

只支援有提供自動增進或物件 ID 的資料庫,目前像是 PostgreSQL, MySQL 以及 MSSQL 都有。PostgreSQL 回傳一個 OID,可以在資料庫重載入時改變。只有使用持續連結方式,當你完成一筆交易時,這個函數才會有精確的結果。這是因為被 Execute() 宣告的連結可能和下一個 Execute() 時用的連結不同。

MetaDatabases()

回傳一個在伺服器中的資料庫清單於陣列裡。首先你必需連結到伺服器。目前只支援 ODBC, MySQL 及 ADO。

MetaTables()

回傳目前資料庫中全部資料表名稱於一個陣列中。如果可能,這個陣列將會排除系統目錄資料表。

MetaColumns($table)

回傳一個 ADOFieldObject 的陣列,一個欄位物件對應到一個 $table 的所有行。目前 Sybase 不能辨別資料型別,ADO 不能辨識正確的資料型別(所以我們預設為 varchar)..

MetaColumnNames($table)

回傳 $table 的行名於一個陣列中。


ADORecordSet(資料集)

當一個SQL指令成功的被 ADOConnection->Execute($sql)執行後,一個 ADORecordSet 物件會被回傳回來。這個物件提供了一個虛擬的指標,所以我們可以移動它,從一筆到一筆。也提供一些函數,以取得欄位資訊和欄位類別,並有協助函數去格式化結果,以展示給使用者看。

ADORecordSet 屬性

fields: 包含了目前記錄的陣列。不是關連式陣列,但它的索引值是從 0 到 欄位數 - 1。請參考函數 Fields ,這個函數的動作就像是一個關連式陣列。

dataProvider: 連結資料庫的底層機制,正常設定為 native ,除非是使用 odbcado

blobSize: 一個 char , string 或者 varchar object 在被轉成 Blob 前的最大長度(Blob 在顯示時應該使用 textarea)。其它請參考 MetaType 函數。

sql: 儲存了建立本資料集所使用的 sql 指令。

canSeek: 如果 Move() 函數有作用,會被設成 true 。

EOF: 當指標被移動到最後一筆時,這個值會被設定成 true 。

ADORecordSet 函數

ADORecordSet( )

建構函數。一般來說你不需要自己呼叫這個函數。

GetAssoc([$force_array])

如果欄位數大於 2 ,那麼從資料集中產生一個關連式陣列。這個陣列是從目前的指標起一直到檔尾(EOF)。這個資料集的第一個欄位會成為陣列的索引。如果欄位數剛好是2,當這陣列被每一個鍵值所建立時,那麼索引會直接對應到值,除非  $force_array 被設成 true 。

範例:

以下是我們資料集的資料:

列1: Apple, Fruit, Edible
列2: Cactus, Plant, Inedible
列3: Rose, Flower, Edible

GetAssociation 將會產生一個如下的關聯式陣列:

Apple => [Fruit, Edible]
Cactus => [Plant, Inedible]
Rose => [Flower,Edible]

回傳值:

關連式陣列,錯誤則傳回 false 。

GetArray([$number_of_rows])

從目前指標位置產生一個陣列,索引值從 0 到 $number_of_rows - 1 。如果 $number_of_rows 沒有被定義,那會到檔尾(EOF)。

GetRows([$number_of_rows])

是 GetArray() 的同義函數,是為了與 Microsoft ADO 相容才有的。

GetMenu($name, [$default_str=''], [$blank1stItem=true], [$multiple_select=false], [$size=0], [$moreAttr=''])

建立一個 HTML 選單  (<select><option><option></select>) 。資料集的第一欄 (fields[0]) 將會作為 <option> 裡的顯示字串。如果資料集有超過一個以上的欄位,第二欄 (fields[1]) 將設定成回傳給WEB伺服器的值(即 value)。選單將被給予 $name 為名稱。

如果 $default_str 被定義了,那麼如果 $default_str == fields[0] , 那麼這個欄位將會被選取。 如果 $blank1stItem 為 true ,那第一個選項將會是空值。$Default_str 在對於可多選清單盒時,可以是一個陣列。

要產生一個選單區,設定 $size 為一個非 0 值(或者傳入 $default_str 為一個陣列)。如果 $multiple_select 為 true ,那麼一個選單區將會被產生成有 $size 個項目可見的選單(如果 $size ==  0 那預設為 5 個),而且ADODB將會回傳一個陣列給伺服器。最後,你可以使用 $moreAttr 去增加其它的屬性,像是 javascript 或樣式表。

選單範例 1: GetMenu('menu1','A',true) 將會產生一個像這樣的選單 : A B C 這裡的資料 (A,1), (B,2), (C,3). 請參考 範例 5

選單範例 2: 相同的資料, GetMenu('menu1',array('A','B'),false) 將會產生一個 A 及 B 被選取的選單 : A B C

GetMenu2($name, [$default_str=''], [$blank1stItem=true], [$multiple_select=false], [$size=0], [$moreAttr=''])

近似於 GetMenu ,除了 $default_str 將會和 fields[1] 做比對也就是選項值。

選單範 3: 給予在範例 2 裡的資料 , GetMenu2('menu1',array('1','2'),false) 將會產生一個選單,A及B將會被選取。然而,這一次的被選取的比對基準是第二個欄位,也就是存放要被回傳給伺服器裡的值。

UserDate($str, [$fmt])

轉換日期字串 $str 為另一個格式,UserDate 呼叫 UnixDate 來解譯 $str ,而 $fmt 預設值是 Y-m-d 。

UserTimeStamp($str, [$fmt])

轉換時間字串 $str 為另一個格式,時間字串格式是 Y-m-d H:i:s , 像是 "2002-02-28 23:00:12"。UserTimeStamp 呼叫 UnixTimeStamp 來解譯 $str ,而 $fmt 預設值為 Y-m-d H:i:s 。

UnixDate($str)

將日期字串 $str 解譯,並且轉換成 unix mktime 格式(從 1970.01.01 00:00:00 起到現在的秒數)後傳回。預設日期是以 Y-m-d H:i:s 格式來傳入的。而對於 Sybase 及 Microsoft SQL Server 而言 M d Y 也是可以接受的(三個字元的月份表示法是被一個全域陣列所控制的,這個部份可能需要在地化 )。

自 1.91 版起,這個函數存在於 ADORecordSet 及 ADOConnection兩個地方。

UnixTimeStamp($str)

將時間字串 $str 解譯,並且轉換成 unix mktime 格式(從 1970.01.01 00:00:00 起到現在的秒數)後傳回。預設日期是以 Y-m-d H:i:s 格式來傳入的。而對於 Sybase 及 Microsoft SQL Server 而言 M d Y 也是可以接受的(三個字元的月份表示法是被一個全域陣列所控制的,這個部份可能需要在地化 )。

自 1.91 版起,這個函數存在於 ADORecordSet 及 ADOConnection兩個地方。

MoveNext( )

移動內部指標到下一筆,fields 陣列將會自動的更新。如果不能移動,會回傳 false 值,其它情況則會回傳 true 。

範例 :

$rs = $db->Execute($sql);
if ($rs) 
        while (!$rs->EOF) {
                ProcessArray($rs->fields);
                $rs->MoveNext();
        } 

Move($to)

移動內部指標到指定的列 ($to) 。 列數是零基的,例如,0是第一列。fields 陣列將會自動更新。對於不支援內部卷動的資料庫,ADODB將會自動模擬捲動。部份資料庫不支援向後捲動。對大多數的資料庫言,如果 $to 的位置在 EOF 之後,$to 將會被移動到資料集的最後一筆。有些無名的資料庫使用 odbc 時,可能會沒有動作。

注意:這個函數使用了絕對定址,不像 Microsoft 的 ADO。

回傳值是 true 或是 false。如果是 false ,這個內部指標在大多數的實際運作上並沒有移動,所以 AbsolutePosition() 將會回傳指標在執行 Move() 之前最後的位置

MoveFirst()

實際上是呼叫 Move(0) 。注意,有一些資料庫並不支援這個函數。

MoveLast()

實際上是呼叫 Move(RecordCount() - 1)。注意,有一些資料庫並不支援這個函數。

GetRowAssoc($toUpper=true)

這個函數並不能持續的以理想的方式維持關連陣列的內容(每換一筆記錄,就要重新執行一次)。使用 $ADODB_FETCH_MODE 共用變數來替代它。

回傳一個包含了目前記錄的關連式陣列,陣列的索引值就是欄位名。欄位名全都是大寫的,以便存取。要取得下一筆記錄,你要呼叫 MoveNext() 。

範例 :
Array ( [ID] => 1 [FIRSTNAME] => Caroline [LASTNAME] => Miranda [CREATED] => 2001-07-05 )

註意:不要同時使用 GetRowAssoc() 和 $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC 。因為他們有相同的功能,會彼此交互干擾。

AbsolutePage($page=-1)

回傳目前的頁碼,需要先呼叫 PageExecute() / CachePageExecute() 。參考 Example 8

AtFirstPage($status='')

如果在第一頁,回傳 true (1基式),需要先呼叫 PageExecute() / CachePageExecute() 。參考 Example 8

AtLastPage($status='')

如果在最後一頁,回傳 true (1基式),需要先呼叫 PageExecute() / CachePageExecute() 。參考 Example 8

Fields($colname)

不鼓勵使用,請改以 $ADODB_FETCH_MODE 取代。

當使用原生函數庫時,有些資料庫函數回傳具名及索引雙陣列(如 MySQL)。GetRowAssoc() 並不回傳結合了具名及索引的陣列元素。

本函數回傳由 $colname 所指欄名,在目前記錄裡的的欄位值。

欄位名區分大小寫。

FetchRow()

回傳目前記錄內容的陣列,如果是檔尾(EOF),回傳 false 。注意:不要把 FetchRow 和 MoveNext() 混用。

用法 :

$rs = $db->Execute($sql);
if ($rs)
        while ($arr = $rs->FetchRow()) {
           # process $arr
        }

FetchInto(&$array)

設定 $array 到目前的記錄裡。如果在檔尾(EOF),回傳 PEAR_Error 物件。如果成功,回傳 1 (DB_OK 常數)。

如果 PEAR 未定義,當 EOF 時回傳 false 。FetchRow() 很容易使用,請參考之前的例子。

FetchField($column_number)

回傳一個物件,包含了所指欄位的名稱,類別及最大長度。如果最大長度不能被明確決定,將會回傳 -1 。 行號是以 0 基為計算起點的,請參考 範例 2

FieldCount( )

回傳資料集裡欄位數。

RecordCount( )

回傳資料集裡的記錄筆數。如果無法從資料庫驅動程式API裡取得正確的數字,ADODB將會把所有的記錄內容,存放在記憶體裡,等全部取完後,再回傳記錄總筆數。這個記憶體可以藉由設定全域變數 $ADODB_COUNTERECS = false 而被取消(基於執行效能的理由)。當取消後,對某些資料庫,RecordCount() 將會回傳 -1 。相關支援狀況,請參考前面的資料庫支援表有詳細的說明。

RowCount 和 RecordCount 是同義函數。

PO_RecordCount($table, $where)

回傳在資料集裡的記錄筆數。如果資料庫不支援,那麼將回傳對 $table 資料表下達以 $where 為條件的 SELECT COUNT(*) 指令後回傳的值。

$numrows = $rs->PO_RecordCount("articles_table", "group=$group");

會回傳資料庫執行 SELECT COUNT(*) FROM articles_table WHERE group=$group 的結果。

FetchObject($toupper=true)

回傳目前的記錄為一個物件。如果 $toupper 為 true ,那麼物件欄位名將會設為大寫。注意:較新的 FetchNextObject() 是取得記錄物件較被建議的方式,請參看後續說明。

FetchNextObject($toupper=true)

取得目前的記錄成一個物件,並且自動移動到下一個記錄。如果在檔尾,回傳 false 。如果 $toupper 為 true ,那麼物件欄位名將會設為大寫。

$rs = $db->Execute('select firstname,lastname from table');
if ($rs) {
        while ($o = $rs->FetchNextObject()) {
                print "$o->FIRSTNAME, $o->LASTNAME<BR>";
        }
}

在使用 FetchNextObject() 時會影響效能,如果效能很重要,你應該使用 fields[] 陣列來存取。

CurrentRow( )

目傳目前資料集的記錄編號,0 表示是第一筆。

AbsolutePosition( )

和 CurrentRow 是相同的函數,是為了和 ADO 相容而存在的。

MetaType($nativeDBType[,$field_max_length],[$fieldobj])

設定資生資料庫裡的原生型別 $nativeDBType 為那一種通用資料型別,以及它的最大長度。請注意,如果長度未知,可以設為 -1 。欄位物件可以使用 $fieldobj 傳入。這對於像是 mysql 這一類欄位物件有較多屬性的資料庫來說,是很有用的。

使用欄位 blobsize 及比較 $field_max_length 去決定目前的欄位是否為 blob 。

回傳值:

  • C:  character 欄位,應該使用 <input type="text"> 標記來取值。

  • X: 文字欄位(Text) , 長文字欄位,使用 <textarea> 標記來顯示資料。

  • B: Blob 欄位或者大型的二位元物件(像程式,圖檔等)。

  • D: 日期欄位

  • T: 時間欄位

  • L: 邏輯欄位(真假值)或位元欄位

  • N: 數字欄位,包含自動進位、編號、整數、浮點數、實數等。

  • I: 整數欄位

  • R: 序列欄位,包含了序列、自動增進整數,只對被選擇的資料庫作用。

Close( )

關閉目前的資料集。


function rs2html($adorecordset,[$tableheader_attributes], [$col_titles])

這是一個獨立的函數 (rs2heml = recordset to html) ,相當於 PHP 中的 odbc_result_all 函數。本函數會輸出一整個 ADORecordSet,$adorecordset 如同一個 HTML表格。$tableheader_attributes 允許你控制表格裡的參數如 cellpadding,cellspacing 及 border 等的屬性。最後,你可以透過 $col_titles 陣列,更換資料庫欄位名稱,使用你自己的欄位抬頭。這是設計用來快速除錯的機制,不是一個好的表格記錄瀏覽器。

要使用這個函數,你必需引入 tohtml.inc.php 。

rs2html 範例:

<?
include('tohtml.inc.php'); # load code common to ADOdb 
include('ADOdb.inc.php'); # load code common to ADOdb 
$conn = &ADONewConnection('mysql');   # create a connection 
$conn->PConnect('localhost','userid','','agora');# connect to MySQL, agora db
$sql = 'select CustomerName, CustomerID from customers'; 
$rs   = $conn->Execute($sql); 
rs2html($rs,'border=2 cellpadding=3',array('Customer Name','Customer ID'));
?>

感謝
------------------

PHP ADODB 1.99版手冊中文翻譯
Tripc <tripc.tw@yahoo.com.tw>