Einen Webdienst programmieren

Jede Funktion oder öffentliche Methode einer Klasse kann in PHP 5 über die Klasse SOAPServer als Webdienst verfügbar gemacht werden.

Der Konstruktor der Klasse SOAPServer erwartet entweder den Pfad zu einer WSDL-Beschreibung des Webdienstes als ersten Parameter oder ein assoziatives Array, das Informationen wie die URL des Webdienstes enthält, als zweiten Parameter. Wir betrachten zunächst den Fall, dass keine WSDL-Beschreibung vorliegt. In Beispiel 9.1 übergeben wir den Wert NULL als ersten Parameter sowie ein Array mit der Konfiguration des Webdienstes als zweiten Parameter.

Mit der Methode setClass() des SOAPServer-Objektes legen wir die Klasse fest, deren öffentliche Methoden wir über den Webdienst verfügbar machen möchten. Mit der Methode handle() "starten" wir den Webdienst. Das bedeutet, dass eine HTTP-Anfrage an das Skript des SOAPServer-Objektes als Anfrage an den Webdienst aufgefasst und entsprechend verarbeitet wird.

Beispiel 9.1: Der Hallo-Welt-Webdienst

<?php
class Webdienst {
  public function halloWelt() {
    return 'Hallo Welt';
  }
}
 
try {
  $server = new SOAPServer(
    NULL,
    array(
      'uri' => 'http://localhost/HalloWelt'
    )
  );
 
  $server->setClass('Webdienst');
  $server->handle();
}
 
catch (SOAPFault $f) {
  print $f->faultstring;
}
?>


Fehler, die während der SOAP-Verarbeitung auftreten, werden durch eine SOAPFault-Ausnahme repräsentiert und können entsprechend behandelt werden.

Nehmen wir einmal an, dass Beispiel 9.1 unter der URL http://localhost.org/HalloWelt.php erreichbar ist. Eine "normale" HTTP-Anfrage für dieses Dokument führt zu einer SOAP-Fehlermeldung, wie sie Abbildung 9.1 zeigt, da sie keine gültige Anfrage im SOAP-Format enthält.

Abbildung 9.1. Ausgabe: SOAP-Antwort auf eine HTTP-Anfrage

<?xml version="1.0" encoding="UTF-8"?>

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <faultcode>SOAP-ENV:Server</faultcode>
      <faultstring>Bad Request. Can't find HTTP_RAW_POST_DATA</faultstring>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


Über eine HTTP-Post-Anfrage (Beispiel 9.2), die im SOAP-XML-Format gestellt wird, können wir die Methode halloWelt() der Klasse Webdienst (Beispiel 9.1) aufrufen.

Beispiel 9.2: Eine SOAP-Anfrage an den Hallo-Welt-Webdienst


<?xml version="1.0" encoding="UTF-8"?>

<SOAP-ENV:Envelope
 soap-env:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:si="http://soapinterop.org/xsd">

 <SOAP-ENV:Body>
  <ns1:halloWelt xmlns:ns1="http://localhost" />
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Hallo Welt


Eine solche Anfrage von Hand zu erstellen ist bereits in dem hier gezeigten einfachen Beispiel (keine Parameter, einfacher String als Ergebnis) mühsam. Im folgenden Abschnitt werden wir sehen, wie uns die Klasse SOAPClient diese Arbeit abnimmt.

Doch zunächst beschreiben wir den Webdienst mit WSDL in der Datei HalloWelt.wsdl (Beispiel 9.3). Die WSDL-Beschreibung enthält unter anderem Informationen über die Adresse des Webdienstes sowie die Datentypen von Parametern und Rückgabewerten der angebotenen Methoden.

Beispiel 9.3: Den Hallo-Welt-Webdienst mit einem WSDL-Dokument beschreiben


<?xml version ="1.0" encoding ="UTF-8" ?>

<definitions name="HalloWelt"
 targetNamespace="http://localhost/HalloWelt"
 xmlns:tns=" http://localhost/HalloWelt"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns="http://schemas.xmlsoap.org/wsdl/">

 <message name="halloWeltResponse">
  <part name="Result" type="xsd:string"/>
 </message>

 <portType name="HalloWeltPortType">
  <operation name="halloWelt">
   <output message="tns:halloWeltResponse"/>
  </operation>
 </portType>

 <binding name="HalloWeltBinding" type="tns:HalloWeltPortType">
  <soap:binding
   style="rpc"
   transport="http://schemas.xmlsoap.org/soap/http"/>

  <operation name="halloWelt">
   <soap:operation soapAction="urn:hallowelt#halloWelt"/>
   <output>
    <soap:body
     use="encoded"
     namespace="urn:hallowelt"
     encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
   </output>
  </operation>
 </binding>

 <service name="HalloWeltService">
  <port name="HalloWeltPort" binding="HalloWeltBinding">
   <soap:address location="http://localhost/HalloWelt.php"/>
  </port>
 </service>
</definitions>



Bei der Erzeugung des SOAPServer-Objektes können wir nun anstelle von NULL und dem assoziativen Parameter-Array den Pfad zur WSDL-Beschreibung aus Beispiel 9.3 angeben (Beispiel 9.4). Für eine HTTP-Anfrage an http://localhost/HalloWelt.php?wsdl liefert das Skript nun die WSDL-Beschreibung aus.

Beispiel 9.4: Der Hallo-Welt-Webdienst mit WSDL-Beschreibung

<?php
class Webdienst {
  public function halloWelt() {
    return 'Hallo Welt';
  }
}
 
try {
  $server = new SOAPServer('HalloWelt.wsdl');
  $server->setClass('Webdienst');
  $server->handle();
}
 
catch (SOAPFault $f) {
  print $f->faultstring;
}
?>