how to implement paypal in cakephp?
January 6, 2010 12 Comments
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("&",$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&useraction=commit&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("&", $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



I found a small error in line 72 see this
while ($read_length header = chop($responseHeader);Falopa!
but it seems okay to me !!
Pingback: 2010 in review « Tanveer's Weblog
I think two end braces are left at line 78. But really this code is very helpful. I am implementing it in my project.
Thanks for the code.
Thanks Ankita for your comment.
Source code edited.
Hi! Tanveer,
You have written good code here but there is some error in this code I just trying to make you notice over it:
1. at line 72:
while ($read_length header = chop($responseHeader);
what is header here
2. $this->buildQuery(); is undefined in your component.
3. at line 161 : if ($resultpaypalUserName;
Invalid syntax wont identify that how many lines is to come in the condition coz end braces also missing.
Please Correct them I need to Use this script onto my Project.
I shall be very thankful to you!
Hi Ashok,
Thanks for visiting my blog.
For this moment please try with the Martin Maly’s Paypal Library
and do the necessary changes as I did for your CakePHP project.
I will fix the error as soon as possible.
Best,
Tanveer
Hello Tanveer,
Where to save step 4 and 5 contents in files?
thanks
Hi Sav,
Step 4. is nothing but a method name in your controller where you want to call expressPaypalCheckOut()
Step 5. is for Direct Payment. This step is also depends on your business logic and you can use in
your controller. So make $order array first.
$order = array( … ); Then, you must need to call:
$this->Paypal->doDirectPayment($order);
Feel free to drop comments if any!
Hello Tanveer,
I’m getting same error.
1. at line 72:
while ($read_length header = chop($responseHeader);
thanks
Interesting. I might try this method if the methods I’m trying to implement won’t work