Créer un web service en PHP
Les services web fournissent un moyen simple de faire communiquer les applications. Au contraire de systèmes propriétaires tels que Corba ou RMI il permettent (au moins théoriquement) de faire communiquer des applications hétérogènes.
PHP5 fourni une extension SOAP en natif qui permet de mettre en place un web service très simplement.
Pour l’exemple, nous allons mettre en place un service qui permet des clients dans une base de données située sur le serveur (base clients de l’entreprise) serveur A. Nous accéderons à ce service depuis un client situé par exemple dans le back-office du site web hébergé sur un autre serveur, serveur B.
Le service sera comportera les éléments suivant :
- code serveur sur le serveur A (customers.php)
- fichier WSDL sur le serveur A (customers.wsdl)
- code client sur le serveur B (customers_search.php)
Le principe même d’un service web est d’assurer une communication entre 2 machines, un serveur et un (ou plusieurs) client(s).
Le serveur est implémenté de la manière suivante dans le fichier customers.php :
<?php
class Customers{
function search($keywords){
/* on remplacera le code suivant par une recherche des données dans la base */
return array(
array('id'=>1, 'first_name'=>'bob', 'bob'),
array('id'=>2, 'first_name'=>'bill', 'bill')
);
}
}
$wsdl = 'customers.wsdl';
$server = new SoapServer($wsdl);
$server->setClass('Customers');
$server->handle();
?>
Le fichier WSDL est un fichier XML, il a pour rôle de décrire le service : quelles méthodes sont accessibles, quelle données sont attendues en entrée, quelles données sont retournées, etc. Le but du jeu étant de pouvoir rechercher un service web et que sa description soit compréhensible par une machine.
Implémentation du fichier WSDL :
<?xml version='1.0' encoding='UTF-8'?>
<!-- WSDL file generated by Zend Studio. -->
<definitions name="customers" targetNamespace="urn:customers"
xmlns:typens="urn:customers"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<schema xmlns="http://www.w3.org/2000/10/XMLSchema">
<complexType name="ArrayOfCustomers">
<complexContent>
<restriction base="soapenc:Array"/>
</complexContent>
</complexType>
</schema>
</types>
<message name="search">
<part name="keywords" type="xsd:string"/>
</message>
<message name="searchResponse">
<part name="searchReturn" type="ArrayOfCustomers"/>
</message>
<portType name="CustomersPortType">
<operation name="search">
<input message="typens:search"/>
<output message="typens:searchResponse"/>
</operation>
</portType>
<binding name="CustomersBinding" type="typens:CustomersPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="search">
<soap:operation soapAction="urn:CustomersAction"/>
<input>
<soap:body namespace="urn:customers" use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body namespace="urn:customers" use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="customersService">
<port name="CustomersPort" binding="typens:CustomersBinding">
<soap:address location="http://serveur-a/tests/web-services/customers.php"/>
</port>
</service>
</definitions>
Ce fichier a été généré avec Zend Studio puis modifié légèrement. Créer les fichiers WSDL à la main serait très laborieux.
Implémentation du client, customers_search.php sur le serveur B :
$wsdl = 'http://serveur-a/tests/web-services/customers.wsdl';
$options = array(
'compression'=>true,
'exceptions'=>false,
'trace'=>true
);
$serv_customers = new SoapClient($wsdl, $options);
$customers_arr = $serv_customers->search('bob');
if (is_soap_fault($customers_arr)) {
echo 'fault : ';
var_dump($serv_customers->__getLastRequest());
var_dump($serv_customers->__getLastRequestHeaders());
} else {
echo '<pre>'.var_export($customers_arr, true).'</pre>';
}
?>
En théorie, tout marche correctement. Dans la pratique, rien ne marche jamais. Donc si ça ne fonctionne pas :
- Appeler le fichier WSDL pour vérifier que c’est du XML bien formé (IE signalera une erreur si le XML est mal formé)
- Tester le serveur indépendemment
L’extension SOAP met les fichier WSDL en cache par défaut. Donc, si vous modifiez ce fichier, il faut supprimer la version en cache sur le “serveur client” (serveur B). Le comportement du cache de SOAP peut être modifié dans la section SOAP du php.ini.
L’appel d’un web service est une opération couteuse. Il vaut mieux grouper les appels plutôt que d’appeler un web service plusieurs fois dans un même traitement.
Quelques autres questions à creuser :
- sécuriser notre service web (sinon la terre entiere a potentiellement accès au SI de l’entreprise)
- réaliser un web service qui supporte les sessions (statefull)
N’hésitez pas à laisser un message si quelque chose ne semble pas clair.

3 janvier 2008 at 8:02
[…] Réflexe - le blog a work in progess « Créer un web service en PHP […]
10 mars 2008 at 20:51
[…] Pour rappel sur la création d’un service web. […]