Handling Paypal Instant Payment Notification (IPN)

 

When you reach the payment detail page on paypal site and click the "Pay" button paypal will send a POST message to our server. Our script then send a confirmation back to paypal to verify this POST.

Here's that flow diagram again.

Paypal Checkout Process

Paypal Configuration File

The script that process the notification is located in include/paypal/ipn.php. But before talking about that file let's see the paypal configuration first.

Source code : paypal.inc.php

<?php

$paypal = array();

$paypal['business'] = "armanpi@phpwebcommerce.com";
$paypal['site_url'] = "http://www.phpwebcommerce.com/plaincart/";
$paypal['image_url'] = "";
$paypal['success_url'] = "success.php";
$paypal['cancel_url'] = "error.php";
$paypal['notify_url'] = "include/paypal/ipn.php";
$paypal['return_method'] = "2"; //1=GET 2=POST
$paypal['currency_code'] = "USD";
$paypal['lc'] = "US";


//$paypal['url'] = "https://www.paypal.com/cgi-bin/webscr";
$paypal['url'] = "https://www.sandbox.paypal.com/cgi-bin/webscr";
$paypal['post_method'] = "fso"; //fso=fsockopen();
$paypal['curl_location'] = "/usr/local/bin/curl";

 

// ... other "not so important" settings down here

?>

Here is the description for each configuration :

  1. $paypal['business']
    The email address that shown as the recipient when you pay

  2. $paypal['site_url']
    The store's main url. It is NOT ALWAYS the same as the site's homepage url

  3. $paypal['image_url']
    I'm not using any images to display on paypal site during the checkout process so i just left this blank

  4. $paypal['success_url']
    When paypal can verify the customer's credit card and everything gone smoothly the customer will be sent back to this url

  5. $paypal['cancel_url']
    And if something went wrong the customer are taken to this one

  6. $paypal['notify_url']
    This is the main script that check the verification message sent by paypal. It also update the database if the payment is successful

  7. $paypal['return_method']
    It sets the http method used by paypal to send the verification message

  8. $paypal['currency_code']
    What currency will the customer be paying. Other currencies supported are GBP,JPY,CAD, and EUR

  9. $paypal['lc']
    The language ( locale )

  10. $paypal['url']
    We send all payment information to this url. For testing we use the sandbox url : https://www.sandbox.paypal.com/cgi-bin/webscr
    But when the store goes live we'll use the real paypal url : https://www.paypal.com/cgi-bin/webscr

  11. $paypal['post_method']
    The function fsockPost($url,$data) can use several method to send transaction data. They are fso ( fsockopen() ), curl ( curl command line), and libCurl ( php compiled with libCurl support ). We're using fso because a hosting company may not provide PHP with curl support

  12. $paypal['curl_location']
    If you're using curl as the post method you must supply the path to the curl command on your server

Submitting The Payment Information

From the second step on the flowchart above we post some form values to paypal server so they can process the payment. Below you can see the variables sent from payment.php and their description

  1. business
    The merchant's email address. The payment will be sent to the paypal account identified by this email address. The value for this variable is taken from the configuration file ( $paypal['business'] )

  2. amount
    The amount of payment that the customer must pay.

  3. invoice
    The order id. We need this so we can know which order is being paid

  4. item_name
    Since the customer can buy multiple items i just hard code this one to "Plaincart purchase".

  5. return
    The url where you want to send the customer to after the payment is complete ( $paypal['success_url'] )

  6. cancel_return
    When the payment fails the customer is redirected here ( $paypal['cancel_url'] )

  7. notify_url
    The url of the script that checks the IPN notification from paypal and send back a confirmation to paypal ( $paypal['notify_url'] )

  8. rm
    The return method. The available values are 1 ( GET ) and 2 ( POST ). Since we use POST in this example the value of rm is 2.

  9. currency_code
    In what currency do you want to be paid in ( $paypal['currency_code'] ) .

  10. lc
    The language ( $paypal['lc'] )

  11. cmd
    The value is _xclick which is hardcode. Paypal provides several kinds of payment processing services so we need to tell them what kind of service we're using.

  12. no_shipping
    Since we already ask the shipping address during checkout. We don't need to ask it again on the paypal site. So we set this value to 1. Use 0 ( zero ) if you want paypal to ask the shipping address instead.

 

Processing The Payment

Here is the code for the IPN script :

Source code : include/paypal/ipn.php

<?php

if (strpos($_SERVER['REMOTE_ADDR'], '66.135.197.') === false) {
   exit;
}

require_once './paypal.inc.php';

// repost the variables we get to paypal site
// for validation purpose
$result = fsockPost($paypal['url'], $_POST);

//check the ipn result received back from paypal
if (eregi("VERIFIED", $result)) {

   require_once '../../library/config.php';

   // check that the invoice has not been previously processed
   $sql = "SELECT od_status
               FROM tbl_order
               WHERE od_id = {$_POST['invoice']}";

   $result = dbQuery($sql);

   // if no invoice with such number is found, exit
   if (dbNumRows($result) == 0) {
      exit;
   } else {

      $row = dbFetchAssoc($result);

      // process this order only if the status is still 'New'
      if ($row['od_status'] !== 'New') {
         exit;
      } else {

         // check that the buyer sent the right amount of money
         $sql = "SELECT SUM(pd_price * od_qty) AS subtotal
         FROM tbl_order_item oi, tbl_product p
         WHERE oi.od_id = {$_POST['invoice']} AND oi.pd_id = p.pd_id
         GROUP by oi.od_id";
         $result = dbQuery($sql);
         $row = dbFetchAssoc($result);

         $subTotal = $row['subtotal'];
         $total = $subTotal + $shopConfig['shippingCost'];

   
     if ($_POST['payment_gross'] != $total) {
            exit;
         } else {

            $invoice = $_POST['invoice'];
            $memo = $_POST['memo'];
            if (!get_magic_quotes_gpc()) {
               $memo = addslashes($memo);
            }


            $sql = "UPDATE tbl_order
            SET od_status = 'Paid', od_memo = '$memo', od_last_update = NOW()
            WHERE od_id = $invoice";
            $result = dbQuery($sql);
         }
      }
   }

} else {
   exit;
}
?>

Right at the top of the script we check if the ip address of the page requester. Since this page is meant only to be accessed by paypal server we disallow any connection that didn't come from paypal. Paypal server's IP address begin with 66.135.197 so if we don't see that in the remote address we just assume someone trying to mess with our script and exit immediately.

If the request does come from paypal we send a reply POST to let Paypal know that we have receive their message. Upon receiving our reply Paypal send another reply notifying the payment status whether it's verified or not.

If we found the word VERIFIED in the reply that means payment has been made and we move on updating the status for the order

Here is the series of checking that the script perform :

  1. Check the database to see if the invoice id really exist
  2. If it does exist check the order status is still 'New' to prevent double action
  3. If it's a new order check the amount of money sent and make sure the currency is correct.
  4. When everything is okay we can update the order status to "Paid", add the buyer's memo and modify the update time.

That's it. Once the customer made her payment you can check the order on the admin page. When you click on the "Order" menu on the admin page you can see all paid orders. From there it's up to you as the store owner to decide what to do with those orders.

 

Creating Your Paypal Account

If you want to test the shopping cart script on your own server you should create your own developer account. Here are the steps to setup a developer account with paypal :

  1. Go to https://developer.paypal.com ,click on on "Sign Up Now" and complete the registration
  2. Paypal will send you a verification email. Click the link in the email to verify your email address
  3. Login to PayPal Developer Central
  4. Create a sandbox account by clicking on the "Sandbox" tab
  5. Click on "Create Account". Anew window will popup. On the popup screen choose "Personal Account", select a country from the list then hit "Continue". This is just for testing so you can enter false email and use false data to fill in the form. Don't forget to enter the characters in the security image (it's case insensitive)
  6. On the next screen just hit the
  7. Complete the 'extra ...' stuff
  8. Check your paypal inbox
  9. Open the welcome email and click the verification link
  10. Open the 'extra ...' email and click on the link then enter the number


You will still need to create a "normal" Paypal account not only the developer account before testing. If not all payment status will be "Pending" instead of "Completed". If you don't already have it yet here are the steps to create and configure your paypal account :

  1. Create a business account with paypal ( the personal account is not enough ) and add a credit card so your account is verified. If you don't add a credit card then IPN will always say that the payment status is "Pending"
  2. Login
  3. Go to My Account > Profile > Instant Payment Notification Preferences
  4. Click on the "Edit" button
  5. Check the checkbox and enter the url where we want to receive the IPN notifications ( in our case it's http://www.phpwebcommerce.com/plaincart/include/paypal/ipn.php) then hit "Save"

Since our script already pass the hidden input called notify_url, which is the url of the script that process IPN notifications, this step is actually not required anymore. I just put this for the sake of completeness.


I did try to make checkout process as simple as possible but somehow i feel it gets quite complex now. If you found something weird / not clear please contact me. Howevert if you're question is about paypal it would be a lot better to ask the questions in the paypal forum especially the IPN section. This forum is packed with paypal experts.

 

 

 

 

Online Shop - Using Paypal PHP MySQL Shopping Cart Tutorial : Online Shop - Handling Paypal IPN Source Code
Google
 
Web www.phpwebcommerce.com
 

At long last i'm finally able to update this site. Now the shopping cart can handle payment through paypal. As always you have any critiques, questions, comments or problems about this tutorial please tell me. Click here to send your feedback. And if you like this tutorial please link to this site. It will really help a lot :-)

 

Get custom programming done at ScriptLance.com!

 



PHP MySQL Shopping Cart Tutorial
Copyright © 2005 - 2008 www.phpwebcommerce.com