PHP: Ein erweiterter SOAP-Server

Ich möchte einen Lösungsweg beschreiben, der aus meiner praktischen Arbeit entstanden ist und so nicht im Internet in einer geschlossenen Dokumentation zu finden war. Da es kein Betriebsgeheimnis ist, hoffe ich ein gutes Werk zu tun.

Normalerweise besteht ein SOAP-Server in PHP im Kern aus drei Zeilen:

<?php
try {
     $server = new SoapServer($meine_wsdl_url);
     $server->setClass('meine_klasse_mit_funktionen');
     $server->handle();
} catch(SoapFault $e) {
     echo "Fehler SOAP-Server: $e";
}

class meine_klasse_mit_funktionen {

    public function f1($object1) {
        return $object1->wert1;
        // wert1 wird vom Client der Gegenstelle empfangen
    }
}
?>

Zum eigentlichen Server, der mit handle() endet, kommt eine Klasse ‚meine_klasse_mit_funktionen‘, die die benötigten Funktionen enthält, wie sie auch im ggf. vorhandenen WSDL-File definiert sind und die nicht instantiiert wird. Die Funktionen wie f1($object1) werden vom Client der Gegenstelle aufgerufen, was hier nicht behandelt werden soll.

Mein Problem war nun, dass ich noch nie was mit SOAP zu tun hatte und außerdem der Auftraggeber seine diesbezüglichen Schnittstellen nicht für den Anfänger dokumentiert hat. Besonders einige Eigenheiten des verlangten XML-Headers machten mir Probleme. Also musste ich nach einer Lösung dafür suchen, wie ich die gesamte Nachricht vom Client des Auftraggebers zunächst mal sichtbar machen konnte. Ich sah immer nur das Ergebnis (oder besser gesagt keins, denn es funktionierte lange nichts…), aber „dazwischen“ konnte ich nichts sehen.

Die Lösung ist recht einfach, war aber für mich eher ein Zufallsfund. Mittels

$xmlstring = file_get_contents('php://input');

hat man die gesamte empfangene Zeichenkette in der Variable $xmlstring. Diese kann ich in eine Date test.xml schreiben und vom Opera-Browser aufrufen. Nebenbei: Firefox ist dafür ungeeignet, denn der interpretiert die vorkommenden Namespaces als nicht erkennbar und schreibt sie nicht hin! Jetzt konnte ich zumindest schon mal sehen, was bei mir ankommt.

Nun war es noch nötig, einzelne Attribute und deren Werte  auszulesen. Eine Hürde dabei war, dass alle Attribute an verschiedene Namespaces geknüpft sind. Das verhindert nämlich das einfache Auslesen als einfaches XML-Element, wie es zum Beispiel hier gemacht wird. Meine Lösung sieht schematisch wie folgt aus:

$xml = new SimpleXMLElement($xmlstring);
$xml->registerXPathNamespace('wsse', $mein_security_namespace);
$attribut_wert = $xml->xpath('//wsse:username');

Damit kann ich auf jedes Element samt Namespace zugreifen und vielleicht eine Abfrage der Anmeldedaten realisieren.

Insgesamt kommt dabei folgendes als grobe Vorlage heraus:

<?php

$xmlstring = file_get_contents('php://input');

$xml = new SimpleXMLElement($xmlstring);
$xml->registerXPathNamespace('wsse', $mein_security_namespace);
$attribut_wert = $xml->xpath('//wsse:username');

if('MaxMustermann' == $attribut_wert) {

  try {
    $server = new SoapServer($meine_wsdl_url);
    $server->setClass('meine_klasse_mit_funktionen');
    $server->handle();
  } catch(SoapFault $e) {
    echo "Fehler SOAP-Server: $e";
  }
} // if

class meine_klasse_mit_funktionen {
  public function f1($object1) {
    return $object1->wert1;
    // wert1 wird vom Client der Gegenstelle empfangen    
  }
}
?>

Ich hoffe, es kann dem einen oder anderen helfen. Kommentare sind ausdrücklich erwünscht 🙂 !