PHP的PDO连接数据库测试

Php IT敢客 2年前 (2016-11-03) 8776次浏览 已收录 0个评论 扫描二维码

PDO 一是 PHP 数据对象(PHP Data Object)的缩写。

以连接 Mysql 和 Sqlserver 为例进行测试:

PDO 连接的方便就是统一化。

(1)Mysql

<?php
header("Content-Type:text/html;charset=utf8");
$dbms='mysql';
$dbName='phptest';
$user='root';
$pwd='111111';
$host='localhost';
$dsn="$dbms:host=$host;dbname=$dbName";
try {
$pdo=new PDO($dsn,$user,$pwd);
echo "PDO 连接 Mysql 成功";
} catch (Exception $e) {
echo $e->getMessage()."<br>";
}
?>

(2)Sqlserver

<?php
header("Content-Type:text/html;charset=utf8");
$dbms='sqlsrv';
$dbName='phptest';
$user='sa';
$pwd='11111';
$host='localhost';
$dsn="$dbms:server=$host;Database=$dbName";
try {
$pdo=new PDO($dsn,$user,$pwd);
echo "PDO 连接 SqlServer 成功";
} catch (Exception $e) {
echo $e->getMessage()."<br>";
}
?>

下面是以 DB2 数据库连接做一系列的测试。

1、连接管理

连接是通过创建 PDO 基类的实例而建立的。不管您想要使用哪种驱动程序,您总是使用 PDO 类名。构造函数接受用于指定数据源(即 DSN)的参数,可能还包括用户名和密码参数(如果有的话)。最后一个参数用于传递附加的调优参数到 PDO 或底层驱动程序 —— 后面很快会有更详细的论述。下面是一个简短的连接到 DB2 的示例脚本:

清单 2. 如何使用 PDO 连接到 DB2

try { $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2'); echo "Connected
";} catch (Exception $e) { echo "Failed: " . $e->getMessage();}

odbc:SAMPLE 告诉 PDO 它应该使用 ODBC 驱动程序,并且应该使用 "SAMPLE" 数据库。如果使用一个驱动程序管理器,那么可以用一个 ODBC 级数据源名称替代 SAMPLE。实际上,在冒号字符之后可以指定任何有效的 ODBC 数据源连接字符串。

如果连接成功,您将看到消息 "Connected",否则,PDO 将抛出一个 PDOException,解释为什么连接失败。可能的原因包括无效的参数,不正确的用户/密码,甚至是您忘了装载驱动程序。

值得注意的是,除非您捕捉从构造函数抛出的异常,否则,如果 PHP 脚本未能连接到数据库,它将终止。这与传统的 PHP 数据库扩展有很大的不同。对于不喜欢异常的人来说,只有两个“硬故障(hard-failure)”点可能抛出异常,这是其中一个点(另一个地点是,当您试图使用事务时缺乏对事务的支持)。对于所有其他错误,PDO 将使用您选择的 错误处理设置。

连接将保持开放状态,直到所有对它的引用被释放。如果在主脚本的顶端打开连接,并将其句柄存储在一个全局变量中,那么该连接将一直处于开放状态,直到脚本结束,或者直到 $dbh 变量被设为 null。如果在一个函数中打开连接,并且只将句柄存储在一个本地变量中,那么当函数返回时,连接将被关闭。这些语义对于 PHP 中的任何对象都是一样的,没有什么特别的地方。

ODBC 连接池如果您使用的是 Windows,或者如果您选择在 UNIX 型平台上使用一个 ODBC 驱动程序管理器,那么值得注意的是,PDO_ODBC 将自动尝试使用该驱动程序管理器的 ODBC 连接池特性。这个特性类似于 PHP 级连接缓存,不要求专门请求一个持久的连接。此外,缓存是在 ODBC 级进行的,这意味着在同一个进程中运行的其他组件(例如在 IIS 下运行的 ASP/.Net 脚本)也能利用相同的连接池。

对于流量较大的站点,让 PHP 在不同请求的间隙中缓存打开的连接,使得每个进程(每个惟一的连接参数集)只需花费一次建立连接的成本,这样做常常很有益处。虽然这听起来像是一个不错的想法,但您应该仔细评估这样做对系统的影响,因为当大量缓存的连接空闲在那里的时候,就会适得其反。

要建立一个缓存的连接(如果您更熟悉传统的数据库扩展的话,也可以说是 *pconnect()),需要在实例化数据库连接时传递一个属性:

清单 3. 如何用 PDO 连接到 DB2,使用持久(缓存)连接

try { $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2', array(PDO_ATTR_PERSISTENT => true)); echo "Connected
"; } catch (Exception $e) { echo "Failed: " . $e->getMessage(); }

2、事务提交

至此,您已经通过 PDO 连接到了 DB2,在发出查询之前,您应该理解 PDO 是如何管理事务的。如果之前没有接触过事务,那么首先要知道事务的 4 个特征:原子性(Atomicity)、一致性(Consistency)、独立性(Isolation)和持久性(Durability),即 ACID。用外行人的话说,对于在一个事务中执行的任何工作,即使它是分阶段执行的,也一定可以保证该工作会安全地应用于数据库,并且在工作被提交时,不会受到来自其他连接的影响。事务性工作可以根据请求自动撤销(假设您还没有提交它),这使得脚本中的错误处理变得更加容易。

事务通常是通过把一批更改积蓄起来、使之同时生效而实现的。这样做的好处是可以大大提高这些更新的效率。换句话说,事务可以使脚本更快,而且可能更健壮(不过需要正确地使用事务才能获得这样的好处)。

警告只有在通过 PDO::beginTransaction() 启动事务的情况下,才会发生自动回滚。如果手动地发出开始一个事务的查询,那么 PDO 就无法知道该事务,从而不能在必要时进行回滚。

不幸的是,并不是每种数据库都支持事务,所以当第一次打开连接时,PDO 需要在所谓的“自动提交(auto-commit)”模式下运行。自动提交模式意味着,如果数据库支持事务,那么您所运行的每一个查询都有它自己的隐式事务,如果数据库不支持事务,每个查询就没有这样的事务。如果您需要一个事务,那么必须使用 PDO::beginTransaction() 方法来启动一个事务。如果底层驱动程序不支持事务,那么将会抛出一个 PDOException(无论错误处理设置是怎样的:这总是一个严重错误状态)。在一个事务中,可以使用 PDO::commit() 或 PDO::rollBack() 来结束该事务,这取决于事务中运行的代码是否成功。

DB2 特性虽然我认为事务通常要更快一些,但您还是应该自己评估事务是否真的可以加快代码。例如,在高并发环境中您可能会发现,过度使用事务会增加锁开销。如果在应用程序中出现这种情况,那么建议的补救办法是在一般情况下使用自动提交,而对于真正需要全部 ACID 特征的代码部分则仍然使用事务。

当脚本结束时,或者当一个连接即将被关闭时,如果有一个未完成的事务,那么 PDO 将自动回滚该事务。这是一种安全措施,有助于避免在脚本非正常结束时出现不一致的情况 —— 如果没有显式地提交事务,那么假设有某个地方会出现不一致,所以要执行回滚,以保证数据的安全性。

清单 4. 在事务中执行批处理

try { $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2', array(PDO_ATTR_PERSISTENT => true)); echo "Connected
"; $dbh->setAttribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION); $dbh->beginTransaction(); $dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')"); $dbh->exec("insert into salarychange (id, amount, changedate) values (23, 50000, NOW())"); $dbh->commit(); } catch (Exception $e) { $dbh->rollBack(); echo "Failed: " . $e->getMessage(); }

在上面的示例中,假设我们为一个新雇员创建一组条目,这个雇员有一个 ID 号,即 23。除了输入这个人的基本数据外,我们还需要记录雇员的薪水。两个更新分别完成起来很简单,但通过将这两个更新包括在 beginTransaction() 和 commit() 调用中,就可以保证在更改完成之前,其他人无法看到更改。如果发生了错误,catch 块可以回滚事务开始以来发生的所有更改,并打印出一条错误消息。

并不是一定要在事务中作出更新。您也可以发出复杂的查询来提取数据,还可以使用那种信息构建更多的更新和查询。当事务在活动时,可以保证其他人在工作进行当中无法作出更改。事实上,这不是 100% 的正确,但如果您之前没有听说过事务的话,这样介绍也未尝不可。

关于 PHP 应用程序中安全性的说明

PHP Security Consortium 虽然本文表明在使用 PDO 时不再需要引用输入,但这不是说您应该盲目地使数据通过数据库。XSS 攻击是很实际的危险。您应该总是确保对传入应用程序的不受信任的数据应用适当的过滤器,并采取措施避免让不受信任的数据在站点上发出 HTML 或 javascript。 请访问 The PHP Security Consortium 以了解关于这些危险的更多知识,以及应该如何避免这些危险。

很多 PHP 脚本中一个常见的缺陷是缺乏输入检验。这种缺陷可以被利用,从而招致 XSS(Cross Site Scripting)以及 SQL 入侵攻击。在 SQL 入侵中,不受信任的数据(例如发给 Web 网页的反馈)和其他文本被衔接在一起,构成一个查询。攻击者可以蓄意地安排他们的输入,使之溢出引号之外,并在您想运行的真正查询后面链接上任意一个查询。这种攻击使攻击者可以更新、插入或删除数据,甚至可能可以看到数据库中的任意信息。

XSS 也是一个类似的问题。不过这一次不受信任的数据瞄准的是浏览站点的人们,而不是应用程序本身。通过提交包含 HTML 或 javascript 组合的文本,攻击者期望您之后会将那种数据直接输出到其他访问站点的人那里,从而使恶意代码可以在站点访问者的浏览器上运行。

在编写应用程序时,需要同时考虑这两种攻击。如果小心地检验和过滤输入,这两种攻击都是可以防止的。对 XSS 的处理很有技巧性,所以在这里我不便多讲(不过可以从侧栏找到有用的参考资料)。相比之下,SQL 入侵更容易对付。您只需在构造查询之前,适当地排除每块不受信任的数据。这种事情有点烦杂,特别是当您有大量的字段要处理时,很容易忘记做这件事。

虽然这是有用的(并且也是重要的)信息,但是您可能想知道,为什么我要花时间提到这一点,本文的重点不是结合使用 PDO 和 DB2 吗?原因是这样的:PHP 现在得到很广泛的部署,自然地,大量流行的基于 PHP 的应用程序也得到了广泛的部署。每当某一种这样的应用程序(和 PHP 本身没有联系)被发现存在漏洞时,PHP 常常被误认为是不安全的,可被利用的或者有缺陷的。为了避免将来出现这样的情况,我们可以采取的一个措施是鼓励应用程序开发人员多考虑安全问题,从而减少由诚实的错误导致的损害。扯远了,下面继续介绍其他关键概念。

3、预处理过程

很多更成熟的数据库都支持预处理语句的概念。什么是预处理语句?您可以把预处理语句看作您想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。预处理语句可以带来两大好处:

查询只需解析(或准备)一次,但是可以用相同或不同的参数执行多次。当查询准备好后,数据库将分析、编译和优化执行该查询的计划。对于复杂的查询,这个过程要花比较长的时间,如果您需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度。通过使用预处理语句,可以避免重复分析/编译/优化周期。简言之,预处理语句使用更少的资源,因而运行得更快。 提供给预处理语句的参数不需要用引号括起来,驱动程序会处理这些。如果应用程序独占地使用预处理语句,那么可以确保没有 SQL 入侵发生。(然而,如果您仍然将查询的其他部分建立在不受信任的输入之上,那么就仍然存在风险)。 预处理语句是如此有用,以致 PDO 实际上打破了在目标 4 中设下的规则:如果驱动程序不支持预处理语句,那么 PDO 将仿真预处理语句。

下面是使用预处理语句的两个例子。第一个例子 通过替换指定占位符的 name 和 value,执行一次插入。而 第二个例子 使用问号占位符执行一条 select 语句。

清单 4. 使用预处理语句的重复插入

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); $stmt->bindParam(':name', $name);$stmt->bindParam(':value', $value); // insert one row$name = 'one';$value = 1;$stmt->execute(); // insert another row with different values$name = 'two';$value = 2; $stmt->execute();

清单 5. 使用预处理语句取数据

$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?"); if ($stmt->execute(array('one'))) { while ($row = $stmt->fetch()) { print_r($row); }}

如果数据库驱动程序支持,您还可以绑定输出和输入参数。输出参数通常用于从存储过程获取值。输出参数使用起来比输入参数要复杂一些,当绑定一个给定的输出参数时,必须知道该参数的长度。如果为参数绑定的值大于您建议的长度,那么就会产生错误。

清单 6. 带输出参数调用存储过程

$stmt = $dbh->prepare("CALL sp_returns_string(?)"); $stmt->bindParam(1, $return_value, PDO_PARAM_STR, 4000); // call the stored procedure$stmt->execute(); print "procedure returned $return_value
";

您还可以指定同时具有输入和输出值的参数,其语法类似于输出参数。在接下来的例子中,字符串 'hello' 被传递给存储过程,当存储过程返回时,hello 被替换为该存储过程返回的值。

清单 7. 带输入/输出参数调用存储过程

$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)"); $value = 'hello'; $stmt->bindParam(1, $value, PDO_PARAM_STR|PDO_PARAM_INPUT_OUTPUT, 4000); // call the stored procedure$stmt->execute(); print "procedure returned $value
";

4、错误处理

PDO 提供了 3 种不同的错误处理模式,以满足不同风格的编程:

PDO_ERRMODE_SILENT 这是默认模式。PDO 将只设置错误代码,以通过 errorCode() 和 errorInfo() 方法对语句和数据库对象进行检查。如果错误是由于对语句对象的调用而产生的,那么可以在那个对象上调用 errorCode() 或 errorInfo() 方法。如果错误是由于调用数据库对象而产生的,那么可以在那个数据库对象上调用上述两个方法。 PDO_ERRMODE_WARNING 除了设置错误代码以外,PDO 还将发出一条传统的 E_WARNING 消息。如果您只是想看看发生了什么问题,而无意中断应用程序的流程,那么在调试/测试当中这种设置很有用。 PDO_ERRMODE_EXCEPTION 除了设置错误代码以外,PDO 还将抛出一个 PDOException,并设置其属性,以反映错误代码和错误信息。这种设置在调试当中也很有用,因为它会放大脚本中产生错误的地方,从而可以非常快速地指出代码中有问题的潜在区域(记住,如果异常导致脚本终止,则事务将自动回滚)。 异常模式另一个有用的地方是,与传统的 PHP 风格的警告相比,您可以更清晰地构造自己的错误处理,而且,比起以静寂方式以及显式地检查每个数据库调用的返回值,异常模式需要的代码/嵌套也更少。 PDO 定制了使用 SQL-92 SQLSTATE 错误代码字符串的标准;不同 PDO 驱动程序负责将它们本地代码映射为适当的 SQLSTATE 代码。例如,SQLSTATE 是用于 DB2(以及通常的 ODBC)的本地错误代码格式,这是多么方便啊!errorCode() 方法返回一个 SQLSTATE 代码。如果您需要关于一个错误的更多特定的信息,PDO 还提供了一个 errorInfo() 方法,该方法将返回一个数组,其中包含 SQLSTATE 代码、特定于驱动程序的错误代码以及特定于驱动程序的错误字符串。

分页数据、滚动游标和定位更新

在 Web 应用程序中,一种常见的范例是对查询结果进行分页。如果您使用一个 Internet 搜索引擎,那么很可能每天都会做这样的事。您输入搜索词,然后得到前 10-20 个匹配项。如果您想看到更多搜索结果,可以单击 "next page" 链接。如果想回头看前面看过的结果,可以单击 "previous page" 链接。记得在几年前,当我第一次在 Web 上使用这样的东西时,我对自己说:“为什么我不能通过滚动查看所有数据呢?” 问题的答案说简单也简单,说复杂也复杂 —— 我只想说,HTTP 不会智能地使数据库上的可滚动游标一直处于开放状态,即便如此,需要大量传输的 Web 应用程序也会很快地消耗掉大量开放的可滚动游标。因此,最简单的解决方案是为用户显示所有的匹配项 —— 但是用户很容易迷失在大量的结果当中。比较符合逻辑的措施是人工地将数据格式化到多个页面上,使用户可以每次查看一部分可以管理的数据。

所以人们编写可以取所有数据的 PHP 应用程序,然后只显示前 10 行。根据下一次请求,应用程序又显示 11-20 行,依此类推。这对于只返回少量数据的查询来说很不错,但是,如果有很多匹配项(比如多于 100),那么先取全部数据然后丢弃其中的 90%,这种做法很浪费。PHP 的创始人 Rasmus Lerdorf 就这种情形特地为 MySQL 发明了一个特殊的 "LIMIT, OFFSET" 子句。它允许您通知数据库,您只对一小部分行感兴趣,这样它就不会取其他不需要的行了。其语法(或非常类似的东西)已经被其他流行的开放源代码数据库采纳,但并不是所有数据库都提供了相同的语法。 Troels Arvin 收集了一些非常有用的信息,对不同 RDBMS 所支持的语法进行了比较。

如果您想在以 DB2 为后台数据库的 PHP 应用程序中实现分页结果,那么可以(也应该)使用下面示例中的语法。这里我们假设有一个 books 表,表中包含书名和作者,我们现在想要每次在一页中显示 10 个以上结果:

清单 8. 使用 SQL Standard "Window Functions" 实现数据分页

$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2'); // the offset is passed in from the user when they click on a link // this cast to integer ensures that no SQL injection can occur $offset = (int)$_GET['offset'];$stmt = $db->prepare("select * from ( select ROW_NUMBER() OVER (ORDER BY author) as rownum, * from books ) as books_windowWHERE rownum > $offset AND rownum <= (10 + $offset)"); if ($stmt->execute()) { while (($row = $stmt->fetch()) !== false) { print_r($row); }}

Cloudscape 说明在撰写本文之际,Cloudscape 在其 SQL 实现中还不支持 ROW_NUMBER(),所以需要使用可滚动游标。

现在,如果您要编写一个更通用的应用程序,并希望实现分页结果集,但是不想专门编写很多的代码,并且也不想使用更重量级的抽象层,Troels Arvin 的非常有帮助的 RDBMS 信息建议,您可以使用游标作为更轻便(稍微慢一点)的方案。碰巧的是,PDO 具有这方面的 API 级的支持。下面将谈到如何使用这种支持来达到与上面示例相同的效果:

清单 9. 使用滚动游标实现数据分页

$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2'); $stmt = $db->prepare("select * from books order by author", array( PDO_ATTR_CURSOR => PDO_CURSOR_SCROLL)); // the offset is passed in from the user when they click on a link // this cast to integer ensures that no SQL injection can occur $offset = (int)$_GET['offset'];if ($stmt->execute()) { // moves the cursor to the requested offset and fetches the first for ($tofetch = 10, $row = $stmt->fetch(PDO_FETCH_ASSOC, PDO_FETCH_ORI_REL, $offset); $row !== false && $tofetch– > 0; $row = $stmt->fetch(PDO_FETCH_ASSOC)) { print_r($row); } }

需要强调的是,虽然滚动游标对于更冗长的 window 函数方案来说是一个很方便的替代方案,但这种方案要慢很多。如果在一个传输量比较少的环境中进行测试,您可能发现不了速度上的差异,但当规模扩大时,您就会开始发现速度降慢带来的痛苦。

定位更新

可滚动游标的另一个用途是,基于 SQL 中无法表达的重大标准驱动更新。如果您有一个 Web 页面链接的表,并且需要在每晚的批处理过程中更新那个表,以反映 Web 页面当前大小,那么可以编写如下代码:

清单 10. 使用滚动游标作出定位更新

$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2'); // create a named, scrolling, updateable cursor $stmt = $db->prepare("select url, size from links FOR UPDATE OF size", array( PDO_ATTR_CURSOR => PDO_CURSOR_SCROLL, PDO_ATTR_CURSOR_NAME => 'link_pos'));if ($stmt->execute()) { // a statement for applying our updates. // Notice the WHERE CURRENT OF clause mentions "link_pos", // which is the name of the cursor we're using to select the data $upd = $db->prepare("UPDATE links set size = ? WHERE CURRENT OF link_pos"); // grab each row while (($row = $stmt->fetch()) !== false) { // There are much more efficient ways to do this; // this is a brief example only: grab all the content // from the URL $content = file_get_conents($row['url']); // and measure its length $size = strlen($content) // and pass that as a parameter to our update statement $upd->execute(array($size)); }}

大型对象

在应用程序中的某个地方,您可能发现需要在数据库中存储“大型(large)”数据。大型通常意味着“大约 4kb 或 4kb 以上”,尽管在没有“大型”数据之前 DB2 最大可以处理 32kb 的数据。 大型对象可以是文本的,也可以是二进制的。PDO 允许在 bindParam() 或 bindColumn() 调用中通过使用 PDO_PARAM_LOB 类型代码来使用大型数据类型。PDO_PARAM_LOB 告诉 PDO 将数据映射为流,所以可以使用 PHP Streams API 来操纵这样的数据。下面是一个示例:

5、程序功能

清单 11. 从数据库取一副图像

$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2'); $stmt = $db->prepare("select contenttype, imagedata from images where id=?"); $stmt->execute(array($_GET['id']));list($type, $lob) = $stmt->fetch(); header("Content-Type: $type");fpassthru($lob);

上面的介绍很简明扼要。现在让我们试试另一面,将上传的图像插入到一个数据库中:

清单 12. 将图像插入数据库中

$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2'); $stmt = $db->prepare("insert into images (id, contenttype, imagedata) values (?, ?, ?)"); $id = get_new_id(); // some function to allocate a new ID // assume that we are running as part of a file upload form // You can find more information in the PHP documentation $fp = fopen($_FILES['file']['tmp_name'], 'rb');$stmt->bindParam(1, $id); $stmt->bindParam(2, $_FILES['file']['type']); $stmt->bindParam(3, $fp, PDO_PARAM_LOB); $stmt->execute();

这两个例子都是宏观层次的。请记住,被取的大型对象是一个流,可以通过所有常规的流函数来使用它,例如 fgets()、fread()、fgetcsv() 和 stream_get_contents()。

关于全球化、NLS 和字符集的简要说明

在越来越多的 PHP 应用程序中,越来越重要的一点是让应用程序能够在全球范围内使用。从实践角度来讲,这意味着应用程序需要能够正确地处理多种语言(例如英语和日语)中的数据,并且其功能性不变。这是一个很大的专题,做起来很有技巧性。实现全球化要走的第一步是采用一种适合所有数据的全球编码,例如 UTF-8。这是一种 ASCII 兼容的编码,它可以使用特殊字符序列为整个 unicode 字符集编码。UTF-8 也是一种多字节编码。

与常规 ASCII 字符串相比,多字节编码的字符串处理起来要棘手一点,因为一个或多个字符对应于一个给定的字母 —— 例如,UTF-8 允许最多 6 个字符的序列映射到字符串中的一个字母。ASCII 字符在 UTF-8 中仍具有相同的表示,因此,如果只是处理不带任何特殊音调的纯英文文本,则 UTF-8 看上去就像是 ASCII。这意味着类似的字符串函数(作用于字节而不是字符位置),例如 strlen() 和 substr(),可能得不到预期的效果,这取决于 UTF-8 字符串中的内容。幸运的是,PHP iconv 扩展为这些函数提供了一些编码感知的替代函数。例如,您可以使用 iconv_strlen() 来得出字符串中的字符数,而不是使用 strlen()。类似地,您可以不用 strpos() 或 substr(),而使用 iconv_strpos() 和 iconv_substr()。

iconv 扩展为您提供了在处理多种编码下的数据时所需的基本工具。应用程序应该尽量确保所有数据都是 UTF-8 编码的。如果用适当的 Content-Type 标记 Web 页面,那么大多数浏览器将发送 UTF-8 编码的数据,可以确信,一定有一个编码类型属性可应用于 HTML FORM 标签。

接下来的一步是设置 DB2 实例,使它在您与之交互时使用 UTF-8。这很容易办到,只需在 DB2 的命令行提示符中运行以下命令:

清单 14. 设置 DB2 实例,使之使用 UTF-8

$ db2set DB2CODEPAGE=1208

完成这样的更改后,从 DB2 实例取到的所有文本数据都是 UTF-8 编码的。同样,DB2 期望您输入的所有文本也是 UTF-8 编码的。当应用程序的每个部分都使用 UTF-8 时,应用程序就可以全球使用了,并且能够显示任何语言的文本,只要这种语言的文本可以用 UTF-8 编码。前面我已经暗示过,这只是通往国际化大道的第一步。还有很多其他的事情需要考虑,例如本地化(采用给定用户的地区设置来显示日期、时间、重量和度量,将通用文本翻译成用户本地的语言)、从右到左或双向(bi-di)文本布局,等等。

值得注意的是,PDO 不对该数据做任何特殊的事情。有些驱动程序允许更改为一个连接使用的编码,但是在 PDO 级没有处理这种事情的特殊逻辑。其原因是,PHP 内部完全不知道 unicode,所以在这里试图使 PDO 知道 unicode 是没有意义的。如果您对这方面的专题感兴趣,那么您会欣喜地得知,PHP 的 unicode 支持很快就要出现,不过我也不知道它初次露面的确切日期。


IT 敢客 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:PHP 的 PDO 连接数据库测试
喜欢 (155)
[313176056@qq.com]
分享 (0)
IT敢客
关于作者:
“我所做的一切都是为了方便我的生活~~~“
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址