转:http://www.chinaitlab.com/linux/manual/database/adodb1.99.html


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-StyleLGPL双轨制,换句话就是Freeware,没有什么限制。但在取得ADODB后,最好还是要看一下相关版权说明及用法,并和本文对照一下,以免错误。

使用ADODB

基本上使用ADODB是相当容易的,取得压缩档后解开,我建议将整个内容都解到ADODB的目录里。然后你可以一边参考本文,一边研究里面的范例,就放在里面的test目录下。

由于ADODB附上的说明十分完整详实,以下的说明大部份来自ADODBreadme.htm,这里不是全部的内容,我把一些我认为没有用的内容都去掉了,像版本差异说明、何撰写支持ADODB的驱动程序等与应用无关的部份。想要了解全部内容的读者还是可以自己去参考 readme.htm


·         简介

·         特色

·         安装

·         激活ADODB

o        ADONewConnection

o        NewADOConnection

·         支持的数据库

·         学习手册

o        范例 1 : Select

o        范例 2 : 进阶 Select

o        范例 3 : Insert

o        范例 4 : 除错及 rs2html 范例

o        范例 5 : MySQL 及选单

o        范例 6 : 一次连结两个数据库

o        范例 7 : 产生更新及新增的SQL指令

o        范例 8 : 用下一笔及上一笔实作卷动

·         客制化错误处理及PEAR错误

·         资料集快取

·         参考手册

o        ADOConnection

§         连结数据库:Connect PConnect

§         执行SQLExecute CacheExecute SelectLimit CacheSelectLimit Prepare PrepareSP GetOne GetRow

§         产生 更新/新增:GetUpdateSQL GetInsertSQL

§         BLOB : UpdateBlob UpdateClob UpdateBlobFile

§         换页/卷页 : PageExecute CachePageExecute

§         清除 : CacheFlush Close

§         交易 : BeginTrans CommitTrans RollbackTrans

§         提取资料 : $ADODB_FETCH_MODE BlankRecordSet

§         字符串 : Concat qstr

§         日期 : DBDate DBTimeStamp UnixDate UnixTimeStamp

§         ""管理器 : Affected_Rows Insert_ID GenID

§         错误处理 : ErrorMsg ErrorNo

§         资料辞典 : MetaDatabases MetaTables MetaColumns MetaColumnNames

§         反对 : Bind (? 没有说明)

o        ADORecordSet

§         取单笔记录 : FetchRow FetchInto FetchObject FetchNextObject GetRowAssoc Fields GetAssoc

§         取全部记录 : GetArray GetRows

§         卷动 : Move MoveNext MoveFirst MoveLast AbsolutePosition CurrentRow AtFirstPage AtLastPage AbsolutePage

§         选单制作 : GetMenu GetMenu2

§         日期 : UserDate UserTimeStamp UnixDate UnixTimeStamp

§         记录信息 : RecordCount PO_RecordSet

§         字段信息 : FieldCount FetchField MetaType

§         清除 : Close

·         rs2html 公用函式说明  范例

简介

由于PHP的数据库存取函数没有标准化,所以我们需要一组函数库或是类别来隐藏不同数据库函数接口间的差异,让我们可以很简单的去切换数据库,而这,就是ADODB的目的。

ADODB目前支持MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, Informix, PostgreSQL, FrontBase, Interbase (Firebird  Borland 版本), Foxpro, Access, ADO ODBCADODB也有透过ODBC成功连结ProgressDB2的报告,我们希望能有更的人提供驱动接口来支持更多的数据库。

PHP4支持连结变量(session variables),使用者可以透过ADODB储存连结信息,以达成真正的可移植性及弹性,相关的用法及信息请自行参考ADOdb-session.php这个范例。

另外,如果要撰写一个具有高度可移植性的SQL码,也可以参阅 http://php.weblogs.com/portable_sql 这篇文章。

特色

·         对熟悉Windows的工程师而言,ADODB很容易使用,因为ADODB里的很多功能和MicrosoftADO很像。

·         与其它的PHP数据库类别不同,它们大多集中在处理与 select 指令有关的东西,而ADODB对于 inserts  update 也提供额外的支持,并且可以很快的连结到多数据库。所提供的方法更扩及日期的掌握,字符串的连结及字符串标记字符差异处理(在某些数据库间字符串的连结和标记符号是有差异的)

·         型别对照系统是内建的,所以我们可以设定或描述像CHAR,TEXTSTRING在不同的数据库间其实是相同的资料型别。

·         更容易去移植,因为所有与数据库相依的程序代码被都隐藏在后端,所以使用者不再需要去移植类别里的逻辑。

·         支持 PHP4 连结变量,请参考 ADOdb-session.php

安装

首先要确定你所使用的PHP版本是 4.01pl2 或是之后的版本(因为ADODB使用到了 require_onceinclude_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

interbaseFirebird版本

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





mysqlt maxsql

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下层的数据库结结机制,除了使用 odbc  ado 外,一般正常会设为  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 宣告。

 PostgreSQLSELECT * FROM TABLE LIMIT 3 将会只传回从头开始的三笔记录。相同的,$connection->SelectLimit('SELECT * FROM TABLE',3)也有同样的意思。

 SELECT * FROM TABLE LIMIT 3 OFFSET 2 将会回传记录 3,45三笔(也就是在记录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_bind  ocibindbyname  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,p2p3来结合。这些变量将会配到 :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 ,除非是使用 odbc  ado 

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) 将会产生一个选单,AB将会被选取。然而,这一次的被选取的比对基准是第二个字段,也就是存放要被回传给服务器里的值。

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( )

目传目前资料集的记录编号,表示是第一笔。

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 允许你控制表格里的参数如 cellpaddingcellspacing  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>

 

PHP ADOdb 类库介绍

 

前言

为什么要使用数据库类库?

 

初学者 (甚至一些非初学者)常常犯的错误,就是在开发应用程序的时候,缺乏对未来的考虑。假如有一天,你的程序需要使用其它的数据库,难道你还需要重新写一篇针对于这个版本数据库的程序吗?这不是不可能发生的,尤其是当目前的数据库可能不适合你当前的需要的时候。 但是当你做这一切的时候 ,你会发现绝非你想像的那样容易:每一个DBMS 有不同的函数。举例来说:在 Mysql 中连接数据库的函数为 mysql_connect(),而在MSSQL却是 mssql_connect()。重新查看你所有的代码,然后修改所有操作数据库的函数和查询语法,这绝不是一项简单的工作。程序会经常的被捆绑到了错误的数据库上,以至无法在运行时达到最优性能。数据库类库就是这样产生的。它允许你通过同样的代码来操作不同的数据库。一个设计良好的数据库类库可以完美的改变这一切。它允许你通过极小的修改,就能转接到其他数据库:无论你要连接什么数据库管理系统,只要使用同一个的函数,和不同的参数。举例来说 ADOdb ,只需简单地将 $db = NewADOConnection('access ') 修改为$db = NewADOConnection('mysql'),这样,你就轻松的把你的程序从Access 数据库转移到了 Mysql 数据库中。现在网络上已经有了很多这样的数据库类库,比如PearPHPlib,我也已经在工作中使用它们了,也许你也曾经用过。但本文仅将重点放在我所特别关注的 ADOdb。本文我只简要地作一个介绍,使你能够马上运用它来开发你的下一个项目。以后的文章中我们将会循序渐进的对它进入更深入的了解。

 

目前,ADOdb 支持的数据库包括 MySQL, PostgreSQLInterbaseFirebirdInformixOracleMS SQL 7FoxproAccessADOSybaseFrontBaseDB2  generic ODBC

 

ADOdb 的安装

安装 ADOdb 是一件极期容易的事,相信聪明的你一定不会感到吃力。

 

首先确定你正在运行的 PHP  4.0.4 版或更新版。 如果不是,我强列建议你升级!

 PHP Everywhere 站点下载 .zip  .tgz 文件,解压缩到你所选的路径下。

这个路径不应在网页目录(WWWTREE,译者注:如果你的网页是在/www/下,那么,这个目录就不应为/www/here)下!虽然ADOdb的包含文件已经使用了 .inc.php 的扩展名 ,使得服务器即使是在最糟糕的配置下,也不会将这些.inc文件通过明文方式在浏览器中显示出来,但是我们向来不提倡将库函数文件放在网页目录下的行为。然后把下载下来的文件运行:tar -zxvf adodb350.tgz 解压,在Windows下你可以使用一个你喜欢的解压软件来操作,这样,你会得到一个 adodb 的目录其下包括了许多子目录。

 

测试你的安装

好了,让我们来测试一下你的安装吧。 通过在脚本中添加下列三行代码来测试你的安装是否成功。注意要把代码中的参数修改成你自己的。

 

include("$adodb_path/adodb.inc.php"); // includes the adodb library

$db = NewADOConnection('$database_type'); // A new connection

$db->Connect("$host", "$user", "$password", "$database_name");

现在你已经拥有一个数据库连接对象 $db 了。 你也可以使用 ADONewConnection 来替换 NewADOConnection —— 这两个是同一函数的不同的名字。 连接的数据库变量$database_type 需要针对你的实际情况改成你所需要的。可以使用以下列表中的一个(括号内的为描述部分,不要在代码中使用)

 

access (Microsoft Access/Jet)

ado (Generic ADO, the base for all the other ADO drivers)

ado_access (Microsoft Access/Jet using ADO)

ado_mssql (Microsoft SQL Server using ADO)

db2 (DB2)

vfp (Microsoft Visual FoxPro)

fbsql (FrontBase)

ibase (Interbase 6 or before)

firebird (Firebird)

informix72 (Informix databases before Informix 7.3)

informix (Informix)

maxsql (MySQL with transaction support)

mssql (Microsoft SQL Server 7)

mssqlpo (Portable mssql driver)

mysql (MySQL without transaction support)

mysqlt (MySQL with transaction support, identical to maxmysql)

oci8 (Oracle 8/9)

oci805 (Oracle 8.0.5)

oci8po (Oracle 8/9 portable driver)

odbc (Generic ODBC, the base for all the other ODBC drivers)

odbc_mssql (MSSQL via ODBC)

odbc_oracle (Oracle via ODBC)

oracle (Oracle 7)

postgres (PostgreSQL)

postgres64 (PostgreSQL 6.4)

postgres7 (PostgreSQL 7, currently identical to postgres )

sqlanywhere (Sybase SQL Anywhere)

sybase (Sybase)

如果你的链接代码出现了错误的提示,那么你首先要检查的地方就是在路径或连接的变量上。在你责备 ADOdb 之前,请确定你是已经正确的使用那些变量。(很多朋友常花太多时间去修正这些显而易见的错误。如果连接没有任何错误提示,那么我们现在已经可以在我们的项目中来使用 ADodb 了。

 

通过你的脚本连接到数据库

把上边的代码加入到你的代码前,让我们先退一步。我们最好能把上边的代码用我们自己的方法来封装起来。这样可以使你的程序变得更灵活、更具移植性。如果你直接把上面的代码插入到你的项目的每个文件中,如果将来项目的路径改变了,将会很容易产生错误,如果你的密码改变了,你可能需要对你所有的脚本进行修改,这样将会影响我们使用库函数的初衷。并且,因为你的密码信息是在WEBTREE下的,这将产生隐患。我推荐将密码信息放在一个独立的包含文件中,比如在 ADOdb 安装目录下的某个地方。如果你要在其他服务器上运行你的程序时,你就不能保证目录结构会是相同的,所以,你要确保这个路径是正确的。我建议使用PHP 的自动包含功能来自动地包含这个文件。

 

 

include("$adodb_path/db_values.inc.php");

include("$adodb_path/adodb.inc.php");

$db = NewADOConnection('$database_type');

$db->Connect("$host", "$user", "$password", "employees");

 

如果你也想要使用持久连接不是每次创造一个新的连接(这使许多WEB应用程序得到了加速,但是要注意有些数据库是不支持的)。可以使用 PConnect 替换掉 Connect

文件 db_values.inc.php 是我们的数据库信息文件,内容为(你需要把下面代码中的变量改成你自己的):

 

<?php

$database_type="mysql";

$host = "localhost"; // 本地数据库

$user = "ian"

$password = "let_me_in"

?>

 

你可以在 php.ini 配置中设定自动包含我们的配置文件,具体操作可以修改 PHP.ini 的下述行:

 

; Automatically add files before or after any PHP document.

auto_prepend_file = /usr/local/build/apache/www/tool_lib/defaults.inc

auto_append_file =

 

 

文件 defaults.inc 包含了 $adbdb_path 的值:

 

<?

$adodb_path = "/usr/local/build/apache/www/tool_lib/";

?>

 

还有其他方式来实现它,但是我发现这种方法在移植时,可以相对地减少复杂度。

 

 

从一个数据库中进行选择(SELECT)操作

当同时使用开发良好的库函数,和PHP自身提供的函数时,可以有多种方法来访问数据库。用什么方法,完全取决于你自己的喜好。

这里是一个简单的例子:

 

$sql = "SELECT surname, age FROM employees";

$rs = &$db->Execute($sql);

if (!$rs) {

print $db->ErrorMsg(); // Displays the error message if no results could be returned

}

else {

while (!$rs->EOF) {

print $rs->fields[0].' '.$rs->fields[1].'<BR>';

// fields[0] is surname, fields[1] is age

$rs->MoveNext(); // Moves to the next row

}

}

 

 

在上例中,$rs->fields 是一个包含返回值的数组。数组索引被赋予了初始的数字,你也可以按下面的方法来指定其索引:

 

$sql = "SELECT surname, age FROM employees";

$db->SetFetchMode(ADODB_FETCH_ASSOC); // Return associative array

$rs = &$db->Execute($sql);

if (!$rs) {

print $db->ErrorMsg(); // Displays the error message if no results could be returned

}

else {

while (!$rs->EOF) {

print $rs->fields['surname']." ".$rs->fields['age']."<BR>";

$rs->MoveNext(); // Moves to the next row

} // end while

} // end else

 

 

对结果浏览的另一个可选的方法是将每条记录作为一个对象返回。 ADOdb 有一个 FetchNextObject() 的函数来实现这一功能,指针会自动地移到下一条记录。

 

$sql = "SELECT surname, age FROM employees";

$db->SetFetchMode(ADODB_FETCH_ASSOC); // Return associative array

$rs = &$db->Execute($sql);

if (!$rs) {

print $db->ErrorMsg(); // Displays the error message if no results could be returned

}

// loop through results

while ($row = $rs->FetchNextObject()) {

// The field names need to be uppercase

print $row->SURNAME." ".$row->AGE."<BR>";

}

 

 

插入、更新记录

基本的 INSERT 操作方便、快捷拥有与SELECT一样的语法。

 

$sql = "INSERT INTO employees (surname, age) values ('Clegg','43')";

if (!($db->Execute($sql))) {

print 'Error inserting: '.$db->ErrorMsg().'<BR>';

}

 

 

库函数真正的优点,在于它允许你通过相同的语法将记录放入不同的数据库之内,这在以前是绝对不可能的。通常有两种发生的情形。

 

第一种,引号。所有的引号需要用脱字符(`符号,键位在Tab键的上边)代替,否则会引起语法错误。但是一些数据库使用一个单引号,另外一些则使用两个单引号。所以,你应当使用 ADOdb 中的 qstr() 而不是 PHP 中的 addslashes()。这样,返回值就将与你所使用的数据库相吻合了。

 

第二种,日期。许多数据库接受跟他们的日期类型不一致的、不兼容的格式。 ADOdb 有一个 DBDate() 函数,可以将 Unix  timestamp,  ISO(Y-m-d) 格式转换成任意格式,以此来满足你的数据库的需求。 见下例:

 

$employee_surname = $db->qstr("d'Angelo");

$arrival_time = $db->DBDate(time());

// The above two functions also add the enclosing quotes, so, $arrival_time, not '$arrival_time'

$sql = "INSERT INTO employee_arrival (arrival_time,surname) values ($arrival_time,$employee_surname)";

if (!($db->Execute($sql))) {

print 'Error inserting: '.$db->ErrorMsg().'<BR>';

}

 

你可以以完全相同的方式更新数据库,举例来说:

 

$sql = "UPDATE employees SET age='44' WHERE id='121')";

if (!($db->Execute($sql))) {

print 'Error updating: '.$db->ErrorMsg().'<BR>';

}

 

以上仅仅是 Adodb 的一些基本操作 —— 下次我们将会关注一些 ADOdb 提供的比较深层次的东西。 如果我已经使你胃口大开,而且你已经不能再等待, 我建议你去PHP Everywhere看一下,这个站点是ADOdb的专业站点,里面有很多有用的帮助信息。

 

对查询进行缓存

 

上个月,我们简单地了解了ADOdb,如何进行SELECTINSERTUPDATE的操作。如果你在ADOdb上是个新手,我建议先读一下上个月的那篇文章。 ADOdb 还有很多更高级的特征,这个月,我们就一起来关注其中的部分内容。

 

数据库时常会成为应用程序效率低下的祸首。尽量减少对数据库的查询,是提高执行效率的方法之一。这,通常可以通过对整页内容进行缓存(有很多种方法来实现。比如,PEAR->Cache,或者,如果你需要做一张动态页面,并且只想让查询指令被缓存,那么,你可以使用ADOdb,简单地将查询指令缓存起来。在你视图通过缓存来提高你的应用程序的糟糕性能之前,我建议你先试图去优化你的查询指令。有时候,一些简单的索引可以改变一切——有太多的所谓的专业的解决方案,都在使用糟糕的索引。在本文中,你能找到很多这样的实例。现在,让我们来看看ADOdb是如何使你能够对数据库的查询结果进行缓存的。在这个实例中,ADOdb把我们的最后的一次查询的结果保存在/var/tmp/adodb_cache这个缓存文件中,并保留10分钟。

 

include("$adodb_path/db_values.inc.php");

include("$adodb_path/adodb.inc.php");

$db = NewADOConnection('$database_type');

$db->Connect("$host", "$user", "$password", "employees");

 

$ADODB_CACHE_DIR = "/var/tmp/adodb_cache"; //Directory to store cached files

 

$sql = "SELECT surname, age FROM employees";

$rs = &$db->CacheExecute(600,$sql); // Executes, and caches the results for 600 seconds

if (!$rs) {

print $db->ErrorMsg(); // Displays the error message if no results could be returned

}

else {

while (!$rs->EOF) {

print $rs->fields[0].' '.$rs->fields[1].'<BR>';

// fields[0] is surname, fields[1] is age

$rs->MoveNext(); // Moves to the next row

} // end while

} // end else

 

 

CacheExecute() 函数有两个参数第一个参数是缓存文件将被保留的时间,以秒计时;第二个参数是 SQL 声明。 第一个参数是可选择的 (一些开发者或许会认为它应当成为第二个参数,如果你没有限定时间,那么,默认值是 3600 ,也就是1个小时。缓存文件被命名为 adodb_*.cache,你可以在文件系统中安全地将他们删除。你应该定期清楚过期的缓存文件(用UNIX“crontab万年历”,或者WINDOWS计划任务”。译者注:万年历不知有没有译错,我没有UNIX。)。要注意的是,要使用缓存方法,你需要将PHP的参数magic_quotes_runtime设为off(译者注:在php.ini中,将值设为0)。你可以根据需要,在运行时修改它的值:

set_magic_quotes_runtime(0)

只需将上述代码放到你调用数据库的指令之前就可以了。你可以在任何时候,通过调用CacheFlush();来清除缓存。处于对安全的考虑,ADOdb 也建议将PHP的参数register_globals 设为0(PHP最新版中,这是默认值

 

 

更多关于查询结果的信息

 

开发者通常会对他们的要得到的结果产生一些质疑,最通常的问题是:有多少个记录?ADOdb能够很容易地通过RecordCount()来回答这个问题。 RowCount()是同义函数。

 

$sql = "SELECT surname, age FROM employees";

$rs = &$db->CacheExecute(600,$sql); // Executes, and caches the results for 600 seconds

print $rs->RecordCount() . " rows returned]"; // Display number of rows returned

 

 

或许第二个问题会产生在需量列表上:被返回字段数量是多少?不用担心,ADOdbFieldCount()

 

$sql = "SELECT surname, age FROM employees";

$rs = &$db->CacheExecute(600,$sql); // Executes, and caches the results for 600 seconds

print $rs->FieldCount() . " columns returned]"; // Display number of rows returned

 

 

 

限制结果

 

上次我们讨论了如何通过使用一个数据库库函数使你的应用程序更简洁,更易于移植。在从MySQL转移到 Informix , 我经历了一次痛苦的移植过程。一切都归咎于非ANSII标准的LIMIT子句举例来说, MySQL中允许下列指令:SELECT name FROM employee LIMIT 15),它是一个非常有用的功能,可在Informix中却不被支持。(在Informix中,相同功能的书写应该是:SELECT FIRST 15 name FROM employee in Informix。)它似乎对你敲响了警钟,要你停止在你的查询中使用非标准SQL的指令,而去认真地学习标准的SQL。幸运的是,ADOdb有一个处理LIMIT的方法:SelectLimit()

 

$sql = "SELECT surname, age FROM employees";

$rs = &$db->SelectLimit($sql, 10, 100); // Select 10 rows, starting at row 100

if (!$rs) {

print $db->ErrorMsg(); // Displays the error message if no results could be returned

}

else {

while (!$rs->EOF) {

print $rs->fields[0].' '.$rs->fields[1].'<BR>';

// fields[0] is surname, fields[1] is age

$rs->MoveNext(); // Moves to the next row

} // end while

} // end else

 

 

SelectLimit()SQL声明作为第一参数,第二个是返回的列的数量,最后一个参数是偏移量(返回的第一行)。注意这跟MySQL的指令中LIMIT子句的参数顺序相反。SelectLimit()对于将搜索结果部分地显示在页面上,是十分有用的,通过PreviousNext按钮,可以浏览所有的结果。

 

不止一次地,我看到的代码将来自数据库的所有查询结果,都用PHP作过滤处理——杀鸡用牛刀你完全可以使用 CacheSelectLimit()函数来贮藏这种类型的结果。

 

 

处理事务

 

处理事务是许多应用程序的一个重要的特征。(对于初学者来说,处理事务是你可以提交一打查询操作的过程,而这些查询是都成功了,还是有部分失败了,都需要考虑进去。

经典范例是银行处理。钱从你的帐户转出,然后转入到其他某个人的帐户中。只要其中任意一项失败,那么,这整个过程都必须被认定为失败。不然,钱被划出,而没有进对方的帐户;或者,钱没有划出,对方帐户无端多了一笔小费。)

 

处理事务可以在代码级上进行机警地管理控制。 常数错误检查被用来判断是否要COMMIT(事务的所有各项都正确,执行正确,结束事务)还是ROLLBACK(事务中有错误,所有改动需要恢复原来状况)。ADOdb 有一些能使处理操作正确进行的有用的函数。下例在某个职员的结余加10,并在另一个上减10,整个过程有两个查询,作为一个完整的事务。

 

$sql1 = "UPDATE employees SET balance=balance-10 WHERE id=15";

$sql2 = "UPDATE employees SET balance=balance+10 WHERE id=22";

$db->StartTrans();

$db->Execute($sql);

$db->Execute($sql2);

$db->CompleteTrans();

 

 

 

当你浏览老的代码时,可能会看到一个比较老的方法来实现这一切。使用 BeginTrans()CommitTrans()RollbackTrans()函数时,需要你自己来处理错误。StartTrans()和CompleteTrans()将会自动地处理错误,并适当地进行COMMITROLLBACK。当需要的时候,你可以通过FailTrans()来强制执行ROLLBACK

 

当然你可能需要知道处理是失败了还是成功了。ADOdb 提供了 HasFailedTrans() 来实现这个功能。 如果出错(或者,你可以将这种情况称作FailTrans()),返回TRUE;如果成功,返回FALSE

 

$sql1 = "UPDATE employees SET balance=balance-10 WHERE id=15";

$sql2 = "UPDATE employees SET balance=balance+10 WHERE id=22";

$db->StartTrans();

$db->Execute($sql);

$db->Execute($sql2);

$db->CompleteTrans();

if ($db->HasFailedTrans()) {

// Something went wrong

}

 

 

值得注意的是,你的数据库需要支持这些事务函数。 (大多数的数据库是支持的,不过,MySQL InnoDB表支持, MySQL MyISAM 表不支持。)

 

我希望我所做的一切能让你对数据库库函数能有极大的兴趣。还有大量有趣的函数可以用来从数据库表中自动生成HTML,并且同一结果有不同的方法来实现。你可以在此找到完整的手册。