The Oracle + PHP Cookbook

Online PayPal Payments with PHP and Oracle


by Nick Bollweg

Help your users buy products instantly online.

Downloads for this article:
 Oracle Database 10g Express Edition
 Zend Core for Oracle
 PayPal SDK

Published June 2006

Many small businesses and non-profit organizations hesitate to enter the online marketplace because of the mis-perceptions that online payment processing is risky for their users, expensive to implement, and integrate poorly with existing systems. In reality, with the advent of and subsequent improvement to Web services, the efficiency of fund transfer has greatly increased, providing an ideal way to handle nearly any volume of transactions through third-party vendors. eBay's PayPal, among the most widely known, offers competitive rates and a workable PHP SDK to access its API.

This recipe will provide an overview of this service as well as PayPal's API-less method, which can get your application processing payments even more quickly.

Let's Be Pals

To continue investigation beyond the examples in this recipe, you will need a properly configured PHP5 installation connected to a Web server application of your choice, as well as an Oracle database with appropriate connections to PHP. Zend Core for Oracle and Oracle Database 10g Express Edition (XE) are the best tools for the job. Because of the sensitive nature of online payment processing, you will want to ensure this server is secure, making strong php.ini configuration a priority. Several extensions are also required for the successful installation of the PayPal SDK: PEAR, cURL, and SSL. Best results are attained when these are compiled with PHP, though they can be loaded in the php.ini.

With your environment adequately set up, you will need to download the PayPal PHP SDK, which includes the Services/PayPal PEAR package, the PayPal WebConsole, SDK documentation and an informative PDF. (See an important note regarding WebConsole in the "Un-WebConsole-able" section below.) After downloading and extracting this file, you will need to run a few command line operations:

pear install --alldeps <location_of_extracted_sdk>/Services_PayPal/package.xml
cp -r <location_of_extracted_sdk>/WebConsole <web_server_document_root>
This command may install a few other PEAR packages and leave you with a functioning install of the PayPal SDK. You can check whether it worked by visiting http://localhost/WebConsole in your browser, where you should be greeted by the PayPal Profile Admin Tool. Common pitfalls include a missing cURL or SSL installation, which you can fix by modifying your php.ini or recompiling PHP, then running the PEAR command again. If you are unable to install PEAR or one of the necessary extensions due to hosting limitations or security concerns, you can still use Standard Checkout, described below.

Take the High Road...

Using the API through the SDK is a very flexible and powerful way to use PayPal's functionality. The two payment methods allowed through the API are:

  • Direct Payment: Use this to gather billing details on your Web site, charge the user's credit card, and never leave your domain. Suited to large organizations that already have https secure applications and infrastructure for storing customer and cart information.
  • Express Checkout: Users save time by using their PayPal account information as well as choose shipping methods, instead of reentering this information on your site. This approach frees your application from having to store a local copy of the buyer's information, and can be conducted with a minimum of additional security infrastructure.
Additional API features, not fully covered in this recipe, are also available:
  • Charitable donations: Provide your users with real-time information on charitable donations based on their purchases.
  • Shipping: If selling real-world goods, allow users to choose from various shipping vendors, shipping types, insurance, and other attributes. You will instantly be able to provide the cost of shipping to your users before they actually purchase the goods, or could use this to populate more accurate prices in your product display pages.
  • Refunds: Provide means to return funds to your users.
  • Taxes: Charge per-item or per-cart taxes, to be displayed appropriately on receipts and invoices.
  • Subscriptions: Flexibly define subscriptions for real-world or digital goods with recurrence.
The SDK also provides extensive eBay support, which although valuable is outside our scope here.

...Or the Low Road

The power of the SDK can far exceed what your users require; for this case, PayPal provides another solution. Standard Checkout does not use SOAP, relying solely on passing HTML form values between your application and PayPal's secure server. To use this, you need only generate a form, which can submit appropriate POST variables such as the example below:

<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>
After submitting this form, users will be taken to PayPal's server where they enter billing information. After verification of information and authorization of billing mechanism, they will be returned to your site at a place you define. If you are merely collecting donations, instead of selling things, you're done! However, for all other cases, a plethora of variables are available to customize this experience from functional, monetary, and display perspectives. (See the Reference Guide.)

Using Instant Payment Notification (IPN) with the notify_url variable allows your application to be notified as soon as the user finishes payment to a location of your choosing—you can use a customized link to provide back your proprietary user identifier, for example, to allow instant access to online content or trigger an order from a wholesaler. Furthermore, through the use of invoice and custom variables, you can create a structure to tie PayPal's records back to your own. If your application already saves user name and address information, you can pass this information along to PayPal through a slew of variables including address1, city, and country, and the appropriate fields will be pre-populated.

Many of the features provided by the API for collecting funds for things other than product are also covered in a rudimentary fashion by Standard Checkout: variables exist for tax, handling, and shipping, and can be applied by the cart or singly per product.

The cpp_ family of variables allows you to fine-tune the experience your users will see on the PayPal server, including cpp_header_image, cpp_headerback_color, cpp_headerborder_color and cs, which sets the payment page background color. If your application needs are met by this method, Standard Checkout can be a very cost-effective solution. Unlike the API-based Direct Payment, no monthly fee is assessed and less development is required at implementation time.

Get Ready to Pay

To make use of the PayPal API, first become familiar with the Developer Center. It is here that you create an account to create sample seller and buyer accounts in the Sandbox. Once created, logging in to the Sandbox with a sample account will show a working PayPal account with play money. Your buyer can purchase from, and your seller can refund, other Sandbox accounts, all without real money changing hands or PayPal charging commission. An excellent step-by-step guide is available at PayPal's Integration Center (note that Step 3 is the installation process I described earlier), but I'll provide an overview here.

First you will need an account for developer.paypal.com; this is the central point for accessing different aspects of the developer resources and is required for creating Sandbox accounts. Next, you will create a sample buyer and a sample seller in the Sandbox tab of developer.paypal.com. This is relatively painless, requiring only enough creativity as to be meaningful. For example, where you are presented with the mechanism for adding bank account information, it is suggested that you use the provided fictitious account number as the name of the bank for easy reference. Furthermore, you should use the same passwords for buyer and seller accounts, as the risk from compromise on this server is low. The features mastered in the Sandbox will be the exact same ones used in production, reducing training and testing time.

One last important step in the Sandbox is the creation of a Test Certificate, a small text file containing an encryption key to be used with every API call. To create a certificate, it is necessary to log in to the seller Sandbox account and click on Profile, API Access, and then View or Remove Credentials. Keep track of this file and password; you will need them when configuring your application.

Back in developer.paypal.com, you can view information about and download Test Certificates in the Test Certificates tab. The API password cannot be viewed here, however; to retrieve this information, you must log back in to http://www.sandbox.paypal.com and visit the location described above.

Direct Payment Processing

The most flexible way to interact with PayPal is through the SDK, which abstracts the SOAP-based requests to a manageable level. Different calls accomplish different goals, but the steps are usually similar: authentication, action, response processing. This first step, authentication, is adapted from the SDK example, and is also required for the Express Checkout method below. The values shown are for a Sandbox test: a new certificate with authentication details needs to be created for production.

$certfile = dirname(__FILE__) . '/sdk-seller_cert.pem';
$apiusername = '<your API username>';
$apipassword = '<your API password>';
$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);
After authentication, the application is ready to process API requests. With Direct Payment, your application must have the power and responsibility to create, store the state of and create a receipt for an order: in the next example, we'll assume the application has stored all of the pertinent information in the following tables: Customer, Billing_Method, Order and Line_item. This example uses PHP Data Objects (PDO), although classic OCI8 methods would also work.
                               
$db = new PDO('oci:', 'scott', 'tiger' 'HR', 'HR');

$dbcustomer = $dbh->query("SELECT       * " .
        "FROM           customer " .
        "WHERE  customerid = '{$_SESSION[customerid]'}");
        $dborder = $dbh->query("SELECT  * " .
        "FROM   order " .
        "WHERE  customerid = '{$_SESSION[customerid]}' " .
        "AND    orderid = '{$_SESSION[orderid]}'");
$dbbilling = $dbh->query("SELECT        * " .
        "FROM           billing_method " .
        "WHERE          billingid = '{$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);
                            
At this point, PayPal performs the Direct Payment requested. To find out what happened, the application now retrieves the information in the third step: response processing.
$response = $caller->DoDirectPayment($ddp);
The various fields returned in this response provide information about the success of the transaction, as well as a transaction id. By storing this ID and providing it to a later API call, the application can later retrieve details about the transaction, and as such would merit another table.
$d =& Services_PayPal::getType('GetTransactionDetailsRequestType');
$d->setTransactionId('<transaction ID from above>');
$response = $caller->GetTransactionDetails($d);

Un-WebConsole-able

At the time of writing, the WebConsole provided with the SDK download above is broken, missing important directories. However, an archive containing all the necessary files is available for download. The console provides the ability to both test API calls and generate PHP code snippets, which can be adapted to your purposes. Through some investigation here and in the SDK reference, it is possible to explore all the API calls against the sandbox from the comfort of your browser.

Take a Ride on Checkout Express

Between the power of Direct Payment and the simplicity of Standard Checkout lies Express Checkout. With Express Checkout, an API-based method, your user concludes his order creation process on your site, then proceeds to PayPal to handle all billing and shipping information. The user need only enter this information once for all merchants using Express Checkout, and your application need not store it—a considerable security and development advantage. As above, by storing the transaction ID the application can retrieve details though additional API calls. Express Checkout can make use of IPN, described above, allowing additional real-time processing options. The snippets below are adapted from the SDK examples.

$amount =& Services_PayPal::getType('BasicAmountType');
$amount->setval(<amount determined by your page>);
$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);
The result of this call provides you with a token, which you then append to a link or redirect on your site to PayPal. The user then conducts their business with PayPal and, upon success or failure, is redirected to your site. In this example, the page called return would issue the following API call to your application:
$ecd =& Services_PayPal::getType('GetExpressCheckoutDetailsRequestType');
$ecd->setToken('<token from above>');

$response = $caller->GetExpressCheckoutDetails($ecd);
This includes all the information about the transaction that is useful to you, without sensitive information like credit card numbers. After the user confirms these values on your site, the final API call actually performs the transaction of funds:
$amount =& Services_PayPal::getType('BasicAmountType');
$amount->setval(<amount from above>);
$amount->setattr('currencyID', 'USD');

$pdt =& Services_PayPal::getType('PaymentDetailsType');
$pdt->setOrderTotal($amount);

$details =& Services_PayPal::getType('DoExpressCheckoutPaymentRequestDetailsType');
$details->setPaymentAction('Sale');
$details->setToken('<token from above>');
$details->setPayerID('juser@jisp.com');
$details->setPaymentDetails($pdt);

$ecprt =& Services_PayPal::getType('DoExpressCheckoutPaymentRequestType');
$ecprt->setDoExpressCheckoutPaymentRequestDetails($details);

$response = $caller->DoExpressCheckoutPayment($ecprt);
Similarly, on successive calls to updateChart, ChartData fires the onResult method:
_root.chartData.onResult = function() {
        _root.chart.throbber._visible = false;
        drawChart(this);
}
Express Checkout is nearly as customizable as Direct Payment, while maintaining the privacy and security advantages of Standard Checkout.

Here's To You, Pal

PayPal payment processing, in any of its forms, offers an efficient way to collect online payments. It is up to the implementer to decide which model is most appropriate: Standard Checkout provides small organizations with the ability to collect payments without investing in more security architecture, Direct Payment is ideal when integrating with an existing enterprise application, and Express Checkout offers a middle ground, suitable for adaptation into third-party products. Choosing a balance of flexibility, security and ease of implementation allows you to leverage your existing Oracle infrastructure to gain access to online payments. Nick Bollweg [ nick.bollweg@gmail.com] is a freelance Web developer in the Baltimore, Maryland, area.

Send us your comments