Клиент PHP Soap с WCF BadContextToken

После нескольких дней google -ing / try / losing hair я все еще не могу найти решение для этого, пожалуйста, помогите 🙂

Краткая информация:
Мне нужно работать с WCF-сервисом с PHP (SOAP-клиент). Он использует 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, но без успеха, запрос все еще зависает.
3) Попытка «самогенерированного» запроса CURL с заголовком SOAPAction. Наконец, я получил некоторую ошибку там (я сгенерировал запрос с классом 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, hashed password, простой пароль и множество других вещей, которые я сейчас не могу вспомнить.
Я также попытался скомпилировать 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 (и, если это поможет, пожалуйста, понять, как это сделать)?

Я решил это некоторое время назад, но никогда не успевал сделать его более «приятным». Таким образом, в целом проблема заключалась в том, как работает защита сообщений wsHttpBinding и как ее реализовать на PHP. Я использовал концепцию из https://github.com/enginaygen/kps-soap-client/blob/master/KPSSoapClient.php, а также добавил psha1 от реализации алгоритма P_SHA1 в PHP .

Таким образом, он должен работать:

  1. Запрос PHP для маркера безопасности из WSS с его секретным запросом
  2. WS генерирует маркер безопасности и возвращает его на PHP
  3. PHP генерирует подписанное сообщение SOAP C14N с запрошенным маркером безопасности

Вот пример : я не реализовал его, расширив PHP-мыльный клиент из-за проблем с импортом WSDL. Также, как я уже сказал, я использовал концепции других людей и никогда не делал очистку кода, особенно создание 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('Ymd\TH:i:s\Z', $time); $dateExpires = gmdate('Ymd\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('Ymd\TH:i:s\Z', $time); $dateExpires = gmdate('Ymd\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; }