how to implement paypal in cakephp?

Here is an idea how to implement paypal in cakephp less than 5 mins? Answer is use Socket programming!! Yes, I found these very handy two classes from my friend Rajib Deb. So big big thanks for him.

Now step by step to implementation of this component.

Step 1: Create paypal.php file in /app/controllers/components/
Step 2: Paste this two class in paypal.php file

class HTTPRequest {

private $host;
private $path;
private $method;
private $port;
private $rawhost;

private $header;
private $content;
private $parsedHeader;

function __construct($host, $path, $method = 'POST', $ssl = false, $port = 0) {
$this->host = $host;
$this->rawhost = $ssl ? ("ssl://".$host) : $host;
$this->path = $path;
$this->method = strtoupper($method);
if ($port) {
$this->port = $port;
} else {
if (!$ssl) $this->port = 80; else $this->port = 443;
}
}

public function connect( $data = ''){
$fp = fsockopen($this->rawhost, $this->port);
if (!$fp) return false;
fputs($fp, "$this->method $this->path HTTP/1.1\r\n");
fputs($fp, "Host: $this->host\r\n");
//fputs($fp, "Content-type: $contenttype\r\n");
fputs($fp, "Content-length: ".strlen($data)."\r\n");
fputs($fp, "Connection: close\r\n");
fputs($fp, "\r\n");
fputs($fp, $data);

$responseHeader = '';
$responseContent = '';

do
{
$responseHeader.= fread($fp, 1);
}
while (!preg_match('/\\r\\n\\r\\n$/', $responseHeader));


if (!strstr($responseHeader, "Transfer-Encoding: chunked"))
{
while (!feof($fp))
{
$responseContent.= fgets($fp, 128);
}
}
else
{

while ($chunk_length = hexdec(fgets($fp)))
{
$responseContentChunk = '';

$read_length = 0;

while ($read_length < $chunk_length)
{
$responseContentChunk .= fread($fp, $chunk_length - $read_length);
$read_length = strlen($responseContentChunk);
}

$responseContent.= $responseContentChunk;

fgets($fp);

}

}

$this->header = chop($responseHeader);
$this->content = $responseContent;
$this->parsedHeader = $this->headerParse();

$code = intval(trim(substr($this->parsedHeader[0], 9)));

return $code;
}

function headerParse(){
$h = $this->header;
$a=explode("\r\n", $h);
$out = array();
foreach ($a as $v){
$k = strpos($v, ':');
if ($k) {
$key = trim(substr($v,0,$k));
$value = trim(substr($v,$k+1));
if (!$key) continue;
$out[$key] = $value;
} else
{
if ($v) $out[] = $v;
}
}
return $out;
}

public function getContent() {return $this->content;}
public function getHeader() {return $this->parsedHeader;}


}


class PaypalComponent extends Object {

var $endpoint;
var $host;
var $gate;
var $returnSuccessUrl;
var $returnCancelUrl;
var $paypalUserName;
var $paypalPassword;
var $paypalSignature;

function __construct($real = false) {
$this->endpoint = '/nvp';
if ($real) {
/*
* Production Credentials
*/
$this->host = "api-3t.paypal.com";
$this->gate = 'https://www.paypal.com/cgi-bin/webscr?';
} else {
/*
* Sendbox Credentials for testing purpose
*/
$this->host = "api-3t.sandbox.paypal.com";
$this->gate = 'https://www.sandbox.paypal.com/cgi-bin/webscr?';
}
}

/**
* @return string URL of the "success" page
*/
function getReturnTo() {
return $this->returnSuccessUrl;
}

/**
* @return string URL of the "cancel" page
*/
function getReturnToCancel() {
return $this->returnCancelUrl;
}

/**
* @return HTTPRequest
*/
function response($data){
$r = new HTTPRequest($this->host, $this->endpoint, 'POST', true);
$result = $r->connect($data);
if ($result->paypalUserName)
$data['PWD'] = $this->paypalPassword;
$data['SIGNATURE'] = $this->paypalSignature;
$data['VERSION'] = '51.0';
if(!function_exists('http_build_query')) {
$query = $this->http_build_query_php4($data);
} else {
$query = http_build_query($data);
}
return $query;
}
function http_build_query_php4($data,$b='',$c=0){
if (!is_array($data)) return false;
foreach ((array)$data as $key=>$value){
$pair[]=$key."=".urlencode($value);
}
return implode("&amp;",$pair);
}

/**
* Main payment function
*
* If OK, the customer is redirected to PayPal gateway
* If error, the error info is returned
*
* @param float $amount Amount (2 numbers after decimal point)
* @param string $desc Item description
* @param string $invoice Invoice number (can be omitted)
* @param string $currency 3-letter currency code (USD, GBP, CZK etc.)
*
* @return array error info
*/
function doExpressCheckout($amount, $desc, $invoice='', $currency='USD'){
$data = array(
'PAYMENTACTION' =>'Sale',
'AMT' =>$amount,
'RETURNURL' =>$this->getReturnTo(),
'CANCELURL'  =>$this->getReturnToCancel(),
'DESC'=>$desc,
'NOSHIPPING'=>"1",
'ALLOWNOTE'=>"1",
'CURRENCYCODE'=>$currency,
'METHOD' =>'SetExpressCheckout');

$data['CUSTOM'] = $amount.'|'.$currency.'|'.$invoice;
if ($invoice) $data['INVNUM'] = $invoice;

$query = $this->buildQuery($data);

$result = $this->response($query);

if (!$result) return false;
$response = $result->getContent();
$return = $this->responseParse($response);
if ($return['ACK'] == 'Success') {
header('Location: '.$this->gate.'cmd=_express-checkout&amp;useraction=commit&amp;token='.$return['TOKEN'].'');
die();
}
return($return);
}

function getCheckoutDetails($token){
$data = array(
'TOKEN' => $token,
'METHOD' =>'GetExpressCheckoutDetails');
$query = $this->buildQuery($data);

$result = $this->response($query);

if (!$result) return false;
$response = $result->getContent();
$return = $this->responseParse($response);
return($return);
}
function doPayment(){
$token = $_GET['token'];
$payer = $_GET['PayerID'];
$details = $this->getCheckoutDetails($token);
if (!$details) return false;
list($amount,$currency,$invoice) = explode('|',$details['CUSTOM']);
$data = array(
'PAYMENTACTION' => 'Sale',
'PAYERID' => $payer,
'TOKEN' =>$token,
'AMT' => $amount,
'CURRENCYCODE'=>$currency,
'METHOD' =>'DoExpressCheckoutPayment');
$query = $this->buildQuery($data);

$result = $this->response($query);

if (!$result) return false;
$response = $result->getContent();
$return = $this->responseParse($response);

/*
* [AMT] => 10.00
* [CURRENCYCODE] => USD
* [PAYMENTSTATUS] => Completed
* [PENDINGREASON] => None
* [REASONCODE] => None
*/

return($return);
}

function getScheme() {
$scheme = 'http';
if (isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') {
$scheme .= 's';
}
return $scheme;
}

function responseParse($resp){
$a=explode("&amp;", $resp);
$out = array();
foreach ($a as $v){
$k = strpos($v, '=');
if ($k) {
$key = trim(substr($v,0,$k));
$value = trim(substr($v,$k+1));
if (!$key) continue;
$out[$key] = urldecode($value);
} else {
$out[] = $v;
}
}
return $out;
}

function doDirectPayment($Order) {

$Order['METHOD'] = 'DoDirectPayment';

$query = $this->buildQuery($Order);

$result = $this->response($query);
if (!$result)
return false;
$response = $result->getContent();
return $this->responseParse($response);

}
}

Step 3: In your controller add

var $components=array( ‘Paypal’);

Step 4: For PayPal Express Check Out use somthing like

public function expressPaypalCheckOut(){
$this->Paypal->paypalUserName = $pyapal_settings['user'];
$this->Paypal->paypalPassword = $pyapal_settings['password'];
$this->Paypal->paypalSignature = $pyapal_settings['signature'];
$this->Paypal->returnSuccessUrl = "/success/url/returnByPaypal/pay?csid=" . session_id();
$this->Paypal->returnCancelUrl = "/cancel/url/returnByPaypal/cancel?csid=".session_id();
$ret = ($this->Paypal->doExpressCheckout($user_info["amount"], 'Access to source code library','','EUR')); // use USD for dollar
}

Step 5: For PayPal Direct Payment use somthing like

$order = array(
'PAYMENTACTION'=>'Sale',
'AMT'=> ($FREQUEST->postvalue('amount')/100),
'CREDITCARDTYPE'=>$FREQUEST->postvalue('card_type'),
'ACCT'=>$FREQUEST->postvalue('creditCard1'),
'EXPDATE'=>$FREQUEST->postvalue('expire_month').$FREQUEST->postvalue('expire_year'),
'CVV2'=>$FREQUEST->postvalue('cvvno'),
'FIRSTNAME'=> $session_information["billto_array"]["firstname"],
'LASTNAME'=> $session_information["billto_array"]["lastname"],
'STREET'=> $session_information["billto_array"]["street_address"],
'CITY'=>$session_information["billto_array"]["city"],
'STATE'=> $session_information["billto_array"]["state"],
'ZIP'=> $session_information["billto_array"]["postcode"],
'COUNTRYCODE'=> $session_information["billto_array"]["country"]["iso_code_2"],
'CURRENCYCODE'=> 'USD'</code>

);

$this->Paypal->paypalUserName = $pyapal_settings['user'];
$this->Paypal->paypalPassword = $pyapal_settings['password'];
$this->Paypal->paypalSignature = $pyapal_settings['signature'];
$this->Paypal->returnSuccessUrl = "/success/url/returnByPaypal/pay?csid=" . session_id();
$this->Paypal->returnCancelUrl = "/cancel/url/returnByPaypal/cancel?csid=".session_id();
$ret = ($this->Paypal->doDirectPayment($order));
</blockquote>

<strong>6</strong> Now after getting the responds from PayPal you need to reconfigure again the PayPal settings something like
<blockquote>
public function returnByPaypal($callback = null){
if ($callback == 'cancel') {
			$this->redirect("your/cancel/page");
	        exit;
	    } else if ($callback == 'pay') {
               $pyapal_settings = Configure::read('paypal_settings');
			$this->Paypal->paypalUserName = $pyapal_settings['user'];
			$this->Paypal->paypalPassword = $pyapal_settings['password'];
			$this->Paypal->paypalSignature = $pyapal_settings['signature'];
			$paypalRespons = $this->Paypal->doPayment();
                        if($paypalRespons['ACK'] == 'Success'){
                             /* your code in here*/
                        }
            }
}

Well, thats it. Please consider some syntax error or other cause i am not testing these code yet!!! enjoy ;)

Inspired from Martin Maly’s Paypal Library

[CakePHP] Unit Testing

What a fun !! :D
Today i test one of my Country Model using cakephp component. That why i write down this notes to make sure that i can use several times.

1. Download Simple Test unit testing suite.
2. Uncompress it in my app/vendors directory.
3. Change DEBUG level of 1 in my app/config/core.php file
4. Create a new database connection in app/config/database.php for only testing purpose like;

var $test = array(
‘driver’ => ‘mysql’,
‘persistent’ => true,
‘host’ => ‘localhost’,
‘login’ => ‘root’,
‘password’ => ”,
‘database’ => ‘db_name’,
‘prefix’ => ”,
‘encoding’ => ‘utf8′
);

5. Fixture : Create a file named country_test_fixture.php in your app/tests/fixtures directory, with the following content

<?php
class CountryTestFixture extends CakeTestFixture {

var $name = ‘CountryTest’;

var $import = array(‘model’ => ‘Country’, ‘records’ => true , ‘connection’ => ‘test’);

}
?>

6. Test Case : Create a file named country.test.php in your app/tests/cases/models directory, with the following contents:

<?php

loadModel(‘Country’);

class CountryTest extends Country {
var $name = ‘Country’;
//var $useDbConfig = ‘test_suite’;
}

class CountryTestCase extends CakeTestCase {

var $fixtures = array( ‘Country_test’ );

function testFindAll() {

$this->CountryTest =& new CountryTest();

$result = $this->CountryTest->findAll(“Country.country_id=1″);

$expected = array(

array (
‘Country’ => array( ‘country_id’ => 1, ‘region_id’ => 2 , ‘country’ => ‘Bangladesh’ ),

)

);

$this->assertEqual($result, $expected);

}

}
?>

7. Running My Test Case: Point my browser to http://tanveer-noman/myProject/test.php. Click on App Test Cases and find the link to your models/country.test.php. Click on that link.
Waoow!! I got a nice green screen saying that your test succeded.
;)

To know more

cake bake

CakePHP: Creating a route usage https (SSL connection)

While playing in my workspace i need to make a route which should be use a secure path. That means https (SSL connection). So after googled for while i got the idea. Basically what i need is.. when an user in my sing in page will go through via the ssl connection. After entering user name and password will validated and redirect in to another location. So usually user will go through in https protocol then again redirected into http.

Here what i did;

Well, obviously i use cake’s component

1. Create a file ssl.php into app/controllers/components/
paste this code

class SslComponent extends Object {

	var $components = array('RequestHandler');

	var $Controller = null;

	function initialize(&$Controller) {
		$this->Controller = $Controller;
	}

	function force() {
		if(!$this->RequestHandler->isSSL()) {
			$this->Controller->redirect('https://'.$this->__url(443));
		}
	}

	function unforce() {
		if($this->RequestHandler->isSSL()) {
			$this->Controller->redirect('http://'.$this->__url());
		}
	}

	/**This method updated from John Isaacks**/
	function __url($default_port = 80)
	{
		$port = env('SERVER_PORT') == $default_port ? '' : ':'.env('SERVER_PORT');
		return env('SERVER_NAME').$port.env('REQUEST_URI');
	}
}

you can find it also here but i added unforce() ;)

3. Now, in my case only when user click in to sign in or lend now, I need the https connection. Thats why, in my home controller i added this beforeRender() method, but make sure you assign this Ssl component.

var $components = array( 'Ssl' );
public function beforeRender(){

$action = array( 'signin', 'lendnow' );

if( in_array( $this->params['action'] , $action ) ){

     $this->Ssl->force();
}else{
     $this->Ssl->unforce();
}

}

So, i will create a secure connection with my apache server.
4. User now enter their user name and password and submit

5. If anyone click beside this they will have only http connection

That’s it

enjoy ;)

cakephp : $ajax.observeField and Session lost

Finlay i made the solution in my style… :)
In my cakePHP project when ever i made any Ajax request to my system… my session was lost.. and the new requested controller and action take the place on my session variable. I was totally mad.. because it takes my localization action away… The thing is when ever i change my combo box.. it calls the ajax request and reset my language session value and if any one click on the language flag on that moment my page layout was lost and broke down… :(

Solutions:

1. Change the CAKE_SECURITY in app core.php to a level of medium or low
(don't worry it will not make any hole in the system and someone says that it can be the solution anyway..)
2. In app_controller set
var $components=array('RequestHandler');
3. Now, inside the beforeRender() method...add
$current_session_value = $this->Session->read('my_sess_var') ;
// this is the session which i want to have it
//What i did just check is ther any Ajax request has occurred.. so i use isAjax()
if ( $this->RequestHandler->isAjax() ) {
$this->Session->write('my_sess_var', null ); //i reset that session which was use to store
$this->Session->write('my_sess_var', $current_session_value ); // re-assign again
}

yahoo…. my problem is solved… no i can change my language whenever i want…

:)

open-flash-chart in cakephp

Today i implement open-flash-chart into one of my cakephp project. The main goal of my work was to show a line graph with total amount of loan per month from june 2007 to till. Then take some time in google to find out some useful tutorials and i made my one way.

First i made the helper as describe in open-flash-chart-helper-draw-charts-the-cake-way from bakery. nice tutorial.
not so hard to implemnt..
what i did just maintain the vendor path
vendor(‘open-flash-chart’); in the flash_chart helper class class file
That’s it…

Follow

Get every new post delivered to your Inbox.

Join 286 other followers