Paypal is the most popular and convenient way to get paid. If you are selling some products in your website, you should definitely use Paypal payment gateway, why? because it’s free and there are over 350 million Paypal users all over the world who would happily purchase your products.
In this tutorial let us find-out how we can use Paypal Express Checkout in websites to sell some products instantly.
To test your PayPal store in a local server, you need to signup for PayPal Developer account and use their sandbox. See creating PayPal Sandbox account. To sell your products in real world, you need to signup for real Paypal account and obtain sellers information needed for the configuration file.
As you can see we have four PHP files in this tutorial index.php, config.php, process.php and paypal.class.php, but if you observe mainly two files index.php and process.php, you should be pretty clear how everything works.
Configuration
config.php PHP file is used to store seller’s Paypal API information. Use your sandbox or live PayPal API details to replace variables in config.php file.
1 2 3 4 5 6 7 8 9 | <?php $PayPalMode = 'sandbox'; // sandbox or live $PayPalApiUsername = 'selleremail@somesite.com'; //PayPal API Username $PayPalApiPassword = '123456'; //Paypal API password $PayPalApiSignature = 'ZWxwchnCsdQg5PxAUjcH6OPuZK3sPcPH'; //Paypal API Signature $PayPalCurrencyCode = 'USD'; //Paypal Currency Code $PayPalReturnURL = 'http://yoursite.com/paypal/process.php'; //Point to process.php page $PayPalCancelURL = 'http://yoursite.com/paypal/cancel_url.php'; //Cancel URL if user clicks cancel ?> |
Product Page
index.php is initial page where your buyers get to see your products, it doesn’t matter how you are planning to present your products, it could be complex ajax driven page, single product or just list of few products, you just need to list your products similar to example below.
Each product item contains a form, and each form contains hidden input variables item name, item number, item quantity and price. A buyer is able to see product details and select quantity before buying the product. When buyer decides to buy, the selected product data gets posted to process.php.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <?php include_once("config.php"); ?> <html> <head> <title>My Products</title> </head> <body><h2 align="center">Test Products</h2> <div class="product_wrapper"> <table class="procut_item" border="0" cellpadding="4"> <tr> <td width="50%"><h4>Product 1</h4> (Product Description)</td> <td width="50%"><form method="post" action="process.php"> <input type="hidden" name="itemname" value="Product One" /> <input type="hidden" name="itemnumber" value="1" /> <input type="hidden" name="itemprice" value="10" /> Quantity : <select name="itemQty"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select> <input class="dw_button" type="submit" name="submitbutt" value="Buy (10 USD)" /> </form></td> </tr> </table> <table class="procut_item" border="0" cellpadding="4"> <tr> <td width="50%"><h4>Product 2</h4> (Product Description)</td> <td width="50%"><form method="post" action="process.php"> <input type="hidden" name="itemname" value="Product Two" /> <input type="hidden" name="itemnumber" value="2" /> <input type="hidden" name="itemprice" value="20" /> Quantity : <select name="itemQty"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select> <input class="dw_button" type="submit" name="submitbutt" value="Buy (20 USD)" /> </form></td> </tr> </table> </div> </body> </html> |
Class
paypal.class.php is nothing but collection of functions, PPHttpPost() PHP function is used to carry out API operations in progress.php file, such as sending HTTP POST Request or getting response from the server. You can add additional functions (if needed) in this class file and execute like this $paypal->functionname().
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | <?php class MyPayPal { function PPHttpPost($methodName_, $nvpStr_, $PayPalApiUsername, $PayPalApiPassword, $PayPalApiSignature, $PayPalMode) { // Set up your API credentials, PayPal end point, and API version. $API_UserName = urlencode($PayPalApiUsername); $API_Password = urlencode($PayPalApiPassword); $API_Signature = urlencode($PayPalApiSignature); if($PayPalMode=='sandbox') { $paypalmode = '.sandbox'; } else { $paypalmode = ''; } $API_Endpoint = "https://api-3t".$paypalmode.".paypal.com/nvp"; $version = urlencode('76.0'); // Set the curl parameters. $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $API_Endpoint); curl_setopt($ch, CURLOPT_VERBOSE, 1); // Turn off the server and peer verification (TrustManager Concept). curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); // Set the API operation, version, and API signature in the request. $nvpreq = "METHOD=$methodName_&VERSION=$version&PWD=$API_Password&USER=$API_UserName&SIGNATURE=$API_Signature$nvpStr_"; // Set the request as a POST FIELD for curl. curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq); // Get response from the server. $httpResponse = curl_exec($ch); if(!$httpResponse) { exit("$methodName_ failed: ".curl_error($ch).'('.curl_errno($ch).')'); } // Extract the response details. $httpResponseAr = explode("&", $httpResponse); $httpParsedResponseAr = array(); foreach ($httpResponseAr as $i => $value) { $tmpAr = explode("=", $value); if(sizeof($tmpAr) > 1) { $httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1]; } } if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) { exit("Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint."); } return $httpParsedResponseAr; } } ?> |
Processing PayPal Payment
process.php is the final PHP file where buyer selected product data is received and processed it further for payment. We will execute mainly three Paypal methods here SetExpressCheckout, DoExpressCheckout & GetTransactionDetails. Each comment line in PHP code below explains how process.php deals with data received from buyer and PayPal.
SetExpressCheckOut
When buyer sends product details by clicking buy button, process.php needs to obtain PayPal token with SetExpressCheckOut method using Seller’s PayPal API credentials.
Once we successfully receive PayPal token, we need to set some session variable (itemprice, totalamount, itemName, itemNo, itemQTY) for later. And then we redirect buyer to PayPal order summary page, where buyer pays in secure PayPal environment, but remember PayPal hasn’t transferred money yet.
DoExpressCheckoutPayment
After payment, buyer is redirected back to process.php page with Paypal token and PayerID values. We again need to send these values back to PayPal using DoExpressCheckoutPayment method, where PayPal verifies these values, only then the money is transferred to Seller’s account.
GetTransactionDetails
Obtains information about a specific transaction, on successful payment you might want to collect buyer details such as address, payment Information etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | <?php session_start(); include_once("config.php"); include_once("paypal.class.php"); if($_POST) //Post Data received from product list page. { //Mainly we need 4 variables from an item, Item Name, Item Price, Item Number and Item Quantity. $ItemName = $_POST["itemname"]; //Item Name $ItemPrice = $_POST["itemprice"]; //Item Price $ItemNumber = $_POST["itemnumber"]; //Item Number $ItemQty = $_POST["itemQty"]; // Item Quantity $ItemTotalPrice = ($ItemPrice*$ItemQty); //(Item Price x Quantity = Total) Get total amount of product; //Data to be sent to paypal $padata = '&CURRENCYCODE='.urlencode($PayPalCurrencyCode). '&PAYMENTACTION=Sale'. '&ALLOWNOTE=1'. '&PAYMENTREQUEST_0_CURRENCYCODE='.urlencode($PayPalCurrencyCode). '&PAYMENTREQUEST_0_AMT='.urlencode($ItemTotalPrice). '&PAYMENTREQUEST_0_ITEMAMT='.urlencode($ItemTotalPrice). '&L_PAYMENTREQUEST_0_QTY0='. urlencode($ItemQty). '&L_PAYMENTREQUEST_0_AMT0='.urlencode($ItemPrice). '&L_PAYMENTREQUEST_0_NAME0='.urlencode($ItemName). '&L_PAYMENTREQUEST_0_NUMBER0='.urlencode($ItemNumber). '&AMT='.urlencode($ItemTotalPrice). '&RETURNURL='.urlencode($PayPalReturnURL ). '&CANCELURL='.urlencode($PayPalCancelURL); //We need to execute the "SetExpressCheckOut" method to obtain paypal token $paypal= new MyPayPal(); $httpParsedResponseAr = $paypal->PPHttpPost('SetExpressCheckout', $padata, $PayPalApiUsername, $PayPalApiPassword, $PayPalApiSignature, $PayPalMode); //Respond according to message we receive from Paypal if("SUCCESS" == strtoupper($httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($httpParsedResponseAr["ACK"])) { // If successful set some session variable we need later when user is redirected back to page from paypal. $_SESSION['itemprice'] = $ItemPrice; $_SESSION['totalamount'] = $ItemTotalPrice; $_SESSION['itemName'] = $ItemName; $_SESSION['itemNo'] = $ItemNumber; $_SESSION['itemQTY'] = $ItemQty; if($PayPalMode=='sandbox') { $paypalmode = '.sandbox'; } else { $paypalmode = ''; } //Redirect user to PayPal store with Token received. $paypalurl ='https://www'.$paypalmode.'.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='.$httpParsedResponseAr["TOKEN"].''; header('Location: '.$paypalurl); }else{ //Show error message echo '<div style="color:red"><b>Error : </b>'.urldecode($httpParsedResponseAr["L_LONGMESSAGE0"]).'</div>'; echo '<pre>'; print_r($httpParsedResponseAr); echo '</pre>'; } } //Paypal redirects back to this page using ReturnURL, We should receive TOKEN and Payer ID if(isset($_GET["token"]) && isset($_GET["PayerID"])) { //we will be using these two variables to execute the "DoExpressCheckoutPayment" //Note: we haven't received any payment yet. $token = $_GET["token"]; $playerid = $_GET["PayerID"]; //get session variables $ItemPrice = $_SESSION['itemprice']; $ItemTotalPrice = $_SESSION['totalamount']; $ItemName = $_SESSION['itemName']; $ItemNumber = $_SESSION['itemNo']; $ItemQTY =$_SESSION['itemQTY']; $padata = '&TOKEN='.urlencode($token). '&PAYERID='.urlencode($playerid). '&PAYMENTACTION='.urlencode("SALE"). '&AMT='.urlencode($ItemTotalPrice). '&CURRENCYCODE='.urlencode($PayPalCurrencyCode); //We need to execute the "DoExpressCheckoutPayment" at this point to Receive payment from user. $paypal= new MyPayPal(); $httpParsedResponseAr = $paypal->PPHttpPost('DoExpressCheckoutPayment', $padata, $PayPalApiUsername, $PayPalApiPassword, $PayPalApiSignature, $PayPalMode); //Check if everything went ok.. if("SUCCESS" == strtoupper($httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($httpParsedResponseAr["ACK"])) { echo '<h2>Success</h2>'; echo 'Your Transaction ID :'.urldecode($httpParsedResponseAr["TRANSACTIONID"]); /* //Sometimes Payment are kept pending even when transaction is complete. //because of Currency change, user choose other payment option or its pending review etc. //hence we need to notify user about it and ask him manually approve the transiction */ if('Completed' == $httpParsedResponseAr["PAYMENTSTATUS"]) { echo '<div style="color:green">Payment Received! Your product will be sent to you very soon!</div>'; } elseif('Pending' == $httpParsedResponseAr["PAYMENTSTATUS"]) { echo '<div style="color:red">Transaction Complete, but payment is still pending! You need to manually authorize this payment in your <a target="_new" href="http://www.paypal.com">Paypal Account</a></div>'; } echo '<br /><b>Stuff to store in database :</b><br /><pre>'; $transactionID = urlencode($httpParsedResponseAr["TRANSACTIONID"]); $nvpStr = "&TRANSACTIONID=".$transactionID; $paypal= new MyPayPal(); $httpParsedResponseAr = $paypal->PPHttpPost('GetTransactionDetails', $nvpStr, $PayPalApiUsername, $PayPalApiPassword, $PayPalApiSignature, $PayPalMode); if("SUCCESS" == strtoupper($httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($httpParsedResponseAr["ACK"])) { /* #### SAVE BUYER INFORMATION IN DATABASE ### $buyerName = $httpParsedResponseAr["FIRSTNAME"].' '.$httpParsedResponseAr["LASTNAME"]; $buyerEmail = $httpParsedResponseAr["EMAIL"]; $paymentStatus = $httpParsedResponseAr["PAYMENTSTATUS"]; $conn = mysql_connect("localhost","MySQLUsername","MySQLPassword"); if (!$conn) { die('Could not connect: ' . mysql_error()); } mysql_select_db("Database_Name", $conn); mysql_query("INSERT INTO BuyerTable (BuyerName,BuyerEmail,TransactionID,ItemName,ItemNumber, ItemAmount,ItemQTY,PaymentStatus) VALUES ('$buyerName','$buyerEmail','$transactionID','$ItemName',$ItemNumber, $ItemTotalPrice,$ItemQTY,$paymentStatus)"); mysql_close($con); */ echo '<pre>'; print_r($httpParsedResponseAr); echo '</pre>'; } else { echo '<div style="color:red"><b>GetTransactionDetails failed:</b>'.urldecode($httpParsedResponseAr["L_LONGMESSAGE0"]).'</div>'; echo '<pre>'; print_r($httpParsedResponseAr); echo '</pre>'; } }else{ echo '<div style="color:red"><b>Error : </b>'.urldecode($httpParsedResponseAr["L_LONGMESSAGE0"]).'</div>'; echo '<pre>'; print_r($httpParsedResponseAr); echo '</pre>'; } } ?> |
Conclusion
I hope this tutorial will help you sell your products easily using PayPal. If you are facing issue of Paypal holding fund for 21 days, please read their policy here, and if you sell huge amount of products everyday, you might want to automate things by setting up PayPal IPN listener script. Good luck!

hello, thank you for the tutorial,
I have a problem is that I do not know how to add the payment with the card without a paypal account
Wow, your stuff is wonderful. Thank you for taking such time and effort. I was wondering if you had any ideas for me about the session variables not working. I am implementing your cart in Joomla on the Gantry Framework and I am finding that session variables are not working even for test scenarios to pass “Hello World.” I was trying to implement the Joomla session control but wanted to ask if you had any ideas. You make it look so effortless:-) Thank you!
Hi this is easy in joomla :
2
3
$session->set('var1','123456'); //set session
$session->get('var1'); //get session
Hello,
help me please :
Error : Security header is not valid
2
3
4
5
6
7
8
9
10
11
12
(
[TIMESTAMP] => 2012%2d08%2d11T10%3a38%3a39Z
[CORRELATIONID] => 8da2e6f5383cd
[ACK] => Failure
[VERSION] => 76%2e0
[BUILD] => 3435050
[L_ERRORCODE0] => 10002
[L_SHORTMESSAGE0] => Security%20error
[L_LONGMESSAGE0] => Security%20header%20is%20not%20valid
[L_SEVERITYCODE0] => Error
)
Thanks,
Hi, did you resolve this error? I am getting the same error. Thanks.
Solved: I had this because I used Test Account vs. API Username, which both look similar. Be sure you have the correct username. Also look out for space in the name.
Hi Saaraan!
Thanks for your coding on the paypal express checkout.
I am using it and it worked from the first moment.
Although, I have little to now knowledge now how this thing works. I would need a little help.
I am using your script to sell digital downloads immediately after paypal processing (I use the return url and provide the download there if payment was successfull)
Now there is a small problem, paypal is keeping my money for 21 days until ‘shipping’ is confirmed. (or there is a positive ebay feedback…whatever)
I have read that for ‘digital goods’ it is possible to set the order state to downloaded automatically.
But I do not know how to implement that??
Do you have any idea and can help me?
Thanks
Bodo
I really have enjoyed using your script, but I am getting an error back from the Paypal sandbox that the Order Total is missing. However, I am seeing the total showing on Paypal.
Here is the dump of $padata (without the final URLs shown)
2
3
4
5
6
7
8
9
10
PAYMENTACTION=Sale&
ALLOWNOTE=0&
PAYMENTREQUEST_0_CURRENCYCODE=USD&
PAYMENTREQUEST_0_AMT=155.00&
PAYMENTREQUEST_0_ITEMAMT=155.00&
L_PAYMENTREQUEST_0_AMT0=155.00&
L_PAYMENTREQUEST_0_NAME0=Nene&
L_PAYMENTREQUEST_0_NUMBER0=&
AMT=155.00
Hi! I have the same problem here. Do you have any solution?
Thanks!
Hi, I’m also getting the ‘order total is missing’ problem, and you haven’t replied to this issue? Is it a known bug? Do you have the answer?
Regards,
Max
Pingback: Paypal Express Checkout Error in PHP | Jisku.com - Developers Network
Pingback: PayPal Payments Pro 4.2
Thank you a lot
Wonderful tutorial, it was easy to build on with it… so great work!
Thanks Saaraan,
you did a great job…
but let me one thing…how to do it in mobile on web view.
Thanks in advance
hello,
seems to be a nice.
for me the download-button does not work.
whats wrong?
i will get a new tab with this content:
PK)†ö@¸‰ö”paypal-express-checkout/config.php;OÃ0…çVê¸R·ZPÚW‰ÂP·U„ÔÇ …
can you tell me which browser you are using? Also you can right click and click “save link as..” a zip file, if you are using Chrome.
its firefox 16 and windows 7
Thanks for the tutorial and script, very well explained. Before I try to use it could you tell me if there would be a problem with clashing sessions?
At the moment I have a test site that users log into via Facebook and there are a few pages that they need to be logged in to see which is controlled with a session ‘$uid = $session’. I would like to have one of those pages visited only after a payment and if they need to revisit the page they will need to repay.
I understand that I can achieve this using the PayPal sessions in your script but would I be able to use both my existing session and the new one together?
Thanks
What do i need to change in the code to enable it to go to Mobile Express Checkout ?
How can I add extra fields to be processed from the form such as Tax amount (which will get calcualted) and a fixed booking fee regardless of quantity. Desperate for this bit and thanks for the code it works but I cant do this bit which is crucial for my situation.
how about putting the logo in the page ??
this script is the best. finally I find something clear. Thank You
Thanks for this tutorial, it is really good! How can I use this example, if i have many items on cart?
How can i use this if i have multi prodcuts on my cart?
Where can I send to paypal the shipping cost???
Get Script. Thank you.
One question: When I click the “buy” button, I receive “Error opening page” error. Any ideas or suggestions as to the cause.
if you have multi products you simply make a do-while, set all the parameters following and replace the zero(_0_) with a counter variable… watch out to set the total sum right…
2
3
4
5
6
7
8
9
10
11
L_PAYMENTREQUEST_0_NAME0=Nene&
L_PAYMENTREQUEST_0_NUMBER0=&
L_PAYMENTREQUEST_1_AMT0=155.00&
L_PAYMENTREQUEST_1_NAME0=Nene&
L_PAYMENTREQUEST_1_NUMBER0=&
_0_
_1_
_2_
Hi,
Thanks saaran, Iam trying to connect the paypal server using curl.
but iam getting the following error:
SetExpressCheckout failed: couldn’t connect to host(7)
I have enabled the curl extension in php.ini
Can you help me out what is exactly missing ?
Thanks,
Srinivas
Try this : http://j.mp/VRMpw0 or http://j.mp/VRN5Sd
I am getting same error but the solutions mentioned doesn’t help. So pls help
Please check whether you have enabled curl properly in your local host otherwise host your files in any public domain and check it again.
of several sandbox paypal payment scripts, I have found yours to be working in my application. thanks!
Thanks for this tutorial, its very helpfull.
I think there is a conceptual error. After get logged at pay pal , next step it ask to confirm de shipping adress, and there is a note at the bottom that says: you’ll confirm your payment at the store…So, it should be still one more step that would be come back to your website and there make the final call to the DoExpressCheckoutPayment.
Aren’t you agree?
Hi,
Thank you for this really helpful post. Now I would like to ask if it is possible to handle multiple products the same way?
Thanks
Hi, I am having trouble implementing this into my site. I create session variables however when returning from Paypal they are unable to be retrieved. Any ideas why this wouldn’t be working? Thanks
Maika – I already answered your question for multiple products, scroll up.
James – Your problem might have to do with an Apple Browser, are you testing this on a tablet PC? It appears that some iPads/iPhones do delete all session variables if you forward to another website (go from your domain to paypal.com…). (this could be the reason, anyway, you need to solve it, so see what I have done)
Resolution:
You do not need to use a session variable anyway. Within the first request in this script you receive a PAYPAL TOKEN.
Search for the:
$httpParsedResponseAr["TOKEN"]
Save this paypal token into your database.
Then, after the visitor paid and comes back from paypal you receive the TOKEN again as a GET variable.
$_GET["token"]
Check this token with your stored token in the database, should be the same. So you can tell exactly who paid and you do not need any session variable. I had the same problem, so I deleted all session variables and work with the token now. Much better.
Thanks for your reply Bodo,
I am more so wanting to use the session variables so I can pass the shopping cart item qty, name and amount through to doexpresscheckout. The reason I want this is so the merchant when printing packing slips from there paypal account has the items on the packing slips. This is not showing up when just passing through setexpresscheckout. If you have any ideas let me know! Thanks.
Thanks.
Hi James
Hm, I am not sure what kind of system you are using and if you have a database behind it?
I have a table where I store every customers shopping cart. (itemnumber(s) and shopping_cart id), if someone checks out via paypal I also store the paypal token within this shopping cart table, so I can identify him after payment again. I know this script was using some session variables to store name and qty, but I did not want to use sessions for that anymore (some mobile browsers do not open new pages, instead they start a complete new browse when you are leaded to another page – so all sessions are lost.)
My suggestion to you is – try to use cookies.
Anyway, some users do not allow cookies, so you will have the next problem.
Hi, I have a question.
I would like to have a premium function on my website, where an user can buy something and the premium featuren should directly be active on his account. How can I enable this? Where should I put the Query to update his account? I mean, what if the paymentstatus is pending, then I don’t have the money. Does he have the possibility to cancel the order?
Or should I add the query after the GetTransactionDetails. Or is there the possibility that the order is complete, but the query will not be excuted?
Thanks!
Thank you so much for this script. Spent days ALMOST getting some other scripts working. This worked right off the bat – incredible. Keep posting great tutorials!
Hi Dude!
I just want to say thank you for the tutorial! it is really a big help for me!
Thanks!
Bernard
Hi, Very very very nice great work.
can i make express checkout to pay for multiple items in one go?
what should be the changes in the $padata.