PHP SoapServer formatting - php

I am new to SOAP and trying to format a SOAP response using PHP's SoapServer class.
It might be useful to know that this is for an EWS Push Subscription callback service and that I am using the php-ews library. I have managed to subscribe to the EWS Push Subscription but am having trouble formatting the reply which EWS is expecting from my callback service.
I need the following SOAP response returned by my PHP SOAP service:
<s:Envelope xmlns:s= "http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<SendNotificationResult xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
<SubscriptionStatus>OK</SubscriptionStatus>
</SendNotificationResult>
</s:Body>
</s:Envelope>
Instead I am getting the following output:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://localhost/ioc/ebooking_v4/services/ews/notification.php" 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:SendNotificationResponse>
<return xsi:type="SOAP-ENC:Struct">
<SubscriptionStatus xsi:type="xsd:string">OK</SubscriptionStatus>
</return>
</ns1:SendNotificationResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
My PHP service code:
class ewsService {
public function SendNotification( $arg ) {
$result = new EWSType_SendNotificationResultType();
$result->SubscriptionStatus = 'OK';
return $result;
}
}
$server = new soapServer( null, array(
'uri' => $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'],
));
$server->setObject( new ewsService() );
$server->handle();
The SOAP call to my service is as follows:
<soap11:Envelope xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<soap11:Header>
<t:RequestServerVersion xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" Version="Exchange2010_SP2" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" />
</soap11:Header>
<soap11:Body>
<m:SendNotification xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages">
<m:ResponseMessages>
<m:SendNotificationResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:Notification>
<t:SubscriptionId>GQBjaGNpb2ExODEuY2lvLm9seW1waWMub3JnEAAAAFgvEpJcS3JDkpvHOMgnX60FhmhpPInRCA==</t:SubscriptionId>
<t:PreviousWatermark>AQAAAIiCiXu/q1ZPvYPyvRVVh5cajSoKAAAAAAA=</t:PreviousWatermark>
<t:MoreEvents>false</t:MoreEvents>
<t:StatusEvent>
<t:Watermark>AQAAAIiCiXu/q1ZPvYPyvRVVh5cajSoKAAAAAAA=</t:Watermark>
</t:StatusEvent>
</m:Notification>
</m:SendNotificationResponseMessage>
</m:ResponseMessages>
</m:SendNotification>
</soap11:Body>
</soap11:Envelope>
So I suppose my question is how do I to change the formatting of the SOAP response, using the PHP SoapServer class? Do I need to add a WSDL or pass a classmap to the SoapServer constructor?
If there is no way to do this using the SoapServer class, is there any other way to do this other than creating a string buffer and passing that back manually?
Any help would be greatly appreciated.

I figured this out and posted the solution on a more generic question of this problem here
For completeness I have included the answer here as well...
It would seem that I was close but needed to include the NotificationService.wsdl when instantiating the SoapServer class. The WSDL then allows that SoapServer class to format the response accordingly.
$server = new SoapServer( PHPEWS_PATH.'/wsdl/NotificationService.wsdl', array(
The WSDL was not included in the php-ews library download, however it is included with the Exchange Server installation. If like me you don't have access to the Exchange Server installation you can find the file here. I also had to add the following to the end of the WSDL because I was storing the WSDLs locally and not using autodiscovery:
<wsdl:service name="NotificationServices">
<wsdl:port name="NotificationServicePort" binding="tns:NotificationServiceBinding">
<soap:address location="" />
</wsdl:port>
</wsdl:service>
So the full working PHP code is as follows:
class ewsService {
public function SendNotification( $arg ) {
$result = new EWSType_SendNotificationResultType();
$result->SubscriptionStatus = 'OK';
//$result->SubscriptionStatus = 'Unsubscribe';
return $result;
}
}
$server = new SoapServer( PHPEWS_PATH.'/wsdl/NotificationService.wsdl', array(
'uri' => $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'],
));
$server->setObject( $service = new ewsService() );
$server->handle();
Which gives the following output:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.microsoft.com/exchange/services/2006/messages">
<SOAP-ENV:Body>
<ns1:SendNotificationResult>
<ns1:SubscriptionStatus>OK</ns1:SubscriptionStatus>
</ns1:SendNotificationResult>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Hope that helps someone else because that took me a while to figure out!

Related

PHP SoapServer return empty response on function without return

i have a soap with a method that return nothing
class mySoapService {
foo(){
}
}
$wsdl = ...;
$soapService = new mySoapService();
$soapServer = new \SoapServer($wsdl);
$soapServer->setObject($soapService);
$soapServer->handle(); // write nothing on call foo
some soap client raise an exception because they expect a proper xml-soap empty response, like this:
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 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:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
the questions are:
why PHP SoapServer return an empty response and not a xml-soap empty response?
what say the soap standard for method without return a value?
Changing
$soapServer->handle();
to
$soapServer->handle(file_get_contents("php://input"));
worked for me

EWS Push Subscription using PHP

Does anyone know how to respond to EWS (Exchange Web Services) Push Notifications using PHP.
I have initiated the EWS Push Subscription but cannot seem to send the correct SOAP response (in order to keep the subscription alive) when EWS sends my service a SOAP notification.
Taken from this page, I was under the impression that my SOAP response should be as follows:
<s:Envelope xmlns:s= "http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<SendNotificationResult xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
<SubscriptionStatus>OK</SubscriptionStatus>
</SendNotificationResult>
</s:Body>
</s:Envelope>
However, EWS doesn't seem to be accepting my response as valid.
I have tried the following 2 code snippets with no luck:
Respond using a SOAP string with Content-Type header
header( 'Content-Type: text/xml; charset=utf-8' );
echo '<?xml version="1.0" encoding="utf-8"?>'.
'<s:Envelope xmlns:s= "http://schemas.xmlsoap.org/soap/envelope/">'.
'<s:Body>'.
'<SendNotificationResult xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">'.
'<SubscriptionStatus>OK</SubscriptionStatus>'.
'</SendNotificationResult>'.
'</s:Body>'.
'</s:Envelope>';
OR Respond using a SOAP service
class ewsService {
public function SendNotification( $arg ) {
$result = new EWSType_SendNotificationResultType();
$result->SubscriptionStatus = 'OK';
return $result;
}
}
$server = new SoapServer( null, array(
'uri' => $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'],
));
$server->setObject( new ewsService() );
$server->handle();
It might help to know that the classes I am using in my code come from the PHP-EWS library.
Any help would be greatly appreciated.
I also posted a more specific question here, but have had no responses so thought I would ask whether someone has actually gotten this working using any method.
It would seem that I was close but needed to include the NotificationService.wsdl when instantiating the SoapServer class. The WSDL then allows that SoapServer class to format the response accordingly.
$server = new SoapServer( PHPEWS_PATH.'/wsdl/NotificationService.wsdl', array(
The WSDL was not included in the php-ews library download, however it is included with the Exchange Server installation. If like me you don't have access to the Exchange Server installation you can find the file here. I also had to add the following to the end of the WSDL because I was storing the WSDLs locally and not using autodiscovery:
<wsdl:service name="NotificationServices">
<wsdl:port name="NotificationServicePort" binding="tns:NotificationServiceBinding">
<soap:address location="" />
</wsdl:port>
</wsdl:service>
So the full working PHP code is as follows:
class ewsService {
public function SendNotification( $arg ) {
$result = new EWSType_SendNotificationResultType();
$result->SubscriptionStatus = 'OK';
//$result->SubscriptionStatus = 'Unsubscribe';
return $result;
}
}
$server = new SoapServer( PHPEWS_PATH.'/wsdl/NotificationService.wsdl', array(
'uri' => $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'],
));
$server->setObject( $service = new ewsService() );
$server->handle();
Which gives the following output:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.microsoft.com/exchange/services/2006/messages">
<SOAP-ENV:Body>
<ns1:SendNotificationResult>
<ns1:SubscriptionStatus>OK</ns1:SubscriptionStatus>
</ns1:SendNotificationResult>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Hope that helps someone else because that took me a while to figure out!

PHP Akamai SOAP Exception

I am making a SOAP request and it successfully return the function list which you can call.
I am calling PurgeRequest method and receiving following error
Exception: class com.idoox.soap.DemarshallException: Type in schema
differs from type in SOAP message - expected
string#http://www.w3.org/1999/XMLSchema; got
Map#http://xml.apache.org/xml-soap"
I tried with SOAP UI and get the successful response id. But, my PHP request is failing..Can some one tell me what this error is about and how to resolve this. one reference say it is because of passing the empty array but I am sure that parameter is not empty.
if(class_exists('SoapClient'))
{
$client = new SoapClient('https://ccuapi.akamai.com/ccuapi.wsdl',
array(
'trace' => 1,
'exceptions' => 0,
'features' => SOAP_USE_XSI_ARRAY_TYPE
)
);
echo '<pre>';
var_dump($client->__getFunctions());
try {
$purgeResult = $client->purgeRequest($username,$password,'',$opt,$url);
}
catch(SoapFault $e){
echo "Exception\n";
}
echo '<pre>';
var_dump($purgeResult);
}
It works for me, but I'm not logging in (of course). I get normal SOAP exceptions:
Exception: class com.idoox.soap.DemarshallException: Dimensions not found in array type
when I pass an empty string in $opt, or
object(stdClass)#2 (6) {
["resultCode"]=>
int(301)
["resultMsg"]=>
string(29) "Invalid username or password."
["sessionID"]=>
string(16) "17F1327329982356"
["estTime"]=>
int(-1)
["uriIndex"]=>
int(-1)
["modifiers"]=>
NULL
}
when I pass empty arrays in $opt and $url.
Anyway, your issue seems to be due to different SOAP xsd headers. The service expects http://www.w3.org/1999/XMLSchema header, your script seems to be passing http://xml.apache.org/xml-soap.
Service WSDL defines it:
<?xml version="1.0" standalone="no"?>
<definitions name="PurgeRequest"
targetNamespace="http://www.akamai.com/purge"
xmlns:tns="http://www.akamai.com/purge"
xmlns:purgedt="http://www.akamai.com/purge"
xmlns:xsd="http://www.w3.org/2000/10/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
You need to make sure your client respects this and sets it properly.
Please post output of your
var_dump($client->__getLastRequest());
(right after
var_dump($purgeResult);
)
mine looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://www.akamai.com/purge"
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:purgeRequest>
<name xsi:type="xsd:string">ee</name>
<pwd xsi:type="xsd:string">rr</pwd>
<network xsi:type="xsd:string"/>
<opt SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array">
<item xsi:type="xsd:string"/>
</opt>
<uri SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array">
<item xsi:type="xsd:string"/>
</uri>
</ns1:purgeRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
see, this request features xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Also make sure you are using right SOAP version
'soap_version' => SOAP_1_1
and your __doRequest() method in SOAP extension is not overriden to send custom headers, like here.

simple php SoapClient example for paypal needed

Could I get a simple example of using PHP's SoapClient class to make an empty call to Paypal with nothing but the version number? I have the correct WSDL url and server url, so that's not what I need help with. This is what I have:
public function SOAPcall($function, $args=array()) {
$args['Version'] = '63.0';
$args = new SoapVar($args, SOAP_ENC_ARRAY, $function.'_Request');
$args = array(new SoapVar($args, SOAP_ENC_ARRAY, $function.'_Req', 'urn:ebay:api:PayPalAPI'));
$results = $this->soapClient->__soapCall($function, $args, array('location' => $this->activeKeys['certificate']), $this->soapOptions);
}
I hope it's okay I am not showing everything. The body of the request comes out completely wrong, as you can see below:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="urn:ebay:api:PayPalAPI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="urn:ebay:apis:eBLBaseComponents">
<SOAP-ENV:Header>
<ns1:RequesterCredentials>
<ns2:Credentials>
<ns2:Username>xxx</ns2:Username>
<ns2:Password>xxx</ns2:Password>
<ns2:Signature>xxx</ns2:Signature>
</ns2:Credentials>
</ns1:RequesterCredentials>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:GetBalanceReq xsi:type="ns1:GetBalance_Req">
<xsd:string>63.0</xsd:string>
</ns1:GetBalanceReq>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
It should look like this:
<?xml version=”1.0” encoding=”UTF-8”?>
<SOAP-ENV:Envelope xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/”
xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”
><SOAP-ENV:Header>
<RequesterCredentials xmlns=”urn:ebay:api:PayPalAPI”>
<Credentials xmlns=”urn:ebay:apis:eBLBaseComponents”>
<Username>api_username</Username>
<Password>api_password</Password>
<Signature/>
<Subject/>
</Credentials>
</RequesterCredentials>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<specific_api_name_Req xmlns=”urn:ebay:api:PayPalAPI”>
<specific_api_name_Request>
<Version xmlns=urn:ebay:apis:eBLBaseComponents”>service_version
</Version>
<required_or_optional_fields xsi:type=”some_type_here”> data
</required_or_optional_fields>
</specific_api_name_Request>
</specific_api_name_Req>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Of course, Paypal throws a "Version is not supported" error.
This is the cleanest solution I could come up with:
$client = new SoapClient( 'https://www.sandbox.paypal.com/wsdl/PayPalSvc.wsdl',
array( 'soap_version' => SOAP_1_1 ));
$cred = array( 'Username' => $username,
'Password' => $password,
'Signature' => $signature );
$Credentials = new stdClass();
$Credentials->Credentials = new SoapVar( $cred, SOAP_ENC_OBJECT, 'Credentials' );
$headers = new SoapVar( $Credentials,
SOAP_ENC_OBJECT,
'CustomSecurityHeaderType',
'urn:ebay:apis:eBLBaseComponents' );
$client->__setSoapHeaders( new SoapHeader( 'urn:ebay:api:PayPalAPI',
'RequesterCredentials',
$headers ));
$args = array( 'Version' => '71.0',
'ReturnAllCurrencies' => '1' );
$GetBalanceRequest = new stdClass();
$GetBalanceRequest->GetBalanceRequest = new SoapVar( $args,
SOAP_ENC_OBJECT,
'GetBalanceRequestType',
'urn:ebay:api:PayPalAPI' );
$params = new SoapVar( $GetBalanceRequest, SOAP_ENC_OBJECT, 'GetBalanceRequest' );
$result = $client->GetBalance( $params );
echo 'Balance is: ', $result->Balance->_, $result->Balance->currencyID;
This produces the following XML request document, which, at the time of writing, was being successfully accepted and processed by PayPal:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="urn:ebay:apis:eBLBaseComponents" xmlns:ns2="urn:ebay:api:PayPalAPI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<ns2:RequesterCredentials>
<ns1:Credentials xsi:type="Credentials">
<Username>***</Username>
<Password>***</Password>
<Signature>***</Signature>
</ns1:Credentials>
</ns2:RequesterCredentials>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns2:GetBalanceReq xsi:type="GetBalanceRequest">
<GetBalanceRequest xsi:type="ns2:GetBalanceRequestType">
<ns1:Version>71.0</ns1:Version>
<ns2:ReturnAllCurrencies>1</ns2:ReturnAllCurrencies>
</GetBalanceRequest>
</ns2:GetBalanceReq>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In response to some of the other comments on this page:
I'm fairly certain the OP has read the API doc, because that's where the example XML came from that he is trying to reproduce using PHP SOAP library.
The PayPal PHP API has some shortcomings, the biggest one being that it fails to work with E_STRICT warnings turned on. It also requires PEAR, so if you are not currently using PEAR in your project it means dragging in quite a lot of new code, which means more complexity and potentially more risk, in order to achieve what should be two or three fairly simple XML exchanges for a basic implementation.
The NVP API looks pretty good too, but I'm a glutten for punishment, so I chose the hard path. :-)
Did you check out the API's provided by PayPal here? And a direct link to the PHP SOAP API download.
And here is a link to the NVP API which PayPal recommends you use.
PHP has a very easy to use soapClass.
Which can be found here.
http://www.php.net/manual/en/class.soapclient.php

What is method signature in SOAP header?

I want to imitate the following SOAP request using Zend Framework but I don't understand the '__MethodSignature' part in header. Could someone please explain this?
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header>
<h3:__MethodSignature xsi:type="SOAP-ENC:methodSignature"
xmlns:h3="http://schemas.microsoft.com/clr/soap/messageProperties"
SOAP-ENC:root="1">
xsd:string
</h3:__MethodSignature>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<i4:ReturnDataset id="ref-1"
xmlns:i4="http://schemas.microsoft.com/clr/nsassem/Interface.IReturnDataSet/Interface">
<tName id="ref-5">BU</tName>
</i4:ReturnDataset>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
When I call this ReturnDataSet function like this:
$client = new Zend_Soap_Client($wsdl_url, array('soap_version' => SOAP_1_1));
$tName = "BU";
$result = $client->ReturnDataset($tName);
Server throws an error. I think this header part is playing some role?
Try setting the MethodSignature or __MethodSignature SOAP header. With the normal PHP SOAP client, you do this as follows:
$client->__setSoapHeaders(new SoapHeader(
'http://schemas.microsoft.com/clr/soap/messageProperties',
'__MethodSignature',
'xsd:string'
));

Categories