经过几天google -ing /尝试/失去头发后,我仍然无法找到解决方案,所以请帮助:)
简短信息:
我需要使用PHP(SOAP客户端)的WCF服务。它使用wsHttpBinding(ws-security),无法设置basicHttpBinding。一切都在VPN背后,所以我无法为您提供webservice的链接。此外,数据被视为机密(来自客户的请求),因此我无法向您提供完整信息,只能提供一些“常见”信息。这是WS config:
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IServices" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" negotiateServiceCredential="true" algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://topSecert.url/Service.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServices"
contract="IServices" name="WSHttpBinding_IServices" />
</client>
</system.serviceModel>
我的尝试:
1)基本的PHP Soap客户端不起作用。它始终挂起,直到达到最大执行时间(不生成错误)。我后来发现PHP Soap客户端不支持wsHttpBinding(想哭)
2)一些SoapClient扩展classes但没有成功,请求仍然挂起。
3)使用SOAPAction头尝试“自生成”CURL请求。最后我得到了一些错误(我用wse类生成了请求):
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action>
</s:Header>
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Sender</s:Value>
<s:Subcode>
<s:Value xmlns:a="http://schemas.xmlsoap.org/ws/2005/02/sc">a:BadContextToken</s:Value>
</s:Subcode>
</s:Code>
<s:Reason>
<s:Text xml:lang="en-US">The security context token is expired or is
not valid. The message was not processed.</s:Text>
</s:Reason>
</s:Fault>
</s:Body>
我将服务器时间更改为有效区域(与WCF相同),尝试使用nonce,哈希密码,普通密码以及其他一些我现在都记不起来的东西。 我也尝试编译wso2/wsf但是无法在PHP 5.4上编译它(我尝试应用提供的FIX但是它导致了同样的错误)。
测试XML示例:
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
xmlns:ns1="https://topSercret.url/Test">
<env:Header>
<wsse:Security
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
env:mustUnderstand="1">
<wsse:UsernameToken>
<wsse:Username><!-- Removed --></wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"><!-- Removed --></wsse:Password>
<wsse:Nonce><!-- Removed --></wsse:Nonce>
<wsu:Created
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2014-01-19T15:20:31Z</wsu:Created>
</wsse:UsernameToken>
<wsu:Timestamp
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2014-01-19T15:20:31Z</wsu:Created>
<wsu:Expires>2014-01-19T16:20:31Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</env:Header>
<env:Body>
<ns1:SomeAction />
</env:Body>
这是测试脚本的代码(可能有错误,我为此帖子删除了大部分内容):
<?php
date_default_timezone_set( 'UTC' );
include 'WSSESoap.php';
class TestSoap extends SoapClient {
private $_username;
private $_password;
private $_digest;
// test vars
public $r_request;
public $r_location;
public $r_action;
function addUserToken($username, $password, $digest = false) {
$this->_username = $username;
$this->_password = $password;
$this->_digest = $digest;
}
function __doRequest($request, $location, $saction, $version, $one_way = 0) {
$doc = new DOMDocument('1.0');
$doc->loadXML($request);
$objWSSE = new WSSESoap($doc);
$objWSSE->signAllHeaders = TRUE;
$objWSSE->addTimestamp();
$objWSSE->addUserToken($this->_username, $this->_password, $this->_digest);
// take data for "my" usage
$this->r_request = $objWSSE->saveXML();
$this->r_location = $location;
$this->r_action = $saction;
return '';
}
}
function test()
{
$soapUrl = "https://topSecret.url/Services.svc";
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'allow_self_signed' => true
)
));
$client = new TestSoap('/mypath/wsdl.xml', array(
'stream_context' => $context,
'soap_version' => SOAP_1_2,
'trace' => 1,
'connection_timeout' => 10
));
$client->addUserToken('User', 'Password', TRUE );
$requestParams = array(
'data1' => '1',
'data2' => '2',
);
// call to generate request string
$client->myAction($requestParams);
$xml_post_string = $client->r_request;
$headers = array(
"Content-type: application/soap+xml; charset=\"utf-8\"",
"Accept: text/xml,application/soap+xml",
"Cache-Control: no-cache",
"Pragma: no-cache",
"SOAPAction: " . $client->r_action,
"Content-length: " . strlen($xml_post_string)
);
// generate && run cURL request
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_URL, $soapUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string); // the SOAP request
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
}
test();
所以最后这个问题。可以使用PHP来使用这种服务(如果它可以帮助理解如何)?
答案 0 :(得分:9)
我前段时间解决了这个问题,但从来没有时间让它更“更好”。因此,问题通常是wsHttpBinding消息安全如何工作以及如何在PHP上实现它的方式。我使用了来自https://github.com/enginaygen/kps-soap-client/blob/master/KPSSoapClient.php的概念,还添加了来自Implementation of P_SHA1 algorithm in PHP的psha1。
所以它需要工作的方式是:
这是imeplentation(注意:由于WSDL导入问题,我没有通过扩展PHP soap客户端来实现它。另外正如我所说的,我使用了其他人的概念,从未做过清理代码 - 尤其是XML生成强>)。
// TODO implement this by extending SoapClient class
// currently not implemented in it because request params are not generated correctly
/**
* Client implementing SOAP wsHttpBinding with message security. <br>
* NOTE: this is adapted to work for special needs of our client. It can be modified and there is a lot of work that jet needs to be done (nicer code, options and optimization).
*/
class WSSoap
{
/**
* Securit token request template
*/
const STS_TEMPLATE = <<<X
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</a:Action><a:MessageID></a:MessageID><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand="1"></a:To><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><u:Timestamp u:Id="_0"><u:Created></u:Created><u:Expires></u:Expires></u:Timestamp><o:UsernameToken u:Id="_1"><o:Username></o:Username><o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"></o:Password></o:UsernameToken></o:Security></s:Header><s:Body><t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"><t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType><t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType><t:Entropy><t:BinarySecret Type="http://schemas.xmlsoap.org/ws/2005/02/trust/Nonce"></t:BinarySecret></t:Entropy><t:KeySize>256</t:KeySize></t:RequestSecurityToken></s:Body></s:Envelope>
X;
/**
* Any action request template (mainly for headers)
*/
const KPS_TEMPLATE = <<<X
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><a:Action s:mustUnderstand="1">n</a:Action><a:MessageID></a:MessageID><a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand="1"></a:To><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><u:Timestamp u:Id="_0"><u:Created></u:Created><u:Expires></u:Expires></u:Timestamp><c:SecurityContextToken xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc"><c:Identifier></c:Identifier></c:SecurityContextToken><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"></SignatureMethod><Reference URI="#_0"> <Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue></DigestValue></Reference></SignedInfo><SignatureValue></SignatureValue><KeyInfo><o:SecurityTokenReference><o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct"></o:Reference></o:SecurityTokenReference></KeyInfo></Signature></o:Security></s:Header><s:Body></s:Body></s:Envelope>
X;
/**
* Namespaces
*/
const S11 = "http://schemas.xmlsoap.org/soap/envelope/";
const S12 = "http://www.w3.org/2003/05/soap-envelope";
const WSU = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
const WSSE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
const WSSE11 = "http://docs.oasis-open.org/wss/oasis-wss-wsecurity-secext-1.1.xsd";
const WST = "http://schemas.xmlsoap.org/ws/2005/02/trust";
const DS = "http://www.w3.org/2000/09/xmldsig#";
const XENC = "http://www.w3.org/2001/04/xmlenc#";
const WSP = "http://schemas.xmlsoap.org/ws/2004/09/policy";
const WSA = "http://www.w3.org/2005/08/addressing";
const XS = "http://www.w3.org/2001/XMLSchema";
const WSDL = "http://schemas.xmlsoap.org/wsdl/";
const SP = "http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702";
const SC = "http://schemas.xmlsoap.org/ws/2005/02/sc";
/**
* STS Properties
*/
protected $stsHostName;
protected $stsEndpoint;
protected $stsUsername;
protected $stsPassword;
protected $stsNamespace;
/**
* Binary secret used for generating request
*/
protected $requestSecret;
protected $rstrBinarySecret;
protected $rstrKeyIdentifier;
protected $token;
protected $tokenReference;
function __construct( $username, $password, $endpointURL, $namespace )
{
$this->stsUsername = $username;
$this->stsPassword = $password;
$this->stsHostName = parse_url( $endpointURL, PHP_URL_HOST);
$this->stsEndpoint = $endpointURL;
$this->stsNamespace = $namespace;
}
function request( $action, $fullActionName, $params )
{
$this->stsRequest();
$kpsDom = new \DOMDocument("1.0", "utf-8");
$kpsDom->preserveWhiteSpace = false;
$kpsDom->loadXML(static::KPS_TEMPLATE);
$kpsXpath = new \DOMXPath($kpsDom);
$kpsXpath->registerNamespace('S12', static::S12);
$kpsXpath->registerNamespace('WSA', static::WSA);
$kpsXpath->registerNamespace('WSU', static::WSU);
$kpsXpath->registerNamespace('WSSE', static::WSSE);
$kpsXpath->registerNamespace('XENC', static::XENC);
$kpsXpath->registerNamespace('DS', static::DS);
$kpsXpath->registerNamespace('SC', static::SC);
// Addressing
$uuid = $this->uuid();
$actionPath = $kpsXpath->query("//S12:Envelope/S12:Header/WSA:Action");
$messageIDPath = $kpsXpath->query("//S12:Envelope/S12:Header/WSA:MessageID");
$toPath = $kpsXpath->query("//S12:Envelope/S12:Header/WSA:To");
$actionPath->item(0)->nodeValue = $fullActionName;
$messageIDPath->item(0)->nodeValue = sprintf("urn:uuid:%s", $uuid);
$toPath->item(0)->nodeValue = $this->stsEndpoint;
// Timestamp
$time = time();
$dateCreated = gmdate('Y-m-d\TH:i:s\Z', $time);
$dateExpires = gmdate('Y-m-d\TH:i:s\Z', $time + (5 * 60));
$timestampPath = $kpsXpath->query("//S12:Envelope/S12:Header/WSSE:Security/WSU:Timestamp");
$timestampDateCreatedPath = $kpsXpath->query("//S12:Envelope/S12:Header/WSSE:Security/WSU:Timestamp/WSU:Created");
$timestampDateExpiresPath = $kpsXpath->query("//S12:Envelope/S12:Header/WSSE:Security/WSU:Timestamp/WSU:Expires");
$timestampDateCreatedPath->item(0)->nodeValue = $dateCreated;
$timestampDateExpiresPath->item(0)->nodeValue = $dateExpires;
$timestampC14N = $timestampPath->item(0)->C14N(true, false);
// DigestValue
$digestValue = base64_encode(hash('sha1', $timestampC14N, true));
$digestValuePath = $kpsXpath->query("//S12:Envelope/S12:Header/WSSE:Security/DS:Signature/DS:SignedInfo/DS:Reference/DS:DigestValue");
$digestValuePath->item(0)->nodeValue = $digestValue;
// Signature
$signaturePath = $kpsXpath->query("//S12:Envelope/S12:Header/WSSE:Security/DS:Signature/DS:SignedInfo");
$signatureValuePath = $kpsXpath->query("//S12:Envelope/S12:Header/WSSE:Security/DS:Signature/DS:SignatureValue");
$signatureC14N = $signaturePath->item(0)->C14N(true, false);
$psBinary = $this->psha1( $this->requestSecret, $this->rstrBinarySecret );
$signatureValue = base64_encode(hash_hmac("sha1", $signatureC14N, $psBinary, true));
$signatureValuePath->item(0)->nodeValue = $signatureValue;
// token reference
$securityContextTokenReference = $kpsXpath->query("//S12:Envelope/S12:Header/WSSE:Security/DS:Signature/DS:KeyInfo/WSSE:SecurityTokenReference/WSSE:Reference");
$securityContextTokenReference->item(0)->setAttribute('URI', "#$this->tokenReference");
// token ID
$tokenPath = $kpsXpath->query("//S12:Envelope/S12:Header/WSSE:Security/SC:SecurityContextToken");
$tokenPath->item(0)->setAttribute('u:Id', $this->tokenReference);
// token
$tokenPath = $kpsXpath->query("//S12:Envelope/S12:Header/WSSE:Security/SC:SecurityContextToken/SC:Identifier");
$tokenPath->item(0)->nodeValue = $this->token;
// Message
$bodyElemet = $kpsXpath->query("//S12:Envelope/S12:Body")->item(0);
$root = $kpsDom->createElementNS( $this->stsNamespace, $action );
foreach( $params as $name => $value ) {
$root->appendChild( $kpsDom->createElement( $name, $value ) );
}
$bodyElemet->appendChild( $root );
$kpsRequest = $kpsDom->saveXML();
// Request
try {
$stsResponse = $this->execCurl( $kpsRequest );
} catch ( \Exception $e ) {
throw $e;
}
return $stsResponse;
}
/**
* Performs a STS request
*
* @param string $location Request location
*/
protected function stsRequest()
{
$rstXml = static::STS_TEMPLATE;
$rstDom = new \DOMDocument("1.0", "utf-8");
$rstDom->preserveWhiteSpace = false;
$rstDom->loadXML($rstXml);
$rstXpath = new \DOMXPath($rstDom);
$rstXpath->registerNamespace('S12', static::S12);
$rstXpath->registerNamespace('WSA', static::WSA);
$rstXpath->registerNamespace('WSU', static::WSU);
$rstXpath->registerNamespace('WSSE', static::WSSE);
$rstXpath->registerNamespace('XENC', static::XENC);
$rstXpath->registerNamespace('DS', static::DS);
$rstXpath->registerNamespace('WST', static::WST);
$rstXpath->registerNamespace('WSP', static::WSP);
// Addressing
$uuid = $this->uuid();
$messageIDPath = $rstXpath->query("//S12:Envelope/S12:Header/WSA:MessageID");
$toPath = $rstXpath->query("//S12:Envelope/S12:Header/WSA:To");
$messageIDPath->item(0)->nodeValue = sprintf("urn:uuid:%s", $uuid);
$toPath->item(0)->nodeValue = $this->stsEndpoint;
// Timestamp
$time = time();
$dateCreated = gmdate('Y-m-d\TH:i:s\Z', $time);
$dateExpires = gmdate('Y-m-d\TH:i:s\Z', $time + (5 * 60));
$timestampDateCreatedPath = $rstXpath->query("//S12:Envelope/S12:Header/WSSE:Security/WSU:Timestamp/WSU:Created");
$timestampDateExpiresPath = $rstXpath->query("//S12:Envelope/S12:Header/WSSE:Security/WSU:Timestamp/WSU:Expires");
$timestampDateCreatedPath->item(0)->nodeValue = $dateCreated;
$timestampDateExpiresPath->item(0)->nodeValue = $dateExpires;
// Credentials
$usernamePath = $rstXpath->query("//S12:Envelope/S12:Header/WSSE:Security/WSSE:UsernameToken/WSSE:Username");
$passwordPath = $rstXpath->query("//S12:Envelope/S12:Header/WSSE:Security/WSSE:UsernameToken/WSSE:Password");
$usernamePath->item(0)->nodeValue = $this->stsUsername;
$passwordPath->item(0)->nodeValue = $this->stsPassword;
// Set binary key
$this->requestSecret = uniqid();
$binaryKeyPath = $rstXpath->query("//S12:Envelope/S12:Body/WST:RequestSecurityToken/WST:Entropy/WST:BinarySecret");
$binaryKeyPath->item(0)->nodeValue = base64_encode( $this->requestSecret );
// Endpoint
$stsRequest = $rstDom->saveXML();
// Request
try {
$stsResponse = $this->execCurl( $stsRequest );
} catch ( \Exception $e ) {
throw $e;
}
$rstrDom = new \DOMDocument("1.0", "utf-8");
$rstrDom->preserveWhiteSpace = false;
$rstrDom->loadXML($stsResponse);
$rstrXpath = new \DOMXPath($rstrDom);
$rstrXpath->registerNamespace('S12', static::S12);
$rstrXpath->registerNamespace('WSA', static::WSA);
$rstrXpath->registerNamespace('WSU', static::WSU);
$rstrXpath->registerNamespace('WSSE', static::WSSE);
$rstrXpath->registerNamespace('XENC', static::XENC);
$rstrXpath->registerNamespace('DS', static::DS);
$rstrXpath->registerNamespace('WST', static::WST);
$rstrXpath->registerNamespace('WSP', static::WSP);
$rstrXpath->registerNamespace('SC', static::SC);
// parse security context token
$securityContextTokenReference = $rstrXpath->query("//S12:Envelope/S12:Body/WST:RequestSecurityTokenResponse/WST:RequestedSecurityToken/SC:SecurityContextToken");
$this->tokenReference = $securityContextTokenReference->item(0)->getAttribute('u:Id');
$securityContextToken = $rstrXpath->query("//S12:Envelope/S12:Body/WST:RequestSecurityTokenResponse/WST:RequestedSecurityToken/SC:SecurityContextToken/SC:Identifier");
$this->token = $securityContextToken->item(0)->nodeValue;
$securityContextToken = $rstrXpath->query("//S12:Envelope/S12:Body/WST:RequestSecurityTokenResponse/WST:Entropy/WST:BinarySecret");
$this->rstrBinarySecret = base64_decode( $securityContextToken->item(0)->nodeValue );
}
protected function execCurl( $request )
{
// Request
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->stsEndpoint);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // disable SSL verification - re-enable if needed
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Host: " . $this->stsHostName,
"Content-Type: application/soap+xml; charset=utf-8",
"Content-Length: " . strlen( $request ),
));
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if ( $response === false ) {
throw new \Exception(curl_error($ch));
}
curl_close($ch);
return $response;
}
/**
* Generates UUID
*
* @return string UUID
*/
protected function uuid()
{
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', //
mt_rand(0, 0xffff), //
mt_rand(0, 0xffff), //
mt_rand(0, 0xffff), //
mt_rand(0, 0x0fff) | 0x4000, //
mt_rand(0, 0x3fff) | 0x8000, //
mt_rand(0, 0xffff), //
mt_rand(0, 0xffff), //
mt_rand(0, 0xffff) //
);
}
/**
* Calculate psha1 hash used for signature generation
* @param unknown $clientSecret
* @param unknown $serverSecret
* @param number $sizeBits
* @return string
*/
protected function psha1($clientSecret, $serverSecret, $sizeBits = 256)
{
$sizeBytes = $sizeBits / 8;
$hmacKey = $clientSecret;
$hashSize = 160; // HMAC_SHA1 length is always 160
$bufferSize = $hashSize / 8 + strlen($serverSecret);
$i = 0;
$b1 = $serverSecret;
$b2 = "";
$temp = null;
$psha = array();
while ($i < $sizeBytes) {
$b1 = hash_hmac('SHA1', $b1, $hmacKey, true);
$b2 = $b1 . $serverSecret;
$temp = hash_hmac('SHA1', $b2, $hmacKey, true);
for ($j = 0; $j < strlen($temp); $j++) {
if ($i < $sizeBytes) {
$psha[$i] = $temp[$j];
$i++;
} else {
break;
}
}
}
return implode("", $psha);
}
}
所以在请求中得到这样的东西:
<s:Header>
<a:Action s:mustUnderstand="1">https://some.url/NamespaceName/IServices/CheckTransaction</a:Action>
...
</s:Header>
<s:Body>
<CheckTransaction xmlns="https://sime.url/ActionToDo">
<TransactionID>1234567</TransactionID>
</CheckTransaction>
</s:Body>
代码将是:
$url = 'https://some.url/Services.svc';
$namespace = 'https://some.url/NamespaceName'; // this is action namespace you need, since there is no WSDL parsing you need to set it by yourself
try {
$c = new WSSoap( $username, $password, $url, $namespace );
$params = array(
'TransactionID' => '1234567'
);
$r = $c->request( 'CheckTransaction', 'https://some.url/NamespaceName/IServices/CheckTransaction', $params ); // also applies - no WSDL parsing so we need to set params
} catch (Exception $e) {
throw $e;
}