С помощью этого интерфейса вы можете переводить средства со своего кошелька. Полное описание интерфейса находится здесь. Интерфейс требует включения - подробности в теме Подключение интерфейса X2 в Merchant.WebMoney.
Наш XML-запрос должен выглядеть так:
Что означают параметры:
Приведем теперь полностью функцию, которая реализует работу с интерфейсом X2 и добавим её в wmxml.inc.php:
Разберем, что происходит в этой функции.
Функция получает переменные:
Выполняем некоторые преобразования, чтобы избежать ошибок. У $desc и $pcode убираем лишние пробелы в начале и конце. У $amount удаляем незначащие нули, если они есть. Этого требует описание интерфейса.
Получаем подпись XML-пакета с помощью функции _GetSign(). На вход функции подаем строку, полученную в результате склейки параметров, как это предусмотрено в описании интерфейса. Параметры должны склеиваться именно в таком порядке, как это указано ниже. Значения всех параметров при формировании строки подписи обязательно должны быть в кодировке Win1251! Поэтому - внимание! - если функция _WMXML2(), с которой мы сейчас работаем, получила переменные $desс или $pcode в кодировке, отличной от Win1251, то их нужно сперва перекодировать. Остальные параметры содержат всегда только цифры и английские буквы, поэтому для них кодировка никакой роли не играет.
Теперь преобразуем специальные символы ("<", "&" и др.) в html-сущности. Если этого не сделать, то при попадании в $desc или $pcode таких символов WebMoney наш запрос не примет и вернет ошибку "A name was started with an invalid character". Обратите внимание, что при формировании строки подписи переменные $desc и $pcode пребывали в своем первозданном виде, со всеми спецсимволами, а преобразование мы выполняем уже после получения подписи. Преобразовать спецсимволы в PHP можно с помощью функции htmlspecialchars():
Но это еще не всё. $desc и $pcode могут содержать русские символы. Например, в $desc может быть такой текст: "тестовый товар & тестовая услуга". И здесь нужно понимать, как подготовить $desc и $pcode для передачи в составе XML-пакета. Дело в том, что содержимое полученного от вас XML сервер WebMoney попытается прочитать так, будто он пришел в кодировке Unicode. Если сервер встретит в пакете русские символы в другой кодировке, то вернет ошибку: "An invalid character was found in text content" ("Обнаружен ошибочный символ"). Для того чтобы этого не произошло, нам нужно принудительно перекодировать $desc и $pcode в UTF-8 и уже в таком виде включать их в XML-запрос.
Сделать преобразование кодировок можно с помощью функции iconv() из одноименного расширения PHP:
То же самое, но с помощью функции mb_convert_encoding() из расширения mbstring:
Можно даже преобразовать не в UTF-8, а в html-сущности, это тоже сработает:
Если же iconv и mbstring вашим сервером не поддерживаются, то могу предложить еще один вариант. Оставьте $desc и $pcode в кодировке Win1251, а в начале XML-запроса вставляйте заголовок <?xml version='1.0' encoding='windows-1251'?>. Он укажет, что данные в пакете переданы в Win1251, и сервер WebMoney обработает их именно в этой кодировке. То есть пакет будет начинаться так:
Правда, хотя на момент написания этих строк такой вариант работал нормально, не могу поручиться, что он будет работать всегда, поскольку точная логика обработки XML-пакета сервером WebMoney не известна, и не ясно, будет ли всегда сервер учитывать заголовок XML-запроса.
Понятно, что если переменные $desc и $pcode были переданы в функцию _WMXML2(), уже пребывая в кодировке UTF-8, то никаких преобразований делать не нужно.
Наконец, формируем XML-пакет с запросом:
Отправляем запрос на сервер WebMoney и получаем от него ответ с помощью функции _GetAnswer(). На вход функции подаем URL интерфейса X2 из глобального массива $XML_addr, а также пакет XML-запроса, сформированный только что:
Для отладки и поиска ошибок может потребоваться прочитать XML-ответ "в чистом виде". Тогда просто раскомментируйте следующую строку:
Вызовом функции simplexml_load_string() из библиотеки SimpleXML создаем на основе XML-ответа, полученного от WebMoney, объект. Параметры XML-ответа становятся свойствами объекта, и мы сможем легко получать к ним доступ.
Если $xmlres не создан, значит, мы по какой-то причине не получили ответ от WebMoney. Тогда прерываем работу функции:
Читаем следующие свойства объекта: retval (содержит результат выполнения запроса; если перевод на кошелек выполнен успешно, то retval равен 0), retdesc (содержит расшифровку результата), operation/datecrt (содержит дату и время создания транзакции в системе WebMoney в случае успешного перевода, либо дату и время последнего успешного перевода в случае ошибки). Сохраняем эти переменные в массив $result.
Обратите внимание, что содержимое поля <retdesc> мы перекодировали из UTF-8 в Win1251. Дело в том, что XML-ответ от WebMoney приходит в кодировке Windows1251, но SimpleXML при помещении XML-данных в объект принудительно превратил их в Юникод. Такая вот у него особенность. А так как <retdesc> - это строка, и теоретически она может содержать русские символы, то при выемке её из объекта мы возвращаем ей "родную" кодировку. Хотя, в общем, это не обязательно и зависит от ваших нужд и задач.
На выходе функция _WMXML2() возвращает массив $result:
Теперь осталось только проверить, как работает то, что мы написали. Создадим скрипт для тестов test.php:
Этот код должен выполнить перевод 0.10 WM без протекции; с примечанием "тестовый товар & тестовая услуга"; с кошелька_отправителя на кошелек_получателя; при условии, что соблюдены ограничения на прием переводов, установленные получателем (onlyauth=1).
Естественно, на кошельке-отправителе $purse должно быть достаточно средств для совершения перевода.
Наш XML-запрос должен выглядеть так:
Код:
<w3s.request>
<reqn></reqn>
<wmid></wmid>
<sign></sign>
<trans>
<tranid></tranid>
<pursesrc></pursesrc>
<pursedest></pursedest>
<amount></amount>
<period></period>
<pcode></pcode>
<desc></desc>
<wminvid></wminvid>
<onlyauth></onlyauth>
</trans>
</w3s.request>
- reqn - номер запроса, всякий раз должен быть больше предыдущего;
- wmid - ваш WMID;
- sign - подпись запроса, сформированная из параметров: reqn + tranid + pursesrc + pursedest + amount + period + pcode + desc + wminvid;
- tranid - уникальный номер перевода;
- pursesrc - номер вашего кошелька, с которого выполняется перевод;
- pursedest - номер кошелька, на который выполняется перевод;
- amount - сумма перевода;
- period - срок протекции в днях;
- pcode - код протекции;
- desc - примечание перевода;
- wminvid - номер счета в системе WebMoney, по которому выполняется перевод;
- onlyauth - признак, который определяет, будет ли выполнен перевод, если получатель запрещает входящие переводы.
Приведем теперь полностью функцию, которая реализует работу с интерфейсом X2 и добавим её в wmxml.inc.php:
PHP:
// ИНТЕРФЕЙС X2. ОТПРАВКА ПЕРЕВОДА.
// На выходе: массив ['retval'=>код выполнения, 'retdesc'=>описание результата, 'date'=>дата и время]
function _WMXML2 ($tranid,$purse,$rpurse,$amount,$period,$pcode,$desc,$wminvid,$onlyauth) {
global $Global_WMID, $XML_addr;
$reqn=_GetReqn();
$desc=trim($desc); $pcode=trim($pcode); $amount=floatval($amount);
$rsign=_GetSign($reqn.$tranid.$purse.$rpurse.$amount.$period.$pcode.$desc.$wminvid);
$pcode=htmlspecialchars($pcode, ENT_QUOTES);
$desc=htmlspecialchars($desc, ENT_QUOTES);
$pcode=iconv("CP1251", "UTF-8", $pcode);
$desc=iconv("CP1251", "UTF-8", $desc);
$xml="
<w3s.request>
<reqn>$reqn</reqn>
<wmid>$Global_WMID</wmid>
<sign>$rsign</sign>
<trans>
<tranid>$tranid</tranid>
<pursesrc>$purse</pursesrc>
<pursedest>$rpurse</pursedest>
<amount>$amount</amount>
<period>$period</period>
<pcode>$pcode</pcode>
<desc>$desc</desc>
<wminvid>$wminvid</wminvid>
<onlyauth>$onlyauth</onlyauth>
</trans>
</w3s.request>";
$resxml=_GetAnswer($XML_addr[2], $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['date']=strval($xmlres->operation->datecrt);
return $result;
}
Функция получает переменные:
- $tranid - номер транзакции в системе учета вашего сайта. Может быть любым целым числом длиной 32 бита, то есть от 0 до 2147483647 (отрицательные числа от 0 до -2147483647 тоже возможны, хотя официальным описанием это запрещено). $tranid не должен повторяться более одного раза. Вам нужно организовать сохранение предыдущего $tranid на вашем сайте, например, в базе данных и увеличивать его всякий раз при создании очередной транзакции.
- $purse - ваш кошелек, с которого списываются средства. Кошелек должен быть из числа тех, что принадлежат вашему WMID, фигурирующему в поле <wmid> XML-запроса.
- $rpurse - кошелек получателя средств.
- $amount - сумма перевода. В качестве разделителя дробной части используйте точку, а не запятую. Незначащие нули в конце должны отсутствовать (например, 10.5 - верно, 10.50 - вызовет ошибку).
- $period - количество дней протекции. Если перевод без протекции, то устанавливайте в 0.
- $pcode - код протекции до 255 символов без пробелов в начале и конце. Допускаются любые символы, в том числе русские буквы. Если $period=0 (то есть перевод без протекции), то $pcode обязательно должен быть пустым. $pcode желательно передавать в функцию в кодировке Win1251.
- $desc - примечание к переводу до 255 символов без пробелов в начале и конце. Допускаются любые символы, в том числе русские буквы. $desc желательно передавать в функцию в кодировке Win1251.
- $wminvid - номер счета в системе WebMoney, по которому выполняется перевод. Если перевод не по счету, то поле должно быть равно 0.
- $onlyauth - если это поле равно 0, то перевод выполнится даже в том случае, если получатель запретил (в настройках своего WM Keeper) прием входящих переводов от неавторизованных корреспондентов и наш WMID окажется неавторизованным. Если это поле равно 1, то перевод выполнится только в том случае, если получатель разрешил переводы от неавторизованных, либо если наш WMID авторизован отправителем.
Генерируем уникальный номер запроса $reqn с помощью функции _GetReqn():Примечание. Запрет на прием платежей от неавторизованных корреспондентов обычно устанавливают продавцы, которые используют автоматизированный прием WebMoney посредством WM Merchant и хотят избежать поступления на кошельки прямых переводов, которые не ожидаются ("в обход" WM Merchant), чтобы не искать их потом вручную. Из этих соображений, для соблюдения бизнес-этики, рекомендуем передавать интерфейсу всегда onlyauth=1.
PHP:
$reqn=_GetReqn();
PHP:
$desc=trim($desc); $pcode=trim($pcode); $amount=floatval($amount);
PHP:
$rsign=_GetSign($reqn.$tranid.$purse.$rpurse.$amount.$period.$pcode.$desc.$wminvid);
PHP:
$pcode=htmlspecialchars($pcode, ENT_QUOTES);
$desc=htmlspecialchars($desc, ENT_QUOTES);
Сделать преобразование кодировок можно с помощью функции iconv() из одноименного расширения PHP:
PHP:
$pcode=iconv("CP1251", "UTF-8", $pcode);
$desc=iconv("CP1251", "UTF-8", $desc);
PHP:
$pcode=mb_convert_encoding($pcode, "UTF-8", "windows-1251");
$desc=mb_convert_encoding($desc, "UTF-8", "windows-1251");
PHP:
$pcode=mb_convert_encoding($pcode, "HTML-ENTITIES","windows-1251");
$desc=mb_convert_encoding($desc, "HTML-ENTITIES","windows-1251");
Код:
$xml=" <?xml version='1.0' encoding='windows-1251'?>
<w3s.request>
...
Понятно, что если переменные $desc и $pcode были переданы в функцию _WMXML2(), уже пребывая в кодировке UTF-8, то никаких преобразований делать не нужно.
Наконец, формируем XML-пакет с запросом:
PHP:
$xml="
<w3s.request>
<reqn>$reqn</reqn>
<wmid>$Global_WMID</wmid>
<sign>$rsign</sign>
<trans>
<tranid>$tranid</tranid>
<pursesrc>$purse</pursesrc>
<pursedest>$rpurse</pursedest>
<amount>$amount</amount>
<period>$period</period>
<desc>$desc</desc>
<wminvid>$wminvid</wminvid>
<onlyauth>$onlyauth</onlyauth>
</trans>
</w3s.request>";
PHP:
$resxml=_GetAnswer($XML_addr[2], $xml);
PHP:
// echo $resxml;
PHP:
$xmlres = simplexml_load_string($resxml);
PHP:
if(!$xmlres) {
$result['retval']=1000;
$result['retdesc']="Не получен XML-ответ";
return $result;
}
PHP:
$result['retval']=strval($xmlres->retval);
$result['retdesc']=iconv("UTF-8", "CP1251", strval($xmlres->retdesc));
$result['date']=strval($xmlres->operation->datecrt);
На выходе функция _WMXML2() возвращает массив $result:
PHP:
return $result;
PHP:
// test.php - скрипт для тестирования
include("wmxml.inc.php");
$tranid="1";
$purse="кошелек_отправитель";
$rpurse="кошелек_получатель";
$amount="0.10";
$period="0";
$pcode="";
$desc="тестовый товар & тестовая услуга";
$wminvid="0";
$onlyauth="1";
$r=_WMXML2($tranid,$purse,$rpurse,$amount,$period,$pcode,$desc,$wminvid,$onlyauth);
echo "Результат (0 - успешно) - ".$r['retval']."<br>";
echo "Расшифровка - ".$r['retdesc']."<br>";
echo "Дата и время - ".$r['date']."<br>";
Естественно, на кошельке-отправителе $purse должно быть достаточно средств для совершения перевода.