Accepting Payments for Multiple Items with PayPal in PHP

PayPal is a most popular online payment system that helps to easily integrate payment gateway on the website. PayPal payments standard is the most simple way to implement the payment system to your website and accept payment from the buyers. In our earlier PayPal payment gateway integration tutorial, the PHP script has been provided to add PayPal buy now button to accept payment for a single item. But many times you want to accept payment for one or more items with a single checkout flow. In this tutorial, we’ll show how you can easily integrate PayPal standard payment gateway in PHP for sending multiple items to PayPal checkout.

Using PayPal Add to Cart button, you can easily accept payment for multiple items in single checkout on your website. Also, you can validate transaction using PayPal IPN and insert the order items, payment details, and transaction information into the MySQL database. Follow the step-by-step guide to integrating shopping cart with PayPal in PHP.

Create Sandbox Account

Before you make the payment gateway live, the payment process need to be tested. PayPal sandbox environment allows you to test PayPal payment gateway on your website without real payment. If you don’t have a PayPal sandbox account, create a sandbox account first.

Database Tables Creation

We’ll create 3 tables in MySQL database with some basic required fields to store the products, payments, and order items information.

The product details are stored into the products table.

CREATE TABLE `products` (
 `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `image` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `price` float(10,2) NOT NULL,
 `status` tinyint(1) NOT NULL DEFAULT '1',
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

The payments table holds the payment information.

CREATE TABLE `payments` (
 `payment_id` int(11) NOT NULL AUTO_INCREMENT,
 `txn_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `payment_gross` float(10,2) NOT NULL,
 `currency_code` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
 `payment_status` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `payer_email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
 PRIMARY KEY (`payment_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

The order_items table is used for storing the order items of the respective payment.

CREATE TABLE `order_items` (
 `payment_id` int(11) NOT NULL,
 `item_number` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 `quantity` int(5) NOT NULL,
 `gross_amount` float(10,2) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `payment_id` (`payment_id`),
 CONSTRAINT `order_items_ibfk_1` FOREIGN KEY (`payment_id`) REFERENCES `payments` (`payment_id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Database Configuration (dbConfig.php)

The dbConfig.php file is used to connect and select the database using PHP and MySQL. Specify your database credentials in $dbHost, $dbUsername, $dbPassword, and $dbName variable’s.

//Database credentials
$dbHost 'localhost';
$dbUsername 'root';
$dbPassword '';
$dbName 'semicolonworld';

//Connect with the database
$db = new mysqli($dbHost$dbUsername$dbPassword$dbName);

//Display error if failed to connect
if ($db->connect_errno) {
printf("Connect failed: %s\n"$db->connect_error);

Products (products.php)

In products.php file, all the products are fetched from the database and listed with the PayPal Add to Cart button. A form with some predefined PayPal HTML variables needs to be submitted on clicking the AddToCart button. You need to specify your PayPal email into the $paypalID variable.

//Include db configuration file
include 'dbConfig.php';

//PayPal API URL
$paypalURL '';

//PayPal Business Email
$paypalID 'InsertPayPalSandboxBusinessEmail';
?> <div class="container"> <?php
//Fetch products from the database
$results $db->query("SELECT * FROM products");
$row $results->fetch_assoc()){
?> <div class="proBox"> <img src="images/<?php echo $row['image']; ?>"/> <p>Name: <?php echo $row['name']; ?></p> <p>Price: <?php echo $row['price']; ?></p> <form target="_self" action="<?php echo $paypalURL?>" method="post"> <!-- Identify your business so that you can collect the payments. --> <input type="hidden" name="business" value="<?php echo $paypalID?>"> <!-- Specify a PayPal Shopping Cart Add to Cart button. --> <input type="hidden" name="cmd" value="_cart"> <input type="hidden" name="add" value="1"> <!-- Specify details about the item that buyers will purchase. --> <input type="hidden" name="item_name" value="<?php echo $row['name']; ?>"> <input type="hidden" name="item_number" value="<?php echo $row['id']; ?>"> <input type="hidden" name="amount" value="<?php echo $row['price']; ?>"> <input type="hidden" name="currency_code" value="USD"> <!-- Specify URLs --> <input type='hidden' name='cancel_return' value=''> <input type='hidden' name='return' value=''> <!-- Display the payment button. --> <input type="image" name="submit" src="" alt="Add to Cart"> <img alt="" width="1" height="1" src=""> </form> </div> <?php ?> </div>

Validate Transaction and Store Payment Information

To validate transaction you need to use PayPal IPN. To use PayPal IPN feature, IPN must be enabled on your PayPal account. If you have not yet enabled the IPN, follow this guide to enable IPN in PayPal – How to enable PayPal Instant Payment Notification

Add Notify URL in PayPal Form
Add the following input field (notify_url) HTML along with the other PayPal HTML Variables.

<input type='hidden' name='notify_url' value=''>

Once the IPN is enabled PayPal will send the transaction data to the specified Notify URL ( Place the following code in the ipn.php file to validate the transaction and insert payment and order information into the database.

//Include DB configuration file
include 'dbConfig.php';

 * Read POST data
 * reading posted data directly from $_POST causes serialization
 * issues with array data in POST.
 * Reading raw POST data from input stream instead.
$raw_post_data file_get_contents('php://input');
$raw_post_array explode('&'$raw_post_data);
$myPost = array();
foreach (
$raw_post_array as $keyval) {
$keyval explode ('='$keyval);
    if (
count($keyval) == 2)
$myPost[$keyval[0]] = urldecode($keyval[1]);

// Read the post from PayPal system and add 'cmd'
$req 'cmd=_notify-validate';
function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists true;
foreach (
$myPost as $key => $value) {
$get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value urlencode(stripslashes($value));
    } else {
$value urlencode($value);
$req .= "&$key=$value";

 * Post IPN data back to PayPal to validate the IPN data is genuine
 * Without this step anyone can fake IPN data
$paypalURL "";
$ch curl_init($paypalURL);
if (
$ch == FALSE) {

// Set TCP timeout to 30 seconds
curl_setopt($chCURLOPT_HTTPHEADER, array('Connection: Close''User-Agent: company-name'));
$res curl_exec($ch);

 * Inspect IPN validation result and act accordingly
 * Split response headers and payload, a better way for strcmp
$tokens explode("\r\n\r\n"trim($res));
$res trim(end($tokens));
if (
strcmp($res"VERIFIED") == || strcasecmp($res"VERIFIED") == 0) {

//Payment data
$txn_id $_POST['txn_id'];
$payment_gross $_POST['mc_gross'];
$currency_code $_POST['mc_currency'];
$payment_status $_POST['payment_status'];
$payer_email $_POST['payer_email'];
//Check if payment data exists with the same TXN ID.
$prevPayment $db->query("SELECT payment_id FROM payments WHERE txn_id = '".$txn_id."'");
$prevPayment->num_rows 0){
//Insert tansaction data into the database
$insertPayment $db->query("INSERT INTO payments(txn_id,payment_gross,currency_code,payment_status,payer_email) VALUES('".$txn_id."','".$payment_gross."','".$currency_code."','".$payment_status."','".$payer_email."')");
//Insert order items into the database
$payment_id $db->insert_id;
$num_cart_items $_POST['num_cart_items'];
$order_item_number $_POST['item_number'.$i];
$order_item_quantity $_POST['quantity'.$i];
$order_item_gross_amount $_POST['mc_gross_'.$i];
$insertOrderItem $db->query("INSERT INTO order_items(payment_id,item_number,quantity,gross_amount) VALUES('".$payment_id."','".$order_item_number."','".$order_item_quantity."','".$order_item_gross_amount."')");

Payment Success (success.php)

After successful payment at PayPal site, the buyer redirects to this page. Using the $_GET method you can get some basic information about the transaction, like transaction ID, gross payment amount, currency code, and payment status.
The complete payment and order details can be fetched from the database based on the respective transaction ID ($txn_id).

include 'dbConfig.php';

//Get payment information from PayPal 
$txn_id $_GET['tx'];
$payment_gross $_GET['amt'];
$currency_code $_GET['cc'];
$payment_status $_GET['st'];

//Check if payment data exists with the same TXN ID.
$paymentResult $db->query("SELECT * FROM payments WHERE txn_id = '".$txn_id."'");
$paymentResult->num_rows 0){
//payment information
$paymentRow $paymentResult->fetch_assoc();
$payment_id $paymentRow['payment_id'];
//order items details
$orderItemResult $db->query("SELECT, i.quantity, i.gross_amount FROM order_items as i LEFT JOIN products as p ON = i.item_number WHERE payment_id = '".$payment_id."'");
?> <h1>Your payment has been successful.</h1> <h2>Payment ID: <?php echo $payment_id?></h2> <h2>Payment Gross: <?php echo '$'.$paymentRow['payment_gross'].' '.$paymentRow['currency_code']; ?></h2>     <?php if($orderItemResult->num_rows 0){ ?> <h3>Order Items</h3> <table style="width:50%"> <tr> <th>#</th> <th>Product Name</th> <th>Quantity</th> <th>Gross Amount</th> </tr>     <?php $i=0; while($item $orderItemResult->fetch_assoc()){ $i++; ?> <tr> <td align="center"><?php echo $i?></td> <td align="center"><?php echo $item['name']; ?></td> <td align="center"><?php echo $item['quantity']; ?></td> <td align="center"><?php echo '$'.$item['gross_amount'].' '.$paymentRow['currency_code']; ?></td> </tr>     <?php ?> </table>     <?php ?>    
<?php }else{ ?> <h1>Your payment has been successful.</h1> <h2>TXN ID: <?php echo $txn_id?></h2> <h2>Payment Gross: <?php echo '$'.$payment_gross.' '.$currency_code?></h2> <?php } }else{ ?> <h1>Your payment has failed.</h1> <?php ?> <a href="products.php">Back to products</a>

Payment Cancel (cancel.php)

If the buyer wishes to cancel payment at the PayPal payment page, this page will show to the buyer.

<h1>Your PayPal transaction has been canceled.</h1>
<a href="products.php">Back to products</a>

Configure PayPal Auto Return and Payment Data Transfer

Make sure you had been configured Auto Return for Website Payments on your PayPal business account. Otherwise, the transaction information will not be sent to the success.php file. To enable Auto Return, Payment Data Transfer and set Return URL on your PayPal account, follow this guide – How to Configure PayPal Auto Return and Payment Data Transfer

Make PayPal Payment Gateway Live

When you satisfied with your integrated PayPal payment gateway for multiple items checkout, you need to do two small changes to make PayPal payment gateway live for accepting real payment.

Open the products.php file, change the $paypalURL and $paypalID value with live PayPal URL and business email.

$paypalURL '';
$paypalID 'InsertPayPalBusinessEmail';

Open the ipn.php file and change the $paypalURL value with live PayPal URL.

$paypalURL "";

Related Articles

Comments 0