четверг, 4 сентября 2008 г.

XML-интерфейсы WebMoney. Часть 3. X1, X3, X4, X9, X14, X16 (2)

Интерфейс X4. Проверка выписанных счетов.

С помощью этого интерфейса вы можете получать историю выписанных счетов и проверять их состояние (оплачен, не оплачен, отказан в оплате), а также проверять состояние конкретного счёта по его номеру. Полное описание интерфейса находится здесь. Интерфейс по умолчанию включен для всех пользователей WebMoney и не имеет никаких специальных требований по активации.

Интерфейс довольно сложный, но очень похож на рассмотренный выше X3. "Поведение" этого интерфейса тоже во многом зависит от того, какие именно входные параметры он получает в XML-запросе пользователя.

Наш XML-запрос должен выглядеть так:

<w3s.request> <reqn></reqn> <wmid></wmid> <sign></sign> <getoutinvoices> <purse></purse> <wminvid></wminvid> <orderid></orderid> <datestart></datestart> <datefinish></datefinish> </getoutinvoices> </w3s.request>

Что означают параметры:

  • reqn - номер запроса, всякий раз должен быть больше предыдущего (в рамках данного отдельно взятого интерфейса);
  • wmid - ваш WMID;
  • sign - подпись запроса, сформированная из параметров: purse + reqn;
  • getoutinvoices\purse - номер вашего кошелька, по которому вы хотите получить историю выписанных счетов;
  • getoutinvoices\wminvid - номер счёта в системе WebMoney;
  • getoutinvoices\orderid - номер счёта в системе учёта вашего сайта;
  • getoutinvoices\datestart - минимальная дата и время выписки счёта;
  • getoutinvoices\datefinish - максимальная дата и время выписки счёта.

Формат ответа сервера WebMoney следующий:

<w3s.response> <reqn></reqn> <retval></retval> <retdesc></retdesc> <outinvoices cnt="n" > <outinvoice id="n1" ts="n2"> <orderid></orderid> <customerwmid></customerwmid> <storepurse></storepurse> <amount></amount> <desc></desc> <address></address> <period></period> <expiration></expiration> <state></state> <datecrt></datecrt> <dateupd></dateupd> <wmtranid></wmtranid> </outinvoice> <outinvoice>...</outinvoice> </outinvoices> </w3s.response>

В ответе нас, прежде всего, интересует поле <retval> (eсли оно равно 0, то история счетов получена успешно, в противном случае retval будет содержать код ошибки, расшифровку которой нужно смотреть в поле <retdesc>). Также нас будет интересовать атрибут cnt поля <outinvoices>, в котором содержится количество счетов, попавших в выборку. Кроме того, мы "уложим" в структуру массивов полученную выборку счетов, а именно их уникальные номера в базе данных WebMoney (атрибуты id полей <outinvoice>) и состояния оплаты (поля <state>). Мы детально опишем всё это ниже, когда будем рассматривать работу функции.

Приведем теперь полностью функцию, которая реализует работу с интерфейсом X4, и добавим её в wmxml.inc.php:

// ИНТЕРФЕЙС X4. ПРОВЕРКА ВЫПИСАННЫХ СЧЕТОВ. // На выходе: массив ['retval'=>код выполнения, 'retdesc'=>описание результата, // 'cnt'=>количество счетов вошедших в выборку, 'invoices'=>массив со счетами] function _WMXML4 ($purse,$wminvid,$orderid,$datestart,$datefinish) { global $Global_WMID, $XML_addr; $reqn=_GetReqn(); $rsign=_GetSign($purse.$reqn); $xml=" <w3s.request> <reqn>$reqn</reqn> <wmid>$Global_WMID</wmid> <sign>$rsign</sign> <getoutinvoices> <purse>$purse</purse> <wminvid>$wminvid</wminvid> <orderid>$orderid</orderid> <datestart>$datestart</datestart> <datefinish>$datefinish</datefinish> </getoutinvoices> </w3s.request>"; $resxml=_GetAnswer($XML_addr[4], $xml); //echo $resxml; $xmlres = simplexml_load_string($resxml); if(!$xmlres) { $result['retval']=1000; $result['retdesc']="Не получен XML-ответ"; return $result; } $result['retval']=strval($xmlres->retval); $result['retdesc']=iconv("UTF-8", "CP1251", strval($xmlres->retdesc)); $result['cnt']=strval($xmlres->outinvoices->attributes()->cnt); if($result['cnt']>0) { // В элементе $result['invoices'] формируем массив // [номер счёта в WM] = состояние оплаты foreach ($xmlres->outinvoices->outinvoice as $invoice) { $wminvid=strval($invoice->attributes()->id); $state=strval($invoice->state); $result['invoices'][$wminvid]=$state; } } return $result; }

Разберём, что происходит в этой функции.

Функция получает переменные:

  • $purse - номер вашего кошелька, по которому вы хотите получить историю выписанных (исходящих) счетов. Напомним, что счета в системе WebMoney выставляются "от имени" конкретного кошелька, вот именно этот свой кошелёк и необходимо указать в данной переменной. Обязательный параметр.
  • $wminvid - уникальный номер счёта в системе WebMoney, присвоенный ему во время выписки. Целое положительное число. Необязательный параметр.
  • $orderid - номер счёта во внутренней системе учёта вашего сайта. Этот номер вы сами присваиваете счёту при выписке (см. интерфейс X1). Целое положительное число. Необязательный параметр.
  • $datestart - минимальная дата и время выписки счёта в формате ГГГГММДД ЧЧ:ММ:СС. Счета, выставленные раньше $datestart, в выборку не попадут. Обязательный параметр.
  • $datefinish - максимальная дата и время выписки счёта в формате ГГГГММДД ЧЧ:ММ:СС. Счета, выставленные позднее $datefinish, в выборку не попадут. Обязательный параметр.

Здесь всё очень похоже на интерфейс X3. Переменные: $purse (пойдет в поле getoutinvoices\purse XML-запроса), $datestart (пойдет в поле getoutinvoices\datestart XML-запроса) и $datefinish (пойдет в поле getoutinvoices\datefinish XML-запроса) - являются обязательными! Если вы не зададите какое-либо из этих полей, интерфейс выдаст ошибку. Отсюда вывод: интерфейс X4 всегда должен знать, по какому кошельку и за какой период времени запрашивается история исходящих счетов. Если вам вдруг захочется получить полную историю за всё время существования кошелька, то задайте, например, $datestart="19700101 00:00:00" и $datestart="20990101 00:00:00".

Переменные: $wminvid (пойдет в поле getoutinvoices\wminvid XML-запроса) и $orderid (пойдет в поле getoutinvoices\orderid XML-запроса) - являются необязательными. Если обе эти переменные не заданы, то выбираются все счета по кошельку за указанный промежуток времени - так, как это описано в предыдущем абзаце. Если задана переменная $wminvid, то в выборку попадёт только один счёт, имеющий именно такой уникальный номер в базе данных WebMoney, однако лишь при условии, что он был выписан с указанного кошелька $purse и в указанный промежуток времени $datestart - $datefinish. Если задана переменная $orderid, то в выборку попадут счета, имеющие именно такой внутренний номер в учетной системе вашего сайта и удовлетворяющие условиям, что они были выписаны с указанного кошелька $purse и в указанный промежуток времени $datestart - $datefinish. Поскольку внутренний номер в вашей учетной системе - это неуникальное поле (иными словами, вы могли выписать несколько счетов с одинаковым orderid), то в такой выборке может оказаться не один счёт, а несколько. Если в getoutinvoices\orderid будет передан 0, то интерфейс посчитает, что orderid вообще не передан и является пустым. Наконец, если заданы одновременно и переменная $wminvid, и переменная $orderid, то $orderid будет проигнорирован интерфейсом.

Отсюда ещё один вывод: $wminvid и $orderid, если заданы, сужают выборку и, как правило, ограничивают её одним единственным счётом. Откуда можно узнать wminvid и orderid конкретного интересующего нас счёта, мы уже рассказывали, когда говорили об интерфейсе X3. Повторим.

Уникальный номер (в базе данных WebMoney) WM-счёта ($wminvid):

  • может быть получен от интерфейса X1 при выписке счёта;
  • может быть получен из истории операций с помощью интерфейса X3;
  • передаётся вашему серверу при оплате через WM Merchant в форме оповещения о платеже, т.к. при оплате через WM Merchant тоже, незаметно для покупателя и продавца, создаётся счёт;

Номер (в системе учёта выставителя) WM-счёта ($orderid):

  • назначается вами самостоятельно при выписке счёта в интерфейсе X1;
  • может быть получен из истории операций с помощью интерфейса X3;
  • может быть получен от интерфейса X2 при оплате по счёту с соответствующим wminvid;

Всё это может показаться вам слишком сложным, однако на самом деле вам важно лишь определиться, каким именно образом вы будете использовать интерфейс X4. Как правило, единственная задача, которая стоит перед разработчиком при использовании X4 - автоматически проверить состояние оплаты выписанных ранее счетов. Для этого есть два пути:

  1. Путь первый. Робот на вашем сайте запускается с определённой периодичностью и запрашивает информацию по всем счетам за определённый промежуток времени. В этом случае в функцию передаются переменные $purse, $datestart, $datefinish ($wminvid и $orderid не передаются). Значения $datestart и $datefinish устанавливайте в зависимости от ваших конкретных задач и условий. Например, если ваш сайт выписывает счета со сроком действия 2 дня, то и временной отрезок при их проверке в X4 также имеет смысл ограничить последними 2 днями. Просматривая выборку в цикле, "вытаскивайте" состояния оплаты счетов и выполняйте необходимые действия.
  2. Путь второй. После выписки счёта покупателю вы предоставляете ему специальную ссылку или даёте возможность нажать на специальную кнопку, в результате чего покупатель сам инициирует вызов интерфейса X4. Запрашивается информацию по данному конкретному счёту. В этом случае вы передаёте в функцию одну из переменных $wminvid или $orderid (в зависимости от того, как вы учитываете и идентифицируете у себя выписанные счета), а также $purse, $datestart, $datefinish. В полученной выборке будет присутствовать только один искомый счёт. "Вытаскивайте" состояние его оплаты и, если счёт оплачен, отгружайте товар покупателю.
Как правило, разработчики используют оба способа параллельно.

О том, какие бывают состояния оплаты счёта и как их определить, я расскажу ниже. Вернёмся к рассмотрению функции.

Генерируем уникальный номер запроса $reqn с помощью функции _GetReqn():

$reqn=_GetReqn();

Получаем подпись XML-пакета с помощью функции _GetSign(). На вход функции подаём строку, полученную в результате склейки параметров, как это предусмотрено в описании интерфейса. Параметры должны склеиваться именно в таком порядке, как это указано ниже.

$rsign=_GetSign($purse.$reqn);

Наконец, формируем XML-пакет с запросом:

$xml=" <w3s.request> <reqn>$reqn</reqn> <wmid>$Global_WMID</wmid> <sign>$rsign</sign> <getoutinvoices> <purse>$purse</purse> <wminvid>$wminvid</wminvid> <orderid>$orderid</orderid> <datestart>$datestart</datestart> <datefinish>$datefinish</datefinish> </getoutinvoices> </w3s.request>";

Отправляем запрос на сервер WebMoney и получаем от него ответ с помощью функции _GetAnswer(). На вход функции подаём URL интерфейса X4 из глобального массива $XML_addr, а также пакет XML-запроса, сформированный только что:

$resxml=_GetAnswer($XML_addr[4], $xml);

Для отладки и поиска ошибок может потребоваться прочитать XML-ответ "в чистом виде". Тогда просто раскомментируйте следующую строку:

// echo $resxml;

Вызовом функции simplexml_load_string() из библиотеки SimpleXML создаём на основе XML-ответа, полученного от WebMoney, объект. Параметры XML-ответа становятся свойствами объекта, и мы сможем легко получать к ним доступ.

$xmlres = simplexml_load_string($resxml);

Если $xmlres не создан, значит, мы по какой-то причине не получили ответ от WebMoney. Тогда прерываем работу функции:

if(!$xmlres) { $result['retval']=1000; $result['retdesc']="Не получен XML-ответ"; return $result; }

Читаем следующие свойства объекта: retval (содержит результат выполнения запроса; если история счетов получена успешно, то retval равен 0), retdesc (содержит расшифровку результата), а также атрибут cnt свойства outinvoices, в котором содержится количество счетов, вошедших в выборку. Сохраняем эти переменные в массив $result.

$result['retval']=strval($xmlres->retval); $result['retdesc']=iconv("UTF-8", "CP1251", strval($xmlres->retdesc)); $result['cnt']=strval($xmlres->outinvoices->attributes()->cnt);

Обратите внимание, что содержимое поля <retdesc> мы перекодировали из UTF-8 в Win1251. Дело в том, что XML-ответ от WebMoney приходит в кодировке Windows1251, но SimpleXML при помещении XML-данных в объект принудительно превратил их в Юникод. Такая вот у него особенность. А так как <retdesc> - это строка, и теоретически она может содержать русские символы, то при выемке её из объекта мы возвращаем ей "родную" кодировку. Хотя, в общем, это не обязательно и зависит от ваших нужд и задач.

Далее, если cnt больше 0, т.е. в выборке есть хотя бы один счёт, переходим к сохранению информации о счетах. Нас, напомню, интересует состояние их оплаты. Информация о счетах содержится внутри одинаковых блоков XML-ответа <outinvoice>...</outinvoice>. Пробегаем эти блоки в цикле и формируем массив, где ключами элементов делаем уникальные номера счетов в системе WebMoney (атрибут id полей <outinvoice>), а значениями элементов делаем соответствующие этим счетам состояния их оплаты (поля <state>). Сформированный массив сохраняем внутрь элемента invoices выходного массива $result:

if($result['cnt']>0) { // В элементе $result['invoices'] формируем массив [номер счёта в WM] = состояние оплаты foreach ($xmlres->outinvoices->outinvoice as $invoice) { $wminvid=strval($invoice->attributes()->id); $state=strval($invoice->state); $result['invoices'][$wminvid]=$state; } }

На выходе функция _WMXML4() возвращает массив $result:

return $result;

Чтобы было лучше понятно, ещё раз посмотрим на содержимое массива $result (его можно привести в читабельный вид с помощью функции print_r(), например):

Array ( [retval] => код_выполнения [retdesc] => описание_результата [сnt] => количество_счетов_в_выборке [invoices] => Array ( [номер_счёта] => состояние оплаты [номер_счёта] => состояние оплаты [номер_счёта] => состояние оплаты ... ) )

Что касается состояния оплаты, то оно по каждому счёту может иметь одно из следующих значений: 0 - не оплачен, 1 - оплачен с протекцией, 2 - оплачен окончательно, 3 - отказ от оплаты. "Оплачен окончательно" (2) означает, что протекция перевода по счёту уже снята, либо счёт был выставлен и оплачен вообще без протекции.

Теперь осталось только проверить, как работает то, что мы написали. Создадим скрипт для тестов test.php:

<!--php // test.php - скрипт для тестирования include("wmxml.inc.php"); $purse="ваш_кошелёк"; // укажите! $wminvid=""; $orderid=""; $datestart="20080830 00:00:00"; $datefinish="20080831 00:00:00"; $r=_WMXML4($purse,$wminvid,$orderid,$datestart,$datefinish); echo "Результат (0 - успешно) - ".$r['retval']."<br-->"; echo "Расшифровка - ".$r['retdesc']."<br>"; echo "Количество - ".$r['cnt']."<br>"; while(list($key,$val)=each($r['invoices'])) { echo "* У счёта ".$key." состояние оплаты ".$val."<br>"; } ?>

В этом примере мы получили полную историю счетов, выписанных 30-го августа 2008 года.

Завершая разговор об X4, хотим заметить, что приведенный пример функции _WMXML4() во многом является лишь демонстративным. В вашем конкретном случае может понадобиться получение "на выходе" более расширенной информации, либо структурирование её в ином виде. Не сомневаемся, что вы сможете адаптировать функцию под свои нужды. Главное - понять, как устроен интерфейс.

Интерфейс X9. Получение балансов по кошелькам.

С помощью данного интерфейса вы можете получать информацию о текущих остатках на кошельках вашего WMID. Полное описание интерфейса находится здесь. Интерфейс требует включения путем обращения в службу поддержку WMID 941977853154.

X9 особенно полезен для автоматических обменных пунктов, сайтов, выплачивающих "WM-бонусы" и других проектов, в которых посетитель должен видеть текущие денежные резервы сервиса.

Наш XML-запрос должен выглядеть так:

<w3s.request> <reqn></reqn> <wmid></wmid> <sign></sign> <getpurses> <wmid></wmid> </getpurses> </w3s.request>

Что означают параметры:

  • reqn - номер запроса, всякий раз должен быть больше предыдущего (в рамках данного отдельно взятого интерфейса);
  • wmid - ваш WMID, которым подписывается запрос;
  • sign - подпись запроса, сформированная из параметров: getpurses\wmid+reqn;
  • getpurses\wmid - WMID, по кошелькам которого необходимо проверить балансы. Дело в том, что данный интерфейс поддерживает доверенности, т.е. вы можете проверить балансы на кошельках чужого WMID, если владелец этого WMID дал вам соответствующую доверенность на сайте security.webmoney.ru. Запрос в этом случае вы всё равно должны подписывать своим WMID, но в поле getpurses\wmid записать WMID проверяемый. В приведенном ниже примере функции мы будем проверять балансы на собственном WMID. Если же вы захотите проверить балансы по доверенности, вам нужно будет немного видоизменить функцию.

Формат ответа сервера WebMoney следующий:

<w3s.response> <reqn></reqn> <retval></retval> <retdesc></retdesc> <purses cnt="n"> <purse id="n"> <pursename></pursename> <amount></amount> </purse> <purse> ... </purse> </purses> </w3s.response>

Что нас интересует в ответе? Во-первых, поле <retval> (если оно равно 0, то балансы получены успешно, в противном случае retval будет содержать код ошибки, расшифровку которой нужно смотреть в поле <retdesc>). Во-вторых, поля <pursename> и <amount>, содержащие соответственно номера кошельков и их балансы.

Как вы уже поняли, запросить остаток по одному конкретному кошельку, к сожалению, нельзя. Ответ возвращает балансы сразу всех кошельков.

Приведем теперь полностью функцию, которая реализует работу с интерфейсом X9, и добавим её в wmxml.inc.php:

// ИНТЕРФЕЙС X9. ПОЛУЧЕНИЕ БАЛАНСА // На выходе: массив ['retval'=>код выполнения, 'retdesc'=>описание результата, // 'purses'=>массив балансов] function _WMXML9 () { global $Global_WMID, $XML_addr; $reqn=_GetReqn(); $rsign=_GetSign($Global_WMID.$reqn); $xml=" <w3s.request> <reqn>$reqn</reqn> <wmid>$Global_WMID</wmid> <sign>$rsign</sign> <getpurses> <wmid>$Global_WMID</wmid> </getpurses> </w3s.request>"; $resxml=_GetAnswer($XML_addr[9], $xml); // echo $resxml; $xmlres = simplexml_load_string($resxml); if(!$xmlres) { $result['retval']=1000; $result['retdesc']="Не получен XML-ответ"; return $result; } $result['retval']=strval($xmlres->retval); $result['retdesc']=iconv("UTF-8", "CP1251", strval($xmlres->retdesc)); if($result['retval']==0 && $result['retval']!==false) { // Формируем массив [номер кошелька] = баланс foreach ($xmlres->purses->purse as $purse) { $pursename=strval($purse->pursename); $amount=floatval($purse->amount); $result['purses'][$pursename]=$amount; } } return $result; }

Разберём, что происходит в этой функции.

Функция не получает никаких входных параметров.

Генерируем уникальный номер запроса $reqn с помощью функции _GetReqn():

$reqn=_GetReqn();

Получаем подпись XML-пакета с помощью функции _GetSign(). На вход функции подаём строку, полученную в результате склейки параметров, как это предусмотрено в описании интерфейса. Параметры должны склеиваться именно в таком порядке, как это указано ниже.

$rsign=_GetSign($Global_WMID.$reqn);

Наконец, формируем XML-пакет с запросом:

$xml=" <w3s.request> <reqn>$reqn</reqn> <wmid>$Global_WMID</wmid> <sign>$rsign</sign> <getpurses> <wmid>$Global_WMID</wmid> </getpurses> </w3s.request>";

Отправляем запрос на сервер WebMoney и получаем от него ответ с помощью функции _GetAnswer(). На вход функции подаём URL интерфейса X9 из глобального массива $XML_addr, а также пакет XML-запроса, сформированный только что:

$resxml=_GetAnswer($XML_addr[9], $xml);

Для отладки и поиска ошибок может потребоваться прочитать XML-ответ "в чистом виде". Тогда просто раскомментируйте следующую строку:

// echo $resxml;

Вызовом функции simplexml_load_string() из библиотеки SimpleXML создаём на основе XML-ответа, полученного от WebMoney, объект. Параметры XML-ответа становятся свойствами объекта, и мы сможем легко получать к ним доступ.

$xmlres = simplexml_load_string($resxml);

Если $xmlres не создан, значит, мы по какой-то причине не получили ответ от WebMoney. Тогда прерываем работу функции:

if(!$xmlres) { $result['retval']=1000; $result['retdesc']="Не получен XML-ответ"; return $result; }

Читаем следующие свойства объекта: retval (содержит результат выполнения запроса; если балансы успешно получены, то retval равен 0), retdesc (содержит расшифровку результата). Сохраняем эти переменные в массив $result.

$result['retval']=strval($xmlres->retval); $result['retdesc']=iconv("UTF-8", "CP1251", strval($xmlres->retdesc));

Обратите внимание, что содержимое поля <retdesc> мы перекодировали из UTF-8 в Win1251. Дело в том, что XML-ответ от WebMoney приходит в кодировке Windows1251, но SimpleXML при помещении XML-данных в объект принудительно превратил их в Юникод. Такая вот у него особенность. А так как <retdesc> - это строка, и теоретически она может содержать русские символы, то при выемке её из объекта мы возвращаем ей "родную" кодировку. Хотя, в общем, это не обязательно и зависит от ваших нужд и задач.

Если retval равен 0, то можно перейти к сохранению балансов по кошелькам. Номера кошельков и их балансы содержатся внутри одинаковых блоков XML-ответа <purse>...</purse> в <pursename> и <amount> соответственно. Пробегаем эти блоки в цикле и формируем ассоциативный массив, где ключами элементов делаем номера кошельков, а значениями элементов делаем соответствующие этим кошелькам балансы. Сформированный массив сохраняем внутрь элемента purses выходного массива $result:

if($result['retval']==0 && $result['retval']!==false) { // Формируем массив [номер кошелька] = баланс foreach ($xmlres->purses->purse as $purse) { $pursename=strval($purse->pursename); $amount=floatval($purse->amount); $result['purses'][$pursename]=$amount; } }

На выходе функция _WMXML9() возвращает массив $result:

return $result;

Чтобы было лучше понятно, ещё раз посмотрим на содержимое массива $result (его можно привести в читабельный вид с помощью функции print_r(), например):

Array ( [retval] => код_выполнения [retdesc] => описание_результата [purses] => Array ( [номер_кошелька] => баланс [номер_кошелька] => баланс [номер_кошелька] => баланс ... ) )

Теперь осталось только проверить, как работает то, что мы написали. Создадим скрипт для тестов test.php:

<!--php // test.php - скрипт для тестирования include("wmxml.inc.php"); $r=_WMXML9(); echo "Результат (0 - успешно) - ".$r['retval']."<br-->"; echo "Расшифровка - ".$r['retdesc']."<br>"; while(list($key,$val)=each($r['purses'])) { echo "* На кошельке ".$key." ".$val." WM<br>"; } ?>

Интерфейс X14. Бескомиссионный возврат перевода.

С помощью этого интерфейса вы можете в течение 14 дней сделать возврат полученных WM-средств отправителю, не потеряв при этом комиссию системы. Интерфейс будет очень полезен для обменных пунктов и других сервисов в случае необходимости произвести возврат клиенту ошибочного платежа. Полное описание интерфейса находится здесь. Если Вы являетесь владельцем аттестата продавца и используете merchant.webmoney.ru, то использовать X14 вы можете без дополнительной регистрации. В противном случае, необходимо включить интерфейс путем обращения в службу поддержку WMID 941977853154.

Наш XML-запрос должен выглядеть так:

<w3s.request> <reqn></reqn> <wmid></wmid> <sign></sign> <trans> <inwmtranid></inwmtranid> <amount></amount> </trans> </w3s.request>

Что означают параметры:

  • reqn - номер запроса, всякий раз должен быть больше предыдущего (в рамках данного отдельно взятого интерфейса);
  • wmid - ваш WMID;
  • sign - подпись запроса, сформированная из параметров: reqn+trans\inwmtranid+trans\amount
  • trans\inwmtranid - уникальный номер возвращаемой транзакции (в системе WebMoney);
  • trans\amount - сумма возвращаемой транзакции.

Формат ответа сервера WebMoney можно посмотреть в описании интерфейса. В ответе нас интересуют: поле <retval> (eсли оно равно 0, то возврат произведён успешно, в противном случае retval будет содержать код ошибки, расшифровку которой нужно смотреть в поле <retdesc> или всё в том же описании интерфейса), а также атрибут id поля <operation> (содержит номер транзакции возврата) и поле <datecrt> (дата и время создания транзакции возврата).

Приведем теперь полностью функцию, которая реализует работу с интерфейсом X14, и добавим её в wmxml.inc.php:

// ИНТЕРФЕЙС X14. БЕСКОМИССИОННЫЙ ВОЗВРАТ. // На выходе: массив ['retval'=>код выполнения, 'retdesc'=>описание результата, // 'date'=>дата и время, 'wmtranid_ret'=>номер транзакции возврата] function _WMXML14 ($wmtranid,$amount) { global $Global_WMID, $XML_addr; $reqn=_GetReqn(); $amount=floatval($amount); $rsign=_GetSign($reqn.$wmtranid.$amount); $xml=" <w3s.request> <reqn>$reqn</reqn> <wmid>$Global_WMID</wmid> <sign>$rsign</sign> <trans> <inwmtranid>$wmtranid</inwmtranid> <amount>$amount</amount> </trans> </w3s.request>"; $resxml=_GetAnswer($XML_addr[14], $xml); // echo $resxml; $xmlres = simplexml_load_string($resxml); if(!$xmlres) { $result['retval']=1000; $result['retdesc']="Не получен XML-ответ"; return $result; } $result['retval']=strval($xmlres->retval); $result['retdesc']=iconv("UTF-8", "CP1251", strval($xmlres->retdesc)); $result['wmtranid_ret']=strval($xmlres->operation->attributes()->id); $result['date']=strval($xmlres->operation->datecrt); return $result; }

Разберём, что происходит в этой функции.

Функция получает переменные:

  • $wmtranid - уникальный номер транзакции (в базе данных WebMoney), которая возвращается. Целое число. Обязательный параметр.
  • $amount - сумма возвращаемой транзакции. Данное значение используется в интерфейсе исключительно в целях самопроверки: если указанная сумма не равна реальной сумме возвращаемой транзакции, то интерфейс вернет ошибку. Заметим также, что транзакция может быть возвращена только полностью на всю сумму; частичный возврат не допускается. Обязательный параметр.

Напомним, откуда мы можем получить значение $wmtranid:

  • передаётся вашему серверу при оплате через WM Merchant в форме оповещения о платеже;
  • может быть получен из истории операций с помощью интерфейса X3.

Генерируем уникальный номер запроса $reqn с помощью функции _GetReqn():

$reqn=_GetReqn();

У $amount удаляем незначащие нули, если они есть:

$amount=floatval($amount);

Получаем подпись XML-пакета с помощью функции _GetSign(). На вход функции подаём строку, полученную в результате склейки параметров, как это предусмотрено в описании интерфейса. Параметры должны склеиваться именно в таком порядке, как это указано ниже.

$rsign=_GetSign($reqn.$wmtranid.$amount);

Наконец, формируем XML-пакет с запросом:

$xml=" <w3s.request> <reqn>$reqn</reqn> <wmid>$Global_WMID</wmid> <sign>$rsign</sign> <trans> <inwmtranid>$wmtranid</inwmtranid> <amount>$amount</amount> </trans> </w3s.request>";

Отправляем запрос на сервер WebMoney и получаем от него ответ с помощью функции _GetAnswer(). На вход функции подаём URL интерфейса X14 из глобального массива $XML_addr, а также пакет XML-запроса, сформированный только что:

$resxml=_GetAnswer($XML_addr[14], $xml);

Для отладки и поиска ошибок может потребоваться прочитать XML-ответ "в чистом виде". Тогда просто раскомментируйте следующую строку:

// echo $resxml;

Вызовом функции simplexml_load_string() из библиотеки SimpleXML создаём на основе XML-ответа, полученного от WebMoney, объект. Параметры XML-ответа становятся свойствами объекта, и мы сможем легко получать к ним доступ.

$xmlres = simplexml_load_string($resxml);

Если $xmlres не создан, значит, мы по какой-то причине не получили ответ от WebMoney. Тогда прерываем работу функции:

if(!$xmlres) { $result['retval']=1000; $result['retdesc']="Не получен XML-ответ"; return $result; }

Читаем следующие свойства объекта: retval (содержит результат выполнения запроса; если возврат произведен успешно, то retval равен 0), retdesc (содержит расшифровку результата), атрибут id свойства operation (содержит уникальный номер только что созданной транзакции возврата в базе данных WebMoney), свойство operation\datecrt (содержит дату и время выполнения транзакции возврата). Сохраняем эти переменные в массив $result.

$result['retval']=strval($xmlres->retval); $result['retdesc']=iconv("UTF-8", "CP1251", strval($xmlres->retdesc)); $result['wmtranid_ret']=strval($xmlres->operation->attributes()->id); $result['date']=strval($xmlres->operation->datecrt);

Обратите внимание, что содержимое поля <retdesc> мы перекодировали из UTF-8 в Win1251. Дело в том, что XML-ответ от WebMoney приходит в кодировке Windows1251, но SimpleXML при помещении XML-данных в объект принудительно превратил их в Юникод. Такая вот у него особенность. А так как <retdesc> - это строка, и теоретически она может содержать русские символы, то при выемке её из объекта мы возвращаем ей "родную" кодировку. Хотя, в общем, это не обязательно и зависит от ваших нужд и задач.

На выходе функция _WMXML14() возвращает массив $result:

return $result;

Теперь осталось только проверить, как работает то, что мы написали. Создадим скрипт для тестов test.php:

<!--php // test.php - скрипт для тестирования include("wmxml.inc.php"); $wmtranid="128150624"; $amount="0.5"; $r=_WMXML14($wmtranid,$amount); echo "Результат (0 - успешно) - ".$r['retval']."<br-->"; echo "Расшифровка - ".$r['retdesc']."<br>"; echo "Номер - ".$r['wmtranid_ret']."<br>"; echo "Дата - ".$r['date']."<br>"; ?>

Отметим, что примечание операции возврата, совершенной интерфейсом X14, всегда будет иметь следующий вид: "Moneyback transaction: номер возвращаемой транзакции. (примечание возвращаемой транзакции)", и изменить его нельзя.

Интерфейс X16. Создание кошелька.

Пожалуй, один из самых простых интерфейсов. С его помощью вы можете создавать кошельки в своём WMID. Полное описание интерфейса находится здесь. Интерфейс доступен всем пользователям с любым аттестатом и не требует специального включения.

Наш XML-запрос должен выглядеть так:

<w3s.request> <reqn></reqn> <wmid></wmid> <sign></sign> <createpurse> <wmid></wmid> <pursetype></pursetype> <desc></desc> </createpurse> </w3s.request>

Что означают параметры:

  • reqn - номер запроса, всякий раз должен быть больше предыдущего (в рамках данного отдельно взятого интерфейса);
  • wmid - ваш WMID;
  • sign - подпись запроса, сформированная из параметров: createpurse\wmid+createpurse\pursetype+reqn
  • createpurse\wmid - WMID, в рамках которого мы хотим создать новый кошелёк. По идее, здесь можно было бы указать не только свой, но и чужой WMID, однако, данный интерфейс не поддерживает доверие, поэтому создавать кошелёк можно только в своем WMID. По этой причине и в wmid, и в createpurse\wmid должен значиться один и тот же WMID - ваш. В общем, зачем этот параметр включен разработчиками в состав XML-запроса - осталось неясным;
  • createpurse\pursetype - тип создаваемого кошелька;
  • createpurse\desc - название кошелька, которое будет отображаться в Keeper Classic или Keeper Light.

Формат ответа сервера WebMoney можно посмотреть в описании интерфейса. В ответе нас интересуют поля <retval> (eсли оно равно 0, то кошелёк создан успешно, в противном случае retval будет содержать код ошибки, расшифровку которой нужно смотреть в поле <retdesc> или всё в том же описании интерфейса) и <pursename>. В последнем содержится номер созданного кошелька.

Приведем теперь полностью функцию, которая реализует работу с интерфейсом X16, и добавим её в wmxml.inc.php:

// ИНТЕРФЕЙС X16. СОЗДАНИЕ КОШЕЛЬКА. // На выходе: массив ['retval'=>код выполнения, 'retdesc'=>описание результата, // 'purse'=>номер кошелька] function _WMXML16 ($type,$desc) { global $Global_WMID, $XML_addr; $reqn=_GetReqn(); $rsign=_GetSign($Global_WMID.$type.$reqn); $desc=trim($desc); $desc=htmlspecialchars($desc, ENT_QUOTES); $desc=iconv("CP1251", "UTF-8", $desc); $xml=" <w3s.request> <reqn>$reqn</reqn> <wmid>$Global_WMID</wmid> <sign>$rsign</sign> <createpurse> <wmid>$Global_WMID</wmid> <pursetype>$type</pursetype> <desc>$desc</desc> </createpurse> </w3s.request>"; $resxml=_GetAnswer($XML_addr[16], $xml); // echo $resxml; $xmlres = simplexml_load_string($resxml); if(!$xmlres) { $result['retval']=1000; $result['retdesc']="Не получен XML-ответ"; return $result; } $result['retval']=strval($xmlres->retval); $result['retdesc']=iconv("UTF-8", "CP1251", strval($xmlres->retdesc)); $result['purse']=strval($xmlres->purse->pursename); return $result; }

Разберём, что происходит в этой функции.

Функция получает переменные:

  • $type - тип кошелька (1 буква - Z, R, U и т.д.). Обязательный параметр.
  • $desc - название кошелька. Допускаются любые символы, в том числе русские буквы. $desc желательно передавать в функцию в кодировке Win1251. Обязательный параметр.

Генерируем уникальный номер запроса $reqn с помощью функции _GetReqn():

$reqn=_GetReqn();

У $desc убираем лишние пробелы в начале и конце:

$desc=trim($desc);

Получаем подпись XML-пакета с помощью функции _GetSign(). На вход функции подаём строку, полученную в результате склейки параметров, как это предусмотрено в описании интерфейса. Параметры должны склеиваться именно в таком порядке, как это указано ниже.

$rsign=_GetSign($Global_WMID.$type.$reqn);

Теперь преобразуем специальные символы ("<", "&" и др.) в html-сущности. Если этого не сделать, то при попадании в $desc таких символов WebMoney наш запрос не примет и вернет ошибку "A semi colon character was expected". Преобразовать спецсимволы в PHP можно с помощью функции htmlspecialchars():

$desc=htmlspecialchars($desc, ENT_QUOTES);

Но это ещё не всё. $desc может содержать русские символы. Например, в $desc может быть такой текст: "тестовый кошелёк". И здесь нужно понимать, как подготовить $desc для передачи в составе XML-пакета. Дело в том, что содержимое полученного от вас XML-пакета сервер WebMoney попытается прочитать так, будто он пришел в кодировке Unicode. Если сервер встретит в пакете русские символы в другой кодировке, то вернет ошибку: "An invalid character was found in text content" ("Обнаружен ошибочный символ"). Для того чтобы этого не произошло, нам нужно принудительно перекодировать $desc в UTF-8 и уже в таком виде включать его в XML-запрос.

Сделать преобразование кодировок можно с помощью функции iconv() из одноименного расширения PHP:

$desc=iconv("CP1251", "UTF-8", $desc);

То же самое, но с помощью функции mb_convert_encoding() из расширения mbstring:

$desc=mb_convert_encoding($desc, "UTF-8", "windows-1251");

Можно даже преобразовать не в UTF-8, а в html-сущности, это тоже сработает:

$desc=mb_convert_encoding($desc, "HTML-ENTITIES","windows-1251");

Если же iconv и mbstring вашим сервером не поддерживаются, то могу предложить ещё один вариант. Оставьте $desc в кодировке Win1251, а в начале XML-запроса вставляйте заголовок <?xml version='1.0' encoding='windows-1251'?>. Он укажет, что данные в пакете переданы в Win1251, и сервер WebMoney обработает их именно в этой кодировке. То есть пакет в этом случае будет начинаться так:

$xml="<!--xml version='1.0' encoding='windows-1251'?--> <w3s.request> ...

Наконец, формируем XML-пакет с запросом:

$xml=" <w3s.request> <reqn>$reqn</reqn> <wmid>$Global_WMID</wmid> <sign>$rsign</sign> <createpurse> <wmid>$Global_WMID</wmid> <pursetype>$type</pursetype> <desc>$desc</desc> </createpurse> </w3s.request>";

Отправляем запрос на сервер WebMoney и получаем от него ответ с помощью функции _GetAnswer(). На вход функции подаём URL интерфейса X16 из глобального массива $XML_addr, а также пакет XML-запроса, сформированный только что:

$resxml=_GetAnswer($XML_addr[16], $xml);

Для отладки и поиска ошибок может потребоваться прочитать XML-ответ "в чистом виде". Тогда просто раскомментируйте следующую строку:

// echo $resxml;

Вызовом функции simplexml_load_string() из библиотеки SimpleXML создаём на основе XML-ответа, полученного от WebMoney, объект. Параметры XML-ответа становятся свойствами объекта, и мы сможем легко получать к ним доступ.

$xmlres = simplexml_load_string($resxml);

Если $xmlres не создан, значит, мы по какой-то причине не получили ответ от WebMoney. Тогда прерываем работу функции:

if(!$xmlres) { $result['retval']=1000; $result['retdesc']="Не получен XML-ответ"; return $result; }

Читаем следующие свойства объекта: retval (содержит результат выполнения запроса; если кошелёк создан успешно, то retval равен 0), retdesc (содержит расшифровку результата), purse\pursename (содержит номер созданного кошелька, включая первую "сигнальную" букву, т.е. в формате буква+12 цифр). Сохраняем эти переменные в массив $result.

$result['retval']=strval($xmlres->retval); $result['retdesc']=iconv("UTF-8", "CP1251", strval($xmlres->retdesc)); $result['purse']=strval($xmlres->purse->pursename);

Обратите внимание, что содержимое поля <retdesc> мы перекодировали из UTF-8 в Win1251. Дело в том, что XML-ответ от WebMoney приходит в кодировке Windows1251, но SimpleXML при помещении XML-данных в объект принудительно превратил их в Юникод. Такая вот у него особенность. А так как <retdesc> - это строка, и теоретически она может содержать русские символы, то при выемке её из объекта мы возвращаем ей "родную" кодировку. Хотя, в общем, это не обязательно и зависит от ваших нужд и задач.

На выходе функция _WMXML16() возвращает массив $result:

return $result;

Теперь осталось только проверить, как работает то, что мы написали. Создадим скрипт для тестов test.php:

<!--php // test.php - скрипт для тестирования include("wmxml.inc.php"); $type="U"; $desc="тестовый кошелёк"; $r=_WMXML16($type,$desc); echo "Результат (0 - успешно) - ".$r['retval']."<br-->"; echo "Расшифровка - ".$r['retdesc']."<br>"; echo "Номер кошелька - ".$r['purse']."<br>"; ?>

В заключение ещё раз приведём ссылку на файл с функциями всех 10 XML-интерфейсов WebMoney, которые мы рассмотрели в статьях на оВебМани.Ру. Вот он. Файл готов к работе, вы можете включать его в свои программы и использовать.



Комментариев нет: