Serveur SOAP avec PHP5



«  ♥  »


Posted on May 28, 2011 | Published in PHP Tuts

Nous allons voir dans ce tutoriel comment coder un serveur / client SOAP, en utilisant l’extension SOAP native de PHP5. Pour cela nous allons avoir besoin de développer les parties suivantes:

  1. Un fichier WSDL qui va contenir la définition des différentes méthodes offertes par notre serveur de services (voir),
  2. Une classe qui représente l’API de vos services (voir)
  3. Un fichier pour le serveur SOAP (voir),
  4. Un fichier pour simuler un client SOAP (voir)

Imaginons le scénario suivant: supposons que vous voulez permettre à vos clients de récupérer la liste des produits que vous vendez! Autrement dit, on va créer un catalogue produit, simple, non?

Bon, c’est partie !

1 Création du fichier WSDL

Sans rentrer trop dans les détails, un fichier WSDL (Web Services Description Language) est un simple fichier XML où vous devez définir les opérations qui sont offertes par votre service.
Normalement, pour construire un fichier WSDL, le plus simple est d’utiliser des outils qui permettent de générer un tel WSDL en se basant sur les définitions des opérations que vous souhaitez offrir; Cependant, dans notre cas, nous allons écrire ce fichier à la main, et vous verrez qu’il n’est pas si effrayant que cela!

Dans un premier temps, nous allons commencer par décrire la définition de l’entête du WSDL (namespace, …), tout en haut du WSDL:

1
2
3
4
5
6
7
8
9
10
11
< ?xml version ='1.0' encoding ='UTF-8' ?>

<definitions name='CatalogueProduits'
 targetNamespace='http://cheghamwassim.com/tuts/soap-php5/catalogueProduits.wsdl'
 xmlns:tns='http://cheghamwassim.com/tuts/soap-php5/catalogueProduits.wsdl'
 xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
 xmlns:xsd='http://www.w3.org/2001/XMLSchema'
 xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
 xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
 xmlns='http://schemas.xmlsoap.org/wsdl/'>
</definitions>

Notez bien l’attribut name=’CatalogueProduits’ , nous allons nous en servir pour la suite!
Ensuite, et dans un souci de simplicité, nous allons ajouté des blocs au WSDL en partant du bas!

Nous ajoutons donc, tout en bas du WSDL, quelques informations concernant le serveur SOAP; veillez à bien nommez votre service du même nom que dans la définition dans l’entête:

1
2
3
4
5
<service name='CatalogueProduits'>
  <port name='CatalogueProduits' binding='tns:CatalogueProduitsBinding'>
    <soap:address location='http://cheghamwassim.com/tuts/soap-php5/catalogueProduits_server.php'/>
  </port>
</service>

Notez bien l’attribut binding=’tns:CatalogueProduitsBinding’, nous allons nous en servir pour la suite!

Ensuite, nous rajoutons la définition des opérations qui sont offertes par le service, dans un bloc :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<binding name='CatalogueProduitsBinding' type='tns:CatalogueProduitsPortType'>
  <soap:binding style='rpc'
   transport='http://schemas.xmlsoap.org/soap/http'/>
   
  <!-- début de l'opération : getProducts -->
  <operation name='getProducts'>
    <soap:operation soapAction='urn:xmethods-delayed-quotes#getProducts'/>
    <input />
      <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
       encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    <output>
      <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
       encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
    </output>
  </operation>
  <!-- fin de l'opération : getProducts -->

  <!-- ajouter les autres opérations ici -->

</binding>

Notez bien l’attribut type=’tns:CatalogueProduitsPortType’, nous allons nous en servir pour la suite!

Nous allons ensuite déclarer les signatures de nos opérations, dans un bloc <portType></portType>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<portType name='CatalogueProduitsPortType'>

  <!-- début de la déclaration : getProducts -->
  <operation name='getProducts'>
 <documentation>
 Returns the available products list.
 </documentation>
 <input message='tns:getProductsRequest'/>
 <output message='tns:getProductsResponse'/>
  </operation>
  <!-- fin de la déclaration : getProducts -->

  <!-- ajouter les autres déclarations ici -->

</portType>

Notez bien les attributs message=’tns:getProductsRequest’ et message=’tns:getProductsResponse’, nous allons nous en servir pour la suite!

Pour finir, nous allons définir les types des paramètres des opérations que nous avons déclaré :

1
2
3
4
5
6
7
8
9
10
<!-- début des paramètres de : getProducts -->
<message name='getProductsRequest'>
  <part name='authKey' type='xsd:string'/>
</message>
<message name='getProductsResponse'>
  <part name='Result' type='xsd:array'/>
</message>
<!-- fin des paramètres de : getProducts -->

<!-- définitions des paramètres des autres opérations ici -->

Nous avons donc définit un paramètre effectif pour notre opération getProduct(), qui se nomme authKey et est de type String. Puis, nous avons déclaré que notre opération retourne un paramètre de type Array, se nommant Result.

Je vous conseille de lire la documentation du W3C pour connaitre l’ensemble des types disponibles!

Et voilà! C’est tout pour la création de notre fichier WSDL. Voici le contenu final :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
< ?xml version ='1.0' encoding ='UTF-8' ?>

<definitions name='CatalogueProduits'
targetNamespace='http://cheghamwassim.com/tuts/soap-php5/catalogueProduits.wsdl'
xmlns:tns='http://cheghamwassim.com/tuts/soap-php5/catalogueProduits.wsdl'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
xmlns='http://schemas.xmlsoap.org/wsdl/'>

 <!-- début des paramètres de : getProducts -->
 <message name='getProductsRequest'>
  <part name='authKey' type='xsd:string'/>
 </message>
 <message name='getProductsResponse'>
  <part name='Result' type='xsd:array'/>
 </message>
 <!-- fin des paramètres de : getProducts -->

 <!-- définitions des paramètres des autres opérations ici -->

 <porttype name='CatalogueProduitsPortType'>

  <!-- début de la déclaration : getProducts -->
  <operation name='getProducts'>
   <documentation>
   Returns the available products list.
   </documentation>
   <input message='tns:getProductsRequest'/>
   <output message='tns:getProductsResponse'/>
    </operation>
    <!-- fin de la déclaration : getProducts -->

    <!-- ajouter les autres déclarations ici -->

 </porttype>

 <binding name='CatalogueProduitsBinding'
     type='tns:CatalogueProduitsPortType'>
    <soap:binding style='rpc'
              transport='http://schemas.xmlsoap.org/soap/http'/>
   
    <!-- début de l'opération : getProducts -->
    <operation name='getProducts'>
       <soap:operation soapAction='urn:xmethods-delayed-quotes#getProducts'/>
       <input />
          <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
            encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
   
       <output>
          <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes'
            encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>
       </output>
    </operation>
    <!-- fin de l'opération : getProducts -->

   <!-- ajouter les autres opérations ici -->

 </binding>

 <service name='CatalogueProduits'>
    <port name='CatalogueProduits' binding='tns:CatalogueProduitsBinding'>
       <soap:address location='http://cheghamwassim.com/tuts/soap-php5/catalogueProduits_server.php'/>
    </port>
 </service>
</definitions>

ATTENTION: Ne pas copier/coller ce contenu dans votre code, ceci risque d’invalider le fichier WSDL!

Veuillez trouver le fichier WSDL que nous allons utilisé pour la démo à cette url : http://cheghamwassim.com/tuts/soap-php5/catalogueProduits.wsdl

2 Implémentation de l’API

Avant d’implémenter le code du serveur SOAP, nous allons créer une classe qui encapsulera toutes les méthodes que nous voulons rendre disponibles aux services SOAP.
Créons donc un fichier CatalogueProduits_API.php qui contiendra la classe CatalogueProduits_API suivante:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?php

/**
 * This class define the products catalogue API
 * @version 1.0
 */

class CatalogueProduits_API {
 
 /**
  * Define some API keys
  */

 private $_authKeys = array('5uCuSpu$R#g3wrURUdRUCRamuPrugeRuFraxuDr_XaF-+geZEfApU?avan!pa$u?',
      'mecReprEwEphaWrasWaphe3red8de6RUyEspAp$e7?fRUxUzamez34$qa8enaS8a',
      'ph6kuju-emUph&6eSwup23-4ePruW53e2eBruq5t*r8@$Pre=efr*f5w?exu5e?p');

 /**
  * Define some dummy products. Real products may come from the database!
  */

 private $_products = array('Product #1', 'Product #2', 'Product #3', 'Product #4', 'Product #5' );
 
 /**
  * Leave this constructor empty !
  */

 public function __constructor(){}
 
 /**
  * This method gets all available products
  * @param String $authKey A valid API key
  * @return Mixed All available products if any, an empty array otherwise
  */

 public function getProducts($authKey){

  $response = array();

  if ( $this->_isValidAuthKey($authKey) ){
   $response['response']['code'] = 200;
   $response['response']['message'] = 'Response built successfully.';
   $response['data']['name'] = 'Products';
   $response['data']['value'] = $this->_products;
   }
  else {
   $response['response']['code'] = 403;
   $response['response']['message'] = 'Invalid API key.';
  }

  return $response;

 }

 // define other public methods here ...

  /**
  * Check either the given API key is valid or not
  * @param String $atuthKey The API key
  * @return True if the authKey is valid, False otherwise
  */

 private function _isValidAuthKey($authKey){
  return in_array($authKey, $this->_authKeys, true);
 }

}
?>

En ce qui concerne l’API que nous venons d’implémenter, vous pouvez remarquer que nous utilisons un simple tableau comme source de données pour simplifier les choses, vous pouvez bien sûr imaginer récupérer vos données depuis une base de données, un fichier XML, voire même depuis un autre service Web!

Aussi, pour plus de sécurité, nous avons définit un simple tableau contenant une série de clés valides que nous allons réclamer à nos utilisateurs à chaque demande d’un service! Bien sûr, en réalité, vous pouvez associer une clé à un compte client pour plus d’identification.

Nous allons maintenant passer à l’implémentation du serveur SOAP.

3 Création du serveur SOAP

Afin de coder le serveur SOAP, nous allons utiliser l’extension SOAP offerte par PHP5. (>=5.0.1)

Voici le contenu du fichier catalogueProduits_server.php que nous avons déclaré dans notre fichier WSDL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

$wsdl = "catalogueProduits.wsdl";
if ( isset($_GET['wsdl']) ){
 header('location: '.$wsdl);
}
else {
 
 if ($_SERVER["REQUEST_METHOD"] == "POST") {

  // require our API
  require_once('CatalogueProduits_API.php');
 
  //  during development stage, turn off the WSDL caching
  ini_set("soap.wsdl_cache_enabled", "0");

  // create a new SOAP server
  $server = new SoapServer($wsdl);

  // tel the server to use our API
  $server->setClass("CatalogueProduits_API");
 
  // launch the server
  $server->handle();
   
   }
 
}
?>

Simple et court, vous ne trouvez pas?

A noter cependant que par défaut, la mise en cache des fichiers WSDL est activée et ceci afin d’éviter au serveur de télécharger le fichier WSDL (depuis HTTP) à chaque requête. Or, pendant la phase de développement, on doit désactiver la mise en cache des WSDL car en toute logique, si vous modifiez vos fichiers WSDL vous risquez de ne pas pouvoir voir vos changements, puisque le fichier WSDL risque d’être rechargé depuis le cache!

Autre chose importante: nous avons décidé d’encapsuler toutes nos méthodes dans une classe que nous fournissons par la suite au serveur SOAP grâce à la méthode setClass()! Or, vous avez également la possibilité de déclarer des fonctions uniquement au serveur grâce à la méthode addFunction()

3 Création d’un client de test

Maintenant que notre serveur SOAP est prêt, il ne nous reste plus qu’à le tester et pour cela nous avons besoin de créer un client SOAP. Avant toute chose, sachez qu’en ce qui concerne le client, nous ne somme pas obligé de l’implémenter en PHP; en effet, le client peut être écrit dans n’import quel langage supportant le SOAP: Python, C, Flex, Java … et la liste est longue!

Voici le code de notre client SOAP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache

$APIKey = 'mecReprEwEphaWrasWaphe3red8de6RUyEspAp$e7?fRUxUzamez34$qa8enaS8a';
$wsdl = 'http://cheghamwassim.com/tuts/soap-php5/catalogueProduits.wsdl';
$client = new SoapClient($wsdl);

header('Content-Type: text/plain; charset: utf-8');
try {

 $return = $client->getProducts($APIKey);
 echo "Call : getProducts ...\n";
 print_r($return);
 
}
catch (SoapFault $exception) {
  echo $exception;      
}

?>

A noter que pour une meilleur gestion d’erreur nous encadrons l’appel au opérations du service dans un bloc try … catch!

Et voilà, on a maintenant un serveur SOAP qui attend nos requêtes et une API qui n’attend qu’à être étoffée de méthodes!

4 Démo

Vous pouvez tester notre petite application depuis cette URL: http://cheghamwassim.com/tuts/soap-php5/catalogueProduits_client.php

Cependant, si vous voulez tester le serveur SOAP avec votre propre client (ou un autre client SOAP générique), voici quelques informations utiles:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
URL du WSDL
http://cheghamwassim.com/tuts/soap-php5/catalogueProduits.wsdl

---
URL du serveur:
http://cheghamwassim.com/tuts/soap-php5/catalogueProduits_server.php

---
Clé d'autorisation (au choix):

Clé #1:
5uCuSpu$R#g3wrURUdRUCRamuPrugeRuFraxuDr_XaF-+geZEfApU?avan!pa$u?

Clé #2:
mecReprEwEphaWrasWaphe3red8de6RUyEspAp$e7?fRUxUzamez34$qa8enaS8a

Clé #3:
ph6kuju-emUph&6eSwup23-4ePruW53e2eBruq5t*r8@$Pre=efr*f5w?exu5e?p

Enjoy :)


In the same category
 ♥ 




Scan this with your mobile to visit http://cheghamwassim.com/blog/serveur-soap-avec-php5