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!
Related
$data2=[
"user_name"=>"****",
"password"=>"****",
"customer_num"=>"***",
"process_num"=>000,
];
$wsdl = "https://vbtestservice.vakifbank.com.tr/HesapHareketleri.OnlineEkstre/SOnlineEkstreServis.svc?singleWsdl";
$client =new SoapClient($wsdl,array("trace"=>true,"exceptions"=>0));
$a=$client->__soapCall('GetirDekont', $data2);
echo $client->__getLastResponse();
Result of php : looks like we got no xml document
or response
The requested URL was rejected. Please consult with your administrator."
But
As shown in the pictures the wdsl is working at he SoapUI but how to implement the options in the pure php or in the laravel framework. Thank you you for helping !!
SoapUI return response this xml:
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">
Peak.Integration.ExternalInbound.Ekstre/ISOnlineEkstreServis/GetirDekontResponse
</a:Action>
</s:Header>
<s:Body>
<GetirDekontResponse xmlns="Peak.Integration.ExternalInbound.Ekstre">
<GetirDekontResult
xmlns:b="http://schemas.datacontract.org/2004/07/Peak.Integration.ExternalInbound.Ekstre.DataTransferObjects"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<b:IslemKodu>VBD0004</b:IslemKodu>
<b:IslemAciklamasi>Talimat için dekont bulunamadı.</b:IslemAciklamasi>
<b:DekontListesi xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</GetirDekontResult>
</GetirDekontResponse>
</s:Body>
</s:Envelope> ```
I found the solution :)
Quote from Alper Yaman, a member of Laravel Turkey group on Facebook.
To set WSA Addressing and add default wsa:To options on SoapClient connection in Laravel, you can follow these steps:
You can specify "soap_version" and "features" in the options array when creating the SoapClient object. Example:
$options = array(
'soap_version' => SOAP_1_2,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
);
$client = new SoapClient($wsdl, $options);
You can set WSA Addressing and add default wsa:To options by editing the headers of the request sent to the SoapClient object. Example:
$headers = array(
new SoapHeader("http://www.w3.org/2005/08/addressing", "Peak.Integration.ExternalInbound.Ekstre/ISOnlineEkstreServis/GetirDekont", $to),
new SoapHeader("http://www.w3.org/2005/08/addressing", "WEB SERVICE LINK ENDING WITH ?WSDL HERE", $action)
);
$client->__setSoapHeaders($headers);
Note: The $to and $action variables are required values for WSA Addressing.
After doing these operations, try to connect to the web service with the SoapClient object.
If you still get the error, please contact the server's administrator to ensure that the URL is not rejected.
I'm trying to make a soap header that would look like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<a-user xmlns="a">testName</a-user>
<a-pass xmlns="a">testPassword</a-pass>
</s:Header>
<s:Body>
...
</s:Body>
</s:Envelope>
I'm pretty new to soap so I'm pretty sure I just don't understand what I'm supposed to put in for the parameters of the SoapHeader constructor, this is what I'm currently trying and it keeps failing to authenticate:
$authHeader = new SoapHeader("http://schemas.xmlsoap.org/soap/envelope/", "Envelope", array("Header" => array("a-user" => "testName", "a-pass" => "testPassword")));
Can someone explain how I'm supposed to translate that header from the xml into a php soapheader please?
Edit: Yes, agunn, I'm using a real user name and pass, I get a SoapFault exceptions saying "Vendor not authorized!" when I make my soapCall.
Here's the soap call part included:
$this->client->__setSoapHeaders($authHeader);
$response = $this->client->__soapCall("Foo", $params);
$authHeader = new SoapHeader("http://schemas.xmlsoap.org/soap/envelope/", "Envelope", array("Header" => array("a-user" => "testName", "a-pass" => "testPassword")));
By the SoapClient spec you should try like this
$this->client->__setSoapHeaders(array($authHeader));
$response = $this->client->__soapCall("Foo", $params);
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!
Hello i am very new to webservice, in php with below code i am trying to make soap request as shown in below XML, but it says Error
HTTP Error: Unsupported HTTP response status 405 Method Not Allowed (soapclient->response has contents of the response)
Questions:
How to pass headers?
How to pass FetchCalendarRequest with request like in XML?
I have used Nusoap here but if you have a SOAP PHP class solution it is also invited.
My code:
<?php
require_once('../lib/nusoap.php');
$client = new nusoap_client("http://webservices.test.com/ows/5.1/Availability.wsdl");
$err = $client->getError();
if ($err)
{
client_debug_error_message('Constructor error', $err, $client);
exit;
}
// Call the SOAP method
$result = $client->call(
'FetchCalendar',
array(
'StayDateRange' => array(
'StartDate' => '2013-10-01',
'EndDate' => '2013-10-10',
),
),
);
// Check for a fault
if ($client->fault)
{
debug_preformatted('Fault', $result);
}
else
{
// Check for errors
$err = $client->getError();
if ($err)
{
debug_preformatted('Error', $err);
}
else
{
debug_preformatted('Result', $result);
}
}
// Display the request and response
client_debug_dump($client);
XML :
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<OGHeader transactionID="005435" timeStamp="2008-12-09T13:26:56.4056250-05:00" xmlns="http://webservices.test.com/og/4.3/Core/">
<Origin entityID="OWS" systemType="WEB" />
<Destination entityID="WEST" systemType="ORS" />
</OGHeader>
</soap:Header>
<soap:Body>
<FetchCalendarRequest xmlns:a="http://webservices.test.com/og/4.3/Availability/" xmlns:hc="http://webservices.test.com/og/4.3/HotelCommon/" xmlns="http://webservices.test.com/ows/5.1/Availability.wsdl">
<HotelReference chainCode="AXA" hotelCode="AXAMUM" />
<StayDateRange>
<hc:StartDate>2013-10-01</hc:StartDate>
<hc:EndDate>2013-10-10</hc:EndDate>
</StayDateRange>
<GuestCount>
<hc:GuestCount ageQualifyingCode="ADULT" count="1" />
<hc:GuestCount ageQualifyingCode="CHILD" count="0" />
</GuestCount>
</FetchCalendarRequest>
</soap:Body>
</soap:Envelope>
Post Url :http://000.000.000.00:8080/ows_ws_51/Availability.asmx
Soap Action : http://webservices.test.com/ows/5.1/Availability.wsdl#FetchCalendar
Edit: Working Solution 16 Sep 2013
This solution is with Soap PHP Class only I want it to work with Nusoap bow.
<?php
$wsdl = "http://###.###.###.##:8080/ows_ws_51/Availability.asmx?wsdl";
$client = new SoapClient($wsdl, array( 'soap_version' => SOAP_1_1,'trace' => true,));
//=========== Header Setting ============
$ns = 'http://webservices.micros.com/og/4.3/Availability/'; //Namespace of the WS.//Body of the Soap Header.
$strHeaderComponent_Session = <<<XML
<OGHeader transactionID="005435" timeStamp="2008-12-09T13:26:56.4056250-05:00" xmlns="http://webservices.micros.com/og/4.3/Core/">
<Origin entityID="OWS" systemType="WEB" />
<Destination entityID="WEST" systemType="ORS" />
</OGHeader>
XML;
$objVar_Session_Inside = new SoapVar($strHeaderComponent_Session, XSD_ANYXML, null, null, null);
$objHeader_Session_Outside = new SoapHeader($ns , 'SessionHeader', $objVar_Session_Inside);
// More than one header can be provided in this array.
$client->__setSoapHeaders(array($objHeader_Session_Outside));
//============== Request ================
$xml = <<<XML
<FetchCalendarRequest xmlns:a="http://webservices.micros.com/og/4.3/Availability/" xmlns:hc="http://webservices.micros.com/og/4.3/HotelCommon/" xmlns="http://webservices.micros.com/ows/5.1/Availability.wsdl">
<HotelReference chainCode="AXA" hotelCode="{$DdlHotels}" />
<StayDateRange>
<hc:StartDate>{$Arrive}</hc:StartDate>
<hc:EndDate>{$Depart}</hc:EndDate>
</StayDateRange>
<GuestCount>
<hc:GuestCount ageQualifyingCode="ADULT" count="1" />
<hc:GuestCount ageQualifyingCode="CHILD" count="0" />
</GuestCount>
</FetchCalendarRequest>
XML;
$args = array(new SoapVar($xml, XSD_ANYXML));
try
{
$response = $client->__soapCall( 'FetchCalendar', $args );
}
catch (SoapFault $e)
{
echo "Error: {$e}"; exit;
}
You can use PHP's built in SOAP library to create a SOAP client and call a method from the WSDL, try something like this:
$client = new SoapClient($wsdl, array( 'soap_version' => SOAP_1_1,
'trace' => true,
));
try {
$params = array(
//Your parameters here
);
$res = $client->__soapCall( 'SoapMethod', $params );
return $res;
} catch (SoapFault $e) {
echo "Error: {$e}";
}
//for debugging what the outgoing xml looks like
$client->__getLastRequest();
The WSDL should help structure the xml for your params. If you cannot get that to work the way you want you could try passing the xml yourself using SoapVar() and setting the encode to XSD_ANYXML.
If you also need to add additional header information take a look at this example from the PHP docs.
$params = array(//your params as specified by documentation);
$result = $client->call(array("Availability"=>$params));
Might I suggest trying to learn SOAP with a different example web service. The wsdl document published for this service appears to be incomplete, as they have entered the incorrect SOAP address for the Availability service. With an incorrect or incomplete WSDL document, the SOAP library you are using will not be able to form a valid SOAP request and send it to the correct endpoint.
<wsdl:service name="AvailabilityService">
<wsdl:port name="AvailabilityPort" binding="tns:AvailabilityBinding">
<soap:address location="http://tempuri.org"/>
</wsdl:port>
</wsdl:service>
As you can see, the AvailabilityService endpoint is described as http://tempuri.org, which is explained as a default test namespace here.
In your original post, you have the 'POST URL' described as http://000.000.000.00:8080/ows_ws_51/Availability.asmx. How is anyone supposed to try the example, if you list the 'POST URL' an as obviously invalid URL.
You have also listed the WSDL document as http://webservices.test.com/ows/5.1/Availability.wsdl, which is also an invalid URL.
Here is a PHP example, accessing a valid WSDL document, using PHP's built-in SOAP library, which can be enabled by enabling the php_soap.dll extension in your php.ini file.
<?php
$wsdl = "http://www.restfulwebservices.net/wcf/StockQuoteService.svc?wsdl";
$client = new SoapClient($wsdl, array(
"trace" => 1,
"exceptions" => 0));
$parameters = array("request" => "IBM");
$value = $client->GetStockQuote($parameters);
$json = json_encode($value);
echo $json;
Note: The following is more of a comment than an answer. I leave it here for further reference as it would not fit into a comment box and it references existing Q&A possible worth for future visitors
You ask two questions regarding Nusoap here:
How to pass headers?
How to pass FetchCalendarRequest with request like in XML?
The first one How to pass headers? has been outlined already in this Q&A:
NuSoap PHP webservice with soap headers
As you have not written specifically in your question what of this (and possible other of the) existing Q&A didn't work for you, this might not suit your needs but you need to give detailed feedback first I'd say.
The second question How to pass FetchCalendarRequest with request like in XML? you probably mean how to call a SOAP action or method ("Request") that has been named in a WSDL. This has already been covered as well for Nusoap on the Stackoverflow website:
Nusoap use existing WSDL how to?
As you have not written specifically in your question what of this (and possible other of the) existing Q&A didn't work for you, this might not suit your needs but you need to give detailed feedback first I'd say to turn this into a concrete programming question.
BTW Stackoverflow works best by asking one question at a time.
I'm trying to communicate with the eWay server and had everything working until we ended up needing to switch to a different API. The problem is that SoapClient is creating a different namespace for the header (that includes the authentication) then from the body, which, obviously, doesn't get me any results. Instead, I get eWay's servers saying it must have the authentication information.
Here's my code:
$client = new SoapClient($url.'?WSDL', array('trace'=>TRUE));
// Set our SOAP Headers for authentication
$header_body = array(
'eWAYCustomerID' => $gateway['customer_id'],
'Username' => $gateway['username'],
'Password' => $gateway['password']
);
$header_var = new SoapVar($header_body, SOAP_ENC_OBJECT);
$header = new SOAPHeader('http://www.eway.com.au/gateway/managedpayment', 'eWAYHeader', $header_body);
//$client->__setSoapHeaders($header);
try {
$response = $client->__soapCall($action, $xml, null, $header);
} catch (SoapFault $e)
{
echo 'SOAP Fault: '. $e->getMessage()."<br>\n";
}
As you can see, I've tried it with and without using a SoapVar for the header, all with no luck.
Here's the XML request that is being created:
<soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="https://www.eway.com.au/gateway/managedpayment" xmlns:ns2="http://www.eway.com.au/gateway/managedpayment">
<soap-env:header>
<ns2:ewayheader>
<ewaycustomerid>87654321</ewaycustomerid>
<username>test#eway.com.au</username>
<password>test123</password>
</ns2:ewayheader>
</soap-env:header>
<soap-env:body>
<ns1:createcustomer>...</ns1:createcustomer>
This may be an obvious question, but did you try specifying the typename and type namespace in the SoapVar() call?