Given that the following client.php creates this request XML:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://soap.dev/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:Test>
<RequestId xsi:type="xsd:int">1</RequestId>
<PartnerId xsi:type="xsd:int">99</PartnerId>
</ns1:Test>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
How do I access the names of the parameters? (RequestId and PartnerId) inside a server.php? The names are clearly there in the payload, but on server side only the values are received (1 and 99)
Sample code follows:
client.php
<?php
$client_params = array(
'location' => 'http://soap.dev/server.php',
'uri' => 'http://soap.dev/',
'trace' => 1
);
$client = new SoapClient(null, $client_params);
try {
$res = $client->Test(
new SoapParam(1, 'RequestId'),
new SoapParam(99, 'PartnerId')
);
} catch (Exception $Ex) {
print $Ex->getMessage();
}
var_dump($client->__getLastRequest());
var_dump($client->__getLastResponse());
server.php
class receiver {
public function __call ($name, $params)
{
$args = func_get_args();
// here $params equals to array(1, 99)
// I want the names as well.
return var_export($args, 1);
}
}
$server_options = array('uri' => 'http://soap.dev/');
$server = new SoapServer(null, $server_options);
$server->setClass('receiver');
$server->handle();
Please note that I can not really change the incoming request format.
Also, I am aware that I could give the names back to parameters by creating a Test function with $RequestId and $PartnerId parameters.
But what I really want to is to get name/value pairs out of incoming request.
So far the only idea I have is to simply parse the XML and this cannot be right.
Back when I had this problem I finally decided to go with the proxy function idea - Test function with parameters named ($RequestId and $PartnerId) to give names back to parameters. Its adequate solution, but certainly not the best.
I have not yet lost the hope for finding a better solution though, and here is my best idea so far
<?php
class Receiver {
private $data;
public function Test ()
{
return var_export($this->data, 1);
}
public function int ($xml)
{
// receives the following string
// <PartnerId xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:int">99</PartnerId>
$element = simplexml_load_string($xml);
$this->data[$element->getName()] = (string)$element;
}
}
$Receiver = new Receiver();
$int = array(
'type_name' => 'int'
, 'type_ns' => 'http://www.w3.org/2001/XMLSchema'
, 'from_xml' => array($Receiver, 'int')
);
$server_options = array('uri' => 'http://www.w3.org/2001/XMLSchema', 'typemap' => array($int), 'actor' => 'http://www.w3.org/2001/XMLSchema');
$server = new SoapServer(null, $server_options);
$server->setObject($Receiver);
$server->handle();
It still means parsing XML manually, but one element at a time which is a bit more sane that parsing entire incoming SOAP message.
Related
Webservice : http://webservices.dishtv.in/Services/Mobile/Trade/TradeSubscriberInfo.asmx
Overloaded method is GetSubscriberInfoV2 MessageName="GetSubscriberInfoVCLogV2"
My php code is,
<?php
$mobileno="01523833622";
$url="http://webservices.dishtv.in/Services/Mobile/Trade/TradeSubscriberInfo.asmx?wsdl";
$client = new SoapClient($url);
$soapHeader = array('UserID' => '47','Password' => 'zZa##286##');
$header = new SOAPHeader('http://tempuri.org/', 'AuthenticationHeader', $soapHeader);
$client ->__setSoapHeaders($header);
try
{
$res = $client->GetSubscriberInfoVCLogV2(array('vcNo' => $mobileno, 'mobileNo' => '', 'BizOps' => '1', 'UserID' => '555300', 'UserType' => 'DL' ));
}
catch(SoapFault $e)
{
echo "Invalid No";
print_r($e);
}
print_r($res);
?>
It gives error GetSubscriberInfoVCLogV2 is not found. I need to get the response of GetSubscriberInfoVCLogV2. Can anyone help me to find the solution.
The only way to do this is writing the XML request manually and sending it through the method SoapClient::__doRequest.
It would be something like this:
$request = <<<'EOT'
<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://tempuri.org/">
<SOAP-ENV:Body>
<ns1:TheMessageNameGoesHere>
<ns1:param1>$param1</ns1:param1>
<ns1:param2>$param2</ns1:param2>
<ns1:param3>$param3</ns1:param3>
</ns1:TheMessageNameGoesHere>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
EOT;
$response = $soapClient->__doRequest(
$request,
"http://www.exemple.com/path/to/WebService.asmx",
"http://tempuri.org/TheMessageNameGoesHere",
SOAP_1_1
);
Change "TheMessageNameGoesHere" for the MessageName found in the WebService description page.
The XML structure can also be found in the WebService description page, when you click in the function.
The third parameter of the method __doRequest is the SOAP action, and can be found in the WSDL file as an attribute of the tag <soap:operation>
How can I create the following part as part of a soap request?
<RequestDetails xsi:type="PostcodeRequest">
<Postcode>SW1A 1AA</Postcode>
</RequestDetails>
I am creating the soap request using arrays
$aPostcode = array('Postcode'=>'SW1A 1AA')
$aPostcodeRequest = array('PostcodeRequest' => $aPostcode);
$GetLineCharacteristicsRequest = array('RequestDetails' => aPostcodeRequest);
I didn't find a way to achieve it using arrays, but I could do it with classes. The code:
try {
$options = [
'trace'=> 1,
'location' => 'http://localhost/pruebas/soap-server-nowsdl.php',
'uri' => 'http://localhost/pruebas'
];
class PostCodeRequest {
function __construct($pc)
{
$this->Postcode = $pc;
}
}
$client = new SOAPClient(null, $options);
$pc = new PostcodeRequest('SW1A 1AA');
$postCodeRequest = new SoapVar($pc, SOAP_ENC_OBJECT, 'PostCodeRequest', 'http://soapinterop.org/xsd');
$response = $client->hola(new SoapParam($postCodeRequest, 'RequestDetails'));
header('Content-type:text/xml');
echo $client->__getLastRequest();
}
catch (SoapFault $e) {
echo $e;
}
Will give this as request:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://localhost/pruebas" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="http://soapinterop.org/xsd" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:hola>
<RequestDetails xsi:type="ns2:PostCodeRequest">
<Postcode xsi:type="xsd:string">SW1A 1AA</Postcode>
</RequestDetails>
</ns1:hola>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Of course, this is assuming you have a "hola" function in your SOAP server. Replace it with whatever you're calling.
This solution is based in the example of the SoapVar constructor.
The SOAP server I call has two functions
GetUserInfo and
GetAllUserInfo
the client calls the second function perfectly and displays all users. But the first function returns a null. I know it has something to do with the parameters, so I have tried a number of possible ways, still nothing. Here is the xml of soap and the function I used.
1.GetUserInfo
Request Xml:
<GetUserInfo>
<ArgComKey xsi:type="xsd:integer”>ComKey</ArgComKey>
<Arg>
<PIN xsi:type="xsd:integer”>Job Number</PIN>
</Arg>
</GetUserInfo>
Response Xml:
<GetUserInfoResponse>
<Row>
<PIN>XXXXX</PIN>
<Name>XXXX</Name>
<Password>XXX</Password>
2.GetAllUserInfo *
Request Xml:
<GetAllUserInfo>
<ArgComKey xsi:type="xsd:integer”>ComKey</ArgComKey>
</GetAllUserInfo>
Response Xml:
<GetAllUserInfoResponse>
<Row>
<PIN>XXXXX</PIN>
<Name>XXXX</Name>
<Password>XXX</Password>
< Group>X</ Group>
And here is the code I wrote for the client I use to get a specific user and all users.
try {
$opts = array('location' => 'http://192.168.0.201/iWsService',
'uri' => 'iWsService');
$client = new \SOAPClient(null, $opts);
$attendance = $client->__soapCall('GetUserInfo', array('PIN'=> 2));
var_dump($attendance);
} catch (SOAPFault $exception) {
print $exception;
}
When I called GetAllUserInfo with a parameter of empty array() it returns all the users. Including a user with PIN = 2. But the GetUserInfo method returns null. Am I missing something when I called the GetUserInfo method?
In order to make the correct SOAP call for GetUserInfo, you will need to know 2 parameters: the ComKey and the PIN. In my SOAP call below, I assume that the ComKey is 12345, but you will have to replace this value with something meaningful. Try using the following code:
try {
$opts = array('location' => 'http://192.168.0.201/iWsService',
'uri' => 'iWsService');
$client = new \SOAPClient(null, $opts);
$attendance = $client->__soapCall('GetUserInfo', array('ArgComKey'=>12345,
'Arg' => array('PIN' => 2)));
var_dump($attendance);
} catch (SOAPFault $exception) {
print $exception;
}
Here I am trying to match the XML format for the GetUserInfo request as closely as possible.
I need to get data from http://ws.jrtwebservices.com/jrtlowfaresearch/jrtlfs.asmx, this service need credential information.such as ID, userid and system value. I put these information into one string:
$xml_post_string = "<POS><Source> <RequestorID Type='21' ID='xxx'/> </Source> <TPA_Extensions> <Provider><System>xxx</System> <Userid>xxx</Userid> </Provider></TPA_Extensions></POS>"
And i also defined SoapClient:
$client = new SoapClient(null, array('uri' => "http://ws.jrtwebservices.com",
'location => "http://ws.jrtwebservices.com/jrtlowfaresearch/jrtlfs.asmx") );
I call soapCall as:
$response = $client->__soapCall('do_LowfareSearch',array($xml_post_string),array('soapaction' => 'http://jrtechnologies.com/do_LowfareSearch'));
Does anybody know why i get empty response?
Thanks very much!
Using your code, the request looks like this:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xm...">
<SOAP-ENV:Body>
<ns1:do_LowfareSearch>
<param0 xsi:type="xsd:string">
"<POS><Source> <RequestorID Type='21' ID='xxx'/> </Source> <TPA_Extensions> <Provider <System>xxx</System> <Userid>xxx</Userid> </Provider></TPA_Extensions></POS>"
</param0>
</ns1:do_LowfareSearch>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The client used the method you passed but could not structure the parameters the way you gave them. All of your parameters are just in " " inside of <param0>.
(Also, you are missing a ' after location. 'location => "http:...)
When you make your SOAP client you want to set the WSDL, it will do all the XML formatting for you.
The WSDL should have the location in it so you do not need to worry about that.
I like to use a WSDL validator to test out the methods and see their parameters.
You should structure the information you want to pass as arrays or a classes and let the SOAP client and WSDL convert it into the XML you need.
So something like this is what you are looking for:
<?php
//SOAP Client
$wsdl = "http://ws.jrtwebservices.com/jrtlowfaresearch/jrtlfs.asmx?WSDL";
$client = new SoapClient($wsdl, array( 'soap_version' => SOAP_1_1,
'trace' => true, //to debug
));
try {
$args = array(
'companyname'=> 'xxx',
'name'=> 'xxx',
'system'=> 'xxx',
'userid'=> 'xxx',
'password'=> 'xxx',
'conversationid'=>'xxx',
'entry'=> 'xxx',
);
$result = $client->__soapCall('do_LowfareSearch', $args);
return $result;
} catch (SoapFault $e) {
echo "Error: {$e}";
}
//to debug the xml sent to the service
echo($client->__getLastRequest());
//to view the xml sent back
echo($client->__getLastResponse());
?>
I get this SoapFault I dont understand. Calling the function below, codewordStemExists(), should create a SoapClient which connects to a SoapServer that is up and running (no errors that I can found has been reported from the server side).
private static function initClient() {
ini_set("soap.wsdl_cache_enabled", "0");
$classmap = array(
'CodewordStemExists' => 'CodewordStemExists',
'CodewordStemExistsResponse' => 'CodewordStemExistsResponse',
);
$client = new \SoapClient("http://..../service.wsdl", array(
"trace" => true,
"exceptions" => true,
"classmap" => $classmap
));
return $client;
}
public static function codewordStemExists($stem) {
$client = self::initClient();
try {
$req = new CodewordStemExists();
$req->username = "....";
$req->password = "....";
$req->codewordStem = $stem;
$res = $client->codewordStemExists($req);
return (bool)$res->result;
}
catch (\SoapFault $e) {
var_dump($client->__getLastResponse());
}
/** The result from var_dump: */
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://....">
<SOAP-ENV:Body>
<ns1:CodewordStemExistsResponse><ns1:result>false</ns1:result>
</ns1:CodewordStemExistsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The SoapFault:
Class 'CodewordStemExistsResponse' not found
CodewordStemExistsResponse is required at bootstrapping, it is possible to instantiate it at any time.
Anyone seen this before? Thanks.
Check if this needs proper namespacing, e.g. \vendor\CodewordStemExistsResponse.