Hack 86 Synchronizing PDT and IPN

figs/expert.gif figs/hack86.gif

Ensure that your product is delivered, even when PDT fails and the return page never shows, by introducing redundancy with IPN.

PayPal's PDT system [Hack #85] automatically redirects your customers back to your web page after they pay and sends the transaction information along with them. While this is an effective way to deliver products and services to your customers without forcing them to wait for IPN to contact your server, it's certainly not infallible. If you care about record keeping, you'll want to use IPN to record payment details into a database [Hack #82] so that you don't miss any payments.

This hack shows how to coordinate PDT with IPN to ensure that every transaction is processed by your server. The potential problem here is that when using PDT, or even the return variable feature, your customer can be redirected back to your web site before the IPN system has finished processing. You can address this issue by checking your local database to see whether or not the transaction details have been inserted yet; this refreshes the return page until the order has been processed and the IPN data has been received.

The reason you still need to use the IPN system is that the PDT is intended to be used only for a one-time query when the transaction takes place. If that query fails, the data for that transaction is lost forever. The IPN system has a high level of redundancy; it continues to call your IPN processing script for up to four days until it processes successfully.

7.26.1 The Code

The following ASP code simply reads the transaction data passed from PDT and then checks your local database to see if the IPN has finished processing the transaction. If not, it repeatedly refreshes the page (every five seconds) until it finds the corresponding transaction in the database. Use this as your PDT return page:


1. Response.AddHeader "Pragma","no-cache"

Response.Expires = 0

Response.buffer = true


2.  'Create transaction id variable

Dim txn_id

txn_id = Request("txn_id")

3.  'Check if IPN has been processed with database query and recordset

Dim rsOrderCheck

Set rsOrderCheck = Server.CreateObject("ADODB.Recordset")

rsOrderCheck.ActiveConnection = MM_connPayloadz_STRING

rsOrderCheck.Source = "SELECT tblOrderDetails.* FROM tblOrderDetails 

                WHERE tblOrderDetails.txn_id = '" & txn_id & "'"

rsOrderCheck.Open( )

4.  'Count how many times you refresh the browser

Dim vRCount

If Request("rcount") = "" Then 

        vRCount = 1


        vRCount = cInt(Request("rcount")) + 1

End If




<% If rsOrderCheck.EOF And rsOrderCheck.BOF Then 'ipn not processed yet %>

5.  <meta http-equiv="refresh" content="5;URL=



<% End If %>



<% If rsOrderCheck.EOF And rsOrderCheck.BOF Then 'ipn not processed yet %>

6.  Please wait while we locate your order.

This may take up to 30 seconds.

<% Else 'ipn has been processed %>

7.  IPN has been processed, insert content here.

<% End If %>



Line 1 tells the browser and server not to cache the page content, but rather to expire it immediately; this makes sure that new content appears when it is available. Then, line 2 initializes the transaction ID, and line 3 checks it against the database. Line 5 contains the meta refresh tag, which refreshes the page automatically if the recordset is empty (e.g., if IPN has not processed the order yet).

Place your own messages on lines 6 and 7 to inform the customer that the order is still being processed and that the order is ready, respectively.

This example illustrates synchronizing the PDT and IPN system, but you can also use the same technique presented here for your return page if you are not using the PDT system. For information on using the return page for order processing, see [Hack #85] .

7.26.2 Hacking the Hack

Normally, the IPN system contacts your server and completes the process in a matter of seconds after the customer pays. However, there are times when the IPN system can take longer (up to several minutes or even hours). This can be caused by load on the PayPal system, on your site, or any number of other possibilities. In the event of such a delay, the repeated refreshing of the page is likely to induce seizure in your customer or, at the very least, try his patience.

To address this issue, you might want to limit the number of times the browser is refreshed and display a message to the customer if that limit is reached (something to the effect that his order is still being processed and he should contact you or get a cup of coffee or something). Simply add the following snippet of code before the opening <html> tag:


'Redirect customer to order search timeout page

If vRCount => 5 Then


End If


This code simply checks the number of times the browser has been refreshed (vRCount, set in the original code) and interrupts the process after five unsuccessful tries (this means that at least 30 seconds have passed since the customer was first sent to your PDT page).