3

Here's the call I'm trying to make:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <urn:SessionHeader  xmlns:urn="http://www.mywebservice.com/webservices/SoapService" xmlns="http://www.mywebservice.com/webservices/SoapService" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <urn:sessionId xmlns:urn="http://www.mywebservice.com/webservices/SoapService">LOGINTOKEN=your instance name</urn:sessionId>
    </urn:SessionHeader>
</soap:Header>
<soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <ns2:login xmlns:ns2="http://www.mywebservice.com/webservices/SoapService">
        <wsUser>
            <entityId>0</entityId>
            <password>your password</password>
            <username>your username</username>
        </wsUser>
    </ns2:login>
</soap:Body>

But I'm having trouble finding out how to set up the custom headers in PHP5's Soap. With nuSoap I could just put the whole thing into a variable and then use $client->setHeader($headerVar) but I can't find anything similar in PHP. If I could replicate this one call, I can figure the rest out. Any help would be appreciated!

Thanks in advance!

Update: I've gone through tutorial after tutorial, and read the PHP docs, but nothing seems to work. I can do what I want with curl (as well as nuSoap) but I thought the native PHP5 Soap would be easier and possibly more stable. I guess not...

Update 2 Here's the code I'm trying:

$soapurl = 'http://www.mywebservice.com/webservices/SoapService?wsdl';
$client = new SoapClient($soapurl,array('trace'=>true));
$token = "LOGINTOKEN=your instance name";

$header = new SoapHeader('http://www.mywebservice.com/webservices/SoapService', 'SessionHeader', array('sessionId' => $token));
$client->__setSoapHeaders($header);


$client->login(array("wsUser" => array('entityId'=>'0','username'=>'my username','password'=>'my password')));

And the error I get:

**Fatal error**: Uncaught SoapFault exception: [ns1:InvalidSecurity] An error was discovered processing the <wsse:Security> header in C:\www\soap\index.php:12 Stack trace: #0 C:\www\soap\index.php(12): SoapClient->__call('login', Array) #1 C:\www\soap\index.php(12): SoapClient->login(Array) #2 {main} thrown in C:\www\soap\index.php on line 12

Update 3 So it looks like the "sessionId" is being sent as "key" with the token sent as "value".

 *REQUEST*:
    <?xml version="1.0" encoding="UTF-8"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.mywebservice.com/webservices/SoapService">
<SOAP-ENV:Header>
<ns1:SessionHeader><item><key>sessionId</key><value>LOGINTOKEN=my token</value></item>
</ns1:SessionHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body><ns1:login><wsUser><entityId>0</entityId><password>my password</password><username>my username</username></wsUser></ns1:login></SOAP-ENV:Body></SOAP-ENV:Envelope>
Charles
  • 50,943
  • 13
  • 104
  • 142
TerryMatula
  • 1,264
  • 2
  • 14
  • 29
  • SoapClient::__setSoapHeaders() doesn't do what you want? http://php.net/soapclient.setsoapheaders – Daniel R Sep 22 '10 at 04:56
  • It might, and I've experimented with implementing it, but I can't figure out how to make it return that exact format. – TerryMatula Sep 24 '10 at 14:15

1 Answers1

2

Have you tried the SoapHeader class to construct your header? Would something like this work?

//Assume $token holds your login token and $client holds the SoapClient object
$header = new SoapHeader('http://www.mywebservice.com/webservices/SoapService', 'SessionHeader', array('sessionId' => $token));
$client->__setSoapHeaders($header);

That should create the header and add it to the SoapClient. Every subsequent call using the SoapClient will then have that header set. As to the exact format, I wouldn't worry too much. You sample XML uses an alias for the namespace called urn. PHP probably won't arrive at exactly the same alias but it should still work. Also I don't think that declaring the xmlns in every child element is needed. I think that a child node automatically inherits the namespace of its parent in XML, but I'm not 100% certain on that. The bottom line is that as long as the right URL's are declared in the namespaces it should be fine even if the XML doesn't exactly match your example.

One other thing you could try-have you switched on tracing in the SoapClient? This is one of the parameters that can be passed to the constructor and it enables you to view the XML SOAP requests and responses. If it still doesn't work using the SoapHeader class try switching tracing on to see what's being sent and received.

Jeremy
  • 2,651
  • 1
  • 21
  • 28
  • Can't get it working. I get an "Uncaught SoapFault exception". See my edit for more info... – TerryMatula Feb 14 '11 at 20:31
  • The SoapFault is thrown if the Soap Response from the service contains an error (soap fault). Can you catch the exception and access the error message? It might give you some valuable info as to what's going on. Also try turning on the tracing and dumping the XML that is being sent and received. Could you post back when you've done that and I'll see if I can think of any other suggestions. – Jeremy Feb 14 '11 at 20:37
  • just submitted an edit to the question. Thanks for the help. – TerryMatula Feb 14 '11 at 20:39
  • Just looking at your code: you are replacing "LOGINTOKEN=your instance name" with an actual login token value aren't you? Sorry if that seems like an obvious question. Try wrapping your code in a try{}catch{} block to catch any Soap Faults that are raised. You can then dump information about them. Also, could you turn on tracing and post the raw XML that is sent as the SOAP request? If you turn on tracing it should be available in the SoapClient::__getLastRequest() method after the request has been sent. – Jeremy Feb 14 '11 at 21:04
  • updated. Looks like I found the problem, just not sure how to fix it. – TerryMatula Feb 14 '11 at 21:29
  • I think you might have this a bit mixed up, but I can't be sure without knowing the web service you're trying to interact with. At least with other services I've seen like this you would call the login method before you set the Soap Headers. This method will return a token to you, which you then use to create the soap headers which can be used to interact with other methods of the service. I've been working with the SalesNet API recently where you do just that. You log in through a security soap service which returns a token to use with the other services. HTH. – Jeremy Feb 15 '11 at 01:06
  • Yeah, it's not the best SOAP server, which is why I've been having so many problems. The initial token is a static value: LOGINTOKEN=xxxxx . This initial SOAP call is used to get a SessionId that gets passed with all subsequent calls. If I can just get this call working, and return the SessionId, I won't have a problem with the rest. Thanks for the help. – TerryMatula Feb 16 '11 at 14:55
  • Sorry to take a little while to get back to you. Does the SoapService to login have the same endpoint (URL) as the service to perform other requests? You will need to login, getting the token from the service, and then use that to set the SoapHeader. – Jeremy Feb 17 '11 at 12:11