Интеграция оплаты paypal

Деловые люди сталкивающиеся с интернетом хотят заработать денег, поэтому paypal позволяющий делать оплату кредитными картами по всему миру — ценнейшая услуга для интеграции на свой сайт. Примерные цены за услугу: 2-4% от суммы +  0,3$ за транзакцию зависит от типа оплаты.

У Paypal есть несколько возможностей оплаты товара, но к счастью они едины тем что это делается HTML-формой в которой просто разные входы обозначают разные процессы оплаты. Вот некоторые процессы которые можно сделать..

  •  Покупка в «один клик»
    • С передачей данных об оплате (Payment Data Transfer) — в обычном варианте процесс похож на pangalink. В качестве расширения можно включить авторедирект пользователя после оплаты.
    • Buy Now Hosted Button — упрощённая форма где все данные оплаты уже вбиты в paypal-админке. Хороший вариант для оплачиваемого хобби — например если вы продаёте например свой компакт-диск который один единственный для всего сайта.
    • C межсерверным оповещением (Instant Payment Notification)
  • Корзина
  • Подписка

Ниже я покажу процесс IPN. Для тестирования оплаты есть Sandbox-режим. Для более детального описания этого и других процессов почитайте старенькую но актуальную статью в phpclub

Процесс

В моём случае пользователь покупает «кредиты» (виртуальную валюту сайта) которую может потратить на разные внутренние услуги. Соответсвенно он может выбрать сколько денег он хочет потратить обычным radio-полем

  1. При открытии этой страницы в БД сразу регистрируется новый заказ со статусом «adding». Старые заказы с таким статусом удаляются.
  2. Пользователю показывается форма
  3. При её подтверждении пользователь переносится на сайт paypal где оплачивает услугу со всеми проверками
  4. При удачной оплате Paypal в фоновом режиме говорит серверу по notify_url о состоянии оплаты и именно в это время меняется статус заказа
  5. Пользователь перенаправляется на return URL где ему показывается состояние заказа

Форма

На нашем сайте надо установить HTML-форму с полями, для этого в контроллере я передаю в шаблон такие данные (упрощённые что-бы вам было легче понять)

$this->assign('paypal',array(
            'gate'               => 'https://www.paypal.com/cgi-bin/webscr',
//'https://www.sandbox.paypal.com/cgi-bin/webscr' для режима тестирования
            'receiver_email'     => '[email protected]',
            'description'        => 'Quarti.ru credits',
            'price'              => 10, //в долларах
            'order_id'           => $iOrder, //номер заказа
            'notify_url'         => 'http://quarti.ru/paypal_direct_responce/',
            'link_return'        => 'http://quarti.ru/payment_completed/'
            'link_cancel'        => 'http://quarti.ru/payment_failed/',
        ));

Дальше в шаблоне рисуем собственно форму

<form method="post" action="{$paypal.gate}" id="paypal_form">
    <input type="hidden" name="cmd"             value="_xclick" />
    <input type="hidden" name="business"        value="{$paypal.receiver_email}" />
    <input type="hidden" name="item_name"       value="{$paypal.description}" />
    <input type="hidden" name="item_number"     value="{$paypal.order_id}" />
    <input type="hidden" name="amount"          value="{$paypal.price}" />
    <input type="hidden" name="return"          value="{$paypal.link_return}" />
    <input type="hidden" name="cancel_return"   value="{$paypal.link_cancel}" />
    {if $paypal.notify_url}
    <input type="hidden" name="notify_url"  value="{$paypal.notify_url}" />
    {/if}
    <input type="hidden" name="no_shipping"     value="1" />
    <input type="hidden" name="rm"              value="2" />
</form>

Проверка

Когда пользователь оплачивает покупку, то paypal в фоновом режиме передаёт статус оплаты. Это необходимо что-бы иметь синхронизированную транзакцию даже если пользователь не вернётся на наш сайт после оплаты по каким-то причинам. Проверка простейшая — собираются все данные что «paypal» запостил и переспрашиваются у него через CURL. А дальше уже обновляются статусы в БД, пишется лог со временем, передача ошибок и тп.

private function verifyPaypalNotification($sGatewayURL,$sMerchantEmail,$sError){
    $postdata="";
    foreach ($_POST as $key=>$value) {
        $postdata.=$key."=".urlencode($value)."&";
    }
    $postdata .= "cmd=_notify-validate";
    $curl = curl_init($sGatewayURL);
    curl_setopt ($curl, CURLOPT_HEADER, 0);
    curl_setopt ($curl, CURLOPT_POST, 1);
    curl_setopt ($curl, CURLOPT_POSTFIELDS, $postdata);
    curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt ($curl, CURLOPT_SSL_VERIFYHOST, 1);
    $response = curl_exec ($curl);
    curl_close ($curl);
    if ($response != "VERIFIED") {
        $sError="TRANSACTION_NOT_VERIFIED";
        return false;
    }
    if (strtolower($_POST['receiver_email']) != $sMerchantEmail){
        $sError="INVALID_RECEIVER";
        return false;
    }
    if ($_POST["txn_type"] != "web_accept"){
        $sError="INVALID_TRANSACTION_TYPE";
        return false;
    }
    return true;
}