1 <?php 2 try 3 { 4 $client = new SoapClient(NULL, 5 array("location" => "http://[Ihr Server]/[Ihr Service]", 6 "uri" => "urn:getServerTime", 7 "style" => SOAP_RPC, 8 "use" => SOAP_ENCODED)); 9 10 print($client->__soapCall("getServerTime", 11 array(), 12 array("uri" => "urn:getServerTime", 13 "soapaction" => "urn:getServerTime"))); 14 } 15 catch (SoapFault $e) 16 { 17 print($e); 18 } 19 ?>Wie man sieht muss man eine Menge schreiben um eine simple Funktion aufzurufen. Zuerst wird der SoapClient durch Angabe der WSDL, in unserem Falle "null" und zusätzlichen Parameter erzeugt. Ist keine WSDL-Datei vorhanden, sind die Parameter zwingend erforderlich, ansonsten optional, da diese automatisch aus der WSDL-Datei ausgelesen werden können. Danach wird die Funktion durch einen Soap-Call aufgerufen. Der erste Parameter ist der Name der aufzurufenden Funktion, danach kommen die zu übergebende Parameter, und zuletzt noch zusätzliche Optionen.
1 <?php 2 try 3 { 4 $client = new SoapClient("http://[Ihr Server]/[Ihre WSDL]"); 5 print($client->getServerTime()); 6 } 7 catch (SoapFault $e) 8 { 9 print($e); 10 } 11 ?>Durch parsen der WSDL-Datei werden alle Services zu direkt aufufbaren Methoden des Clients. Die Handhabung wird dadurch einfacher, allerdings die Last und der Netzwerk-Traffic gesteigert.
1 <?xml version="1.0" encoding="UTF-8"?> 2 <wsdl:definitions 3 targetNamespace="http://[Ihr Server]/[Ihr Service]" 4 xmlns:apachesoap="http://xml.apache.org/xml-soap" 5 xmlns:impl="http://[Ihr Server]/[Ihr Service]" 6 xmlns:intf="http://[Ihr Server]/[Ihr Service]" 7 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 8 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 9 xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 10 xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 11 12 <wsdl:message name="getServerTimeRequest"> 13 </wsdl:message> 14 <wsdl:message name="getServerTimeResponse"> 15 <wsdl:part name="getServerTimeReturn" type="xsd:int" /> 16 </wsdl:message> 17 18 <wsdl:portType name="server1"> 19 <wsdl:operation name="getServerTime"> 20 <wsdl:input message="impl:getServerTimeRequest" 21 name="getServerTimeRequest" /> 22 <wsdl:output message="impl:getServerTimeResponse" 23 name="getServerTimeResponse" /> 24 </wsdl:operation> 25 </wsdl:portType> 26 27 <wsdl:binding name="server1SoapBinding" type="impl:server1"> 28 <wsdlsoap:binding style="rpc" 29 transport="http://schemas.xmlsoap.org/soap/http" /> 30 <wsdl:operation name="getServerTime"> 31 <wsdlsoap:operation soapAction="" /> 32 <wsdl:input name="getServerTimeRequest"> 33 <wsdlsoap:body 34 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 35 namespace="http://DefaultNamespace" use="encoded" /> 36 </wsdl:input> 37 <wsdl:output name="getServerTimeResponse"> 38 <wsdlsoap:body 39 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 40 namespace="http://[Ihr Server]/[Ihr Service]" use="encoded" /> 41 </wsdl:output> 42 </wsdl:operation> 43 </wsdl:binding> 44 45 <wsdl:service name="server1Service"> 46 <wsdl:port binding="impl:server1SoapBinding" name="server1"> 47 <wsdlsoap:address location="http://[Ihr Server]/[Ihr Service]" /> 48 </wsdl:port> 49 </wsdl:service> 50 51 </wsdl:definitions>Eine WSDL-Datei gliedert sich in 2 Grundbestandteile: einen abstrakten Teil, der die Datentypen und die Schnittstellen definiert, und einen konkreten Teil, der das Binding und die Adresse des Service definiert. In unserem Beispiel fehlt die Datentypdefinition, die durch die Sektion <types> angegeben wird, da wir auf den Einsatz von komplexen Typen verzichten. Der Abschnitt <message> beschreibt die Nachrichten, die zwischen Server und Client ausgetauscht werden können. <portType> beschreibt, um welche Art des Nachrichtenaustauschs es sich handelt, ob es eine Request-Response-Operation ist, eine Notification, d. h. eine Nachricht des Servers ohne Anfrage, oder ein asynchroner Nachrichtenaustausch. Das <binding> gibt die verwendeten Protokolle und das Nachrichtenformat an. Der letzte Abschnitt <services> definiert den Service, und beschreibt aus welchen Ports er sich zusammensetzt.
1 <?php 2 /** 3 * @desc Gibt die aktuelle Serverzeit zurück 4 * @return int 5 */ 6 function getServerTime() 7 { 8 return time(); 9 } 10 11 ini_set("soap.wsdl_cache_enabled", "0"); 12 $server = new SoapServer("webservice1.wsdl"); 13 $server->addFunction("getServerTime"); 14 $server->handle(); 15 ?>Mit dem ini_set Befehl wird das Caching der WSDL-Datei verhindert. Da das Parsen der WSDL-Datei bei jedem Serviceaufruf viel Performance braucht, sollte man die Zeile im Produktivbetrieb wieder entfernen. Standardmäßig wird die Datei einen Tag gepuffert. Die WSDL-Datei muss vorhanden sein und per Hand erzeugt werden, da die SOAP-Extension in PHP zur Zeit noch keine Generierung dieser unterstützt. Andere SOAP-Implementierungen wie NuSOAP oder PEAR::SOAP unterstützen WSDL-Generierung schon, allerdings nur in Verbindung mit PHPDoc, da die Reflection-API in PHP kein vollständiges Type-Hinting beherrscht. Da diese Implementierungen im Gegensatz zur nativen C-Extension in PHP geschrieben sind, ist die Performance aber um einiges schlechter. Außerdem befindet sich Ext/SOAP gerade erst im Anfangsstadium der Entwicklung, so daß wir auf eine zukünftige WSDL-Generierung hoffen dürfen. Wer solange nicht warten will, kann die PHP-Entwicklungsumgebung "Zend Studio" verwenden, die einen Wizard für die Generierung von WSDL-Dateien aus PHP-Code hat.
1 import org.apache.axis.client.Call; 2 import org.apache.axis.client.Service; 3 import javax.xml.namespace.QName; 4 5 public class ClientTest 6 { 7 public static void main(String[] args) 8 { 9 try 10 { 11 String endpoint = "http://[Ihr Server]/[Ihr Service]"; 12 13 Service service = new Service(); 14 Call call = (Call) service.createCall(); 15 16 call.setTargetEndpointAddress( new java.net.URL(endpoint) ); 17 call.setOperationName("getServerTime"); 18 Integer ret = (Integer) call.invoke( new Object[] {} ); 19 20 System.out.println("ServerTime: " + ret); 21 } 22 catch (Exception e) 23 { 24 System.err.println(e.toString()); 25 e.printStackTrace(); 26 } 27 System.exit(0); 28 } 29 }Damit dieses Programm compiliert müssen sich natürlich die benötigten AXIS-Libaries im classpath befinden.
1 import java.util.Date; 2 3 public class MyWebService 4 { 5 public long getServerTime() 6 { 7 Date now = new Date(); 8 return now.getTime(); 9 } 10 }AXIS stellt automatisch alle Methoden, die public sind, als Webservice bereit. Außerdem liefert es automatisch die WSDL-Datei, wenn man den Service mit "http://[Ihr Server]/axis/MyWebService.jws?wsdl" aufruft. Ein weiterer Vorteil von AXIS ist, dass man den Webservice auch anstelle eines SOAP-Request mit einem normalen GET-Request aufrufen kann. In unserem Falle wäre das "http://[Ihr Server]/axis/MyWebService.jws?method=getServerTime". Zu beachten ist, dass die Rückgabenachricht allerdings eine SOAP-Nachricht ist. Man spart sich hier den SOAP-Overhead zumindest in einer Richtung.