How to remove SOAP namespace from call - php

I'm trying to connect to a WSDL webservice using PHP SOAP. Now I need to remove the SOAP elements from the XML which is send. What I have now is the following:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://service.com">
<SOAP-ENV:Body>
<ns1:Calculate>
//Content
</ns1:Calculate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
What I want is the following:
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Calculate xmlns:ns1="http://service.com">
//Content
</ns1:Calculate>
Is there any way to accomplish this? Is SOAP the one I need to send such requests?

SOAP is protocol, and if you want to SOAP request both client and server side must accept and send back requests according to this protocol.
Just check these settings :
$client = new SoapClient("some.wsdl", array('soap_version' => SOAP_1_2));
Server may uses 1_2 or 1_1 version.
And you should contact with Web Service provider to get documentation about implementation of web service.

Override SoapClient class with a customized __doRequest. The new method removes the namespace references from the XML then calls the parent's __doRequest to fulfill the request with the modified XML. A simple but effective solution.
class MySoapClient extends SoapClient
{
public function __doRequest($request, $location, $action, $version, $one_way=0)
{
$request = str_replace('ns1:', '', $request);
parent::__doRequest($request, $location, $action, $version, $one_way);
}
}
# Invoke derived class instead of base class SoapClient
$client = new MySoapClient($wsdl, $options);

If you want to make a SOAP request, these tags are required. Is it really SOAP server on your opposite trying to make request?

Related

How does it work with the magic WSDL URI query parameter?

I'm building a Soap server within a Symfony application. As first step I created a controller with my "hello world" Soap action and defined the route for it:
routing.yml
api.soap.foo
path: /soapapi/foo
defaults: { _controller: SoapBundle\Controller\FooController:bar }
methods: [GET, HEAD, POST]
FooController#bar(...)
protected function bar(Request $request)
{
$autodiscover = new AutoDiscover();
$autodiscover
->setClass(MyFooBarService::class)
->setUri('http://my-app.loc/soapapi/foo/bar')
->setServiceName('MyFooBarService')
;
$wsdl = $autodiscover->generate();
$wsdl->dump(__DIR__ . '/soapapi-foo-bar.wsdl');
$server = new SoapServer(__DIR__ . '/soapapi-foo-bar.wsdl');
$server->setObject($this->myFooBarService);
$response = new Response();
$response->headers->set('Content-Type', 'text/xml; charset=ISO-8859-1');
ob_start();
$server->handle();
$response->setContent(ob_get_clean());
return $response;
}
Now, when I call http://my-app.loc/soapapi/foo/bar in a browser or using cURL (so via HTTP GET), I get an error:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>Bad Request</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
But when I call http://my-app.loc/soapapi/foo/bar?wsdl, I actually get the (generated) WSDL document. Why? I have not defined anywhere, that it should work like this. Why and how does this (magic) work? Is it Symfony specific magic?
This is a great question.
No this is not Symfony specific, it's a behavior of the built-in SOAP server in PHP. When the endpoint URL is accessed with ?wsdl appended, the SOAP server will respond with the wsdl document that it was instantiated with in the constructor:
$server = new SoapServer(__DIR__ . '/soapapi-foo-bar.wsdl');
I haven't been able to find where this behavior is documented on the PHP website, but it clearly exists and is reproducible.
The code for the feature can be found in PHP's source code starting on line 1369 and ending on line 1396. The code checks if the request method is GET and checks for the presence of a 'wsdl' query parameter.

Make and Display SOAP Request via PHP

I want to learn how to make a SOAP request and then post response in PHP. Here is my request code: http://pastebin.com/PBb2i0XN
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://www.restfulwebservices.net/ServiceContracts/2008/01">
<SOAP-ENV:Body>
<ns1:GetStockQuote>
<ns1:request>Goog</ns1:request>
</ns1:GetStockQuote>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
WSDL is http://www.restfulwebservices.net/wcf/StockQuoteService.svc?wsdl
PHP has a wrapper for SOAP. Check out http://php.net/soap. This should solve all your problems.
You first instantiate a SoapClient class using the following syntax.
$client = new SoapClient("some.wsdl");
You can then use the SoapClient::__getFunctions() method to determine the different functions your WSDL gives you.
public array SoapClient::__getFunctions ( void )
This client will enable you to call the soap functions from your WSDL as if they were PHP functions
For example in order to call the GetStockQuote method from your WSDL, all you have to do is the following.
$client = new SoapClient("http://www.restfulwebservices.net/wcf/StockQuoteService.svc?wsdl");
$client->GetStockQuote();
Also when you use the getFunctions method, you will get a list of all parameters each method in the WSDL expects.
Hope this was helpful. All the best.

PHP SoapClient - Possible name spacing issues - non-wsdl mode

I previously managed to call a .NET service using PHP's SoapClient library without too many issues, but now I face a scenario where I have to access the same services in non-WSDL mode.
I seem to have created, more or less, the correct XML structure to send through to the service, but the server does not seem to be picking up the variables I am sending.
Based on output from SOAPUI, I should be attempting to generate the following SOAP call:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:int="http://someservices.com/">
<soapenv:Header/>
<soapenv:Body>
<int:getService>
<int:foo>String value for foo</int:foo>
<int:bar>String value for bar</int:bar>
</int:getService>
</soapenv:Body>
</soapenv:Envelope>
The output that I am generating with SOAPClient is:
<?xml version="1.0" encoding="UTF-8"?> <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://someservices.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
<env:Body>
<ns1:getService env:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<foo xsi:type="xsd:string">String value for foo</foo>
<bar xsi:type="xsd:string">String value for bar</bar>
</ns1:getService>
</env:Body>
</env:Envelope>
The error returned from the .NET service is "bar expected!" - indicating, at the very least, that the service is not picking up my second parameter.
I am constructing my soap call using the following:
$foo = 'String value for foo';
$bar = 'String value for bar';
$options = array(
'trace' => 1,
'exceptions' => 1,
'uri' => 'http://someservices.com',
'soapaction' => 'http://someservices.com/getService',
'soap_version' => SOAP_1_2,
'type_map' => array('type_ns' => 'int')
);
$response = $soapclient->__soapCall('getService', array( new SoapParam($foo, 'foo'), new SoapParam($bar, 'bar')), $options);
I am not sure what the issue is. Right now I am guessing that it might be an xmlns attribute issue. Note that the SOAPUI call specifies the int: in front of the function calls and parameters. I have tried to specify this xmlns but without luck. As you can see xmlns generated by Soap Client call is:
xmlns:ns1
Any help would be greatly appreciated.
As it turns out, having the namespace labelled as ns1 instead of int was not the issue.
The problem was that the getService parameter was being prefixed with the namespace ns1, whilst the variables foo and bar were not.
As such, this was resolved by appending "ns1:" to the Soap Params in the soapCall function, as follows:
$response = $soapclient->__soapCall('getService', array( new SoapParam($foo, 'ns1:foo'), new SoapParam($bar, 'ns1:bar')), $options);

Switching from NuSoap to PHP5 Soap - need a jumpstart

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>
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.

php soap question: howto create custom namespace

I am using php soap. I can't get my soap body to include a custom namespace.
Here is an example of what I want:
<?xml version='1.0' encoding='UTF8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<tns:MyCall xmlns:tns="my.sx"><tns:op>getStuff</tns:op><tns:args />
</tns:MyCall>
</soapenv:Body>
</soapenv:Envelope>
I can't get the namespace called tns to appear inside the body, or the elements op and args.
Can anyone suggest how this is done?
My code looks like:
$client = CreateSoapClient();
try{
$result = $client->__soapCall(
'MyCall',
array(), // no params
array(
'uri' => 'urn:Myurn',
'soapaction' => 'urn:Myurn'
));
?>
You need to define your namespace in your WSDL. It's probably easiest to just use the Zend WSDL autogenerator, which I believe will let you set the namespace. Let me know if you need more information.

Categories