PDO一是PHP數(shù)據(jù)對(duì)象(PHP Data Object)的縮寫。二是丙二醇簡(jiǎn)稱PDO。三是阿曼石油開(kāi)發(fā)公司 (petroleum development of Oman.)的縮寫。四是過(guò)程數(shù)據(jù)對(duì)象(Process data object)的縮寫。五是太平洋十年濤動(dòng)。
至此我們已經(jīng)掌握了數(shù)據(jù)庫(kù)及 PHP 的背景知識(shí),現(xiàn)在正好可以提及 PDO 背后的一些設(shè)計(jì)目標(biāo):
為大多數(shù)數(shù)據(jù)庫(kù) API 中的常見(jiàn)特性提供一致的 API。
具有可擴(kuò)展性,以使數(shù)據(jù)庫(kù)供應(yīng)商 X 仍然可以暴露特性 Y 并保持 PDO 的兼容性。
提供大量基本的兼容性技巧,以便能夠更方便地創(chuàng)建跨數(shù)據(jù)庫(kù)兼容的應(yīng)用程序。
不為給定數(shù)據(jù)庫(kù) API 中本來(lái)沒(méi)有的特性(例如序列)提供完全抽象或仿真。PDO 類意圖為您提供對(duì)數(shù)據(jù)庫(kù)本地特性的一致性訪問(wèn),并減少干擾。
通過(guò)將與 PHP 內(nèi)部打交道的代碼(這是最難于編寫的部分)集中起來(lái),簡(jiǎn)化 PHP 數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序的創(chuàng)建。
最后一點(diǎn)非常重要。PDO 是模塊化結(jié)構(gòu),它被分成一個(gè)公共核心以及一個(gè)或多個(gè)驅(qū)動(dòng)程序擴(kuò)展,公共核心提供了在腳本(PDO 本身)中使用的 API,驅(qū)動(dòng)程序擴(kuò)展則為 PDO 和本地 RDBMS 客戶機(jī) API 庫(kù)架起一座橋梁。DB2 用戶將會(huì)希望使用 PDO_ODBC 驅(qū)動(dòng)程序,據(jù)稱它可以提供以下特性:
它經(jīng)過(guò)重新編寫,能支持遵從 ODBC V3 的驅(qū)動(dòng)程序和驅(qū)動(dòng)程序管理器。它還考慮了對(duì) DB2 特定特性和優(yōu)化的支持,這成為設(shè)計(jì)過(guò)程中的一部分 -- 不是后來(lái)補(bǔ)充的。
它支持經(jīng)過(guò)試驗(yàn)和測(cè)試的存儲(chǔ)過(guò)程和大型對(duì)象。它不僅能夠工作,而且非常好用。
對(duì)于取 10,000 行記錄這樣的 DB2 訪問(wèn)操作,使用 PDO_ODBC 驅(qū)動(dòng)程序時(shí)的性能比使用傳統(tǒng)的 PHP Unified ODBC 擴(kuò)展要快大約 10 倍。之所以有這么大的差異,是因?yàn)樵?PDO 中默認(rèn)的游標(biāo)是輕量級(jí)的只能向前移動(dòng)的游標(biāo)。
并不能使用PDO擴(kuò)展本身執(zhí)行任何數(shù)據(jù)庫(kù)操作,必須使用一個(gè)database-specific PDO driver(針對(duì)特定數(shù)據(jù)庫(kù)的PDO驅(qū)動(dòng))訪問(wèn)數(shù)據(jù)庫(kù)服務(wù)器。
PDO并不提供數(shù)據(jù)庫(kù)抽象,它并不會(huì)重寫SQL或提供數(shù)據(jù)庫(kù)本身缺失的功能,如果你需要這種功能,你需要使用一個(gè)更加成熟的抽象層。
PDO需要PHP5核心OO特性的支持,所以它無(wú)法運(yùn)行于之前的PHP版本。
隨著擁有更成熟 OO 語(yǔ)法的 PHP 5 的發(fā)布,PHP 越來(lái)越多地受到越來(lái)越大的機(jī)構(gòu)的關(guān)注,對(duì)于 PHP 來(lái)說(shuō),提供更加一致的和可訪問(wèn)的數(shù)據(jù)訪問(wèn) API 變得越來(lái)越重要。
PHP 與流行的開(kāi)放源代碼關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)(RDBMS)MySQL 之間總是很有默契。這對(duì)拍檔的成功很大程度上是由于它們免費(fèi)可用,而且進(jìn)入的門檻也比較低,這兩種產(chǎn)品的合作使它們各自都取得了廣受推崇的地位。
很多 PHP 應(yīng)用程序開(kāi)發(fā)人員都習(xí)慣于 PHP-MySQL 這對(duì)組合,以致 PHP 對(duì)其他數(shù)據(jù)庫(kù)的支持常常模仿 MySQL 客戶機(jī)庫(kù) API。然而,并不是所有的數(shù)據(jù)庫(kù)客戶機(jī) API 都是一樣的,也不是所有的數(shù)據(jù)庫(kù)都提供相同的特性。雖然存在模仿,但不同的 PHP 數(shù)據(jù)庫(kù)擴(kuò)展都有它們各自的怪僻和不同之處,所以從一種數(shù)據(jù)庫(kù)遷移到另一種數(shù)據(jù)庫(kù)時(shí)會(huì)有一些困難。雖然這不是創(chuàng)建 PDO 的直接原因,但是在設(shè)計(jì)過(guò)程中還是有一定影響的。
如果您是帶著想結(jié)合使用 PHP 和 DB2 的目的閱讀本文,那么您很可能屬于以下類型中的一種:
您從一家小公司開(kāi)始,在 MySQL(舉個(gè)例子)上運(yùn)行 PHP,由于業(yè)務(wù)增長(zhǎng),您需要 DB2 所提供的可伸縮性/可靠性/支持或其他特性。您希望移植代碼,以使用 DB2,但由于 API 的變化,您需要編寫或?qū)崿F(xiàn)一個(gè)抽象層,以便在 DB2 上測(cè)試應(yīng)用程序的同時(shí)可以繼續(xù)在舊的數(shù)據(jù)庫(kù)上運(yùn)行。不僅如此,您還希望能有自己的選擇,并保留支持其他 RDBMS 的可能性,因?yàn)槟宄行┛蛻魴C(jī)可能已經(jīng)和其他平臺(tái)栓在一起了。
您用 PHP 在 MySQL之上構(gòu)建了一個(gè)小型的部門應(yīng)用程序(同樣,這只是舉個(gè)例子,我并不是要跟 MySQL 過(guò)不去)。事實(shí)證明這個(gè)應(yīng)用程序本身很有用,現(xiàn)在已經(jīng)在這個(gè)部門之外使用,并且闖入了 CIO/CTO 的法眼 -- 現(xiàn)在需要遵從托管的標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)。(是的,這是第一點(diǎn)的一個(gè)變種。) 在其他某些復(fù)雜的企業(yè)級(jí)應(yīng)用程序的后臺(tái),您已經(jīng)有一個(gè) DB2 實(shí)例,您希望利用 PHP 的快速應(yīng)用程序開(kāi)發(fā)和原型設(shè)計(jì)來(lái)生成動(dòng)態(tài)報(bào)告。
1,3-丙二醇簡(jiǎn)稱PDO
中文名稱: 1,3-丙二醇
英文名稱: 1,3-propanediol
英文名稱2: 1,3-dihydroxypropane
分子式: C3H8O2
結(jié)構(gòu): HOCH2CH2CH2OH
CAS No.: 504-63-2
分子量: 76.10
外觀與性狀: 無(wú)色、無(wú)臭,具咸味、吸濕性的粘稠液體。(純品)
熔點(diǎn)(℃): -27
沸點(diǎn)(℃): 210-211
相對(duì)密度(水=1): 1.05(25℃)
相對(duì)蒸氣密度(空氣=1): 2.6
飽和蒸氣壓(kPa): 0.13(60℃)
閃點(diǎn)(℃): 79
引燃溫度(℃): 400
爆炸上限%(V/V): 無(wú)資料
爆炸下限%(V/V): 無(wú)資料
溶解性: 與水混溶,可混溶于乙醇、乙醚。
主要用途: 用作溶劑, 用于有機(jī)合成。
連接是通過(guò)創(chuàng)建 PDO 基類的實(shí)例而建立的。不管您想要使用哪種驅(qū)動(dòng)程序,您總是使用 PDO 類名。構(gòu)造函數(shù)接受用于指定數(shù)據(jù)源(即 DSN)的參數(shù),可能還包括用戶名和密碼參數(shù)(如果有的話)。最后一個(gè)參數(shù)用于傳遞附加的調(diào)優(yōu)參數(shù)到 PDO 或底層驅(qū)動(dòng)程序 -- 后面很快會(huì)有更詳細(xì)的論述。下面是一個(gè)簡(jiǎn)短的連接到 DB2 的示例腳本:
清單 2. 如何使用 PDO 連接到 DB2
try { $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2'); echo "Connected\n";} catch (Exception $e) { echo "Failed: " . $e->getMessage();} |
odbc:SAMPLE 告訴 PDO 它應(yīng)該使用 ODBC 驅(qū)動(dòng)程序,并且應(yīng)該使用 "SAMPLE" 數(shù)據(jù)庫(kù)。如果使用一個(gè)驅(qū)動(dòng)程序管理器,那么可以用一個(gè) ODBC 級(jí)數(shù)據(jù)源名稱替代 SAMPLE。實(shí)際上,在冒號(hào)字符之后可以指定任何有效的 ODBC 數(shù)據(jù)源連接字符串。
如果連接成功,您將看到消息 "Connected",否則,PDO 將拋出一個(gè) PDOException,解釋為什么連接失敗??赡艿脑虬o(wú)效的參數(shù),不正確的用戶/密碼,甚至是您忘了裝載驅(qū)動(dòng)程序。
值得注意的是,除非您捕捉從構(gòu)造函數(shù)拋出的異常,否則,如果 PHP 腳本未能連接到數(shù)據(jù)庫(kù),它將終止。這與傳統(tǒng)的 PHP 數(shù)據(jù)庫(kù)擴(kuò)展有很大的不同。對(duì)于不喜歡異常的人來(lái)說(shuō),只有兩個(gè)"硬故障(hard-failure)"點(diǎn)可能拋出異常,這是其中一個(gè)點(diǎn)(另一個(gè)地點(diǎn)是,當(dāng)您試圖使用事務(wù)時(shí)缺乏對(duì)事務(wù)的支持)。對(duì)于所有其他錯(cuò)誤,PDO 將使用您選擇的 錯(cuò)誤處理設(shè)置。
連接將保持開(kāi)放狀態(tài),直到所有對(duì)它的引用被釋放。如果在主腳本的頂端打開(kāi)連接,并將其句柄存儲(chǔ)在一個(gè)全局變量中,那么該連接將一直處于開(kāi)放狀態(tài),直到腳本結(jié)束,或者直到 $dbh 變量被設(shè)為 null。如果在一個(gè)函數(shù)中打開(kāi)連接,并且只將句柄存儲(chǔ)在一個(gè)本地變量中,那么當(dāng)函數(shù)返回時(shí),連接將被關(guān)閉。這些語(yǔ)義對(duì)于 PHP 中的任何對(duì)象都是一樣的,沒(méi)有什么特別的地方。
ODBC 連接池如果您使用的是 Windows,或者如果您選擇在 UNIX 型平臺(tái)上使用一個(gè) ODBC 驅(qū)動(dòng)程序管理器,那么值得注意的是,PDO_ODBC 將自動(dòng)嘗試使用該驅(qū)動(dòng)程序管理器的 ODBC 連接池特性。這個(gè)特性類似于 PHP 級(jí)連接緩存,不要求專門請(qǐng)求一個(gè)持久的連接。此外,緩存是在 ODBC 級(jí)進(jìn)行的,這意味著在同一個(gè)進(jìn)程中運(yùn)行的其他組件(例如在 IIS 下運(yùn)行的 ASP/.Net 腳本)也能利用相同的連接池。 |
對(duì)于流量較大的站點(diǎn),讓 PHP 在不同請(qǐng)求的間隙中緩存打開(kāi)的連接,使得每個(gè)進(jìn)程(每個(gè)惟一的連接參數(shù)集)只需花費(fèi)一次建立連接的成本,這樣做常常很有益處。雖然這聽(tīng)起來(lái)像是一個(gè)不錯(cuò)的想法,但您應(yīng)該仔細(xì)評(píng)估這樣做對(duì)系統(tǒng)的影響,因?yàn)楫?dāng)大量緩存的連接空閑在那里的時(shí)候,就會(huì)適得其反。
要建立一個(gè)緩存的連接(如果您更熟悉傳統(tǒng)的數(shù)據(jù)庫(kù)擴(kuò)展的話,也可以說(shuō)是 *pconnect()),需要在實(shí)例化數(shù)據(jù)庫(kù)連接時(shí)傳遞一個(gè)屬性:
清單 3. 如何用 PDO 連接到 DB2,使用持久(緩存)連接
try { $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2', array(PDO_ATTR_PERSISTENT => true)); echo "Connected\n"; } catch (Exception $e) { echo "Failed: " . $e->getMessage(); } |
至此,您已經(jīng)通過(guò) PDO 連接到了 DB2,在發(fā)出查詢之前,您應(yīng)該理解 PDO 是如何管理事務(wù)的。如果之前沒(méi)有接觸過(guò)事務(wù),那么首先要知道事務(wù)的 4 個(gè)特征:原子性(Atomicity)、一致性(Consistency)、獨(dú)立性(Isolation)和持久性(Durability),即 ACID。用外行人的話說(shuō),對(duì)于在一個(gè)事務(wù)中執(zhí)行的任何工作,即使它是分階段執(zhí)行的,也一定可以保證該工作會(huì)安全地應(yīng)用于數(shù)據(jù)庫(kù),并且在工作被提交時(shí),不會(huì)受到來(lái)自其他連接的影響。事務(wù)性工作可以根據(jù)請(qǐng)求自動(dòng)撤銷(假設(shè)您還沒(méi)有提交它),這使得腳本中的錯(cuò)誤處理變得更加容易。
事務(wù)通常是通過(guò)把一批更改積蓄起來(lái)、使之同時(shí)生效而實(shí)現(xiàn)的。這樣做的好處是可以大大提高這些更新的效率。換句話說(shuō),事務(wù)可以使腳本更快,而且可能更健壯(不過(guò)需要正確地使用事務(wù)才能獲得這樣的好處)。
警告只有在通過(guò) PDO::beginTransaction() 啟動(dòng)事務(wù)的情況下,才會(huì)發(fā)生自動(dòng)回滾。如果手動(dòng)地發(fā)出開(kāi)始一個(gè)事務(wù)的查詢,那么 PDO 就無(wú)法知道該事務(wù),從而不能在必要時(shí)進(jìn)行回滾。 |
不幸的是,并不是每種數(shù)據(jù)庫(kù)都支持事務(wù),所以當(dāng)?shù)谝淮未蜷_(kāi)連接時(shí),PDO 需要在所謂的"自動(dòng)提交(auto-commit)"模式下運(yùn)行。自動(dòng)提交模式意味著,如果數(shù)據(jù)庫(kù)支持事務(wù),那么您所運(yùn)行的每一個(gè)查詢都有它自己的隱式事務(wù),如果數(shù)據(jù)庫(kù)不支持事務(wù),每個(gè)查詢就沒(méi)有這樣的事務(wù)。如果您需要一個(gè)事務(wù),那么必須使用 PDO::beginTransaction() 方法來(lái)啟動(dòng)一個(gè)事務(wù)。如果底層驅(qū)動(dòng)程序不支持事務(wù),那么將會(huì)拋出一個(gè) PDOException(無(wú)論錯(cuò)誤處理設(shè)置是怎樣的:這總是一個(gè)嚴(yán)重錯(cuò)誤狀態(tài))。在一個(gè)事務(wù)中,可以使用 PDO::commit() 或 PDO::rollBack() 來(lái)結(jié)束該事務(wù),這取決于事務(wù)中運(yùn)行的代碼是否成功。
DB2 特性雖然我認(rèn)為事務(wù)通常要更快一些,但您還是應(yīng)該自己評(píng)估事務(wù)是否真的可以加快代碼。例如,在高并發(fā)環(huán)境中您可能會(huì)發(fā)現(xiàn),過(guò)度使用事務(wù)會(huì)增加鎖開(kāi)銷。如果在應(yīng)用程序中出現(xiàn)這種情況,那么建議的補(bǔ)救辦法是在一般情況下使用自動(dòng)提交,而對(duì)于真正需要全部 ACID 特征的代碼部分則仍然使用事務(wù)。 |
當(dāng)腳本結(jié)束時(shí),或者當(dāng)一個(gè)連接即將被關(guān)閉時(shí),如果有一個(gè)未完成的事務(wù),那么 PDO 將自動(dòng)回滾該事務(wù)。這是一種安全措施,有助于避免在腳本非正常結(jié)束時(shí)出現(xiàn)不一致的情況 -- 如果沒(méi)有顯式地提交事務(wù),那么假設(shè)有某個(gè)地方會(huì)出現(xiàn)不一致,所以要執(zhí)行回滾,以保證數(shù)據(jù)的安全性。
清單 4. 在事務(wù)中執(zhí)行批處理
try { $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2', array(PDO_ATTR_PERSISTENT => true)); echo "Connected\n"; $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(); } |
在上面的示例中,假設(shè)我們?yōu)橐粋€(gè)新雇員創(chuàng)建一組條目,這個(gè)雇員有一個(gè) ID 號(hào),即 23。除了輸入這個(gè)人的基本數(shù)據(jù)外,我們還需要記錄雇員的薪水。兩個(gè)更新分別完成起來(lái)很簡(jiǎn)單,但通過(guò)將這兩個(gè)更新包括在 beginTransaction() 和 commit() 調(diào)用中,就可以保證在更改完成之前,其他人無(wú)法看到更改。如果發(fā)生了錯(cuò)誤,catch 塊可以回滾事務(wù)開(kāi)始以來(lái)發(fā)生的所有更改,并打印出一條錯(cuò)誤消息。
并不是一定要在事務(wù)中作出更新。您也可以發(fā)出復(fù)雜的查詢來(lái)提取數(shù)據(jù),還可以使用那種信息構(gòu)建更多的更新和查詢。當(dāng)事務(wù)在活動(dòng)時(shí),可以保證其他人在工作進(jìn)行當(dāng)中無(wú)法作出更改。事實(shí)上,這不是 100% 的正確,但如果您之前沒(méi)有聽(tīng)說(shuō)過(guò)事務(wù)的話,這樣介紹也未嘗不可。
關(guān)于 PHP 應(yīng)用程序中安全性的說(shuō)明
PHP Security Consortium 雖然本文表明在使用 PDO 時(shí)不再需要引用輸入,但這不是說(shuō)您應(yīng)該盲目地使數(shù)據(jù)通過(guò)數(shù)據(jù)庫(kù)。XSS 攻擊是很實(shí)際的危險(xiǎn)。您應(yīng)該總是確保對(duì)傳入應(yīng)用程序的不受信任的數(shù)據(jù)應(yīng)用適當(dāng)?shù)倪^(guò)濾器,并采取措施避免讓不受信任的數(shù)據(jù)在站點(diǎn)上發(fā)出 HTML 或 javascript。 請(qǐng)?jiān)L問(wèn) The PHP Security Consortium 以了解關(guān)于這些危險(xiǎn)的更多知識(shí),以及應(yīng)該如何避免這些危險(xiǎn)。 |
很多 PHP 腳本中一個(gè)常見(jiàn)的缺陷是缺乏輸入檢驗(yàn)。這種缺陷可以被利用,從而招致 XSS(Cross Site Scripting)以及 SQL 入侵攻擊。在 SQL 入侵中,不受信任的數(shù)據(jù)(例如發(fā)給 Web 網(wǎng)頁(yè)的反饋)和其他文本被銜接在一起,構(gòu)成一個(gè)查詢。攻擊者可以蓄意地安排他們的輸入,使之溢出引號(hào)之外,并在您想運(yùn)行的真正查詢后面鏈接上任意一個(gè)查詢。這種攻擊使攻擊者可以更新、插入或刪除數(shù)據(jù),甚至可能可以看到數(shù)據(jù)庫(kù)中的任意信息。
XSS 也是一個(gè)類似的問(wèn)題。不過(guò)這一次不受信任的數(shù)據(jù)瞄準(zhǔn)的是瀏覽站點(diǎn)的人們,而不是應(yīng)用程序本身。通過(guò)提交包含 HTML 或 javascript 組合的文本,攻擊者期望您之后會(huì)將那種數(shù)據(jù)直接輸出到其他訪問(wèn)站點(diǎn)的人那里,從而使惡意代碼可以在站點(diǎn)訪問(wèn)者的瀏覽器上運(yùn)行。
在編寫應(yīng)用程序時(shí),需要同時(shí)考慮這兩種攻擊。如果小心地檢驗(yàn)和過(guò)濾輸入,這兩種攻擊都是可以防止的。對(duì) XSS 的處理很有技巧性,所以在這里我不便多講(不過(guò)可以從側(cè)欄找到有用的參考資料)。相比之下,SQL 入侵更容易對(duì)付。您只需在構(gòu)造查詢之前,適當(dāng)?shù)嘏懦繅K不受信任的數(shù)據(jù)。這種事情有點(diǎn)煩雜,特別是當(dāng)您有大量的字段要處理時(shí),很容易忘記做這件事。
雖然這是有用的(并且也是重要的)信息,但是您可能想知道,為什么我要花時(shí)間提到這一點(diǎn),本文的重點(diǎn)不是結(jié)合使用 PDO 和 DB2 嗎?原因是這樣的:PHP 現(xiàn)在得到很廣泛的部署,自然地,大量流行的基于 PHP 的應(yīng)用程序也得到了廣泛的部署。每當(dāng)某一種這樣的應(yīng)用程序(和 PHP 本身沒(méi)有聯(lián)系)被發(fā)現(xiàn)存在漏洞時(shí),PHP 常常被誤認(rèn)為是不安全的,可被利用的或者有缺陷的。為了避免將來(lái)出現(xiàn)這樣的情況,我們可以采取的一個(gè)措施是鼓勵(lì)應(yīng)用程序開(kāi)發(fā)人員多考慮安全問(wèn)題,從而減少由誠(chéng)實(shí)的錯(cuò)誤導(dǎo)致的損害。扯遠(yuǎn)了,下面繼續(xù)介紹其他關(guān)鍵概念。
很多更成熟的數(shù)據(jù)庫(kù)都支持預(yù)處理語(yǔ)句的概念。什么是預(yù)處理語(yǔ)句?您可以把預(yù)處理語(yǔ)句看作您想要運(yùn)行的 SQL 的一種編譯過(guò)的模板,它可以使用變量參數(shù)進(jìn)行定制。預(yù)處理語(yǔ)句可以帶來(lái)兩大好處:
查詢只需解析(或準(zhǔn)備)一次,但是可以用相同或不同的參數(shù)執(zhí)行多次。當(dāng)查詢準(zhǔn)備好后,數(shù)據(jù)庫(kù)將分析、編譯和優(yōu)化執(zhí)行該查詢的計(jì)劃。對(duì)于復(fù)雜的查詢,這個(gè)過(guò)程要花比較長(zhǎng)的時(shí)間,如果您需要以不同參數(shù)多次重復(fù)相同的查詢,那么該過(guò)程將大大降低應(yīng)用程序的速度。通過(guò)使用預(yù)處理語(yǔ)句,可以避免重復(fù)分析/編譯/優(yōu)化周期。簡(jiǎn)言之,預(yù)處理語(yǔ)句使用更少的資源,因而運(yùn)行得更快。 提供給預(yù)處理語(yǔ)句的參數(shù)不需要用引號(hào)括起來(lái),驅(qū)動(dòng)程序會(huì)處理這些。如果應(yīng)用程序獨(dú)占地使用預(yù)處理語(yǔ)句,那么可以確保沒(méi)有 SQL 入侵發(fā)生。(然而,如果您仍然將查詢的其他部分建立在不受信任的輸入之上,那么就仍然存在風(fēng)險(xiǎn))。 預(yù)處理語(yǔ)句是如此有用,以致 PDO 實(shí)際上打破了在目標(biāo) 4 中設(shè)下的規(guī)則:如果驅(qū)動(dòng)程序不支持預(yù)處理語(yǔ)句,那么 PDO 將仿真預(yù)處理語(yǔ)句。
下面是使用預(yù)處理語(yǔ)句的兩個(gè)例子。第一個(gè)例子 通過(guò)替換指定占位符的 name 和 value,執(zhí)行一次插入。而 第二個(gè)例子 使用問(wèn)號(hào)占位符執(zhí)行一條 select 語(yǔ)句。
清單 4. 使用預(yù)處理語(yǔ)句的重復(fù)插入
$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. 使用預(yù)處理語(yǔ)句取數(shù)據(jù)
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?"); if ($stmt->execute(array('one'))) { while ($row = $stmt->fetch()) { print_r($row); }} |
如果數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序支持,您還可以綁定輸出和輸入?yún)?shù)。輸出參數(shù)通常用于從存儲(chǔ)過(guò)程獲取值。輸出參數(shù)使用起來(lái)比輸入?yún)?shù)要復(fù)雜一些,當(dāng)綁定一個(gè)給定的輸出參數(shù)時(shí),必須知道該參數(shù)的長(zhǎng)度。如果為參數(shù)綁定的值大于您建議的長(zhǎng)度,那么就會(huì)產(chǎn)生錯(cuò)誤。
清單 6. 帶輸出參數(shù)調(diào)用存儲(chǔ)過(guò)程
$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\n"; |
您還可以指定同時(shí)具有輸入和輸出值的參數(shù),其語(yǔ)法類似于輸出參數(shù)。在接下來(lái)的例子中,字符串 'hello' 被傳遞給存儲(chǔ)過(guò)程,當(dāng)存儲(chǔ)過(guò)程返回時(shí),hello 被替換為該存儲(chǔ)過(guò)程返回的值。
清單 7. 帶輸入/輸出參數(shù)調(diào)用存儲(chǔ)過(guò)程
$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\n"; |
PDO 提供了 3 種不同的錯(cuò)誤處理模式,以滿足不同風(fēng)格的編程:
PDO_ERRMODE_SILENT 這是默認(rèn)模式。PDO 將只設(shè)置錯(cuò)誤代碼,以通過(guò) errorCode() 和 errorInfo() 方法對(duì)語(yǔ)句和數(shù)據(jù)庫(kù)對(duì)象進(jìn)行檢查。如果錯(cuò)誤是由于對(duì)語(yǔ)句對(duì)象的調(diào)用而產(chǎn)生的,那么可以在那個(gè)對(duì)象上調(diào)用 errorCode() 或 errorInfo() 方法。如果錯(cuò)誤是由于調(diào)用數(shù)據(jù)庫(kù)對(duì)象而產(chǎn)生的,那么可以在那個(gè)數(shù)據(jù)庫(kù)對(duì)象上調(diào)用上述兩個(gè)方法。 PDO_ERRMODE_WARNING 除了設(shè)置錯(cuò)誤代碼以外,PDO 還將發(fā)出一條傳統(tǒng)的 E_WARNING 消息。如果您只是想看看發(fā)生了什么問(wèn)題,而無(wú)意中斷應(yīng)用程序的流程,那么在調(diào)試/測(cè)試當(dāng)中這種設(shè)置很有用。 PDO_ERRMODE_EXCEPTION 除了設(shè)置錯(cuò)誤代碼以外,PDO 還將拋出一個(gè) PDOException,并設(shè)置其屬性,以反映錯(cuò)誤代碼和錯(cuò)誤信息。這種設(shè)置在調(diào)試當(dāng)中也很有用,因?yàn)樗鼤?huì)放大腳本中產(chǎn)生錯(cuò)誤的地方,從而可以非??焖俚刂赋龃a中有問(wèn)題的潛在區(qū)域(記住,如果異常導(dǎo)致腳本終止,則事務(wù)將自動(dòng)回滾)。 異常模式另一個(gè)有用的地方是,與傳統(tǒng)的 PHP 風(fēng)格的警告相比,您可以更清晰地構(gòu)造自己的錯(cuò)誤處理,而且,比起以靜寂方式以及顯式地檢查每個(gè)數(shù)據(jù)庫(kù)調(diào)用的返回值,異常模式需要的代碼/嵌套也更少。 PDO 定制了使用 SQL-92 SQLSTATE 錯(cuò)誤代碼字符串的標(biāo)準(zhǔn);不同 PDO 驅(qū)動(dòng)程序負(fù)責(zé)將它們本地代碼映射為適當(dāng)?shù)?SQLSTATE 代碼。例如,SQLSTATE 是用于 DB2(以及通常的 ODBC)的本地錯(cuò)誤代碼格式,這是多么方便啊!errorCode() 方法返回一個(gè) SQLSTATE 代碼。如果您需要關(guān)于一個(gè)錯(cuò)誤的更多特定的信息,PDO 還提供了一個(gè) errorInfo() 方法,該方法將返回一個(gè)數(shù)組,其中包含 SQLSTATE 代碼、特定于驅(qū)動(dòng)程序的錯(cuò)誤代碼以及特定于驅(qū)動(dòng)程序的錯(cuò)誤字符串。
分頁(yè)數(shù)據(jù)、滾動(dòng)游標(biāo)和定位更新
在 Web 應(yīng)用程序中,一種常見(jiàn)的范例是對(duì)查詢結(jié)果進(jìn)行分頁(yè)。如果您使用一個(gè) Internet 搜索引擎,那么很可能每天都會(huì)做這樣的事。您輸入搜索詞,然后得到前 10-20 個(gè)匹配項(xiàng)。如果您想看到更多搜索結(jié)果,可以單擊 "next page" 鏈接。如果想回頭看前面看過(guò)的結(jié)果,可以單擊 "previous page" 鏈接。記得在幾年前,當(dāng)我第一次在 Web 上使用這樣的東西時(shí),我對(duì)自己說(shuō):"為什么我不能通過(guò)滾動(dòng)查看所有數(shù)據(jù)呢?" 問(wèn)題的答案說(shuō)簡(jiǎn)單也簡(jiǎn)單,說(shuō)復(fù)雜也復(fù)雜 -- 我只想說(shuō),HTTP 不會(huì)智能地使數(shù)據(jù)庫(kù)上的可滾動(dòng)游標(biāo)一直處于開(kāi)放狀態(tài),即便如此,需要大量傳輸?shù)?Web 應(yīng)用程序也會(huì)很快地消耗掉大量開(kāi)放的可滾動(dòng)游標(biāo)。因此,最簡(jiǎn)單的解決方案是為用戶顯示所有的匹配項(xiàng) -- 但是用戶很容易迷失在大量的結(jié)果當(dāng)中。比較符合邏輯的措施是人工地將數(shù)據(jù)格式化到多個(gè)頁(yè)面上,使用戶可以每次查看一部分可以管理的數(shù)據(jù)。
所以人們編寫可以取所有數(shù)據(jù)的 PHP 應(yīng)用程序,然后只顯示前 10 行。根據(jù)下一次請(qǐng)求,應(yīng)用程序又顯示 11-20 行,依此類推。這對(duì)于只返回少量數(shù)據(jù)的查詢來(lái)說(shuō)很不錯(cuò),但是,如果有很多匹配項(xiàng)(比如多于 100),那么先取全部數(shù)據(jù)然后丟棄其中的 90%,這種做法很浪費(fèi)。PHP 的創(chuàng)始人 Rasmus Lerdorf 就這種情形特地為 MySQL 發(fā)明了一個(gè)特殊的 "LIMIT, OFFSET" 子句。它允許您通知數(shù)據(jù)庫(kù),您只對(duì)一小部分行感興趣,這樣它就不會(huì)取其他不需要的行了。其語(yǔ)法(或非常類似的東西)已經(jīng)被其他流行的開(kāi)放源代碼數(shù)據(jù)庫(kù)采納,但并不是所有數(shù)據(jù)庫(kù)都提供了相同的語(yǔ)法。 Troels Arvin 收集了一些非常有用的信息,對(duì)不同 RDBMS 所支持的語(yǔ)法進(jìn)行了比較。
如果您想在以 DB2 為后臺(tái)數(shù)據(jù)庫(kù)的 PHP 應(yīng)用程序中實(shí)現(xiàn)分頁(yè)結(jié)果,那么可以(也應(yīng)該)使用下面示例中的語(yǔ)法。這里我們假設(shè)有一個(gè) books 表,表中包含書名和作者,我們現(xiàn)在想要每次在一頁(yè)中顯示 10 個(gè)以上結(jié)果:
清單 8. 使用 SQL Standard "Window Functions" 實(shí)現(xiàn)數(shù)據(jù)分頁(yè)
$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 說(shuō)明在撰寫本文之際,Cloudscape 在其 SQL 實(shí)現(xiàn)中還不支持 ROW_NUMBER(),所以需要使用可滾動(dòng)游標(biāo)。 |
現(xiàn)在,如果您要編寫一個(gè)更通用的應(yīng)用程序,并希望實(shí)現(xiàn)分頁(yè)的結(jié)果集,但是不想專門編寫很多的代碼,并且也不想使用更重量級(jí)的抽象層,Troels Arvin 的非常有幫助的 RDBMS 信息建議,您可以使用游標(biāo)作為更輕便(稍微慢一點(diǎn))的方案。碰巧的是,PDO 具有這方面的 API 級(jí)的支持。下面將談到如何使用這種支持來(lái)達(dá)到與上面示例相同的效果:
清單 9. 使用滾動(dòng)游標(biāo)實(shí)現(xiàn)數(shù)據(jù)分頁(yè)
$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); } } |
需要強(qiáng)調(diào)的是,雖然滾動(dòng)游標(biāo)對(duì)于更冗長(zhǎng)的 window 函數(shù)方案來(lái)說(shuō)是一個(gè)很方便的替代方案,但這種方案要慢很多。如果在一個(gè)傳輸量比較少的環(huán)境中進(jìn)行測(cè)試,您可能發(fā)現(xiàn)不了速度上的差異,但當(dāng)規(guī)模擴(kuò)大時(shí),您就會(huì)開(kāi)始發(fā)現(xiàn)速度降慢帶來(lái)的痛苦。
定位更新
可滾動(dòng)游標(biāo)的另一個(gè)用途是,基于 SQL 中無(wú)法表達(dá)的重大標(biāo)準(zhǔn)驅(qū)動(dòng)更新。如果您有一個(gè) Web 頁(yè)面鏈接的表,并且需要在每晚的批處理過(guò)程中更新那個(gè)表,以反映 Web 頁(yè)面當(dāng)前大小,那么可以編寫如下代碼:
清單 10. 使用滾動(dòng)游標(biāo)作出定位更新
$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)); }} |
大型對(duì)象
在應(yīng)用程序中的某個(gè)地方,您可能發(fā)現(xiàn)需要在數(shù)據(jù)庫(kù)中存儲(chǔ)"大型(large)"數(shù)據(jù)。大型通常意味著"大約 4kb 或 4kb 以上",盡管在沒(méi)有"大型"數(shù)據(jù)之前 DB2 最大可以處理 32kb 的數(shù)據(jù)。 大型對(duì)象可以是文本的,也可以是二進(jìn)制的。PDO 允許在 bindParam() 或 bindColumn() 調(diào)用中通過(guò)使用 PDO_PARAM_LOB 類型代碼來(lái)使用大型數(shù)據(jù)類型。PDO_PARAM_LOB 告訴 PDO 將數(shù)據(jù)映射為流,所以可以使用 PHP Streams API 來(lái)操縱這樣的數(shù)據(jù)。下面是一個(gè)示例:
清單 11. 從數(shù)據(jù)庫(kù)取一副圖像
$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); |
上面的介紹很簡(jiǎn)明扼要。現(xiàn)在讓我們?cè)囋嚵硪幻?,將上傳的圖像插入到一個(gè)數(shù)據(jù)庫(kù)中:
清單 12. 將圖像插入數(shù)據(jù)庫(kù)中
$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(); |
這兩個(gè)例子都是宏觀層次的。請(qǐng)記住,被取的大型對(duì)象是一個(gè)流,可以通過(guò)所有常規(guī)的流函數(shù)來(lái)使用它,例如 fgets()、fread()、fgetcsv() 和 stream_get_contents()。
關(guān)于全球化、NLS 和字符集的簡(jiǎn)要說(shuō)明
在越來(lái)越多的 PHP 應(yīng)用程序中,越來(lái)越重要的一點(diǎn)是讓應(yīng)用程序能夠在全球范圍內(nèi)使用。從實(shí)踐角度來(lái)講,這意味著應(yīng)用程序需要能夠正確地處理多種語(yǔ)言(例如英語(yǔ)和日語(yǔ))中的數(shù)據(jù),并且其功能性不變。這是一個(gè)很大的專題,做起來(lái)很有技巧性。實(shí)現(xiàn)全球化要走的第一步是采用一種適合所有數(shù)據(jù)的全球編碼,例如 UTF-8。這是一種 ASCII 兼容的編碼,它可以使用特殊字符序列為整個(gè) unicode 字符集編碼。UTF-8 也是一種多字節(jié)編碼。
與常規(guī) ASCII 字符串相比,多字節(jié)編碼的字符串處理起來(lái)要棘手一點(diǎn),因?yàn)橐粋€(gè)或多個(gè)字符對(duì)應(yīng)于一個(gè)給定的字母 -- 例如,UTF-8 允許最多 6 個(gè)字符的序列映射到字符串中的一個(gè)字母。ASCII 字符在 UTF-8 中仍具有相同的表示,因此,如果只是處理不帶任何特殊音調(diào)的純英文文本,則 UTF-8 看上去就像是 ASCII。這意味著類似的字符串函數(shù)(作用于字節(jié)而不是字符位置),例如 strlen() 和 substr(),可能得不到預(yù)期的效果,這取決于 UTF-8 字符串中的內(nèi)容。幸運(yùn)的是,PHP iconv 擴(kuò)展為這些函數(shù)提供了一些編碼感知的替代函數(shù)。例如,您可以使用 iconv_strlen() 來(lái)得出字符串中的字符數(shù),而不是使用 strlen()。類似地,您可以不用 strpos() 或 substr(),而使用 iconv_strpos() 和 iconv_substr()。
iconv 擴(kuò)展為您提供了在處理多種編碼下的數(shù)據(jù)時(shí)所需的基本工具。應(yīng)用程序應(yīng)該盡量確保所有數(shù)據(jù)都是 UTF-8 編碼的。如果用適當(dāng)?shù)?Content-Type 標(biāo)記 Web 頁(yè)面,那么大多數(shù)瀏覽器將發(fā)送 UTF-8 編碼的數(shù)據(jù),可以確信,一定有一個(gè)編碼類型屬性可應(yīng)用于 HTML FORM 標(biāo)簽。
接下來(lái)的一步是設(shè)置 DB2 實(shí)例,使它在您與之交互時(shí)使用 UTF-8。這很容易辦到,只需在 DB2 的命令行提示符中運(yùn)行以下命令:
清單 14. 設(shè)置 DB2 實(shí)例,使之使用 UTF-8
$ db2set DB2CODEPAGE=1208 |
完成這樣的更改后,從 DB2 實(shí)例取到的所有文本數(shù)據(jù)都是 UTF-8 編碼的。同樣,DB2 期望您輸入的所有文本也是 UTF-8 編碼的。當(dāng)應(yīng)用程序的每個(gè)部分都使用 UTF-8 時(shí),應(yīng)用程序就可以全球使用了,并且能夠顯示任何語(yǔ)言的文本,只要這種語(yǔ)言的文本可以用 UTF-8 編碼。前面我已經(jīng)暗示過(guò),這只是通往國(guó)際化大道的第一步。還有很多其他的事情需要考慮,例如本地化(采用給定用戶的地區(qū)設(shè)置來(lái)顯示日期、時(shí)間、重量和度量,將通用文本翻譯成用戶本地的語(yǔ)言)、從右到左或雙向(bi-di)文本布局,等等。
值得注意的是,PDO 不對(duì)該數(shù)據(jù)做任何特殊的事情。有些驅(qū)動(dòng)程序允許更改為一個(gè)連接使用的編碼,但是在 PDO 級(jí)沒(méi)有處理這種事情的特殊邏輯。其原因是,PHP 內(nèi)部完全不知道 unicode,所以在這里試圖使 PDO 知道 unicode 是沒(méi)有意義的。如果您對(duì)這方面的專題感興趣,那么您會(huì)欣喜地得知,PHP 的 unicode 支持很快就要出現(xiàn),不過(guò)我也不知道它初次露面的確切日期。
在Unix環(huán)境下PHP5.1以上版本中:
如果你正在使用PHP5.1版本,PDO和PDO SQLITE已經(jīng)包含在了此發(fā)行版中;當(dāng)你運(yùn)行configure時(shí)它將自動(dòng)啟用。推薦你將PDO作為共享擴(kuò)展構(gòu)建,這樣可以使你獲得通過(guò)PECL升級(jí)的好處。推薦的構(gòu)建支持PDO的PHP的configure line應(yīng)該也要啟用zlib。你也應(yīng)該啟用你選擇的數(shù)據(jù)庫(kù)的PDO驅(qū)動(dòng) ;關(guān)于這個(gè)的更多信息請(qǐng)查看database-specific PDO drivers ,但要注意如果你將PDO作為一個(gè)共享擴(kuò)展構(gòu)建,你必須也要將PDO驅(qū)動(dòng)構(gòu)建為共享擴(kuò)展。SQLite擴(kuò)展依賴于PDO,所以如果PDO作為共享擴(kuò)展構(gòu)建,SQLite也應(yīng)當(dāng)這樣構(gòu)建
./configure --with-zlib --enable-pdo=shared --with-pdo-sqlite=shared --with-sqlite=shared
將PDO安裝為一個(gè)共享模塊后,你必須編輯php.ini文件使得在PHP運(yùn)行時(shí)自動(dòng)載入PDO擴(kuò)展。你同樣需要啟用那兒的特定數(shù)據(jù)庫(kù)驅(qū)動(dòng);確保他們列出在 pdo. so 行之后,因?yàn)镻DO必須在特定數(shù)據(jù)庫(kù)驅(qū)動(dòng)載入之前初始化。如果你是以靜態(tài)方式構(gòu)建的PDO和特定數(shù)據(jù)庫(kù)驅(qū)動(dòng)擴(kuò)展,你可以跳過(guò)這一步。
extension=pdo. so
讓PDO作為一個(gè)共享的模塊將使你可以在新版PDO發(fā)布時(shí)運(yùn)行 pecl upgrade pdo 命令升級(jí),而不用強(qiáng)制你重新構(gòu)建整個(gè)PHP。注意如果你是這樣做的,你也需要同時(shí)升級(jí)你的特定數(shù)據(jù)庫(kù)驅(qū)動(dòng)。
在windows環(huán)境下PHP5.1以上版本中:
PDO和主要數(shù)據(jù)庫(kù)的驅(qū)動(dòng)同PHP一起作為擴(kuò)展發(fā)布,要激活它們只需簡(jiǎn)單的編輯php.ini文件:
extension=php_pdo.dll
然后,選擇針對(duì)特定數(shù)據(jù)庫(kù)的DLL文件使用 dl() 在運(yùn)行時(shí)加載,或者在php.ini文件中 php_pdo.dll 行后啟用它們,如:
extension=php_pdo.dll
extension=php_pdo_firebird.dll
extension=php_pdo_informix.dll
extension=php_pdo_mssql.dll
extension=php_pdo_mysql.dll
extension=php_pdo_oci.dll
extension=php_pdo_oci8.dll
extension=php_pdo_odbc.dll
extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
這些DLL文件應(yīng)當(dāng)存在于系統(tǒng)的 extension_dir 目錄里。
注意 PDO_INFORMIX 只能作為一個(gè)PECL擴(kuò)展使用。
========================================================================================
PHP 5.1 發(fā)布時(shí)將附帶一個(gè)全新的數(shù)據(jù)庫(kù)連接層,即 PHP Data Objects (PDO)。雖然 PHP 一直都擁有很好的數(shù)據(jù)庫(kù)連接,但 PDO 讓 PHP 達(dá)到一個(gè)新的高度。學(xué)習(xí)如何獲得、安裝和使用 PDO,以連接到 IBM? DB2? Universal Database? 和 IBM Cloudscape? 數(shù)據(jù)庫(kù),插入和檢索數(shù)據(jù),并探索更多高級(jí)特性,例如預(yù)處理語(yǔ)句(prepared statements)、綁定參數(shù)(bound parameters)、可滾動(dòng)游標(biāo)(scrollable cursors)、定位更新(positioned updates)以及 LOB。
PHP 5.1 發(fā)布時(shí)將附帶 PDO,但是也可以通過(guò) PECL 這個(gè) PHP 擴(kuò)展庫(kù)(PHP Extension Repository)來(lái)結(jié)合使用 PDO 和 PHP 5.0.3 及以上版本。如果您使用的是 Windows,那么您會(huì)欣喜地發(fā)現(xiàn)安裝過(guò)程要簡(jiǎn)單得多。
我將假設(shè)您已經(jīng)擁有配置 PHP 5 使之使用您選擇的 Web 服務(wù)器的經(jīng)驗(yàn),只有在此假設(shè)下,我才能集中精力關(guān)注更相關(guān)的細(xì)節(jié)。同樣,我還將假設(shè)您使用的是一個(gè) DB2 Universal Database 服務(wù)器或網(wǎng)絡(luò)服務(wù)器模式下的 IBM Cloudscape 數(shù)據(jù)庫(kù),并且接受了用戶為 db2inst1、密碼為 ibmdb2 的默認(rèn)安裝選項(xiàng)。如果您自己編譯驅(qū)動(dòng)程序,那么在進(jìn)行編譯的機(jī)器上,應(yīng)該安裝有 DB2 客戶機(jī),并且存在應(yīng)用程序開(kāi)發(fā) header,否則編譯將遭到失敗。
格式:pdf
大小:2.3MB
頁(yè)數(shù): 11頁(yè)
評(píng)分: 4.7
聚對(duì)二氧環(huán)己酮(PPDO)是一種具有良好生物降解性和生物相容性的脂肪族聚酯醚,其獨(dú)特的醚酯結(jié)構(gòu)又賦予了材料高強(qiáng)度和良好的柔韌性,是一種理想的生物醫(yī)用材料。綜述了近年來(lái)針對(duì)PPDO單體合成、開(kāi)環(huán)聚合、PPDO結(jié)構(gòu)與性能,納米復(fù)合、淀粉共聚等方面的相關(guān)研究成果。隨著單體對(duì)二氧環(huán)己酮(PDO)合成技術(shù)的突破而導(dǎo)致成本的大幅度下降、PDO開(kāi)環(huán)聚合可控性的實(shí)現(xiàn)以及PPDO納米復(fù)合材料的原位合成對(duì)性能的有效改善,必將推進(jìn)該聚合物在一次性使用塑料領(lǐng)域的廣泛應(yīng)用。
格式:pdf
大?。?span id="qgsx96b" class="single-tag-height">2.3MB
頁(yè)數(shù): 4頁(yè)
評(píng)分: 4.5
介紹了該海外工程的空調(diào)冷源及室內(nèi)空調(diào)系統(tǒng)的設(shè)計(jì)。歸納總結(jié)了該工程在應(yīng)用國(guó)際先進(jìn)的計(jì)算軟件、空調(diào)系統(tǒng)形式、節(jié)能措施、自控手段及噪聲控制等方面的設(shè)計(jì)特點(diǎn),并闡述了設(shè)計(jì)中遇到的難點(diǎn)及設(shè)計(jì)體會(huì)。
產(chǎn)品名稱(中文)LAP Dorado 激光定位系統(tǒng)
產(chǎn)品名稱(英文)LAP Dorado Laser Positioning Systems
注冊(cè)號(hào)國(guó)食藥監(jiān)械(進(jìn))字2005第2240139號(hào)
產(chǎn)品性能結(jié)構(gòu)及組成結(jié)構(gòu):固定激光燈, 可移動(dòng)激光軌,手控盒。性能:可移動(dòng)激光軌移動(dòng)范圍600mm;激光移動(dòng)定位精度±0.25mm。
產(chǎn)品適用范圍該定位系統(tǒng)與CT掃描設(shè)備安裝在一起,在病人皮膚上投射出用作標(biāo)記的位置參考點(diǎn), 供對(duì)病人腫瘤放射治療時(shí)定位之用。
注冊(cè)代理德國(guó)LAP激光應(yīng)用有限公司上海代表處
售后服務(wù)機(jī)構(gòu)德國(guó)LAP激光應(yīng)用有限公司上海代表處
批準(zhǔn)日期2005.01.17
有效期截止日2009.01.16
備注LAP GmbH Laser Application,
生產(chǎn)廠商名稱(英文)LAP GmbH Laser Application
生產(chǎn)廠地址(中文)Zeppelinstr. 23 D-21337 Luneburg, Germany
生產(chǎn)場(chǎng)所Zeppelinstr. 23 D-21337 Luneburg, Germany
生產(chǎn)國(guó)(中文)德國(guó)
規(guī)格型號(hào)Dorado CT-1-1, Dorado CT-1-3, Dorado CT-1-4、
產(chǎn)品標(biāo)準(zhǔn)YZB/GEM 1738-24-2004 《LAP Dorado 激光定位系統(tǒng)》
單品 產(chǎn)品名稱 產(chǎn)地/廠商 地域 價(jià)格 (元/噸) 漲跌 報(bào)價(jià)日期 DOP DOP 東莞盛和 全國(guó) 12800 0 12-08-07 DOP DOP 浙江慶安 全國(guó) 12500 0 12-08-07 DOP DOP 鎮(zhèn)江聯(lián)成 全國(guó) 12500 0 12-08-07 DOP DOP 山東宏信 全國(guó) 12400 100 12-08-07 DOP DOP 愛(ài)敬寧波 全國(guó) 12600 100 12-08-07 DOP DOP 齊魯增塑劑 全國(guó) 12500 100 12-08-07 DOP DOP 寧波聯(lián)泰 全國(guó) 12500 0 12-08-07 DOP DOP 寧波東來(lái) 全國(guó) 12500 0 12-08-07 DOP DOP 金陵石化 全國(guó) 12500 0 12-08-07 DOP DOP 浙江偉博 全國(guó) 12500 0 12-08-07
單品 產(chǎn)品名稱 產(chǎn)地/廠商 地域 價(jià)格 (元/噸) 漲跌 報(bào)價(jià)日期 DOP DOP 東莞盛和 全國(guó) 12800 -100 12-08-06 DOP DOP 浙江慶安 全國(guó) 12500 0 12-08-06 DOP DOP 鎮(zhèn)江聯(lián)成 全國(guó) 12500 0 12-08-06 DOP DOP 山東宏信 全國(guó) 12300 0 12-08-06 DOP DOP 愛(ài)敬寧波 全國(guó) 12500 0 12-08-06 DOP DOP 齊魯增塑劑 全國(guó) 12400 0 12-08-06 DOP DOP 寧波聯(lián)泰 全國(guó) 12500 0 12-08-06 DOP DOP 寧波東來(lái) 全國(guó) 12500 0 12-08-06 DOP DOP 金陵石化 全國(guó) 12500 0 12-08-06 DOP DOP 浙江偉博 全國(guó) 12500 0 12-08-06