Библиотека для работы с QIWI через SOAP

от автора

Так уж получилось, что мы решили у себя подключить прием платежей через QIWI. Сказано — сделано! Вот только в процессе разработки пришлось столкнуться с убогостью примеров кода от разработчиков киви:

Код сервера, принимающего запрос от киви

<?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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *