WordPress, PHP, JavaScript, Web 2.0, Gaming, Fotografie, Piratenpartei, Schießsport, Privates

SOAP Dienste programmieren mit PHP

Di 10 Nov. 09 # Permalink

Wer für seine eigene Anwendung eine Web-API anbieten möchte, hat vielfältige Möglichkeiten dies zu realisieren. Per einfachem HTTP GET oder POST Request und einer Rückgabe als XML/RSS/CSV/JSON/whatever, oder – was ich etwas eleganter finde – per SOAP. Dabei ist das Entwickeln eines eigenen SOAP Dienstes mit PHP gar nicht so kompliziert, wie vielleicht vermutet. Zumindest finde ich SOAP schöner als die weitere Alternative XML-RPC.

Aber nun zur Definition von SOAP (Quelle: Wikipedia): SOAP (ursprünglich für Simple Object Access Protocol) ist ein Netzwerkprotokoll, mit dessen Hilfe Daten zwischen Systemen ausgetauscht und Remote Procedure Calls durchgeführt werden können. SOAP stützt sich auf andere Standards: XML zur Repräsentation der Daten und Internet-Protokolle der Transport- und Anwendungsschicht (vgl. TCP/IP-Referenzmodell) zur Übertragung der Nachrichten. Die gängigste Kombination ist SOAP über HTTP und TCP.

In der Praxis bedeutet das folgendes: In einer XML Datei (WSDL) werden Nachrichten-Typen definiert und an Operationen gebunden. Dabei gibt es Input-Nachrichten und Output-Nachrichten, sprich Übergaben und Rückgaben. Die WSDL Datei (WSDL = Web Services Description Language) wird dabei vom Client, als auch vom Server genutzt und regelt so die Kommunikation dieser beider Stellen.

Die Vorgehensweise um einen neuen Web-Service zu erstellen ist bei mir immer zuerst die WSDL zu erzeugen, danach die Operationen im Server abzubilden, um diese anschließend mit dem Client zu testen. Eine Beispiel WSDL könnte z.B. so aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="TheGeek"
	targetNamespace="http://thegeek.de/wp-soap/thegeek.wsdl"
	xmlns:tns="http://thegeek.de/wp-soap/thegeek.wsdl"
	xmlns="http://schemas.xmlsoap.org/wsdl/"
	xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">

	<!-- GET LATEST POSTS -->
	<message name="RequestGetPostsIn">
		<part name="apikey" type="xsd:string"/>
		<part name="num" type="xsd:integer"/>
	</message>
	<message name="RequestGetPostsOut">
		<part name="returncode" type="xsd:integer"/>
		<part name="error" type="xsd:string"/>
		<part name="posts" type="xsd:struct"/>
		<part name="posts_count" type="xsd:integer"/>
	</message>
	<portType name="RequestGetPosts_PortType">
		<operation name="GetPosts">
			<input message="tns:RequestGetPostsIn"/>
			<output message="tns:RequestGetPostsOut"/>
		</operation>
	</portType>
	<binding name="GetPosts_Binding" type="tns:RequestGetPosts_PortType">
		<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
		<operation name="GetPosts">
			<soap:operation soapAction="GetPosts"/>
			<input>
				<soap:body
					encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
					namespace="urn:thegeek-getpostsservice"
					use="encoded"/>
			</input>
			<output>
				<soap:body
					encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
					namespace="urn:thegeek-getpostsservice"
					use="encoded"/>
			</output>
		</operation>
	</binding>
	<service name="GetPosts_Service">
		<documentation>Return latest posts</documentation>
		<port binding="tns:GetPosts_Binding" name="GetPosts_Port">
			<soap:address location="http://thegeek.de/wp-soap/index.php"/>
		</port>
	</service>

</definitions>

Diese WSDL definiert eine einfache Funktion “GetPosts” mit einer eingehenden Nachricht und einer ausgehenden Nachricht. Für die einzelnen Felder der Nachrichten sind entsprechende Typen definiert. Nachdem die Nachrichten an die Operation “GetPosts” gebunden wurden, wird mit dieser Operation ein Soap-Service definiert. Ein Service besteht also aus einem Binding, welches wiederum aus eine Input- und/oder Output-Message besteht. Das klingt nun zugegeben ziemlich kompliziert, ist aber in der Praxis wirklich einfach nachzuvollziehen, wenn wir uns mal den Server-Quellcode zu dieser WSDL Definition ansehen.

<?php

// SOAP config array
$soap_config = array( 'encoding' => 'UTF-8' );

// Don't cache WSDL files, mandatory for development
ini_set( 'soap.wsdl_cache_enabled', '0' );

class thegeek_soapserver
{
	function __construct( $parameters )
	{

	}

	public function GetPosts( $apikey = '', $num = 10 )
	{
		if( $apikey == 'demoapikey' )
		{
			$posts = array( 	array( 'title' => 'Demo Post 1', 'body' => 'Demo content 1' ),
						array( 'title' => 'Demo Post 2', 'body' => 'Demo content 2' ),
						array( 'title' => 'Demo Post 3', 'body' => 'Demo content 3' ),
						array( 'title' => 'Demo Post 4', 'body' => 'Demo content 4' )
			);
			return array(	'return' => true,
					'error' => '',
					'posts' => $posts,
					'posts_count' => 0
			);
		}
		// API KEY FAIL
		else
		{
			return array(	'return' => false,
					'error' => 'API KEY INVALID',
					'posts' => array(),
					'posts_count' => 0
			);
		}
	}
}

// Run SOAP server
$soapserver = new SoapServer( 'http://thegeek.de/wp-soap/thegeek.wsdl', $soap_config );
$soapserver -> setClass( 'thegeek_soapserver', 'some parameters for the constructor (example only...)' );
$soapserver -> handle();

?>

Nachdem die Soap-Config für die PHP Klasse “SoapServer” definiert und das caching von WSDL Dateien per “ini_set” ausgeschaltet wurde, folgt unsere eigene Klasse, die den Web-Service abbildet. Der Konstruktor kann wie gewohnt definiert werden, auch beim Initialisieren unserer Klasse über die PHP Klasse “SoapServer”, können beliebige Parameter übergeben werden. Übrigens sind auch extends problemlos möglich.

Dann findet sich in der Klasse eine Methode, welche unseren SoapService “GetPosts” abbildet, als Übergabeparameter sind die Variablen unserer Input-Nachricht angegeben. Wie die Variablennamen in der Methode gewählt werden ist egal, aber die Methode muss genau so heißen, wie in der WSDL angegeben (soap:operation soapAction=”GetPosts”). Der Code in der Methode dient natürlich nur der Verdeutlichung, wie Rückgaben erfolgen, nämlich als assoziatives Array, welches die in der WSDL definierte Output-Nachricht abbildet.

Um unsere Server-Klasse dann zu initialisieren, wird die PHP Klasse “SoapServer” mit entsprechenden Parametern (Web-Pfad zur WSDL, SoapConfig) aufgerufen. Danach wird mit Hilfe der Methode “setClass” unsere Klasse als Handler ausgewählt und der Server letztendlich mit der Methode “handle” konstruiert.

Fehlt eigentlich nur noch ein kleiner Test-Client:

<?php

// Create new SOAP client
$soap_client = new SoapClient( 'http://thegeek.de/wp-soap/thegeek.wsdl', array( 'encoding' => 'UTF-8' ) );
if( is_object( $soap_client ) )
{
	$soap_result = $soap_client -> GetPosts( 'demoapikey', 10 );
	// Debug output
	echo "<pre>";
	print_r( $soap_result );
	echo "</pre>";
}
else	die( 'SOAP Server not available' );

?>

Der Client ist ziemlich problemlos umzusetzen: Einfach mit der PHP Klasse “SoapClient” ein Client-Objekt erzeugen (Web-Pfad zur WSDL übergeben) und die Methoden (= Operationen) wie in der WSDL definiert nutzen. Obiges Beispiel gibt folgendes aus:

Array
(
    [returncode] =>
    [error] =>
    [posts] => Array
        (
            [0] => Array
                (
                    [title] => Demo Post 1
                    [body] => Demo content 1
                )

            [1] => Array
                (
                    [title] => Demo Post 2
                    [body] => Demo content 2
                )

            [2] => Array
                (
                    [title] => Demo Post 3
                    [body] => Demo content 3
                )

            [3] => Array
                (
                    [title] => Demo Post 4
                    [body] => Demo content 4
                )

        )

    [posts_count] => 0
)

So schwierig ist das mit SOAP und PHP also nicht. Wichtig ist allerdings noch: PHP muss mit der Option “–enable-soap” kompiliert werden, um die SOAP Extension nutzen zu können. Alternativ kann aber auch das SOAP PEAR Paket genutzt oder auf die Klasse nuSoap zurückgegriffen werden.

Wer selbst mal von seinem Webspace aus testen will: http://thegeek.de/wp-soap/thegeek.wsdl

Wer Fragen hat: Comments are open.

Willst du die Kommentare dieses Beitrags verfolgen, kannst du den Kommentar Feed abonnieren. Du kannst auch selbst einen Kommentar hinzufügen, oder einen Trackback von deiner eigenen Seite senden.

3 Kommentare zu “SOAP Dienste programmieren mit PHP”

  1. jan sagt:

    Hi. Ich hab’ auch mal ein Beispiel mit NuSOAP programmiert und den Quellcode veröffentlicht:
    http://www.kammerath.net/php-und-soap.html

    Viele Grüße,

    Jan

  2. Ben sagt:

    Was ist jetzt aber generell der Vorteil von SOAP gegenüber der direkten Abarbeitung eines per POST/ GET geschickten Formulars?

    Muß das SOAP-Programm irgenwie gestartet werden und im Hintergrund ständig laufen, damit es auf Eingaben/ Anfragen warten kann?

    Mir ist der Einsatz von SOAP noch nicht so richtig klar, deshalb die Fragen. Evtl. versteh ich auch etwas komplett falsch. Ich sehe das so, dass SOAP auch nichts anderes macht, als per HTTP übertragene Daten zu verarbeiten.

    Danke
    Ben

  3. Marc sagt:

    Hallo Ben,
    SOAP hat den Vorteil, dass es eine definierte und leicht nachvollziehbare Schnittstelle ist, da die Methoden und Objekte durch eine WSDL Datei definiert werden.
    In .net z.B. kannst du einfach sagen “lade mir die WSDL” und dann wird entsprechend der WSDL Quellcode automatisiert aufgebaut, den du nur noch mit Leben füllen musst.

    Gruß,
    Marc

Hinterlasse einen Kommentar

Name (Pflichtangabe)

E-Mail, wird NIEMALSNICHT veröffentlicht! (Pflichtangabe)

Webseite

Dein Kommentar