Настраиваем прием платежей на своем сайтеСергей «gurza» Попиневский brain@bidiko.ru Есть идея! Да, совершенно точно этот проект сможет принести деньги! Пусть небольшие, но деньги. Но стоит ли затевать весь сыр-бор, если я не смогу организовать прием платежей? Будут ли связываться со мной крупные платежные системы или отправят лесом? Да и насколько сложно это технически? Вот и разберемся на практике. Помнится, много лет назад я хотел организовать прием платежей через Webmoney. Все желание пропало, когда я прочитал, сколько волокиты с этим связано: невнятные технические решения, необходимость получения сертификата. Словом, игра не стоила свеч. С тех пор, конечно, многое изменилось, но проблемы отчасти остались те же. Если говорить о серьезном проекте с большими инвестициями, то проблем в сотрудничестве с платежными системами быть не должно. Но совсем другое дело – скажем, совсем небольшой Интернет-магазин, у которого на первых порах совсем нет оборота. А его требуют, выдвигают условия и, более того, заставляют пройти все круги ада, оформляя всевозможные документы. Вот и получается логический тупик: пока у тебя нет нормальной клиентской базы и репутации, ты не можешь полноценно сотрудничать с разными платежными системами. А пока у тебя нет возможности принимать платежи, о какой клиентской базе может идти речь? К счастью, есть приятные исключения. Если ты прочитал статью «Налаживаем систему приема платежей» (или ее PDF-версию на нашем диске), то должен знать, каким образом можно принять платеж по кредитной карте или по SMS. Особо тепло мы отзывались о Robokassa'е (www.robokassa.ru), позволяющей избавиться от геморроя общения напрямую с разными системами оплаты. Задумайся, хочется ли тебе договариваться по отдельности с каждой системой электронных платежей, получать какие-то непонятные сертификаты, высылая кипу юридических бумаг, и ожидая, что какой-нибудь манагер проверит, все ли ты выслал и правильно ли заполнил анкеты. За небольшой процент с каждой транзакции можно одним махом подключить самые разные варианты платежей, предоставив пользователям максимальное удобство и право выбора. Хочешь прием платежей через электронные деньги (Янднекс.Деньги, Webmoney и другие)? Запросто! Хочешь предложить самый простой вариант оплаты – через SMS? Тоже нет проблем. Для многих оплата по кредитной карте стала нормой – и ты можешь это предложить. Ах да, забыли про пресловутые терминалы для оплаты? Поддерживаются, сразу 9 различных сетей. И это далеко не весь список. При этом ты ведешь бухгалтерию только с одной системой, предоставляешь пользователям удобный единый интерфейс – и отдаешь 5% с продаж за отсутствие головной боли. Но в данной ситуации, не менее важно и другое. Система крайне лояльно хорошо относится к небольшим проектам, в том числе самым начинающим! А значит, имея желание, прямые руки, минимальное знание PHP (+ curl) и фрейморка jQuery, тебе под силу поднять свой маленький бизнес в Сети. Организация платежа через RoboKassaВ общем-то, язык программирования совсем необязательно должен быть PHP, но мы возьмем его для простоты примера. Взаимодействие с RoboKassa осуществляется через специальный API-интерфейс. Другими словами, есть несложные правила обмена данными между электронным магазином и сервисом для приема. Если следовать правилам, то работать с системой можно как угодно: будь у тебя скрипты на PHP, Perl или, скажем, ASP или Python – неважно. Один из способов передать сообщение сервису – сформировать HTTP-запрос и передать его методом GET или POST по специальному URL’у https://merchant.roboxchange.com. Далее магазин отправляет пользователя по данному адресу для произведения им оплаты. Общая схема взаимодействия магазина и платежки RoboKassa выглядит следующим образом:
URL-адреса Result-скрипта и страниц Success, Fail могут быть указаны и изменены в личном кабинете на сайте RoboKassa в любое время. 1.В листинге ниже приведен алгоритм формирования URL-адреса, по которому мы должны перенаправить клиента для совершения оплаты: Разберемся с каждым из параметров запроса, передаваемого методом GET.
Последний параметр, который мы еще не рассмотрели, SignatureValue – это цифровая подпись, которая представляет собой значение хеш-функции md5 от строки "$mrh_login:$out_summ:$inv_id:$mrh_pass1:Shp_item=$shp_item:Shp_user=$shp_user". Для того чтобы подпись не смог подделать злоумышленник, строка содержит переменную $mrh_pass1 – первый пароль мерчанта. Всего паролей два, оба задаются в личном кабинете на сайте RoboKassa. Важно помнить, что для однозначности дополнительные параметры запроса должны следовать в алфавитном порядке. 2.Робокасса отображает пользователю интерфейс для оплаты, с учетом тех параметров, которые мы передали через URL. Клиент выбирает удобный для себя вариант оплаты покупки и подтверждает намерение произвести перевод денег. 3.Для того чтобы сообщить магазину об исходе транзакции, Робокасса особым образом формирует ответ и передает его специальному Result-скрипту, который должен сделать следующее: во-первых, считать данные из ответа, во-вторых, сформировать по этим данным проверочную подпись (используется второй пароль) и проверить, чтобы подпись из ответа была равна проверочной. Если подписи различны, то скрипт должен вернуть строку Bad sign, иначе OK<%номер заказа%>. В листинге ниже я привел основную часть Result-скрипта.
Остальные действия, которые могут быть выполнены в Result-скрипте, зависят от конкретной реализации твоего инет-магазина. Но нужно обязательно записать данные о проведенной операции, то есть, образно говоря, пробить чек. Взгляд сверхуТеперь, когда ты знаком со спецификаций API-интерфейса RoboKassa, перейдем к разработке платежки для магазина. Наша основная цель – написать интерфейс для оплаты некоторой услуги. При разработке любого интерфейса мы должны в первую очередь помнить о его юзабильности, поэтому разрабатываемый интерфейс должен удовлетворять следующим критериям. 1. Требуется выводить полный список поддерживаемых платежных систем, логически разделенных по группам (электронные деньги, терминалы, банковские переводы и т.д.). Покупатель может выбрать тот способ, которым ему наиболее удобно внести плату. Покажем покупателю, что мы о нем заботимся и предоставляем большой выбор вариантов оплаты. 2. На странице со списком поддерживаемых платежек должна быть указана конечная стоимость услуги в этой платежки. Человек – существо рациональное, и очень часто бывает, что выбор платежки обусловлен только максимальной дешевизной. Покажем сразу конечную стоимость – честно поможем выбрать наиболее подходящий вариант. Таким образом, нам нужно реализовать страницу со списком платежек, при входе на которую должен запускаться ajax-скрипт, запрашивающий курсы (по сути, конечную стоимость) по всем платежкам, затем производящий парсинг ответа и подставляющий полученные значения на страницу. Нам также понадобится библиотека curl: зачем это нужно и как с ней работать, станет понятно по ходу разработки функционала. Создаем каркасИнтерфейс платежки будет находиться в payments.php. Входными данными этого скрипта является параметр $item – номер товара/заказа (зависит от реализации магазина), который передается методом GET. Скрипт payments.php сначала выводит информацию о заказе, а затем (для наглядности) таблицу с логотипами поддерживаемых платежных систем. Ниже приведена структура скрипта payments.php.
Для простоты в скрипте payments.php (как и все остальные скрипты ты можешь найти его на диске) вместо обращения к базе данных товаров магазина, я использую обычный оператор выбора switch. Когда же ты будешь писать рабочий скрипт для своего магазина, учти, что кроме выбора сведений о товаре из базы данных, тебе будет необходимо бронировать товар в соответствующей таблице. Естественно, что бронировать нужно на время, которое выделяется пользователю на оплату выбранного им товара. По истечении данного интервала времени товар должен быть автоматически снят с брони. Есть исключение: ты продаешь товар, который не может окончиться на складе (например, внутренняя электронная валюта сайта), или ты просто перекупаешь товар в других магазинах и автоматизировать процесс проверки наличия товара просто невозможно. Рассмотрим структуру таблицы pay_table. Для каждой поддерживаемой платежки выделяем по две ячейки: первая для логотипа, вторая для указания стоимости платежа вида: вместо PayCode будут указаны соответствующие идентификаторы для платежек. Например, для Яндекс.Денег – это PCR.
Линки подобного вида повесим на каждый логотип платежки и строку, содержащую цену товара. XML-интерфейс RoboKassa и jQueryЕще одна проблема – отобразить стоимость товара в разных валютах, для чего нам потребуется узнать курсы для каждой из поддерживаемых платежек. Получить курсы можно через XML-интерфейс RoboKassa. Для этого необходимо составить и отправить XML-запрос методом POST по адресу www.roboxchange.com/xml/rate.asp. Запрос имеет следующий вид:
Тут OUTCURR – идентификатор исходящей валюты (определяется при регистрации мерчанта в системе RoboKassa), LOGIN – логин мерчанта, CNT – на какую сумму будет совершена покупка. XML-ответ от RoboKassa согласно спецификации протокола будет иметь вид
где:
каждый тег <rate> описывает один курс, поэтому их будет столько, сколько платежек было подключено через RoboKassa.
Функции getXML() передается два параметра. Первый параметр url – непосредственно URL-адрес, куда необходимо отправить запрос. Второй параметр cnt – стоимость товара в магазине. Функции, на которые ссылаются переменные в теле метода ajax(), а именно, xmlStart, xmlSuccess, xmlError, xmlComplete, я разберу позже. А пока необходимо решить одну проблему. Дело в том, что в качестве параметра url нельзя передавать ссылку на документ, который находится на другом домене. PHP-прокси и XMLHttpRequestМетод ajax() библиотеки jQuery для пересылки данных использует API-функцию XMLHttpRequest. Благодаря технологии XMLHttpRequest возможно выполнить HTTP-запрос, не перезагружая страницу. Чтобы злоумышленникам было сложнее проводить XSS-атаки, XMLHttpRequest не работает с внешними доменами. Например, если мы пишем скрипт script.js, который находится на сервере serv1.com, то не получится отправить запрос на serv2.com методом XMLHttpRequest. Для решения этой проблемы мы напишем небольшой прокси-скрипт rk_rate_proxy.php. Схема взаимодействия следующая: rk_xml_int.js с помощью XMLHttpRequest отправляет XML-запрос rk_rate_proxy.php (расположен на нашем сервере), который с помощью библиотеки curl ретранслирует запрос к XML-интерфейсу RoboKassa, считывает ответ и возвращает его. Приступим. Код отправки XML-запроса через библиотеку curl выглядит следующим образом:
Переменная $url – адрес XML-интерфейса RoboKassa, объявляется непосредственно в rk_rate_proxy.php. Переменная $request – это, в свою очередь, XML-запрос, структуру которого мы разбирали ранее:
Для запроса используется тестовая учетная запись мерчанта – demo. Библиотека curl очень проста в освоении, и очень изящна. Чтобы это оценить, посмотри на листинг чтения ответа и возвращения результата
Все, скрипт PHP-прокси rk_rate_proxy.php написан. Теперь вернемся к парсеру. Добиваем парсерAjax-запросы теперь ходят через прокси, XMLHttpRequest работает, так как запрос идет на скрипт в своем домене. Осталось разобраться с функциями, на которые ссылаются переменные метода ajax(). Сначала второстепенные. Функция xmlStart() вызывается перед отправкой XML-запроса. С помощью данной функции я изменяю CSS-стиль для элемента div с id=xmlConsole. Стиль ajaxLoaderCSS отображает картинку в бэкграунде – статус выполнения запроса. Кстати спешу порекомендовать онлайн-сервис www.ajaxload.info, который поможет сгенерировать всевозможные статусбары на любой вкус и цвет. Код функции xmlStart() приведен в листинге ниже. Как ясно из названия xmlError(), данная функция вызывается, если в ходе выполнения XML-запроса произошла ошибка. В случае возникновения ошибки выводится сообщение для пользователя и скрывается div-"обертка" с логотипами платежных систем.
По завершению XML-запроса сначала выполняется функция xmlComplete(), в теле которой у элемента с id=xmlConsole удаляется CSS-стиль ajaxLoaderCSS, а затем xmlSuccess(), в теле которой и происходит вызов функции parseXML() – парсер для обработки XML-ответа. Реализация функции parseXML() наглядно демонстрирует основной принцип библиотеки jQuery – принцип ненавязчивого JavaScript, листинг ее приведен ниже.
Теперь парсер написан полностью. Чтобы инициализировать XML-запрос, распарсить его и вывести результат в payments.php пишем
Функция getXML() будет вызвана при загрузке страницы, точнее после того, как браузер построит DOM-структуру документа. МодернизируйВот и готов каркас для приема платежей через Робокассу. Полностью рабочие скрипты ты можешь использовать и своих проектах, практически сходу наладив прием платежей. Сложно ли это было? Нет! Сам процесс работы с Робокассой очень прост. Больше времени ушло на оболочку, внешний вид, обустройства интерфейса для того, чтобы пользователю было удобно. Но именно это и важно для конечного клиента. И теперь нам есть что ему предложить. Cемь раз – отмерьКрайне важно досконально оттестировать скрипты, имеющие отношение к оплате. Хочу обратить твое внимание на одну деталь, а точнее предупредить тестеров скриптов. Если твой Result-скрипт будет недоступен или вернет в качестве ответа "bad sign", то это не значит, что платеж клиента не пройдет и/или будет отменен, наоборот, он скорее пройдет. Если пункт 2 общей схемы взаимодействия твоего магазина и RoboKassa, описанной в разделе организации платежа через RoboKassa, выполнен успешно, то платеж уже откатить нельзя. В этот момент деньги уже снялись с электронного счета клиента, более того, они уже перешли на твой счет в RoboKassa, о чем ты незамедлительно получишь уведомление на рабочий email. Поэтому тестируй все внимательно, с деньгами все-таки приходится работать реальными! Основную отладку нужно проводить на тестовом сервере RoboKassa, URL и спецификацию по работе с которым легко найти в разделе технической документации на официальном сайте. DVDНа диске ты найдешь исходники скриптов для организации приема платежей |