|
Mrz
26
|
Dieses Tutorial beschreibt, wie man mit PHP in kürzester Zeit einen SOAP WebService erstellt, der mit Persistenz umgehen kann und WSDL-Dateien selber generiert.
Wenn es in PHP-Projekten um Client-Server-Kommunikation, ins Besondere um RPC, geht, lässt man sich schnell dazu verleiten “mal eben” was eigenes zu bauen, obwohl es doch einige Standards für RPC gibt. Viele – genau wie ich auch – scheuen den Aufwand sich in Monster wie SOAP oder das etwas schlankere XML-RPC einzuarbeiten. Mit den richtigen Tool’s jedoch können PHP-Klassen jedoch mit geringstem Mehraufwand über SOAP zugänglich gemacht werden.
Die Einzige Vorraussetzung ist einen Webserver mit PHP5.0.3 oder aktueller und aktiviertem SOAP.
Leider ist die native SOAP-Implementation von PHP jedoch relativ kryptisch und bietet momentan keine Möglichkeit WSDL Dateien zu generieren. Die Web Services Description Language ist eine plattform-, programmiersprachen- und protokollunabhängige Beschreibungssprache für Netzwerkdienste (Web Services) zum Austausch von Nachrichten auf Basis von XML. Über diese WSDL-Dateien können dann Client-Stubs, z.B. in .NET komplett generiert werden.
Abhilfe schafft da der Webservice-Helper [nachfolgend WSH genannt] von jool.nl. Der WSH nimmt einem jegliche Arbeit ab, um Klassen und Objekte über SOAP bereitzustellen.Zusätzlich generiert der WSH automatisch WSDL-Dateien. Diese WSDL’s können dann, wie gesagt zum generieren von Clients in beliebigen Sprachen benutzt werden.
Also den WSH herunterladen und entpacken. Standardmäßig kann der WSH auf Klassen zugreifen die in den folgenden Unterordnern liegen:
- lib/data_objects/Klassenname.class.php
- lib/soap/Klassenname.class.php
- lib/Klassenname.class.php
Der Dateiname muss sich aus dem Klassennamen und “.class.php” zusammensetzten. Es ist jedoch auch möglich, Klassen aus anderen Ordnern bereitzusetellen. Dazu muss die Autoload-Funktion in der common.php angepasst werden.
-
/** autoload functie voor PHP5 */
-
function __autoload($classname) {
-
include("lib/data_objects/$classname.class.php");
-
include("lib/soap/$classname.class.php");
-
include("lib/$classname.class.php");
-
}
Die dort definierten Suchpfade und auch Dateinamen (.class.php) können nach belieben geändert werden. Ist der Zugriff konfiguriert, müssen die Klassen noch in der config.php freigegeben werden.
config.php
-
/* All the allowed webservice classes */
-
"BeispielKlasse",
-
"TestKlasse",
-
"Klasse"
-
);
-
-
/* The classmap associative array. When you want to allow objects as a parameter for
-
* your webservice method. ie. saveObject($object). By default $object will now be
-
* a stdClass, but when you add a classname defined in the type description in the @param
-
* documentation tag and add your class to the classmap below, the object will be of the
-
* given type. Requires PHP 5.0.3+
-
*/
-
"TestDatentyp" => "TestDatentyp"
-
);
Alle Klassen, die über SOAP betreitgestellt werden sollen müssen im Array $WSClasses aufgeführt werden. Damit wird sichergestellt, dass über die autoload Funktion keine ungewollten Dateien aufgerufen werden. Objekte bzw. strukturierte Datentypen, die als Paramer oder Rückgabewert einer Funktion genutzt werden, sollten noch im Array $WSStructures aufgeführt werden, damit man einen typisierten Austausch dieser Daten realisieren kann.
Typisierte Daten in PHP?! Ja genau. Damit die ganze Geschichte funktioniert muss der PHP Code Dokumentiert/Typisiert werden. Die Syntax der Dokumentation ist analog der von phpDocumentor, jedoch wird nur ein Teil der Schlüsselwörter benutzt. Jeder Parameter und der Rückgabewert einer Methode muss Typisiert werden. Das geschieht durch die Schlüsselwörter @param und @return um Doc-Block (/** */). Dazu ein kleines Beispiel:
BeispielKlasse.class.php
-
<?php
-
-
/**
-
* Beispiel einer Dokumentierten Klasse
-
*/
-
class BeispielKlasse{
-
-
/**
-
* Funktion mit mehreren Parametern und ohne Rückgabewerte
-
* Aufbau: @return datentyp|void
-
* Aufbau: @param datentyp $parametername Beschreibung
-
* @return void
-
* @param sting $text Ein übergebener String
-
* @param int $number Ein Integer
-
* @param boolean $something Ein boolean-Wahrheitswert
-
*
-
*/
-
public function foo($text, $number, $something) {
-
}
-
-
/**
-
* Funktion mit einfachem Rückgabewert
-
* @return string
-
*/
-
public function helloWorld() {
-
return "Hallo Welt";
-
}
-
-
/**
-
* Funktion die ein Array eines komplexen Datentyps zurückgibt
-
* @return TestDatentyp[]
-
*/
-
public function helloWorld() {
-
$objects[] = new TestDatentyp();
-
$objects[] = new TestDatentyp();
-
$objects[] = new TestDatentyp();
-
$objects[] = new TestDatentyp();
-
return $objects;
-
}
-
}
-
?>
-
-
Natürlich muss der genutzte Datentyp "TestDatentyp" auch definiert und ebenfalls typisiert werden:
TestDatentyp.class.php
-
<?php
-
-
/**
-
* Beispiel eines strukturierten Datentyps mit zwei Attributen.
-
*/
-
class TestDatentyp{
-
/**
-
* Name einer Person
-
* @var string
-
*/
-
public $name;
-
-
/**
-
* Alter einer Person
-
* @var int
-
*/
-
public $age;
-
-
/**
-
* Geschlecht einer Person
-
* @var boolean
-
*/
-
public $gender;
-
-
/**
-
* Name einer Person
-
* @var string
-
*/
-
public $name;
-
-
//…weitere, auch strukturierte Attribute / Funktionen möglich
-
}
-
?>
Sind alle Klassen geschrieben ist der WebService fertig. Denn der WSH sorgt nun dafür, dass alle Methoden, die public sind, über SOAP bereit gestellt werden. Die passende WSDL zum WebService gibts automatisch dazu. Unter folgendem Pfad kann man die WDSL beziehen:
http://deinserver/service.php?class=BeispielKlasse&wsdl
Mit dieser WSDL-Datei kann man nun auf einfachste Weise Client-Stubs generieren. Ein Tutorial dazu werde ich die Tage mal verfassen.
Bei der Arbeit mit diesem PHP WebService wird man auf zwei größere Hürden stoßen:
- Persistenz
- Codeänderungen
Zu 1: Die PHP-SOAP-Engine kennt zwei Persistenz-Modi: SOAP_PERSISTENCE_SESSION und SOAP_PERSISTENCE_REQUEST. Der SOAP_PERSISTENCE_SESSION-Modus ist der schönere von beiden
, PHP-Objekte werden mit all Ihren Attributen in einer Session gespeichert und sind somit über mehrere Aufrufe persistent. Da PHP Cookies nutzt um die Session-ID an den Client zu übermitteln, muss sichergestellt sein, dass der SOAP-Client dies auch unterstützt.
Der SOAP_PERSISTENCE_REQUEST-Modus hingegen deaktiviert die Persistenz und versetzt den WebService in den Amnesie-Modus ![]()
Leider ist die Persistenz im WSH standardmäßig deaktiviert. Um die szu ändern muss folgende Codezeile in der service.php ersetzt werden:
-
$WSHelper->setPersistence(SOAP_PERSISTENCE_REQUEST);
ersetzten durch
-
$WSHelper->setPersistence(SOAP_PERSISTENCE_SESSION);
Zu 2: Damit die ganze WebService Sache einigermaßen performant bleibt, arbeiten sowohl der WSH alsauch die nativen PHP-Methoden mit Caches. Damit äußere Strukturänderungen an den über SOAP bereitgestellten Klassen angewandt werdem müssen der WSDL-Cache und der PHP-Cache gelöscht werden. Die WSDL-Dateien befinden sich im Unterordner ‘wsdl’ vom WSH. Bei geändertem Code einfach alle Datien löschen, damit diese neu generiert werden können. Dazu sollte man noch den WSDL-Cache von PHP löschen. Dieser befindet sich im tmp-Ordner des Servers (/tmp). Alle Dateien die mit ‘wsdl-’ beginnen löschen – dann klappts auch mit den Änderungen
In diesem Sinne, viel Erfolg. Fragen bitte als Kommentar posten!

April 27th, 2009 at 20:12
What are the native types that WSH can use to generate the WSDL? So far I’ve seen:
@var string
@var int
@var boolean
What about “@var date”? Perhaps this isn’t included because of different binary representations of date? Is it simply safer to use @var string?
Any help really appreciated – thanks
April 27th, 2009 at 20:32
Hey Scott,
I only used string, int and booloean so far, but I am sure there is no native date type. You could exchange a date over a unix-timestamp (int) or build your own one. This could looke like:
class date{ @var int public $day; @var int public $month; @var int public $year; }Februar 4th, 2010 at 15:52
hi,
ich beschäftige mich auch grad mit webservices via php.
Soap ist echt klasse.
Ich wollt jetzt gern mit der Session-Variante arbeiten.
Aber ganz versteh ich das nicht.
Gerade der Teil mit dem Cookie setzte und wiederherstellen der Session wäre interessant, doch dieser fehlt hier total.
Das mit setPercistence steht in jedem tut, aber das was man braucht um die session erfolgreich auf dem server fortzusetzten fehlt immer.
Wäre schön hier etwas dazu zu finden
GC
Februar 11th, 2010 at 17:50
Moin Christian,
wenn der Client im Cookie die PHP-Session-ID wieder mitschickt, dann musst du auf Server-Seite nichts machen.
Leider musst du selber dafür sorgen, dass alle persistenten Werte in $_SESSION[] abgelegt werden, deine Objekte sind nicht automatisch persistent verfügbar.
Um ganze Objekte über eine Sitzung hinweg zu erhalten müssen diese meines Wissens nach serialisiert und in $_SESSION abgelegt werden:
http://de.php.net/manual/en/language.oop5.serialization.php
MfG
Mai 4th, 2010 at 02:07
Hallo,
ich programmiere seit geraumer Zeit an einer SOAP-Schnittstelle.
Klappt auch alles perfekt – nur will ich jetzt gern aus einer DB
mehrere Datensätze auslesen und per XML wieder zurückgeben.
Aaaaber … das klappt nicht so ganz wie ich will.
per XML erhalte ich:
Array
Stehen in ‘Array’ die übergebenen Werte oder habe ich etwas falsch
gecoded?
Bin grad am verzweifeln…eigentlich sollte doch in XML jeder Wert
einzeln und sichtbar übergeben werden.
Ich meine so wies da oben steht isses falsch…
Bitte um Hilfe….
LG ANdré
Mai 4th, 2010 at 08:36
Guten Morgen André,
kann es sein dass du versuchst ein zweidimensionales Array zu übermitteln? Quasi daten[zeilen][spalten]? Das klappt nach meiner Erfahrung nicht mit WS-Helper.
Du musst dir für die Spalten einen eigenen Datentyp bauen.
class MyDatatype{
public col1; //Daten der ersten Spalte
public col2; //der zweiten
public col3; //...
public col4;
...
}
Wenn das soweit ist, dann ein Array von dem Datentyp mit SOAP übermitteln:
MyDatatype[rows]
Das hat bei mir hingehauen. Es dürfen keine mehrdimensionalen Arrays benutzt werden.
lg
Mai 4th, 2010 at 09:32
Hallo gk,
vielen Dank für die schnelle Antwort.
Werde das so probieren.
Der Datentyp muss dann aber noch in der config.php angegeben
werden oder?
LG André
Mai 21st, 2010 at 23:20
Hallo,
wie kann man die Performance des WSDL steigern?
Ich lade per SOAP Bilder hoch und möchte dies beschleunigen.
Die Bilder sind derzeit ca. 150 KB groß.
Habt ihr eine Idee?
LG André
Mai 25th, 2010 at 12:55
Schnellere DSL-Leitung?! Nein Scherz bei Seite. Ideen wären Bilder per FTP hochladen und über SOAP IDs übermitteln oder den Datenstrom des Bildes vorher durch eine Kompression jagen. Beispiel: http://de3.php.net/manual/en/function.bzcompress.php
MfG
gk
Juli 26th, 2010 at 19:39
Hallo
Ich baue gerade an einer SOAP-API und verwende den Webservice Helper 1.5
Leider bin ich auf das problem gestoßen, dass ich kein Array als return Wert liefern kann. Wenn ich versuche z.B array() als datentyp an zu geben, bekomme ich die Fehlermeldung:
Error creating WSDL document:Error creating WSDL: no class found with the name ” / : , so how should we know the structure for this datatype?
Und generell vermiesse ich einen Datentyp wie Mixed oder Anytype. Denn es kommt vor, dass abhängig von Parametern die Funktion verschiedene Sachen ausspuckt.
Hat jemand einen Rat? Denn ich verstehe nicht ganz, wie man seinen eigenen Datentyp für den WSH macht. Ich habs versucht, er hat ihn aber als Return nicht angenommen.
MfG NBZ4live