专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »PHP教程 » phppdo:通过 PDO 将 PHP 连接到 DB2 和 Cloudscape »正文

phppdo:通过 PDO 将 PHP 连接到 DB2 和 Cloudscape

来源: 发布时间:星期一, 2009年1月12日 浏览:41次 评论:0
  PHP 5.1 发布时将附带个全新数据库连接层即 PHP Data Objects (PDO)虽然 PHP 直都拥有很好数据库连接但 PDO 让 PHP 达到个新高度学习如何获得、安装和使用 PDO以连接到 IBM? DB2? Universal Database? 和 IBM Cloudscape? 数据库插入和检索数据并探索更多高级特性例如预处理语句(prepared statements)、绑定参数(bound parameters)、可滚动游标(scrollable cursors)、定位更新(positioned updates)以及 LOB另外本文将简要地介绍下对多字节数据处理

  背景

  随着拥有更成熟 OO 语法 PHP 5 发布PHP 越来越多地受到越来越大机构关注对于 PHP 来说提供更加和可访问数据访问 API 变得越来越重要

  PHP 和流行开放源代码关系数据库管理系统(RDBMS)MySQL 的间总是很有默契这对拍档成功很大程度上是由于它们免费可用而且进入门槛也比较低这两种产品合作使它们各自都取得了广受推崇地位

  很多 PHP 应用开发人员都习惯于 PHP-MySQL 这对组合以致 PHP 对其他数据库支持常常模仿 MySQL 客户机库 API然而并不是所有数据库客户机 API 都是也不是所有数据库都提供相同特性虽然存在模仿但区别 PHP 数据库扩展都有它们各自怪僻和区别的处所以从种数据库迁移到另种数据库时会有些困难虽然这不是创建 PDO 直接原因但是在设计过程中还是有定影响

  如果您是带着想结合使用 PHP 和 DB2 阅读本文那么您很可能属于以下类型中种:

  您从家小公司开始在 MySQL(举个例子)上运行 PHP由于业务增长您需要 DB2 所提供可伸缩性/可靠性/支持或其他特性您希望移植代码以使用 DB2但由于 API 变化您需要编写或实现个抽象层以便在 DB2 上测试应用同时可以继续在旧数据库上运行不仅如此您还希望能有自己选择并保留支持其他 RDBMS 可能性您清楚有些客户机可能已经和其他平台栓在起了

  您用 PHP 在 MySQL的上构建了个小型部门应用(同样这只是举个例子我并不是要跟 MySQL 过不去)事实证明这个应用本身很有用现在已经在这个部门的外使用并且闯入了 CIO/CTO 法眼 —— 现在需要遵从托管标准数据库(是这是第个变种)

  在其他某些复杂企业级应用后台您已经有个 DB2 例子;您希望利用 PHP 快速应用开发和原型设计来生成动态报告

  目标

  至此我们已经掌握了数据库及 PHP 背景知识现在正好可以提及 PDO 背后些设计目标:

  为大多数数据库 API 中常见特性提供 API

  具有可扩展性以使数据库供应商 X 仍然可以暴露特性 Y 并保持 PDO 兼容性

  提供大量基本兼容性窍门技巧以便能够更方便地创建跨数据库兼容应用

  不为给定数据库 API 中本来没有特性(例如序列)提供完全抽象或仿真PDO 类意图为您提供对数据库本地特性致性访问并减少干扰

  通过将和 PHP 内部打交道代码(这是最难于编写部分)集中起来简化 PHP 数据库驱动创建

  最后点非常重要PDO 是模块化结构它被分成个公共核心以及个或多个驱动扩展公共核心提供了在脚本(PDO 本身)中使用 API驱动扩展则为 PDO 和本地 RDBMS 客户机 API 库架起座桥梁DB2 用户将会希望使用 PDO_ODBC 驱动据称它可以提供以下特性:

  它经过重新编写能支持遵从 ODBC V3 驱动和驱动管理器它还考虑了对 DB2 特定特性和优化支持这成为设计过程中部分 —— 不是后来补充

  它支持经过试验和测试存储过程和大型对象它不仅能够工作而且非常好用

  对于取 10,000 行记录这样 DB2 访问操作使用 PDO_ODBC 驱动性能比使用传统 PHP Unied ODBC 扩展要快大约 10 倍的所以有这么大差异在 PDO 中默认游标是轻量级只能向前移动游标

  获取和安装 PDO

  PHP 5.1 发布时将附带 PDO但是也可以通过 PECL 这个 PHP 扩展库(PHP Extension Repository)来结合使用 PDO 和 PHP 5.0.3 及以上版本如果您使用是 Windows?那么您会欣喜地发现安装过程要简单得多

  我将假设您已经拥有配置 PHP 5 使的使用您选择 Web 服务器经验只有在此假设下我才能集中精力关注更相关细节同样我还将假设您使用个 DB2 Universal Database 服务器或网络服务器模式下 IBM Cloudscape 数据库并且接受了用户为 db2inst1、密码为 ibmdb2 默认安装选项如果您自己编译驱动那么在进行编译机器上应该安装有 DB2 客户机并且存在应用开发 header否则编译将遭到失败

  在 PHP 5.0.3 及以上版本上通过 PECL 进行安装

  默认情况下PHP 将安装 "PEAR" 包管理系统您选择 OS 发行版很可能已经创建了个包含 PEAR 组件很可能您已经安装了这个包并准备运行它让我们试验

  清单 1. 列出已安装 PEAR 包

        $ pear list
Installed packages:
=
Package    Version State
Archive_Tar  1.1   stable
Console_Getopt 1.2   stable
PEAR      1.3.4  stable
XML_RPC    1.1.0  stable


  这个包列表表明我已经安装了 PEAR 1.3.4很可能您也会安装那个版本为了成功地安装 PDO需要升级到 PEAR 1.3.5;这个过程很快很顺利:

$ sudo pear upgrade PEAR

  现在便可以放心安装 PDO 了:

$ sudo pear PDO

  您已经安装了 PDO 核心为了使的生效需要在 php.ini 文件中启用它您需要添加以下行:

extension=pdo.so

  现在安装用于 PDO ODBC 驱动如果您需要连接到 DB2、Cloudscape 或 Apache Derby就需要这个驱动:

$ sudo pear PDO_ODBC

  您将看到这样提示:flavour,dir ? (just leave blank for help)这是个稍微有点隐蔽提示它询问需要配置哪种类型 ODBC 驱动以及将它安装在哪里如果在安装 DB2 时选择了默认安装选项那么可以输入 ibm-db2这相当于 ibm-db2,/home/db2inst1/sqllib如果您选择了区别安装位置那么应该用它置替换 /home/db2inst1/sqllib输入了正确细节后按下 enter 键这样驱动就会构建和安装

  您需要将驱动添加到 php.ini 文件中从而激活驱动确保将下面这行添加在的前所添加 pdo.so 这行的后否则 PHP 不能正确地

extension=pdo_odbc.so

  PHP 5.1 及以上版本上安装

  PHP 5.1 发布时附带了 PDO为获得 DB2 支持只需将下面开关添加到配置行您显然希望添加更多配置选项以满足您自己 Web 服务器有关这方面详细内容可以查看 PHP 文档我将假设您使用个最近 Linux? 发行版并运行 Apache 2:

$ tar xjf php-5.1.0.tar.bz2
$ cd php-5.1.0
$ ./configure --with-pdo-odbc=ibm-db2,/home/db2inst1/sqllib
       --with-apxs2=/usr/sbin/apxs
$ make
$ sudo make


  Windows 上安装

  Windows 上安装比起 UNIX? 上安装来要简单如果您下载了 PHP 5.1那么就已经拥有了这个包中相关 DLL否则您需要从 PHP 快照站点(请参阅本文后面“下载”小节)下载这些 DLL

  为了激活 PDO将下面两行添加到 php.ini 文件:

extension=php_pdo.dll
extension=php_pdo_odbc.dll


  重新启动 Web 服务器

  安装完毕后应该完全重新启动 Web 服务器以确保 PHP 装载新扩展这样就可以开始使用 PDO 了如果您使用是 UNIX 平台那么需要获得 DB2 客户机 DB2 例子环境以便正确地如果您使用是 bourne shell 型 shell那么可以通过运行命令 . /home/db2inst1/sqllib/db2profile 来获得(注意: 假定开头部分句号已经在那里!)您需要作出安排使的在 Web 服务器启动脚本中自动发生

  PDO 中关键概念

  为了掌握 PDO需要了解 5 个关键概念这 5 个概念是:

  连接和连接管理

  事务和自动提交

  预处理语句和存储过程

  处理

  特定于驱动功能性包括 滚动游标 和 大型对象

  连接和连接管理

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

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

        try {
 $dbh = PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
 echo "Connectedn";
} 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 中任何对象都是没有什么特别地方

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

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

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

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


  事务和自动提交

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

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

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

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

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

try {
 $dbh = PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
   .gif' />(PDO_ATTR_PERSISTENT => true));
 echo "Connectedn";
 $dbh->Attribute(PDO_ATTR_ERRMODE, PDO_ERRMODE_EXCEPTION);
 $dbh->beginTransaction;
 $dbh->exec("insert o staff (id, first, last) values (23, 'Joe', 'Bloggs')");
 $dbh->exec("insert o 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 脚本中个常见缺陷是缺乏输入检验这种缺陷可以被利用从而招致 XSS(Cross Site Scripting)以及 SQL 入侵攻击在 SQL 入侵中不受信任数据(例如发给 Web 网页反馈)和其他文本被衔接在构成个查询攻击者可以蓄意地安排他们输入使的溢出引号的外并在您想运行真正查询后面链接上任意个查询这种攻击使攻击者可以更新、插入或删除数据甚至可能可以看到数据库中任意信息

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

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

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

  预处理语句和存储过程

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

  查询只需解析(或准备)但是可以用相同或区别参数执行多次当查询准备好后数据库将分析、编译和优化执行该查询计划对于复杂查询这个过程要花比较长时间如果您需要以区别参数多次重复相同查询那么该过程将大大降低应用速度通过使用预处理语句可以避免重复分析/编译/优化周期简言的预处理语句使用更少资源因而运行得更快

  提供给预处理语句参数不需要用引号括起来驱动会处理这些如果应用独占地使用预处理语句那么可以确保没有 SQL 入侵发生(然而如果您仍然将查询其他部分建立在不受信任输入的上那么就仍然存在风险)

  预处理语句是如此有用以致 PDO 实际上打破了在目标 4 中设下规则:如果驱动不支持预处理语句那么 PDO 将仿真预处理语句

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

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

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insert _disibledevent= 2;
$stmt->execute;


0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: