PayPal Payment Gateway Integration using PHP and MYSQL

PayPal Payment Gateway Integration using PHP and MYSQL

PayPal is the most popular web-based payment service, so being able to integrate your website with PayPal's Instant Payment Notification Service (IPN) is necessary if payments are to be processed through your website.

There are 3 main parts to the PayPal IPN system:

  • A webpage that initiates a request to PayPal to make a payment.
  • PayPal calls a PHP tab on your webserver to inform you that the payment has been made.
  • A website that acknowledges the above payment and proceeds to your web application's next step, such as a ' Thank You ' tab.

Customers can access points 1 and 3 on your website. Point 2 can only be seen on PayPal. The diagram below shows how your client, PayPal and your website interact.

The following steps break down each part of the process into simple chunks to follow, assuming you have knowledge of both PHP and MySQL.

  • If you don't get the correct response from Paypal make sure you use your Paypal Sandbox account with the main test account (Verified Business Account).
  • Please make sure that you check the Paypal IPN Script on an online webserver (Not MAMP, Xampp, etc.), as Paypal wants a ' return url, ' ' cancel url ' and ' notify url ' that can be accessed.


If you don't have PayPal account the create new one in order to use IPN and your account must be business type.

Once you have a PayPal account registered your account must be set up correctly to use IPN. From your PayPal account, click 'edit profile' and review the settings below.

  • Under ' My Sales Preferences ' > > 'Getting paid and managing risk' > > ' Preferences for instant payment updates '
    • Set the IPN value to 'On'
    • Set the IPN URL to the PHP page with the IPN code provided in steps 3 & 4 of this tutorial. (http:/
  • Under 'My Selling Preferences' >> 'Getting paid and managing risk' >> 'Block payments'
    • Block app payments which are paid with eCheque. (This is because the compensation will not be immediate)
  • Under 'account information' >> 'email'
    • Note down your email address. Users will see this email so make it a professional one. Users may be concerned about sending money with the domain ' ' or ' ' etc. to an e-mail address.


Your website now needs to send all the correct values to PayPal for processing of the payment.

The following example of code shows a basic type we'll use to submit the values:

<!DOCTYPE html>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Paypal Integration Test</title>

    <form class="paypal" action="payments.php" method="post" id="paypal_form">
        <input type="hidden" name="cmd" value="_xclick" />
        <input type="hidden" name="no_note" value="1" />
        <input type="hidden" name="lc" value="UK" />
        <input type="hidden" name="bn" value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest" />
        <input type="hidden" name="first_name" value="Customer's First Name" />
        <input type="hidden" name="last_name" value="Customer's Last Name" />
        <input type="hidden" name="payer_email" value="" />
        <input type="hidden" name="item_number" value="123456" / >
        <input type="submit" name="submit" value="Submit Payment"/>


During the next stage, the business name, price, submit form, notify URL and other sensible values will be sent.

You will find a complete list of the values to submit on the PayPal website under the heading "A Sample IPN Message and Response."


The payment.php page will be used to manage PayPal's outgoing request and also to handle the incoming response once the payment is processed.

We need to first build up the parameters to make a payment request and transfer these to PayPal via the query string.

We need to pass the values below:

  • business - Your PayPal account Email Address
  • item_name - Name of item to be purchased
  • amount - Price of the item
  • return - The address to return to when the payment is successful
  • cancel_return - The address to be referred to after payment cancelled
  • notify_url - Payments.php account adress on your website
  • custom - Any other data to be sent and returned on request by PayPal
// We want to allow sandbox mode for test payments. If you would like to bring it live
// Payments must be changed to 'false' through this setting
$enableSandbox = true;

// Database setup. Adjust those for configuration of your database.
$dbConfig = [
    'host' => 'localhost',
    'username' => 'user',
    'password' => 'secret',
    'name' => 'example_database'

// Settings of PayPal. Add these information to your account and to the appropriate URLs for your site.
$paypalConfig = [
    'email' => '',
    'return_url' => '',
    'cancel_url' => '',
    'notify_url' => ''

$paypalUrl = $enableSandbox ? '' : '';

// Product being purchased.
$itemName = 'Test Item';
$itemAmount = 5.00;

// Include Functions
require 'functions.php';

// Check if paypal request or response
if (!isset($_POST["txn_id"]) && !isset($_POST["txn_type"])) {

    // Grab the post data so that we can set up the query string for PayPal.
    // Ideally we'd use a whitelist here to check nothing is being injected into
    // our post data.
    $data = [];
    foreach ($_POST as $key => $value) {
        $data[$key] = stripslashes($value);

    // Set the PayPal account.
    $data['business'] = $paypalConfig['email'];

    // Set the PayPal return addresses.
    $data['return'] = stripslashes($paypalConfig['return_url']);
    $data['cancel_return'] = stripslashes($paypalConfig['cancel_url']);
    $data['notify_url'] = stripslashes($paypalConfig['notify_url']);

    // Set the details about the product being purchased, including the amount
    // and currency so that these aren't overridden by the form data.
    $data['item_name'] = $itemName;
    $data['amount'] = $itemAmount;
    $data['currency_code'] = 'GBP';

    // Add any custom fields for the query string.
    //$data['custom'] = USERID;

    // Build the query string from the data.
    $queryString = http_build_query($data);

    // Redirect to paypal IPN
    header('location:' . $paypalUrl . '?' . $queryString);

} else {
    // Handle the PayPal response.

We allocate the post data to an array to create the question string, which we then move any additional values to which we do not want to be altered by the post data. This way we can ensure a consumer is unable to exploit the sum being paid or any other sensitive information. We then use http build query to convert the array to a query string, and transfer it through the header to PayPal.


Now we want to manage PayPal's response, this is the callback that PayPal makes to our previously configured notification URL. We reassign a local variable to the post response and then verify that the transaction is legitimate and check that we haven't already processed this transaction until adding the payment to our database.

To do all of this we would like to apply the following code to our other payments.php script message.

// Handle the PayPal response.

// Create a connection to the database.
$db = new mysqli($dbConfig['host'], $dbConfig['username'], $dbConfig['password'], $dbConfig['name']);

// Assign posted variables to local data array.
$data = [
    'item_name' => $_POST['item_name'],
    'item_number' => $_POST['item_number'],
    'payment_status' => $_POST['payment_status'],
    'payment_amount' => $_POST['mc_gross'],
    'payment_currency' => $_POST['mc_currency'],
    'txn_id' => $_POST['txn_id'],
    'receiver_email' => $_POST['receiver_email'],
    'payer_email' => $_POST['payer_email'],
    'custom' => $_POST['custom'],

// We need to verify the transaction comes from PayPal and check we've not
// already processed the transaction before adding the payment to our
// database.
if (verifyTransaction($_POST) && checkTxnid($data['txn_id'])) {
    if (addPayment($data) !== false) {
        // Payment successfully added.

To check the response's validity we call the VerifyTransaction feature. This will take the post data received from PayPal and confirm it by making a curl request to PayPal with the data received from the transaction. If we get the VERIFIED response back then we know that everything is OK and can go ahead adding the payment to our database.

It looks like the verify Transaction function (you can find it on functions.php file).

function verifyTransaction($data) {
    global $paypalUrl;

    $req = 'cmd=_notify-validate';
    foreach ($data as $key => $value) {
        $value = urlencode(stripslashes($value));
        $value = preg_replace('/(.*[^%^0^D])(%0A)(.*)/i', '${1}%0D%0A${3}', $value); // IPN fix
        $req .= "&$key=$value";

    $ch = curl_init($paypalUrl);
    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
    curl_setopt($ch, CURLOPT_SSLVERSION, 6);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
    $res = curl_exec($ch);

    if (!$res) {
        $errno = curl_errno($ch);
        $errstr = curl_error($ch);
        throw new Exception("cURL error: [$errno] $errstr");

    $info = curl_getinfo($ch);

    // Check the http response
    $httpCode = $info['http_code'];
    if ($httpCode != 200) {
        throw new Exception("PayPal responded with http code $httpCode");


    return $res === 'VERIFIED';

Once the transaction has been checked and it is a good idea to check that we haven't already processed it before we add it to our database. That is what our call is going to do to checkTxnid. It actually tests that PayPal's txn I d value already doesn't exist in our database.

function checkTxnid($txnid) {
    global $db;

    $txnid = $db->real_escape_string($txnid);
    $results = $db->query('SELECT * FROM `payments` WHERE txnid = '' . $txnid . ''');

    return ! $results->num_rows;

This is also a good opportunity for you to put in place some additional checks before accepting the payment on your platform. You might want to check the amount paid tallies, for example, with the sum you charged.


With the PayPal response checked and any additional checks that we want to do at our end, it's time to add the payment to our database.

A payment table must be created to store details of the payment in our database. The following MySQL will create the table of payments used in the example code.

    `id` int(6) NOT NULL AUTO_INCREMENT,
    `txnid` varchar(20) NOT NULL,
    `payment_amount` decimal(7,2) NOT NULL,
    `payment_status` varchar(25) NOT NULL,
    `itemid` varchar(25) NOT NULL,
    `createdtime` datetime NOT NULL,
    PRIMARY KEY (`id`)

Then, we call addPayment in our code to insert a payment into the database. So looks this function:-

function addPayment($data) {
    global $db;

    if (is_array($data)) {
        $stmt = $db->prepare('INSERT INTO `payments` (txnid, payment_amount, payment_status, itemid, createdtime) VALUES(?, ?, ?, ?, ?)');
            date('Y-m-d H:i:s')

        return $db->insert_id;

    return false;


PayPal Sandbox provides all of PayPal's features, but uses "Fake Accounts" within the sandbox built by the developer. You can create fake buyer and fake seller profiles, then use your creation platform to check your PayPal integration. Sandbox accounts can be created on the PayPal Developer website

We use the URL when experimenting with the sandbox. We have to use to make payments live. Our example code is configured to use the sandbox but by changing $enableSandbox to false you can turn it to live payments, this will change the URLs used to communicate with PayPal.

Once the payment process is ready for real customers to use you will need to disable the application sandbox mode.

That's it; you're ready to start making online payments through your website.

Leave comment

Comments (1)


What are you searching for....?


Subscribe to us on youtube for updates of our videos first on youtube.


To receive updates on the latest news, tutorials and special offers, subscribe to our email newsletter today!


We use cookies to ensure you have the best browsing experience on our website. By using our site, you acknowledge that you have read and understood our Privacy Policy That's Fine