Un Web service (servizio web), secondo la documentazione W3C, è un sistema software progettato per supportare l’ interoperabilità tra macchine che si trovano sulla stessa rete. Ha un’interfaccia descritta da un formato facilmente processabile dalle macchine: il Web Service Definition Language (WSDL), che è un formato XML.
Il Web service è un concetto astratto che deve essere implementato da un oggetto concreto (chiamato agente) che deve implementare un sistema per inviare e ricevere messaggi. Il modo in cui è implementato, e il linguaggio di programmazione utilizzato, è a completa discrezione dello sviluppatore ed è indifferente per il client che consuma i suoi servizi.
Esistono diversi tipi di web service, ma i più utilizzati sono:
- Web service di tipo REST (Representational Transfer State);
- Web service di tipo SOAP.
In questo articolo parleremo del Web service di tipo SOAP e vedremo come gestirlo attraverso il linguaggio PHP. Se si volesse invece avere più informazioni sulle differenze fra le due tipologie di web service si rimanda alla lezione Differenze tra Web service REST e SOAP della guida Rest.
Il protocollo SOAP e il Web Service Definition Language (WSDL)
SOAP è un protocollo creato per lo scambio di informazioni tra sistemi software. In passato era l’acronimo di Simple Object Access Protocol
(che denota la natura a oggetti del protocollo), ma dalla versione 1.2 dello standard il W3C ha cancellato l’acronimo.
Un messaggio SOAP è definito come un insieme di informazioni in formato XML. Un esempio di messaggio SOAP, preso dal W3C, è:
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header>
<n:alertcontrol xmlns:n="http://example.org/alertcontrol">
<n:priority>1</n:priority>
<n:expires>2001-06-22T14:00:00-05:00</n:expires>
</n:alertcontrol>
</env:Header>
<env:Body>
<m:alert xmlns:m="http://example.org/alert">
<m:msg>Pick up Mary at school at 2pm</m:msg>
</m:alert>
</env:Body>
</env:Envelope>
Come si può vedere il messaggio ha una struttura Header-Body. Solitamente l’header di un messaggio SOAP contiene le informazioni che possono servire al destinatario del messaggio, mentre il body contiene le informazioni da spedire.
Un altro elemento presente è il SOAP envelope, che rappresenta l’elemento root di ogni messaggio SOAP. È utile notare che gli elementi Header
e Body
non sono obbligatori. Un messaggio SOAP senza uno di questi elementi, o senza nessuno dei due, è perfettamente lecito. L’elemento envelope
invece è obbligatorio.
Come scritto in precedenza un Web service ha un’interfaccia descritta da un formato creato per essere facilmente leggibile dalle macchine. Questo formato è il WSDL.
Il WSDL è un formato XML utilizzato per descrivere servizi sulla rete. Viene utilizzato per permettere ai client che vogliono consumare il Web service di conoscere tutte le caratteristiche del Web service stesso.
Qui ci basta vedere gli aspetti più importanti del documento, chi invece volesse una spiegazione completa degli elementi di un file WSDL può leggere la lezione Gli elementi di un documento WSDL della Guida Web Service.
Questi sono rappresentati dagli elementi:
- types : rappresentano i tipi di dato utilizzati dal Web service. Si possono creare anche tipi di dato complessi che contengono elementi di tipo atomico (interi, stringhe, ecc.);
- message : è la serie di messaggi che il Web service manda e riceve grazie alle funzioni che mette a disposizione;
- portType : rappresenta l’elemento più importante del documento. Descrive il Web service in termini delle operazioni che può fare e dei messaggi che può scambiare con i client;
- binding : definisce il formato dei messaggi e il protocollo per le operazioni e per i messaggi definiti nell’elemento portType;
- service : raggruppa un insieme di porte (elementi
port
) ognuna collegata a un elemento binding precedentemente definito.
Il nostro primo Web service SOAP in PHP
Il PHP dalla versione 5 ha le classi e le funzioni native per interagire con un Web service SOAP. La versione attuale del PHP supporta le versioni SOAP 1.1 e 1.2 e la versione WSDL 1.1.
In particolare è stata introdotta la classe SoapServer
che permette di creare un oggetto per un Web service SOAP.
La classe ha la funzione addFunction
che permette di aggiungere una funzione all’oggetto SoapServer
, e quindi al Web service stesso. E la funzione setClass
che setta la classe che gestirà le richieste SOAP. Tutte le funzioni della classe assegnata rappresenteranno le funzioni del Web service.
Come esempio di Web service creiamo un servizio che permette all’utente di chiedere l’indirizzo internet di un motore di ricerca.
class SearchEngineWS {
function getWebUrl($name){
$engines = array(
'google' => 'www.google.it',
'yahoo' => 'www.yahoo.it'
);
return isset($engines[$name]) ? $engines[$name] : “Search Engine unknown”);
}
}
$server= new SoapServer("search_engine.wsdl");
$server->setClass("SearchEngineWS");
$server->handle();
Questo semplice codice istanzia un oggetto di tipo SoapServer
, e setta la classe SearchEngineWS
. Tutte le funzioni della classe rappresentano ora le funzioni messe a disposizione dal Web service. Le funzioni non devono essere dichiarate private
o protected
altrimenti i client non possono accedervi. È facile notare che queste funzioni potrebbero interrogare un database e ritornare valori dinamici.
Il costruttore dell’oggetto SoapServer
può riceve 2 parametri, il secondo dei quali è opzionale. Il primo rappresenta l’indirizzo del file WSDL che descrive il Web service, mentre il secondo è un array che permette di definire alcune caratteristiche del Web service: la versione SOAP supportata, l’encoding del server e l’actor uri.
Un esempio di oggetto SoapServer
può essere questo:
$server = new SoapServer("file.wsdl", array('soap_version' => SOAP_1_2));
È possibile passare il valore NULL come primo parametro. In questo caso, è necessario passare nel secondo parametro l’elemento actor uri
, che rappresenta il namespace destinazione per il Web service.
Quando definiamo un Web service WSDL (quindi con il primo parametro dell’oggetto SoapServer
non nullo), è possibile utilizzare la funzione getFunctions
per avere la lista delle funzioni definite nel file WSDL.
Infine la funzione handle
processa una richiesta SOAP e manda un messaggio di ritorno al client che l’ha richiesta.
Un WSDL per il nostro Web service
Il WSDL è un formato XML creato per essere facilmente leggibile da macchine. Questo comporta che è molto difficile per un essere umano leggere un file WSDL e interpretarlo correttamente.
Per il nostro esempio creiamo questo file (search_engine.wsdl
) e lo mettiamo nella stessa directory del Web service:
<?xml version="1.0" encoding ="utf-8"?>
<definitions
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="https://www.html.it/php_ws_soap"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="https://www.html.it/php_ws_soap">
<types>
<xs:schema targetNamespace="https://www.html.it/php_ws_soap">
<xs:element name="name" type="xs:string" />
<xs:element name="weburl" type="xs:string" />
</xs:schema>
</types>
<message name="getWebUrl">
<part name="name" type="xs:string" />
</message>
<message name="returnWebUrl">
<part name="weburl" type="xs:string" />
</message>
<portType name="WebServiceTest">
<operation name="getWebUrl">
<input message="tns:getWebUrl" />
<output message="tns:returnWebUrl" />
</operation>
</portType>
<binding name="WebServiceSOAPBinding" type="WebServiceTest">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getWebUrl">
<soap:operation soapAction="http://localhost/ws_server/SearchEngineWS.php/getWebUrl" style="rpc"/>
<input>
<soap:body use="encoded" namespace="https://www.html.it/php_ws_soap" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded" namespace="https://www.html.it/php_ws_soap" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="GetWebUrl">
<port name="WebUrl" binding="tns:WebServiceSOAPBinding">
<soap:address location="http://localhost/ws_server/SearchEngineWS.php"/>
</port>
</service>
</definitions>
Sebbene di difficile comprensione, si può notare la presenza dei due tipi di dato string, dei due messaggi che il Web service gestirà (uno in input e l’altro in output) e dell’operazione getWebUrl
che rappresenta la funzione messa a disposizione dal Web service.
Il file all’indirizzo http://localhost/ws_server/SearchEngineWS.php è il file del nostro Web service dove è stata definita la classe SearchEngineWS
con il metodo getWebUrl
.
Un semplice client SOAP in PHP
Con il server SOAP definito in precedenza, possiamo scrivere un semplice client che chiede al Web service l’indirizzo internet di un motore di ricerca. PHP 5 mette a disposizione l’oggetto SoapClient
per definire un client.
try {
$gsearch = new SoapClient('http://localhost/ws_server/search_engine.wsdl');
print_r($gsearch->getWebUrl('google'));
} catch (SoapFault $e) {
print_r($e);
}
Anche il costruttore dell’oggetto SoapClient
può ricevere due parametri, il secondo dei quali, un array di opzioni, è opzionale. Il primo rappresenta l’indirizzo di un file WSDL del Web service.
L’oggetto SoapClient
ha definita una funzione __soapCall
che può essere utilizzata per chiamare una funzione del Web service. Solitamente è utile nei Web service non WSDL, quando non si può utilizzare la funzione __getFunctions
(la stessa funzione nell’oggetto SoapServer
è definita senza i due trattini bassi iniziali) per ottenere la lista delle funzioni definite nel Web service.
La gestione degli errori mostra l’oggetto SoapFault
che non è altro che una classe che eredita da Exception
.
Se chiamiamo questo file in un browser otteniamo come risposta: www.google.it.