PayPal Direct Payment API Component
Useful component that provides a wrapper for PayPal's Direct Payment API, allowing any cake based application to accept payments via Direct Payment (processing credit cards and payments without leaving your website) and Express Checkout (allowing users to use their PayPal account to pay)
Index
Introduction
While building a large CakePHP based application I found myself needing to integrate PayPal Direct Payment API with CakePHP. For those of you who don't know this API here's a short statement from PayPal's website describing its main objective:
Direct Payment API offers you direct credit card payment processing capability through PayPal. For credit card transactions, customers stay on your website as PayPal processes the payment in the background.
Now, I have built PayPal Direct Payment API applications in the past, but I wanted to bake paypal the proper cakish way. Furthermore, as PayPal's TOS states, PayPal's business rules require that sites that offer Direct Payment API (credit card processing without leaving your website) also must offer Express Checkout Payment (where buyer gets transferred to PayPal's website to confirm the order and then taken back to your website.) It is a bummer, but it is mandatory.
It is also important to know that only people with bank accounts in the US can apply for Website Payments Pro (the PayPal service that allows you to use Direct Payment API.) While this may discourage some bakers from even trying the API, you should now that PayPal offers a Sandbox environment to allow you to test every aspect of the integration.
For that purpose I've created a CakePHP component that provides a wrapper for PayPal's Direct Payment API. I have tested it with CakePHP 1.1.10.3825 running on:
- Apache 2, Windows XP, PHP 4.4.4
- Apache 2, Debian Linux, PHP 5.2.0
Pre-requisites
PEAR and PayPal Direct Payment API
You'll obviously need PayPal's Direct Payment API for PHP. You can get it at:https://www.paypal.com/IntegrationCenter/ic_sdk-resource.html
It is a PEAR based package so needless to say PEAR's core must be included on the vendors path. It is up to you how you install the API on your cake environment. This is what I've done:
- Downloaded PEAR base from http://pear.php.net/package/PEAR
- Unzipped PEAR based to {CAKE}/app/vendors/PEAR
- Downloaded PayPal Direct Payment SDK from https://www.paypal.com/IntegrationCenter/ic_sdk-resource.html
- Unzipped directory php-sdk/lib in SDK's zip to {CAKE}/app/vendors/PEAR
- Created a pear.inc.php file on {CAKE}/app/vendors with following content: Download code
// Set path to PEAR filesܡםX]yZ0x%w ((kjaܡםDownload code
define('PEAR_PATH', dirname(__FILE__) . DS . 'PEAR');
// Add PEAR path to library path
set_include_path(PEAR_PATH . PATH_SEPARATOR . get_include_path());vendor('pear.inc');
Set up a PayPal Sandbox account
Can't really go through the whole explanation, but follow instructions on https://www.paypal.com/IntegrationCenter/ic_sandbox.htmlImportant Notes
There are two ways to make a payment: through Direct Payment API and via Express Checkout.
The Direct Payment API takes mandatory information such as order amount, credit card info, and shipping addresses to process the order by contacting PayPal's server via SOAP messages. When it is done, you either get a succesfull code (meaning that the sale was made) or an error. Therefore, it is a one-time call to the component. You set up the component's required variables, call directPayment(), and you get the appropiate result.
Unlike the simplicity of Direct Payment API, Express Checkout requires the user to be redirected to PayPal's website to confirm the payment, and then sends a callback to your site sending a Token ID. This callback is a way for PayPal to give us this ID that we will need when we want it to process the order. This means that you will need to call expressCheckout() function inside the component twice: when you initiate the payment (at which point the user is redirected to paypal) and when you get back the token and want to perform the actual transaction. There's no need to tell the component which token you've got, it will figure out what it's supposed to do when you call expressCheckout().
One very important issue regarding Express Checkout: I have my PayPal payment behind an authenticated action. When testing online I discovered that after paypal's callback to my website Cake's session got lost. Since you can tell the component which will be the URL that will be called when PayPal gives the callback, I added Cake's session ID to the URL. Before the first call to expressCheckout(), the call that makes the redirect to paypal, I store the session information using the component's function:
Download code
$this->Paypal->storeSession();
Then, when I get the callback (which I can check because I specify which URL gets called) I restore the session:
Download code
if (isset($_REQUEST['csid']))
{
// Restore session
if (!$this->Paypal->restoreSession($_REQUEST['csid']))
{
$this->redirect('/');
exit;
}
}
Comments
Comment
1 PayPal Direct Payment API Version
Is the API used the US version for paypal pro?
I am wondering as paypal pro api is now avaliable in the uk but doesn't use the same sdk as the US version.
Would it be easy to have an all-in-one component that handled all version as this could be updated centrally instead of the uk users having to write there own?
Penfold
Comment
2 PayPal Direct Payment API Version
Penfold: Well I'm using the API they give you when you look for DirectPayment's SDK. I find it hard to believe they would change the API for another country. Can you provide a link (to my email) with the information you have that tells you their SDKs are different for US and UK?
Comment
3 Thanks
Question
4 UK version
Comment
5 Thank You
I'll be trying it out today. It will most definitely save me many, many hours.
Question
6 API Question
Controller Class:
<?php$this->Paypal->setEnvironment(CAKE_COMPONENT_PAYPAL_ENVIRONMENT_SANDBOX);
$this->Paypal->setUser('ApiUser');
$this->Paypal->setPassword('ApiPassword');
$this->Paypal->setCertificate('sandbox.paypal.com.pem');
$this->Paypal->setOrder($order);
?>
Hi, where should i put the pem file? technically it is located under {cake}/app/vendors/PEAR/PayPal/cert but the code errors up the says sandbox.paypal.com.pem cannot be located.
Please, badly need help to implement your API.
Comment
7 API Question
Comment
8 important
- Remove setCertificate and replace it with
$this->Paypal->setSignature('signature provided by paypal');.
and people it worked!!
Question
9 Cake 1.2 integration for the Paypal component
Comment
10 Cake 1.2 integration for the Paypal component
Comment
11 Fatal Error
Warning (2): require_once(PayPal.php) [function.require-once]: failed to open stream: No such file or directory [APP/controllers/components/paypal.php, line 12]Comment
12 Complicated Solutions
I try to implement the whole tutorials but it seems...it's quit difficult for me to understand with specially it doesn't give any instruction where to go. Where to put the a certain code. Specially the form and it's components.
Can u or anyone could help me how to make a step by step work in cooking paypal payment methods? Sorry but i'm just a newbie,...could anyone help me???
thnks
Comment
13 hi i have same problem... can you help me with it
i am able to copy PEAR and paypal component ...every thing is working fine (it is able to include Pear , recognize paypal component).. but i am unable to figure out hoe to implement it in my project.
please guide me to solve this issue..
i will be greatfull to you if you can send some example application if you can...
Thanks in advance
M A Rasheed
Question
14 Reset Endpoints?
So, here is my situation. I seem to have everything working fine on cake1.2 on my local box (os x leopard). However, when I deploy the same code to the pre-production box (Aplus.net shared hosting), I am getting a curl permission denied issue. Typically this can be due to proxy issues, and I think its only related to hitting the sandbox site.
Apparently, this can be fixed by resetting the endpoint URL to api-aa.sandbox.paypal.com/2.0/.
However, I can not for the life of me find the section in the code that is physically setting the URL request in the DirectPayment method. I see how its setting the environment to the constant declared above (i.e. CAKE_COMPONENT_PAYPAL_ENVIRONMENT_SANDBOX)-- and I can see in the Express Checkout where its replacing the string based off of that value. But, I can not find how the request is being built for the directPayment method to change the value to api-aa.sandbox.paypal.com/2.0/.
Please let me know if anyone has any ideas.
Thanks!
Chris
Question
15 I want guideline to integrate Paypal in any Cake Project
I am not able to understand the given code. Some part of code is not explained where to place it
Comment
16 I am getting same error on live server
Hi it is working fine on local system (localhost)but it is not working on live server.... any solution?
please help me!!
Thanks in advance
M A Rasheed
Comment
17 Instructions for use
To use this component, the following steps need to be taken:
1) The complete code for the component (located on page 4) needs to be saved as app/controller/components/paypal.php
2) In the controller you wish to use the component for, add: var $uses = array('Paypal');
3) In your controller, add the example express() method (provided on page 2).
This presumes that you have the PayPal API set up. The PayPal API is completely separate to this component. To install the PayPal API:
1) Download the PayPal API from the PayPal SDK website
2) Copy the file PayPal.php and the folder PayPal into your existing PEAR installation.
This again assume that you have a working PEAR installation, and that your include_path correctly includes your PEAR library.
Question
18 Accessing the SetExpressCheckoutRequestDetails object
At the moment, the way the component is written, it's not possible to access this object. Can the author think of a way to allow customisation without hardcoding it in the component?
Comment
19 Paypal
Question
20 How to solve Cannot modify header information Error ?
it will occur when on line number 731 in paypal.php
header('Location: ' . $payPalUrl);
Question
21 Requires more Detailed Installation
Thanks for this tutorial. I have tried to follow it through along with help from existing comments but there seem to be header modify error that is very annoying.
This is what I have done.
I have saved the PaypalComponent php script as paypal.php in components/.
I have created a folder inside vendor called "PEAR", inside I have extracted the base lib folder from pear base package as well as the Paypal SDK.
I have also created a Pear.inc.php file inside vendor that Includes the PEAR directory.
In my payment controller, I have added App::import('Vendor', 'PearVendor', array('file' => 'pear.inc.php')); on the top.
And var $components = array('othAuth', 'Paypal');
Now, when I try to access any actions inside this controller, it gives me the following error:
Warning (2): Cannot modify header information - headers already sent by (output started at F:\production\Workspace\paymenttest\dev\app\controllers\components\paypal.php:984) [CORE\cake\libs\controller\controller.php, line 640]
Code | Context
$status = "Location: http://localhost/users/login?from=users/express"
header - [internal], line ??
Controller::header() - CORE\cake\libs\controller\controller.php, line 640
Controller::redirect() - CORE\cake\libs\controller\controller.php, line 621
othAuthComponent::redirect() - APP\controllers\components\oth_auth.php, line 818
othAuthComponent::check() - APP\controllers\components\oth_auth.php, line 936
AppController::beforeFilter() - APP\app_controller.php, line 26
Dispatcher::_invoke() - CORE\cake\dispatcher.php, line 209
Dispatcher::dispatch() - CORE\cake\dispatcher.php, line 194
[main] - APP\webroot\index.php, line 88
---------
Any help is appreciated.
Comment
22 Paypal outdated endpoints
When moved to LIVE, I was getting success response messages with the transaction IDs. However, no money being charged to the CC and no money going to the Paypal's account.
After spending about an hour with the Paypal technician on the phone, we learned that the endpoint URLs are incorrect in the PEAR package !.
To correct that, you need to update these files :
(suppose you installed the PEAT into vendors (not in the app dir, but in the root of your cake installation)
vendors/PEAR/Paypal/lib/Paypal/wsdl/paypal-endpoints.php
vendors/PEAR/Paypal/lib/Paypal/wsdl/paypal-endpoints.xml
Note ; I do not know which file is used , so I update both of them
This is the new values for the LIVE environment :
'PayPalAPI' => 'https://api-3t.paypal.com',
'PayPalAPIAA' => 'https://api-3t.paypal.com',
'PayPalAPI-threetoken' => 'https://api-3t.paypal.com',
'PayPalAPIAA-threetoken' => 'https://api-3t.paypal.com',
Change the URL in the XML file to https://api-3t.paypal.com as well.
Everything should be fine and you should get the money into your account.
Note : these files also hold min and max values for the price you charge via Paypal.
Note 2 : I have created complete a complete payments controller with four (4) steps :
1) enter personal info
2) enter billing info
3) review order (with the options to edit)
4) process payment
The payments controller also have admin functionality.
Let me know if anyone were interested in this as a packge.
Good Luck
Martin
Comment
23 PayPal Direct Payment API Component for 1.2
trying to make the component work, I finally got it working in Cake
1.2. I'm relatively new to Cake, but have been working with PHP for
over 5 year, so there are a few things that I'm not sure if I used the
best way to do it.
So this are the confusions I got:
1. The PEAR directory I comes like PEAR-1.8.1/PEAR. I wasn't sure of
which of the two directories I should uncompress and where. Also I had
confusions with what directories should be uncompressed from the
PayPal SDK.
For the PEAR directory, you should uncompress the files so you get the
file PEAR.php in vendors/PEAR/ (vendors/PEAR/PEAR.php).
For the SDK, you should uncompress the php-sdk/lib directory at
vendors/PEAR/.
The final directory structure should look like the following: (only
showing the main files, not all of them)
->{CAKE}/app/vendors
->./PEAR
->./HTTP
->./Log
->./Net
->./PayPal
->./PEAR
->PayPal.php
->Multi.php
->Log.php
->PEAR.php
->Multi.php
2. The second confusion I had was how to replace the vendors call to
App::import() for Cake 1.2... Unfortunately this wasn't working for me
at all. So I (and this is the part that I think is not how it's
supposed to be done, but I worked for me) went to the bootstrap file
({cake}/app/config/bootstrap.php) and added the following code to the
bottom of the file:
set_include_path(dirnameThis sets the PEAR directory in the vendors file as part of the(__FILE__).DS.'..'.DS.'vendors'.DS.'PEAR'.PATH_SEPARATOR.get_include_path
());
include path, so all the require calls from {cake}/app/controllers/
components/paypal.php work fine.
3. I'm a bit ashamed of this one, but I forgot for a moment that they
were talking about a component for I was a bit confused of were to put
the paypal component content. It was a stupid confusion, but if
anybody has a doubt, you have to put the component in {cake}/app/
controllers/components/paypal.php.
Those were the main confusions that were bugging me during the whole
day.
To make the component work, follow this steps:
1. Download PEAR and place it how it's explained in my confusions #1
(above)
2. Download the PayPal PHP SDK (https://cms.paypal.com/us/cgi-bin/? cmd=_render-content&content_ID=developer/library_download_sdks) and
uncompress it how I explained in my confusions #1 (above) -> 3. Create the file {cake}/app/controllers/components/paypal.php and
write the components content (http://bakery.cakephp.org/leafs/view/22)
in this file.
4. Don't forget to add 'Paypal' to your controller's components: var
$components = array('Paypal');
5. Change the credentials (username,password and signature/
certificate) to your paypal's account
Note: In the example code, a certificate is being used instead of a
signature. Paypal let you use one or the other, if you use signature,
change the method call from $this->Paypal->setCertificate() to $this-
>Paypal->setSignature().
6. You should be able to use now the example code at
http://bakery.cakephp.org/leafs/view/20
I hope this was helpful for somebody. If you have any questions you
can send me an email and I'll try to help you!
Comment
24 problem with live server
i did the installation like posted by Jorge Pedret. it works fine on my local server (win xp, xampp). but i get an error on my live server:
Fatal error: require_once() [http://php.net/function.require]: Failed opening required 'PEAR.php'does anybody have any idea why?