Home / Programmazione / PHP / Creare un web service SOAP con PHP
Mattepuffo

Creare un web service SOAP con PHP

Creare un web service SOAP con PHP

Oggi vediamo come implementare un semplice web service SOAP con PHP.

Creeremo sia la parte client che la parte server, usando un file TXT per leggere e scrivere i dati.

Può essere un buon punto di partenza per qualcosa di più completo e utile; potreste, ad esempio, aggiungere le operazioni su database.

Quindi questi saranno i file, messi dentro alla directory soap (che fantasia!):

  • Client.php
  • Server.php
  • data.txt
  • index.php
  • no_wsdl.php
  • wsdl.php
  • wsdl.wsdl

Abbiamo la possibilità di decidere se usare WSDL; in entrambi i casi possiamo eseguire le stesse operazioni.

Per scrivere sul file data.txt, dovete impostare i permessi di scrittura; questo il suo contenuto iniziale di esempio:

matteo<br>
marco<br>
giulia<br>

Bene, entriamo più nel vivo iniziando con la parte server.

Questo il contenuto di Server.php:

<?php

class Server {

    const FILENAME = 'data.txt';

    /**
     * Inserisce i dati.
     * Viene invocato dal client.
     *
     * @param $data Dati da inserire
     * @return Risposta dal server.
     */
    public function insertData($data) {
        $writtenBytes = file_put_contents(self::FILENAME, $data . '<br>', FILE_APPEND);
        if ($writtenBytes) {
            $response = "Sono stati inseriti $writtenBytes bytes.";
        } else {
            $response = "Errore nell'inserimento dei dati.";
        }
        return $response;
    }

    /**
     * Legge i dati.
     * Invocato dal client.
     *
     * @return I dati del file
     */
    public function readData() {
        $contents = file_get_contents(self::FILENAME);
        return $contents;
    }

}
 

Le funzioni sono commentate, e sono tutte abbastanza semplici.

Paradossalmente la parte server è più di quella client.

Il file Client.php contiene questo:

<?php

class Client {

    const MODE_WSDL = 'wsdl';
    const MODE_NO_WSDL = 'no_wsdl';

    private $client;

    /**
     * Costruttore
     *
     * @param $soapMode SOAP mode, WSDL o non WSDL
     * @param $serverLocation Indirizzo server
     */
    public function __construct($soapMode, $serverLocation) {
        $this->initializeClient($soapMode, $serverLocation);
    }

    /**
     * Istanzia il client, con la modalità specificata.
     *
     * Nel caso della modalità WSDL, serve solo l'url del servizio, che combacia con il file .wsdl.
     *
     * Nel caso della modalità non WSDL, il primo paramentro del costruttore è NULL.
     * Il secondo è un array di opzioni che specifica l'url e l'uri del server.
     */
    protected function initializeClient($soapMode, $serverLocation) {
        switch ($soapMode) {
            case self::MODE_WSDL:
                $this->client = new SoapClient($serverLocation);
                break;
            case self::MODE_NO_WSDL:
                $options = array(
                    'location' => $serverLocation,
                    'uri' => $serverLocation
                );
                $this->client = new SoapClient(NULL, $options);
                break;
            default:
                throw new Exception('Errore: modalità SOAP invalida.');
                break;
        }
    }

    /**
     * Inserisce i dati nel servizio remoto.
     *
     * @param $data I dati da inserire
     * @return La risposta dal servzio
     */
    public function insertData($data) {
        $response = $this->client->insertData($data);
        return $response;
    }

    /**
     * Legge i dati dal servizio.
     *
     * @return Ritorna i dati
     */
    public function readData() {
        return $this->client->readData();
    }

}

Abbiamo due costanti, a seconda della modalità che decidiamo di invocare.

Nel caso della modalità no_wsdl, al costruttore di SoapClient dobbiamo passare il primo a NULL (non abbiamo un file descrittore WSDL).

La maggior parte del lavoro viene fatto dal file index.php, che possiamo definire come una spece di dispatcher; è il file che viene richiamato dal browser o da qualunque tipo di client che fa la request:

<?php

require_once './Client.php';

// Parametri GET parameter che definiscono modalità e azione.
define('INSERT', 'insert');
define('READ', 'read');
define('INSERT_VALUE', 'value');
define('WSDL', 'wsdl');
define('NO_WSDL', 'no_wsdl');

// Url del server, diverso a seconda della modalità scelta.
define('LOCATION_WSDL', 'http://ferrons.homepc.it/soap/wsdl.wsdl');
define('LOCATION_NO_WSDL', 'http://ferrons.homepc.it/soap/no_wsdl.php');

/**
 * Controlla se sono stati definiti i parametri.
 *
 * @param $parameters Parametri da controllare.
 */
function checkGETParametersOrDie($parameters) {
    foreach ($parameters as $parameter) {
        isset($_GET[$parameter]) || die("Parametro '$parameter' mancante.");
    }
}

/**
 * Istanzia il client con l'url corretto a seconda della modalità.
 *
 * @param $mode Modalità SOAP
 * @return Istanza del Client.
 */
function instantiateSoapClient($mode) {
    if ($mode == WSDL) {
        $serverLocation = LOCATION_WSDL;
    } else {
        $serverLocation = LOCATION_NO_WSDL;
    }
    try {
        $soapClient = new Client($mode, $serverLocation);
    } catch (Exception $exception) {
        die("Errore nell'inizializzare il SOAP client: " . $exception->getMessage());
    }
    return $soapClient;
}

checkGETParametersOrDie(['mode', 'action']);

$mode = $_GET['mode'];
$action = $_GET['action'];

$soapClient = instantiateSoapClient($mode);

switch ($action) {
    case INSERT:
        checkGETParametersOrDie([INSERT_VALUE]);
        $value = $_GET[INSERT_VALUE];
        try {
            $response = $soapClient->insertData($value);
            echo $response;
        } catch (Exception $exception) {
            die("Errore nell'inserimento: " . $exception->getMessage());
        }
        break;
    case READ:
        try {
            $data = $soapClient->readData();
            echo $data;
        } catch (Exception $exception) {
            die('Errore nella lettura: ' . $exception->getMessage());
        }
        break;
    default:
        die('"action" non esistente.');
        break;
}

Sostanzialmente si occupa di:

  • identificare i parametri passati in GET, che servono a identificare almeno la modalità scelta, e la action da eseguire (lettura o scrittura)
  • in base alla modalità scelta, indirizzare la richiesta verso il file corretto
  • eseguire l'azione indicata nel parametro GET action

Nel caso della modalità no_wsdl, verrà invocato il file no_wsdl.php:

<?php

require_once './Server.php';

$options = array('uri' => $_SERVER['PHP_SELF']);

$server = new SoapServer(NULL, $options);
$server->setClass('Server');
$server->handle();

Nell'altro caso, verrà richiamato il file wsdl.wsdl, che è un file XML che descrive le varie operazioni:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:tns="http://ferrons.homepc.it/soap"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             name="SOAP server"
             targetNamespace="http://ferrons.homepc.it/soap">

    <message name="stringParam">
        <part name="reqParam" type="xsd:string" />
    </message>
    <message name="response">
        <part name="resParam" type="xsd:string" />
    </message>

    <portType name="SimpleServircePortType">
        <operation name="insertData">
            <input message="tns:stringParam" />
            <output message="tns:response" />
        </operation>
        <operation name="readData">
            <output message="tns:response" />
        </operation>
    </portType>

    <binding name="SimpleServirceBinding" type="tns:SimpleServircePortType">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
        <operation name="insertData">
            <soap:operation soapAction="" />
            <input>
                <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
            </input>
            <output>
                <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
            </output>
        </operation>
        <operation name="readData">
            <output>
                <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
            </output>
        </operation>
    </binding>

    <service name="SoapService">
        <documentation>Legge e scrive dentro un file txt.</documentation>
        <port name="SimpleServircePort" binding="tns:SimpleServirceBinding">
            <soap:address location="http://ferrons.homepc.it/soap/wsdl.php" />
        </port>
    </service>

</definitions>

Questo a sua volta richiamerà il file wsdl.php:

<?php

require_once './Server.php';

$server = new SoapServer('http://ferrons.homepc.it/soap/wsdl.wsdl');
$server->setClass('Server');
$server->handle();

Se seguite il flusso delle operazioni, non è complicato.

A prima vista, sembrerebbe meglio non usare WSDL.

Ma nel caso di web service più complicati, è sicuramente meglio usarlo.

Enjoy!