PPExt - PayPal extension

(Stianlik) #1


Latest version can be downloaded from:


EDIT: The first version (ppext.tar.gz / ppext.zip in this post) has faulty IPN-code,

please download from the url above.

I am developing an event based PayPal extension for Yii, and would like to know it there is any interest in this? Feedback and feature requests are very welcome.

Features so far:

  • Button manager (you specify settings using an array of NVP-values)

  • PDT handler

  • IPN handler

  • Logging via Yii::log()


PDT- and IPN listeners (see src-code for a better example, including some payment processing)

class MinimalController extends Controller


	public function actionPdt() {

		$pdt = new PPPdtAction($this, "pdt");

                // Process payment

		$pdt->onRequest = function($event) {



                // Notify user on success

		$pdt->onSuccess = function($event) {



                // Notify user on failure

		$pdt->onFailure = function($event) {





	public function actionIpn() {

		$ipn = new PPIpnAction($this,"ipn");

                // Process payment

		$ipn->onRequest = function($event) {

			$event->setMsg("Received payment.");



                // Log success

		$ipn->onSuccess = function($event) {

			Yii::log($event->msg, "info", "payPal.controllers.DefaultController");


                // Log failure

		$ipn->onFailure = function($event) {

			Yii::log($event->msg, "error", "payPal.controller.DefaultController");





Button Manager - Creating a buy now button

$this->bm = Yii::app()->getModule('payPal')->buttonManager;

$this->bm->createButton($name, array('BUTTONTYPE'=>'BUYNOW'));

Installation instructions:

  1. Extract the file into WebRoot/modules/payPal

  2. Open WebRoot/modules/payPal/PayPalModule.php for further instructions

(Stianlik) #2

Discovered a bug in the previous attachment, this should work better.

(Stianlik) #3

I have done some refactoring and cleaned up the IPN and PDT functionality.

  • All IPN and PDT events are logged (success and failure)

  • Moved ipnRequest and pdtRequest from PPUtils into IPN- and PDT actions

  • Details about events (payments usually) is now stored in PPEvent::details

The new event class:

class PPEvent extends CEvent {

	public $responseAr = array();	// HTTP Response from PayPal

	public $requestAr = array();	// HTTP Request sent to PayPal

	public $details = array();	// Verified payment details (assoc array)

	public $msg = "";		// Description of event


Version 0.2 will be uploaded as soon as I have finished a couple of additional improvements, and testing.

(Spamec) #4

This looks really neat… thanks for sharing and inspiring piece of code :)

(Stianlik) #5

Thanks for the positive reply :)

Version 0.2 is ready:

  • PPIpnAction and PPPdtAction cleaned up and tested

  • DefaultController (IPN and PDT example) cleaned up and tested

  • Updated documentation


  • PPDbButtonManager - Database implementation of the button manager

  • Helper methods for common buttons

  • Standard payment processing methods (validating payment status, saving transactions in DB, …)?

(Antonio) #6

Thank you very much for sharing. I keep my self ‘connected’ to this post to see how it evolves.

(Stianlik) #7

Uploaded module into:


(Antonio) #8

Thank you stianlik

(Jamesmoey) #9

Bug in components/PPUtils.php

Index: application/modules/payPal/components/PPUtils.php


--- application/modules/payPal/components/PPUtils.php	(revision )

+++ application/modules/payPal/components/PPUtils.php	(revision )

@@ -205,7 +205,7 @@


 		// Sent HTTP GET request

 		$getStr = self::urlencode($getVars);

-		$getStr = self::implode("&",$getStr);

+		$getStr .= self::implode("&",$getStr);

 		$response = PPUtils::httpGet(self::getUrl(self::NVP), $getStr, true);


 		// Return false on HTTP error

(Jamesmoey) #10

Please ignore my last post. My mistake.

(Jamesmoey) #11

The run method in PPIpnAction class check that txn_id exist otherwise it is consider the notification as failure without even doing the validation with Paypal.

  • I think it should validation the notification with Paypal no matter what. And log any invalidate notification as hack attempt.

  • Also there are notification that does not contain txn_id. For example subscr_cancel or the subscription update. Maybe we should check both subscr_id and txn_id before marking the notification as failure.

(Stianlik) #12

I think it’s sensible to remove the txn_id check. Then all requests will be validated (failures are also logged) and txn_id / subscr_id can be checked by a simple isset() in onRequest.

EDIT: I have made the changes, check out version 0.4.

(Jamesmoey) #13

Excellent work by the way. A big time saver for me.

Consider putting this on github?

(Stianlik) #14

Thank you. I will consider github (or probably launchpad since I’m using bzr at the moment) and post a link if I decide to upload.

(Stianlik) #15

Moved from how to use ppext.

I’m working on a simple ecommerce example, it will be posted on the extension page after completion.

I have attached an example to illustrate how you:

  • Create buy now buttons

  • Remove buttons

  • Display buttons

Everything is included in a controller to make it simple.



Example: Creating a buy now button using the button manager

    $buttonManager = Yii::app()->getModule('payPal')->buttonManager;

    $nvp = array(



        'L_BUTTONVAR1'=>'item_name=My button',



    $buttonManager->createButton('My button', $nvp);

For payment processing, you should look at PPDefaultController and PPPhpTransaction.

(Kostya Molchanov) #16

My steps:

  1. Move module to /protected/modules/payPal

  2. Create account on paypal with e-mail kostya.molchanov@gmail.com

  3. In sandbox create 2 test-accounts - seller_1292519600_biz@gmail.com and buyer_1292577660_per@gmail.com

  4. In config.php









					'signature'=>'Your PayPal API signature',


					'identityToken'=>'Your PayPal identity token',




//					'class'=>'payPal.components.PPDbButtonManager',






  1. In view.php file


			$buttonManager = Yii::app()->getModule('payPal')->buttonManager;

			$nvp = array(



				'L_BUTTONVAR1'=>'item_name=My button',



			$buttonManager->createButton('My button', $nvp);


  1. Log

2010/12/18 13:47:30 [error] [payPal.helpers.PPUtils] NVP request failed


Response:TIMESTAMP=2010-12-18T07:47:30Z&CORRELATIONID=8059d1cb27f4a&ACK=Failure&VERSION=63.0&BUILD=1603674&L_ERRORCODE0=10002&L_SHORTMESSAGE0=Security error&L_LONGMESSAGE0=Security header is not valid&L_SEVERITYCODE0=Error

in /home/gluck/src/thesloganchefs/protected/modules/payPal/components/PPUtils.php (222)

in /home/gluck/src/thesloganchefs/protected/modules/payPal/components/PPButtonManager.php (59)

in /home/gluck/src/thesloganchefs/protected/views/projects/view.php (21)

2010/12/18 13:47:30 [error] [payPal.components.PPButtonManager] Failed create button

Request: BUTTONTYPE=BUYNOW&L_BUTTONVAR0=currency_code=USD&L_BUTTONVAR1=item_name=My button&L_BUTTONVAR2=amount=200.00&METHOD=BMCreateButton

in /home/gluck/src/thesloganchefs/protected/modules/payPal/components/PPButtonManager.php (240)

in /home/gluck/src/thesloganchefs/protected/modules/payPal/components/PPButtonManager.php (60)

in /home/gluck/src/thesloganchefs/protected/views/projects/view.php (21)

This is my first problem. And where paypal will send payment results?

(Stianlik) #17

You have to provide those values.

  1. Login to paypal using the seller account

  2. Find your signature at "My account" > "Profile" > "API Acess" > "View API Signature" (or "Request API Access")

  3. Find your identityToken at "My account" > "Profile" and look for "Secure Merchant Account ID"

You will be notified of payments by IPN (see PPDefaultController). Configure the IPN handler

in your PayPal account at "My account" > "Profile" > "Instant Payment Notification Preferences".

Before processing payments using IPN, you should read and understand this: Introducing IPN

(Kostya Molchanov) #18

Thank you very much. I copy PPDefaultLegacyController to protected/controllers/PayController.php Instant Payment Notification Preferences i set http://mydomain.com/pay/ipn/ and everything become good, my site receive payments results. but there is another question, how to send for example user_id to paypal and then receive this user_id to make some actions on my site. I read about “custom” but can’t create button with “custom” parametr and don’t know how to receive this parametr from paypal.

(Stianlik) #19

To create buttons with the "custom" parameter set to $userId, you can include the following code in your controller (use getButtonForm($id,$userId) instead of $buttonManager->getButton($id)->webSiteCode in your actions):


 * Get button form (HTML code) for button $id including

 * custom field with $userId as value.


 * @param string $id Button id

 * @param string $userId User id

 * @return string HTML Form


public function getButtonForm($id,$userId) {

    if ( ($button = $this->buttonManager->getButton($id)) !== false)

        return self::addHiddenField('custom',$userId,$button->webSiteCode);

    else return false;




 * Add hidden field to form.


 * @param string $name Field name (e.g. 'custom')

 * @param string $value Field value (e.g. 'My custom value')

 * @param string $form Form (e.g. $button->webSiteCode)

 * @return string Form with hidden an extra hidden field


public static function addHiddenField($name,$value,$form) {

	return preg_replace(

		'/< *\/form *>/i',

		'<input type="hidden" name="'.$name.'" value="'.$value.'" />'."\n</form>\n",




When you receive the IPN- and PDT notifications from PayPal, the user id can be found in $event->details[‘custom’].

I will include a better mechanism for this sort of thing in the next version.

(Kostya Molchanov) #20

Everything works perfect. Thanks a lot!