0

I intent to implement a webservice using PHP. The creators of the web-service sent me the WSDLs required via email and I was able to import them into Soap UI and test them.

Seeing that they work just fine, I'm tasked with repeating the same process in my PHP application. I did a bit of googling around, to find that PHP5 already supplies a SoapClient to consume webservices. I even tested two examples and they worked just fine. But not the one that was running using Soap UI.

SoapClient receives a URI of the WSDL file as the first parameter1 - is this the url of the service that soapui shows in the top bar? I noticed that the other webservices I tested, if the uri was copied and pasted to a browser, an XML format would be returned with the data regarding the webservice. With the data soapui was pointing as the endpoint, the browser would simply output a "Lenght Required" 411 error message.

So my question is, is the .xml file that SOAP ui uses to import a project the one I should point in my php? Like:

SoapClient ( "file:://C:\users\something\webservice.xml?wsdl",
['service'=>'login', 'username'=>'something', 'password'=>'secret' ] );

I would expose the .xml I received with the webservice information, but I'm afraid of leaking sensitive data. I will copy the header of the request, ommiting any sensitive data

<?xml version="1.0" encoding="UTF-8"?>
<con:soapui-project activeEnvironment="Default" name="" resourceRoot="" soapui-version="5.2.0" abortOnError="false" runType="SEQUENTIAL" id="" xmlns:con="..."><con:settings/><con:interface xsi:type="con:WsdlInterface" wsaVersion="NONE" name="..." type="wsdl" bindingName="{...}GenericTicketConnector_Service" soapVersion="1_1" anonymous="optional" definition="file:/D:/.../Documents/file.wsdl" id="..." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:settings/><con:definitionCache type="TEXT" rootPart="file:\D:\...\Documents\file.wsdl"><con:part><con:url>file:\D:\...\Documents\file.wsdl</con:url><con:content><![CDATA[<--!...-->
<wsdl:definitions name="GenericTicketConnector" targetNamespace="http://www.otrs.org/TicketConnector/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.otrs.org/TicketConnector/">
  <wsdl:documentation/>
  <!--Warning: This WSDL file is for Development and Test purposes ONLY!-->
  <wsdl:types>
    <xsd:schema targetNamespace="http://www.otrs.org/TicketConnector/">

After this the .xml file looks like a normal wsdl file, describing the webservices supplied, the format of the request, the respose... etc...

Thank you.

Community
  • 1
  • 1
Thaenor
  • 611
  • 1
  • 9
  • 28

1 Answers1

1

I'm not that familiar with SoapUI, but for the WSDL parameter of the ctor of SoapClient (first parameter) it's not much of a difference if you have it as a HTTP URL or a path to a local file.

Consider the following example which downloads the WSDL file on the fly to the directory where the example script is stored and then uses the local file instead of the URL:

// just an example webservice WSDL
$wsdl = 'http://www.webservicex.net/globalweather.asmx?WSDL';

// store the WSDL file in current directory if it does not yet exist
$filename = __DIR__ . '/globalweather.asmx.wsdl';
if (!is_readable($filename)) {
    file_put_contents($filename, fopen($wsdl, 'r'));
}

$soapclient = new SoapClient($filename);
$params     = ['CountryName' => 'Spain', 'CityName' => 'Alicante'];
$response   = $soapclient->getWeather($params);

var_dump($response);

The response is an (unmapped) stdClass for the GetWeatherResult from the webservice. Already the $soapclient->getWeather call works which only would be the case if the WSDL is successfully loaded.

Note: On the Windows operating system, the question mark ("?") is not valid in a file-name, so take care that you use only valid filenames.

The WSDL file contains all data need to be known to interact with the webservice. So you don't need any more infos.

...
  <wsdl:service name="GlobalWeather">
    <wsdl:port name="GlobalWeatherSoap" binding="tns:GlobalWeatherSoap">
      <soap:address location="http://www.webservicex.net/globalweather.asmx" />
    </wsdl:port>
...

As this example shows, the WSDL contains the concrete URI SoapClient (or SoapUI for that matter) will send HTTP requests to. Try with the local file within SoapUI as well if it accepts it or not.


Edit: The WSDL file of the OTRS Websvervice is available on Github, here is the example adopted to the OTRS webservice, just listing the methods and the types:

$wsdl = 'https://raw.githubusercontent.com/OTRS/otrs/master/development/webservices/GenericTicketConnectorSOAP.wsdl';

// store the WSDL file in current directory if it does not yet exist
$filename = __DIR__ . '/GenericTicketConnectorSOAP.wsdl';
if (!is_readable($filename)) {
    file_put_contents($filename, fopen($wsdl, 'r'));
}

$soapclient = new SoapClient($filename);
print_r($soapclient->__getFunctions());
print_r($soapclient->__getTypes());

Output:

Array
(
    [0] => TicketCreateResponse TicketCreate(TicketCreate $parameters)
    [1] => TicketUpdateResponse TicketUpdate(TicketUpdate $parameters)
    [2] => TicketGetResponse TicketGet(TicketGet $parameters)
    [3] => TicketSearchResponse TicketSearch(TicketSearch $parameters)
    [4] => SessionCreateResponse SessionCreate(SessionCreate $parameters)
)
...
hakre
  • 193,403
  • 52
  • 435
  • 836
  • I tried changing the address so it would call the "soap file". Like so: ` $client = new SoapClient("file:///C:/Users/nb21334/Desktop/OTRSTicketConnector-soapui-project.wsdl",$params);` - but I got the error `SOAP-ERROR: Parsing WSDL: Couldn't find in 'file:///C:/Users (rest of the path to file)`- I tried with both .xml and .wsdl extensions. – Thaenor Aug 09 '15 at 15:18
  • 1
    Sounds like the WSDL file is incomplete. Contact OTRS and ask them what the `` of the Webservice are and why the element is missing in the WSDL file. They might have an reason for that. Depending on what is missing you can also provide data via the options. – hakre Aug 09 '15 at 15:45
  • I think I'm not using the proper file. Either I need to generate the wsdl myself or there's something else missing. Is there a way I can manually write the xml that gets attached to the request and manually sent it to the servers? The error I'm getting happens because I'm not feeding the correct wsdl to php. (on PHP the request doesn't even get sent, I know this because I get exactly the same error independantly of being online or offline) – Thaenor Aug 09 '15 at 18:00
  • 1
    You *get* the WSDL from the vendor of the webservice, you normally do not create it yourself. It should spare you work. The WSDL from the example I posted is not that large. You can use it to orient yourself with it. It's perhaps not the best example, but it's self-containing and you should be able to get it to run within minutes. It downloads the WSDL for you, you can look into it after you executed the script the first time. Give it a try. – hakre Aug 09 '15 at 18:05
  • I think I'm making some progress. I declared the soap client in non wsdl mode. So I just did $client SoapClient = (null, $params); used the same url to the server as url and uri. vardumping the $client variable turned something like this `object(SoapClient)[247] public 'uri' => string 'url' (length=90) public 'location' => string 'uri' (length=85) public '_soap_version' => int 1` By then doing a SoapCall it printed an extra line `public 'httpurl' => resource(214, Unknown)` - So I think this is working, I just have to figure out how to read those values – Thaenor Aug 09 '15 at 18:15
  • 1
    Try that both together, take your local WSDL file and the options. – hakre Aug 09 '15 at 18:30
  • You mean use the .xml I received to import to SoapUI? That would be the url or uri? Btw, I added a soapCall to a new variable and it vardumping that shows an error code and error message "password parameter is missing". Before you ask, SOAP ui shows a parameter 'Password' and I'm sure the value to it is correctly written – Thaenor Aug 09 '15 at 18:47
  • 1
    which authentication is the service using? Is it on the HTTP level of the protocol? Check the password and auth options for the second parameter of **SoapClient** ctor: http://php.net/soapclient.soapclient – hakre Aug 09 '15 at 18:51
  • As far as I know there's no authentication. That process I was doing is a function that returns a session key. That session key is then used to fetch the data I really need. How do I verify these settings in soapui? From what I can tell it's just a header less soap request. It takes one userLogin, an optional name and the password. I'm declaring these as an array and passing them in the soapCall request (which I heard is deprecated). – Thaenor Aug 09 '15 at 21:36
  • 1
    Then authentication is not on the transport layer but on the level of the service itself. I strongly recommend you contact OTRS and as for the WSDL `` so you don't need to do so much guesswork. IIRC `SoapClient::__soapCall` is not deprecated but just a low-level function if you're in non-WSDL mode. – hakre Aug 09 '15 at 21:44
  • 1
    @Thaenor: btw: https://github.com/OTRS/otrs/tree/master/development/webservices via: http://stackoverflow.com/q/25068807/367456 -> http://forums.otterhub.org/viewtopic.php?f=53&t=25984&p=103824#p103824 - Probably OTRS did never provide you a WSDL? – hakre Aug 09 '15 at 21:46
  • 1
    @Thaenor: I'll update the answer in a minute, it's nearly the same example, just with the OTRS WSDL file, got it to run in less than 3 minutes, this is why you need to obtain the WSDL file first. – hakre Aug 09 '15 at 21:55
  • This is not an official OTRS module. This was developped by a team that manages "my" company OTRS instance. I actually developped the DB query that aquired the information I needed. They wrapped that in a webservice so I could remotely fetch data. – Thaenor Aug 09 '15 at 22:28
  • The service I'm trying to invoke is [SessionCreate](https://github.com/OTRS/otrs/blob/master/development/webservices/GenericTicketConnectorSOAP.wsdl#L2166) on line 2166 – Thaenor Aug 09 '15 at 22:37
  • I just want to share some developments. I was able to export a .wsdl from SOAPUI and feed that as the wsdl on the soapClient constructor. Now I'm able to use functions such as __getFunctions() or __getTypes() that sucesfully dump information regarding the class I can make to the webservice and the time of input required. I'm trying to make a call after that with ` $client->SessionCreate("SessionCreate", array( "SessionCreate" => array( "UserLogin" => "username", "Password" => "secret" ))); ` returns The request is empty! – Thaenor Aug 10 '15 at 00:03
  • Actually it prints SessionCreate.MissingParameterSessionCreate: The request is empty! - because that's the return value of __getLastResponse - There is no actual error on the code (not one that breaks the try block at least) – Thaenor Aug 10 '15 at 00:05
  • You have to call the method with the correct parameter types and so on and so forth. That's where you start to roll. Most important thing is that you can initialize the SoapClient with the WSDL. Which I think is your original question here. The rest is using that interface I hope you have a good start with SOAP. Take a look for examples with that interface specifically. – hakre Aug 10 '15 at 06:27