APIs e Microsserviços

18 jan, 2012

Integração com Express Checkout em PHP

Publicidade

Uma das grandes vantagens do uso do Express Checkout como solução de pagamento para o comerciante é o aumento das taxas de conversão. Com ele, o cliente não precisa inserir informações pessoais na aplicação, o checkout é muito simples, amplamente aceito e mantém o cliente dentro da loja após a finalização da compra. Já para o desenvolvedor, a grande vantagem está justamente na facilidade de integração, que pode ser feita em 4 passos simples:

  1. Adição do botão de checkout na tela de pagamento.
  2. Adição do comportamento (click) no botão para integrar com o PayPal utilizando a operação da API do Express Checkout.
  3. Na tela de finalização, utilize a operação da API do Express Checkout para recuperar o endereço de entrega e aceitar o pagamento.
  4. Testes no sandbox.

Vamos começar este artigo com a adição do botão. Para isso, iremos até Express Checkout – Button Code para gerar a imagem.

 <img src="https://www.paypal.com.br/pt_BR/i/btn/btn_xpressCheckout.gif" align="left" style="margin-right:7px;"> 

Isso gerará a seguinte imagem (percebam o pt_BR para localização do texto do botão):

Faça checkout com o paypal

Com a imagem gerada, criamos um formulário HTML, no qual adicionaremos o comportamento ao botão:

 <html>
    <head>
        <title>Express Checkout</title>
        <style type="text/css">
            #ec-button {
                cursor: pointer;
                margin-right: 7px;
            }
        </style>
    </head>
    <body>
        <form id="checkout" action="checkout.php" method="post">
            <span>Total </span><span>RINSERT:CONTENT:ENDnbsp;100.00</span><br />
            <img id="ec-button" src="https://www.paypal.com.br/pt_BR/i/btn/btn_xpressCheckout.gif" onclick="checkout.submit();" />
        </form>
    </body>
</html>

Esse formulário fará uma postagem ao checkout.php, que, por sua vez, é bastante simples:

 <?php
$total = 100.00; //Total do carrinho do cliente

$nvp = array(
    'PAYMENTREQUEST_0_AMT'                => $total,
    'PAYMENTREQUEST_0_CURRENCYCODE'        => 'BRL',
    'PAYMENTREQUEST_0_PAYMENTACTION'    => 'Sale',
    'RETURNURL'                            => 'http://127.0.0.1/paypal/retorno.php',
    'CANCELURL'                            => 'http://127.0.0.1/paypal/cancelamento.php',
    'METHOD'                            => 'SetExpressCheckout',
    'VERSION'                            => '64',
    'PWD'                                => 'xxxx',
    'USER'                                => 'login.do.usuario',
    'SIGNATURE'                            => 'assinatura'
);

$curl = curl_init();

curl_setopt( $curl , CURLOPT_URL , 'https://api-3t.sandbox.paypal.com/nvp' );
curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false );
curl_setopt( $curl , CURLOPT_RETURNTRANSFER , 1 );
curl_setopt( $curl , CURLOPT_POST , 1 );
curl_setopt( $curl , CURLOPT_POSTFIELDS , http_build_query( $nvp ) );

$response = urldecode( curl_exec( $curl ) );
$responseNvp = array();

curl_close( $curl );

if ( preg_match_all( '/(?<name>[^\=]+)\=(?<value>[^&]+)&?/' , $response , $matches ) ) {
    foreach ( $matches[ 'name' ] as $offset => $name ) {
        $responseNvp[ $name ] = $matches[ 'value' ][ $offset ];
    }
}

if ( isset( $responseNvp[ 'ACK' ] ) && $responseNvp[ 'ACK' ] == 'Success' ) {
    $paypalURL = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
    $query = array(
        'cmd'    => '_express-checkout',
        'token'    => $responseNvp[ 'TOKEN' ]
    );

    header( 'Location: ' . $paypalURL . '?' . http_build_query( $query ) );
} else {
    echo 'Falha na transação';
}

Um ponto que pode ser notado no código acima é que podemos utilizar, na URL de retorno e de cancelamento, durante os testes no sandbox, como nossa URL local http://127.0.0.1. Isso torna mais práticos nossos testes agiliza o desenvolvimento. Após a requisição ao checkout.php ser concluída, o cliente é direcionado ao ambiente seguro do PayPal para fazer login, confirmar os dados da transação e, logo após a confirmação de todos os dados, o usuário é redirecionado à URL de retorno definida no campo RETURNURL da requisição. Na URL de retorno, o PayPal enviará um token de identificação da transação; com essa informação, conseguiremos fazer uma nova chamada à operação da API PayPal para verificar o sucesso da operação e recuperar os dados do cliente:

 <?php
if ( isset( $_GET[ 'token' ] ) ) {
    $token = $_GET[ 'token' ];

    $nvp = array(
        'TOKEN'                                => $token,
        'METHOD'                            => 'GetExpressCheckoutDetails',
        'VERSION'                            => '64',
        'PWD'                                => 'xxxx',
        'USER'                                => 'login.do.usuario',
        'SIGNATURE'                            => 'ASSINATURA'
    );

    $curl = curl_init();

    curl_setopt( $curl , CURLOPT_URL , 'https://api-3t.sandbox.paypal.com/nvp' );
    curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false );
    curl_setopt( $curl , CURLOPT_RETURNTRANSFER , 1 );
    curl_setopt( $curl , CURLOPT_POST , 1 );
    curl_setopt( $curl , CURLOPT_POSTFIELDS , http_build_query( $nvp ) );

    $response = urldecode( curl_exec( $curl ) );
    $responseNvp = array();

    curl_close( $curl );

    if ( preg_match_all( '/(?<name>[^\=]+)\=(?<value>[^&]+)&?/' , $response , $matches ) ) {
        foreach ( $matches[ 'name' ] as $offset => $name ) {
            $responseNvp[ $name ] = $matches[ 'value' ][ $offset ];
        }
    }

    if ( isset( $responseNvp[ 'TOKEN' ] ) && isset( $responseNvp[ 'ACK' ] ) ) {
        if ( $responseNvp[ 'TOKEN' ] == $token && $responseNvp[ 'ACK' ] == 'Success' ) {
            echo '<pre>';
            print_r( $responseNvp );
            echo '</pre>';
        } else {
            echo 'Nãoo foi possível concluir a transação';
        }
    } else {
        echo 'Não foi possível concluir a transação';
    }
}

Isso nos dará uma matriz com um conteúdo semelhante ao seguinte:

 Array
(
    ..
    [EMAIL] => email.do.cliente@dominio.com
    [PAYERID] => X0X0X0XXXX0XX
    [PAYERSTATUS] => verified
    [FIRSTNAME] => Usuário
    [LASTNAME] => teste
    [COUNTRYCODE] => BR
    [SHIPTONAME] => Usuário de teste
    [SHIPTOSTREET] => Endereço
    [SHIPTOCITY] => Cidade do usuário
    [SHIPTOSTATE] => SP
    [SHIPTOZIP] => 123456789
    [SHIPTOCOUNTRYCODE] => BR
    [SHIPTOCOUNTRYNAME] => Brasil
    [ADDRESSSTATUS] => Confirmed
    [CURRENCYCODE] => BRL
    [AMT] => 100.00
    ...
)

Com as informações retornadas pela operação GetExpressCheckoutDetails, podemos concluir a transação fazendo apenas um ajuste no código da página de retorno:

 <?php
if ( isset( $_GET[ 'token' ] ) ) {
    $token = $_GET[ 'token' ];

    $nvp = array(
        'TOKEN'                                => $token,
        'METHOD'                            => 'GetExpressCheckoutDetails',
        'VERSION'                            => '64',
        'PWD'                                => 'xxxx',
        'USER'                                => 'login.do.usuario',
        'SIGNATURE'                            => 'ASSINATURA'
    );

    $curl = curl_init();

    curl_setopt( $curl , CURLOPT_URL , 'https://api-3t.sandbox.paypal.com/nvp' );
    curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false );
    curl_setopt( $curl , CURLOPT_RETURNTRANSFER , 1 );
    curl_setopt( $curl , CURLOPT_POST , 1 );
    curl_setopt( $curl , CURLOPT_POSTFIELDS , http_build_query( $nvp ) );

    $response = urldecode( curl_exec( $curl ) );
    $responseNvp = array();

    if ( preg_match_all( '/(?<name>[^\=]+)\=(?<value>[^&]+)&?/' , $response , $matches ) ) {
        foreach ( $matches[ 'name' ] as $offset => $name ) {
            $responseNvp[ $name ] = $matches[ 'value' ][ $offset ];
        }
    }

    if ( isset( $responseNvp[ 'TOKEN' ] ) && isset( $responseNvp[ 'ACK' ] ) ) {
        if ( $responseNvp[ 'TOKEN' ] == $token && $responseNvp[ 'ACK' ] == 'Success' ) {
            $nvp[ 'PAYERID' ]                            = $responseNvp[ 'PAYERID' ];
            $nvp[ 'PAYMENTREQUEST_0_AMT' ]                = $responseNvp[ 'PAYMENTREQUEST_0_AMT' ];
            $nvp[ 'PAYMENTREQUEST_0_CURRENCYCODE' ]        = $responseNvp[ 'PAYMENTREQUEST_0_CURRENCYCODE' ];
            $nvp[ 'METHOD' ]                            = 'DoExpressCheckoutPayment';
            $nvp[ 'PAYMENTREQUEST_0_PAYMENTACTION' ]    = 'Sale';

            curl_setopt( $curl , CURLOPT_POSTFIELDS , http_build_query( $nvp ) );

            $response = urldecode( curl_exec( $curl ) );
            $responseNvp = array();

            if ( preg_match_all( '/(?<name>[^\=]+)\=(?<value>[^&]+)&?/' , $response , $matches ) ) {
                foreach ( $matches[ 'name' ] as $offset => $name ) {
                    $responseNvp[ $name ] = $matches[ 'value' ][ $offset ];
                }
            }

            if ( $responseNvp[ 'PAYMENTINFO_0_PAYMENTSTATUS' ] == 'Completed' ) {
                echo 'Parabéns, sua compra foi concluída com sucesso';
            } else {
                echo 'Não foi possível concluir a transação';
            }
        } else {
            echo 'Não foi possível concluir a transação';
        }
    } else {
        echo 'Não foi possível concluir a transação';
    }

    curl_close( $curl );
}

Como podemos ver, Express Checkout é vantajoso:

  1. Para nós, como desenvolvedores, pois é muito simples de implementar.
  2. Para nossos clientes, pois aumenta a taxa de conversão e é mundialmente aceito.
  3. Para os clientes de nossos clientes, pois oferece um ambiente seguro, simples e confiável no qual o usuário não precisará informar seus dados pessoais diretamente na loja.

O código utilizado neste artigo poderá ser encontrado na íntegra em Code Sample e, caso encontrem alguma dificuldade na implementação, o Fórum do PayPal X Brasil possui uma categoria dedicada ao Express Checkout. No nosso próximo artigo, demonstraremos como integrar o Express Checkout em uma aplicação mobile e disponibilizaremos uma aplicação de exemplo. Então, até lá.