php sqlserver2005编程

by 清泉 7. 十二月 2009 12:56
SQL Server 2005 Driver for PHP 提供了24 个可以用在PHP 程式的函式,这些函式名称都是sqlsrv_ 开头。而本文即将说明这些函式如何协助PHP 程式存取Microsoft SQL Server 资料库。此外,本文附上一段5分钟的影片,说明以SQL Server 2005 Driver for PHP 的函式所编写的AdventureWorks Product Reviews 应用范例。
  • 资料库存取的基本步骤
  • 连接资料库
  • 检视用户端资讯
  • 取得资料
  • 更新资料
  • 转换资料型别
  • 错误处理
  • 结语
本文无法尽数说明所有24 个函式,而是依照资料库存取的动作类型-- 包括连接资料库、取得资料、更新资料、转换资料型别、错误处理等,分别说明对应到的SQL Server 2005 Driver for PHP 函式。

资料库存取的基本步骤
连接资料库是存取资料库优先且必要的动作;要取得资料库里的资料、或更新资料库,都必须先成功连上资料库。 SQL Server 2005 Driver for PHP 提供了sqlsrv_connect 函式让我们连接SQL Server。
连接资料库之后,接着要以T-SQL 陈述式来「查询」已连上的资料库,查询的内容包罗万象,甚至有可能超出单纯的查询。因此这个部分必须根据目的、需求,编写出适当的T-SQL 陈述式,并加以执行。我们可以利用SQL Server 2005 Driver for PHP 的sqlsrv_query 函式进行一次查询,而sqlsrv_prepare / sqlsrv_execute 函式能处理多次查询。
然后我们要取得查询结果;查询结果能以阵列、物件、资料流传回程式,或者也能直接撷取单一栏位。取得查询结果大都还需要一一「挖出」阵列或物件里的资料,并呈现在网页。 SQL Server 2005 Driver for PHP 提供的查询结果取得函式包括sqlsrv_fetch_array、sqlsrv_fetch_object、sqlsrv_fetch、sqlsrv_get_field、sqlsrv_next_result 等。
此外也可能要将资料回存资料库-- 不论是以新资料更新旧资料,或是新增资料列。我们可以利用查询函式(sqlsrv_prepare / sqlsrv_execute)来更新资料。
连接及关闭资料库
SQL Server 2005 Driver for PHP 提供了sqlsrv_connect 函式来连接资料库。但为了安全,连接资料库应该有所验证。因此SQL Server 2005 Driver for PHP 也提供了两种资料库连接的验证方式:Windows 验证及SQL Server 验证;预设是采用Windows 验证。
不论是Windows 验证或SQL Server 验证,都必须有权限适当的Windows 帐号或SQL Server 帐号;帐号的权限必须足以进行PHP 程式后续的动作,但为了安全考量,也不应该使用权限太大的帐号。
sqlsrv_connect 函式的使用看似简单,只需两个参数(第1 个是连接的伺服器名称$serverName 字串,第2 个是连接资讯$connectionInfo 阵列);但事实上,第2 个可选择的连接资讯阵列可包含了诸多连接相关参数。
sqlsrv_connect( string $serverName [, array $connectionInfo])
$serverName 字串指定了欲连接的伺服器名称、IP 位址(需确定SQL Server 组态管理员已启用TCP/IP 或具名管道通讯协定),这个字串也可以包含SQL Server 执行个体名称(例如myServer\instanceName)或TCP 通讯埠编号(例如myServer,1943,但这必须先将SQL Server 设定成能接听特定的通讯埠)。
可选择的$connectionInfo 是关联阵列,内含诸多连接相关参数,通常我们会利用这个阵列来指定连接SQL Server 之后欲使用的资料库。如果使用SQL Server 验证,也要以此阵列指定SQL Server 帐号的使用者ID(UID)和通行码(password,PWD)。
sqlsrv_connect 函式若执行成功,会传回PHP 连线资源,后续的存取动作都会用到。但若执行失败,会传回 false。
Windows 验证
如果没有以$connectionInfo 阵列指定SQL Server 帐号的UID 和PWD,sqlsrv_connect 函式就会以Windows 验证登入SQL Server;Windows 验证是SQL Server 2005 Driver for PHP 预设的验证方式。如果Web 伺服器使用模拟(impersonation),这种验证则是以Web 伺服器的行程或绪程作为连接SQL Server 的身份。因此执行中的Web 伺服器行程或绪程的凭证,必须能登入SQL Server。此外,如果SQL Server 和Web 伺服器分属不同电脑,SQL Server 必须设定成能够远端连接。
以下是Windows 验证的例子:
// 指定伺服器名称(本机电脑)$serverName = "(local)";// 指定连接字串的资料库名称$connectionInfo = array( " ;Database"=>"AdventureWorks");/* sqlsrv_connect 函式连接失败会传回false, 成功会传回PHP连线资源, 因此PHP连线资源会被指定到变数$conn */$conn = sqlsrv_connect( $serverName, $connectionInfo);
SQL Server 验证
sqlsrv_connect 函式也能以SQL Server 验证的方式登入SQL Server,但首先SQL Server 必须设定成SQL Server 混合模式验证,然后只要以$connectionInfo 阵列指定能够登入SQL Server 的UID 和PWD 即可。但为了安全起见,不应该直接将UID 和PWD 写在PHP 程式里,可以改成将UID 和PWD 存放在特定且具备适当存取权限的档案,然后再以PHP 程式读取UID 和PWD,是较为安全的作法,例如:
// 指定伺服器名称(本机电脑)$serverName = "(local)";// 将UID 和PWD 分别存在C 碟里的档案,再以file_get_contents 函式读取$uid = file_get_contents("C:\AppData\uid.txt");$pwd = file_get_contents("C:\AppData\pwd.txt");$connectionInfo = array( "UID" =>$uid, "PWD"=>$pwd, "Database"=>"AdventureWorks");/* sqlsrv_connect 函式连接失败会传回false, 成功会传回PHP连线资源,因此PHP连线资源会被指定到变数$conn */$conn = sqlsrv_connect( $serverName, $connectionInfo);
连接共用
连接共用(connection pooling)是指成功连线之后,将连线集中置于集区,让程式能重复使用集区里的连线,而不需重新连接。 SQL Server 2005 Driver for PHP 利用ODBC 的连接共用来提供这项功能,而且预设便启用连接共用。当PHP 程式欲连接SQL Server 时,SQL Server 2005 Driver for PHP 在建立新的连线之前,会检查集区里是不是已经有属性相同的连线:如果有,就会使用集区里现有的连线(并且会重置其连接状态);如果没有,SQL Server 2005 Driver for PHP 才会建立新的连线,并将成功建立的连线加入集区。
但无论如何,我们亦可将连接资讯的ConnectionPooling 属性设为false(0),以此强制SQL Server 2005 Driver for PHP 建立新的SQL Server 连线(ConnectionPooling属性的预设值为True):
// 指定伺服器名称(本机电脑)$serverName = "(local)";$connectionInfo = array("Database"=>"AdventureWorks" , "ConnectionPooling"=>false);$conn = sqlsrv_connect($serverName, $connectionInfo);
结束连接
若欲结束已建立的连接,要使用sqlsrv_close 函式,并以欲结束的PHP 连线资源作为参数;如果是强制建立的SQL Server 连线,用完之后务必要以sqlsrv_close 函式来结束连线。
// 以sqlsrv_close 函式并搭配$conn 变数里的PHP 连线资源来结束连线sqlsrv_close( $conn);
检视用户端及伺服端资讯
为了便于检视用户端及伺服端资讯,SQL Server 2005 Driver for PHP 分别提供了sqlsrv_client_info 及sqlsrv_server_info 函式。这两个函式在使用之前,都必须先建立SQL Server 连线,并以PHP 连线资源作为执行函式的参数。而且这两个函式都是将取得的相关资讯存放在关联阵列。
sqlsrv_client_info:检视用户端资讯
如果执行失败,sqlsrv_client_info 函式会传回false,若执行成功,则会将以下资讯放置在关联阵列。
索引键
说明
DriverDllName
SQL Server Native Client DLL档名(SQLNCLI.DLL)
DriverODBCVer
ODBC 版本序号
DriverVer
SQL Server Native Client DLL 版本序号
ExtensionVer
php_sqlsrv.dll(SQL Server 2005 Driver for PHP)版本序号
以下是sqlsrv_client_info 函式的使用范例及执行结果。
// $conn 内容是PHP 连接资源// 叫用sqlsrv_client_info 函式取得用户端资讯if( $client_info = sqlsrv_client_info( $conn)){ // 以foreach 回圈显示$client_info 阵列内容foreach( $client_info as $key => $value) { echo $key.":".$value."</br>"; }}// 若叫用结果为false,表示叫用失败else{ echo "sqlsrv_client_info函式执行有误</br>";}
php sqlserver2000编程(引用) - pangqzh-23 -在路上
图1 sqlsrv_client_info 函式的执行结果
sqlsrv_server_info:检视用户端及伺服端资讯
与sqlsrv_client_info 函式相当类似的是,sqlsrv_server_info 函式如果执行失败也会传回false,若执行成功,则会将以下资讯放置在关联阵列。
索引键
说明
CurrentDatabase
目前列为目标的资料库
SQLServerVersion
SQL Server 版本序号
SQLServerName
伺服器名称
以下是sqlsrv_server_info 函式的使用范例及执行结果。
// $conn 内容是PHP 连接资源// 叫用sqlsrv_server_info 函式取得用户端资讯if( $server_info = sqlsrv_server_info( $conn)){ // 以foreach 回圈显示$server_info 阵列内容foreach( $server_info as $key => $value) { echo $key.":".$value."</br>"; }}// 若叫用结果为false,表示叫用失败else{ echo "sqlsrv_server_info 函式执行有误</br>";}
php sqlserver2000编程(引用) - pangqzh-23 -在路上
图2 sqlsrv_server_info 函式的执行结果
取得资料
资料库查询结果会传回资料列,只要利用不同的sqlsrv_fetch_array、sqlsrv_fetch_object、sqlsrv_fetch 等函式,我们即可以阵列、物件、资料流等不同形式来取得资料,而且也能取得单一栏位或多笔结果的资料。
这些函式是以查询的执行结果作为参数,而且若执行成功,会传回所取得的资料,但若执行失败,会传回false;如果执行成功但未能取得资料,则会传回null(可以利用PHP 函式is_null 来检查)。
sqlsrv_fetch_array:以阵列传回下一笔资料
若执行成功,sqlsrv_fetch_array 函式会传回存放资料的阵列,而且可以是数值索引的阵列,也可以是关联阵列。使用sqlsrv_fetch_array 函式时,必须将查询的结果指定为第1 个参数,第2 个参数可选择,用来指定传回数值索引阵列或关联阵列(预设两者皆传回)。
sqlsrv_fetch_array( resource $stmt[ , int $fetchType])
第2 个参数能以如下的常数指定:SQLSRV_FETCH_NUMERIC(数值索引阵列)、SQLSRV_FETCH_ASSOC(关联阵列)、SQLSRV_FETCH_BOTH(两者,此为预设值)。
以下是sqlsrv_fetch_array 函式的使用范例及执行结果,其中是使用数值索引阵列。
// 定义查询$tsql = "SELECT ProductID, UnitPrice, StockedQty FROM Purchasing.PurchaseOrderDetail WHERE StockedQty < 3 AND DueDate='2002-01-29'";/ / 执行查询// $conn 内容是PHP 连接资源$stmt = sqlsrv_query( $conn, $tsql);if ( $stmt ){ echo "已执行SQL 查询";} else { echo "查询失败,错误讯息如下:"; die( print_r( sqlsrv_errors(), true));}// 以回圈显示阵列里的查询结果while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC)){ echo "ProdID: " ;.$row[0]."</br>"; echo "UnitPrice: ".$row[1]."</br>"; echo "StockedQty: ". $row[2]."</br>"; echo "-----------------</br>";}// 释放查询及连接资源sqlsrv_free_stmt( $stmt);sqlsrv_close( $conn);?>
php sqlserver2000编程(引用) - pangqzh-23 -在路上
图3 sqlsrv_fetch_array 函式的执行结果
上述范例是使用数值索引阵列,如果要使用关联阵列,需调整如下:
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC)){ echo "ProdID: ".$row['ProductID']."<\br>" ;; echo "UnitPrice: ".$row['UnitPrice']."<\br>"; echo "StockedQty: ".$row['StockedQty']."<\br> ;"; echo "-----------------<\br>";}
sqlsrv_fetch_object:以物件传回下一笔资料
sqlsrv_fetch_object 函式能以物件的形式取得资料列,而且我们可以自订类别来存放所取得的物件,也能使用预设的stdClass 类别。以下的例子是使用预设的类别。
// 已建立PHP 连接资源,也已执行查询($stmt)// $obj 的内容是PHP物件形式的资料列while( $obj = sqlsrv_fetch_object( $stmt )){ // 一一显示物件里的LastName 及FirstName echo $obj->LastName.", ".$obj->FirstName."</br>";}
以下是自订类别的例子,与前者最大差别,是这种作法要先定义类别、建构函式,然后在执行sqlsrv_fetch_object 函式时,必须以第2个参数指定自订的类别。
// 定义Product 类别class Product{ // 建构函式public function Product($ID) { $this->objID = $ID; } public $objID; public $ name; public $StockedQty; public $SafetyStockLevel; private $UnitPrice; // method function getPrice() { return $this->UnitPrice; }}// 省略连接SQL Server、执行查询等程式码$i=0;/ / 以下叫用sqlsrv_fetch_object,是以第2 个参数指定自订的类别while( $product = sqlsrv_fetch_object( $stmt, "Product", array($i))){ echo "Object ID: ".$ product->objID."</br>"; echo "Product Name: ".$product->Name."</br>"; echo "Stocked Qty: " .$product->StockedQty."</br>"; echo "Safety Stock Level: ".$product->SafetyStockLevel."</br>"; echo "Product Color : ".$product->Color."</br>"; echo "Unit Price: ".$product->getPrice()."</br>"; echo "-----------------</br>"; $i++;}
sqlsrv_fetch / sqlsrv_get_field:取得单一栏位资料
如果只是想取得某一笔资料列的单一栏位,可以搭配使用sqlsrv_fetch和sqlsrv_get_field,前者能让下一笔资料列变得可读,后者则可读取目前资料列的特定栏位(如果必须指定回传资料的PHP 资料型别,或必须以资料流的方式取得资料,就应该使用sqlsrv_get_field)。
sqlsrv_fetch( resource $stmt)
sqlsrv_get_field( resource $stmt, int $fieldIndex [, int $getAsType])
以下的范例会先取得Purchasing 资料表里特定日期和特定库存量的产品资讯,再利用sqlsrv_fetch 函式重复检视查询结果的每一笔资料列,然后再以sqlsrv_get_field 函式取得特定栏位的资料。
// 定义查询$tsql = "SELECT ProductID, UnitPrice, StockedQty FROM Purchasing.PurchaseOrderDetail WHERE StockedQty < 3 AND DueDate='2002-01-29'";/ / 省略连接SQL Server、执行查询等程式码,$stmt 是查询结果// 以while 回圈重复检视查询结果的每一笔资料列while( sqlsrv_fetch( $stmt)){ // 以sqlsrv_get_field 函式取得特定栏位的资料echo "ProdID: ".sqlsrv_get_field($stmt, 0)."<\br>"; echo "UnitPrice: ".sqlsrv_get_field($stmt, 1)." <\ br>"; echo "StockedQty: ".sqlsrv_get_field($stmt, 2)." <\br>"; echo "---------------- -<\br>";}
sqlsrv_next_result:处理多笔资料
SQL Server 2005 Driver for PHP 的sqlsrv_next_result 函式能让PHP 程式继续处理下一笔结果。
sqlsrv_next_result( resource $stmt )
以下的例子会执行批次查询来取得特定产品编号的评论资讯、插入产品评论,然后再次取得特定产品编号的评论资讯,因此就能看到新加入的产品评论。这个例子是以sqlsrv_next_result 函式将批次查询的结果移往下一笔。
// 省略连接SQL Server的程式码// 定义批次查询$tsql = "--Query 1 SELECT ProductID, ReviewerName, Rating FROM Production.ProductReview WHERE ProductID=? ;// 省略连接SQL Server 的程式码// 定义批次查询--Query 2 INSERT INTO Production.ProductReview (ProductID, ReviewerName, ReviewDate, EmailAddress, Rating) VALUES (?, ?, ?, ?, ?); - -Query 3 SELECT ProductID, ReviewerName, Rating FROM Production.ProductReview WHERE ProductID=?;";// 指定参数值并执行查询$params = array(798, 798, 'CustomerName', '2008-4-15', 'test@customer.com', 3, 798 );$stmt = sqlsrv_query($conn, $tsql, $params);// 取得并显示第1 次查询的结果echo "查询1 的结果:<\ br>";while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC )){ print_r($row);}// 以sqlsrv_next_result 函式将批次查询的结果移往下一笔sqlsrv_next_result($stmt);//取得并显示第2 次查询的结果echo "查询2 的结果:<\br>";echo "资料已更新:".sqlsrv_rows_affected($stmt)."</br>" ;// 以sqlsrv_next_result 函式将批次查询的结果移往下一笔sqlsrv_next_result($stmt);// 取得并显示第3 次查询的结果echo "查询3 的结果:<\br>"; while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC )){ print_r($row);}
更新资料
SQL Server 2005 Driver for PHP 除了能以参数化查询的方式更新资料,也能以资料流的方式传送资料(包括送进及送出资料库),并且支援资料交易。以下将说明两种参数化查询的用法。
参数化查询
SQL Server 2005 Driver for PHP 提供了sqlsrv_query 或sqlsrv_prepare / sqlsrv_execute 函式用作查询的执行。 sqlsrv_query 可以用作一次查询,而且适用多数情形。 sqlsrv_prepare / sqlsrv_execute 是一对互相搭配的函式,将陈述式分成「准备」和「执行」两部份,适用于多次查询。
以下是以更新Production 资料表某些产品编号的数量为例,说明如何以sqlsrv_query 函式来执行参数化查询。
// 定义查询字串,这里要更新Production 资料表的某些产品编号的数量(数量亦未知)$tsql1 = "UPDATE Production SET Quantity = ? WHERE ProductID = ?";// 初始或更新对应到T-SQL 查询替代符号的PHP 变数// 本例欲将编号为709 的产品数量更新成10$qty = 10;$productId = 709;// 以sqlsrv_query 函式来执行查询$stmt1 = sqlsrv_query( $conn, $tsql1, array($qty, $productId));
sqlsrv_prepare / sqlsrv_execute 函式
以下的例子示范了sqlsrv_prepare / sqlsrv_execute 函式的用法,此例会将数笔订单插入Sales资料表。其中在叫用sqlsrv_prepare 函式时,会将$params 阵列系结到陈述式($stmt),而每次插入新订单之前,会以对应到订单细节的新值来更新$params 阵列。执行后面的查询时,则会用到新的参数值。
// 定义查询字串$tsql = "INSERT INTO Sales (SalesOrderID, OrderQty, ProductID, SpecialOfferID, UnitPrice) VALUES (?, ?, ?, ?, ?)" ;;/* 初始或更新对应到T-SQL 查询替代符号的PHP变数以下的每个子阵列会是查询的参数阵列每个子阵列里的顺序是SalesOrderID、OrderQty、ProductID、SpecialOfferID、UnitPrice */$parameters = array( array(43659, 8, 711, 1, 20.19), array(43660, 6, 762, 1, 419.46), array(43661, 4, 741, 1, 818.70));// 初始参数值$ orderId = 0;$qty = 0;$prodId = 0;$specialOfferId = 0;$price = 0.0;// 准备$stmt = sqlsrv_prepare( $conn, $tsql, array( $orderId, $qty, $prodId, $ specialOfferId, $price));// sqlsrv_ prepare 函式执行失败会传回falseif( $stmt === false ){ // 向使用者显示执行失败的讯息,下一行程式可显示系统的错误讯息die( print_r( sqlsrv_errors(), true));}// 执行$parameters 里每组参数的陈述式foreach( $parameters as $params){ list($orderId, $qty, $prodId, $specialOfferId, $price) = $params; if( sqlsrv_execute($stmt) === false ) { // 向使用者显示执行失败的讯息,下一行程式可显示系统的错误讯息die( print_r( sqlsrv_errors(), true)); } else { // 显示新的资料列,以确认资料列已成功插入echo "资料列已改变: ".sqlsrv_rows_affected( $stmt )."<\br>"; }}// 释放查询的PHP 资源sqlsrv_free_stmt( $stmt);
转换资料型别
PHP 程式从资料库取出资料、或将资料送回资料库时,可能需要转换资料型别,这涉及PHP 本身的资料型别和SQL Server 资料型别的差异,而转换分成两种:一是系统以预设资料型别自动转换,另一种是我们以指定的型别自行转换。
资料送回资料库的型别转换
当资料送回资料库时,如果我们没有自行转换,SQL Server 2005 Driver for PHP 会根据下表SQL Server 预设的资料型别,将PHP 的资料型别转换成SQL Server 资料型别。
PHP 资料类别
SQL Server 预设的资料型别
NULL
varchar(1)
Boolean
bit
Integer
int
Float
float(24)
String (长度小于8000 位元组)
varchar(<字串长度>)
String (长度超过8000 位元组)
varchar(max)
Resource
Not supported.
Stream (非二进位编码)
varchar(max)
Stream (二进位编码)
varbinary
Integer
int
Array
不支援
Object
不支援
DateTime
datetime
从资料库取出资料的型别转换
反之,从资料库取出资料时,如果我们没有自行转换资料型别,SQL Server 2005 Driver for PHP 会根据下表,将SQL Server 资料型别转换成PHP资料型别。
SQL Server 资料型别
预设的PHP 资料型别
预设的编码方式
bigint
String
8位元字元¹
binary
Stream²
Binary³
bit
Integer
8位元字元¹
char
String
8位元字元¹
datetime
Datetime
不适用
decimal
String
8位元字元¹
float
Float
8位元字元¹
image4
Stream²
Binary³
int
Integer
8位元字元¹
money
String
8位元字元¹
nchar
String
8位元字元¹
numeric
String
8位元字元¹
nvarchar
String
8位元字元¹
nvarchar(MAX)
Stream²
8位元字元¹
ntext5
Stream²
8位元字元¹
real
Float
8位元字元¹
smalldatetime
Datetime
8位元字元¹
smallint
Integer
8位元字元¹
smallmoney
String
8位元字元¹
sql_variant
String
8位元字元¹
text6
Stream²
8位元字元¹
timestamp
Stream²
8位元字元¹
tinyint
Integer
8位元字元¹
UDT
Stream²
Binary³
uniqueidentifier
String7
8位元字元¹
varbinary
Stream²
Binary³
varbinary(MAX)
Stream²
Binary³
varchar
String
8位元字元¹
varchar(MAX)
Stream²
8位元字元¹
variant
不支援
不支援
xml
Stream²
8位元字元¹
以下请注意:
  1. 资料会根据Windows 系统地区设定的字码页将资料转换成8 位元字元,无法对映到此字码页的字元,会被换成单位元组的问号(?)。
  2. 若以sqlsrv_fetch_array 或sqlsrv_fetch_object 取得PHP Stream 型别资料,资料会以字串回传(但编码与Stream 相同)。例如,若以sqlsrv_fetcharray 取回SQL Server 二进位型别,回传的预设型别会是二进位字串。
  3. 回传时,将资料视为来自伺服端且未经编码或转换的未处理的byte stream。
  4. 这是对映到varbinary(max) 型别的传统型别。
  5. 这是对映到nvarchar(max) 型别的传统型别。
  6. 这是对映到varchar(max) 型别的传统型别。
  7. UNIQUEIDENTIFIER 是由以下规则运算式所代表的GUID:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-f] {4}-[0-9a-fA-f]{4}-[0-9a-fA-F]{12}。
转换成SQL Server 型别
如果要指定存回SQL Server 资料库的资料型别,可以在准备或执行插入或更新资料等查询时,利用$params 阵列。以下将资料存回资料库的例子,将$changeDate、$rate、$payFrequency 的型别分别指定成SQLSRV_SQLTYPE_DATETIME、SQLSRV_SQLTYPE_MONEY、SQLSRV_SQLTYPE_TINYINT,没有指定型别的$employeeId,则回使用预设值。
// 定义查询$tsql1 = "INSERT INTO HumanResources.EmployeePayHistory (EmployeeID, RateChangeDate, Rate, PayFrequency) VALUES (?, ?, ?, ?)";//建构参数阵列$employeeId = 5;$changeDate = "2005-06-07";$rate = 30;$payFrequency = 2;$params1 = array( // EmployeeID 没有指定SQL Server 资料型别,会使用预设型别array($employeeId, null), // datetime:SQLSRV_SQLTYPE_DATETIME array($changeDate, null, null, SQLSRV_SQLTYPE_DATETIME), // money:SQLSRV_SQLTYPE_MONEY array($rate, null, null, SQLSRV_SQLTYPE_MONEY), // tinyint:SQLSRV_SQLTYPE_TINYINT array ($payFrequency, null, null, SQLSRV_SQLTYPE_TINYINT));// 执行插入查询$stmt1 = sqlsrv_query($conn, $tsql1, $params1);
转换成PHP 资料型别
与前述相反的是,从SQL Server 资料库取出的资料,可能需要自行指定成PHP 的资料型别。此时我们可以使用sqlsrv_get_field 函式,并且将欲指定的PHP 资料型别当成函式的第3 个参数。当然,欲使用sqlsrv_get_field 函式,必须先搭配使用sqlsrv_fetch 函式。
// 定义T-SQL 查询$tsql = "SELECT ReviewerName, ReviewDate, Rating, Comments FROM Production.ProductReview WHERE ProductID = ? ORDER BY ReviewDate DESC";// 设定参数值$productID = 709;$params = array( $productID);// 执行查询$stmt = sqlsrv_query($conn, $tsql, $params);// 取回并显示资料;取回资料的同时,亦指定成PHP 资料型别while ( sqlsrv_fetch( $stmt)){ // 不指定;使用预设型别echo "Name: ".sqlsrv_get_field( $stmt, 0 )."</br>"; // 指定成8 位元字元编码的字串echo "Date: ".sqlsrv_get_field( $stmt, 1, SQLSRV_PHPTYPE_STRING( SQLSRV_ENC_CHAR))."</br>"; // 不指定;使用预设型别echo "Rating: ".sqlsrv_get_field( $stmt, 2 )."</br>"; echo "Comments: "; // 指定成8 位元字元编码的资料流$comments = sqlsrv_get_field( $stmt, 3, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_CHAR)); fpassthru( $comments); echo "</br>"; }
将UTF-8 编码资料存回伺服器
首先,资料库目的资料行的型别必须是nchar 或nvarchar。然后要以PHP 的iconv 函式将资料转成UTF-16LE 编码,例如$data 是UTF-8 编码的变数,以下将可转换成UTF-16LE:
$data = iconv("utf-8", "utf-16le", $data) ;接着要在参数阵列将PHP 型别指定成SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY):$params = array( array($data, null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY)));
从资料库取得资料后转成UTF-8 编码
首先,资料库里的资料是以UTF-16LE 编码。接着要以sqlsrv_get_field 函式取得资料,然后将PHP 资料型别指定成SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY):
$data = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY));接着利用PHP 的iconv 函式将取得的资料转换成UTF -8(原本是UTF-16LE 编码):$data = iconv("utf-16le", "utf-8", $data);
错误处理
SQL Server 2005 Driver for PHP 预设会将警告视为错误,因此如果叫用SQL Server 2005 Driver for PHP 所属的函式产生了警告或错误,都会传回false。但我们也可以利用sqlsrv_configure 函式来关闭这项功能。例如PHP 程式若包含以下程式,就会让SQL Server 2005 Driver for PHP 所属的函式产生错误时才会传回false(也就是若产生警告,并不会传回false):
sqlsrv_configure("WarningsReturnAsErrors", 0);
如果将上述程式里的0 改成1,就会恢复成预设状态。不论改成0 或1,只会影响执行的PHP 程式。
此外,利用php.ini 的[sqlsrv] 也可以设定上述的WarningsReturnAsErrors(这会影响整个PHP 执行环境):
sqlsrv.WarningsReturnAsErrors = 0
取得细节
SQL Server 2005 Driver for PHP 提供的sqlsrv_errors 函式,能传回最近一次SQL Server 2005 Driver for PHP 运作的错误或警告详细资讯:
sqlsrv_errors( [int $errorsAndOrWarnings] )
其中的可选择参数$errorsAndOrWarnings,是用来指定sqlsrv_errors 传回何种类型的错误,包括:
  • SQLSRV_ERR_ALL:传回错误和警告,此为预设值。
  • SQLSRV_ERR_ERRORS:传回错误。
  • SQLSRV_ERR_WARNINGS:传回警告。
sqlsrv_errors 函式会传回阵列或null 型别的资料,null 表示没有最近没有产生错误或警告,而阵列则包含了3 组键/值(以下键值亦可是0、1、2 等数值):
  • SQLSTATE:
    • 若是源自ODBC 驱动程式的错误,SQLSTATE 是由ODBC 传回,细节可参考ODBS 错误码。
    • 若是源自SQL Server 2005 Driver for PHP 的错误,SQLSTATE 为IMSSP。
    • 若是源自SQL Server 2005 Driver for PHP 的警告,SQLSTATE 为01SSP。
  • code:
    • 若是源自SQL Server 的错误,是SQL Server 本生的错误码。
    • 若是源自ODBC 驱动程式的错误,错误码会由ODBC 传回。
    • 若是源自SQL Server 2005 Driver for PHP 的错误,错误码会由SQL Server 2005 Driver for PHP 传回。
  • message:描述错误的讯息。
显示错误或警告讯息
我们可以用print_r 来显示整个物件:
print_r(sqlsrv_errors());
也可以一一显示物件的内容:
$errors = sqlsrv_errors();foreach( $errors as $error){ echo "SQLSTATE: ".$error[ 'SQLSTATE']."</br> ;"; echo "code: ".$error[ 'code']."</br>"; echo "message : ".$error[ 'message']."</br>";}不过,处理之前,最好先检查是不是真的有错误或警告:if( ($errors = sqlsrv_errors() ) != null){ // 有错误或警告}
结语
SQL Server 2005 Driver for PHP 提高了PHP 程式存取Microsoft SQL Server 的透通性,尤其是较新的SQL Server 2005、或最新的SQL Server 2008。目前的SQL Server 2005 Driver for PHP 1.0 提供了24 个函式,供作PHP 程式存取SQL Server 之用。虽然本文花了相当的篇幅及例子在说明这些函式,但依然无法尽数说完所有的函式;就算已说明的函式,也无法完全解说所有细节。
因此完整的说明,需请您参阅微软提供的文件(SQL Server Driver for PHP Documentation);除了可于微软网站查阅,下载回来的SQL Server 2005 Driver for PHP档案(SQLServerDriverForPHP.EXE),也包含内容相同的线上说明档(SQLServerDriverForPHP_1.0.8204.chm)。

Tags:

PHP技术资料

添加评论



(将显示你的Gravatar头像)  

biuquote
微笑得意调皮害羞酷大笑惊讶发呆喜欢可怜尴尬闭嘴噘嘴皱眉伤心抓狂呕吐坏笑漫骂发怒
Loading



Supidea.com 晨飞的梦 @ All Rights Reserved. Powered by BlogYi.NET ver:1.8.0.0. 苏ICP备09011404号

关于博主

kamau
抱着美好的理想背井离乡,这酸甜苦辣只能默默忍受。既然选择了路,就得风雨兼程……

Calendar

<<  二月 2012  >>
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011

在日历中查看文章

最近的评论

Comment RSS

声明

      本博所发一切破解相关附件只作学习研究交流之用,严禁用于商业用途,请在下载24小时内删除。
      本博所有网友评论不代表本博立场,版权归其作者所有。

© Copyright 2009