Прием платежей PayPal

Думаю каждый из разработчиков тех или иных сервисов или систем сталкивался с необходимость приема платежей на сайте. Большинство закзачиков ограничиваются подключением системы Webmoney, робокассы и все, да и по большому счету этого достаточно если проект ориентирован на жителей СНГ, однако если превалирующая аудитория проекта это европейцы, которые и знать не знают что такое Webmoney или просто не имеют возможности пополнить кошелек этой системы приходиться задумываться о подключении такой системы как PayPal. Именно с такой ситуацией я и столкнулся работаю над крупным проектом ориентированным на жителей Германии. Честно говоря это был мой первый опыт знакомства с платежной системой PayPal, что могу сказать, остался доволен, хотя есть и свои минусы, но об этом дальше.

В интернете есть ума статей, хотя нет, как правило это одна и та же статья прошедшая через небольшой рерайт, в которых описано как организовать оплату плюшек у себя на сайте через систему PayPal, однако большинство кода безнадежно устарело. На самом деле как оказалось на сайте paypal есть огромное количество информации о том как можно организовать прием денег через эту систему у себя на сайте, но есть два огромных минуса:

1. Эти гигабайты информации практически не структурированы, так что приходится тратить уйму времени для того что бы найти нужную.

2. Вся информация на английском языке, хотя может это и не совсем минус, ну или не для всех.

Но есть и достаточно много плюсов, основные, которые особенно понравились мне это наличие так называемой песочницы (sandbox) в которой можно создать себе нужно количество тестовых аккаунтов, с нужным балансом и тестировать прием платежей.

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

Для приема платежей нам потребуется форма отправки, код которой представлен ниже

<form action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post"> <input name="cmd" type="hidden" value="_xclick" /> <input name="business" type="hidden" value="murik2_1308603338_biz@gmail.com" / <input name="item_name" type="hidden" value="Ticketing. Order #5" /> <input name="item_number" type="hidden" value="5" /> <input name="amount" type="hidden" value="123" /> <input name="no_shipping" type="hidden" value="1" /> <input name="rm" type="hidden" value="2" /> <input name="return" type="hidden" value="http://site.ru/order/success/" /> <input name="cancel_return" type="hidden" value="http://site.ru/order/fail/" /> <input name="currency_code" type="hidden" value="EUR" /> <input name="notify_url" type="hidden" value="http://site.ru/order/paypallistener/" /> <input type="submit" value="Платить через PayPal" /> </form>

давайте теперь разберем что мы передаем и в какой переменной

1. адрес — так как мы пока в песочнице то и адрес https://www.sandbox.paypal.com/cgi-bin/webscr для выхода из песочницы достаточно просто убрать sandbox из строки адреса

2. cmd — обязательный параметр. Должен иметь значение «_xclick»

3. business — обязательный параметр — e-mail продавца

4. item_name — наименование товара, которое будет показано покупателю

5. item_number — идентификатор товара. Это значение не будет показано пользователю, однако будет передано вашему скрипту при подтверждении транзакции. Если вы используете PayPal для оплаты товаров из корзины, в этом поле можно передавать идентификатор корзины

6. amount — сумма к оплате. Если этот параметр не передать, покупателю будет предоставлена возможность ввести сумму самостоятельно(используется для donations)

7. no_shipping — не запрашивать адрес для доставки. «1» — не запрашивать адрес, «0» — запрашивать

8. rm — этот параметр определяет, как будет передаваться информация об успешно завершенной транзакции скрипту, указанному в параметре return. «1» — никакие параметры передаваться не будут.»2″ — будет использоваться метод POST. «0» — будет использоваться метод GET. По умолчанию «0».

9. return — URL, куда покупатель будет перенаправлен после успешной оплаты. Если этот параметр не передать, покупатель останется на сайте PayPal

10. cancel_return — URL, куда покупатель будет перенаправлен при отмене им оплаты . Если этот параметр не передать, покупатель останется на сайте PayPal

11. currency_code — код валюты. Возможные значения: «USD»,»EUR»,»GBP»,»YEN»,»CAD». По умолчанию «USD»

12. notify_url — URL, на который PayPal будет предавать информацию о транзакции (IPN). Если не передавать этот параметр, будет использоваться значение, указанное в настройках аккаунта. Если в настройках аккаунта это также не определено, IPN использоваться не будет

Теперь давайте рассмотрим сам процесс приема оплаты через систему PayPal, после того как мы сформировали форму, с нужной информацией и пользователь кликнул на кнопку оплатить, он перенаправляется на сайт paypal где ему предлагается либо войти в уже имеющийся аккаунт, либо пройти процедуру регистрации. После того как покупатель осуществил оплату Paypal отправляет информацию о платеже на адрес который мы указали в notify_url где можно или даже нужно провести проверку как оплатили, сколько, и когда. После чего Paypal предлагает пользователю вернуться на сайте откуда он пришел.

Думаю сейчас самое время рассмотреть так называемый paypal listener в котором по сути и осуществляется проверка оплаты и другие нужные действия на стороне продавца.

Для удобства отладки, да и вообще на всякий случай будем вести небольшой лог ответов от paypal в файлик ipn.log

<? $log = fopen("ipn.log", "a"); fwrite($log, "\n\nipn - " . gmstrftime ("%b %d %Y %H:%M:%S", time()) . "\n"); $req = "cmd=_notify-validate"; foreach($_POST as $key=>$val) { $req.= "&".$key."=".urlencode($val); fwrite($log,$key."=".$val."\n"); } $header = "POST http://www.paypal.com/cgi-bin/webscr HTTP/1.0\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . strlen ($req) . "\r\n\r\n"; $fp = fsockopen ("www.sandbox.paypal.com", 80, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)"; fwrite($log, "Failed to open HTTP connection!\n"); fwrite($log, $errstr." ".$errno); fclose ($log); return; } fputs ($fp, $header . $req); $res=""; while (!feof($fp)) $res .= fgets ($fp, 1024); fclose ($fp); if (strpos($res, "VERIFIED")===FALSE) { fwrite($log,"ERROR - UnVERIFIIED payment\r\nPayPal response:"); fwrite($log,$res); fclose($log); return; } fwrite($log,"payment VERIFIIED\r\n"); if ($_POST["payment_status"]!="Completed") { if ($_POST["payment_status"]=="Pending" ) { fwrite($log,"ERROR - payment status is not Completed - $_POST[payment_status] | $_POST[pending_reason]\r\n"); fclose($log); // а тут отмечаем заказ как оплаченный, но требующий подтверждение оплаты со стороны плательщика // такое бывает редко, но все же бывает и лучше подстраховаться. return; } fwrite($log,"ERROR - payment status is not Completed - $_POST[payment_status] | $_POST[pending_reason]\r\n"); fclose($log); return; //update order status } fwrite($log,"OK - payment received $_POST[item_number].\r\n"); // тут отмечаем заказ оплаченным. // деньги уже на счету продавца fclose($log); ?>

Как вы видите у нас есть три варианта завершения платежа, это «оплачено и деньги поступили к нам на счет», «оплачено, но требуется подтверждение платежа», «оплата закончилась не удачей» первый вариант конечно самый оптимальный, но иногда может быть и второй, например тогда, когда валюта в которой платят и валюта в которой выставлен счет не совпадает, конечно же paypal все успешно переведет в нужную валюту, но попросит плательщика подтвердить транзакцию так же есть и другие случаи.

В общем то это и все что я хотел вам рассказать.