This tutorial will help you to integrate PayPal payment gateway using PHP with an example. I will walk you through a step by step process and make it easy for you do the integration.
You will learn about three things today,
PayPal provides different options to integrate the gateway like,
In this example, we will use “PayPal Payments Standard” method for integrating the payment gateway.
If you wish to process card payments refer the Stripe payment gateway integration using PHP articles.
Below screenshot shows the file structure of this PHP example code created for integrating Payment Gateway using PayPal Payments Standard method.
The landing page shows an entry point for proceeding with the PayPal payment transaction process. It will show a sample product tile containing PayPal payment fields followed by a Pay Now button.
The return.php and the cancel.php files are the acknowledgment pages to which the user will be redirected appropriately. The notify.php is the IPN listener connect database to save payment transaction responses and data.
DBController.php file contains the code to create a database connection objects and to handle queries on payment database updates.
In this HTML code, we can see the PayPal Payments Standard form fields with a custom Pay Now button. This example code targets the PayPal sandbox URL on the form action.
The PayPal payment form must contain the business email address, order information like item_number, name, amount, currency, and the callback and return page URLs.
By submitting this form, the payment parameters will be posted to the PayPal server. So, the user will be redirected to the PayPal Login and asked for payment confirmation.
<body>
<div id="payment-box">
<img src="images/camera.jpg" />
<h4 class="txt-title">A6900 MirrorLess Camera</h4>
<div class="txt-price">$289.61</div>
<form action="https://www.sandbox.paypal.com/cgi-bin/webscr"
method="post" target="_top">
<input type='hidden' name='business'
value='PayPal Business Email'> <input type='hidden'
name='item_name' value='Camera'> <input type='hidden'
name='item_number' value='CAM#N1'> <input type='hidden'
name='amount' value='10'> <input type='hidden'
name='no_shipping' value='1'> <input type='hidden'
name='currency_code' value='USD'> <input type='hidden'
name='notify_url'
value='http://sitename/paypal-payment-gateway-integration-in-php/notify.php'>
<input type='hidden' name='cancel_return'
value='http://sitename/paypal-payment-gateway-integration-in-php/cancel.php'>
<input type='hidden' name='return'
value='http://sitename/paypal-payment-gateway-integration-in-php/return.php'>
<input type="hidden" name="cmd" value="_xclick"> <input
type="submit" name="pay_now" id="pay_now"
Value="Pay Now">
</form>
</div>
</body>
PayPal provides notifications using different mechanisms. It will be useful for updating your backend processes, sending order notifications and similar transactional jobs. Following are the different types of notifications provided by PayPal.
Notifications should be used as part of the payment gateway integration process. Imagine you are running a website that sells digital goods online. At the end of the payment process, you are obliged to send the digital product via email.
You should not do this on the thank-you page. As there is no guarantee that this page will be displayed in the user’s browser. There can be network failures, users might close the browser and there are so many variables involved in this.
The dependable way of doing this is using PayPal notifications. You get a callback from PayPal to your backend server (asynchronously) and you can manage the backend process from there.
PayPal notifies the merchants about the events related to their transactions. This automatic callback can be used to perform administrative tasks and fulfill orders.
Notifications are done by PayPal on different types of events like, payments received, authorizations made, recurring payments, subscriptions, chargebacks, disputes, reversals, and refunds.
An integral part of the payment gateway integration process is the ability to receive PayPal notifications and process backend administrative processes.
Order fulfillment is an important step in shopping cart software. It should be done via the PayPal notification and never should be done as part of the thank you or order completion page.
The notify.php is created as the instant payment notification listener. This listener URL will be sent to PayPal via the form seen above. It can also be set in the PayPal REST API app settings. Paypal provides the IPN listener code samples for various languages.
This listener will be called asynchronously by PayPal to notify payment processing response. The payment response will be posted to this URL.
This code passes the API parameters to verify the post data via PHP cURL post request.
The below code verifies the payment status from the response returned by PayPal. If the payment is verified and completed then the result will be updated in a database table.
<?php
// CONFIG: Enable debug mode. This means we'll log requests into 'ipn.log' in the same directory.
// Especially useful if you encounter network errors or other intermittent problems with IPN (validation).
// Set this to 0 once you go live or don't require logging.
define("DEBUG", 1);
// Set to 0 once you're ready to go live
define("USE_SANDBOX", 1);
define("LOG_FILE", "ipn.log");
// Read POST data
// reading posted data directly from $_POST causes serialization
// issues with array data in POST. Reading raw POST data from input stream instead.
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode ('=', $keyval);
if (count($keyval) == 2)
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
if(function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = true;
}
foreach ($myPost as $key => $value) {
if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// Post IPN data back to PayPal to validate the IPN data is genuine
// Without this step anyone can fake IPN data
if(USE_SANDBOX == true) {
$paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr";
} else {
$paypal_url = "https://www.paypal.com/cgi-bin/webscr";
}
$ch = curl_init($paypal_url);
if ($ch == FALSE) {
return FALSE;
}
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_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
if(DEBUG == true) {
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
}
// CONFIG: Optional proxy configuration
//curl_setopt($ch, CURLOPT_PROXY, $proxy);
//curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
// Set TCP timeout to 30 seconds
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
// CONFIG: Please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path
// of the certificate as shown below. Ensure the file is readable by the webserver.
// This is mandatory for some environments.
//$cert = __DIR__ . "./cacert.pem";
//curl_setopt($ch, CURLOPT_CAINFO, $cert);
$res = curl_exec($ch);
if (curl_errno($ch) != 0) // cURL error
{
if(DEBUG == true) {
error_log(date('[Y-m-d H:i e] '). "Can't connect to PayPal to validate IPN message: " . curl_error($ch) . PHP_EOL, 3, LOG_FILE);
}
curl_close($ch);
exit;
} else {
// Log the entire HTTP response if debug is switched on.
if(DEBUG == true) {
error_log(date('[Y-m-d H:i e] '). "HTTP request of validation request:". curl_getinfo($ch, CURLINFO_HEADER_OUT) ." for IPN payload: $req" . PHP_EOL, 3, LOG_FILE);
error_log(date('[Y-m-d H:i e] '). "HTTP response of validation request: $res" . PHP_EOL, 3, LOG_FILE);
}
curl_close($ch);
}
// Inspect IPN validation result and act accordingly
// Split response headers and payload, a better way for strcmp
$tokens = explode("\r\n\r\n", trim($res));
$res = trim(end($tokens));
if (strcmp ($res, "VERIFIED") == 0) {
// assign posted variables to local variables
$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'];
include("DBController.php");
$db = new DBController();
// check whether the payment_status is Completed
$isPaymentCompleted = false;
if($payment_status == "Completed") {
$isPaymentCompleted = true;
}
// check that txn_id has not been previously processed
$isUniqueTxnId = false;
$param_type="s";
$param_value_array = array($txn_id);
$result = $db->runQuery("SELECT * FROM payment WHERE txn_id = ?",$param_type,$param_value_array);
if(empty($result)) {
$isUniqueTxnId = true;
}
// check that receiver_email is your PayPal email
// check that payment_amount/payment_currency are correct
if($isPaymentCompleted) {
$param_type = "sssdss";
$param_value_array = array($item_number, $item_name, $payment_status, $payment_amount, $payment_currency, $txn_id);
$payment_id = $db->insert("INSERT INTO payment(item_number, item_name, payment_status, payment_amount, payment_currency, txn_id) VALUES(?, ?, ?, ?, ?, ?)", $param_type, $param_value_array);
}
// process payment and mark item as paid.
if(DEBUG == true) {
error_log(date('[Y-m-d H:i e] '). "Verified IPN: $req ". PHP_EOL, 3, LOG_FILE);
}
} else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation
// Add business logic here which deals with invalid IPN messages
if(DEBUG == true) {
error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE);
}
}
?>
This file handles database-related functions using prepared statements with MySQLi. This is important, always remember to use Prepared Statements as it will safeguard you from SQL injections and a primary step towards your security of the application.
<?php
class DBController
{
private $host = "";
private $user = "";
private $password = "";
private $database = "";
private $conn;
function __construct()
{
$this->conn = $this->connectDB();
}
function connectDB()
{
$conn = mysqli_connect($this->host, $this->user, $this->password, $this->database);
return $conn;
}
function runQuery($query, $param_type, $param_value_array)
{
$sql = $this->conn->prepare($query);
$this->bindQueryParams($sql, $param_type, $param_value_array);
$sql->execute();
$result = $sql->get_result();
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
$resultset[] = $row;
}
}
if (! empty($resultset)) {
return $resultset;
}
}
function bindQueryParams($sql, $param_type, $param_value_array)
{
$param_value_reference[] = & $param_type;
for ($i = 0; $i < count($param_value_array); $i ++) {
$param_value_reference[] = & $param_value_array[$i];
}
call_user_func_array(array(
$sql,
'bind_param'
), $param_value_reference);
}
function insert($query, $param_type, $param_value_array)
{
$sql = $this->conn->prepare($query);
$this->bindQueryParams($sql, $param_type, $param_value_array);
$sql->execute();
}
}
?>
This section shows the payment database table structure in .sql format. This is provided with the downloadable source code with sql/payment.sql file. Import this file into your test environment to run this example.
--
-- Table structure for table `payment`
--
CREATE TABLE IF NOT EXISTS `payment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item_number` varchar(255) NOT NULL,
`item_name` varchar(255) NOT NULL,
`payment_status` varchar(255) NOT NULL,
`payment_amount` double(10,2) NOT NULL,
`payment_currency` varchar(255) NOT NULL,
`txn_id` varchar(255) NOT NULL,
`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
Test! Test! Test! It is important. We are processing payments and you cannot be casual about this implementation. Every bit of your PHP script should be tested thoroughly before going live.
PayPal provides an excellent toolset to perform the end-to-end testing of the payment gateway integration. It provides a sandbox environment using which you can simulate the complete payment process including the payments and fulfillments step.
Testing the IPN is critical as it takes care of the order fulfillment process. Go through the below steps to set up a PayPal Sandbox account and test your PHP code for payment gateway integration.
Once everything is working well with the entire payment transaction processing flow, then it will be time to go live with your PayPal payment gateway integration using PHP code. Change the sandbox mode to live mode and do the following.
It requires to do the following changes in the code.
<input type='hidden' name='business' value='PayPal Business Email'>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
define("USE_SANDBOX", 1);
The below screenshot shows the product title which includes PayPal payments standard form and a custom Pay Now button.
After a successful payment transaction, the user will be automatically redirected to the return URL as specified in the payment form. The return page will acknowledge the user as shown below.
The return URL is nothing but a thank you page or order completion page. This is the last step in the payment gateway integration process.
An important thing to know is that the order fulfillment steps should not be done sequentially in the return URL call. It should be done via the IPN callback or the other PayPal notifications.
This code is complicated and I don’t understand it! but it works. Thanks
Erik,
Welcome. Let me know which part is difficult for you to understand and I will try my best to help you.
how to use paypal with out paypal login
Hi Simi,
You need PayPal account, without that it is not possible to integrate PayPal payment gateway.
hello this demo working properly, thank you so much
Welcome, Desai.
The best article of Paypal gateway I’ve ever read, great job Vincy ;)
Hey, thank you Leonardo. These nice words keep me motivated. Thank you.
Thanks but notify.php is not working
The callback may not happen due to many issues. Right from basic Internet failure to sending wrong parameters. You need to debug. If you can post some stack trace, I can help you out.
Payment transactions are working, but data is not saving in DB. Could you please help me in this
Khaja, you need to check DB connection credentials and watchout for errors.
Nice tutorial..but can you write more articles on other payment gateways?
Thank you, John. So far, I have written on PayPal, Stripe, Authorize.net, Sage Pay and CCAvenue. Let me know which payment gateway you are looking for and I will write on it. Thanks.
can you make a payment gateway on jazzcash and easypessa.
Sure Muhammad, I will try to write on it soon.
Hi Erik,
Thank you so much for sharing this code, I have tried this and it is working very fine but there is a doubt in my mind about that is it secured way to integrate this with using email only, I mean what about those API Token I have received from paypal account. I didn’t find any configuration for them in your code.
Thanks
Hi Chandan,
Yes, of course, it is a secure way of integrating with PayPal. Absolutely no issues with it.
You need that token when you make REST API calls to PayPal. Here in this scenario, we do not require it and so it is not needed.
Are you have any code base for paypal payout feature in PHP?
If yes please share your experience.
Hi Mohtashim, I will soon write an article for that.
Very good article, accurate and comprehensive.
Exactly what I was looking for the way I need it!
Thanks!
Welcome, Szoupi. Keep reading and sharing.
Thank you for the code , i was able to understand and implement it fully .
Welcome Biswas.
Plz one example on Instamojo payment gateway tutorial with save database.
Hi Pravin,
Sure, I will try to write an article for Instamojo payment gateway integration.
the code is working cool
Thank you Ones Derry.
Can you write articles on transfer money payout from stripe to stripe account?
if you have any idea about that, please share link?
Sure, I will write about it Vijendra.
will it work for umbraco website?
Hi Jimy,
Are you referring to Umbraco .Net website? If so, this will not work in that. This is exclusively coded in PHP and you will need server with PHP support.
one of the simplest implimentations. Thanks for the great work. I am having one issue. Sandbox transactions are not getting inserted into the db. Do i have to do some changes in the script or use “as is”?
Thank you Rupesh. Sandbox transaction will work on a server reachable by PayPal. Localhost will not work.
Thanks !
Welcome Vijay.
The database part seems quite complicated
Hi Padmanabhan,
To get a reasonably functional payment gateway integration we need that size of code and eventually complexity increases. If you can let me know which part of code is puzzling you, I will be happy to help.
Nice article
Thank you Victor.
Hello – I tried the cart. It updated the tbl_order with the order (as pending) but it did not update tbl_payment. It also did not state the order ID in the thank you page where it says “Thank you for shopping with us. Your order has been placed. You order Id is “.
Could this be a host issue? I am on a shared hosting with 1&1 IONOS and I’m wondering if some hosts, in your experience, block Paypal IPN.
Thank you.
Chris
Hi Chris,
I have not seen hosts blocking PayPal IPN. It should be related to configuration mostly.
Hi Vincy, I am very fond of Your work, keep up the good work You do.
I am from Africa/Rwanda, I really tried Stripe IPN and 2checkout, unfortunately my country is not eligible for certain payment gateways. Which payment processor would You recommended for me in the fact that I can develop an E – Commerce web without restrictions. Thank You
Hi,
Thank you for nice words. Actually it is not a recommendation as I have not used these payment providers. But following is a list of providers in Rwanda, Paysera payment gateway, Pesapal, BitPay, CoinPayments.
Thanks very much Vincy.
Does not save data in database in trial mode Why ?!
If it is in localhost, notify url will not be reachable by PayPal.
Thanks for yours great job
you are the best
Welcome Ali.
It is very easy to understand tnx
Welcome Yesuraj.
Hi
any tutorial links for latest Stripe v3 example demo.
Here is a tutorial for Stripe v3 https://phppot.com/php/stripe-payment-gateway-integration-using-php/ with example.
thank you vincy,
From Cliff Mathebula in South Africa.
Welcome Cliff.
Vincy, the payment is successful using sandbox, but the response is always INVALID , any help ?
Hi Faisal,
Need the information passed by PayPal on callback to debug that.
Hi Vincy,
A BIG thanks for sharing your work. It saved me hours of research and frustration.
Thanks again.
Welcome Lucas.
Hi, the notify part is not working for me.It doesn’t call the notify.php and nothing is inserted in the db. Also, after successful transaction, it doesn’t automatically redirect to the home page. I have to click on the button in paypal to redirect me to the merchant site. Do you know how to troubleshoot that and what potentially is happening.?
Hi Dolp,
For the notify part to work, you should deploy it in a server reachable by PayPal. Localhost will not work.
Where are (cancel.php & return.php) files?
Hi Abdo,
cancel.php – if the user cancels the payment in PayPal site, then this page will be shown.
return.php – On payment, this page will be shown.
can this run on localhost?
Other than the PayPal callback (notify), this can run on localhost. But the core of payment gateway integration is in callback. So it is better to have a test server to work on this.
Thanks for a great tutorial.
How do I add direct credit card payment option if the customer does not have a paypal account?
regards
Allan
Hi Allan,
The PayPal interface will provide option to pay via credit card also.
thanks for tutorial
Welcome Andy.
I have gone through this article but its difficult for me to understand completely. As I have been working with procedural PHP and you have adopted object oriented approach.
Can you make a fully procedural PHP/mysqli code for the folk like me who have not yet jumped into object oriented approach..
if you spare your time for this it will be a great help and will be highly appreciated/
thanking you and I remain.
Hi Mazhar,
Yes, as you have observed I have used object oriented approach. Soon I will try to write a separate article on PayPal payment gateway integration entirely using procedural approach.
should i test it on live server? not localhost?
cuz i didnt saw any update in my db after success payment
Yes Rob. You are correct. For PayPal to call the notify url, you need to deploy in a server. Localhost will not be reachable by PayPal’s servers.
Hi, Nice tutorial, Great work, and your feedback is timely too. Please I want to integrate Payswitch into an application. Can I follow this tutorial? What do I have to change ? Whiles I wait for the response, I will be trying my hands on it to see.
Hi Winfred,
Thank you. To integrate Payswitch this article will not be suitable. This is too specific to PayPal payment gateway integration. I will try to write a separate article for integrating Payswitch.
hy how are you vincy ?
can you plz make a video for pesapal payment gateway in php will thanks fully
Sure Zaid, I will try to do as time permits. Thanks.
Mam Thanking You for a Nice Tutorial. Everything is working correctly, but database is not updating in my localhost.
Hi Arun,
The callback will not happen in your localhost.
How to send payment successful email to payee
Hi Pratap,
To send email refer this https://phppot.com/php/send-email-in-php-using-gmail-smtp/
To email an invoice refer this https://phppot.com/php/generate-ecommerce-purchase-invoice-pdf-using-php-script/
hii…thank you
Welcome Neel.
Hi!
If I try your script it seem not call notify.php. I am nont able to understand what is wrong…. :-(
Hi Gianluca,
Can you give me more information? Do you get any error? etc..
Hi Vincy,
Very good article, accurate and comprehensive.
Exactly what I was looking for the way I need it
I have one doubt, for go live which credential can I use, and how to create go live credentials ?
Hi Laxman,
Thank you.
In your PayPal dashboard, select the Live mode and create keys same way as you did for Sandbox and then use it.
Please guide on UPI and Cards payment together
Hi Lalit,
Sure, I will write an article on UPI and cards payment soon.
Hey bro. Nice Tutorial. can you please tell me that i have php site i want to add login and sign up with payment gateways, i mean i have plans page how can i add subscription plans with payment gateway. please give me your email.
Hi Farhan, my email is vincy@phppot.com.
thanks my freinds
Welcome Olivier.