Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and...

30
Create a Web storefront using PHP and PayPal, Part 3: Setting up orders, shipping, and e-mail An introduction to transactions using PHP Data Objects Skill Level: Intermediate Martin Brown ([email protected]) Freelance Writer Tyler Anderson ([email protected]) Freelance Writer Stexar Corp. 22 Nov 2005 This series chronicles the building of a Web storefront in PHP using PHP Data Objects to access a Derby database. The storefront includes a user manageable shopping cart that allows item purchases using PayPal, and includes the ability for merchants to notify customers via e-mail on successful orders automatically. This final part covers the addition of transactions, a shipping component, and an e-mail notification feature. Section 1. Before you start This tutorial is for those interested in expanding the storefront created in "Create a Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions, shipping, and e-mail functionality. This tutorial assumes knowledge of PHP, including PHP Data Objects (PDO) and user sessions, as covered in Part 1. About this series The staff at Ghastly Computers is excited about completing the storefront and Setting up orders, shipping, and e-mail © Copyright IBM Corporation 1994, 2008. All rights reserved. Page 1 of 30

Transcript of Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and...

Page 1: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

Create a Web storefront using PHP and PayPal,Part 3: Setting up orders, shipping, and e-mailAn introduction to transactions using PHP Data Objects

Skill Level: Intermediate

Martin Brown ([email protected])Freelance Writer

Tyler Anderson ([email protected])Freelance WriterStexar Corp.

22 Nov 2005

This series chronicles the building of a Web storefront in PHP using PHP Data Objectsto access a Derby database. The storefront includes a user manageable shopping cartthat allows item purchases using PayPal, and includes the ability for merchants tonotify customers via e-mail on successful orders automatically. This final part coversthe addition of transactions, a shipping component, and an e-mail notification feature.

Section 1. Before you start

This tutorial is for those interested in expanding the storefront created in "Create aWeb storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of thisthree-part series by integrating transactions, shipping, and e-mail functionality. Thistutorial assumes knowledge of PHP, including PHP Data Objects (PDO) and usersessions, as covered in Part 1.

About this series

The staff at Ghastly Computers is excited about completing the storefront and

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 1 of 30

Page 2: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

putting it to use. This tutorial will cover the finishing touches -- mainly, adding thefunctionality to the storefront that will allow customers to ship purchased items to theproper destinations.

Part 1 focused on setting up a Derby database and creating the basic storefront.You will access Derby through PDO. User sessions are started to help set up forPart 2 where a shopping cart is associated with a user's session ID. The shoppingcart is stored in the Derby database, and the user's session ID becomes the ID ofthe cart. The shopping cart, if it contains items, is shown under the listing ofcategories in the storefront. The cart displays Manage cart and Checkout links.Checking out involves taking a user's ship-to/bill-to information, which will besubmitted for payment to PayPal. After completing the payment to PayPal, the useris then shown a Thank you page, and is given a new session ID.

Part 3 covers viewing orders, and notification for shipping and e-mail. Transactionsusing PDO will also be introduced. Adding shipping to the checkout process will beincorporated via UPS, offering real-time shipping prices. E-mail notification will besent to the customer showing an order summary. PayPal, by default, also sends apayment confirmation e-mail messages to the user and the merchant.

About this tutorial

This tutorial will add some finishing touches to the store application so the staff atGhastly Computers can actually ship the products its customers are buying. You willstart with an administration interface that will enable you to complete the orderprocess (from the administration side). Then, on the user side, you'll add steps thatwill ensure that orders are correctly placed (by using transactions), add shippingcosts and choices to our application (using UPS), and finally add the ability to sendan e-mail to the customer when the transaction has been completed and the orderhas been shipped.

Prerequisites

To follow along, you will need to install and test the following tools:

Web serverPick any Web server and operating system. Feel free to use Apache V2.X, orthe IBM HTTP Server.

PHPDue to the use of PHP data objects, the latest version, PHP V5.1, is necessaryto fully follow along in this tutorial. Note that V5.1 is is a release candidate (RC)

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 2 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 3: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

and is not yet an official release. Be sure to configure PHP with the followingoption to include support for Derby:--with-pdo-odbc=ibm-db2,/home/db2inst1/sqllib. See Resourcesfor information about configuring Apache or the IBM HTTP Server with PHP.

DatabaseThis tutorial uses Derby. Download Derby V10.1, the current IBM DB2 JDBCUniversal Driver, and the DB2® run-time client from IBM. Be sure to follow theinstructions on each page carefully. Follow either the Linux® or Windows®instructions for downloading and installing the DB2 run-time client.You may also use Cloudscape for this tutorial. The internals of Cloudscape arethe same as Derby. However, the DB2 JDBC Universal Driver and other thingsare packaged into Cloudscape, and it is supported by IBM. DownloadCloudscape V10.1, and the DB2 run-time client from IBM.

Java™Derby requires Java technology. I have found the gcj provided in Red Hat Linuxdistributions insufficient. Download Java technology from Sun.

Section 2. Viewing orders

Once a user has added items to the shopping cart and submitted an order to GhastlyComputers, the staff needs to access the orders, prepare the goods, and send theitems. To accomplish this, there needs to be a way to view completed ordersthrough an administration interface.

The order process

Up to now, you've concentrated on the user side of the process by building astorefront. The basic sequence for the user is as follows:

• Browse the catalog

• Add one or more products to the shopping cart

• Edit basket contents

• Start the checkout process

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 3 of 30

Page 4: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

• Enter name and address details

• Get forwarded to the PayPal service to confirm payment

• Get a success message from the store confirming the order

The next part of the process is for employees to fulfill the orders. To do this, theadministration system needs to be extended to include the functionality to view theorders that have been placed. We tackle this next.

Orders that need to be filled

First, you need to produce a list of the available orders. Start by adding a button tothe administration system that links through to a new function that will be createdshortly. Change the following code to admin/storeFront.php, as shown inListing 1. The changes are in bold.

Listing 1. Adding a button to the administration system

if($_GET['viewOrders'] == "true"){printOrders($pdo);

}else if($_GET['viewItem'] != ''){

printViewItem($pdo);}

Listing 1 will force your script to run the printOrders() code, but you also need toadd some code to the navigation bar displayed at the top of the administration page.This is done by adding to the code in the displayTopBarHelper() function in themain includes/shared_functions.php file, as shown in Listing 2.

Listing 2. Adding code to the navigation bar at the top of the administrationpage

if($_GET['viewOrders'] != "true")print(" | <a href='storeFront.php?viewOrders=true'>Manage orders</a>");

elseprint(" | Manage orders");

The result is the addition of a button on your administration page, as shown in Figure1.

Figure 1. The new administration page

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 4 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 5: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

Viewing individual orders

To actually show individual orders, you first have to obtain a list of the orders fromvalid customers. You need to display the customer details, then print out the detailsof the order items and the value. You can start to build your function with the SQLstatement to obtain the list of orders, shown in Listing 3.

Listing 3. The start of the printOrders() function

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 5 of 30

Page 6: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

function printOrders($pdo){

$sql = "select *from orders, customerswhere orders.email=customers.email;";

$result = $pdo->query($sql);

Now, let's print out the information, in the form of a table, so you get a list of all theorders. You can dump out the information, as shown in Listing 4.

Listing 4. Printing the basic order information

$str = "<center><h3>Orders</h3></center>";$str .= "

<table width='100%' border='0' cellspacing='5' cellpadding='0'>";$totalOrders = 0;try{foreach($result as $row){

$orderStr = "";$cartid = $row['CARTID'];$first_name = $row['FIRST_NAME'];$last_name = $row['LAST_NAME'];$street_address = $row['STREET_ADDRESS'];$city = $row['CITY'];$state = $row['STATE'];$zip = $row['ZIPCODE'];$phone_number = $row['PHONE_NUMBER'];$email = $row['EMAIL'];$status = $row['STATUS'];$orderStr .= "\n<b>$first_name $last_name</b><br>";$orderStr .= "$street_address<br>";$orderStr .= "$city, $state&nbsp;&nbsp;$zip<br>";$orderStr .= "$phone<_number<br>";$orderStr .= "$email<br>\n";

Printing individual order items

Now that you have the basic order details, let's execute another query on thedatabase so you can print the individual items in the order. The SQL is quitecomplex because you're going to pick out specific fields from two tables. The firsttable is the product table, which will provide the name, price, and product ID. Thesecond table is the shopping_cart_contents table, where you'll get the attributevalue, quantity, and product ID. You'll use a join between the two tables to get aconcise list of the products, their prices, and their quantities from the database (seeListing 5).

Listing 5. Getting a list of items from an individual order

$sql = "select products.name, products.price, products.productid,shopping_cart_contents.attribute_value,shopping_cart_contents.qty

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 6 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 7: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

from products, shopping_cart_contentswhere products.productid=shopping_cart_contents.productidand shopping_cart_contents.cartid=$cartid";

$result2 = $pdo->query($sql);

Now let's print out the information, embedding the details into another table (seeListing 6). A try statement will be used so you can capture the end of the items inthe shopping cart, close off the table, and output the total price of the goods.

Listing 6. Outputting order items

$orderStr .= "<font size='-1'>";$orderStr .= "<table><tr width='100%'><td width='35%'>Name</td>";$orderStr .= "<td width='25%'>Attribute</td><td width='12%'>";$orderStr .= "Price</td><td width='13%'>Qty</td></tr>";$totalPrice = 0;try{foreach($result2 as $row2){

if($row2['QTY'] <= 0) continue;$orderStr .= printOrderItem($row2);$totalPrice += $row2['PRICE'] * $row2['QTY'];

}}catch(Exception $e){}$orderStr .= "</table>";$orderStr .= "</font>";$orderStr .= "<b>Total: $totalPrice</b><br>";

Before finishing off the statement and ending the function, you'll also print out a formso the staff at Ghastly Computers can mark the order as shipped. You'll do this byintroducing a simple form that will call the viewOrders function again with the formdata. The form itself is made up of the hidden shopping cart ID number and anoption list of statuses to apply to the order. Note that there is a form for each order,so you are still within the main foreach loop iterating over the orders in the system.You can see the code for this in Listing 7.

Listing 7. Adding a status change form

$orderStr .= "<form action='storeFront.php?viewOrders=true'".processGETString("")."' method='post'>";

$orderStr .= "Order status: ";$orderStr .= "<input type='hidden' name='id' value='$cartid' />";

$orderStr .= "<select name='changeStatus'>";if($status == 'Pending')

$orderStr .= "<option value='Pending' selected>Pending</option>";else

$orderStr .= "<option value='Pending'>Pending</option>";

if($status == 'Processing')$orderStr .= "<option value='Processing'

selected>Processing</option>";else

$orderStr .= "<option value='Processing'

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 7 of 30

Page 8: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

>Processing</option>";

if($status == 'Shipped')$orderStr .= "<option value='Shipped' selected>Shipped</option>";

else$orderStr .= "<option value='Shipped'>Shipped</option>";

$orderStr .= "</select>";$orderStr .= "<input type='submit' value='Change status' /><br>";$orderStr .= "</form>-------------------<br>";

if($totalPrice > 0){$str .= $orderStr;$totalOrders++;

}

Now all that's left is to close the table. Just in case there are no available orders inthe system, you'll also print a message if no orders can be found. The final few linescan be seen in Listing 8.

Listing 8. The final lines of the printOrders function

}}catch(Exception $e){}

$str .= "</table>";print($str);if($totalOrders <= 0){

print("There are no orders ... yet!");return;

}}

You can see a sample of the output generated by the code in Figure 2.

Figure 2. Sample output

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 8 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 9: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

To finish off this section, let's add in the code to actually update the status of theorder when the pop-up is changed.

Setting the status of an order

To change the status of an order, you need to modify the printOrders function soit runs the SQL necessary to update the order when called -- assuming the newstatus information has been supplied, of course.

You've seen examples of this in previous parts of this series, so the fundamentals

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 9 of 30

Page 10: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

should be straightforward enough to follow. The full code is shown in Listing 9.

Listing 9. Updating order statuses

if(isset($_POST['changeStatus']) && isset($_POST['id'])){$status = $_POST['changeStatus'];$id = $_POST['id'];$sql = "update orders set

status='$status'where cartid=$id";

$pdo->exec($sql);}

You need to add this code immediately after the function declaration so the orderstatus will be updated and the list of orders will be printed so you can monitor otherorders.

Section 3. Introducing transactions

Web applications and databases don't always work smoothly. Sometimes you needa way to protect the order process from submitting an order that isn't paid for, orfrom paying for an order that never gets submitted. You don't, after all, want toalienate Ghastly Computers' customers. You can improve the reliability of the orderprocess by adding transactions to your payment process.

What is a transaction?

To understand what a transaction is, you need to think about the sequence youfollow when you perform an operation. Let's start with a simple physical transaction.If someone literally hands you a book, you know you received it because you canfeel it in your hands, and, if you look at it, you can see it is the book you expected.

Now let's move on to something more complicated. In a double-entry accountingsystem, if you move money from one account to another, you first debit one account,then credit the other. Let's say, for example, you are transferring $250 from yourchecking account to your credit card account. First, the computer deducts the moneyfrom your checking account, then it credits the same amount to your credit cardaccount.

But what if there is some problem in the system between the debit of your checking

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 10 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 11: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

account and the credit of your credit card account? Your checking account wouldshow a debit of $250, but your credit card account would not show a credit of $250.

You could include all sorts of checking systems into the application, but this wouldstill rely on the application being aware of the status of the process and crediting thechecking account if there had been a failure. That might be an impossible process ifthere has been a database failure. The solution is the transaction, which is a specialfunction of the database engine that enables you to execute a statement, but onlycommit changes when you are sure that the necessary steps in the application havetaken place.

The need for transactions

Returning to the account example, the application would submit the two queries thatwould debit and credit the account, and only then send the instruction to thedatabase to actually commit the transactions once the system was sure the processhad completed properly. If there was any kind of problem with the application, thecommit instruction wouldn't be sent to the database, and the information would beupdated or stored.

By default, most modern databases, including our Derby solution, are in auto-commitmode unless they are told to operate otherwise. This means that every SQLstatement submitted to the system is automatically committed and, therefore, writtento the database.

It is up to the application to tell the database whether to commit (save) or roll back(ignore) any of the changes to the database. All changes are automatically ignoredby the database if the connection to the database from the application dies or isdisconnected.

For your system, the key part of the application that needs transactions is thepayment and order completion system that takes our order, submits the order toPayPal, then updates the order information into the system.

What you don't want is for the PayPal stage of the process to end up confirming thesuccess of the order process if there was some failure in the system. Otherwise, youcould have orders in the system that funds had not been received for, simplybecause the database was updated with information. You can use transactions forthis by wrapping the code that marks an order as complete into a transaction. Then,only when the PayPal process has completed successfully, will the data actually bewritten to the database.

Let's look at how you can change the code to include transactions into the process.

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 11 of 30

Page 12: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

Creating the transaction

Within the realm of your database connection, you need to explicitly tell the systemto work in transaction mode. We do this by calling the beginTransaction()method on your database connection. This, in turn, tells the Derby database to treatall statements from this moment onward as part of a single transaction. Changes tothe database that would normally be triggered by the execution of a SQL statementwill now be held in limbo until such time as the database is told to write the changes.

The only stage you need to protect is the PayPal system. You can change thepaypal_ipn_handler.php file so that when you connect to the database, youimmediately switch into transaction mode:

$pdo = db_connect();$pdo->beginTransaction();

From this moment on in your code, until such time as the database is told to commitor roll back the changes or until the connection dies, no changes will be made to theactual data.

Committing or rolling back the transaction

To save the changes to the database, you must commit them. This is done throughthe PDO system in PHP using the commit() method. You need to do this once youare sure that the PayPal process has completed successfully. As a result, afteryou've checked the PayPal process, you call the method shown in Listing 10.

Listing 10. Committing the changes to the database through the commitmethod

if(strstr($info, "VERIFIED") != ''){if($payment_currency == "USD" &&

$payment_status == "Completed" &&$my_email == MY_EMAIL) {$pdo->commit();

If the process fails, you call the rollBack() method instead to ignore the changes.You'll just use placeholders for this stage for the moment and roll back the data, andyou'll worry about telling the user about the failure later.

Listing 11. Calling the rollBack() method

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 12 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 13: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

}else

$pdo->rollBack();}else{

$pdo->rollBack();// log for manual investigation

}

The Derby database will do the rest. If there is any kind of problem, including somekind of failure in the application, connection, or database, the changes to thedatabase will be ignored without a formal commit instruction.

Section 4. Adding shipping

For Ghastly Computers customers to get their goods, you need to know how you aregoing to ship the items once the orders have been submitted. This could be donewith a standard-rate shipping policy, but it would be much nicer if you could giveindividual customers the opportunity to make decisions about how they want to shiptheir packages and how much they want to pay for those services. By using the UPSrate service and with some changes to your code, you can add that ability to thecheckout process.

UPS' rate service

Once a customer has actually placed an order, you need to ship the items to them.While the shipping system could be complex, UPS provides a service that cancalculate the cost of shipping based on the source, destination, and weight of theitems. It works like other systems you've seen in this series by using informationfrom your database to build a URL used to access data from a remote host andwhich can then be parsed to produce a standard list of shipping options.

The full code, which provides a class for determining shipping rates for specificclasses of shipment (next-day, two-day, etc.) and a variety of weights, can be seenin Listing 12. You can see that changes can be added to the options used accordingto the needs of company. For Ghastly Computers, you'll use the options shown inListing 12. You can save this code as UPS.php.

Listing 12. The UPS rate service interface

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 13 of 30

Page 14: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

<?php

class UPS{function UPS(){

$this->regularity = "Customer+Counter";/* Also available:* On+Call+Air* Letter+Counter* One+Time+Pickup* Regular+Daily+Pickup*/

$this->packaging = "00";/* Customer package (most common)* Can't guarantee that things will fit* in the other boxes.*//* Also available:* 01 - UPS Letter Envelope* 03 - UPS Tube* 21 - UPS Express Box* 24 - UPS WorldWide 25 kg Box* 25 - UPS WorldWide 10 kg Box*/

$this->residential = "1";/* Residential address *//* Also available:* 0 - Commercial address*/

}

/* Country must be 2 character ISO code */function from($zip, $country){

$this->fromZip = $zip;$this->fromCountry = $country;

}

/* Country must be 2 character ISO code */function to($zip, $country){

$this->toZip = $zip;$this->toCountry = $country;

}

/** Price to weight conversion*/

function priceToWeight($price){if($price < 30)

$w = 5;else if($price < 50)

$w = 10;else if($price < 100)

$w = 20;else if($price < 200)

$w = 30;else if($price < 500)

$w = 45;else

$w = 60;$this->weight = $w;

}

/*

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 14 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 15: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

* Standard US based codes:* 1DM == Next Day Air Early AM -- Won't use* 1DA == Next Day Air* 1DP == Next Day Air Saver -- Won't use* 2DM == 2nd Day Air Early AM -- Won't use* 2DA == 2nd Day Air* 3DS == 3 Day Select* GND == Ground** Also available:* STD == Canada Standard* XPR == Worldwide Express* XDM == Worldwide Express Plus* XPD == Worldwide Expedited*/

function getRates(){$methodRate = array('Next Day Air' => '1DA',

'2nd Day Air' => '2DA','3 Day Select' => '3DS','Ground' => 'GND');

$url = $this->urlGen();foreach ($methodRate as $key => $value) {

$methodRate[$key] = $this->query($url . $value);}return $methodRate;

}

function urlGen(){$url = UPS_URL;$url .= "&14_origCountry=".$this->fromCountry;$url .= "&15_origPostal=".$this->fromZip;$url .= "&19_destPostal=".$this->toZip;$url .= "&22_destCountry=".$this->toCountry;$url .= "&23_weight=".$this->weight;$url .= "&47_rateChart=".$this->regularity;$url .= "&48_container=".$this->packaging;$url .= "&49_residential=".$this->residential;$url .= "&13_product=";return $url;

}

function query($url){$fp = fopen($url, "r");$result = fgets($fp, 512);$result = explode("%", $result);$returnval = $result[8];fclose($fp);if(! $returnval) { $returnval = "error, refresh page"; }return $returnval;

}

function getRate($method){return $this->query($this->urlGen() . $method);

}

}

?>

The key method is getRate(), which determines the shipping rate of the packageusing a specific shipping method. It does this by combining information in an

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 15 of 30

Page 16: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

instance of the class into a query sent to the UPS service. This method is furtherwrapped into a function called getRates(), which obtains the shipping rates for arange of shipping methods, returning an associative array of the information.

Formatting the shipping methods

You can further wrap this into a method that will format the information into a seriesof radio buttons that can be included on your shipping pages. This sequence hasbeen distilled down into the function shown in Listing 13.

Listing 13. Adding display options to the UPS class

function displayOptions($price, $toZip){$this->priceToWeight($price);$this->from(FROM_ZIP, "US");$this->to($toZip, "US");$methodRate = $this->getRates();$str = "";foreach ($methodRate as $key => $value) {$str .= "$key: $value";$str .= "<input type='radio' name='shipMethod' value='$key'>\n";$str .= "<input type='hidden' name='$key' value='$value'><br>\n";}return $str;

}

The method calls getRates(), then iterates through the information, generating astring for the radio buttons, returned to the caller.

Let's have a look at how you call this from the checkout procedure.

Changing the checkout process, step two

In your original order sequence, once the user supplied his address details, he wasimmediately forwarded on to PayPal to make a payment for the goods.

You need to change this process because you are now able to provide shippinginformation. You, therefore, need to provide the user with a choice of the level ofshipping he wants to use for the order.

This will be done by changing the form presented to the user at step two and addinga new stage, step three, which will be the summary information and the point atwhich you then forward the user on to the PayPal service so he can pay for theorder. This requires a change to the printCheckout_2() code, shown in Listing14.

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 16 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 17: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

Listing 14. Changing the checkout process

function printCheckout_2($pdo){

$cartid = $_POST['cartid'];$first_name = $_POST['first_name'];$last_name = $_POST['last_name'];$email = $_POST['email'];$street_address = $_POST['street_address'];$city = $_POST['city'];$state = $_POST['state'];$zipcode = $_POST['zipcode'];$phone_number = $_POST['phone_number'];

$sql = "select email from customerswhere email='$email'";

$result = $pdo->query($sql);

if(!$result || !$result->fetch())$sql = "insert into customers values ('$email','$first_name',

'$last_name','$street_address','$city','$state','$zipcode','$phone_number')";

else$sql = "update customers set

first_name='$first_name',last_name='$last_name',street_address='$street_address',city='$city',state='$state',zipcode='$zipcode',phone_number='$phone_number'

where email='$email'";$pdo->exec($sql);

$sql = "update shopping_carts setemail='$email'where cartid=$cartid";

$pdo->exec($sql);

$sql = "select products.price, shopping_cart_contents.qtyfrom shopping_cart_contents, productswhere products.productid=shopping_cart_contents.productidand cartid=$cartid";

$total = 0;foreach ($pdo->query($sql) as $row){

$total += $row['PRICE'] * $row['QTY'];}

All of this information is similar to your original step two, but the function is notfinished. Now you need to add the shipping cost information. First, let's show asummary of the shipping information (see Listing 15).

Listing 15. Add shipping details

$str = "<center><h3>Select Shipping</h3></center>";$str .= "<table width='100%' border='0' cellspacing='5' cellpadding='0'>";$str .= "<tr><td><b>Bill to/Ship to:</b><br>";$str .= "$first_name $last_name<br>$street_address<br>";

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 17 of 30

Page 18: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

$str .= "$city, $state&nbsp;&nbsp;$zipcode<br>";$str .= "$phone_number<br>$email<br>Order total: $total<br>";

The next part is your list of options, so you create a new form; this will send youstraight on to step three of the process.

$str .= "</td><td><br>Select Shipping method:<br><form action='storeFront.php?checkout3=true' method='post'>\n";

Now you need to create a new UPS object and display the list of options using themethod created previously:

$ups = new UPS();$str .= $ups->displayOptions($total, $zipcode);

Finally, output the remainder of the hidden fields you need to pass on to step three,as shown in Listing 16.

Listing 16. Incorporating the order information

$str .="<input type='hidden' name='total' value='$total'/><input type='hidden' name='cartid' value='$cartid' /><input type='hidden' name='first_name' value='$first_name'><input type='hidden' name='last_name' value='$last_name'><input type='hidden' name='email' value='$email'><input type='hidden' name='street_address' value='$street_address'><input type='hidden' name='city' value='$city'><input type='hidden' name='state' value='$state'><input type='hidden' name='zipcode' value='$zipcode'><input type='hidden' name='phone_number' value='$phone_number'><input name='submit' type='submit' value='Proceed' /></form>";

$str .= "</td></tr></table>";

print($str);}

Now the user has been given the option to select the shipping information, and whenthe shipping level is selected, he moves on to step three. You need to changestoreFront.php so the correct function is called. Update that section of the code toread like Listing 17.

Listing 17. Updating the checkout process

else if($_GET['checkout3'] == 'true'){printCheckout_3($pdo);

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 18 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 19: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

}else if($_GET['checkout2'] == 'true'){

printCheckout_2($pdo);}else if($_GET['checkout'] == 'true'){

printCheckout_1($pdo);}

If you examine Figure 3, you can see the changes to the process now include thenew shipping information.

Figure 3. New shipping information

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 19 of 30

Page 20: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

Changing the checkout process, step three

Once the user has selected the shipping option, you can move on to step three. Allyou need to do is add the shipping costs to the total supplied to PayPal.

You do that right at the start when processing the form fields from the previous stage(see Listing 18).

Listing 18. The new printCheckout_3 function

function printCheckout_3($pdo){$shipMethod = $_POST['shipMethod'];$shipTotal = $_POST[str_replace(" ", "_", $shipMethod)];$total = $_POST['total'];$amountDue = $shipTotal + $total;$cartid = $_POST['cartid'];$first_name = $_POST['first_name'];$last_name = $_POST['last_name'];$email = $_POST['email'];$street_address = $_POST['street_address'];$city = $_POST['city'];$state = $_POST['state'];$zipcode = $_POST['zipcode'];$phone_number = $_POST['phone_number'];

The rest of this step follows the content you included in step two (see Listing 19).

Listing 19. The remainder of the step three code

$str = "<center><h3>Order Summary</h3></center>";$str .= "<table width='100%' border='0' cellspacing='5' cellpadding='0'>";

$sql = "select email from orderswhere email='$email'and cartid=$cartid";

$result = $pdo->query($sql);if(!$result || !$result->fetch())

$sql = "insert into orders values ($cartid,'$email',$amountDue,'Pending')";

else{$row = $pdo->query($sql)->fetch();!($row['STATUS'] == 'paid') or

die("This shopping cart has already been paid for!");$sql = "update orders set

status='Pending',amount_due=$amountDuewhere email='$email'and cartid=$cartid";

}$pdo->exec($sql);

$str .= "<b>Bill to/Ship to:</b><br>";$str .= "$first_name $last_name<br>$street_address<br>";

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 20 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 21: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

$str .= "$city, $state&nbsp;&nbsp;$zipcode<br>";$str .= "$phone_number<br>$email<br>";$str .= "Sub total: $$total<br>";$str .= "Shipping: $$shipTotal ($shipMethod)<br>";$str .= "<b>Total: $$amountDue</b><br>";

$str .= "Confirm your order:";$str .= "

<form action='https://".PAYPAL_URL."/cgi-bin/webscr' method='post'><input type='hidden' name='cmd' value='_ext-enter'><input type='hidden' name='redirect_cmd' value='_xclick'><input type='hidden' name='email' value='$email'><input type='hidden' name='amount' value='$amountDue'><input type='hidden' name='item_name' value='".STORE_NAME."'><input type='hidden' name='item_number' value='1'><input type='hidden' name='notify_url'value='http://".MY_URL."/paypal_part3/paypal_ipn_handler.php'><input type='hidden' name='cancel_return'value='http://".MY_URL."/paypal_part3/storeFront.php?checkout2=true'><input type='hidden' name='return'value='http://".MY_URL."/paypal_part3/storeFront.php?thankyou=true'><input type='hidden' name='rm' value='2'><input type='hidden' name='currency_code' value='USD'><input type='hidden' name='business' value='".MY_EMAIL."'><input type='hidden' name='first_name' value='$first_name'><input type='hidden' name='last_name' value='$last_name'><input type='hidden' name='address1' value='$street_address'><input type='hidden' name='city' value='$city'><input type='hidden' name='state' value='$state'><input type='hidden' name='zip' value='$zipcode'><input type='hidden' name='country' value='US'><input type='hidden' name='lc' value='US'><input type='hidden' name='shipping' value='0.00'><input type='hidden' name='custom' value='$cartid'><input type='hidden' name='upload' value='3'><input name='submit' type='submit' value='Pay with PayPal' />";

$str .= "</table>";print($str);

}

When the user completes this stage, he gets sent on to PayPal to organize paymentusing the same PayPal function and process seen before, albeit with the transactionprocess included in step two.

The result is an updated summary page, now showing the total figure including theshipping, as shown here in Figure 4.

Figure 4. New order summary page

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 21 of 30

Page 22: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

Section 5. E-mail notification

Once an order has been submitted, it would be polite for Ghastly Computers toacknowledge receipt of that order with an e-mail detailing the contents of the orderand where and how the goods will be sent. Doing this by hand would betime-consuming, so let's look at how easy it is to add this stage into the checkout

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 22 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 23: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

process.

Order confirmations

If you've gotten all the way through the order process, the next stage is tocommunicate with the user about the order that has just been placed.

E-mail confirmations are important for a number of reasons. Users will sometimesforget about an order, their systems may crash, or their connections may fail duringthe transaction process. Some users can also be impatient, and they may close theirbrowser sessions or windows in frustration when they don't get an instantaneousresponse. The use of PayPal can also mean that some users assume that the entiresequence has completed once they have gone through the PayPal process.

Let's look at how to send an e-mail from within PHP.

Sending an e-mail from PHP

The PHP language includes built-in support for sending e-mail. You don't need toworry about how the e-mail is actually sent. The default configuration should work; ifnot, check your PHP installation documentation for details. The mail() function inPHP is responsible for sending an e-mail. The basic format (and requiredarguments) of the function:

bool mail ( string to, string subject, string message)

You can see that the function accepts only the e-mail address to which you want tosend the message, the subject of the message, and the message string. Therecipient information is required so the mail system knows where to send the e-mail,but the other information, such as whom the e-mail comes from, is informationtechnically embedded into the "header" of the message. The "body" of the message(the real content) is what most would consider the real content of the e-mail. Theheader and body information, which when combined is called the mail data, isseparated by a single blank line. Fortunately, the PHP mail() function enables youto specify the message data, not just the message body.

Therefore, if you want to include an e-mail address (like the administration e-mailaddress for the store), you will need to construct a suitable e-mail body beforesending the e-mail. The easiest way to do this is to build a wrapper function thatconstructs a suitable message, incorporating a custom subject and body with therequired header information.

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 23 of 30

Page 24: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

You'll do this quite simply by incorporating the following function definition into youruser_functions.php file (see Listing 20).

Listing 20. Incorporating the sendMail function

function sendMail($to, $message){mail("$to",

"Message from ".STORE_NAME,$message,"From: ".MY_EMAIL."\r\n\r\n");

}

You can send an e-mail to a customer by calling the function like this:

sendMail(useremail,message)

Before you go ahead and use it, let's determine when you might want to send ane-mail and what you might include in the contents.

Sending the confirmation e-mail

You're going to send a confirmation e-mail as part of the PayPal process. You knowthat PayPal will send confirmation of the payment, but you want to send thecustomer an e-mail that comes directly from the store and includes all of the detailsof the order, including name and address, products ordered, and the shippinginformation.

To do this, you're going to add some code to build the necessary message data tothe final stage of the PayPal process. You'll only send the e-mail to the customer ifthe payment through the PayPal system is accepted and verified.

Immediately after committing the transaction to the database, you build the e-mailmessage contents and call the sendMail() function to send the e-mail message toyour customer.

The first part of the code builds the introductory information for the message, shownin Listing 21.

Listing 21. Building the mail message

if(strstr($info, "VERIFIED") != ''){if($payment_currency == "USD" &&

$payment_status == "Completed" &&$my_email == MY_EMAIL) {

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 24 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 25: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

$pdo->commit();// Check for duplicate transactions through $txn_id

// Send email notification$first_name = $_POST['first_name'];$last_name = $_POST['last_name'];$street_address = $_POST['address1'];$city = $_POST['city'];$state = $_POST['state'];$zipcode = $_POST['zip'];

$msg = "Thank you for your order!!\r\n";$msg .= "Your order number: $cartid\r\n\r\n";$msg .= "Your order details follow:\r\n\r\n";$msg .= "Bill to/Ship to:\r\n";$msg .= "$first_name $last_name\r\n$street_address\r\n";$msg .= "$city, $state $zipcode\r\n\r\n";$msg .= "Items:\r\n";

It's nice to get a list of products for the user. You don't have that information handyat this stage in the process, so you'll access the transaction details to get the productinformation for the transaction from the database and include a line for each item inthe order. See Listing 22 for the item summary code.

Listing 22. Displaying order items

$sql = "select products.name, products.price,shopping_cart_contents.attribute_value,shopping_cart_contents.qty

from products, shopping_cart_contentswhere products.productid=shopping_cart_contents.productidand shopping_cart_contents.cartid=$cartid";

$result = $pdo->query($sql);try{

foreach ($result as $row){$qty = $row['QTY'];if($qty <= 0) continue;$attribute = $row['ATTRIBUTE_VALUE'];if($attribute == "none")

$attribute = '';$price = $row['PRICE'] * $qty;$name = $row['NAME'];$msg .= "$name: $attribute $$price X $qty\r\n";

}

You've used a try statement here so that when you come to the end of the process,you can capture the end of the sequence and include all the final details of the orderinto the e-mail. This includes the total amount for the order, a thank you message,and the name of the store. You can see the final part in Listing 23.

Listing 23. The final code for sending an e-mail

}catch(Exception $e){}$msg .= "\r\nOrder total: $$amountDue\r\n";

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 25 of 30

Page 26: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

$msg .= "\r\n";$msg .= "THANKS AGAIN!!!\r\n";$msg .= "Sincerely,\r\n";$msg .= STORE_NAME."\r\n\r\n";sendMail($email, $msg);

}

Let's have a look at the resulting message in Listing 24.

Listing 24. The confirmation e-mail

Thank you for your order!Your order number: 1031884807

Your order details follow:

Bill to/Ship to:Martin BroenSome streetSome City, A State 90210

Items:Microsoft Office: Platform: Mac OS X $100 X 1Microsoft Office: Platform: Windows $100 X 1

Order total: $215.55

THANKS AGAIN!!!Sincerely,Ghastly Computers

That's it!

The most complicated part of the process really is composing the message. ThePHP system simplifies the actual process of sending the message.

Section 6. Summary

In this tutorial, you added functionality to the storefront code introduced in parts 1and 2. In particular, you added the ability for the Ghastly Computers staff to look atan order so they can prep and ship the items. You also added some functionality tothe user side of the process to make the entire sequence slightly more friendly. Thisincludes allowing the user to select his own shipping method, using the UPS systemto provide a list of possible shipping methods.

The customer will also get confirmation of his order by e-mail, using the information

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 26 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 27: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

he supplied, and the order details. Behind the scenes, you've improved the reliabilityof the code that submits the order into the system by using transactions. A systemwill now only update the database if the other stages of the process, like the PayPalpayments, have completed successfully.

The completeness of the system is entirely dependent on how complex you want tomake it. The functionality doesn't, for example, allow for Ghastly Computers staff toe-mail the customer when the items have been shipped. You do, however, have asystem in place that allows you to send e-mail, and because the status can beupdated, merging the two sequences together would be fairly trivial. There are otheroptions available that would be easy to implement now that you have the basics ofthe order and payment sequence in place.

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 27 of 30

Page 28: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

Downloads

Description Name Size Download method

Source code for Part 3 os-paypal3code.zip14KB HTTP

Information about download methods

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 28 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.

Page 29: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

Resources

Learn

• For an excellent article on integrating PHP with Derby/Cloudscape, see"Connecting PHP applications to Apache Derby."

• Learn how to configure IBM Cloudscape V10.0 and IBM DB2 Universal Database(DB2 UDB) V8.2 servers for access from PHP V4.x and PHP V5.x "Develop IBMCloudscape and DB2 Universal Database applications with PHP."

• For a document that describes the PayPal features for managing orders,including Instant Payment Notification, see the PayPal Order ManagementIntegration Guide (PDF).

• For more information about Instant Payment Notification, read the PayPalWebsite Payments Standard Checkout Integration Guide (PDF).

• Try hosting your cart with PayPal Shopping Cart, instead of in a local database.

• Check out PayPal's Testing Instant Payment Notification.

• Visit PayPal Developer Central to access the PayPal Sandbox test environment,Website Payments testing, Instant Payment Notification, and Payment DataTransfer.

• To access the PayPal Sandbox, log in to PayPal Developer Central first.

• Consider using this PayPal IPN handler for a different style of Instant PaymentNotification handler.

• Test your Instant Payment Notification handler if you're running inside a networkor behind firewall at EliteWeaver UK.

• To learn about the differences between the open source Apache Web server andIBM's version, and view demonstrations of IBM's version running a well-knownPHP application, see the developerWorks article "Hosting PHP applications onthe IBM HTTP Server."

• For information about getting Apache V2 and PHP V4.x to work together onLinux, read the Apache 2 and PHP Installation guide.

• Learn more about PHP data objects and their capabilities in the PHP Manual.

• Various HTML form input data you may want to use for representing attributesare available at w3.org.

• Visit the IBM Tivoli information center to learn more about the SQL syntax anditems.

ibm.com/developerWorks developerWorks®

Setting up orders, shipping, and e-mail© Copyright IBM Corporation 1994, 2008. All rights reserved. Page 29 of 30

Page 30: Create a Web storefront using PHP and PayPal, Part 3 ... · Web storefront using PHP, Derby and PayPal, Part 1" and enhanced in Part 2 of this three-part series by integrating transactions,

• For a series of tutorials designed to broaden your PHP skills, see "Learning PHP,Part 1," Part 2, and Part 3.

• Visit the developerWorks Open source zone for extensive how-to information,tools, and project updates to help you develop with open source technologies anduse them with IBM's products.

Get products and technologies

• Innovate your next open source development project with IBM trial software,available for download or on DVD.

Discuss

• Get involved in the developerWorks community by participating indeveloperWorks blogs.

About the authors

Martin BrownMartin Brown has been a professional writer for more than eight years. He is theauthor of numerous books and articles across a range of topics. His expertise spansmyriad development languages and platforms -- Perl, Python, Java, JavaScript, Basic,Pascal, Modula-2, C, C++, Rebol, Gawk, Shell script, Windows, Solaris, Linux, BeOS,Mac OS/X and more -- as well as Web programming, systems management, andintegration. He is a regular contributor to ServerWatch.com, LinuxToday.com and IBMdeveloperWorks, and a regular blogger at Computerworld, The Apple Blog, and othersites. He is a Subject-Matter Expert (SME) for Microsoft.

Tyler AndersonTyler Anderson graduated with a degree in computer science from Brigham YoungUniversity in 2004 and is currently in his last semester as a master's student incomputer engineering. In the past, he worked as a database programmer forDPMG.com, and he is currently an engineer for Stexar Corp., based in Beaverton, Ore.

developerWorks® ibm.com/developerWorks

Setting up orders, shipping, and e-mailPage 30 of 30 © Copyright IBM Corporation 1994, 2008. All rights reserved.