Soap Protocole
Soap Protocole
Présentation
Dans cet article, nous allons voir la création d'un web service de type SOAP (Simple Object Access Protocol) avec WSDL 2.0 (Web Service Description Language). Cet article sera divisé en deux parties : la création d'un serveur et la création d'un client. Nous commencerons par comprendre comment fonctionnent SOAP et WSDL. SOAP est un protocole d'envoi de petites quantités d'informations en utilisant un format XML et le protocole HTTP pour la transmission. Dans certains cas particuliers, il peut utiliser TCP/IP. WSDL utilise le format XML pour décrire les différents services du web service, les formats des messages et les types utilisés lors de la communication de données. Le plus compliqué lors de la création du web service est le WSDL, surtout que la plupart des informations concernent le format WSDL 1.0 et très peu le 2.0 où la syntaxe change.
SOAP Serveur
Nous allons commencer par la réalisation du serveur et toute la programmation derrière. Pour mieux comprendre, nous allons faire plusieurs exemples avec un certain niveau de difficulté graduel. Le principal problème à résoudre est la création du WSDL pour chaque fonctionnalité que l'on va créer dans notre service Web. Voici un exemple simple pour réaliser ce web service. Pour commencer, nous aurons besoin de certaines choses.
<?php
// Définition de la classe pour le serveur
class SOAP_Server {
public function SOAP_Server () {
}
}
// Désactive la mise en cache du wsdl
// /!\ À chaque appel il ira rechercher le WSDL, Mode dev /!\
ini_set("soap.wsdl_cache_enabled",0);
// Création du serveur avec son WSDL
$serversoap = new SoapServer("http(s)://[nom du site]/soap/serviceSoap.wsdl");
$serversoap->setClass("SOAP_Server");
$serversoap->handle();
?>
Il vous faudra aussi le fichier WSDL avec un minimum d'informations. Certains paramètres sont à changer comme les noms et l'adresse http du service. Remplacez "testsoap" par le nom de votre service et dans <soap:address location="..."/>, mettez l'URL de votre service.
<?xml version = "1.0" encoding="UTF-8"?>
<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="urn:testsoap"
name ="testsoap"
targetNamespace="urn:testsoap"
>
<!-- Types -->
<wsdl:types>
<xsd:schema targetNamespace="urn:testsoap">
<xsd:import Namespace="http://schemas.xmlsoap.org/wsdl/"/>
</xsd:schema>
</wsdl:types>
<!-- Message -->
<!-- PortType -->
<wsdl:portType name ="testsoapPortType">
</wsdl:portType>
<!-- Binding -->
<wsdl:binding name = "testsoapBinding" type="tns:testsoapPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
</wsdl:binding>
<!-- Service -->
<wsdl:service name = "testsoapService">
<wsdl:port name="testsoapPort" binding="tns:testsoapBinding" >
<soap:address location ="http://localhost/soap/soap"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Maintenant, voyons comment réaliser et définir un service. Imaginons que nous avons besoin de récupérer un certain élément par rapport à un ID. Dans la classe, nous allons créer une fonction getByID avec en paramètre un ID de type int. Bien sûr, comme on est sur un langage non typé, ça n'a pas d'importance. Mais pour le WSDL, oui. Il faut le mettre pour les clients qui utilisent un langage typé. Notre fonction va retourner un élément JSON en type string, pour permettre de transporter plusieurs éléments à la fois, comme le résultat de la requête et son état.
class SOAP_Server {
...
public function getByID($id){
$resultat = ["resulta" => 0 , "data" => ""];
if ($id == 10) {
$resultat["resulta"] = 1;
$resultat["data"] = "mes data";
}
return json_encode($resultat);
}
...
}
Note : Le nom de la fonction est important pour la suite. Toute modification du nom nécessitera une modification dans le WSDL.
Après avoir créé la fonction et l'avoir définie, nous allons la déclarer dans le WSDL. Pour ce faire, il faut comprendre la logique qui va suivre. L’image ci-dessous schématise ce qui va suivre :
Pour commencer, nous devons définir les messages d'envoi et de retour. Pour cela, il faut définir les types des éléments que ces messages transportent. Il y a des types réguliers comme int, string, etc., et des types spéciaux qu'on devra définir comme un objet. Nous verrons ceci plus tard dans un autre exemple. Pour l'instant, nous utilisons un int en entrée et un string en sortie. Pour le nom des messages, nous avons utilisé le nom de la fonction + le type du message : Response ou Request.
<!-- Message -->
<wsdl:message name="getByIDRequest">
<wsdl:part name="id" type="xsd:int"/>
</wsdl:message>
<wsdl:message name="getByIDResponse">
<wsdl:part name="jsonResponse" type="xsd:string"/>
</wsdl:message>
Ensuite, nous allons associer les deux messages ensemble, ce qu'on appelle une opération.
<!-- PortType -->
<wsdl:portType name ="testsoapPortType">
...
<wsdl:operation name="getByID">
<wsdl:input message="tns:getByIDRequest"/>
<wsdl:output message="tns:getByIDResponse"/>
</wsdl:operation>
...
</wsdl:portType>
Et pour finir, nous allons associer cette opération avec la fonction de la classe. À ce moment-là, le SOAP action va contenir le namespace + le nom de la fonction.
<!-- Binding -->
<wsdl:binding name = "testsoapBinding" type="tns:testsoapPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
...
<wsdl:operation name="getByID">
<soap:operation soapAction="urn:testsoap#getByID"/>
<wsdl:input>
<soap:body namespace="urn:testsoap" use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body namespace="urn:testsoap" use="literal"/>
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
Après cela, si vous voulez vérifier que votre fichier WSDL est correct, il existe un outil en ligne qui vous permet de le valider :
Site Web WSDL Analyzer

Maintenant, votre service SOAP est opérationnel. Vous pouvez envoyer une requête et récupérer la réponse.
SOAP Client
class SOAP_client {
private $client ;
private $WSDL;
private $service_uri;
private $service_location ;
function __construct() {
// Désactive la mise en cache du wsdl
// /!\ À chaque appel il ira rechercher le WSDL, Mode dev /!\
ini_set("soap.wsdl_cache_enabled", "0");
}
public function build_client() {
try {
$this->client = new SoapClient(
$this->WSDL,
array(
"location" => $this->service_location,
"uri" => $this->service_uri,
"trace" => true,
"exceptions" => true,
'features' => SOAP_SINGLE_ELEMENT_ARRAYS + SOAP_USE_XSI_ARRAY_TYPE,
));
} catch (Exception $e) {
echo "Error SoapClient";
}
}
public function request( SOAP_request $request) {
return $this->client->__soapCall( $request->getNameFuction() ,$request->getarray() );
}
public function get_Cookie () {
return $this->client->_cookies;
}
public function set_Cookie ($name, $data) {
$this->client->__setCookie($name ,$data);
}
public function set_WSDL($url) {
$this->WSDL = $url;
return $this;
}
public function set_service_location ($url) {
$this->service_location = $url;
return $this;
}
public function set_service_url ($url) {
$this->service_uri = $url;
return $this;
}
}
class SOAP_request {
private $nameFuction ;
private $arr = [];
private $arrayParm_ = [];
// nom de la fonction de la request
function __construct($nameFuction , $arrayParm){
$this->nameFuction = $nameFuction;
$this->arrayParm_ = $arrayParm;
foreach ($arrayParm as $key => $value) {
array_push($this->arr , new SoapParam($value,$key));
}
}
function setParm ($arrayParm) {
$this->arrayParm_ = $arrayParm;
$this->arr = [];
foreach ($arrayParm as $key => $value) {
array_push($this->arr , new SoapParam($value,$key));
}
}
public function getParam () { return $this->arrayParm_;}
public function getNameFuction () { return $this->nameFuction;}
public function getarray () { return $this->arr;}
}
class TemplateRequest {
static $login = [
"id" => 0,
];
}
// Création client SOAP
$client = new SOAP_client();
$client->set_WSDL("https://[site du service]/service.php?wsdl") // Vous pouvez aussi donner le chemin d'un fichier qui contient le WSDL du service
->set_service_location("https://[site du service]/service.php")
->set_service_url("https://[site du service]/")
->build_client();
// Préparation de la requête
// /!\ l'ordre des paramètres est important , si vous ne savez pas l'ordre, allez regarder dans le WSDL /!\
$parm = TemplateRequest::login;
$parm["id"] = 5;
$requets = new SOAP_request("login",$parm);
// Envoi de la requête et récupération du résultat
$result = $client->request($requets);
var_dump(json_decode($result));
// Pour récupérer le cookie de connexion après la requête de login et le définir dans le client
// $cookie = $client->get_Cookie()["nom du cookie"][0];
// $client->set_Cookie("nom du cookie",$cookie)
Voici le résultat du code ci-dessus :
