Web services en PHP avec XML-RPC

Qu'est-ce qu'un "web service"?

Un "service web" est une application accessible au travers des protocoles réseau et Internet actuels. Il ne s'agit plus d'une application destinée directement à l'utilisateur humain (comme une page web classique) mais d'un application destinée à éxécuter certaines taches et à communiquer avec d'autres applications disponibles ailleurs sur le réseau (local ou Internet). L'originalité vient du fait que l'interface de ce service (la façon dont il communique avec les autres applications) est définie de manière standardisée et ouverte. En fait, l'interface d'un service web repose uniquement sur des messages qu'elle peut envoyer et recevoir. Cela signifie qu'un service web peut être développé dans n'importe quel langage, sur n'importe quelle plateforme, à condition qu'il soit en mesure de traiter et d'envoyer des messages codés selon un format précis, convenu d'avance et supporté de manière uniforme par les différents acteurs.
 
 
 

En quoi les web services peuvent-ils être utiles?

Supposons que vous ayez besoin de faire bénéficier vos visiteurs d'un répertoire téléphonique. Plusieurs solutions s'offrent à vous: (1) vous développez une application de répertoire téléphonique. Cela prend du temps, des moyens, cela ne corresponds pas à votre métier. (2) vous utilisez une offre logicielle commerciale. Cela va couter cher, prendra nécessairement du temps à installer et à intégrer dans votre système. Dans les deux cas, cela nécessite la présence d'un système de gestion de base de données. (3) vous faites appel à un service web de répertoire téléphonique. Cela vous permet de stocker et de récupérer vos numéros de téléphone sur un serveur distant. La standardisation de l'interface fait en sorte que de très nombreux logiciels peuvent accéder à ces services.
 

Quels sont les problèmes posés par les services web?

Ils sont de plusieurs ordres :
- identification des acteurs : supposons que le stockage d'un nouveau numéro vous coute 10 centimes. Il faut donc empecher que n'importe qui envoie de nouveau numéros au service web en se faisant passer pour vous.
- sécurisation des transmissions : les données concernant vos contacts téléphoniques vont circuler sur le réseau (Internet et local). Si celles-ci sont sensibles, il est nécessaire de sécuriser vos transmissions (par exemple au moyen d'un tunnel SSL)
- confiance en ces acteurs : les fournisseurs du service web ont accès à tous vos contacts téléphoniques, puisque ceux-ci sont stockés sur leur serveur; est-ce que ces fournisseurs sont dignes de confiance?
- disponibilités des serveurs sur lesquels sont stockés les services web : en cas d'incident technique, de crash de la machine serveur, le services web concerné risque d'être indisponible. Que faire pour assurer une continuité de service?
- gestion de la notion de transaction : une procédure éxécutée par un service web peut comprendre une série de sous-procédures. Si l'une d'entre elles ne réussit pas, il ne faut bien entendu pas forcément que le service soit facturé...
 
 

Techniquement, sur quoi reposent les "web services"?

Les services web sont basés sur des appels de procédures distantes (Remote Procedure Calls). Un client envoie un message à un programme serveur, en lui demandant d'éxécuter une procédure bien précise, avec des paramètres spécifiés dans le message. La nouveauté vient du fait que les messages sont codés au format XML, ce qui il existe de nombreux outils permettant de traiter le XML (parseurs).  Il est même possible de transformer un format XML en d'autres formats, XML ou non.
Le transport des messages se fait au moyen de HTTP pour les messages synchrones et de SMTP pour les messages asynchrones.
 
 
 

Création et deploiement d'un "web service" simple grâce à XML-RPC

Nous vous proposons ici de batir votre premier "web service". Il s'agit d'un répertoire téléphonique simple, doté de capacités d'authentification basiques. Pour stocker les informations (numéros de téléphone), nous utiliserons une base de données MySQL.

Par ailleurs, pour mettre en place ce web service et y acceder, nous utiliserons une bibliothèque de fonctions PHP implémentant le protocole XML-RPC. XML-RPC est un format mis au point par Userland Software permettant d'effectuer des appels de procédure distantes via XML. Cette bibliothèque est disponible à l'adresse http://www.xmlrpc.com

Dans un premier temps, nous allons créer la table et y ajouter un numéro (le mien) :

create table repertoire (nom varchar(30), telephone varchar(15));
insert into repertoire values ("Olivier Elemento", "0615025055");


Puis nous allons créer la partie serveur du web service. Ce web service contient deux fonctions : addPhoneNumber() qui permet de stocker un numéro et  getPhoneNumber($params) qui permet de récupérer un numéro à partir d'un nom spécifié.

<?

include("xmlrpc.inc");

include("xmlrpcs.inc");

include("db.inc.php");

function getPhoneNumber($params) {

 $nameObj = $params->getParam(0);

 $name = $nameObj->scalarval();

 

 $query = "SELECT nom, telephone FROM repertoire WHERE nom LIKE '%$name%'";

 $result_id = mysql_query($query);

 while (list($nom, $telephone) = mysql_fetch_array($result_id)) {

  $tableau[$nom] = "$telephone";

 }

 

 return new xmlrpcresp(xmlrpc_encode($tableau));

}

function addPhoneNumber($params) {

 $nameObj = $params->getParam(0);

 $teleObj = $params->getParam(1);

 

 $nom = $nameObj->scalarval();

 $tel = $teleObj->scalarval();

 $query = "INSERT INTO repertoire VALUES ('$nom', '$tel')";

 $result_id = mysql_query($query);

 if ($result_id)

  return new xmlrpcresp(new xmlrpcval(1, 'int'));

 else

  return new xmlrpcresp(new xmlrpcval(0, 'int'));

}

$s = new xmlrpc_server(array("getPhoneNumber" => array("function" => "getPhoneNumber"), "addPhoneNumber" => array("function" => "addPhoneNumber")));

?>
 

 
 
 
 
 

Authentification

Maintenant que nous avons en web service fonctionnel, il va être nécessaire d'en restreindre l'accés. Pour ce faire, nous utiliserons une authentification HTTP classique et simple à mettre en oeuvre. L'authentification HTTP permet de restreindre l'accès d'un répertoire (et de ses sous-répertoires) aux visiteurs fournissant nom d'utilisateur et mot de passe valides.

1ère étape : on crée d'abord un fichier nommé .htaccess, ayant la forme suivante :

AuthUserFile /chemin/vers/.htpasswd
AuthGroupFile /dev/null
AuthName "ma zone secrète"
AuthType Basic
<Limit GET POST>
require valid-user
</Limit>
2eme étape : on crée un fichier nommé .htpasswd avec la commande .htpasswd, en lui spécifiant un nom d'utilisateur. htpasswd vous demande alors d'entrer un mot de passe.
htpasswd -c .htpasswd olly

Taper toto. Cela créera le fichier .htpasswd puis y stockera le
mot de passe de "olly" sous forme cryptée. Si le fichier existe
déjà et que l'on souhaite lui ajouter un utilsateur, on tapera:
htpasswd .htpasswd pierrot
Pour supprimer un utilisateur, il suffit d'ouvrir le fichier avec un éditeur et d'y supprimer la ligne faisant réference à l'utilisateur.
 
 

Accés à ce web service.


Maintenant que nous avons créé un service web, il va falloir y accéder. Pour cela il faut créer un "client", cad à dire un programme qui va invoquer les fonctions du service web distant et en récuperer les résultats.

<html>

<?

include("xmlrpc.inc");

 

/** crée un nouveau client **/

$c=new xmlrpc_client("/~olly/xmlrpc/repertoire_serveur.php", "localhost", 80);



/** user et mot de passe permettant d'accéder au service web distant **/

$c->setCredentials("olly", "toto");

/** crée un nouveau message : ajoute un numéro de téléphone **/

$ajout=new xmlrpcmsg('addPhoneNumber', array(new xmlrpcval("Olivier Jones", "string"), new xmlrpcval("65765544333", "string")));

/** envoie le message et stocke le retour dans $r **/

$r=$c->send($ajout);

$v=$r->value();

if (!$r->faultCode()) {

 $arr = $v->scalarval();

 print $arr;

 



 

} else {

 print "Fault: ";

        print "Code: " . $r->faultCode() . " Reason '" .$r->faultString()."'<BR>";

 print "<HR>I got this value back<BR><PRE>" .

            htmlentities($r->serialize()). "</PRE><HR>\n";

}





$f=new xmlrpcmsg('getPhoneNumber', array(new xmlrpcval("Olivier", "string")));

//$c->setDebug(1);

$c->setCredentials("olly", "batman");

$r=$c->send($f);

//$c->setDebug(1);

$v=$r->value();

if (!$r->faultCode()) {

 $arr = xmlrpc_decode($v);

 //print $arr;

 

 while (list($key, $val) = each($arr)) {

  print "<li>$key => $val";

 }

 

} else {

 print "Fault: ";

        print "Code: " . $r->faultCode() . " Reason '" .$r->faultString()."'<BR>";

 print "<HR>I got this value back<BR><PRE>" .

            htmlentities($r->serialize()). "</PRE><HR>\n";

}







?>
 

 
 
 
 

Ressources

  • XML-RPC Library for Java