Web services Zend Framework : sans MVC et sans WSDL

Comment profiter des fonctions web services du Zend Framework (ZF) dans une vieille application PHP sans MVC et sans trop coder ?

Comme vu dans un post précédent, on peut tout à fait utiliser le framework Zend sans architecture MVC. Ce qui est pratique si l’on souhaite améliorer une application PHP existante sans tout refaire. On pourrait vouloir exposer les fonctions de l’application via des Web Services. Mais avec les souhaits suivants :

  • Profiter de la présence du Zend Framework.
  • Minimum de code à écrire.
  • Pas de WSDL à faire à la main.

Il existe des frameworks de gestion des Webservices (le plus célébre étant NuSOAP) qui gèrent ces aspects et proposent des services supplémentaires qui ne seront pas offerts par le ZF avant la version 2.0 (SOAP Header, types complexes…). PHP propose même des fonctions natives, mais elles marchotent plus ou moins et elles ont besoin d’une WSDL en entrée (dans la version courante 5.3.6, la documentation dit que non, mais dans la pratique cela ne fonctionne pas).

Un exemple concret

Dans les cas les plus simples, voyons comment faire un Webservice d’authentification d’un utilisateur s’appuyant sur les fonctions existantes de l’application. Voici le comportement (pour un site hébergé en local, les sources proposées étant dans le sous-répertoire services) :

  • L’URL http://127.0.0.1/services/User.php?wsdl produit la WSDL complète.
  • L’URL http://127.0.0.1/services/User.php permet de faire une requête SOAP. Dans le cas de l’exemple, la connexion d’un utilisateur à l’application.

La classe de base d’un Web Service

Voici la classe User. les fichiers du sous-répertoire api contiennent les fonctions de mon application PHP existante. Et le code de web_services_api.php est donné plus loin (c’est le moteur des WebServices de notre application). Le framework Zend utilise les commentaires du code au format PHPDocumentor afin de comprendre les types à déclarer dans la WSDL et à ajouter la description des actions SOAP. C’est pour cela qu’il est très important de documenter complètement chacune des méthodes exposées par des Web Services.

<?php
include "web_services_api.php";
include "../api/user_api.php";
include "../api/authentication_api.php";

class User {
  /**
    * Attempt a connection with given user credentials
    * @param string $p_username Username
    * @param string $p_password Password
    * @return boolean is authetication OK
    */
   function connect($p_username, $p_password)
   {
     return auth_verify_login($p_username, $p_password);
   }
}
handle_ws_request('User');?>

Code du gestionnaire de Webservice

Voici le code du gestionnaire de Webservices (web_services_api.php) de mon application et plusieurs remarques dans l’ordre de lecture du code :

  1. Le chargement du framework Zend est expliqué en détail dans ce billet.
  2. On teste la présence du paramètre wsdl dans l’URL entrante. Le cas échéant, on fabrique à la volée la WSDL correspondant à la classe User (le travail est effectué par la classe Zend_Soap_AutoDiscover).
  3. Dans le cas d’une requête entrante, il y a une superbe astuce :
    • La ligne Zend_Soap_Server($url); invoque la page elle-même avec le paramètre wsdl (soit http://127.0.0.1/services/User.php?wsdl). Notez que la construction de la variable $url permet de gérer tous les cas de figure (HTTP ou HTTPS; autre port que le port 80, etc.).
    • Une fois le gestionnaire de Web Services du ZF est chargé, on peut traiter la requête SOAP proprement dite.

Vous noterez que dans le cas de ce fichier comme pour tous les autres fichiers inclus, il n’y a pas de balise PHP fermante ?>. Dans le cas contraire (et si un seul des fichiers inclus en comportement), une ligne blanche commence le fichier WSDL retourné : ce qui rend invalide.

<?php
 //Include and load Zend framework
 set_include_path(get_include_path().
         PATH_SEPARATOR.
         realpath(dirname(__FILE__) . '/../library'));
 require_once '../library/Zend/Loader/Autoloader.php';
 $zend_autoloader = Zend_Loader_Autoloader::getInstance();

 include "../api/db_api.php";

/**
 * Handle incoming webservices request (whether WSDL or SOAPAction)
 * @param string $class Class name
 */
 function handle_ws_request($class) {
     if (isset($_GET['wsdl'])) {
         $server = new Zend_Soap_AutoDiscover();
         $server->setClass($class);
         $server->handle();
     } else {
         $protocol = $_SERVER['HTTPS'] ? "https" : "http";
         $url = $protocol . '://' . $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'] .
                 $_SERVER['PHP_SELF'] . '?' . 'wsdl';
         $server = new Zend_Soap_Server($url);
         $server->setClass($class);
         $server->handle();
     }
 }

Si cet article vous a plu, fouillez un peu dans mon blog ou revenez me voir parce que je poste de temps en temps ce genre d’astuce ou d’explication. Ou jetez un coup d’œil à l’application SQA/TCM qui est dans un cas que l’on rencontrer dans le milieu professionnel : rafraîchir et moderniser une vieille application PHP sans trop dépenser ni tout refaire.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *