NOT Getting Started with PHP 5 SOAP
Not having played with PHP 5's native SOAP extension yet, I did expect it to work smoothly with the most simple application I could think of - querying Google via its SOAP Search API. Well...
I first compiled the latest PHP 5.1.6 with --enable-soap and downloaded the Google SOAP Search API developer's kit which contains their WSDL file, GoogleSearch.wsdl.
Running this example PHP code...
<?php $client = new SoapClient('GoogleSearch.wsdl'); try { $result = $client->doGoogleSearch( '[Secret Google key]', 'Tim Strehle', 0, 3 ); foreach ($result->resultElements as $resultElement) { print $resultElement->URL; } } catch (SOAPFault $f) { echo $f->faultstring . "\n"; } ?>
... produced a lovely error message:
tim@vm:/tmp>php test.php No Deserializer found to deserialize a ':filter' using encoding style 'http://schemas.xmlsoap.org/soap/encoding/'.
Here's the actual SOAP request PHP was sending:
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:GoogleSearch" 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:doGoogleSearch> <key xsi:type="xsd:string">[Secret Google key]</key> <q xsi:type="xsd:string">Tim Strehle</q> <start xsi:type="xsd:int">0</start> <maxResults xsi:type="xsd:int">3</maxResults> <filter xsi:nil="true"/> <restrict xsi:nil="true"/> <safeSearch xsi:nil="true"/> <lr xsi:nil="true"/> <ie xsi:nil="true"/> <oe xsi:nil="true"/> </ns1:doGoogleSearch> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
The error message did come from Google:
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"> <SOAP-ENV:Body> <SOAP-ENV:Fault> <faultcode>SOAP-ENV:Client</faultcode> <faultstring>No Deserializer found to deserialize a ':filter' using encoding style 'http://schemas.xmlsoap.org/soap/encoding/'.</faultstring> <faultactor>/search/beta2</faultactor> </SOAP-ENV:Fault> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Obviously Google doesn't like the *xsi:nil* stuff created by PHP. Modifying those empty tags manually in an XML file...
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:GoogleSearch" 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:doGoogleSearch> <key xsi:type="xsd:string">[Secret Google key]</key> <q xsi:type="xsd:string">Tim Strehle</q> <start xsi:type="xsd:int">0</start> <maxResults xsi:type="xsd:int">3</maxResults> **<filter xsi:type="xsd:boolean">false</filter> <restrict xsi:type="xsd:string"></restrict> <safeSearch xsi:type="xsd:boolean">false</safeSearch> <lr xsi:type="xsd:string"></lr> <ie xsi:type="xsd:string"></ie> <oe xsi:type="xsd:string"></oe>** </ns1:doGoogleSearch> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
... and sending the SOAP request using [curl](http://curl.haxx.se/ "cURL and libcurl") finally produced correct results:
tim@vm:/tmp>**cat test.curl** header = "SOAPAction: urn:GoogleSearchAction" header = "Content-Type: text/xml" data = "@/tmp/test.xml" url = "http://api.google.com/search/beta2" tim@vm:/tmp>**curl -K test.curl | xmllint --format -** <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"> <SOAP-ENV:Body> <ns1:doGoogleSearchResponse xmlns:ns1="urn:GoogleSearch" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <return xsi:type="ns1:GoogleSearchResult"> <directoryCategories xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:Array" ns2:arrayType="ns1:DirectoryCategory[0]"> </directoryCategories> <documentFiltering xsi:type="xsd:boolean">false</documentFiltering> <endIndex xsi:type="xsd:int">3</endIndex> <estimateIsExact xsi:type="xsd:boolean">false</estimateIsExact> <estimatedTotalResultsCount xsi:type="xsd:int">184000</estimatedTotalResultsCount> <resultElements xmlns:ns3="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns3:Array" ns3:arrayType="ns1:ResultElement[3]"> <item xsi:type="ns1:ResultElement"> <URL xsi:type="xsd:string">http://tim.digicol.de/</URL> <cachedSize xsi:type="xsd:string">4k</cachedSize> <directoryCategory xsi:type="ns1:DirectoryCategory"> <fullViewableName xsi:type="xsd:string"/> <specialEncoding xsi:type="xsd:string"/> </directoryCategory> <directoryTitle xsi:type="xsd:string"/> <hostName xsi:type="xsd:string"/> <relatedInformationPresent xsi:type="xsd:boolean">true</relatedInformationPresent> <snippet xsi:type="xsd:string"><b>Tim</b> at his desk <b>Tim Strehle</b> @ Digital Collections <b>...</b> <b>Tim&#39;s</b> Weblog &middot; Ceterum censeo...<br> www.liederdatenbank.de, my personal project for building a database <b>...</b></snippet> <summary xsi:type="xsd:string"/> <title xsi:type="xsd:string"><b>Tim Strehle</b> @ Digital Collections</title> </item> <item xsi:type="ns1:ResultElement"> <URL xsi:type="xsd:string">http://tim.digicol.de/weblog/</URL> <cachedSize xsi:type="xsd:string">33k</cachedSize> <directoryCategory xsi:type="ns1:DirectoryCategory"> <fullViewableName xsi:type="xsd:string"/> <specialEncoding xsi:type="xsd:string"/> </directoryCategory> <directoryTitle xsi:type="xsd:string"/> <hostName xsi:type="xsd:string"/> <relatedInformationPresent xsi:type="xsd:boolean">true</relatedInformationPresent> <snippet xsi:type="xsd:string">My linkblog: What I (<b>Tim Strehle</b>) read on the web, on PHP. XML. Information Science<br> and Information Architecture... 2006-08-23 <b>...</b></snippet> <summary xsi:type="xsd:string"/> <title xsi:type="xsd:string"><b>Tim&#39;s</b> Weblog » Latest posts</title> </item> <item xsi:type="ns1:ResultElement"> <URL xsi:type="xsd:string">http://freshmeat.net/~tistre/</URL> <cachedSize xsi:type="xsd:string">12k</cachedSize> <directoryCategory xsi:type="ns1:DirectoryCategory"> <fullViewableName xsi:type="xsd:string"/> <specialEncoding xsi:type="xsd:string"/> </directoryCategory> <directoryTitle xsi:type="xsd:string"/> <hostName xsi:type="xsd:string"/> <relatedInformationPresent xsi:type="xsd:boolean">true</relatedInformationPresent> <snippet xsi:type="xsd:string">User info page for <b>Tim Strehle</b>. Name: <b>Tim Strehle</b>. User ID: #96744. Email: <b>tim</b><br> __at__ <b>strehle</b> __dot__ <b>...</b> <b>Tim Strehle</b> didn&#39;t post any article comments yet. <b>...</b></snippet> <summary xsi:type="xsd:string"/> <title xsi:type="xsd:string">freshmeat.net: User information</title> </item> </resultElements> <searchComments xsi:type="xsd:string"/> <searchQuery xsi:type="xsd:string">Tim Strehle</searchQuery> <searchTime xsi:type="xsd:double">0.020699</searchTime> <searchTips xsi:type="xsd:string"/> <startIndex xsi:type="xsd:int">1</startIndex> </return> </ns1:doGoogleSearchResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
I don't know enough SOAP so I cannot say whether this is Google's or PHP's fault, but it's definitely not the "just works" experience I'd expect from both of them. If SOAP's complexity itself is to blame, I may have been right to lean towards REST (or POX over HTTP) without ever having used much SOAP...
Update: "Optional fields cause problems", says Dare Obasanjo - ETech 2005 Trip Report: Building a New Web Service at Google... It turns out that filling in all optional parameters in the SOAP call makes the PHP script work:
<?php $client = new SoapClient('GoogleSearch.wsdl'); try { $result = $client->doGoogleSearch( '[Secret Google key]', 'Tim Strehle', 0, 3, **false, '', false, '', '', ''** ); ... ?>