Skip to main content

REGISTER WITH PAYPAL TUTORIAL (2/3): A Real Register with PayPal Project

By Sam Deering



Free JavaScript Book!

Write powerful, clean and maintainable JavaScript.

RRP $11.95

Explain how PayPal works (IPN and PDT process). Chapter One Chapter Three

Chapter Two

This chapter introduces a real project: “registration with payment”, from start to end, for better explaining PayPal account setup and integration with register form and database.

Project Scenario

  1. First, we have a registration form.
  2. After completing the form correctly (all validation passed), user clicks on the ‘Register’ button.
  3. Then redirect to PayPal, user pay for the registration fee.
  4. After paid, PayPal will redirect to result page, and 10 seconds auto redirect back to our website, then PayPal PDT will process the payment record.
  5. But, user may close the browser, so we have to implement PayPal IPN for backup plan.

Database Structure

E-R Diagram:

  1. temp_register table: temporary store user account and user password, wait for payment. If paid, the tuple will be deleted, and move to users table.
  2. payment table: uid is a foreign key referencing to users, to connect user information and payment information.
  3. users table: store users information, token is verification token in confirmation email. If user verified their user account, verified will be set as 1.

Database Schema:

`timestamp` bigint(20) DEFAULT NULL,
`paid` float DEFAULT NULL COMMENT 'user paid amount returned by paypal',
`bankFee` float DEFAULT NULL,
`currency` varchar(4) DEFAULT NULL,
`txnId` varchar(32) DEFAULT NULL COMMENT 'Transaction ID: specify single unique transaction from paypal. if this field is NOT NULL, means this payment has been process already. So if IPN returns to PHP, we can refuse to update our database.',
`status` varchar(16) DEFAULT NULL,
`uid` int(11) DEFAULT NULL COMMENT 'FK to users PK',
PRIMARY KEY (`payId`),
KEY `uid` (`uid`)
CREATE TABLE IF NOT EXISTS `temp_register` (
`fullName` varchar(255) DEFAULT NULL,
`uAcc` varchar(255) DEFAULT NULL,
`uPwd` varchar(32) DEFAULT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='prevent unpaid user take uAcc(UNIQUE) in our users table' AUTO_INCREMENT=1 ;
`fullName` varchar(255) DEFAULT NULL,
`uAcc` varchar(255) NOT NULL,
`uPwd` varchar(32) NOT NULL,
`token` varchar(32) DEFAULT NULL,
`verified` tinyint(1) NOT NULL DEFAULT '0',
`priviledge` enum('delegate','admin','developer') NOT NULL DEFAULT 'delegate',
ALTER TABLE `payment`
ADD CONSTRAINT `payment_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `users` (`uid`);

User Interface

Project Workflow

  1. Fill the form, and all inputs are validated.
  2. Click Register button, redirect to PayPal.
  3. PayPal Sandbox ‘Pay Now’:
  4. Redirect PayPal result page.
  5. Wait for redirect (PDT works) show success/fail page, or close browser (IPN works).

Setup PayPal Sandbox

Before we start coding, we need to setup PayPal Sandbox account first.

Suppose you have registered a PayPal developer account, and have created one business user account and one buyer account in Sandbox.

Then select business account, and click on the ‘Enter Sandbox Test Site’ Button.

You can see the main panel pop-out page:

Then you can see all information and selling preference settings.

So let’s setup all the three options one by one in order.

1. Enable PDT and Settings

Setup your PDT handler function calling URL.

2. Enable IPN and Settings

Setup your IPN handler function calling URL.

2. Create a PayPal Button and PayPal Parameter Settings

After you saving your change, you can see the source code of your PayPal Button:

It is easy to find out that the button is actually a form, so we need to POST data using its inputs.
When we generate our ‘register’ button, the redirect URL, should contain ‘&cmd=_s-xclick’ and ‘&hosted_button_id=HA9DZBCKXKCL2’.
Now, PayPal Sandbox account has been setup. Then start to code your PDT and IPN handlers.

PDT Handler Function

Source Code:

* ====================
* called by PayPal, send tokens back
* get payment details and payment result
* @return $ret array contains result true/false, and user account or error message
private function _PDT()
// some indexes can not be missing:
$ruler = array(
'tx', // token from paypal
if(count(array_diff($ruler, array_keys($_GET))))
return array('result' => false, 'error' => 'Index missing ... ', 'index' => $_GET, 'missing' => array_diff($ruler, array_keys($_GET)));
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-synch';
// get token and prepare request url (send back to paypal)
$tx_token = $_GET['tx'];$auth_token = "_PJaHiwRfwMmWzW-9nuPuSguYxC-1d9KpxaasaNANtIvyOcmqY6jXNkRmxW";
// $auth_token = "OxDenzKmrWPyEXU0YzIg2zs-VAe7ufCADyjbfxF_RpREL4rLEslZrSa21R4";

$req .= "&tx=$tx_token&at=$auth_token";

// post back to PayPal system to validate

$header = "POST /cgi-bin/webscr HTTP/1.0rn";

$header .= "Host: www.sandbox.paypal.comrn";
// $header .= "Host: www.paypal.comrn";

$header .= "Content-Type: application/x-www-form-urlencodedrn";
$header .= "Content-Length: " . strlen($req) . "rnrn";

$fp = fsockopen ('ssl://', 443, $errno, $errstr, 30); // open socket
// $fp = fsockopen ('ssl://', 443, $errno, $errstr, 30); // open socket

if (!$fp)
return array('result' => false, 'error' => 'HTTP error ... ');
fputs ($fp, $header . $req);
// read the body data
$res = '';
$headerdone = false;
while (!feof($fp))
$line = fgets ($fp, 1024);
if (strcmp($line, "rn") == 0)
$headerdone = true; // read the header
else if ($headerdone)
$res .= $line; // header has been read. now read the contents

// parse the data
$lines = explode("n", $res);
$keyarray = array();
if (strcmp ($lines[0], "SUCCESS") == 0)
for ($i=1; $i_validatePaypal($keyarray);
// log for manual investigation
else if (strcmp ($lines[0], "FAIL") == 0)
// skipped
return array('result' => false, 'error' => 'Transaction failed ... ');
fclose ($fp);
return $ret;


Learn PHP for free!

Make the leap into server-side programming with a comprehensive cover of PHP & MySQL.

Normally RRP $11.95 Yours absolutely free

PayPal call PDTHandler() function, then this handler function process _PDT(). As you see, it receives parameters provided by PayPal, from the URL ($_GET). So we POST token and tx back to PayPal, via fsock ssl. Then PayPal will return payment record, and payment result (SUCCESS/FAIL). _PDT() passes those data to _validatePaypal() which saves data into database. Then, page redirect according to the return.

IPN Handler Function

Source Code:

* ====================
* called by PayPal, send POSTed payment data back (handshake)
* get payment result
* return: payment VERIFIED: array('result' => true/false, and other user details)
* payment INVALID: false // no further process (see handler in Register Module)
* TODO: return true if success, then send email to buyers
private function _IPN()
// get IPN data
$postData = $_POST;// read the post from PayPal system and add 'cmd'
$req = 'cmd=' . urlencode('_notify-validate');
foreach ($postData as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";

// CURL: copy from paypal sample code

$url= '';
// $url= '';

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/x-www-form-urlencoded", "Content-Length: " . strlen($req)));

curl_setopt($ch, CURLOPT_HEADER , array('Host:'));
// curl_setopt($ch, CURLOPT_HEADER , array('Host:'));

curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

$res = @curl_exec($ch);
$curl_err = curl_error($ch);

$keyarray = $postData;

if (strcmp (substr($res, '-8'), "VERIFIED") == 0)
// validate paypal information
return $this->_validatePaypal($keyarray);
elseif (strcmp (substr($res, '-7'), "INVALID") == 0)
// log for manual investigation
return false;
// return $ret; // Do not need to return, because IPN runs in background


PayPal call IPNHandler() function, then this handler function process _ IPN (). As you see, it receives data provided by PayPal, from the request ($_POST). So we POST payment details back to PayPal, via cURL, this is the handshake process. Then PayPal send back payment result (VERIFIED/INVALID). If it’s verified, _IPN() passes those data to _validatePaypal() which saves data into database.

In the zip file, it contains templates, javascript files, css, bootstrap, jquery, debug plugin and smarty plugin, and all core php source code.

Download Project (344KB)

Sam Deering has 15+ years of programming and website development experience. He was a website consultant at Console, ABC News, Flight Centre, Sapient Nitro, and the QLD Government and runs a tech blog with over 1 million views per month. Currently, Sam is the Founder of Crypto News, Australia.

New books out now!

Learn valuable skills with a practical introduction to Python programming!

Give yourself more options and write higher quality CSS with CSS Optimization Basics.