Подключение Paypal

    Вобщем поставили передо мной на работе задачу организовать прием платежей в наш проект через Paypal. От меня требовалось дать все необходимые данные для настройки аккаунта (сам аккаунт настраивался другим человеком), ну и, собственно, написать скрипт, который и будет принимать данные от paypal-а и начислять деньги юзерам.

    Ничего толкового по этой теме на хабре я не нашел. Пришлось разбираться со всем самому. Ниже – результаты этих разбирательств:)

    Виды платежей



    Paypal позволяет принимать несколько видов платежей. Вот некоторые из них:
    1. Buy now buttons – единоразовый платеж, для оплаты одного или нескольких товаров (услуг). Позволяет задавать сумму платежа, описание товаров (услуг), количество товаров, адрес, доставки, вес покупки и т.д. Сумму платежа можно и не задавать, в этом случае Paypal даст юзеру возможность самостоятельно указать сумму, которую хочет заплатить.
    2. Donate buttons – впринципе, по функционалу аналогична «Buy now», тоже единоразовый платеж, сумму можно задать как принудительно, так и оставить на усмотрение юзера. Отоичие в том, что не позволяет указать адрес доставки и все, что с ней (доставкой) связано.
    3. Add to cart buttons – позволяет создавать корзину из ваших товаров, на стороне Paypal`а. На вашем сайте юзер может только добавлять товары в корзину. Чтобы просмотреть содержимое корзины или удалить оттуда какие-либо позиции, придется залогиниться на Paypal.
    4. Subscribe buttons – позволяет организовать прием периодических платежей, например, оплата аккаунта, услуг.
    5. Еслть еще подарочные сертификаты, но с ними даже не пытался разобраться.

    В моем случае идеальным решением было использование платежей “Buy now”, о них и пойдет дальше речь.

    Заюзать “Buy now” на своем сайте можно двумя способами:
    1. создать кнопку c помощью инструментов Paypal’а.
    2. создать свою собственную форму.

    Лично я воспользовался вторым вариантом, хотя бы потому, что это позволяет использовать свой собственный дизайн. Хотя есть и еще пара плюшек, о них позже.

    Создание формы платежа



    Рaypal, что естественно, жестко регламентирует названия полей формы. Полный список этих полей можно найти на cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_html_Appx_websitestandard_htmlvariables. То что использовано у нас:
    — cmd = _xclick – указываем тип платежа “Buy now”;
    — business – тут указываем email, аккаунта, куда будут приниматься платежи. Сам адрес должен быть подтвержденным (подтверждается где-то в настройках аккаунта);
    — item_name – тут задаем описание товара/услуги. Будет отображаться в Paypal при проведении платежа;
    — custom – здесь служебная инфа, понадобится потом нам же для идентификации юзера;
    — amount – сумма платежа;
    — currency – валюта платежа. Возможные варианты Здесь.
    — no_shipping =1 – указываем, что доствка не осуществляется.

    Настройка аккаунта



    Далее, для приема платежей на свой аккаунт, этот самый аккаунт надо соответствующим образом настроить.

    Paypal поддерживает два метода передачи данных о транзакции нашему скрипту: PDT (Payment Data Transfer) и IPN (Instant Payment Notification). Насколько я понял, разница в том, что при использовании PDT от Paypal’а приходит одно единственное сообщение уже после совершения юзером платежа (т.е. когда деньги от юзера уже находятся на пути к вашему аккаунту). При использовании IPN Paypal генерирует несколько сообщений, оповещая нас о каждой отдельной стадии совершения платежа. Для решения моей задачи вполне хватало PDT, который я и заюзал.

    Процесс включения PDT описан Здесь. Там внизу есть раздел Activating PDT.

    Суть PDT — при завершении платежа, Paypalпосылает указанному скрипту GET- зарпос, в котором передает номер транзакции, её статус, сумму и т.д. У самого Paypal’a существует механизм проверки подлинности транзакции — мы отправляем POST-запрос определенного вида на их адрес с полученным номером транзакции. В ответ приходит либо код ошибки, либо описание транзакции — статус, сумма и еще куча всяких служебных данных.

    Алгоритм работы скрипта



    Собственно, что требуется от скрипта:
    1. получить эти данные.
    2. проверить тип транакции — если используется обычная оплата (buy now). то тип транзакции должен быть web_accept;
    3. проверяем емайл получателя платежа и id аккаунта получателя. (поля bussiness, receiver_email, receiver_id);
    4. в поле custom содержится служебная инфа полученная от нас, например
    ид юзера — проверяем его.
    5. в поле txn_id содежится номер транакции в системе paypal. проверяем
    чтобы не было повторных платежей.
    6. после этого, если поле payment_status = Complete, т.е. платеж
    нормально завершен, то проводим платеж уже у себя, при любом другом
    статусе — какие-то траблы.
    Сумма и валюта будут в полях mc_gross и mc_currency.
    Полный список все параметров передаваемых Paypal'ом при использовании PDT (да и при IPN тоже) Здесь.

    Теперь о тех плюшках, которые обещал раньше. Относятся они к полю custom, которое мы сами и отправляем Paypal’y. Можно, конечно, просто записать туда id юзера и не париться, но мы ведь легких путей не ищем. В это поле вполне можно записать id записи с описанием платежа в нашей системе, а уже там сохраняться юзера, запоминать тип услуги, к которую приобрел юзер, сумму и т.д. Это позволит, например, отслеживать покупки, которые так и не были оплачены, а также, при получении данных от Paypal’a, можно сверять с сохраненными у нас, что дает небольшой + к секьюрности.

    Ну и, напоследок, немного кода

    1. <?php
    2. //данная функция юзается для получения данных о транакции от Paypal'a
    3. //код самой функции взят с сайта Paypal'a там где-то есть примеры на различных языках
    4. function get_paypal_data($tx_token, $auth_token){
    5.   $req = 'cmd=_notify-synch';
    6.   $req .= "&tx=$tx_token&at=$auth_token";
    7.  
    8.   // post back to PayPal system to validate
    9.   $header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
    10.   $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
    11.   $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
    12.   $fp = fsockopen ('www.paypal.com'80, $errno, $errstr, 30);
    13.  
    14.   if (!$fp) {
    15.     // HTTP ERROR
    16.     return false;
    17.   } else {
    18.     fputs ($fp, $header . $req);
    19.     // read the body data
    20.     $res = '';
    21.     $headerdone = false;
    22.     while (!feof($fp)) {
    23.       $line = fgets ($fp, 1024);
    24.       if (strcmp($line, "\r\n") == 0) {
    25.         // read the header
    26.         $headerdone = true;
    27.       }elseif ($headerdone){
    28.         // header has been read. now read the contents
    29.         $res .= $line;
    30.       }
    31.     }
    32.   }
    33.   return $res;
    34. }
    35.  
    36. //из GET'a берем только id транакции, все остальное нас не интересует,  эти данные мы получим от Paypal'a  в ответе на наш запрос
    37. $tx = @$_GET['tx'];
    38. if (!$tx){
    39.   error_log('[paypal] ERROR: Tx are absent!!!');
    40.   return false;
    41. }
    42.  
    43. //отправляем запрос Paypal'y для получения данных о транзакции
    44. //PAYPAL_IDENTITY_TOKEN - константа с токеном, полученным при активации PDT
    45. $res = get_paypal_data($tx, PAYPAL_IDENTITY_TOKEN);
    46. $history .= ('[paypal] post request result for '.$tx."\n".$res);
    47. if (!$res){
    48.   $history .= ('[paypal] http error for '.$tx);
    49.   exit();
    50. }
    51.  
    52. //парсим ответ
    53. $strs = explode("\n", $res);
    54. if ($strs[0] == 'FAIL'){
    55.   //если первая строка FAIl - значит какая-то трабла
    56.   //обрабатываем ошибку как вам требуется и выходим
    57.   exit();
    58. } elseif ($strs[0] == 'SUCCESS'){
    59.   //вроде все нормально - парсим остальные параметры
    60.   $res_vars = array();
    61.  
    62.   //parse paypal answer to array where key it's varname
    63.   for($i=1; $i<count($strs);$i++){
    64.     $strs[$i] = trim($strs[$i]);
    65.     if (!$strs[$i]) continue;
    66.     $vars = explode('=', $strs[$i]);
    67.     if (!$vars || count($vars) != 2){
    68.       //какая-то трабла - переходим к следующему параметру
    69.       continue;
    70.     }
    71.     $res_vars[$vars[0]] = $vars[1];
    72.   }
    73.   //в итоге в массиве res_vars  у нас находятся все параметры транзакции
    74.  
    75.   //в поле  txn_type - содердится тип транзакции. нас интересует только web_accept
    76.   switch ($res_vars['txn_type']){
    77.     case 'web_accept':
    78.       //тут мы проверяем все остальные поля: bussiness, receiver_id...
    79.       // при необходимости парсим поле custom
    80.       // если все нормально, то  проверяем состояние платежа
    81.       switch (@$res_vars['payment_status']){
    82.         case 'Completed':
    83.         //все нормально - отправляем юзеру товар, начисляем деньги на виртуальный счет и т.д.
    84.         break;
    85.       }
    86.     break;
    87.   }
    88. }
    89. ?>
    90.  
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 40

      +2
      добавил в закладки. когда-нибудь пригодится.
      спасибо
        0
        В закладки, в закладки… Спасибо!
          0
          Рекомендую использовать оба метода идентификации платежа — PDT и IPN.
          Никак не реже чем раз в полгода IPN перестаёт работать на несколько часов, с чем это связано Paypal не объясняет в итоге транзакции остаются в подвешенном состоянии на это время, клиенты в недоумении.
          Если платежей много это может быть критично.
            0
            ну и пусть IPN перестает работать, у нас то PDT?
              0
              иногда (5%-15%) клиентов оплатив в Paypal и увидив надпись «Ура, Вы успешно потратили свои деньги» закрывают страницу и не возвращаются на сайт соответственно PDT не сработает.
                +1
                не совсем, в случае какой-либо ошибки Paypal выдаст её и оставит у себя на сайте, но если платеж проводится нормально, то сам Paypal ничего не говорит, а сразу редиректит к нам на сайт.
                за это, вроде как, отвечает параметр Auto return в настройках аккаунта.
                  0
                  Да, всё верно, но для некоторых людей даже большие красные слова «Вернись на сайт после оплаты» ничего не значат. Они просто закрывают страницу. Это удивительно, но так случается. И в таком случае Вам нужно будет вручную добавлять покупку в том время как с IPN это не прийдётся делать (кроме описанного выше раз-полгода-мистицизма).
                    0
                    Слово «авто» ничего вам не говорит?)
            0
            >IPN Paypal генерирует несколько сообщений, оповещая нас о каждой отдельной стадии совершения платежа
              +1
              А также продолжает уведомлять наш скрипт при оплате, в течении 4 дней после оплаты, если наш сайт не доступен.
                0
                так вроде и с PDT тоже самое? нет?
            • UFO just landed and posted this here
                0
                поправил, спс
                0
                Огромное вам спасибо, в закладки!
                • UFO just landed and posted this here
                    0
                    Вы из Москвы ведь? Значит вы или как-то обошли запрет PayPal на работу в России, или этот проект зарубежный? Если обошли, то было бы интересно узнать ваши варианты решения.

                    P.S. Очень интересная и хорошая статья, спасибо!
                      0
                      не могу ничего сказать насчет аккаунта, создавал и настраивал не я.
                      я просто дал, адрес скрипта, получил необходимый токен и все.
                      сори)
                        0
                        Эх, разрушил последнюю надежду :(
                        0
                        Мне тоже это интересно, но что то автор молчит
                          0
                          Обойти-то можно, вопрос в целесообразности расходов и потенциальной прибыли.
                          Никто вам не мешает открыть счёт или создать юр лицо в странах европы или сша.
                            0
                            Да, да, а теперь поделитесь кто-нибудь схемами работы с PayPal из России?
                            0
                            статья не плохая, спасибо, но пейпал имел нас ввиду (насчёт получения денег — Россия и Украина) и будет «иметь» нас ещё долго…
                            • UFO just landed and posted this here
                                +2
                                Ничего толкового по этой теме на хабре я не нашел.

                                Ни Хабром единым… phpclub.ru/detail/article/paypal

                                Упомянули бы, кстати, ещё и о песочнице paypal'a — полном аналоге paypal.com, позволяющей тестировать форму покупки без необходимости тратить реальные деньги.
                                  0
                                  Да, действительно про песочницу забыл, каюсь
                                  0
                                  Прикручивал через IPN оплату, процесс намного проще, чем, например у платежных терминалов (вроде QIWI). В самом простом случае это килобайт кода.
                                  Выбор в пользу IPN был за его большую надежность.
                                    0
                                    То что на мой взгляд упущено

                                    1. Можно создать кнопку на сайте PayPal ( hosted_button_id, и потом менять ее параметры на сайте типа валюты платежа, показывать или нет сумму и так далее ) и при этом в форме использовать дополнительные поля. Внешний вид — всего лишь ссылка — меняется на любой имеющийся у PayPal или свою.
                                    Форму вставлять придется по-любому — браузер просто не умеет работать по другому.

                                    2. При PDT ничего никуда PayPal не посылает. Просто в форму можно ввести параметр return в котором указать URL, на который будет у кнопки ( с текстом cbt ) на финальной странице платежа.
                                    Пользователь может нажать кнопку, а может и не нажать. Если не нажмет, то придется смотреть в платежи ( поле custom ) и делать нужное действие вручную.

                                    И в целом как-то сумбурно. На PayPal и то понятнее :)
                                      0
                                      При активации PDT можно включить «Auto return», и тогда в форме ничего указывать не надо, и не надо нажимать на финальной странице платежа никакой кнопки, paypal сам отправит к юзера к тебе на сайт, и не придется лезть в платежи и руками что-то проводить

                                      может и сумбурно, но есть люди, которые уже воспользовались статьей и пикрутили себе paypal:)
                                        0
                                        Хм, уже не один десяток сайтов окучил PayPal, но auto return первый раз вижу, спасибо. :)

                                        Я больше скажу — PayPal настолько популярен что прикручивать его приходиться только под scratch developed скайты. Подо все остальное есть модули.
                                          0
                                          возможно нубский вопрос — что такое scratch developed сайты?:)
                                            +1
                                            без использования CMS и готовых шаблонов.
                                              0
                                              ясно, будем знать)
                                        0
                                        и про кнопку я писал, что её можно создать средствами paypal'a, тольк смысла не вижу в этом
                                          0
                                          Менять условия платежа, не меняя код и не вводя дополнительные параметры на сайте.
                                            0
                                            условия платежа — это сумма, валюта и т.д.?
                                        0
                                        Спасибо за статью. Сохранил у себя, т.к. может пригодиться при монетизации свеого проекта.
                                          +1
                                          всегда пожалуйста)
                                          кстати, если кого интересует, могу написать про подключение вебманей и яндекс.денег
                                            +1
                                            кстати, может стоит перенести топик в какой-то специфический блог (ну там, посвященный РНР или платежным системам)?
                                              0
                                              а существующие веб-магазины с плагинами не рассматривались?
                                              некоторые из них предлагают разные типы paypal-платежей
                                                0
                                                Я так понимаю, что этот код никто не проверял… Пропали все нолики.

                                                Строка 54:
                                                if ($strs[0] == 'FAIL'){
                                                

                                                58:
                                                } elseif ($strs[0] == 'SUCCESS'){
                                                

                                                71:
                                                    $res_vars[$vars[0]] = $vars[1];
                                                

                                                И 24:
                                                 if (strcmp($line, "\r\n") == 0) {

                                                Only users with full accounts can post comments. Log in, please.