Confluence soap api defines two methods with the same name but different parameters:
Page getPage(String token, long pageId) - returns a single Page (according to the documentation the second parameter is String, but in WSDL it is long)
Page getPage(String token, String spaceKey, String pageTitle) - returns a single Page
I would need to call the method with two parameters using PHP SoapClient. In WSDL mode SoapClient insists on using the three-parameter one. In non-WSDL mode I managed to make a call with two parameters, but I cannot make the type of the second parameter to be long. How can I get the SoapClient to call getPage with two parameters with the correct types?
Here's what I've done so far:
Using SoapClient in WSDL mode...
$soapClient = new SoapClient("http://xxx/confluence/rpc/soap-axis/confluenceservice-v1?wsdl", array("trace" => TRUE));
$token = $soapClient->login(CONFLUENCE_USERNAME, CONFLUENCE_PASSWORD);
$page = $soapClient->getPage($token, $confluence_article_id);
...produces a request for the three-parameter method (only body shown)...
<SOAP-ENV:Body><ns1:getPage><in0 xsi:type="xsd:string">dkjLIx00Ap</in0><in1 xsi:type="xsd:string">24445207</in1><in2 xsi:nil="true"/></ns1:getPage></SOAP-ENV:Body>
...which causes fault:
<faultstring>com.atlassian.confluence.rpc.RemoteException: You're not allowed to view that page, or it does not exist.</faultstring>
The page with that ID does exist and I am allowed to see it, which I can confirm by making the correct kind of request with SoapUI.
Using SoapClient is non-WSDL mode...
$soapClient = new SoapClient(null, array(
"location" => "http://xxx/confluence/rpc/soap-axis/confluenceservice-v1",
"uri" => "http://soap.rpc.confluence.atlassian.com",
"trace" => TRUE));
$token = $soapClient->login(CONFLUENCE_USERNAME, CONFLUENCE_PASSWORD);
$page = $soapClient->getPage($token, $confluence_article_id);
...produces a request for the two-parameter method with incorrect type for the second parameter. When $confluence_article_id is string, the request is...
<SOAP-ENV:Body><ns1:getPage><param0 xsi:type="xsd:string">8Or94ZLqe7</param0><param1 xsi:type="xsd:string">24445207</param1></ns1:getPage></SOAP-ENV:Body>
...which returns the same fault as above:
<faultstring>com.atlassian.confluence.rpc.RemoteException: You're not allowed to view that page, or it does not exist.</faultstring>
When $confluence_article_id is integer, the request is...
<SOAP-ENV:Body><ns1:getPage><param0 xsi:type="xsd:string">y0kF4z0m9L</param0><param1 xsi:type="xsd:int">24445207</param1></ns1:getPage></SOAP-ENV:Body>
...which returns a different kind of fault:
<faultstring>org.xml.sax.SAXException: Bad types (int -> class java.lang.String)</faultstring>
If I take the request, change int to long and try it with SoapUI, it works just fine.
I have also tried to call it using __soapCall, but the results are similar:
$page = $soapClient -> __soapCall('getPage', array('in0'=>$token,'in1'=>$confluence_article_id));
There is a related PHP bug report and another one, and discussion on Atlassian forums, but none of them helped me.
So far the best suggestion has been to tweak the WSDL by removing the other getPage definition and saving it locally somewhere.
If I remember correctly you can call the function using an associative array instead ex:
//Page getPage(String token, String spaceKey, String pageTitle)
$soapClient->getPage(array("token" => $token,"spaceKey" => $spaceKey,"pageTitle" => $pageTitle));
Not tested, standard warnings apply
Related
I'm using PHP SoapClient with WSDL. Web service returns such functions:
0. BaseHotelSearchRsp service(HotelSearchAvailabilityReq $parameters)
1. HotelMediaLinksRsp service(HotelMediaLinksReq $parameters)
2. HotelDetailsRsp service(HotelDetailsReq $parameters)
When i'm invoking service in such way:
$mySoapClient = new \SoapClient($wsdl_location);
$mySoapClient->__soapCall('service', array($params));
It always call method 0. BaseHotelSearchRsp service(HotelSearchAvailabilityReq $parameters) with HotelSearchAvailabilityReq parameters.
Even $mySoapClient validates $params on HotelSearchAvailabilityReq suitable parameters (i.e. it does not include into SOAP request passed parameters which are not valid for HotelSearchAvailabilityReq data types).
Question would by how to call another service method ? i.e. 2. HotelDetailsRsp service(HotelDetailsReq $parameters)
I presume each parameter HotelSearchAvailabilityReq, HotelMediaLinksReq and HotelDetailsReq inherits from a base struct, or maybe not. Nevertheless, if you use a different class for each struct type and uses the classmap option, it might work.
If it does not work, then I already faced this issue and had to override the SoapClient::__doRequest method in order to update the XML request sent in order to ensure that the sent element has the good type.
Did you use a WSDL to php generator to ease the request creation and sending process? Did you try PackageGenerator?
Its simple, call it as function:
$client = new SoapClient ($wsdl_location);
$response = $client->HotelDetails($params);
I'm working with a SOAP API, and they've disabled the WSDL document that's normally located in the base .asmx URL for SOAP APIs. The page is instead a 404 page when viewed without an XML request. Right now, simply instantiating a SoapClient fails ($soap = new SoapClient($url);, the error is Premature end of data in tag html line 1). I'm assuming here that a new instance of SoapClient tries to retrieve the WSDL from the server. Is there a way of turning this off? Of saying 'I want to use SoapClient, but don't do any calls until I tell you the XML call that you'll be using (along with all required data)'?
EDIT: I've tried setting cache_wsdl to WSDL_CACHE_NONE but I still get that error.
You have to run SoapClient in non-wsdl mode therefore you must set the wsdl parameter of the SoapClient c'tor to null
public SoapClient::SoapClient ( mixed $wsdl [, array $options ] )
Initialize it the following way
$client = new SoapClient(null, array('location' => http://your_domain/your_webservice",
'uri' => "http://namespace_of_the_webservice/"));
location...The location of the webservice
uri...The namespace of the target webservice
I received a manual to internal SOAP interface of my partner. It says:
MyPARTNER web services are provided in the form of a SOAP interface. The service is available in this URL: https://justsomeurl.com:435/soap
then some bla bla about authorization etc. and then a part about Accessible Methods:
pull()
The PULL method is used for pulling data from the database. The method
receives a unique data based parameter under an internal name
requestXML. This parameter contains data in a structured XML format.
String pull(String requestXML)
The XML contains data required to make the request, and the response
data is sent back.
then some other methods, error codes, it's not important here...
The problem is that I'm totally unexperienced in SOAP so I don't know how to use this interface via PHP. I've tried to find some examples, tutorials and I am now little bit more informed about SOAP and its functionality but still haven't found any advice about how to use interface like this...
thanx for any help
Php comes with PHP SOAP libraries, that usually are included and enabled after a common php installation.
Yuo are asked to biuld the client part of the webservice pattern. Your partner should provide you the .wsdl of the web service. The wsdl describes the avialble method, the parameters they need and what they return.
Tipically parameters and return values are array structures
This could be a skeleton for your code:
//build a client for the service
$client = new SoapClient("partner.wsdl");
//$client is now a sort of object where you can call functions
//prepare the xml parameter
$requestXML = array("parameter" => "<xml>Hello</xml>");
//call the pull function this is like
$result = $client->__soapCall("pull", $requestXML );
//print the value returned by the web service
print_r($result);
Here follows a non-wsdl example
First the location paramater is the address the SOAP request will be sent to.
The uri parameter is the target namespace of the SOAP service. This is related to xml namespaces.
A sample code for you could be:
//for URI specification you should watch your partners documentation. maybe also a fake uri (like mine) could work
//build a client for the service
$client = new SoapClient(null, array(
'location' =>
"https://justsomeurl.com:435/soap",
'uri' => "urn:WebServices",
'trace' => 1 ));
// Once built a non-wsdl web service works as a wsdl one
//$client is now a sort of object where you can call functions
//prepare the xml parameter
$requestXML = array("parameter" => "<xml>Hello</xml>");
//call the pull function this is like
$result = $client->__soapCall("pull", $requestXML );
//print the value returned by the web service
print_r($result);
Here a useful link: http://www.herongyang.com/PHP/SOAP-Use-SOAP-Extension-in-non-WSDL-Mode.html
I'm trying to use Zend_Soap_Client to communicate with an ASP.net web service. Here's my client call:
$client = new Zend_Soap_Client(null, array(
'location' => 'http://example.com/service.asmx',
'uri' => 'http://example.com/'
));
$user = new UserDetail();
$result = $client->UserDetails($user);
However this always gives me the error:
System.NullReferenceException: Object reference not set to an instance of an object. at Service.UserDetails(UserDetail UserDetail)
some googling revealed that this is quite a common problem. The most common solution seemed to be to pass the parameters as an array, so I tried:
$result = $client->UserDetails(array('UserDetail' => $user));
but this gave the same error. I also tried passing the params as a stdClass object, nesting the array in another with 'params' as the key, and a few other things but the error is always the same.
I have the ASP code for the web service itself, the relevant method is:
public Result UserDetails(UserDetail UserDetail) {
[some stuff]
Hashtable ht = new Hashtable();
ht = UserDetail.GenerateData();
}
the error is caused by the GenerateData() call.
I assume the UserDetails method is getting null instead of my object as the parameter, but I'm not sure how I should be calling the method, or how I can debug this further. The majority of the Zend_Soap_Client examples I've found seem to be using WSDL, which this service is not; not sure if that is relevant. Any help appreciated!
I eventually solved this with:
$userDetails = new UserDetails();
$userDetails->UserDetail = $user;
$client->UserDetails($userDetails);
it seems ASP.net expects (and returns) params to be nested in an object/array with the same name as the method being called.
If you have any possibility to change the asp.net code I'd suggest you try an implementation of the method UserDetails without parameters just to make sure that code isn't broken.
I would then create a consumer-method in asp.net, debug the http-request and see how the userdetail-object is serialized/broken down in array form. Then it's "just" a matter of creating a similar http request from php.
The question:
Is there a way to view the XML that would be created with a PHP SoapClient function call BEFORE you actually send the request?
background:
I am new to WSDL communication, and I have a client who wants me to develop in PHP, a way to communicate with a WSDL service written in ASP.NET. I have gotten pretty far, but am running into an issue when it comes to passing a complex type. I have tried a couple of different things so far.
1) Setting up a single array such as $params->Person->name $params->Person->address
2) Setting up a single array $Person = array('name'=>"joe",'address' = "123");
then passing into the call as a param "Person" => $Person;
and a few others. But every time I get the error
SoapException: Server was unable to
process request ---> System.Exception:
Person is Required. at service name.
In order to further the troubleshooting, I would like to see the XML document that is being sent to see if it is creating a complex type in the way I am expecting it to.
I am creating the service using $client = new SoapClient('wsdldoc.asmx?WSDL'); calling it with $client->CreateUser($params); and then trying to see it using the function $client->__getLastRequest(); but it never makes it to the __getLastRequest because it hits a fatal error when calling CreateUser($params).
The question again:
Is there any way to view the XML created by the CreateUser($params) call WITHOUT actually sending it and causing a fatal error
Upfront remark: In order to use the __getLastRequest() method successfully, you have to set the 'trace' option to true on client construction:
$client = new SoapClient('wsdldoc.asmx?WSDL', array('trace' => TRUE));
This way, your request will still be sent (and therefore still fail), but you can inspect the sent xml afterwards by calling $client->__getLastRequest().
Main answer:
To get access to the generated XML before/without sending the request, you'd need to subclass the SoapClient in order to override the __doRequest() method:
class SoapClientDebug extends SoapClient
{
public function __doRequest($request, $location, $action, $version, $one_way = 0) {
// Add code to inspect/dissect/debug/adjust the XML given in $request here
// Uncomment the following line, if you actually want to do the request
// return parent::__doRequest($request, $location, $action, $version, $one_way);
}
}
You'd then use this extended class instead of the original SoapClient while debugging your problem.
I found this thread while working on the same problem, and was bummed because I was using classes that already extended the SoapClient() class and didn't want to screw around with it too much.
However if you add the "exceptions"=>0 tag when you initiate the class, it won't throw a Fatal Error (though it will print an exception):
SoapClient($soapURL, array("trace" => 1, "exceptions" => 0));
Doing that allowed me to run __getLastRequest() and analyze the XML I was sending.
I don't believe there is a way that you'll be able to see any XML that's being created... mainly because the function is failing on it's attempt to create/pass it.
Not sure if you tried already, but if you're having trouble trying to decide what exactly you need to pass into the function you could use:
$client->__getTypes();
http://us3.php.net/manual/en/soapclient.gettypes.php
Hope this helps!