{"id":810,"date":"2006-08-29T00:00:00","date_gmt":"2006-08-28T22:00:00","guid":{"rendered":"https:\/\/wwwneu.strehle.de\/tim\/weblog\/archives\/2006\/08\/29\/748\/"},"modified":"2006-08-29T00:00:00","modified_gmt":"2006-08-28T22:00:00","slug":"748","status":"publish","type":"post","link":"https:\/\/www.strehle.de\/tim\/weblog\/archives\/2006\/08\/29\/748\/","title":{"rendered":"NOT Getting Started with PHP 5 SOAP"},"content":{"rendered":"<p>Not having played with PHP 5&#8217;s native <a href=\"http:\/\/www.php.net\/soap\/\" title=\"PHP: SOAP Functions - Manual\">SOAP extension<\/a> yet, I did expect it to work smoothly with the most simple application I could think of &#8211; querying Google via its <a href=\"http:\/\/www.google.com\/apis\/\" title=\"Google SOAP Search API - Home\">SOAP Search API<\/a>. Well&#8230;<\/p>\n<p>I first compiled the latest PHP 5.1.6 with <em>&#8211;enable-soap<\/em> and downloaded the <a href=\"http:\/\/www.google.com\/apis\/download.html\" title=\"Google SOAP Search API - Download\">Google SOAP Search API developer&#8217;s kit<\/a> which contains their WSDL file, <em>GoogleSearch.wsdl<\/em>.<\/p>\n<p>Running this example PHP code&#8230;<\/p>\n<div style=\"background:silver;border-width:1px;border-style:dotted;white-space: pre;overflow:auto;\">&lt;?php $client = new SoapClient(&#8218;GoogleSearch.wsdl&#8216;); try { $result = $client-&gt;doGoogleSearch( &#8218;[Secret Google key]&#8216;, &#8218;Tim Strehle&#8216;, 0, 3 ); foreach ($result-&gt;resultElements as $resultElement) { print $resultElement-&gt;URL; } } catch (SOAPFault $f) { echo $f-&gt;faultstring . &#8222;\\n&#8220;; } ?&gt;<\/div>\n<p>&#8230; produced a lovely error message:<\/p>\n<div style=\"background:silver;border-width:1px;border-style:dotted;white-space: pre;overflow:auto;\">tim@vm:\/tmp&gt;php test.php No Deserializer found to deserialize a &#8218;:filter&#8216; using encoding style &#8218;http:\/\/schemas.xmlsoap.org\/soap\/encoding\/&#8216;.<\/div>\n<p>Here&#8217;s the actual SOAP request PHP was sending:<\/p>\n<div style=\"background:silver;border-width:1px;border-style:dotted;white-space: pre;overflow:auto;\">&lt;?xml version=&#8220;1.0&#8243; encoding=&#8220;UTF-8&#8243;?&gt; &lt;SOAP-ENV:Envelope xmlns:SOAP-ENV=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8220; xmlns:ns1=&#8220;urn:GoogleSearch&#8220; xmlns:xsd=&#8220;http:\/\/www.w3.org\/2001\/XMLSchema&#8220; xmlns:xsi=&#8220;http:\/\/www.w3.org\/2001\/XMLSchema-instance&#8220; xmlns:SOAP-ENC=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/encoding\/&#8220; SOAP-ENV:encodingStyle=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/encoding\/&#8220;&gt; &lt;SOAP-ENV:Body&gt; &lt;ns1:doGoogleSearch&gt; &lt;key xsi:type=&#8220;xsd:string&#8220;&gt;[Secret Google key]&lt;\/key&gt; &lt;q xsi:type=&#8220;xsd:string&#8220;&gt;Tim Strehle&lt;\/q&gt; &lt;start xsi:type=&#8220;xsd:int&#8220;&gt;0&lt;\/start&gt; &lt;maxResults xsi:type=&#8220;xsd:int&#8220;&gt;3&lt;\/maxResults&gt; &lt;filter xsi:nil=&#8220;true&#8220;\/&gt; &lt;restrict xsi:nil=&#8220;true&#8220;\/&gt; &lt;safeSearch xsi:nil=&#8220;true&#8220;\/&gt; &lt;lr xsi:nil=&#8220;true&#8220;\/&gt; &lt;ie xsi:nil=&#8220;true&#8220;\/&gt; &lt;oe xsi:nil=&#8220;true&#8220;\/&gt; &lt;\/ns1:doGoogleSearch&gt; &lt;\/SOAP-ENV:Body&gt; &lt;\/SOAP-ENV:Envelope&gt;<\/div>\n<p>The error message did come from Google:<\/p>\n<div style=\"background:silver;border-width:1px;border-style:dotted;white-space: pre;overflow:auto;\">&lt;?xml version=&#8220;1.0&#8243; encoding=&#8220;UTF-8&#8243;?&gt; &lt;SOAP-ENV:Envelope xmlns:SOAP-ENV=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8220; xmlns:xsi=&#8220;http:\/\/www.w3.org\/1999\/XMLSchema-instance&#8220; xmlns:xsd=&#8220;http:\/\/www.w3.org\/1999\/XMLSchema&#8220;&gt; &lt;SOAP-ENV:Body&gt; &lt;SOAP-ENV:Fault&gt; &lt;faultcode&gt;SOAP-ENV:Client&lt;\/faultcode&gt; &lt;faultstring&gt;No Deserializer found to deserialize a &#8218;:filter&#8216; using encoding style &#8218;http:\/\/schemas.xmlsoap.org\/soap\/encoding\/&#8216;.&lt;\/faultstring&gt; &lt;faultactor&gt;\/search\/beta2&lt;\/faultactor&gt; &lt;\/SOAP-ENV:Fault&gt; &lt;\/SOAP-ENV:Body&gt; &lt;\/SOAP-ENV:Envelope&gt;<\/div>\n<p>Obviously Google doesn&#8217;t like the *xsi:nil* stuff created by PHP. Modifying those empty tags manually in an XML file&#8230;<\/p>\n<div style=\"background:silver;border-width:1px;border-style:dotted;white-space: pre;overflow:auto;\">&lt;?xml version=&#8220;1.0&#8243; encoding=&#8220;UTF-8&#8243;?&gt; &lt;SOAP-ENV:Envelope xmlns:SOAP-ENV=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8220; xmlns:ns1=&#8220;urn:GoogleSearch&#8220; xmlns:xsd=&#8220;http:\/\/www.w3.org\/2001\/XMLSchema&#8220; xmlns:xsi=&#8220;http:\/\/www.w3.org\/2001\/XMLSchema-instance&#8220; xmlns:SOAP-ENC=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/encoding\/&#8220; SOAP-ENV:encodingStyle=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/encoding\/&#8220;&gt; &lt;SOAP-ENV:Body&gt; &lt;ns1:doGoogleSearch&gt; &lt;key xsi:type=&#8220;xsd:string&#8220;&gt;[Secret Google key]&lt;\/key&gt; &lt;q xsi:type=&#8220;xsd:string&#8220;&gt;Tim Strehle&lt;\/q&gt; &lt;start xsi:type=&#8220;xsd:int&#8220;&gt;0&lt;\/start&gt; &lt;maxResults xsi:type=&#8220;xsd:int&#8220;&gt;3&lt;\/maxResults&gt; **&lt;filter xsi:type=&#8220;xsd:boolean&#8220;&gt;false&lt;\/filter&gt; &lt;restrict xsi:type=&#8220;xsd:string&#8220;&gt;&lt;\/restrict&gt; &lt;safeSearch xsi:type=&#8220;xsd:boolean&#8220;&gt;false&lt;\/safeSearch&gt; &lt;lr xsi:type=&#8220;xsd:string&#8220;&gt;&lt;\/lr&gt; &lt;ie xsi:type=&#8220;xsd:string&#8220;&gt;&lt;\/ie&gt; &lt;oe xsi:type=&#8220;xsd:string&#8220;&gt;&lt;\/oe&gt;** &lt;\/ns1:doGoogleSearch&gt; &lt;\/SOAP-ENV:Body&gt; &lt;\/SOAP-ENV:Envelope&gt;<\/div>\n<p>&#8230; and sending the SOAP request using [curl](http:\/\/curl.haxx.se\/ &#8222;cURL and libcurl&#8220;) finally produced correct results:<\/p>\n<div style=\"background:silver;border-width:1px;border-style:dotted;white-space: pre;overflow:auto;\">tim@vm:\/tmp&gt;**cat test.curl** header = &#8222;SOAPAction: urn:GoogleSearchAction&#8220; header = &#8222;Content-Type: text\/xml&#8220; data = &#8222;@\/tmp\/test.xml&#8220; url = &#8222;http:\/\/api.google.com\/search\/beta2&#8243; tim@vm:\/tmp&gt;**curl -K test.curl | xmllint &#8211;format -** &lt;?xml version=&#8220;1.0&#8243; encoding=&#8220;UTF-8&#8243;?&gt; &lt;SOAP-ENV:Envelope xmlns:SOAP-ENV=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8220; xmlns:xsi=&#8220;http:\/\/www.w3.org\/1999\/XMLSchema-instance&#8220; xmlns:xsd=&#8220;http:\/\/www.w3.org\/1999\/XMLSchema&#8220;&gt; &lt;SOAP-ENV:Body&gt; &lt;ns1:doGoogleSearchResponse xmlns:ns1=&#8220;urn:GoogleSearch&#8220; SOAP-ENV:encodingStyle=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/encoding\/&#8220;&gt; &lt;return xsi:type=&#8220;ns1:GoogleSearchResult&#8220;&gt; &lt;directoryCategories xmlns:ns2=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/encoding\/&#8220; xsi:type=&#8220;ns2:Array&#8220; ns2:arrayType=&#8220;ns1:DirectoryCategory[0]&#8220;&gt; &lt;\/directoryCategories&gt; &lt;documentFiltering xsi:type=&#8220;xsd:boolean&#8220;&gt;false&lt;\/documentFiltering&gt; &lt;endIndex xsi:type=&#8220;xsd:int&#8220;&gt;3&lt;\/endIndex&gt; &lt;estimateIsExact xsi:type=&#8220;xsd:boolean&#8220;&gt;false&lt;\/estimateIsExact&gt; &lt;estimatedTotalResultsCount xsi:type=&#8220;xsd:int&#8220;&gt;184000&lt;\/estimatedTotalResultsCount&gt; &lt;resultElements xmlns:ns3=&#8220;http:\/\/schemas.xmlsoap.org\/soap\/encoding\/&#8220; xsi:type=&#8220;ns3:Array&#8220; ns3:arrayType=&#8220;ns1:ResultElement[3]&#8220;&gt; &lt;item xsi:type=&#8220;ns1:ResultElement&#8220;&gt; &lt;URL xsi:type=&#8220;xsd:string&#8220;&gt;http:\/\/tim.digicol.de\/&lt;\/URL&gt; &lt;cachedSize xsi:type=&#8220;xsd:string&#8220;&gt;4k&lt;\/cachedSize&gt; &lt;directoryCategory xsi:type=&#8220;ns1:DirectoryCategory&#8220;&gt; &lt;fullViewableName xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;specialEncoding xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;\/directoryCategory&gt; &lt;directoryTitle xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;hostName xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;relatedInformationPresent xsi:type=&#8220;xsd:boolean&#8220;&gt;true&lt;\/relatedInformationPresent&gt; &lt;snippet xsi:type=&#8220;xsd:string&#8220;&gt;&amp;lt;b&amp;gt;Tim&amp;lt;\/b&amp;gt; at his desk &amp;lt;b&amp;gt;Tim Strehle&amp;lt;\/b&amp;gt; @ Digital Collections &amp;lt;b&amp;gt;&#8230;&amp;lt;\/b&amp;gt; &amp;lt;b&amp;gt;Tim&amp;amp;#39;s&amp;lt;\/b&amp;gt; Weblog &amp;amp;middot; Ceterum censeo&#8230;&amp;lt;br&amp;gt; www.liederdatenbank.de, my personal project for building a database &amp;lt;b&amp;gt;&#8230;&amp;lt;\/b&amp;gt;&lt;\/snippet&gt; &lt;summary xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;title xsi:type=&#8220;xsd:string&#8220;&gt;&amp;lt;b&amp;gt;Tim Strehle&amp;lt;\/b&amp;gt; @ Digital Collections&lt;\/title&gt; &lt;\/item&gt; &lt;item xsi:type=&#8220;ns1:ResultElement&#8220;&gt; &lt;URL xsi:type=&#8220;xsd:string&#8220;&gt;http:\/\/tim.digicol.de\/weblog\/&lt;\/URL&gt; &lt;cachedSize xsi:type=&#8220;xsd:string&#8220;&gt;33k&lt;\/cachedSize&gt; &lt;directoryCategory xsi:type=&#8220;ns1:DirectoryCategory&#8220;&gt; &lt;fullViewableName xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;specialEncoding xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;\/directoryCategory&gt; &lt;directoryTitle xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;hostName xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;relatedInformationPresent xsi:type=&#8220;xsd:boolean&#8220;&gt;true&lt;\/relatedInformationPresent&gt; &lt;snippet xsi:type=&#8220;xsd:string&#8220;&gt;My linkblog: What I (&amp;lt;b&amp;gt;Tim Strehle&amp;lt;\/b&amp;gt;) read on the web, on PHP. XML. Information Science&amp;lt;br&amp;gt; and Information Architecture&#8230; 2006-08-23 &amp;lt;b&amp;gt;&#8230;&amp;lt;\/b&amp;gt;&lt;\/snippet&gt; &lt;summary xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;title xsi:type=&#8220;xsd:string&#8220;&gt;&amp;lt;b&amp;gt;Tim&amp;amp;#39;s&amp;lt;\/b&amp;gt; Weblog \u00bb Latest posts&lt;\/title&gt; &lt;\/item&gt; &lt;item xsi:type=&#8220;ns1:ResultElement&#8220;&gt; &lt;URL xsi:type=&#8220;xsd:string&#8220;&gt;http:\/\/freshmeat.net\/~tistre\/&lt;\/URL&gt; &lt;cachedSize xsi:type=&#8220;xsd:string&#8220;&gt;12k&lt;\/cachedSize&gt; &lt;directoryCategory xsi:type=&#8220;ns1:DirectoryCategory&#8220;&gt; &lt;fullViewableName xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;specialEncoding xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;\/directoryCategory&gt; &lt;directoryTitle xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;hostName xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;relatedInformationPresent xsi:type=&#8220;xsd:boolean&#8220;&gt;true&lt;\/relatedInformationPresent&gt; &lt;snippet xsi:type=&#8220;xsd:string&#8220;&gt;User info page for &amp;lt;b&amp;gt;Tim Strehle&amp;lt;\/b&amp;gt;. Name: &amp;lt;b&amp;gt;Tim Strehle&amp;lt;\/b&amp;gt;. User ID: #96744. Email: &amp;lt;b&amp;gt;tim&amp;lt;\/b&amp;gt;&amp;lt;br&amp;gt; __at__ &amp;lt;b&amp;gt;strehle&amp;lt;\/b&amp;gt; __dot__ &amp;lt;b&amp;gt;&#8230;&amp;lt;\/b&amp;gt; &amp;lt;b&amp;gt;Tim Strehle&amp;lt;\/b&amp;gt; didn&amp;amp;#39;t post any article comments yet. &amp;lt;b&amp;gt;&#8230;&amp;lt;\/b&amp;gt;&lt;\/snippet&gt; &lt;summary xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;title xsi:type=&#8220;xsd:string&#8220;&gt;freshmeat.net: User information&lt;\/title&gt; &lt;\/item&gt; &lt;\/resultElements&gt; &lt;searchComments xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;searchQuery xsi:type=&#8220;xsd:string&#8220;&gt;Tim Strehle&lt;\/searchQuery&gt; &lt;searchTime xsi:type=&#8220;xsd:double&#8220;&gt;0.020699&lt;\/searchTime&gt; &lt;searchTips xsi:type=&#8220;xsd:string&#8220;\/&gt; &lt;startIndex xsi:type=&#8220;xsd:int&#8220;&gt;1&lt;\/startIndex&gt; &lt;\/return&gt; &lt;\/ns1:doGoogleSearchResponse&gt; &lt;\/SOAP-ENV:Body&gt; &lt;\/SOAP-ENV:Envelope&gt;<\/div>\n<p>I don&#8217;t know enough SOAP so I cannot say whether this is Google&#8217;s or PHP&#8217;s fault, but it&#8217;s definitely not the &#8222;just works&#8220; experience I&#8217;d expect from both of them. If SOAP&#8217;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&#8230;<\/p>\n<p><em>Update:<\/em> &#8222;Optional fields cause problems&#8220;, says Dare Obasanjo &#8211; <a href=\"http:\/\/www.25hoursaday.com\/weblog\/PermaLink.aspx?guid=83ec4876-7578-418c-8335-a3b0a147037b\" title=\"Dare Obasanjo aka Carnage4Life - ETech 2005 Trip Report: Building a New Web Service at Google\">ETech 2005 Trip Report: Building a New Web Service at Google<\/a>&#8230; It turns out that filling in all optional parameters in the SOAP call makes the PHP script work:<\/p>\n<div style=\"background:silver;border-width:1px;border-style:dotted;white-space: pre;overflow:auto;\">&lt;?php $client = new SoapClient(&#8218;GoogleSearch.wsdl&#8216;); try { $result = $client-&gt;doGoogleSearch( &#8218;[Secret Google key]&#8216;, &#8218;Tim Strehle&#8216;, 0, 3, **false, &#8220;, false, &#8220;, &#8220;, &#8220;** ); &#8230; ?&gt;<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Not having played with PHP 5&#8217;s native SOAP extension yet, I did expect it to work smoothly with the most simple application I could think of &#8211; querying Google via its SOAP Search API. Well&#8230; I first compiled the latest PHP 5.1.6 with &#8211;enable-soap and downloaded the Google SOAP Search API developer&#8217;s kit which contains [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_share_on_mastodon":"0"},"categories":[1],"tags":[],"class_list":["post-810","post","type-post","status-publish","format-standard","hentry","category-weblog"],"share_on_mastodon":{"url":"","error":""},"_links":{"self":[{"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/posts\/810","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/comments?post=810"}],"version-history":[{"count":0,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/posts\/810\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/media?parent=810"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/categories?post=810"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.strehle.de\/tim\/wp-json\/wp\/v2\/tags?post=810"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}