Beim Thema Webservices mit PHP scheiden sich wohl die Geister. Nach dem ich aus aktuellem Anlass einige Bibliotheken getestet habe, bin ich zu sehr unterschiedlichen Erkenntnissen gelangt. Während einige Bibliotheken einen sehr schönen Ansatz haben und dem Gedanken der einfachen Handhabung nachkommen, funktionieren lediglich andere Bibliotheken die nicht unbedingt Benutzerfreundlich aber dafür fehlerfrei agieren können.
Folgende Bibliotheken wurden getestet:
Positiv hervorzuheben ist, dass jede Bibliothek unter der GNU Lesser General Public License veröffentlicht wurde und somit frei für die eigene und kommerzielle Verwendung zur Verfügung steht.
Ausgangsbasis für alle getesteten Bibliotheken sind die folgenden 3 Klassen. Erstere ist die sogenannte Funktionsklasse. Sie beinhaltet die Klasse und Methoden die als Service zur Verfügung gestellt werden sollen. Als Beispiel wurde eine Klasse aufbereitet, welche die Grundrechenarten zur Verfügung stellt. Als Übergabeparameter werden jeweils zwei Zahlen vom Datentyp float verlangt. Der Rückgabewert ist in diesem Beispiel ebenfalls eine Zahl vom Typ float.
Mathematics.class.php
/**
* Service class documentation.
*/
class Mathematics {
/**
* Addition of two numbers.
*
* @param float x
* @param float y
* @return float
*/
public function add($x, $y) {
return $x + $y;
}
/**
* Subtraction of two numbers.
*
* @param float x
* @param float y
* @return float
*/
public function minus($x, $y) {
return $x - $y;
}
/**
* Multiply of two numbers.
*
* @param float x
* @param float y
* @return float
*/
public function multiply($x, $y) {
return $x * $y;
}
/**
* Divide of two numbers.
*
* @param float x
* @param float y
* @return float
*/
public function divide($x, $y) {
return $x / $y;
}
}
Bei der zweiten Klasse handelt es sich um die SoapClient.php. Diese wird als Test-Klasse gesehen und prüft die zu Verfügung stehenden Methoden. Diese muss bei der Verwendung von unterschiedlichen Bibliotheken auch entsprechend abgeändert werden. Aber im großen und ganzen ändert sich nur die URL zur Serverklasse. Ebenfalls kann es nötig sein diverse Bibliotheken vorher einzubinden.
ServerSoap.php
<?php
ini_set('soap.wsdl_cache_enabled', "0");
try {
// create the client instance
$client = new SoapClient('http://localhost/SoapServer.php');
$baseMetrics = array(
'add' => '+',
'minus' => '-',
'multiply' => '*',
'divide' => '/'
);
$format = '%.2f %s %.2f = %.2f <br />';
foreach($baseMetrics as $key => $value) {
// call the SOAP method
$x = random(); $y = random();
$result = $client->__soapCall($key, array('x' => $x, 'y' => $y));
printf($format, $x, $value, $y, $result);
}
} catch (SoapFault $fault) {
echo '<h2>Fault</h2><pre>';
print_r($fault);
echo '</pre>';
}
// seed with microseconds
function random() {
list($usec, $sec) = explode(' ', microtime());
mt_srand((float) $sec + ( (float) $usec * 100000));
return mt_rand(1,9) / pi();
}
/*
echo 'Request: <xmp>'.$client->request.'</xmp>';
echo 'Response: <xmp>'.$client->response.'</xmp>';
echo 'Debug log: <pre>'.$client->debug_str.'</pre>';
*/
?>
Die ServerSoap-Klasse soll an dieser Stelle nur grob erklärt werden. Beginnend mit einem ini_set wird die Cache-Funktion von Soap außer Kraft gesetzt. Zu Testzwecken ist dies zwingend erforderlich. Im Produktiveinsatz muss diese dann nicht mehr initiiert werden. Innerhalb einer try-catch Anweisung wird der eigentliche Prozess abgearbeitet. Hierfür wird ein SoapClient initialisiert, welche als erstes Argument die URL vom SoapServer trägt. Ab dem zweiten Argument wird ein Array mit Optionen erwartet, auf die an dieser Stelle aber nicht weiter eingegangen wird. In einem ersten Array werden alle Funktionsnamen festgehalten die getestet werden sollen. Dabei handelt es sich um die Grundrechenarten aus der Mathematics.class.php. Diese werden nach einander abgearbeitet. Mit dem client-Objekt wird ein sogenannter __soapCall gestartet. Das erste Argument trägt den Namen der Methode. Das zweite Argument trägt ein Array mit den jeweiligen Übergabeparametern die verarbeitet werden sollen. Abschließend ist nur noch zu sagen das die Zahlen, zum testen der Methoden, zufällig generiert werden. Hierfür wurde eine eigene random-Methode implementiert. Für fanatische Debugger wurde ganz zum Schluss dieser Klasse einige Ausgaben getätigt. Hier nun auskommentiert, da diese nicht mit jeder Bibliothek kompatibel sind.
Allgemein wird für jede Grundrechenart ein Request gestartet. Und in Form einer Gleichung auf dem Bildschirm ausgegeben. Die Rückgabe stellt das Ergebnis der jeweiligen Gleichung dar. Wie es nun mit den jeweiligen SoapServern aussieht, wird mit den folgenden, getesteten Bibliotheken erklärt.
PHP2WSDL
Dieses doch recht junge Projekt wurde vom Rumänen Dragos Protung veröffentlicht. Eine recht schlanke Bibliothek mit gerade mal 3 Bibliotheksklassen, ermöglicht es dem Anwender, aus einer bestehenden und dokumentierten PHP-Klasse ein WSDL-Dokument zu generieren. Der dahinter stehende Gedanke bezieht sich auf die Arbeitserleichterung, der zu registrierenden Klassen und Methoden. Bei der Verwendung dieser Bibliothek entfallen diese Schritte. Der Anwender hat lediglich eine wohl dokumentiere PHP-Klasse vorzulegen und muss sich um nichts anderes mehr kümmern.
So schön dies auch klingen mag, birgt diese Bibliothek, in der Version 1.0, eine schier von Formfehlern. So muss bereits bei der ersten Verwendung kleinere Anpassung an den Sourcen vorgenommen werden. Auch die automatische Generierung von Variablen läuft nicht fehlerfrei ab. So werden zum Beispiel an den bereits verwendeten Variablen, einer Methode in einer Klasse, fortlaufende Zahlen angehängt. Das ist natürlich unvorteilhaft, wenn das Script selbst die Dokumentationsvariablen und die Übergabeparameter der Methode vergleicht und dementsprechende Datentypen zuweist. Diese werden beim Anhängen von fortlaufenden Zahlen nicht mehr richtig erkannt und erhalten einen unbekannten Datentyp im WSDL-Dokument.
Zum aktuellen Zeitpunkt (Januar 2010) ist im hauseigenen Supportforum nachzulesen das der Entwickler an der nächsten Version (2.0) arbeitet, die solche Fehler einerseits beseitigen soll und neue Features und Unterstützungen für die Dokumentation und Datentypen von PHP bereit halten soll. Es bleibt abzuwarten ob hieraus noch was werden wird, da diese Meldung bereits mehrere Monate alt ist.
So, oder so ähnlich kann diesbezüglich die SoapServer-Klasse aussehen. Eine vernüftige Dokumentation habe ich leider nicht gefunden. Daher habe ich auskommentierte Funktionsaufrufe im folgendem Beispiel belassen. Die Pfade sind dementsprechend abzuändern.
SoapServer.php
<?php
ini_set('soap.wsdl_cache_enabled', "0");
require_once("../WSDLCreator.php");
//header("Content-Type: application/xml");
$test = new WSDLCreator("Mathematics", "http://localhost/php2wsdl/SoapServer.php");
//$test->includeMethodsDocumentation(false);
$test->addFile(Mathematics.class.php");
$test->setClassesGeneralURL("http://localhost/php2wsdl/example");
$test->addURLToClass("Mathematics", "http://localhost/php2wsdl/Mathematics.class.php");
$test->addURLToTypens("XMLCreator", "http://localhost/php2wsdl");
$test->createWSDL();
$test->printWSDL(true); // print with headers
//print $test->getWSDL();
//$test->downloadWSDL();
//$test->saveWSDL(dirname(__FILE__)."/test.wsdl", false);
?>
Ein unbestreitbarer Vorteil ist die einfache Integrierung von mehreren Dateien und Klassen. Es muss lediglich mittelst addFile eine neue Funktionsbibliothek hinzugefügt werden. Der Rest wird vom Script selbst erledigt. Aus den bereits genannten Nachteilen kommt beschwerend hinzu das ich mittelst dieser Bibliothek noch nie ein Response erhalten habe. Dieser war bisher immer NULL.
WSDLDocument
Bei dieser Bibliothek handelt es sich lediglich um eine Bibliothek die ein WSDL-Dokument generiert. Es verfolgt den gleichen Gedanken wie die PHP2WSDL-Bibliothek. Nur mit dem gravierenden Unterschied das diese fehlerfrei funktioniert. Datentypen werden aus der Dokumentation richtig erkannt und in einem WSDL-Dokument aufbereitet. Wie auch beim Vorgänger sind hier ebenfalls Komplexe Datentypen möglich. Dazu gehören unter anderem verschachtelte Arrays. Die Einbindung des Scripts, habe ich einfachshalber gleich in der Funktionsklasse Mathematics erledigt. Dazu ist folgender Quellcode in der Klasse Mathematics.class.php unterzubringen. Beim Aufruf erhält man dann das WSDL-Dokument.
header ("content-type: text/xml");
require_once('WSDLDocument.php');
$wsdl = new WSDLDocument('Mathematics','urn:Mathematics');
echo $wsdl->saveXML();
Dennoch sei gesagt, das dieses Dokument nach einer alten Spezifikation arbeitet. Eine entsprechende Anpassung ist aber relativ zügig realisiert. Was leider nicht funktioniert ist die Ansteuerung des Service selbst. Es wird hierbei wirklich nur ein XML-Dokument ausgegeben.
NuSoap
Nicht Perfekt, aber eine der am erfolgreichsten getesteten Bibliotheken, ist NuSoap. Diese kommt mit einer relativen großen Anzahl an Klassen daher und realisiert das generieren von WSDL-Dokumenten. Leider wird hier nicht der Gedanke des Parsens von PHP-Klassen verfolgt. Wie es von PHP-Soap bereits bekannt ist, müssen Methoden registriert und zusätzlich in der ServerSoap geschrieben werden. Da man dies eigentlich nur einmal macht, kann man diesen Mehraufwand allerdings vernachlässigen. Eine Mathematics.class.php wird hierbei nicht benötigt.
SoapServer.php
<?php
// Pull in the NuSOAP code
require_once('lib/nusoap.php');
// Create the server instance
$server = new soap_server();
// Initialize WSDL support
$server->configureWSDL('Mathematics', 'urn:Mathematics');
// Register the method to expose
$server->register('add',
array('x' => 'xsd:float', 'y' => 'xsd:float'),
array('return' => 'xsd:float'),
'urn:Mathematics',
'urn:Mathematics#add',
'rpc', 'encoded', 'Addition of two numbers.');
$server->register('minus',
array('x' => 'xsd:float', 'y' => 'xsd:float'),
array('return' => 'xsd:float'),
'urn:Mathematics',
'urn:Mathematics#minus',
'rpc', 'encoded', 'Subtraction of two numbers.');
$server->register('multiply',
array('x' => 'xsd:float', 'y' => 'xsd:float'),
array('return' => 'xsd:float'),
'urn:Mathematics',
'urn:Mathematics#multiply',
'rpc', 'encoded', 'Multiply of two numbers.');
$server->register('divide',
array('x' => 'xsd:float', 'y' => 'xsd:float'),
array('return' => 'xsd:float'),
'urn:Mathematics',
'urn:Mathematics#divide',
'rpc', 'encoded', 'Divide of two numbers.');
// Define the method as a PHP function
function add($x, $y) { return ($x + $y); }
function minus($x, $y) { return ($x - $y); }
function multiply($x, $y) { return ($x * $y); }
function divide($x, $y) { return ($x / $y); }
// Use the request to (try to) invoke the service
$HTTP_RAW_POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
$server->service($HTTP_RAW_POST_DATA);
?>
Wie man sieht, ist die Server-Klasse etwas größer geraten, als die bisherigen Methoden. Das WSDL-Dokument, wird ohne Frage richtig generiert. Ein Abzug in der B-Note gibt es für die doppelte Definierung der Methoden. Einmal für die Registrierung für den SoapServer und die eigentliche Bereitstellung. Ebenfalls zu beachten ist die Einbindung der nusoap.php-Bibliothek die hierbei in einem Unterordner namens lib liegt.
Ein großer Pluspunkt ist die Aufbereitung einer „Startseite” des SoapServers. Grafisch, mittelst CSS, werden alle Funktionen und dessen registrierte Dokumentation angezeigt. Ein wirklich tolles Feature, was vielleicht die generelle Dokumntation abnehmen kann. Das eigentliche WSDL-Dokument lässt sich mit dem Paramater „?wsdl” erreichen und muss auch die URL beim SoapClient sein.
Diese Bibliothek wurde als erste vollständig und fehlerfrei getestet und ist somit auch für den allgemeinen Einsatz zu empfehlen. Schade nur das es keine Generierung aus der PHP-Dokumentation ermöglicht. Aber was nicht ist kann ja noch werden.
Fazit
NuSoap hat sich herausragend geschlagen. Mit einem kleinen Mehraufwand, Methoden zu registrieren und zusätzlich zu beschreiben, erledigt es die Aufgabe der Generierung des WSDL-Dokuments und die Abfrage der Services sehr gewissenhaft und konnte keine Fehler in der Verarbeitung vorweisen. Für Beginner eigenen sich dennoch Bibliotheken wie PHP2WSDL und WSDLDocument. Um ein Gefühl für die Materie zu erhalten sollte man sich auch vorher mit dem eigentlichen Aufbau von WSDL-Dokumenten beschäftigt haben.
4 Antworten : “Webservices (WSDL) mit PHP”


Herausragend!!! Vielen Dank für die Infos. Auch ich habe mehrere Möglichkeiten versucht und mich aus eben diesen Gründen für nusoap entschieden. Bin nun froh auch von einer anderen Stelle in meiner Entscheidung bestärkt zu werden.
Eine Sache aber hat mich verwundert:
$server->register(‚multiply‘,
22 array(‚x‘ => ‚xsd:float‘, ‚y‘ => ‚xsd:float‘),
23 array(‚return‘ => ‚xsd:float‘),
24 ‚urn:Mathematics‘,
25 ‚urn:Mathematics#multiply‘,
26 ‚rpc‘, ‚encoded‘, ‚Multiply of two numbers.‘);
und der Aufruf:
$client->__soapCall($key, array(‚x‘ => $x, ‚y‘ => $y));
funktioniert bei mir nicht. Gehen würde
$client->__soapCall($key, $x,$y);
eine Idee weshalb? Ich bekomme ansonsten nur eine 1 für den ersten an die Funktion übergebenen Parameter. Ist dieser nicht gerade float oder int sondern string lautet dieser Array. gettype($x) verrät mir dann, dass Array ebenfalls nur ein String ist.
EDIT: (Evtl. hinzufügen)
Zudem kann ich den Server nicht in Betrieb nehmen, wenn das Return nicht als soapval(‚return‘, ‚xsd:float‘, ($x * $y)) definiert wurde
php2wsdl finde ich ja ehrlich gesagt nicht so gut. Du kannst auch die Reflection API nutzen um die WSDL zu geneieren. Wie das funktioniert gibts hier zu lesen: http://www.easy-coding.de/wiki/php/php-soap-server-mit-wsdl-und-api-schluessel.html
php2wsdl ist auch nur eine getestete Bibliothek. Das diese für den Produktiveinsatz ungeeignet ist, geht hoffentlich aus dem Beitrag hervor. Im Fazit lässt sich ja erkennen das NuSoap am besten geeignet ist.