How to Set Up PayPal Integration with PHP & MySQL

There are 3 main parts to the PayPal IPN system.
  1. A webpage that initiates a request to PayPal to make a payment.
  2. A PHP page on your webserver that PayPal calls to notify you that payment has been made.
  3. A webpage that confirms the above payment and continues on to the next phase of your web application, such as a ‘Thank You’ page.

Step 1 – Setup PayPal Account

Sign up for a PayPal account if you don’t already have one. Select an appropriate account type, either Personal or Business.
Once you have a registered PayPal account your account must be setup correctly to use IPN.
Select ‘edit profile’ from your PayPal account and check the following settings.
  • Under ‘Selling Preferences’ >> ‘Instant Payment Notification Preferences’
    • Set the IPN value to ‘On’
    • Set the IPN URL to the PHP page containing the IPN code shown in steps 3 & 4 of this tutorial. (http://www.example.com/payment.php)
  • Under ‘Selling Preferences’ >> ‘payment receiving preferences’
    • Block payments from users who pay with echeck. (This is because these will not be instant payments)
  • Under ‘account information’ >> ‘email’
    • Note down your primary email address. This email will be visible to users so make it a professional one. User’s may feel apprehensive about sending money to an e-mail address with the domain ‘hotmail.com’ or ‘Yahoo.com’ etc…


    Step 2 – Simple HTML Form

    <form action="payments.php" class="paypal" id="paypal_form" method="post"><input name="cmd" value="_xclick" type="hidden">
        <input name="no_note" value="1" type="hidden">
        <input name="lc" value="UK" type="hidden">
        <input name="currency_code" value="USD" type="hidden">
        <input name="bn" value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest" type="hidden">
        <input name="first_name" value="Your First Name" type="hidden">
        <input name="last_name" value="Your Last Name" type="hidden">
        <input name="payer_email" value="customer@example.com" type="hidden">
        <input name="item_number" value="ep4590" type="hidden">
        <input value="Buy Now" type="submit">
    </form>


  Note:A full list of the values to send can be found at the PayPal website under the title “A Sample IPN Message and Response”


Step 3 – Payments.php (The Request)

The payment.php page will be used to handle the outgoing request to PayPal and also to handle the incoming response after the payment has been processed.

// Database variables
$host = "localhost"; //database location
$user = ""; //database username
$pass = ""; //database password
$db_name = ""; //database name
// PayPal settings
$paypal_email = 'paypal@host.com';
$cancel_url = 'http://yourhost/payment-cancelled.htm';
$notify_url = 'http://yourhost/paypal/payments.php';
$item_name = 'Test Item';
$item_amount = 5.00;
// Include Functions
include("functions.php");
//Database Connection
$link = mysql_connect($host, $user, $pass);
mysql_select_db($db_name);
// Check if paypal request or response
if (!isset($_POST["txn_id"]) && !isset($_POST["txn_type"])){
    // Firstly Append paypal account to querystring
    $querystring .= "?business=".urlencode($paypal_email)."&";
    // Append amount& currency (£) to quersytring so it cannot be edited in html
    //The item name and amount can be brought in dynamically by querying the $_POST['item_number'] variable.
    $querystring .= "item_name=".urlencode($item_name)."&";
    $querystring .= "amount=".urlencode($item_amount)."&";
    //loop for posted values and append to querystring
    foreach($_POST as $key => $value){
        $value = urlencode(stripslashes($value));
        $querystring .= "$key=$value&";
    }
    // Append paypal return addresses
    $querystring .= "return=".urlencode(stripslashes($return_url))."&";
    $querystring .= "cancel_return=".urlencode(stripslashes($cancel_url))."&";
    $querystring .= "notify_url=".urlencode($notify_url);
    // Append querystring with custom field
    //$querystring .= "&custom=".USERID;
    // Redirect to paypal IPN
    header('location:https://www.sandbox.paypal.com/cgi-bin/webscr'.$querystring);
    exit();
}else{
    // Response from PayPal
// read the post from PayPal system and add 'cmd'
    $req = 'cmd=_notify-validate';
    foreach ($_POST as $key => $value) {
        $value = urlencode(stripslashes($value));
        $value = preg_replace('/(.*[^%^0^D])(%0A)(.*)/i','${1}%0D%0A${3}',$value);// IPN fix
        $req .= "&$key=$value";
    }
    // assign posted variables to local variables
    $data['item_name']          = $_POST['item_name'];
    $data['item_number']        = $_POST['item_number'];
    $data['payment_status']     = $_POST['payment_status'];
    $data['payment_amount']     = $_POST['mc_gross'];
    $data['payment_currency']   = $_POST['mc_currency'];
    $data['txn_id']             = $_POST['txn_id'];
    $data['receiver_email']     = $_POST['receiver_email'];
    $data['payer_email']        = $_POST['payer_email'];
    $data['custom']             = $_POST['custom'];
    // post back to PayPal system to validate
    $header = "POST /cgi-bin/webscr HTTP/1.0\r\n";
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
    $fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
    if (!$fp) {
        // HTTP ERROR
    } else {
                mail('adiyya@gmail.com', '0', '0');
        fputs ($fp, $header . $req);
        while (!feof($fp)) {
            $res = fgets ($fp, 1024);
            if (strcmp ($res, "VERIFIED") == 0) {
                // Validate payment (Check unique txnid & correct price)
                $valid_txnid = check_txnid($data['txn_id']);
                $valid_price = check_price($data['payment_amount'], $data['item_number']);
                // PAYMENT VALIDATED & VERIFIED!
                if($valid_txnid && $valid_price){
                    $orderid = updatePayments($data);
                    if($orderid){
                        // Payment has been made & successfully inserted into the Database
                    }else{
                        // Error inserting into DB
                        // E-mail admin or alert user
                    }
                }else{
                    // Payment made but data has been changed
                    // E-mail admin or alert user
                }
            }else if (strcmp ($res, "INVALID") == 0) {
                // PAYMENT INVALID & INVESTIGATE MANUALY!
                // E-mail admin or alert user
            }
        }
    fclose ($fp);
    }
}

 

Step 5 – Functions.php


 The payments.php page calls upon a number of functions used to validate the returned data and store the response in the database.


// functions.php
function check_txnid($tnxid){
    global $link;
    return true;
    $valid_txnid = true;
    //get result set
    $sql = mysql_query("SELECT * FROM `payments` WHERE txnid = '$tnxid'", $link);
    if($row = mysql_fetch_array($sql)) {
        $valid_txnid = false;
    }
    return $valid_txnid;
}
function check_price($price, $id){
    $valid_price = false;
    /*
    you could use the below to check whether the correct price has been paid for the product
    if so uncomment the below code
    $sql = mysql_query("SELECT amount FROM `products` WHERE id = '$id'");
    if (mysql_numrows($sql) != 0) {
        while ($row = mysql_fetch_array($sql)) {
            $num = (float)$row['amount'];
            if($num == $price){
                $valid_price = true;
            }
        }
    }
    return $valid_price;
    */
    return true;
}
function updatePayments($data){
    global $link;
    if(is_array($data)){
        $sql = mysql_query("INSERT INTO `payments` (txnid, payment_amount, payment_status, itemid, createdtime) VALUES (
                '".$data['txn_id']."' ,
                '".$data['payment_amount']."' ,
                '".$data['payment_status']."' ,
                '".$data['item_number']."' ,
                '".date("Y-m-d H:i:s")."'
                )", $link);
    return mysql_insert_id($link);
    }
}
CREATE TABLE IF NOT EXISTS `payments` (
  `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`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

 

Download Source Code 

Click here to download