利用 PHP 和 Oracle 構建線上 PayPal 支付系統
作者:Nick Bollweg
協助使用者線上即時購買產品。
本文相關下載: Oracle 資料庫 10g 特別版 Zend Core for Oracle PayPal SDK |
|
2006 年 6 月發表
許多小型企業和非營利性機構對於進入線上市場猶豫不決,因為他們誤以為線上支付處理對使用者存在風險、實施費用昂貴,並且與現有系統的整合效果差。 事實上,隨著 Web 服務的出現和不斷髮展,資金轉賬的效率大大提高,這為通過第三方供應商處理任意交易量提供了一種理想方式。在最知名的線上支付方式中,eBay 的 PayPal 提供了有競爭性的費率,並提供了一種有效 PHP SDK 來訪問它的 API。
本文介紹了上述服務和 PayPal 的無 API 方法,這種方法有助於更快的進行應用處理支付。
讓我們成為朋友
要進一步討論本文中的樣本前,您需要一個配置正確的 PHP5 安裝,並將此安裝與所選的 Web 服務器應用程式串連。同時,您還需要一個與 PHP 間存在相應串連的 Oracle 資料庫。 Zend Core for Oracle 和 Oracle 資料庫 10g 特別版 (XE) 是完成這一工作的最佳工具。 由於線上支付處理的敏感性,您可能希望確保伺服器的安全,使強大的 php.ini 配置成為優先選項。 另外,要成功的安裝 PayPal SDK,您還需要一些擴充功能: PEAR、cURL 和 SSL。 儘管它們可以在 php.ini 中載入,但使用 PHP 編譯可得到最佳結果。
充分設定好環境後,您需要下載 PayPal PHP SDK,其中包括服務/ PayPal PEAR 程式包、 PayPal Web 控制台、SDK 文檔和 PDF 資訊文檔。 (參見下方“無法使用 Web 控制台”部分中關於 Web 控制台的重要注意事項。) 在下載和提取此檔案後,您需要運行一些命令列操作:
pear install --alldeps /Services_PayPal/package.xml
cp -r /WebConsole
此 命令可以安裝一些其它的 PEAR 程式包,為您提供一個功能完善的 PayPal SDK。 在瀏覽器中訪問 http://localhost/WebConsole 頁面後, PayPal 設定檔管理工具將顯示一條問候訊息,您可以在此處檢查 PayPal SDK 的有效性。 常見問題包括丟失 cURL 或 SSL 的安裝,通過修改 php.ini 或重新編譯 PHP,然後再次運行 PEAR 命令,這些問題將得到修複。 如果因為託管限制或安全性問題而無法安裝 PEAR 或某種必要的擴充功能,您還可以使用下方描述的標準結帳。
採用穩妥的方式……
通過 SDK 使用 API 是使用 PayPal 功能的一種靈活、有效方式。 API 支援的兩種支付方式包括:
- 直接付款:使用此方式可以收集網站上的詳細帳單,從使用者的信用卡收費,全部工作在自己網站上完成。 這種方法適合擁有 https 安全應用程式和基礎架構(用於儲存客戶和購物車資訊)的大型主機構。
- 快速結帳:這種方式允許使用者使用 PayPal 帳戶資訊和選擇發貨方式,不需要在網站上重新輸入資訊,從而節省了時間。同時, 這種方式不需要應用程式儲存購買者資訊的本機複本,管理此方式時只需要最少的額外安全性基礎架構。
其它 API 特性(文中並未完全涉及)包括:
- 慈善捐款:根據使用者的購物情況,提供有關慈善捐款的即時資訊。
- 發貨:如果銷售的是現實產品,則允許使用者選擇發貨商、發貨方式、保險和其它屬性。 在使用者確實購買貨物之前,您就可以向使用者提供發貨的成本,或者也可以使用此特性在產品顯示頁面提供更準確的價格。
- 退款:提供向使用者退款的方法。
- 稅金:根據每件貨物或每個購物車收稅,並適當地將稅金顯示在收據和發票上。
- 訂閱: 靈活地定義現實貨物和數字貨物的迴圈訂閱。
SDK 還提供了廣泛的 eBay 支援,儘管其價值不在我們討論的範圍內。
……或者採用簡易方式
如果 SDK 的功能遠遠超出使用者的需求,在此情況下,PayPal 提供了另一種解決方案。 標準結帳不使用 SOAP,只依賴於在應用程式與 PayPal 安全伺服器間傳遞 HTML 表單值。 要使用標準結帳,您只需要產生一個表單,該表單可以提交適當的 POST 變數,如下面的樣本所示:
<form action="https://sandbox.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_cart">
<input type="hidden" name="upload" value="1">
<input type="hidden" name="business" value="sales@widgetco.com">
<input type="hidden" name="item_name_1" value="Big Widget">
<input type="hidden" name="amount_1" value="100.00">
<input type="hidden" name="item_name_2" value="Little Widget">
<input type="hidden" name="amount_2" value="1.00">
<input type="submit" value="PayPal">
</form>
提交表單後,使用者將進入 PayPal 的伺服器,輸入帳單資訊。 在完成資訊驗證和帳單授權機制後,使用者將返回您在網站上定義的一個位置。 如果您僅僅是收集捐款,而不是銷售物品,那麼您的工作已經完成了! 然而,對於其它情況,使用者可使用大量的變數來定製功能、貨幣和顯示方面的體驗。 (參見參考指南。)
使用帶有 notify_url 變數的即時付款通知 (IPN) 時,一旦使用者在指定的地點完成付款,您的應用程式就會得到通知 — 您可以使用定製的連結提供專用使用者標識,例如,允許對線上內容進行即時訪問或觸發一個批發商的訂單。 另外,通過使用發票和定製變數,您可以建立一個機構,將 PayPal 的記錄限制在您自己的域中。 如果應用程式已經儲存了使用者名稱和地址資訊,您可以通過一組變數(包括 address1、city 和 country)將這些資訊傳遞給 PayPal ,以便預先填充相應的欄位。
標準結帳的基本方式中也包含 API 為收集非盈利性資金而提供的許多特性, 例如,可以應用到每個購物車或每件貨物的稅金、處理和發貨變數。
cpp_ 系列變數(包括 cpp_header_image、cpp_headerback_color、cpp_headerborder_color 和 cs)允許您精確調整使用者在 PayPal 伺服器上的體驗,這些變數用於設定支付頁面的背景顏色。 如果這種方法能夠滿足應用程式的需求,標準結帳將是一種非常經濟有效解決方案。 與基於 API 的直接付款條件不同,標準結帳並不確定每月的費用,並且實施期間的開發工作非常少。
準備付款
要使用 PayPal API,首先要熟悉開發人員中心。 您將在開發人員中心建立帳戶,以便在 Sandbox 中建立買方與賣方的樣本帳戶。 樣本帳戶建立完畢後,使用該帳戶登入到 Sandbox 將顯示擁有資金的有效 PayPal 帳戶。 您的買方可以從其他 Sandbox 帳戶購買物品,您的賣方可以將貨款退還給其他 Sandbox 帳戶,這些都不需要現金轉移,也不需要收費代理。 PayPal 的整合中心提供了極好的逐步指南(注意,第 3 步是我在前面介紹的安裝過程),我將在此處提供該指南的概述。
首先,您需要在 developer.paypal.com 註冊一個帳戶,此網頁是訪問各種開發人員資源的中心點,用於建立 Sandbox 帳戶。 之後,您將在 developer.paypal.com 的 Sandbox 選項卡中建立一個買方樣本和一個賣方樣本。這項工作非常簡單,為了使建立的內容有意義,您只需要足夠的創造力。 例如,在提示您輸入銀行帳戶資訊時,為了方便使用,建議您將系統提供的虛擬帳戶號作為銀行的名稱。 另外,您可以為買方帳戶和賣方帳戶使用相同的密碼,因為此伺服器發生密碼泄露的風險很低。 在 Sandbox 中學習的特性與生產時使用的特性完全相同,從而減少了培訓和測試時間。
在 Sandbox 中最後一個重要的步驟是建立測試認證,這是一個小型文字檔,其中包含將與每個 API 呼叫一起使用的密鑰。 要建立一個認證,您需要登入到賣方 Sandbox 帳戶,單擊 Profile,然後依次選擇 API Access 和 View or Remove Credentials。 記錄此檔案和密碼;您將在配置應用程式時用到它們。
回到 developer.paypal.com,您可以查看測試認證的資訊,也可以從 Test Certificates 選項卡下載測試認證。 此處不能查看 API 密碼;要獲得此資訊,您必須重新登入到 http://www.sandbox.paypal.com,然後訪問上述位置。
直接付款處理
與 PayPal 互動的最靈活的方式是通過 SDK 來完成,SDK 會將基於 SOAP 的請求抽象成可管理的資訊。 不同調用要完成的目標不同,但執行的步驟基本相同: 認證、操作和響應流程。 第一個步驟,認證,來自 SDK 樣本,同樣需要用在下方的快速結帳方法中。 顯示的值用於 Sandbox 測試: 需要為生產建立帶有認證詳細資料的新認證。
$certfile = dirname(__FILE__) . '/sdk-seller_cert.pem';
$apiusername = '';
$apipassword = '';
$subject = null;
$environment = 'Sandbox';
$handler =& ProfileHandler_Array::getInstance(array(
'username' => $apiusername,
'certificateFile' => $certfile,
'subject' => $subject,
'environment' => $environment));
$profile =& APIProfile::getInstance($apiusername, $handler);
$profile->setAPIPassword($apipassword);
$caller =& Services_PayPal::getCallerServices($profile);
認證完成後,應用程式已經準備好處理 API 請求。 在直接付款時,您的應用程式必須有能力、有責任建立和儲存訂單的狀態,並為訂單建立收據: 在下一個樣本中,我們將假定應用程式已將所有相關資訊儲存到以下表格中: Customer、Billing_Method、Order 和 Line_item。 本樣本使用 PHP 資料對象 (PDO),在此情況下,傳統的 OCI8 方法同樣有效。
$db = new PDO('oci:', 'scott', 'tiger' 'HR', 'HR');
$dbcustomer = $dbh->query("SELECT* " .
"FROMcustomer " .
"WHEREcustomerid = '{$_SESSION[customerid]'}");
$dborder = $dbh->query("SELECT* " .
"FROMorder " .
"WHEREcustomerid = '{$_SESSION[customerid]}' " .
"AND orderid = '{$_SESSION[orderid]}'");
$dbbilling = $dbh->query("SELECT* " .
"FROMbilling_method " .
"WHEREbillingid = '{$dborder[billingid]}'");
$dblineitemtotals = $dbh->query("SELECT sum(amount) total " .
"FROM line_item " .
"WHERE customerid = '{$_SESSION[customerid]}' " .
"AND orderid = '{$_SESSION[orderid]}'");
$name =& Services_PayPal::getType('PersonNameType');
$name->setFirstName($dbcustomer['fname']);
$name->setLastName($dbcustomer['lname']);
$address =& Services_PayPal::getType('AddressType');
$address->setStreet1($dbbilling['street1']);
$address->setCityName($dbbilling['city']);
$address->setStateOrProvince($dbbilling['state']);
$address->setCountry($dbbilling['country']);
$address->setPostalCode($dbbilling['zip']);
$payer =& Services_PayPal::getType('PayerInfoType');
$payer->setPayerName($name);
$payer->setPayerCountry('US');
$payer->setAddress($address);
$cc =& Services_PayPal::getType('CreditCardDetailsType');
$cc->setCreditCardType($dbbilling['cardtype']);
$cc->setCreditCardNumber($dbbilling['cardnumber']);
$cc->setExpMonth($dbbilling['expmonth']);
$cc->setExpYear($dbbilling['expyear']);
$cc->setCardOwner($payer);
$amount =& Services_PayPal::getType('BasicAmountType');
$amount->setval($dblineitemtotals['total']);
$amount->setattr('currencyID', 'USD');
$pdt =& Services_PayPal::getType('PaymentDetailsType');
$pdt->setOrderTotal($amount);
$details =& Services_PayPal::getType('DoDirectPaymentRequestDetailsType');
$details->setPaymentAction('Authorization');
$details->setPaymentDetails($pdt);
$details->setCreditCard($cc);
$details->setIPAddress('127.0.0.1');
$details->setMerchantSessionId('merchantId');
$ddp =& Services_PayPal::getType('DoDirectPaymentRequestType');
$ddp->setDoDirectPaymentRequestDetails($details);
此時, PayPal 執行請求的直接付款。 為瞭解發生的情況,現在,應用程式會擷取第三步中的資訊: 響應處理。
$response = $caller->DoDirectPayment($ddp);
此響應中返回的各種欄位提供了有關事務成功的資訊,以及事務的 ID。通過儲存此 ID 並將它提供給後面的 API 呼叫,應用程式將能夠擷取有關事務的詳細資料,並將根據這些資訊產生另一個表格。
$d =& Services_PayPal::getType('GetTransactionDetailsRequestType');
$d->setTransactionId('');
$response = $caller->GetTransactionDetails($d);
無法使用 Web 控制台
在撰寫本文時,隨上述 SDK 下載一起提供的 Web 控制台由於丟失了重要目錄而停止工作。 然而,此時可以下載包含所有必需檔案的存檔。 控制台能夠測試 API 呼叫,產生 PHP 代碼片斷,從而達成您的目標。 通過本文和 SDK 參考中的一些調查,您可以通過瀏覽器方便地查看從 Sandbox 發出的所有 API 呼叫。
快速結帳流程
快速結帳方式介於強大的直接付款條件和簡捷的標準結帳方式之間。 利用快速結帳和基於 API 的方法,使用者可以在您的網站完成訂單建立過程,然後轉至 PayPal 處理所有帳單和發貨資訊。 在使用快速結帳時,使用者只需為所有商品輸入一次帳戶資訊,而您的應用程式也不需要儲存這些資訊 — 這在安全性和開發方面具有明顯的優勢。 同直接付款條件相同,通過儲存事務 ID,應用程式可以利用其他 API 呼叫擷取事物的詳細資料。 快速結帳可以利用上文中描述的 IPN,從而允許其它即時處理選項。 下面的程式碼片段來自 SDK 樣本。
$amount =& Services_PayPal::getType('BasicAmountType');
$amount->setval();
$amount->setattr('currencyID', 'USD');
$ecd =& Services_PayPal::getType('SetExpressCheckoutRequestDetailsType');
$ecd->setOrderTotal($amount);
$ecd->setReturnURL('http://widgetco.com/return');
$ecd->setCancelURL('http://widgetco.com/cancel');
$ec =& Services_PayPal::getType('SetExpressCheckoutRequestType');
$ec->setSetExpressCheckoutRequestDetails($ecd);
$response = $caller->SetExpressCheckout($ec);
此調用的結果將提供一個令牌,您可以將其添加到一個鏈路,或者在網站上將其重新導向到 PayPal 。 然後,使用者使用 PayPal 處理業務。在操作成功或失敗後,系統將使用者重新導向到您的網站。 在本樣本中,調用的頁面返回將向您的應用程式發送以下 API 呼叫:
$ecd =& Services_PayPal::getType('GetExpressCheckoutDetailsRequestType');
$ecd->setToken('');
$response = $caller->GetExpressCheckoutDetails($ecd);
這裡包含您需要的所有事務資訊,但不包含信用卡號等敏感資訊。 使用者在您的網站上對這些值進行確認後,由最終 API 呼叫處理資金事務:
$amount =& Services_PayPal::getType('BasicAmountType');
$amount->setval();
$amount->setattr('currencyID', 'USD');
$pdt =& Services_PayPal::getType('PaymentDetailsType');
$pdt->setOrderTotal($amount);
$details =& Services_PayPal::getType('DoExpressCheckoutPaymentRequestDetailsType');
$details->setPaymentAction('Sale');
$details->setToken('');
$details->setPayerID('juser@jisp.com');
$details->setPaymentDetails($pdt);
$ecprt =& Services_PayPal::getType('DoExpressCheckoutPaymentRequestType');
$ecprt->setDoExpressCheckoutPaymentRequestDetails($details);
$response = $caller->DoExpressCheckoutPayment($ecprt);
同樣,在對 updateChart 進行連續調用時,ChartData 將引發 onResult 方法:
_root.chartData.onResult = function() {
_root.chart.throbber._visible = false;
drawChart(this);
}
快速結帳幾乎與直接付款具有相同的定製性,同時還保持了標準結帳的保密和安全優勢。
乾杯,朋友
PayPal 支付處理的任何一種形式都提供了收集線上付款的有效方式。 由實施者決定哪種方式更加適合: 標準結帳為小型機構提供了收集付款的能力,且不需要這些機構投資其它安全體繫結構;在與當前的企業應用程式整合時,直接付款是理想的解決方案;而快速結帳 介於兩者之間,適合將其更改成第三方產品。 選擇靈活性、安全性和實施便捷性之間的平衡點將允許您利用現有的 Oracle 基礎架構獲得線上支付功能。