ATTENTION! You can download complete module for PHP - WMXI, including implementation of WMSigner functionality in PHP language and access to all open XML System’s interfaces for both key types (Classic, Light) here.
The EXAMPLE of accessing the interface X9. Receiving purses balance statement using the PHP language, with use binary module WMSigner (C++ implementation), can be downloaded here.
The main points of the code are commented here.
WMSigner availability check
The WMSigner module is used to sign the request by WM Keeper Classic keys. Get the detailed information on WMSigner module, keys receiving and adjustment. The text below describes the way to check its availability using PHP. The call to the module is performed in the wm_GetSign() function, it receives the string to sign as an input, and returns the string containing 132 chars, or an error text, or an empty string if the call to the WMSigner module is impossible.
<? echo wm_GetSign('123'); ?>
XML request generation
The XML can be generated in any way, if the result matches the XML syntax and the request format. In the text below DOM XML functions are used.
<?
$reqID = wm_ReqID();
$doc = domxml_new_doc('1.0');
$root = $doc->create_element('w3s.request');
$root = $doc->append_child($root);
$tmp = $doc->create_element('reqn');
$tmp->set_content($reqID);
$root->append_child($tmp);
$tmp = $doc->create_element('wmid');
$tmp->set_content($wmWMID);
$root->append_child($tmp);
$getpurses = $doc->create_element('getpurses');
$root->append_child($getpurses);
$tmp = $doc->create_element('wmid');
$tmp->set_content($wmWMID);
$getpurses->append_child($tmp);
$request = $doc->dump_mem(TRUE);
?>
The wm_ReqID() function generates the unique request identifier based on time functions.
Performing the calls to the certification center
Calls to different interfaces are much alike and differ only in URL, XML format and the return value. The function, which performs the call to the CURL, is given below:
<?
function wm_xmlHttpsReq($addr, $xml){
# Use the variables from the configuration file config.php
global $wmURL, $wmCAcert, $wmType, $wmKey, $wmCert, $wmPass;
# Initializing CURL with the necessary URL
$ch = curl_init($wmURL.$addr);
# In the CURL output http headers are not neccessary
curl_setopt($ch, CURLOPT_HEADER, 0);
# Return the result instead of sending it to stdout
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
# Http-request method is POST
curl_setopt($ch, CURLOPT_POST,1);
# Request data
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
# Define the path of the root certificate WebMoney CA:
curl_setopt($ch, CURLOPT_CAINFO, $wmCAcert);
# Attention! Do not use curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE)!
# It allows to perform the attack by DNS substitution.
# Perform request
$result=curl_exec($ch);
# Handling possible errors
if( curl_errno($ch) != 0 ) {
die('CURL_error: ' . curl_errno($ch) . ', ' . curl_error($ch));
};
# Closing handler
curl_close($ch);
return $result;
}
?>
Response analysis
The response structure is given below:
<w3s.response>
<reqn></reqn> - the number of request that reposnse corresponds to
<retval></retval> - request execution error code: 0 - execution was successful
<retdesc></retdesc> - error description if retval != 0
<reponse_type>
... - response parameters
</response_type>
</w3s.response>
The XML reponse analysis may be performed in any suitable way (SAX, DOM, Regexp и т.д.). In the given case the PHP function xml_parse_into_struct() was used:
<?
$xml_parser = xml_parser_create('UTF-8');
# Parsing XML into variables $vals, $index
xml_parse_into_struct($xml_parser, $result, $vals, $index);
xml_parser_free($xml_parser);
# Checking response correctness
$check = wm_CheckResp($vals,$index);
if( $check != 0) die($check);
# Putting the list of pursesm their descriptions and sums into variable $purses
$purses = array();
$pursename = '';
$amount = '';
$desc = '';
for($n = 0; $n < count($vals); ++$n){
$e = $vals[$n];
switch ($e['tag']){
case 'PURSE':
switch ($e['type']){
case 'open':
$pursename = ''; $amount = ''; $desc = '';
break;
case 'close':
$purses[$pursename] = array('amount' => $amount, 'desc' => $desc);
break;
}
break;
case 'PURSENAME':
$pursename = $e['value'];
break;
case 'AMOUNT':
$amount = $e['value'];
break;
case 'DESC':
$desc = $e['value'];
break;
}
}
?>
Working with WM Keeper Light certificates (X.509)
After the Light certificate is received and installed in browser it should be exported to a file. It would be PKCS12 format file with a .pfx or .p12 extension. This file contains the private key and the certificate itself.
Then it should be converted to PEM format to enable working with CURL. In the example below the openssl utility from the openssl package is used:
$ openssl pkcs12 -in 351237877840.pfx -out 351237877840.key -nocerts
$ openssl pkcs12 -in 351237877840.pfx -out 351237877840.cer -clcerts -nokeys
Thus we get .key and .cer files, which will be used in the request to w3s. The following CURL options should be added:
<?
curl_setopt($ch, CURLOPT_SSLKEY, $wmKey);
curl_setopt($ch, CURLOPT_SSLKEYPASSWD , $wmPass);
curl_setopt($ch, CURLOPT_SSLCERT, $wmCert);
?>
Where $wmPass is the password used while converting the key into the PEM format.
The XML request is also changed. The <sign/> element is removed
Important notes
The key files (including Light) should be kept in the folder inaccessible to other users!
1. WMSigner, its config (and key file) should be kept int the folder inaccessible to other users.
2. The module looks for the config of WMSigner.ini in the folder, where the module is placed.
3. WMSigner searches key file accroding to WMSigner.ini, taking into consideration that the "current" folder is the folder, where the script calling WMSigner is located.
All mentioned above should be understood from the Unix access rights point of view.
Example:
The folder containing scripts and html doucments: /home/my_site/html
Folder containing WMSigner: /home/my_site/sign
Configuration file: /home/my_site/sign/WMSigner.ini :
123456789012
pass
/home/my_site/sign/keyfile.kwm