Inspect Xml Created by PHP Soapclient Call Before/Without Sending the Request

Inspect XML created by PHP SoapClient call before/without sending the request

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.

Can I preview the XML that PHP SOAP wants to send before sending it?

You could use a derived class and overwrite the __doRequest() method of the SoapClient class.

<?php
//$clientClass = 'SoapClient';
$clientClass = 'DebugSoapClient';
$client = new $clientClass('http://www.webservicex.com/CurrencyConvertor.asmx?wsdl');
$client->sendRequest = false;
$client->printRequest = true;
$client->formatXML = true;

$res = $client->ConversionRate( array('FromCurrency'=>'USD', 'ToCurrency'=>'EUR') );
var_dump($res);

class DebugSoapClient extends SoapClient {
public $sendRequest = true;
public $printRequest = false;
public $formatXML = false;

public function __doRequest($request, $location, $action, $version, $one_way=0) {
if ( $this->printRequest ) {
if ( !$this->formatXML ) {
$out = $request;
}
else {
$doc = new DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->loadxml($request);
$doc->formatOutput = true;
$out = $doc->savexml();
}
echo $out;
}

if ( $this->sendRequest ) {
return parent::__doRequest($request, $location, $action, $version, $one_way);
}
else {
return '';
}
}
}

prints

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.webserviceX.NET/">
<SOAP-ENV:Body>
<ns1:ConversionRate>
<ns1:FromCurrency>USD</ns1:FromCurrency>
<ns1:ToCurrency>EUR</ns1:ToCurrency>
</ns1:ConversionRate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
NULL

But you'd have to change the actual code a bit for this to work which I try to avoid when possible (i.e. let tools do the work).

Get SOAP XML before __soapCall?

It is very, very hard (nigh impossible) to do that. What is much easier is using the SoapClient class' built-in debugging functionality to output the request after it has been sent. You can do that like so:

First, when creating your SOAPClient, enable tracing, like so:

$client = new SoapClient($wsdl, array('trace' => true));

Then do whatever processing is necessary to get ready to make the SOAP call and make it. Once it has been made, the following will give you the request you have just sent:

echo("<pre>"); //to format it legibly on your screen
var_dump($client->__getLastRequestHeaders()); //the headers of your last request
var_dump($client->__getLastRequest()); //your last request

And, if you want to see the response as well, the following should work:

var_dump($client->__getLastResponseHeaders()); //response headers
var_dump($client->__getLastResponse()); //the response

How do I see the actual XML generated by PHP SOAP Client Class?

Use getLastRequest. It returns the XML sent in the last SOAP request.

echo "REQUEST:\n" . $SOAP->__getLastRequest() . "\n";

And remember, this method works only if the SoapClient object was created with the trace option set to TRUE. Therefore, when creating the object, use this code:

$SOAP = new SoapClient($WDSL, array('trace' => 1));

Does PHP Validate Requests Against a WSDL Prior to Sending the Request?

Try debugging your script to see if it's actually making the request, PHP's SoapClient object makes it quite easy. Take a look at SoapClient::_getLastRequest and SoapClient::_getLastResponse.

If you want something a little lower, ngrep is a nice simple tool for keeping an eye on what's going across the wire.

Take this simple PHP script...

<?php
$client = new SoapClient('http://www.27seconds.com/kb/ws/Articles.asmx?WSDL');
$article = $client->GetArticle(array('articleId' => 7));

Executing ngrep port 80 & and then executing the above script will dump the traffic, and it should look similar to this...

##
T 208.106.153.223:80 -> 10.0.2.15:40760 [AS]
..
##
T 10.0.2.15:40760 -> 208.106.153.223:80 [AP]
POST /kb/ws/Articles.asmx HTTP/1.1..Host: www.27seconds.com..Connection: Keep-Alive..User-Agent: PHP-SOAP/5.3.10-1ubuntu3.6..Content-Type: text/xml; charset=utf-8..
SOAPAction: "http://dsetzer.27seconds.com/ws/GetArticle"..Content-Length: 279....<?xml version="1.0" encoding="UTF-8"?>.<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://sc
hemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://dsetzer.27seconds.com/ws/"><SOAP-ENV:Body><ns1:GetArticle><ns1:articleId>7</ns1:articleId></ns1:GetArticle></SOA
P-ENV:Body></SOAP-ENV:Envelope>.
#
T 208.106.153.223:80 -> 10.0.2.15:40760 [A]
......
#
T 208.106.153.223:80 -> 10.0.2.15:40760 [A]
HTTP/1.1 200 OK..Date: Fri, 21 Jun 2013 21:11:21 GMT..Server: Microsoft-IIS/6.0..X-Powered-By: ASP.NET..X-AspNet-Version: 2.0.50727..Cache-Control: private, max-age
=0..Content-Type: text/xml; charset=utf-8..Content-Length: 4804....<?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:Body><GetArticleResponse xmlns="http://dsetzer.2
7seconds.com/ws/"><GetArticleResult><xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msda
ta"><xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true"><xs:complexType><xs:choice minOccurs="0" maxOccurs="unbounded"><xs:element
name="Articles"><xs:complexType><xs:sequence><xs:element name="ArticleID" type="xs:int" minOccurs="0" /><xs:element name="ArticleTitle" type="xs:string" minOccurs="
0" /><xs:element name="ArticleSummary" type="xs:string" minOccurs="0" /><xs:element name="ArticleAuthorID" type="xs:int" minOccurs="0" /><xs:element name="ArticlePu
blishDate" type="xs:dateTime" minOccurs="0" /><xs:element name="AuthorName" type="xs:string" minOccurs="0" /><xs:element name="AuthorEmail" type="xs:string" minOccu
rs="0" /><xs:element name="AuthorHomepage" type="xs:string" minOccurs="0" /><xs:element name="ArticleBody" t
##
T 208.106.153.223:80 -> 10.0.2.15:40760 [AP]
ype="xs:string" minOccurs="0
##
T 208.106.153.223:80 -> 10.0.2.15:40760 [A]
" /><xs:element name="ArticleRating" type="xs:double" minOccurs="0" /></xs:sequence></xs:complexType></xs:element><xs:element name="Authors"><xs:complexType><xs:seq
uence><xs:element name="AuthorID" type="xs:int" minOccurs="0" /><xs:element name="AuthorName" type="xs:string" minOccurs="0" /><xs:element name="AuthorEmail" type="
xs:string" minOccurs="0" /></xs:sequence></xs:complexType></xs:element><xs:element name="Applicables"><xs:complexType><xs:sequence><xs:element name="appID" type="xs
:int" minOccurs="0" /><xs:element name="appDescr" type="xs:string" minOccurs="0" /></xs:sequence></xs:complexType></xs:element><xs:element name="Keywords"><xs:compl
exType><xs:sequence><xs:element name="KeyID" type="xs:int" minOccurs="0" /><xs:element name="KeyArticleId" type="xs:int" minOccurs="0" /><xs:element name="Keyword"
type="xs:string" minOccurs="0" /></xs:sequence></xs:complexType></xs:element></xs:choice></xs:complexType></xs:element></xs:schema><diffgr:diffgram xmlns:msdata="ur
n:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"><NewDataSet xmlns=""><Articles diffgr:id="Articles1" msdata:rowOrder="0
"><ArticleID>7</ArticleID><ArticleTitle>Handle double quotes in a form.</ArticleTitle><ArticleSummary>When pulling data from a form or database you can into trouble
if the data contains a double quote (&quot;).</ArticleSummary><ArticleAuthorID>1</ArticleAuthorID><Arti
##
T 208.106.153.223:80 -> 10.0.2.15:40760 [AP]
clePublishDate>2002-03-05T11
##
T 208.106.153.223:80 -> 10.0.2.15:40760 [A]
:40:54-05:00</ArticlePublishDate><AuthorName>Douglas L. Setzer, II</AuthorName><AuthorEmail>dsetzer@27seconds.com</AuthorEmail><AuthorHomepage>http://www.27seconds.
com</AuthorHomepage><ArticleBody><p>..When I was dynamically populating form values, I found that if the data has a double quote (&qout;) in it, it would
cut off the data entered in the form...</p>....<p>..To solve this, I found that I could simple Server.HtmlEncode the value and all was well. Except whe
n I was populating from a database and the data was NULL which caused an error for Server.HtmlEncode. So, I whipped up this little function:..</p>....<p&g
t;..<div style="width=450;height=300;overflow=scroll;">..<pre>..Function formEncode(formValue)..Dim m_sOut.. m_sOut = formValue.....If IsNull(m_sOut)
Then....m_sOut = ""...Else....m_sOut = Server.HTMLEncode(m_sOut)...End If.....formEncode = m_sOut....End Function..</pre>..</div>..</p>....<p&
gt;This is used when you assign a value to the form field:</p>....<p>..<div style="width=450;height=300;overflow=scroll;">..<pre>..&lt;i
nput type="text" name="example" value="&lt;%=formEncode("The ""test"" is good.") %&gt;"&gt;..</pre>..</div>..</p></ArticleBody></Artic
les><Authors diffgr:id="Authors1" msdata:rowOrder="0"><AuthorID>1</AuthorID><AuthorName>Douglas L. Setzer, I
##
T 208.106.153.223:80 -> 10.0.2.15:40760 [AP]
I</AuthorName><AuthorEmail>d
#
T 208.106.153.223:80 -> 10.0.2.15:40760 [AP]
setzer@27seconds.com</AuthorEmail></Authors><Applicables diffgr:id="Applicables1" msdata:rowOrder="0"><appID>1</appID><appDescr>Active Server Pages (ASP)</appDescr>
</Applicables><Keywords diffgr:id="Keywords1" msdata:rowOrder="0"><KeyID>386</KeyID><KeyArticleId>7</KeyArticleId><Keyword>CHR(34)</Keyword></Keywords><Keywords dif
fgr:id="Keywords2" msdata:rowOrder="1"><KeyID>388</KeyID><KeyArticleId>7</KeyArticleId><Keyword>DOUBLE QUOTE</Keyword></Keywords><Keywords diffgr:id="Keywords3" msd
ata:rowOrder="2"><KeyID>387</KeyID><KeyArticleId>7</KeyArticleId><Keyword>QUOTE</Keyword></Keywords></NewDataSet></diffgr:diffgram></GetArticleResult></GetArticleRe
sponse></soap:Body></soap:Envelope>
#root@precise64:~# ##
T 208.106.153.223:80 -> 10.0.2.15:40760 [A]
......
#
T 208.106.153.223:80 -> 10.0.2.15:40760 [AF]
......

Notice the SOAP calls? There are plenty of other ways to do this, but debugging should be your first port of call. :)

Good luck,

Anthony.

SoapClient call returns 500 Internal Server Error

Sometimes a 500 status coming from a SOAP service could be a SoapFault exception being thrown. To help your troubleshooting, you'll want to be able to inspect both your request XML, and the response XML.

Put your code in try/catch blocks, and use $client->__getLastRequest() and $client->__getLastResponse() to inspect the actual XML.

Example:

$client = new SoapClient('http//xxx.xxx.xxx?wsdl', array('soap_version'=>SOAP_1_1,'trace' => 1,'exceptions' => true));
try {
$response = $client->someFunction();
var_dump($response);
} catch (Exception $e) {
var_dump($e->getMessage());
var_dump($client->__getLastRequest());
var_dump($client->__getLastResponse());
}


Related Topics



Leave a reply



Submit