<?php /** * На этот скрипт приходят уведомления от QIWI Кошелька. * SoapServer парсит входящий SOAP-запрос, извлекает значения тегов login, password, txn, status, * помещает их в объект класса Param и вызывает функцию updateBill объекта класса TestServer. * * Логика обработки магазином уведомления должна быть в updateBill. */ $s = new SoapServer('IShopClientWS.wsdl', array('classmap' => array('tns:updateBill' => 'Param', 'tns:updateBillResponse' => 'Response'))); // $s = new SoapServer('IShopClientWS.wsdl'); $s->setClass('TestServer'); $s->handle(); class Response { public $updateBillResult; } class Param { public $login; public $password; public $txn; public $status; } class TestServer { function updateBill($param) { // Выводим все принятые параметры в качестве примера и для отладки $f = fopen('c:\\phpdump.txt', 'w'); fwrite($f, $param->login); fwrite($f, ', '); fwrite($f, $param->password); fwrite($f, ', '); fwrite($f, $param->txn); fwrite($f, ', '); fwrite($f, $param->status); fclose($f); // проверить password, login // В зависимости от статуса счета $param->status меняем статус заказа в магазине if ($param->status == 60) { // заказ оплачен // найти заказ по номеру счета ($param->txn), пометить как оплаченный } else if ($param->status > 100) { // заказ не оплачен (отменен пользователем, недостаточно средств на балансе и т.п.) // найти заказ по номеру счета ($param->txn), пометить как неоплаченный } else if ($param->status >= 50 && $param->status < 60) { // счет в процессе проведения } else { // неизвестный статус заказа } // формируем ответ на уведомление // если все операции по обновлению статуса заказа в магазине прошли успешно, отвечаем кодом 0 // $temp->updateBillResult = 0 // если произошли временные ошибки (например, недоступность БД), отвечаем ненулевым кодом // в этом случае QIWI Кошелёк будет периодически посылать повторные уведомления пока не получит код 0 // или не пройдет 24 часа $temp = new Response(); $temp->updateBillResult = 0; return $temp; } } ?>
Я конечно понимаю, пример исчерпывающий, но можно ведь было что-нибудь «поготовее» выложить? Поскольку система популярна, как и язык PHP — я решил сразу вынести библиотеку в публичный репозитарий, дабы упростить жизнь тем, кому только предстоит подключать эту систему. Так как в недавнем моем вопросе никто против поста не возражал — выкладываю ее тут.В библиотеке есть как клиентская, так и серверная часть. Подключается элементарно — выгружаем через git или добавляем зависимость в composer (nick4fake/ishop). Основная работа идет через экземпляр класса IShop\Client. Например, можно от него наследоваться, и в конструкторе указать имя/пароль магазина, а класс оформить как сервис Symfony2 (так у нас сделано):
<?php namespace MyOwnMegaPrefix\Qiwi; use MyOwnMegaPrefix\Settings; use IShop; class Qiwi extends IShop\Client { protected $settings; public function __construct( Settings $settings // Нечто, что выдает нам настройки ) { $this->settings = $settings; parent::__construct( $this->settings->get('qiwi.login'), $this->settings->get('qiwi.pass') ); } }
Работа клиентом (это тот, кто запросы на SOAP-сервер шлет) элементарна — берем экземпляр IShop\Client и вызываем соответствующие методы. Они — лишь простые обертки над классом для работы с php-soap, преобразовывают параметры, да код возврата меняют на более подробный статус. Поля даты — в \DateTime, все остальное — соответствует api qiwi (только логин/пароль дублировать не нужно).Работа с сервером чуть сложнее. Поскольку методы сервера вызываются весьма хитро (SOAP же), было решено использовать замыкания для обработки запроса. Да, не забываем отключить сертификат x509 в настройках. Я так и не нашел способа прикрутить WSSE к php-soap (насколько я понял, никто не нашел). Обидно то, что в примере кода для Java проверка сертификата есть.
use IShop\ServerMethods\CheckBillResponse as QiwiBill; $callback = function ($bill) use (&$myMegaService) { /** @var QiwiBill $bill */ $row = $myMegaService->findByKey( // Ищем чек в нашей базе $bill->id ); if (!$row) { throw new \Exception('Неправильный код чека'); } $myMegaService->process($row); // Что-то делаем с этим return $myMegaService->status(); // Код возврата для сервера QIWI. 0 - все нормально }; $theIShopObject->processRequest($callback); // Вызываем метод обработки запроса header('Content-Type: text/xml; charset=utf-8'); // Если мы отдадим text/html, qiwi не пропустит платеж (да и вообще, надо протоколу следовать)
Удобно? Мне кажется — да. Вы можете просто сравнить с альтернативным путем. Итак, преимущества библиотеки:
- Можно вообще не задумываться о SOAP, WSDL и т.д. Все просто работает.
- Для сервера есть проверка подписи, после обновления статуса, чек повторно подгружается с сервера (как рекомендуют доки киви).
- PHPDoc и все-все-все, так сложнее ошибиться. Кое-где есть дополнительные уточнения (где грабли лежат).
- Статусы расшифровываются (код -> текст).
- Есть в packagist, подключение займет 2 минуты.
- Нормально работает с автолоадером.
Само-собой, есть минусы:
Какой-то стрёмный тип предлагает вам выписывать чеки через его библиотеку.- PHP 5.3. Замыкания + неймспейсы. Если вас это не устраивает, повырезать новое не составит труда.
Ссылки: описание протокола, пример кода, репозитарий.Уже после того, как система была прикручена, я узнал о готовой библиотеке для работы с киви — от пользователя JekaRu. Значит, будет больший выбор. 🙂 Спасибо за внимание. Если будут замечания касательно чистоты кода — с радостью внемлю (только не говорите, что не PRS, я к нему еще не готов).
ссылка на оригинал статьи http://habrahabr.ru/post/162185/
Добавить комментарий