Question:
I've been researching how to integrate PayPal in my online stores for some time now, the ones I build from 0 to the final step which is payment, but when I went to the PayPal website to learn more about the integration I came across some problems, which was to interpret the NVP (Name-Pair-Value), in order to connect with the PayPal API and define the methods or requests to start until completing the purchase, but after a series of research and studies of OpenSource scripts, despite they seem complex, I was able to understand them as a whole, and I was also able to integrate PayPal ExpressCheckout into my store.
The main questions are:
How do I connect to the PayPal API without compromising my credentials?
How do I define the necessary methods for ExpressCheckout?
How do I know the purchase was made or completed without errors?
Answer:
ExpressCheckout is used to make secure purchases/sales on the PayPal website and at the end of the purchase, the customer returns to the user's or company's website.
To understand how PayPal's ExpressCheckout works, you first have to understand its working flow.
Store -> Order (SetExpressCheckout) -> Server Responds With Token -> HTTP Redirection with &token= -> ->Return URL + TOKEN -> Order (GetExpressCheckoutDetails) -> Response -> Order (DoExpressCheckoutPayment) -> Response (Success/ Failure) -> Order Complete
Connecting with PayPal API.
<?php
class paypal{
//Função de conexão com a API
function api($comando,$param){
$api = 'https://api-3t.sandbox.paypal.com/nvp'; # URL para o modo sandbox
$api_user = urlencode('<API_USUARIO>');
$api_senha = urlencode('<API_SENHA>');
$api_assinatura = urlencode('<API_ASSINATURA>');
$api_versao = urlencode('109.0'); # Esta é a versão da API a ser utilizada
$i = curl_init();
# Definimos uma cabeçalho para a requisição
curl_setopt($i, CURLOPT_URL, $api);
curl_setopt($i, CURLOPT_VERBOSE, 1);
#Desactivar a verificação do servidor e do peer
curl_setopt($i, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($i, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($i, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($i, CURLOPT_POST, 1);
//Passando os parâmetros da API
$nvp = "METHOD=$comando&VERSION=$api_versao&PWD=$api_senha&USER=$api_user&SIGNATURE=$api_assinatura$param";
//Definindo o nvp como campo POST do cURL
curl_setopt($i, CURLOPT_POSTFIELDS, $nvp);
$resposta = curl_exec($i);
curl_close($i);
if(!$resposta){
exit("Erro do $comando ".curl_error($i)."(".curl_errno($i).")");
}
#Aqui transformamos a nossa URL numa array associativa
$respostaP = $this->nvp($resposta);
if(0 == sizeof($respostaP) || !array_key_exists('ACK',$respostaP)){
exit("HTTP resposta inválida do servidor($nvp) para $api");
}
return $respostaP;
}
// função para converter a resposta da cURL em array
function nvp($resposta){
$i = explode('&',$resposta);
$respostaP = array();
foreach($i as $key=>$value){
$d = explode('=',$value);
if(sizeof($d)>1){
$respostaP[$d[0]] = $d[1];
}
}
return $respostaP;
}
}
?>
After defining the connection variables, you can then define the methods to be called to initiate and complete the purchase.
<?php
//Iniciamos a sessão
session_start();
//Incluimos a nossa classe
include_once('paypal.php');
//Se for utilizar o modo live, deixe a variavel $paypalmodo com o ponto(.) apenas
$paypalmodo = '.sandbox';
$moeda = 'USD';
$urlRetorno = 'http://site.com/retorno';
$urlCancela = 'http://site.com/cancela';
//Parte que trata do SetExpressCheckout
if(isset($_POST) && !empty($_POST)){
$itemNome = $_POST['itemNome'];
$itemPreco = $_POST['itemPreco'];
$itemQnt = $_POST['itemQnt'];
$itemTotal = ($itemPreco*$itemQnt);
$taxa = 1.50;
$total = ($itemTotal + $taxa);
$nvpData = '&METHOD=SetExpressCheckout'.
'&RETURNURL='.urlencode($urlRetorno).
'&CANCELURL='.urlencode($urlCancela).
'&PAYMENTREQUEST_0_PAYMENTACTION='.urlencode('Sale').
'&L_PAYMENTREQUEST_0_NAME0='.urlencode($itemNome).
'&L_PAYMENTREQUEST_0_AMT0='.urlencode($itemTotal).
'&L_PAYMENTREQUEST_0_QTY0='.urlencode($itemQnt).
'&NOSHIPPING=0'.
'&PAYMENTREQUEST_0_ITEMAMT='.urlencode($itemTotal).
'&PAYMENTREQUEST_0_TAXAMT='.urlencode($taxa).
'&PAYMENTREQUEST_0_AMT='.urlencode($total).
'&PAYMENTREQUEST_0_CURRENCYCODE='.urlencode($moeda).
'&LOCALECODE=BR'.
'&LOGOIMG='.'http://site.com/logo_a_utilizar_caso_tenha.jpg'.
'&CARTBORDERCOLOR=45D765'.
'&ALLOWNOTE=1';
//Definindo as as variaveis de SESSAO
$_SESSION['itemNome'] = $itemNome;
$_SESSION['itemPreco'] = $itemPreco;
$_SESSION['itemQnt'] = $itemQnt;
$_SESSION['itemTotal'] = $itemTotal;
$_SESSION['taxa'] = $taxa;
$_SESSION['total'] = $total;
//Instanciado a class paypal e chamando a função de conexão api('SetExpressCheckout','paramentros_da_url')
$paypal = new paypal();
$resposta = $paypal->api('SetExpressCheckout',$nvpData);
if('SUCCESS' == strtoupper($resposta['ACK']) || 'SUCCESSWITHWARNING' == strtoupper($resposta['ACK'])){
//Url de redirectionamento com os parâmetros inseridos
$paypalUrl = 'https://www'.$paypalmodo.'.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='.$resposta["TOKEN"].'';
header('Location:'.$paypalUrl);
} else {
echo '<div style="color:red"><b>Erro : </b>'.urldecode($resposta["L_LONGMESSAGE0"]).'</div>';
}
echo '<pre>';
print_r($resposta);
echo '</pre>';
}
//Parte que trata do DoExpressCheckout
if(isset($_GET['token']) && isset($_GET['PayerID'])){
$token = $_GET['token'];
$payer_id = $_GET['PayerID'];
$itemNome = $_SESSION['itemNome'];
$itemNum = $_SESSION['itemNum'];
$itemQnt = $_SESSION['itemQnt'];
$itemTotal = $_SESSION['itemTotal'];
$taxa = $_SESSION['taxa'];
$total = $_SESSION['total'];
$nvpData = '&TOKEN='.urlencode($token).
'&PAYERID='.urlencode($payer_id).
'&PAYMENTREQUEST_0_PAYMENTACTION='.urlencode("Sale").
'&L_PAYMENTREQUEST_0_NAME0='.urlencode($itemNome).
'&L_PAYMENTREQUEST_0_AMT0='.urlencode($itemPreco).
'&L_PAYMENTREQUEST_0_QTY0='.urlencode($itemQnt).
'&PAYMENTREQUEST_0_ITEMAMT='.urlencode($itemTotal).
'&PAYMENTREQUEST_0_TAXAMT='.urlencode($taxa).
'&PAYMENTREQUEST_0_AMT='.urlencode($total).
'&PAYMENTREQUEST_0_CURRENCYCODE='.urlencode($moeda);
//Instanciando a class paypal e chamando a função api('DoExpressCheckoutPayment','paramentros_da_url')
$paypal = new paypal();
$resposta = $paypal->api('DoExpressCheckoutPayment',$nvpData);
if('SUCCESS' == strtoupper($resposta['ACK']) || 'SUCCESSWITHWARNING' == strtoupper($resposta['ACK'])){
echo "<h2 style='color:green;'>Concluído</h2>";
echo "ID da sua compra: ".$resposta['PAYMENTINFO_0_TRANSACTIONID'];
if('Completed' == $resposta['PAYMENTINFO_0_PAYMENTSTATUS']){
session_destroy();
echo '<div style="color:green">Pagamento completo! Obrigado pela compra.</div>';
} else if('Peding' == $resposta['PAYMENTINFO_0_PAYMENTSTATUS']){
echo '<div style="color:red">Transação completa, mas o pagamento precisa de ser aprovado manualmente na sua <a target="_new" href="http://www.paypal.com">Conta do PayPal</a></div>';
}
//Parte Responsavel por pegar os detalhes da transação
//Esta parte só é exibida se a transação for efectuada com sucesso ou retornar Success
$nvpData = '&TOKEN='.urlencode($token);
$paypal = new paypal();
$resposta = $paypal->api('GetExpressCheckoutDetails',$nvpData);
if('SUCCESS' == strtoupper($resposta['ACK']) || 'SUCCESSWITHWARNING' == strtoupper($resposta['ACK'])){
echo '<br /><b>Coisas para adicionar no banco de dados :</b><br /><pre>';
echo '<pre>';
print_r($resposta);
echo '</pre>';
} else {
echo '<div style="color:red"><b>GetTransactionDetails failed:</b>'.urldecode($resposta["L_LONGMESSAGE0"]).'</div>';
echo '<pre>';
print_r(urldecode($resposta));
echo '</pre>';
}
} else {
//Esta parte é responsavel por verificar o erro caso a chamada api('DoExpressCheckoutPayment','paramentros') falhe.
echo "Erro :".urldecode($resposta['L_LONGMESSAGE0']);
echo "<pre>";
foreach($resposta as $id=>$valor){
echo "<div style='color:red; border:2px solid #ccc;'>[".$id."] => ".urldecode($valor)."<br/></div>";
}
echo "</pre>";
}
}
?>
And finally the page responsible for providing the data about the item by the POST method.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Site.com(LOJA)</title>
<style type="text/css">
body {background-color:#D7D7D7;}
*{font-family: Tahoma, Geneva, sans-serif;}
h1 {text-align:center; color:#333; font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;}
h4 {color:#333; font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;}
table {border:1px solid #666; border-radius:5px 5px 5px 5px; box-shadow:1px 0px 1px #999 inset; background-color:#F2F2F2; margin:0 auto;}
input {border:1px solid #333; border-radius:4px 5px 5px 5px; box-shadow:1px 0px 1px #999 inset; padding:5px; margin-top:2px;}
input:hover {background-color:#FFF; transition:ease-in-out 0.4s; box-shadow:1px 0px 1px #CCC inset;}
</style>
</head>
<body>
<?php
$moeda = 'USD';
?>
<h1>Site.com</h1>
<table border="0" cellpadding="4">
<tr>
<td width="70%"><h4>Bilhetes Platina</h4>(Se vai ao concerto logo a noite, esta é a sua melhor chance de ficar na fila V.I.P)</td>
<td width="30%">
<form method="post" action="checkout.php">
<input type="hidden" name="itemNome" value="Bilhetes Platina" />
<input type="hidden" name="itemPreco" value="20.00" />
Quantidade : <select name="itemQnt"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>
<input type="submit" value="Comprar (20.00 <?php echo $moeda; ?>)" />
</form>
</td>
</tr>
</table>
</body>
</html>