Cos'è il SAPONE? Ad esempio esiste un servizio web aperto chiamato belavia.

Qui a LeaseWeb lavoriamo molto con i servizi web SOAP per integrare tra loro le nostre applicazioni interne. Soprattutto durante lo sviluppo e il test delle nostre applicazioni poiché abbiamo bisogno della capacità di esercitarci con le API SOAP.

$ curl -sS http://leaseweb.github.io/php-soap-client/installer | php

Questo scaricherà il file phar nella directory di lavoro corrente e lo renderà eseguibile in modo da poterlo utilizzare immediatamente invocando:

$ ./soap_client

Per installare l'ultima versione master puoi ottenere il codice sorgente direttamente da GitHub, creare un pacchetto del tuo file .phar e installarlo utilizzando GNU Make.
Per poter creare il file .phar è necessario che sia installato Composer. Per saperne di più sul compositore fare riferimento alla loro eccellente documentazione.

# Installa il client php soap $ git clone https://github.com/LeaseWeb/php-soap-client.git $ cd php-soap-client $ compositer.phar install $ make $ sudo make install

Se ricevi un'eccezione phar di compilazione non riuscita durante l'esecuzione, devi impostare phar.readonly = Off nel tuo php.ini. Su una macchina di sviluppo questo va bene, ma sii consapevole dei rischi per la sicurezza quando imposti phar.readonly su Off .

Il comando make install precedente installerà l'applicazione soap_client in /usr/local/bin e la renderà eseguibile in modo da poterla chiamare facilmente in questo modo:

$ soap_client php-soap-client versione 2.1.3 Utilizzo: comando Opzioni: ... Comandi disponibili: call Chiama il servizio remoto con il `metodo` specificato e invia la risposta a stdout. help Visualizza la guida per un comando list Elenca i comandi list-methods Ottieni un elenco dei metodi disponibili per chiamare sul telecomando. request Genera una richiesta SOAP formattata xml per il metodo specificato e invia l'output a stdout. wsdl Ottieni il WSDL di un servizio soap.

Da questo punto in poi presumiamo che tu abbia installato soap_client.phar sul tuo sistema in /usr/local/bin/soap_client e che la directory /urs/local/bin sia nel tuo $PATH .

Diciamo che vorremmo vedere quali metodi sono disponibili sul servizio remoto http://www.webservicex.net/ConvertTemperature.asmx. Potremmo impartire il seguente comando:

$ soap_client --endpoint="http://www.webservicex.net/ConvertTemperature.asmx?WSDL" metodi di elenco

Che produrrà quanto segue:

ConvertiTemp

Se esegui il comando precedente con l'opzione -vvv otterrai un output più dettagliato.
In questo caso l'unico metodo disponibile è ConvertTemp . Vediamo come appare una richiesta XML SOAP per questo metodo:

$ soap_client --endpoint="http://www.webservicex.net/ConvertTemperature.asmx?WSDL" richiesta ConvertTemp 0

Se desideri effettuare una richiesta SOAP al metodo ConvertTemp sul servizio remoto, utilizza il comando secondario call:

$ soap_client --endpoint="http://www.webservicex.net/ConvertTemperature.asmx?WSDL" chiamata --editor ConvertTemp

Notare l'opzione --editor dopo il sottocomando call. Se utilizzi il flag --editor, soap_client aprirà l'editor specificato nella variabile di ambiente $EDITOR in modo da poter modificare l'XML della richiesta prima di inviarlo.

Se emetti la stessa richiesta più volte, puoi salvare una richiesta soap come file XML locale e passarla a /dev/stdin del comando di chiamata soap_client:

# Ottieni l'xml della richiesta e memorizzalo localmente $ soap_client --endpoint="http://www.webservicex.net/ConvertTemperature.asmx?WSDL" request ConvertTemp > my_sample_request.xml # Ora modifica my_sample_request.xml # Ora puoi chiamare il Metodo ConvertTemp con questa richiesta pre-preparata $ soap_client --endpoint="http://www.webservicex.net/ConvertTemperature.asmx?WSDL" chiama ConvertTemp< my_sample_request.xml

Poiché ripeterai frequentemente i comandi soap_client in breve tempo mentre esplori un servizio Web remoto, puoi risparmiare tempo impostando una variabile di ambiente SOAPCLIENT_ENDPOINT che contiene l'URL del WSDL. Quando questa variabile di ambiente è impostata, puoi omettere l'opzione della riga di comando --endpoint. Facciamolo ora e chiamiamo il metodo ConvertTemp:

$ export SOAPCLIENT_ENDPOINT="http://www.webservicex.net/ConvertTemperature.asmx?WSDL" $ soap_client call ConvertTemp< my_sample_request.xml

Volevo sapere quanti sono 107,6 gradi Fahrenheit in Celsius, quindi il mio my_sample_request.xml contiene:

$ cat mia_richiesta_campione.xml 107.6 gradi Fahrenheit laureaCelsius

$ soap_client chiama ConvertTemp< my_sample_request.xml stdClass Object ( => 42)

La risposta è 42.

Se preferisci vedere le risposte in formato XML puoi utilizzare l'opzione della riga di comando --xml:

$ soap_client chiamata --xml ConvertTemp< my_sample_request.xml 42

Questo tutorial dovrebbe fornirti informazioni sufficienti per iniziare a esplorare, testare e/o sviluppare API SOAP.
In un futuro post sul blog, continuerò l'argomento del client php soap. Stiamo attualmente lavorando per comprimere l'archivio .phar per il web.

  • Esercitazione

Ciao a tutti!
È successo così che recentemente ho iniziato a sviluppare servizi web. Ma oggi l'argomento non riguarda me, ma come possiamo scrivere il nostro servizio Web XML basato sul protocollo SOAP 1.2.

Spero che dopo aver letto l'argomento sarai in grado di:

  • scrivere la propria implementazione server di un'applicazione web;
  • scrivere la propria implementazione client di un'applicazione web;
  • scrivere la descrizione del proprio servizio web (WSDL);
  • inviare gli array client dello stesso tipo di dati al server.
Come avrai intuito, tutta la magia verrà eseguita utilizzando PHP e le classi SoapClient e SoapServer integrate. Il nostro coniglio sarà un servizio per l'invio di messaggi SMS.

1 Dichiarazione del problema

1.1 Confini

All'inizio propongo di affrontare il risultato che otterremo alla fine dell'argomento. Come annunciato sopra, scriveremo un servizio per l'invio di messaggi SMS e, più precisamente, riceveremo messaggi da diverse fonti tramite il protocollo SOAP. Dopodiché considereremo in quale forma arrivano al server. Il processo di accodamento dei messaggi per l'ulteriore invio al provider, sfortunatamente, va oltre lo scopo di questo post per molte ragioni.

1.2 Quali dati cambieremo?

Ottimo, abbiamo deciso i confini! Il prossimo passo da compiere è decidere quali dati scambieremo tra il server e il client. Su questo argomento ti consiglio di non cavillare troppo e di rispondere subito da solo alle domande principali:
  • Quali dati minimi devono essere inviati al server per inviare un messaggio SMS a un abbonato?
  • Quali dati minimi devono essere inviati dal server per soddisfare le esigenze del cliente?
Qualcosa mi dice che per questo è necessario inviare quanto segue:
  • numero di cellulare e
  • testo del messaggio SMS.
In linea di principio bastano queste due caratteristiche per inviare, ma immagino subito il caso di un SMS con gli auguri di compleanno che ti arrivi alle 3 del mattino, ovvero alle 4! In questo momento sarò molto grato a tutti per non essersi dimenticati di me! Pertanto, invieremo anche al server e
  • data di invio del messaggio SMS.
La prossima cosa che vorrei inviare al server è:
  • Tipo di messaggio.
Questo parametro non è obbligatorio, ma può esserci molto utile se abbiamo bisogno di dire velocemente al capo quanti nostri clienti abbiamo “deliziato” con le nostre novità, e anche fare delle belle statistiche in merito.

Eppure ho dimenticato qualcosa! Se riflettiamo un po' di più, vale la pena notare che il client può inviare al server un messaggio SMS o più messaggi alla volta. In altre parole, un pacchetto di dati può contenere da uno a infiniti messaggi.

Di conseguenza, otteniamo che per inviare un messaggio SMS abbiamo bisogno dei seguenti dati:

  • Numero di cellulare,
  • testo del messaggio SMS,
  • ora di invio del messaggio SMS all'abbonato,
  • tipo di messaggio.

Abbiamo risposto alla prima domanda, ora dobbiamo rispondere alla seconda domanda. E forse mi permetterò di scherzare un po’. Pertanto dal server invieremo solo dati booleani, il cui significato ha il seguente significato:

  • TRUE – il pacchetto ha raggiunto con successo il server, ha superato l'autenticazione ed è stato messo in coda per l'invio al provider SMS
  • FALSO – in tutti gli altri casi

Questo conclude la descrizione della dichiarazione del problema! E infine, passiamo alla parte divertente: scopriamo che tipo di strana bestia è questo SOAP!

2 Cos'è il SAPONE?

In generale, inizialmente non avevo intenzione di scrivere nulla su cosa sia SOAP e volevo limitarmi ai collegamenti al sito w3.org con le specifiche necessarie, nonché ai collegamenti a Wikipedia. Ma alla fine ho deciso di scrivere una breve nota su questo protocollo.

E inizierò la mia storia con il fatto che questo protocollo di scambio dati appartiene a un sottoinsieme di protocolli basati sul cosiddetto paradigma RPC (Remote Procedure Call), il cui antipodo è REST (Representational State Transfer). Puoi leggere di più a riguardo su Wikipedia; i collegamenti agli articoli sono alla fine dell'argomento. Da questi articoli dobbiamo comprendere quanto segue: “L'approccio RPC consente l'utilizzo di un numero limitato di risorse di rete con un gran numero di metodi e un protocollo complesso. Con l’approccio REST, il numero di metodi e la complessità del protocollo sono strettamente limitati, il che significa che il numero di risorse individuali può essere elevato”. Cioè, per noi, questo significa che nel caso dell'approccio RPC sul sito ci sarà sempre un input (link) al servizio e quale procedura chiamare per elaborare i dati in arrivo che trasferiamo insieme ai dati, mentre con l'approccio REST nel nostro Il sito presenta molti input (link), ognuno dei quali accetta ed elabora solo determinati dati. Se qualcuno che legge sa spiegare la differenza tra questi approcci in modo ancora più semplice, assicurati di scrivere nei commenti!

La prossima cosa che dobbiamo sapere su SOAP è che questo protocollo utilizza lo stesso XML come trasporto, il che da un lato è molto buono, perché Il nostro arsenale include immediatamente tutta la potenza di uno stack di tecnologie basate su questo linguaggio di markup, vale a dire XML-Schema, un linguaggio per descrivere la struttura di un documento XML (grazie Wikipedia!), che consente la convalida automatica dei dati ricevuti dal server dai clienti.

E così, ora sappiamo che SOAP è un protocollo utilizzato per implementare chiamate di procedure remote e utilizza XML come trasporto! Se leggi l'articolo su Wikipedia, puoi anche imparare da lì che può essere utilizzato su qualsiasi protocollo a livello di applicazione e non solo in combinazione con HTTP (sfortunatamente, in questo argomento considereremo solo SOAP su HTTP). E sai cosa mi piace di più di tutto questo? Se non ci sono ipotesi, allora darò un suggerimento: SOAP!... Ancora nessuna ipotesi?... Sei sicuro di aver letto l'articolo su Wikipedia?... In generale, non ti torturerò ulteriormente. Pertanto, andrò direttamente alla risposta: "SOAP (dall'inglese Simple Object Access Protocol - simple protocollo accesso agli oggetti; fino alla specifica 1.2)". La cosa più notevole di questa riga è in corsivo! Non so quali conclusioni hai tratto da tutto ciò, ma vedo quanto segue: poiché questo protocollo non può in alcun modo essere definito "semplice" (e apparentemente anche w3 è d'accordo con questo), dalla versione 1.2 ha smesso di essere decrittografato in qualche modo ! E divenne noto come SOAP, semplicemente SOAP, punto e basta.

Bene, okay, scusami, sono stato un po' distratto. Come ho scritto prima, XML viene utilizzato come trasporto e i pacchetti che viaggiano tra il client e il server sono chiamati buste SOAP. Se consideri la struttura generale della busta, ti sembrerà molto familiare, perché... assomiglia alla struttura di una pagina HTML. Ha una sezione principale - Avvolgere, che include sezioni Intestazione E Corpo, O Colpa. IN Corpo i dati vengono trasmessi ed è una sezione obbligatoria della busta, mentre Intestazioneè facoltativo. IN Intestazione potranno essere trasmessi consensi o altri dati non direttamente riferibili ai dati di input delle procedure del servizio web. Di Colpa non c'è niente di speciale da dire, tranne che arriva al client dal server in caso di errori.

Qui è dove finisce la mia storia di revisione sul protocollo SOAP (esamineremo gli inviluppi stessi e la loro struttura in modo più dettagliato quando il nostro client e server impareranno finalmente a eseguirli l'uno con l'altro) e ne inizia una nuova - sul compagno SOAP chiamato WSDL(Linguaggio di descrizione dei servizi Web). Sì, sì, questa è proprio la cosa che spaventa la maggior parte di noi anche solo dal provare a implementare la nostra API su questo protocollo. Di conseguenza, di solito reinventiamo la nostra ruota con JSON come trasporto. Allora, cos'è il WSDL? WSDL è un linguaggio per descrivere servizi web e accedervi, basato sul linguaggio XML (c) Wikipedia. Se questa definizione non ti chiarisce l'intero significato sacro di questa tecnologia, allora proverò a descriverla con parole mie!

WSDL è progettato per consentire ai nostri client di comunicare normalmente con il server. A tale scopo il file con estensione “*.wsdl” descrive le seguenti informazioni:

  • Quali spazi dei nomi sono stati utilizzati?
  • Quali schemi di dati sono stati utilizzati?
  • Quali tipi di messaggi si aspetta il servizio Web dai client?
  • Quali dati appartengono a quali procedure del servizio web,
  • Quali procedure contiene il servizio web?
  • Come dovrebbe il cliente chiamare le procedure del servizio web,
  • A quale indirizzo devono essere inviate le chiamate dei clienti?
Come puoi vedere, questo file è l'intero servizio web. Specificando l'indirizzo del file WSDL nel client, sapremo tutto su qualsiasi servizio web! Di conseguenza, non abbiamo bisogno di sapere assolutamente nulla su dove si trova il servizio web stesso. Tutto quello che devi sapere è la posizione del suo file WSDL! Scopriremo presto che il SOAP non è così spaventoso come dicono i proverbi russi.

3 Introduzione allo schema XML

Ora sappiamo molto su cosa sia SOAP, cosa c'è al suo interno e abbiamo una panoramica dello stack tecnologico che lo circonda. Poiché, prima di tutto, SOAP è un metodo di interazione tra un client e un server e il linguaggio di markup XML viene utilizzato come mezzo di trasporto, in questa sezione capiremo un po' come avviene la convalida automatica dei dati utilizzando schemi XML.

Il compito principale del diagramma è descrivere la struttura dei dati che elaboreremo. Tutti i dati negli schemi XML sono suddivisi in semplice(scalare) e complesso(strutture) tipi. I tipi semplici includono i seguenti tipi:

  • linea,
  • numero,
  • valore booleano,
  • data di.
Qualcosa di molto semplice che non ha estensioni all'interno. Il loro antipodo sono i tipi complessi complessi. L’esempio più semplice di un tipo complesso che viene in mente a tutti sono gli oggetti. Ad esempio, un libro. Il libro è composto da proprietà: autore, Nome, prezzo, Numero ISBN eccetera. E queste proprietà, a loro volta, possono essere di tipo semplice o complesso. E il compito dello schema XML è descriverlo.

Suggerisco di non andare lontano e scrivere uno schema XML per il nostro messaggio SMS! Di seguito la descrizione xml del messaggio SMS:

71239876543 Messaggio di prova 2013-07-20T12:00:00 12
Il nostro diagramma di tipo complesso sarà simile al seguente:


Questa voce recita come segue: Abbiamo una variabile " Messaggio" tipo " Messaggio" ed esiste un tipo complesso chiamato " Messaggio", che consiste in un insieme sequenziale di elementi " telefono" tipo corda, « testo" tipo corda, « data" tipo appuntamento, « tipo" tipo decimale. Questi tipi sono semplici e sono già definiti nella descrizione dello schema. Congratulazioni! Abbiamo appena scritto il nostro primo schema XML!

Penso che il significato degli elementi " elemento" E " tipocomplesso"Tutto ti è diventato più o meno chiaro, quindi non ci concentreremo più su questi e passiamo direttamente all'elemento compositore" sequenza" Quando usiamo l'elemento compositore " sequenza“Si informa che gli elementi in esso contenuti devono sempre essere posizionati nella sequenza specificata nello schema e sono tutti obbligatori. Ma non disperare! Ci sono altri due elementi compositore negli schemi XML: " scelta" E " Tutto" Compositore" scelta" annuncia che deve esserci uno degli elementi elencati in esso, e il compositore " Tutto» – qualsiasi combinazione degli elementi elencati.

Come ricorderete, nella prima sezione dell'argomento abbiamo concordato che in un pacchetto possono essere trasmessi da uno a infiniti messaggi SMS. Pertanto, propongo di capire come tali dati vengono dichiarati nello schema XML. La struttura generale del pacchetto potrebbe assomigliare a questa:

71239876543 Messaggio di prova 1 2013-07-20T12:00:00 12 71239876543 Messaggio di prova N 2013-07-20T12:00:00 12
Il diagramma per un tipo così complesso sarà simile al seguente:


Il primo blocco contiene la familiare dichiarazione del tipo complesso “ Messaggio" Se hai notato, in ogni tipo semplice incluso in " Messaggio", sono stati aggiunti nuovi attributi chiarificatori" minSi verifica" E " maxOccurs" Come puoi intuire dal nome, il primo ( minSi verifica) indica che questa sequenza deve contenere almeno un elemento di tipo " telefono», « testo», « data" E " tipo", mentre il successivo ( maxOccurs) ci dichiara che esiste al massimo uno di questi elementi nella nostra sequenza. Di conseguenza, quando scriviamo i nostri schemi per qualsiasi dato, ci viene data la più ampia scelta su come configurarli!

Il secondo blocco del diagramma dichiara l'elemento " messageList" tipo " Elenco messaggi" È chiaro che" Elenco messaggi" è un tipo complesso che contiene almeno un elemento " Messaggio", ma il numero massimo di tali elementi non è limitato!

4 Scrivi il tuo WSDL

Ricordi che WSDL è il nostro servizio web? Spero che ti ricordi! Mentre lo scriviamo, il nostro piccolo servizio web verrà eseguito su di esso. Pertanto, suggerisco di non scherzare.

In generale, affinché tutto funzioni correttamente per noi, dobbiamo trasferire al client un file WSDL con il tipo MIME corretto. Per fare ciò è necessario configurare opportunamente il proprio server web, ovvero impostare il tipo MIME per i file con estensione “*.wsdl” sulla riga seguente:

Applicazione/wsdl+xml
Ma in pratica, di solito invio l'intestazione HTTP tramite PHP " testo/xml»:

Intestazione("Tipo contenuto: text/xml; charset=utf-8");
e tutto ha funzionato alla grande!

Voglio avvisarti subito che il nostro semplice servizio web avrà una descrizione piuttosto impressionante, quindi non allarmarti, perché... La maggior parte del testo è acqua obbligatoria e, dopo averlo scritto una volta, puoi copiarlo costantemente da un servizio web all'altro!

Poiché WSDL è XML, è necessario scriverlo direttamente nella prima riga. L'elemento root del file dovrebbe sempre essere chiamato " definizioni»:


Tipicamente, WSDL è composto da 4-5 blocchi principali. Il primo blocco è la definizione di un servizio web o, in altre parole, del punto di ingresso.


Qui dice che abbiamo un servizio chiamato..." SMSService" In linea di principio, tutti i nomi nel file WSDL possono essere modificati da te in qualsiasi cosa tu voglia, perché non svolgono assolutamente alcun ruolo.

Successivamente lo annunciamo nel nostro servizio web " SMSService" c'è un punto di ingresso ("porto") chiamato " PortaServizioSms" È a questo punto di ingresso che verranno inviate tutte le richieste dai client al server. E indicare nell'elemento “ indirizzo» collegamento al file del gestore che accetterà le richieste.

Una volta definito il servizio web e specificato il relativo punto di ingresso, dobbiamo associare ad esso le procedure supportate:


Per fare ciò, elenca quali operazioni e in quale forma verranno chiamate. Quelli. per il porto" PortaServizioSms" un'associazione è definita sotto il nome " SmsServiceBinding", che ha un tipo di chiamata " rpc"e HTTP viene utilizzato come protocollo di trasmissione. Pertanto, abbiamo indicato qui che effettueremo una chiamata RPC su HTTP. Successivamente descriviamo quali procedure ( operazione) sono supportati nel servizio Web. Sosterremo una sola procedura –” inviare SMS" Attraverso questa procedura i nostri meravigliosi messaggi verranno inviati al server! Dopo aver dichiarato la procedura, è necessario indicare in quale forma verranno trasmessi i dati. In questo caso si indica che verranno utilizzate buste SOAP standard.

Successivamente, dobbiamo associare la procedura ai messaggi:


Per fare ciò specifichiamo che la nostra associazione è di tipo " TipoPortaServizioSms" e nell'elemento " portType"con il nome dello stesso tipo si indica l'associazione delle procedure ai messaggi. E così, il messaggio in arrivo (dal client al server) si chiamerà “ inviaSmsRequest", e in uscita (dal server al client)" sendSmsResponse" Come tutti i nomi in WSDL, i nomi dei messaggi in entrata e in uscita sono arbitrari.

Ora dobbiamo descrivere i messaggi stessi, ad es. in entrata e in uscita:


Per fare questo aggiungiamo gli elementi " Messaggio"con nomi" inviaSmsRequest" E " sendSmsResponse"rispettivamente. In essi indichiamo che l'input dovrebbe essere una busta la cui struttura corrisponde al tipo di dati " Richiesta" Successivamente viene restituita una busta dal server contenente il tipo di dati - “ Risposta».

Ora dobbiamo fare solo una piccola cosa: aggiungere una descrizione di questi tipi al nostro file WSDL! E come pensi che il WSDL descriva i dati in entrata e in uscita? Penso che tu abbia già capito tutto molto tempo fa e ti sia detto che usare gli schemi XML! E avrai assolutamente ragione!


Puoi congratularti con noi! Il nostro primo WSDL è stato scritto! E siamo un passo avanti verso il raggiungimento del nostro obiettivo.
Successivamente, esamineremo ciò che PHP ci offre per sviluppare le nostre applicazioni distribuite.

5 Il nostro primo server SOAP

In precedenza ho scritto che per creare un server SOAP in PHP utilizzeremo la classe SoapServer integrata. Affinché tutte le ulteriori azioni avvengano nello stesso modo in cui ho fatto io, dovrai modificare leggermente il tuo PHP. Per essere ancora più precisi, devi assicurarti di avere installata l’estensione “php-soap”. È meglio leggere come installarlo sul tuo server web sul sito ufficiale di PHP (vedi l'elenco dei riferimenti).

Dopo che tutto è stato installato e configurato, dovremo creare un file nella cartella principale del nostro hosting” smsservice.php» con il seguente contenuto:

setClass("SoapSmsGateWay"); //Avvia il server $server->handle();
Spero che non sia necessario spiegare cosa c'è sopra la linea con la funzione "ini_set". Perché lì viene determinato quali intestazioni HTTP invieremo dal server al client e l'ambiente è configurato. Nella riga "ini_set" disabilitiamo la memorizzazione nella cache del file WSDL in modo che le nostre modifiche abbiano immediatamente effetto sul client.

Ora veniamo al server! Come puoi vedere, l'intero server SOAP occupa solo tre righe! Nella prima riga creiamo una nuova istanza dell'oggetto SoapServer e passiamo l'indirizzo della nostra descrizione WSDL del servizio web al suo costruttore. Ora sappiamo che si troverà nella root dell'hosting in un file dal nome autoesplicativo “ smsservice.wsdl.php" Nella seconda riga diciamo al server SOAP quale classe deve essere estratta per elaborare la busta ricevuta dal client e restituire la busta con la risposta. Come avrai intuito, è in questa classe che verrà descritto il nostro unico metodo inviare SMS. Sulla terza riga avviamo il server! Questo è tutto, il nostro server è pronto! Con il quale mi congratulo con tutti noi!

Ora dobbiamo creare il file WSDL. Per fare ciò, puoi semplicemente copiarne il contenuto dalla sezione precedente oppure prenderti delle libertà e “modellarlo” un po’:

"; ?> /" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http:// schemas.xmlsoap.org/wsdl/http/" name="SmsWsdl" xmlns="http://schemas.xmlsoap.org/wsdl/"> /"> /smsservice.php" />
A questo punto dovremmo essere completamente soddisfatti del server risultante, perché Possiamo registrare le buste in arrivo e poi analizzare con calma i dati in arrivo. Per poter ricevere qualsiasi cosa sul server, abbiamo bisogno di un client. Allora veniamo al dunque!

6 Client SOAP in arrivo

Prima di tutto dobbiamo creare un file in cui scriveremo il client. Come al solito, lo creeremo nella root dell'host e lo chiameremo " client.php", e all'interno scriveremo quanto segue:

ListaMessaggi = nuova ListaMessaggi(); $req->messageList->message = nuovo messaggio(); $req->messageList->messaggio->telefono = "79871234567"; $req->messageList->message->text = "Messaggio di prova 1"; $req->messageList->message->date = "2013-07-21T15:00:00.26"; $req->messageList->messaggio->tipo = 15; $client = new SoapClient("http://($_SERVER["HTTP_HOST"])/smsservice.wsdl.php", array("soap_version" => SOAP_1_2)); var_dump($client->sendSms($req));
Descriviamo i nostri oggetti. Quando abbiamo scritto il WSDL, descriveva tre entità per la busta in entrata al server: Richiesta, Elenco messaggi E Messaggio. Di conseguenza classi Richiesta, Elenco messaggi E Messaggio sono riflessi di queste entità nel nostro script PHP.

Una volta definiti gli oggetti, dobbiamo creare un oggetto ( $rich), che invieremo al server. Dopodiché arrivano le due linee per noi più care! Il nostro cliente SOAP! Che tu ci creda o no, questo è sufficiente affinché il nostro server inizi a ricevere messaggi dal client, nonché affinché il nostro server li riceva ed elabori con successo! Nel primo creiamo un'istanza della classe SoapClient e passiamo l'indirizzo della posizione del file WSDL al suo costruttore, e nei parametri indichiamo esplicitamente che lavoreremo utilizzando il protocollo SOAP versione 1.2. Nella riga successiva chiamiamo il metodo inviare SMS oggetto $cliente e visualizzare immediatamente il risultato nel browser.
Eseguiamolo e vediamo cosa abbiamo finalmente ottenuto!

Il seguente oggetto mi è stato restituito dal server:

Oggetto (stdClass) public "status" => booleano vero
E questo è fantastico, perché... Ora sappiamo per certo che il nostro server funziona e non solo funziona, ma può anche restituire alcuni valori al client!

Adesso diamo un'occhiata al log che conserviamo prudentemente lato server! Nella sua prima parte vediamo i dati grezzi arrivati ​​al server:

79871234567 Messaggio di prova 1 21-07-2013 15:00:00.26 15
Questa è la busta. Ora sai che aspetto ha! Ma difficilmente saremo interessati a guardarlo continuamente, quindi deserializziamo l'oggetto dal file di registro e vediamo se va tutto bene:

Oggetto(stdClass) public "messageList" => oggetto(stdClass) public "messaggio" => oggetto(stdClass) public "telefono" => string "79871234567" (lunghezza=11) public "testo" => string "Messaggio di prova 1 " (lunghezza=37) public "data" => stringa "2013-07-21T15:00:00.26" (lunghezza=22) public "tipo" => stringa "15" (lunghezza=2)
Come puoi vedere, l'oggetto è stato deserializzato correttamente, per questo voglio congratularmi con tutti noi! Qualcosa di più interessante ci aspetta dopo! Vale a dire, invieremo al client al server non solo un messaggio SMS, ma un intero pacchetto (per essere più precisi, tre)!

7 Invio di oggetti complessi

Pensiamo a come trasferire un sacco di messaggi al server in un pacchetto? Probabilmente il modo più semplice sarebbe organizzare un array all'interno dell'elemento messageList! Facciamolo:

// crea un oggetto da inviare al server $req = new Request(); $req->ListaMessaggi = nuova ListaMessaggi(); $msg1 = nuovo messaggio(); $msg1->telefono = "79871234567"; $msg1->text = "Messaggio di prova 1"; $msg1->data = "2013-07-21T15:00:00.26"; $msg1->tipo = 15; $msg2 = nuovo messaggio(); $msg2->telefono = "79871234567"; $msg2->text = "Messaggio di prova 2"; $msg2->data = "2014-08-22T16:01:10"; $msg2->tipo = 16; $msg3 = nuovo messaggio(); $msg3->telefono = "79871234567"; $msg3->text = "Messaggio di prova 3"; $msg3->data = "2014-08-22T16:01:10"; $msg3->tipo = 17; $req->messageList->messaggio = $msg1; $req->messageList->messaggio = $msg2; $req->messageList->messaggio = $msg3;
I nostri registri indicano che il seguente pacchetto è stato ricevuto dal client:

79871234567 Messaggio di prova 1 21-07-2013 15:00:00.26 15 79871234567 Messaggio di prova 2 22/08/2014 16:01:10 16 79871234567 Messaggio di prova 3 22/08/2014 16:01:10 17
Che sciocchezza, dici? E in un certo senso avrai ragione, perché... Non appena abbiamo appreso che l'oggetto ha lasciato il client, è arrivato al nostro server assolutamente nella stessa forma sotto forma di busta. È vero, i messaggi SMS non erano serializzati in XML nel modo di cui avevamo bisogno: dovevano essere racchiusi in elementi Messaggio, Non in Struttura. Ora vediamo in che forma un oggetto del genere arriva al metodo inviare SMS:

Oggetto(stdClass) public "messageList" => oggetto(stdClass) public "messaggio" => oggetto(stdClass) public "Struct" => array (dimensione=3) 0 => oggetto(stdClass) public "telefono" => stringa "79871234567" (lunghezza=11) public "testo" => string "Messaggio di prova 1" (lunghezza=37) public "data" => stringa "2013-07-21T15:00:00.26" (lunghezza=22) public " type" => string "15" (lunghezza=2) 1 => oggetto(stdClass) public "telefono" => string "79871234567" (lunghezza=11) public "testo" => string "Messaggio di prova 2" (lunghezza= 37) public "data" => string "2014-08-22T16:01:10" (lunghezza=19) public "tipo" => string "16" (lunghezza=2) 2 => oggetto(stdClass) public "telefono " => string "79871234567" (lunghezza=11) public "testo" => string "Messaggio di prova 3" (lunghezza=37) public "data" => string "2014-08-22T16:01:10" (lunghezza= 19) public "tipo" => stringa "17" (lunghezza=2)
Cosa ci dà questa conoscenza? Solo che il percorso che abbiamo scelto non è corretto e non abbiamo ricevuto risposta alla domanda: "Come possiamo ottenere la struttura dati corretta sul server?" Ma suggerisco di non disperare e di provare a convertire il nostro array nel tipo un oggetto:

$req->messageList->messaggio = (oggetto)$req->messageList->messaggio;
In questo caso riceveremo un'altra busta:

79871234567 Messaggio di prova 1 21-07-2013 15:00:00.26 15 79871234567 Messaggio di prova 2 22/08/2014 16:01:10 16 79871234567 Messaggio di prova 3 22/08/2014 16:01:10 17
È entrato nel metodo inviare SMS l'oggetto ha la seguente struttura:

Oggetto(stdClass) public "messageList" => oggetto(stdClass) public "messaggio" => oggetto(stdClass) public "BOGUS" => array (dimensione=3) 0 => oggetto(stdClass) public "telefono" => stringa "79871234567" (lunghezza=11) public "testo" => string "Messaggio di prova 1" (lunghezza=37) public "data" => stringa "2013-07-21T15:00:00.26" (lunghezza=22) public " type" => string "15" (lunghezza=2) 1 => oggetto(stdClass) public "telefono" => string "79871234567" (lunghezza=11) public "testo" => string "Messaggio di prova 2" (lunghezza= 37) public "data" => string "2014-08-22T16:01:10" (lunghezza=19) public "tipo" => string "16" (lunghezza=2) 2 => oggetto(stdClass) public "telefono " => string "79871234567" (lunghezza=11) public "testo" => string "Messaggio di prova 3" (lunghezza=37) public "data" => string "2014-08-22T16:01:10" (lunghezza= 19) public "tipo" => stringa "17" (lunghezza=2)
Per quanto mi riguarda, “la somma non cambia cambiando i luoghi dei termini” (c). Che cosa FALSO, Che cosa Struttura– non abbiamo ancora raggiunto il nostro obiettivo! E per raggiungere questo obiettivo, dobbiamo assicurarci che al posto di questi nomi incomprensibili venga visualizzato quello nativo Messaggio. Ma l'autore non sa ancora come raggiungere questo obiettivo. Pertanto, l’unica cosa che possiamo fare è sbarazzarci del contenitore in più. In altre parole, ora ci assicureremo che invece di Messaggio divenne FALSO! Per fare ciò, modificare l'oggetto come segue:

// crea un oggetto da inviare al server $req = new Request(); $msg1 = nuovo messaggio(); $msg1->telefono = "79871234567"; $msg1->text = "Messaggio di prova 1"; $msg1->data = "2013-07-21T15:00:00.26"; $msg1->tipo = 15; $msg2 = nuovo messaggio(); $msg2->telefono = "79871234567"; $msg2->text = "Messaggio di prova 2"; $msg2->data = "2014-08-22T16:01:10"; $msg2->tipo = 16; $msg3 = nuovo messaggio(); $msg3->telefono = "79871234567"; $msg3->text = "Messaggio di prova 3"; $msg3->data = "2014-08-22T16:01:10"; $msg3->tipo = 17; $req->elencomessaggi = $msg1; $req->elencomessaggi = $msg2; $req->messageList = $msg3; $req->elencomessaggi = (oggetto)$req->elencomessaggi;
Cosa succede se siamo fortunati e dal diagramma esce il nome corretto? Per fare ciò, diamo un'occhiata alla busta arrivata:

79871234567 Messaggio di prova 1 21-07-2013 15:00:00.26 15 79871234567 Messaggio di prova 2 22/08/2014 16:01:10 16 79871234567 Messaggio di prova 3 22/08/2014 16:01:10 17
Sì, il miracolo non è avvenuto! FALSO– non vinceremo! Vieni a inviare SMS l'oggetto in questo caso sarà simile a questo:

Oggetto(stdClass) public "messageList" => oggetto(stdClass) public "BOGUS" => array (dimensione=3) 0 => oggetto(stdClass) public "telefono" => stringa "79871234567" (lunghezza=11) public " testo" => string "Messaggio di prova 1" (lunghezza=37) public "data" => string "2013-07-21T15:00:00.26" (lunghezza=22) public "tipo" => string "15" (lunghezza =2) 1 => oggetto(stdClass) public "telefono" => string "79871234567" (lunghezza=11) public "testo" => string "Messaggio di prova 2" (lunghezza=37) public "data" => string " 2014-08-22T16:01:10" (lunghezza=19) public "tipo" => stringa "16" (lunghezza=2) 2 => oggetto(stdClass) public "telefono" => stringa "79871234567" (lunghezza= 11) public "testo" => string "Messaggio di prova 3" (lunghezza=37) public "data" => string "2014-08-22T16:01:10" (lunghezza=19) public "tipo" => string " 17" (lunghezza=2)
Come si suol dire: “Quasi”! Su questa nota (un po’ triste), propongo di concludere lentamente le cose e di trarre alcune conclusioni per noi stessi.

8 Conclusione

Finalmente siamo arrivati ​​qui! Scopriamo cosa puoi fare ora:
  • puoi scrivere il file WSDL necessario per il tuo servizio web;
  • puoi facilmente scrivere il tuo client in grado di comunicare con il server tramite SOAP;
  • puoi scrivere il tuo server che comunica con il mondo esterno tramite SOAP;
  • puoi inviare array dello stesso tipo di oggetti al server dal tuo client (con alcune restrizioni).
Abbiamo anche fatto alcune scoperte durante la nostra piccola ricerca:
  • la classe nativa SoapClient non serializza correttamente strutture dati dello stesso tipo in XML;
  • quando serializza un array in XML crea un elemento aggiuntivo chiamato Struttura;
  • quando si serializza un oggetto in XML crea un elemento aggiuntivo chiamato FALSO;
  • FALSO meno malvagio di Struttura a causa del fatto che la busta è più compatta (gli spazi dei nomi aggiuntivi non vengono aggiunti all'intestazione XML della busta);
  • Sfortunatamente, la classe SoapServer non convalida automaticamente i dati della busta con il nostro schema XML (forse neanche altri server lo fanno).

Brett McLaughlin Traduzione di Ilya Chekmenev

SOAP è il protocollo di accesso semplice agli oggetti. Se non ne hai mai sentito parlare prima, allora devi vivere in mezzo al nulla, lontano dalla civiltà. È diventata l'ultima moda nella programmazione web e parte integrante dei servizi web, che vengono utilizzati con tanto fanatismo negli sviluppi web dell'ultima generazione. Se hai sentito parlare di .NET di Microsoft, o della "rivoluzione" peer-to-peer, allora hai sentito parlare di tecnologie che si basano su SOAP (anche se non sai di cosa si tratta). Non ce n'è uno, ma due Implementazioni SOAP di Apache e Microsoft, che hanno migliaia di pagine a loro dedicate sul loro sito di supporto MSDN (http://msdn.microsoft.com/).

In questo articolo ti dirò cos'è SOAP e perché è una parte così importante nello sviluppo del paradigma di programmazione web. Ciò ti aiuterà a saltare le nozioni di base e a iniziare subito a lavorare con il toolkit SOAP. Successivamente fornirò una rapida panoramica dei progetti SOAP esistenti e mi immergerò nell'implementazione di Apache. Questo articolo non intende fornire un quadro completo di SOAP; il mio libro, Java & XML, 2a edizione, colma molte lacune. Troverai le risposte a molte delle domande che sono sorte dopo aver letto questo articolo nel libro.

introduzione

Per prima cosa devi capire cos'è SOAP. Puoi leggere l'opinione completa (e piuttosto lunga) del W3C su http://www.w3.org/TR/SOAP. Quindi, dopo averlo capito e scartato tutta la buccia, capirai che SOAP è solo un protocollo. Si tratta di un protocollo semplice (non è necessario scriverne uno nuovo per utilizzarlo) basato sull'idea che ad un certo punto in un'architettura distribuita vi è la necessità di scambiare informazioni. Inoltre, per i sistemi in cui esiste la possibilità di sovraccarichi e difficoltà nell'elaborazione dei processi, questo protocollo è molto vantaggioso in quanto è leggero e richiede una quantità minima di risorse. Infine, consente di eseguire tutte le operazioni su HTTP, il che rende possibile aggirare cose complicate come i firewall e proteggersi dall'ascolto utilizzando socket su un numero incredibile di porte. L'importante è che tu te ne renda conto, tutto il resto sono dettagli.

Naturalmente vorresti conoscere questi dettagli e non li ignorerò. Ci sono tre componenti fondamentali nella specifica SOAP: una busta SOAP, un insieme di regole di crittografia e un mezzo di interazione tra la richiesta e la risposta. Pensiamo a un messaggio SOAP come a una normale lettera. Ricordi ancora quelle cose antiche nelle buste con il francobollo e l'indirizzo scritto davanti? Questa analogia ti aiuterà a comprendere più chiaramente il concetto di SOAP come "busta". La Figura 12-1 illustra i processi SOAP nella forma di questa analogia.

Figura 12-1. Processo di messaggio SOAP

Tenete a mente questo quadro e diamo un'occhiata ai tre componenti della specifica SOAP. Parlerò brevemente di ciascuno di essi, riportando esempi che meglio rappresentano il concetto. Questi tre componenti chiave rendono SOAP così importante e significativo. La gestione degli errori, il supporto per varie crittografie, la serializzazione dei parametri e il fatto che SOAP funzioni su HTTP nella maggior parte dei casi lo rendono più attraente rispetto ad altre soluzioni per protocolli distribuiti. SOAP fornisce un elevato grado di interoperabilità con altre applicazioni, di cui ho parlato più dettagliatamente nel mio libro. Per ora, voglio concentrarmi sugli elementi fondamentali di SOAP.

Busta

Una busta SOAP è simile a una normale busta da lettera. Contiene informazioni sul messaggio che verrà crittografato nella sezione SOAP principale, incluse informazioni sul destinatario e sul mittente, nonché informazioni sul messaggio stesso. Ad esempio, l'intestazione della busta SOAP può indicare come deve essere elaborato il messaggio. Prima che un'applicazione inizi a elaborare un messaggio, esamina le informazioni sul messaggio, incluso se è in grado di elaborarlo. A differenza delle chiamate XML-RPC standard (ricordate? Messaggi XML-RPC, crittografia, ecc., tutto è combinato in un unico frammento XML), con SOAP avviene l'elaborazione continua per apprendere qualcosa sul messaggio. Un tipico messaggio SOAP può includere anche uno stile di crittografia che aiuterà il destinatario nell'elaborazione del messaggio. L'Esempio 12-1 mostra una busta SOAP che termina con una specifica di codifica.

Esempio 12-1: Busta SOAP

Soapbox http://www-106.ibm.com/developerworks/library/x-soapbx1.html

Come puoi vedere, all'interno della busta viene impostata la crittografia, che consente all'applicazione di determinare (utilizzando l'attributo value codificaStyle), se può leggere il messaggio in arrivo situato nell'elemento Corpo. Assicurati che lo spazio dei nomi della busta SOAP sia corretto, altrimenti i server SOAP che ricevono il tuo messaggio segnaleranno un errore di mancata corrispondenza della versione e non sarai in grado di comunicare con loro.

Crittografia

Il secondo elemento importante di SOAP è la capacità di crittografare tipi di dati personalizzati. Con RPC (e XML-RPC), la crittografia può essere eseguita solo su tipi di dati predefiniti supportati nel toolkit XML-RPC scaricato. La crittografia di altri tipi di dati richiede la modifica personale del server e del client RPC. Con SOAP, uno schema XML può essere utilizzato abbastanza facilmente per specificare nuovi tipi di dati (utilizzando la struttura tipocomplesso, discusso nel capitolo 2 del mio libro) e questi nuovi tipi possono essere rappresentati in XML come parte della sezione principale di SOAP. Grazie all'integrazione di XML Schema, puoi crittografare qualsiasi tipo di dato contenuto in un messaggio SOAP descrivendolo logicamente in uno schema XML.

Chiamata

Il modo migliore per capire come funziona una chiamata SOAP è confrontarla con qualcosa con cui hai familiarità, come XML-RPC. Se ricordi, la chiamata XML-RPC è simile allo snippet di codice presentato nell'Esempio 12-2.

Esempio 12-2. Chiamata a XML-RPC

// Specifica del processore XML (parser) da utilizzare XmlRpc.setDriver("org.apache.xerces.parsers.SAXParser"); // Specificare il server a cui viene effettuata la connessione XmlRpcClient client = new XmlRpcClient("http://rpc.middleearth.com"); // Creazione dei parametri Vector params = new Vector(); params.addElement(numerovolo); params.addElement(numSeats); params.addElement(creditCardType); params.addElement(NumeroCartaCredito); // Richiesta booleana buyTickets = (Boolean)client.execute("ticketCounter.buyTickets", params); // Elabora la risposta

Ho creato un semplice programma per ordinare i biglietti aerei. Ora diamo un'occhiata all'Esempio 12-3, che mostra una chiamata SOAP.

Esempio 12-3. Chiama SOAP

// Creazione dei parametri Vector params = new Vector(); params.addElement(new Parametro("flightNumber", Integer.class, flightNumber, null)); params.addElement(new Parametro("numSeats", Integer.class, numSeats, null)); params.addElement(new Parametro("creditCardType", String.class, creditCardType, null)); params.addElement(new Parametro("CreditCardNumber", Long.class, creditCardNum, null)); // Creazione di un oggetto Call Call call = new Call(); call.setTargetObjectURI("urn:xmltoday-airline-tickets"); call.setMethodName("acquistaBiglietti"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); call.setParams(parametri); // Risposta alla chiamata res = call.invoke(new URL("http://rpc.middleearth.com"), ""); // Elabora la risposta

Come puoi vedere, la chiamata effettiva rappresentata dall'oggetto Chiamata, residente nella memoria. Consente di specificare la destinazione della chiamata, il metodo di chiamata, lo stile di crittografia, i parametri e molti altri parametri non presentati in questo esempio. Si tratta di un meccanismo più flessibile rispetto al metodo XML-RPC, che consente di specificare esplicitamente un insieme di parametri diversi definiti implicitamente in XML-RPC. Più avanti in questo articolo imparerai di più sul processo di chiamata, incluso il modo in cui SOAP gestisce le richieste non valide, la gerarchia degli errori e, ovviamente, i risultati della chiamata restituiti.

Dopo una così breve introduzione, ne sai già abbastanza per interessarti a questa cosa divertente. Ora lascia che ti presenti l'implementazione SOAP che utilizzerò. Spiegherò i motivi per cui l'ho scelto e guarderò alcuni esempi di codice.

Impostazioni

Ora che hai imparato le basi del concetto, è il momento della parte divertente: la programmazione. Per fare ciò, avrai bisogno di un progetto o di un prodotto conveniente, che sia più facile da trovare di quanto possa sembrare a prima vista. Se hai bisogno di un progetto Java che fornisca funzionalità SOAP, non devi cercare a lungo per trovarne uno. Esistono due gruppi di prodotti: commerciali e gratuiti. Come nel mio libro, eviterò di menzionare prodotti commerciali. Questo non è affatto perché siano cattivi (al contrario, alcuni sono eccellenti), ma perché vorrei che ogni lettore potesse provare qualcuno degli esempi forniti. Ciò è dovuto all'accessibilità, che molti prodotti commerciali non hanno. È necessario pagare per utilizzarli o utilizzarli temporaneamente per un periodo di tempo limitato dopo il download.

Pertanto, abbiamo affrontato senza problemi i progetti open source. Di quest'area posso citare un solo prodotto: Apache SOAP. Si trova su http://xml.apache.org/soap e fornisce il toolkit SOAP per Java. Nel momento in cui scriviamo è stata rilasciata la versione 2.2, che potete scaricare dal sito Apache. È questa versione che userò negli esempi di questo articolo.

Altre alternative

Prima di passare all'installazione e alla configurazione di Apache SOAP, risponderò ad alcune domande che potrebbero esserti passate per la mente. Credo di aver spiegato abbastanza chiaramente i motivi per cui non utilizzo prodotti commerciali. Tuttavia, potresti pensare ad altri progetti open source o correlati che potresti voler utilizzare e sei sorpreso che non li abbia commentati.

E che dire di IBM SOAP4J?

La prima nell'elenco delle alternative è un'implementazione di IBM: SOAP4J. Il lavoro di IBM ha costituito la base del progetto Apache SOAP, proprio come XML4J di IBM è cresciuto in quello che oggi è noto come progetto di parser XML Apache Xerces. Si presume che l'implementazione IBM verrà riprogettata, fondendosi con Apache SOAP. Più o meno la stessa cosa è successa con XML4J di IBM: ora fornisce solo pacchetti in Xerces, il che evidenzia solo le tendenze: i grandi produttori spesso supportano e utilizzano progetti OpenSource, in questo caso entrambi i progetti (Apache e IBM) utilizzano la stessa base di codice.

Microsoft è fuori dai giochi?

Ovviamente no. Microsoft e la sua implementazione SOAP, così come l'intero movimento .NET (discusso più in dettaglio nel mio libro), sono piuttosto significativi. Volevo davvero dedicare la maggior parte del mio tempo a esaminare in dettaglio l'implementazione SOAP di Microsoft, ma supporta solo oggetti COM e non supporta Java. Per questi motivi, tale descrizione non potrebbe essere inclusa in un articolo su Java e XML. Tuttavia, Microsoft (nonostante tutte le lamentele che noi, come sviluppatori, abbiamo nei confronti di questa azienda) ha svolto un lavoro importante nel campo dei servizi web, e commetterai un errore se lo scarterai senza pensarci, guidato solo da emozioni grezze. Se hai bisogno di lavorare con componenti COM o Visual Basic, ti consiglio vivamente di provare a utilizzare il toolkit SOAP di Microsoft, disponibile all'indirizzo http://msdn.microsoft.com/library/default.asp?url=/nhp/Default .asp ?contentid=28000523 insieme a molte altre risorse SOAP.

Cos'è l'Asse?

Quelli di voi che seguono le attività di Apache devono aver sentito parlare di Apache Axis. Axis è un toolkit SOAP di nuova generazione sviluppato anch'esso sotto l'ombrello Apache XML. SOAP (una specifica, non un'implementazione specifica), che si è sviluppata rapidamente e radicalmente negli ultimi tempi, è molto difficile da seguire. Anche provare a creare una versione di SOAP che soddisfi pienamente i requisiti attuali man mano che si evolvono è piuttosto impegnativo. Di conseguenza, la versione attuale di Apache SOAP offre una soluzione limitata dalla sua progettazione. Avendo deciso che non valeva la pena provare a riprogettare completamente lo strumento esistente, gli sviluppatori Apache hanno iniziato a creare un progetto basato sul nuovo codice. Così è nato Axis. Anche il nome di SOAP è cambiato, prima da SOAP a XP e poi a XMLP. Successivamente il nome della specifica venne eliminato dal nome del nuovo SOAP e nacque il nome "Axis". Ma ora sembra che il W3C stia tornando al nome della specifica SOAP (versione 1.2 o 2.0), quindi le cose potrebbero ancora cambiare e ci sarà ancora più confusione!

Pensa a IBM SOAP4J come a un'architettura1 del toolkit SOAP. Che dire di Apache SOAP (discusso in questo articolo) come architettura?2. E Axis rappresenta l'architettura ?3, un'architettura di nuova generazione. Questo progetto utilizza SAX mentre Apache SOAP è basato su DOM. Inoltre, Axis, a differenza di Apache SOAP, fornisce un approccio più intuitivo all'interazione dell'utente. Dopo aver elencato questi vantaggi, potresti chiederti perché non ho scelto Axis come materia di studio. Sarebbe semplicemente un po' prematuro. Attualmente è in preparazione il rilascio solo della versione 0.51 di Axis. Questa non è ancora una beta, e nemmeno una versione alpha. Mi piacerebbe parlare delle nuove funzionalità di Axis, ma non avresti alcuna possibilità di convincere il tuo management che puoi utilizzare software open source sub-alpha per le esigenze critiche del tuo sistema. Quindi ho deciso di concentrarmi su qualcosa che sei reale Puoi usare Già Oggi-Sapone Apache. Penso che quando verrà rilasciata la versione finale di Apache Axis, aggiornerò questo materiale nella prossima edizione del mio libro. Fino ad allora, concentriamoci sulla soluzione già disponibile.

Installazione

Esistono due forme possibili di installazione SOAP. Il primo consiste nell'avviare un client SOAP utilizzando l'API SOAP per comunicare con un server in grado di accettare messaggi SOAP. Il secondo modo consiste nell'eseguire un server SOAP in grado di ricevere messaggi da un client SOAP. In questa sezione ho descritto entrambe le procedure.

Cliente

Per utilizzare il client SOAP, è necessario prima scaricare Apache SOAP, disponibile all'indirizzo http://xml.apache.org/dist/soap. Ho scaricato la versione 2.2 in formato binario (dalla sottodirectory versione-2.2). Successivamente devi decomprimere il contenuto dell'archivio in una directory sul tuo computer. Nel mio caso era la directory javaxml2 (c:\javaxml2 sul mio computer Windows /javaxml2 sul mio computer Mac OS X). Di conseguenza, i file sono stati decompressi in /javaxml2/soap-2_2. Sarà inoltre necessario scaricare il pacchetto JavaMail disponibile da Sun http://java.sun.com/products/javamail/. Sarà necessario supportare il protocollo di trasferimento SMTP utilizzato da Apache SOAP. Quindi scaricare Java Beans Activation Framework (JAF), disponibile anche da Sun http://java.sun.com/products/beans/glasgow/jaf.html. Basato sul presupposto che tu abbia già Xerces o un altro parser XML installato e pronto per l'uso.

Nota: Assicurati che il tuo parser XML sia compatibile con JAXP e utilizzi correttamente lo spazio dei nomi. Molto probabilmente il tuo parser soddisfa questi requisiti. Se riscontri problemi, è meglio tornare a utilizzare Xerces.

Nota: Utilizza le ultime versioni di Xerces. La versione 1.4 e successive andranno bene. Sono presenti numerosi bug con SOAP e Xerces 1.3(.1), quindi sconsiglio di utilizzare questa combinazione.

Decomprimi i pacchetti JavaMail e JAF e includi i relativi file jar nel classpath e nella libreria vaso.sapone. Ciascuno di questi file jar deve trovarsi nella directory principale del programma corrispondente o in una sottodirectory /lib. Una volta terminata la tua variabile percorso di classe dovrebbe assomigliare a questo:

$ echo $CLASSPATH /javaxml2/soap-2_2/lib/soap.jar:/javaxml2/lib/xerces.jar: /javaxml2/javamail-1.2/mail.jar:/javaxml2/jaf-1.0.1/activation.jar

Per Windows sarà simile a questo:

c:\>echo %CLASSPATH% c:\javaxml2\soap-2_2\lib\soap.jar;c:\javaxml2\lib\xerces.jar; c:\javaxml2\javamail-1.2\mail.jar;c:\javaxml2\jaf-1.0.1\activation.jar

E infine aggiungi la directory javaxml2/soap-2_2/ nel tuo percorso di classe per eseguire esempi SOAP. In questo capitolo ho descritto la configurazione di diversi esempi.

server

Per creare un insieme di componenti server compatibili con SOAP, è necessario innanzitutto un motore servlet. Come nei capitoli precedenti, ho utilizzato Apache Tomcat (disponibile su http://jakarta.apache.org/) come esempio per questo capitolo. Dovrai aggiungere tutto ciò di cui il cliente ha bisogno percorso di classe server. Il modo più semplice per farlo è ripristinare vaso.sapone, attivazione.jar E mail.jar, così come il tuo parser, nella directory delle librerie del tuo motore servlet. Per Tomcat, questa è la directory /lib, che contiene le librerie per il caricamento automatico. Se si desidera fornire supporto per gli script (che non sono discussi in questo capitolo, ma sono presenti negli esempi SOAP di Apache), è necessario inserire bsf.jar(disponibile all'indirizzo http://oss.software.ibm.com/developerworks/projects/bsf) e js.jar(disponibile su http://www.mozilla.org/rhino/) nella stessa directory.

Nota: Se stai utilizzando Xerces con Tomcat, dovrai ripetere il trucco che ho trattato nel capitolo 10. Rinomina parser.jar V z_parser.jar, UN jaxp.jar V z_jaxp.jar per assicurartene xerces.jar e la versione inclusa di JAXP viene caricata prima di qualsiasi altro parser o implementazione JAXP.

Quindi riavvia il motore servlet e sei pronto per scrivere i componenti del server SOAP.

Servlet del router e client di amministrazione

Oltre alle operazioni di base, Apache SOAP include un servlet del router e un client di amministrazione. Anche se non intendi utilizzarli, ti consiglio di installarli per verificare che SOAP sia installato correttamente. Questo processo dipende dal motore servlet che stai utilizzando, quindi limiterò il processo di installazione a Tomcat. Le istruzioni di installazione per alcuni altri motori servlet possono essere trovate su http://xml.apache.org/soap/docs/index.html.

L'installazione su Tomcat è molto semplice: basta prendere il file soap.war dalla directory sapone-2_2/webapps e rilascialo nella directory $TOMCAT_HOME/webapp- e basta! Per verificare l'installazione, inserisci l'indirizzo nel tuo browser http://localhost:8080/soap/servlet/rpcrouter. Dovreste ricevere una risposta simile a quella mostrata nella Figura 12-2.

Figura 12-2. Servlet RPC del router

Sebbene il messaggio sembri un messaggio di errore, indica che tutto funziona correttamente. Dovresti ottenere la stessa risposta se indirizzi il browser all'indirizzo del client dell'amministratore: http://localhost:8080/soap/servlet/messagerouter.

Per completare il test del server e del client, assicurati di aver seguito completamente tutte le istruzioni. Quindi esegui la seguente classe Java come mostrato di seguito per supportare l'URL del servlet per il servlet del router RPC:

C:\>java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter elenco Servizi distribuiti:

Dovresti ottenere un elenco vuoto di servizi come mostrato sopra. Se ricevi qualche messaggio, consulta il lungo elenco di possibili errori disponibile su http://xml.apache.org/soap/docs/trouble/index.html. Questo è l'elenco più completo dei problemi che potresti riscontrare. Se ricevi un elenco vuoto, significa che la configurazione è completa e sei pronto per iniziare a guardare gli esempi forniti in questo capitolo.

Iniziamo

Esistono tre fasi principali nella scrittura di qualsiasi sistema basato su SOAP. Dopo averli elencati, discuterò brevemente ciascuno di essi:

  • Scelta tra messaggi SOAP-RPC e SOAP;
  • Scrivere o accedere a un servizio SOAP;
  • Scrivere o accedere a un client SOAP.

Il primo passo è scegliere se utilizzare SOAP per le chiamate RPC (in cui viene eseguita una procedura remota sul server) o per i messaggi (in cui il client invia semplicemente informazioni al server). Discuterò questi processi in dettaglio di seguito. Una volta presa questa decisione, dovrai accedere o creare il tuo servizio. Naturalmente, poiché siamo tutti professionisti Java, questo capitolo spiega come crearne uno personalizzato. E infine, devi scrivere un cliente per questo servizio, tutto qui!

RPC o messaggistica?

Il tuo primo compito non ha nulla a che fare con la programmazione ed è più di natura progettuale. Devi scegliere se utilizzerai il servizio RPC o i messaggi. Daremo per scontato che tu abbia familiarità con RPC (ad esempio leggendo uno dei capitoli del mio libro). Il client esegue una procedura remota sul server e quindi riceve una risposta. In questo scenario, SOAP agisce come un sistema XML-RPC avanzato che fornisce una migliore gestione degli errori e un migliore trasferimento di tipi di dati complessi sulla rete. Questo concetto è già familiare e poiché i sistemi RPC sono più facili da scrivere in SOAP, inizierò con essi. In questo articolo viene descritto come creare un servizio RPC, un client RPC e mettere in produzione il sistema.

Un altro modo di lavorare SOAP è basato sullo scambio di messaggi. Invece di eseguire procedure remote, viene utilizzato solo per lo scambio di informazioni. Come puoi immaginare, questo è uno strumento potente che non richiede che il client conosca i singoli metodi di alcun server. Rende inoltre più isolata la modellazione dei sistemi remoti consentendo l'invio di pacchetti di dati (pacchetti in senso figurato, non nel senso di rete) ad altri sistemi. Allo stesso tempo, altri sistemi non hanno bisogno di conoscere le operazioni eseguite con questi dati. Questo stile è più complesso della programmazione RPC, quindi non lo descriverò qui. Lo troverete nel mio libro, insieme ad altri dettagli sull'interazione business-to-business. Innanzitutto, familiarizza con la programmazione SOAP-RPC.

Come la maggior parte dei problemi di progettazione, prendere questa decisione dipende da te. Analizza la tua applicazione e prova a determinare perché è necessario utilizzare SOAP. Se disponi di un server e di una serie di client che eseguono funzioni aziendali specifiche su richiesta, RPC è più adatto a te. Nei sistemi complessi in cui lo scambio di dati va oltre la semplice esecuzione di specifiche funzioni aziendali su richiesta, l'uso dei messaggi SOAP è di gran lunga preferibile.

Servizio RPC

Ora che le formalità sono finite è tempo di agire. Come sai, in RPC avrai bisogno di classi i cui metodi verranno eseguiti in remoto.

Frammenti di codice

Inizierò esaminando alcuni frammenti di codice per il server. Questi frammenti sono classi con metodi eseguiti per i client RPC. Ho usato il codice del mio libro come esempi. Invece di utilizzare classi semplici, ho scelto un esempio più complesso per dimostrare nel modo più chiaro possibile le funzionalità di SOAP. Quindi, ho usato la classe CD come esempio. Per prima cosa definiamo l'elemento carta geografica per ogni tipo di parametro non standard. Per attributo codificaStyle, almeno in Apache SOAP 2.2. è necessario fornire il valore http://schemas.xmlsoap.org/soap/encoding/ . Questa è attualmente l'unica codifica supportata. È necessario specificare lo spazio dei nomi per il tipo definito dall'utente e quindi il nome della classe con il prefisso dello spazio dei nomi per quel tipo. Nel nostro caso, per questi scopi ho utilizzato un namespace fittizio e un semplice prefisso " X". Quindi utilizzando l'attributo javaType, imposta il nome reale della classe Java (in questo caso - javaxml2.CD). E infine, Kuralesil con attributi java2XMLNomeClasse E xml2NomeClasseJava. Con il loro aiuto, viene specificata una classe che viene convertita da Java a XML e viceversa. Ho utilizzato la classe BeanSerializer, incredibilmente pratica, inclusa anch'essa in Apache SOAP. Se il tuo parametro personalizzato è in formato JavaBean, questo serializzatore e deserializzatore ti eviterà la necessità di scriverne uno tuo. Hai bisogno di una classe con un costruttore predefinito (ricorda, per la classe CD ho definito un costruttore semplice e senza parametri) e pubblica tutti i dati di questa classe utilizzando i metodi setXXX E prendiXXX. Perché classe CD soddisfa perfettamente tutti questi requisiti, BeanSerializer funziona perfettamente.

Nota: Che classe CD soddisfa i requisiti BeanSerializer. non importa molto. La maggior parte delle classi può essere facilmente convertita in questo formato. Pertanto, consiglio di evitare di scrivere i propri serializzatori e deserializzatori. Questo è un ulteriore grattacapo (niente di complicato, ma troppo scrupoloso) e ti consiglio di risparmiare energia e utilizzare la conversione bean nei parametri personalizzati. In molti casi, le conversioni dei bean richiedono solo un costruttore predefinito (nessun parametro) nella classe.

Ora ricreamo vaso archiviare e reinstallare il nostro servizio:

(gandalf)/javaxml2/Ch12$ java org.apache.soap.server.ServiceManagerClient http://localhost:8080/soap/servlet/rpcrouter xml/CDatalogDD.xml

Attenzione: Se lasci il motore servlet in esecuzione e allo stesso tempo riallochi un servizio, dovrai riavviare il motore servlet per abilitare le nuove classi per il servizio SOAP e riallocare il servizio.

Ora non resta che modificare il client per utilizzare nuove classi e metodi. L'esempio 12-10 contiene una versione modificata della classe client CDAdder. Le modifiche apportate alla versione precedente sono evidenziate.

Esempio 12-10: classe CDAdder aggiornata

pacchetto javaxml2; importa java.net.URL; import java.util.Vector; import org.apache.soap.Constants; importare org.apache.soap.Fault; import org.apache.soap.SOAPException; importare org.apache.soap.encoding.SOAPMappingRegistry; import org.apache.soap.encoding.soapenc.BeanSerializer; importare org.apache.soap.rpc.Call; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response; importa org.apache.soap.util.xml.QName; classe pubblica CDAdder( public void add(URL URL, titolo stringa, artista stringa, etichetta stringa) genera SOAPException ( System.out.println("Aggiunta di un CD con il titolo "" + titolo + "" artista "" + artista + "" studio " + etichetta); CD cd = nuovo CD(titolo, artista, etichetta); // Crea un oggetto chiamata Call Call call = new Call(); call.setSOAPMappingRegistry(registro); call.setTargetObjectURI("urna:cd-catalogo"); call.setMethodName("aggiungiCD"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); // Impostazione dei parametri Vector params = new Vector(); params.addElement(new Parametro("cd", CD.class, cd, null)); call.setParams(parametri); // Elaborazione della risposta Invoke call Response; risposta = call.invoke(url, ""); if (!response.generatedFault()) ( System.out.println("Aggiunta CD completata con successo."); ) else ( Errore errore = risposta.getFault(); System.out.println(Errore: " + errore.getFaultString ()); ) ) public static void main(String args) ( if (args.length != 4) ( System.out.println("Modello: java javaxml2.CDAdder " + "\"[Titolo CD]\" \"[Nome artista]\ " \"[CD Studio]\""); ritorno; ) try ( // URL del server SOAP a cui viene effettuata la connessione URL url = new URL(args); // Ottieni valori per il nuovo CD String title = args; Artista degli archi = args; Etichetta stringa = args; // Aggiunge il CD CDAdder adder = new CDAdder(); adder.add(url, titolo, artista, etichetta); ) catch (Eccezione e) ( e.printStackTrace(); ) ) )

L'unico cambiamento veramente interessante è nella mappatura delle classi CD:

// Mappare questo tipo in modo che possa essere utilizzato con il registro SOAP SOAPMappingRegistry = new SOAPMappingRegistry(); Serializzatore BeanSerializer = new BeanSerializer(); Registry.mapTypes(Constants.NS_URI_SOAP_ENC, new QName("urn:cd-catalog-demo", "cd"), CD.class, serializer, serializer);

Ecco come un parametro utente può essere codificato e trasmesso sulla rete. Ti ho già detto come funziona la lezione BeanSerializer può essere utilizzato per elaborare parametri in formato JavaBean, come class CD. Ho utilizzato un descrittore di posizionamento per indicarli al server, anche se ora devo dire al client di utilizzare questo serializzatore e deserializzatore. Questa funzione è svolta dalla classe SOAPMappingRegistry. Metodo tipi di mappa() prende la stringa crittografata (di nuovo, è meglio usare una costante per questo NS_URI_SOAP_ENC) e informazioni sul tipo di parametro per il quale deve essere utilizzata la serializzazione speciale. Il QName viene specificato per primo. Questo è il motivo per cui nel descrittore dell'hosting è stato utilizzato lo strano spazio dei nomi. È necessario fornire qui lo stesso URN, così come il nome locale dell'elemento (per questo esempio "CD"), quindi l'oggetto Java Classe classe che verrà serializzata ( CD.class) e infine un'istanza della classe per la serializzazione e la deserializzazione. Per questo esempio, entrambi i casi coinvolgeranno un'istanza BeanSerializer. Una volta inserite tutte queste impostazioni nel registro, notificare l'oggetto Chiamata utilizzando il metodo setSOAPMapping-Registro().

Puoi eseguire questa classe come mostrato in precedenza, aggiungendo un CD e tutto dovrebbe funzionare come previsto:

C:\javaxml2\build>java javaxml2.CDAdder http://localhost:8080/soap/servlet/rpcrouter "Tony Rice" "Manzanita" "Sugar Hill" Aggiunta di un CD intitolato "Tony Rice" di "Manzanita" di Sugar Hill Aggiunta di un CD con successo.

Ho lasciato la modifica della classe CDLister per te. Tutto è prodotto secondo lo stesso modello. Per metterti alla prova puoi fare riferimento ai file di esempio del mio libro, che contengono già queste classi aggiornate.

Nota: puoi deciderlo perché il class CDLister non interagisce direttamente con l'oggetto CD(restituito con metodo elenco() il tipo conta Tabella hash), non sarà necessario apportare alcuna modifica. Tuttavia, la classe restituita Tabella hash contiene istanze di oggetti CD. Se SOAP non sa come deserializzarli, il client genererà un errore. In questo caso per risolvere il problema è necessario specificarlo nell'oggetto Chiamata copia SOAPMappingRegistry.

Gestione efficiente degli errori

Ora che avete visto gli oggetti personalizzati ed effettuato chiamate RPC e simili, lasciatemi parlare di un argomento meno interessante: la gestione degli errori. Con qualsiasi transazione di rete possono verificarsi molti errori. Il servizio non si avvia, c'è un errore nel server, non si trova un oggetto, mancano le classi e tanti altri problemi. Finora ho semplicemente utilizzato il metodo errore.getString() per generare messaggi di errore. Ma questo metodo potrebbe non essere sempre utile. Per vederlo in azione, decommenta il costruttore CDCatalog:

CDCatalog pubblico() ( //catalogo = new Hashtable(); // Crea una directory addCD(new CD("Nickel Creek", "Nickel Creek", "Sugar Hill")); addCD(nuovo CD("Let it Fall", "Sean Watkins", "Sugar Hill")); addCD(nuovo CD("Aerial Boundaries", "Michael Hedges", "Windham Hill")); addCD(nuovo CD("Taproot", "Michael Hedges", "Windham Hill")); )

Ricompilalo, riavvia il motore servlet e riorganizzalo. Ciò comporterà un'eccezione NullPointerException quando il costruttore della classe tenta di aggiungere CD a non inizializzato Tabella hash. All'avvio del client, verrà visualizzato un messaggio di errore, ma non sarà molto informativo:

(gandalf)/javaxml2/build$ java javaxml2.CDLister http://localhost:8080/soap/servlet/rpcrouter Visualizza la directory del CD corrente. Errore: impossibile risolvere l'oggetto di destinazione: null

Queste non sono affatto le informazioni che possono aiutare a identificare e correggere un errore. Tuttavia, il framework gestisce correttamente la gestione degli errori. Ti ricordi DOMFaultListener, che hai specificato come valore dell'elemento erroreListener? È giunto il momento per lui di entrare in gioco. Oggetto restituito in caso di errore Colpa contiene il DOM (Document Object Model) org.w3c.dom.Element con informazioni dettagliate sull'errore. Per prima cosa aggiungi un'espressione di importazione al tuo codice sorgente java.util.Iterator:

importa java.net.URL; import java.util.Enumerazione; importa java.util.Hashtable; import java.util.Iterator; import java.util.Vector; import org.apache.soap.Constants; importare org.apache.soap.Fault; import org.apache.soap.SOAPException; importare org.apache.soap.encoding.SOAPMappingRegistry; import org.apache.soap.encoding.soapenc.BeanSerializer; importare org.apache.soap.rpc.Call; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response; importa org.apache.soap.util.xml.QName;

Ora apportiamo le modifiche per gestire gli errori nel metodo list():

if (!response.generatedFault()) ( Parametro returnValue = risposta.getReturnValue(); Hashtable catalog = (Hashtable)returnValue.getValue(); Enumerazione e = catalog.keys(); while (e.hasMoreElements()) ( String titolo = (String)e.nextElement(); CD cd = (CD)catalog.get(titolo); System.out.println(" "" + cd.getTitle() + "" artista " + cd.getArtist() + " studios " + cd.getLabel()); ) ) else ( Errore errore = risposta.getFault(); System.out.println("Errore: " + errore.getFaultString()); Voci del vettore = fault.getDetailEntries(); for (Iterator i = entry.iterator(); i.hasNext();) ( org.w3c.dom.Element entry = (org.w3c.dom.Element)i.next(); System.out.println(entry .getFirstChild().getNodeValue()); ) )

Utilizzando il metodo getDetailEntries() hai accesso al servizio SOAP e al server dei dati grezzi che supporta il problema. Il codice li rielabora (di solito c'è un solo elemento, ma richiede molta attenzione) e intercetta il DOM Elemento, contenuto in ogni voce. Essenzialmente, ecco l'XML con cui stai lavorando:

SOAP-ENV:Server.BadTargetObjectURI Impossibile risolvere l'obiettivo: null Questo è ciò che vogliamo!

In altre parole, l'oggetto Fault consente di accedere alla parte della busta SOAP che contiene errori. Inoltre, Apache SOAP fornisce una traccia dello stack Java quando si verificano errori, fornendo le informazioni dettagliate necessarie per correggerli. Intercettare un elemento stackTrace e stampando il valore del nodo Testo da questo elemento il tuo client può stampare la traccia dello stack del server. Compilando queste modifiche e riavviando il client otterrai il seguente risultato:

C:\javaxml2\build>java javaxml2.CDLister http://localhost:8080/soap/servlet/rpcr external Visualizza la directory del CD corrente. Errore: impossibile risolvere la destinazione: null java.lang.NullPointerException in javaxml2.CDatalog.addCD(CDatalog.java:24) in javaxml2.CDatalog. (CDCatal.java:14) in java.lang.Class.newInstance0 (metodo nativo) in java.lang.Class.newInstance(Class.java:237)

Non è molto meglio, ma almeno puoi vedere alcune informazioni che indicano che si è verificata un'eccezione NullPointerException e persino scoprire i numeri di riga nelle classi server in cui si è verificato questo problema. Il risultato di queste recenti modifiche ha fornito un quadro chiaro del problema di gestione degli errori. Ora dovresti controllare la presenza di errori nelle classi del server. Sì, quasi dimenticavo, prima non dimenticare di cambiare la tua classe CDCatalog per eliminare gli errori che abbiamo intenzionalmente introdotto per chiarezza!

  1. Si parla molto dell'esecuzione di SOAP su altri protocolli come SMTP (o anche Jabber). Lo standard SOAP attualmente non lo fornisce, ma funzionalità simili potrebbero essere aggiunte in futuro. Pertanto, non sorprenderti se incontri discussioni attive su questo argomento.

Non mi soffermerò sulla questione di cosa sia servizi web e perché sono necessari. Ci sono molti articoli su questo argomento su Internet. Cercherò solo di mostrare brevemente quanto sia semplice creare un client per qualsiasi servizio web in PHP.

Impostazioni

Per uso SAPONE in php è necessario collegare il modulo SOAP (incluso nella distribuzione php5). Sotto Windows, questo viene fatto semplicemente: devi aggiungere (vale a dire aggiungere, poiché questa riga non è solo commentata, manca del tutto) in php.ini:
estensione=php_soap.dll

Non dimenticare di riavviare il server se hai php installato come modulo.


Creazione di un client SOAP da un documento WSDL

La creazione di un client SOAP avviene solitamente entro Documento WSDL, che è un documento XML in un formato specifico che descrive completamente un particolare servizio web. Per dettagli su WSDL, vi rimando al sito web del consorzio W3C - http://www.w3.org/TR/2005/WD-wsdl20-soap11-binding-20050510/.

La cosa principale che devi sapere per creare un client per un servizio web è conoscere l'URL del suo documento WSDL.
Ad esempio, prendiamo il servizio web "Tasso di cambio valuta" da xmethods.com. L'indirizzo di questo servizio web, che consente di ricevere i tassi di cambio online, è http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl.

Il secondo punto importante è che dalla descrizione del servizio web è necessario ottenere informazioni su quali metodi fornisce questo servizio e quali parametri dovremmo passargli come valori di input (molto simile alla chiamata di una normale funzione o classe PHP metodo). Tipicamente queste informazioni sono contenute nella descrizione del servizio sul suo sito web. Il nostro servizio web per ottenere i tassi di cambio fornisce il metodo getRate(), al quale vengono passati i codici valuta come argomenti.

Infine, è importante sapere cosa aspettarsi come risposta: quanti valori, di che tipo, ecc. Questo può essere ricavato anche dalla descrizione.
E di conseguenza il codice risulta essere molto semplice e compatto, quasi elementare:

// Utilizzando il servizio Web
// "Tasso di cambio valuta" da xmethods.com

// Creazione di un client SOAP da un documento WSDL
$client = nuovo SoapClient("http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl");

// Invia una richiesta SOAP e ricevi il risultato
$risultato = $client->getRate("noi", "russia");

Echo 'Tasso di cambio attuale del dollaro: ', $risultato, 'rubli';
?>

Come puoi vedere dal codice, devi passare l'URL del documento WSDL al costruttore della classe SoapClient e ricevere un oggetto per lavorare con il servizio web desiderato. Quindi viene chiamato un metodo di questo oggetto, il cui nome è uguale al nome del metodo del servizio web stesso. Questo metodo restituisce il risultato che desideriamo.

Quindi, questo semplice esempio illustra il principio di creazione di un client SOAP per servizi Web in PHP. Tuttavia in un'applicazione reale c'è ancora molto da fare, in particolare il fatto che quando viene richiamato il servizio web, questo potrebbe essere temporaneamente non disponibile o restituire un errore. Suggerisce chiaramente di utilizzare un blocco provare/prendere/lanciare :)

(PHP5 >= 5.0.1)

SoapClient::SoapClient — Costruttore SoapClient

Parametri

wsdl

URI del WSDL file o NULLO se lavori in non WSDL modalità.

Durante lo sviluppo, la memorizzazione nella cache WSDL potrebbe essere disabilitata utilizzando il file soap.wsdl_cache_ttl php.ini altrimenti le modifiche apportate al file WSDL non avranno effetto fino al soap.wsdl_cache_ttlè scaduto.

opzioni

Una serie di opzioni. Se si lavora in modalità WSDL, questo parametro è facoltativo. Se si lavora in modalità non WSDL, il file posizione E uri le opzioni devono essere impostate, dove posizioneè l'URL del server SOAP a cui inviare la richiesta e uriè lo spazio dei nomi di destinazione del servizio SOAP.

IL stile E utilizzo le opzioni funzionano solo in modalità non WSDL. Nella modalità WSDL provengono dal file WSDL.

IL soap_version l'opzione specifica se utilizzare il client SOAP 1.1 (predefinito) o SOAP 1.2.

Per l'autenticazione HTTP, il login E parola d'ordine le opzioni possono essere utilizzate per fornire credenziali. Per effettuare una connessione HTTP tramite un server proxy, le opzioni host_proxy, porta proxy, proxy_login E password_proxy sono disponibili anche Per l'utilizzo dell'autenticazione del certificato client HTTPS local_cert E frase d'accesso opzioni. Un'autenticazione può essere fornita nel file autenticazione opzione. Il metodo di autenticazione può essere uno dei due SOAP_AUTHENTICATION_BASIC(predefinito) o SOAP_AUTHENTICATION_DIGEST.

IL compressione l'opzione consente di utilizzare la compressione delle richieste e delle risposte HTTP SOAP.

IL codifica l'opzione definisce la codifica interna dei caratteri. Questa opzione non modifica la codifica delle richieste SOAP (è sempre utf-8), ma converte le stringhe in essa.

IL traccia L'opzione consente il tracciamento della richiesta in modo da poter risalire agli errori. L'impostazione predefinita è FALSO

IL mappa di classe l'opzione può essere utilizzata per mappare alcuni tipi WSDL su classi PHP. Questa opzione deve essere un array con tipi WSDL come chiavi e nomi di classi PHP come valori.

Impostazione del valore booleano traccia L'opzione consente l'uso dei metodi SoapClient->__getLastRequest , SoapClient->__getLastRequestHeaders , SoapClient->__getLastResponse e SoapClient->__getLastResponseHeaders .

IL eccezioni opzione è un valore booleano che definisce se gli errori soap generano eccezioni di tipo SoapFault .

IL connesione finita l'opzione definisce un timeout in secondi per la connessione al servizio SOAP. Questa opzione non definisce un timeout per i servizi con risposte lente. Per limitare il tempo di attesa per il completamento delle chiamate, è disponibile l'impostazione default_socket_timeout.

IL typemap l'opzione è un array di mappature di tipi. La mappatura dei tipi è un array con chiavi nome_tipo, tipo_ns(URI dello spazio dei nomi), da_xml(callback che accetta un parametro di stringa) e a_xml(callback che accetta un parametro di oggetto).

IL cache_wsdl l'opzione è una di WSDL_CACHE_NONE, WSDL_CACHE_DISK, WSDL_CACHE_MEMORIA O WSDL_CACHE_BOTH.

IL utente_agente l'opzione specifica la stringa da utilizzare Agente utente intestazione.

IL contesto_stream l'opzione è per il contesto.

IL caratteristiche l'opzione è una maschera di bit di SOAP_SINGLE_ELEMENT_ARRAYS, SOAP_USE_XSI_ARRAY_TYPE, SOAP_WAIT_ONE_WAY_CALLS.

IL keep_alive l'opzione è un valore booleano che definisce se inviare il file Connessione: Keep-Alive intestazione o Connessione: chiusa .

Registro delle modifiche

Versione Descrizione
5.4.0 Nuovo keep_alive opzione.

Esempi

Esempio 1 SoapClient::SoapClient() esempio

$client = new SoapClient("some.wsdl");

$client = nuovo SoapClient ("some.wsdl" , array("soap_version" => SOAP_1_2 ));

$client = nuovo SoapClient ("some.wsdl" , array("login" => "some_name" ,
"password" => "qualche_password" ));

$client = nuovo SoapClient ("some.wsdl" , array("proxy_host" => "localhost" ,
"porta_proxy" => 8080 ));

$client = nuovo SoapClient ("some.wsdl" , array("proxy_host" => "localhost" ,
"porta_proxy" => 8080,
"proxy_login" => "qualche_nome" ,
"proxy_password" => "qualche_password" ));

$client = nuovo SoapClient ("some.wsdl", array("local_cert" => "cert_key.pem" ));

$client = new SoapClient (null , array("location" =>
"uri" => "http://test-uri/" ));

$client = new SoapClient (null, array("location" => "http://localhost/soap.php" ,
"uri" => "http://test-uri/" ,
"stile" => SOAP_DOCUMENT,
"usa" => SOAP_LITERAL ));

$client = new SoapClient("some.wsdl" ,
array("compressione" => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP ));

$server = nuovo SoapClient ("some.wsdl" , array("encoding" => "ISO-8859-1" ));

classe Il mio libro(
pubblico $titolo ;
pubblico $autore;
}

$server = nuovo SoapClient ("books.wsdl" , array("classmap" => array("book" => "MyBook" )));

?>

Chris Gunawardena

Per monitorare le chiamate SOAP in entrata e in uscita da un server UNIX:

Sudo tcpdump -nn -vv -A -s 0 -i eth0 dst o src host xxx.xxx.xxx.xxx e porta 80

E usa sempre "cache_wsdl" => WSDL_CACHE_NONE

svenr su selfhtml punto org

L'opzione "classmap" in realtà è una mappatura dal "ComplexType" utilizzato all'interno di SOAP alle tue classi PHP.

Non confondere i nomi dei tag XML restituiti per la tua richiesta con questi ComplexTypes. SOAP consente loro di essere diversi.

Avevo qualcosa del genere:
...


FooBar

TagName non è la chiave che vuoi inserire nella tua mappa di classe, devi conoscere il nome del ComplexType a cui fa riferimento questo TagName. Queste informazioni sono contenute nella risorsa WSDL.

paulovitorbal su Gmail punto com

Quando si utilizzano i certificati, nel parametro "local_cert", utilizzare il contenuto del file, non il nome del file.

Nuovo soapclient("http://localhost/index.php?wsdl ", array("local_cert"=>file_get_contents("./key.pem"),"passphrase"=>"password"));

In PHP, puoi avere proprietà private definite nelle classi che usi nella tua mappa di classe. Quindi, se crei una proprietà privata $foo nella tua classe e l'elemento SOAP ha un elemento figlio , il contenuto di $foo verrà impostato sul contenuto di . In questo modo puoi controllare l'accesso alle proprietà nelle tue classi.

(Nota: questo non funziona con HPHP di Facebook).

willem punto stuursma presso hyves punto nl

Se desideri utilizzare le classi in uno spazio dei nomi diverso nella mappa delle classi, utilizza semplicemente la barra rovesciata nel nome della classe di destinazione.

Esempio:
$classmap = array("risultato" => "MyNamespace\\Risultato" );
?>

È necessario specificare due volte la barra rovesciata perché è il carattere di escape nelle stringhe.

simonlang a gmx punto cap

Esempio per un client soap con autenticazione HTTP su un proxy:

nuovo SoapClient(
"servizio.wsdl" ,
vettore(
// Roba per lo sviluppo.
"traccia" => 1 ,
"eccezioni" => vero,
"cache_wsdl" => WSDL_CACHE_NONE,
"funzionalità" => SOAP_SINGLE_ELEMENT_ARRAYS,

// Credenziali di autenticazione per la richiesta SOAP.
"login" => "nome utente",
"password" => "password" ,

// URL proxy.
"proxy_host" => "esempio.com" , // Non aggiungere lo schema qui (http o https). Non funzionerà.
"porta_proxy" => 44300,

// Credenziali di autenticazione per il proxy.
"proxy_login" => NULL,
"proxy_password" => NULL,
);
?>
Fornire un URL a un file WSDL sul server remoto (che è anch'esso protetto con l'autenticazione HTTP) non ha funzionato.Ho scaricato il WSDL e l'ho archiviato sul server locale.

Asaf Meller

Una configurazione soap php .net completamente funzionante:
Appunti
1. web.config sul server .net deve funzionare con l'associazione basichttp.
2. i parametri alle funzioni soap devono essere passati come:
array("nome_parm1"=>"valore_parm1",
"parm2_nome"=>"parm2_valore"...)

header("Tipo di contenuto: testo/semplice");

Tentativo (
$opzioni = array(
"versione_soap" => SOAP_1_1,
"eccezioni" => vero,
"traccia" => 1 ,
"cache_wsdl" => WSDL_CACHE_NONE
);
$client = nuovo SoapClient ( "http://www.example.com/end_point.wsdl", $opzioni);

) catch (Eccezione $e ) (
eco "

Errore di eccezione!

" ;
echo $e -> getMessage();
}

Echo "in esecuzione HelloWorld:";

Tentativo (
$risposta = $cliente -> HelloWorld();

}
catch (Eccezione $e)
{
echo "Eccezione rilevata: " , $e -> getMessage (), "\n" ;
}

Print_r($risposta);
?>
buona fortuna!
Asaf.

faebu a faebu punto cap

Sto riscontrando gli stessi problemi quando provo a caricare un campo WDSL protetto dall'autenticazione http di base, poiché i parametri login e password vengono utilizzati solo per la richiesta ma non durante la lettura del file wdsl. Utilizzo semplicemente la seguente soluzione alternativa scaricando il file xml in una posizione non protetta sul mio server. Tieni presente che questo non supporta alcun tipo di memorizzazione nella cache.

la classe SoapAuthClient estende SoapClient (
/**
* Poiché il pacchetto SOAP PHP non supporta l'autenticazione di base
* questa classe scarica il file WDSL utilizzando il pacchetto cURL e
* crea una copia locale del wdsl sul tuo server.
*Assicurati di fornire il seguente parametro aggiuntivo nel file
* $opzioniArray:
* wdsl_local_copy => vero
*/

Privato $cache_dir = "/home/example/htdocs/cache/" ;
privato $cache_url = "http://www.example.com/cache/";

Funzione SoapAuthClient ($wdsl, $opzioni) (
if (isset($opzioni ["wdsl_local_copy"]) &&
$opzioni ["wdsl_local_copy"] == vero &&
isset($opzioni ["accedi"]) &&
isset($opzioni ["password"])) (

$file = md5(uniqid()). ".xml";

If (($fp = fopen ($this -> cache_dir . $file , "w")) == false ) (
lancia una nuova eccezione ( "Impossibile creare il file WDSL locale (". $questo -> dir_cache . $file. ")");
}

$ch = curl_init();
$credito = ($opzioni["login"]. ":" . $opzioni["password" ]);
curl_setopt($ch, CURLOPT_URL, $wdsl);
curl_setopt($canale, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt ($canale, CURLOPT_USERPWD, $credito);
curl_setopt($canale, CURLOPT_TIMEOUT, 15);
curl_setopt ($canale, CURLOPT_FILE, $fp);
if (($xml = curl_exec ($ch )) === false ) (
//curl_close($canale);
fclose($fp);
scollega ($this -> cache_dir. $file);

Genera una nuova eccezione (curl_error ($ ch));
}

Curl_close($canale);
fclose($fp);
$wdsl = $questo -> cache_url . $file;
}

Annulla impostazione ($ opzioni ["wdsl_local_copy"]);
unset($opzioni ["wdsl_force_local_copy"]);

Echo $wdsl;
genitore :: __construct ($wdsl, $opzioni);

Scollega ($this -> cache_dir. $file);
}
}
?>

tatupheba su Gmail punto com

Ciao gente!

Un suggerimento per gli sviluppatori:

Quando si programmano alcuni server soap, impostare la direttiva "soap.wsdl_cache_enabled" nel file php.ini su 0:

Soap.wsdl_cache_enabled=0

Altrimenti verranno visualizzati un sacco di strani errori che dicono che il tuo wsdl non è corretto o manca.

Farlo ti salverà da un sacco di dolore inutile.

titan su phpdevshell punto org

Va notato che se si riceve un errore di ritorno: "Riferimento oggetto non impostato su un'istanza di un oggetto.". Ciò potrebbe essere dovuto a qualcosa di semplice come il passaggio di parametri errati. Quando guardi questo XML:



corda
appuntamento
appuntamento

Il tuo codice dovrebbe assomigliare a questo:

Tentativo (
$opzioni = array(
"versione_soap" => SOAP_1_2,
"eccezioni" => vero,
"traccia" => 1 ,
"cache_wsdl" => WSDL_CACHE_NONE
);
$client = nuovo SoapClient ( "http://esempio.com/doc.asmx?WSDL", $opzioni);
// Nota dove si trovano i tag "Get" e "request" nell'XML
$risultati = $client -> Ottieni (array("richiesta" =>array("CustomerId" => "1234" )));
) catch (Eccezione $e ) (
eco "

Errore di eccezione!

" ;
echo $e -> getMessage();
}

$risultati = $client -> Ottieni (array("richiesta" =>array("CustomerId" => "842115" )));
?>

Se il tuo file WSDL contiene un parametro con un tipo base64Binary, non dovresti utilizzare base64_encode() quando passi le tue variabili soap. Quando si esegue la richiesta, la libreria SOAP base64 codifica automaticamente i tuoi dati, altrimenti li codificherai due volte.

Frammento WSDL:

$stringa = "dati_che_vuoi_inviare___come_xml_in_soap";
$dati_soap = array(
"foo" => "bar" ,
//"content" => base64_encode($string) // non farlo
"content" => $string //fai questo
);
$risposta = $client -> Invia ($soap_data);
?>

marcovtwout su hotmail punto com

Essendo nuovo in SOAP, ho cercato per un po' il motivo per cui il mio messaggio riceveva una risposta in soapUI, ma non con il mio codice php. Il servizio specifico a cui mi stavo rivolgendo fornisce un HTTP 202 Accettato in caso di successo (nessuna risposta), ma restituisce un messaggio SOAP in caso di errori.

Situazione:
Utilizzando una connessione client (autenticata) e un file WDSL, le chiamate SOAP con tipo "One-Way" non forniscono un'intestazione di risposta, anche se è prevista una risposta.

Soluzione:
Quando si chiama il costruttore client, impostare SOAP_WAIT_ONE_WAY_CALLS in $options["features"].

tim su tdinternet punto com

PHP 5.2.11 sembra non essere molto esigente riguardo alla correttezza di un WSDL.

Altri client SOAP si lamentavano di problemi di schema e spazio dei nomi, mentre SoapClient di PHP funzionava perfettamente. La risoluzione di questi problemi per gli altri client tuttavia danneggiava SoapClient di PHP al punto che gli oggetti passati al metodo SOAP diventavano array vuoti sul lato server.

Lezione appresa: alcuni elementi avevano il prefisso xsd: e altri no: assicurati assolutamente che il tuo WSDL sia corretto e coerente (sto usando un WSDL_Gen.php ottimizzato).

James punto Ellis su Gmail punto com

Ho riscontrato problemi nell'ottenere risposte da un server SOAP Coldfusion, senza problemi evidenti nel SoapClient utilizzato.

Alla fine ho scoperto che il server accettava solo richieste SOAP 1.1 e non 1.2. Non sono sicuro che si tratti di un'impostazione Coldfusion a livello di sistema, ma se colpisci lo stesso muro, prova a impostare l'opzione SoapClient "soap_version" sulla costante SOAP_1_1 (che è l'impostazione predefinita ma la mia era impostata su 1.2 poiché il client veniva riutilizzato per un altro servizio )

ajcartmell e fonant punto com

Sembra che ci sia un problema con la specifica di stringhe vuote per le opzioni proxy_host e proxy_port nelle recenti versioni di PHP (da una versione successiva alla 5.2.9 e uguale o precedente alla 5.2.11).

Fornire valori di stringa vuoti per proxy_host e proxy_port causa errori di tipo "host non trovato": fornire NULL o FALSE funziona correttamente.

bhargav punto khatana su Gmail punto com

Mi ci è voluta più di una settimana per capire come implementare le intestazioni WSSE (Web Service Security) nel SOAP PHP nativo. Non ci sono molte risorse disponibili su questo argomento, quindi ho pensato di aggiungerlo qui a beneficio della comunità.

Passaggio 1: crea due classi per creare una struttura per le intestazioni WSSE

classe clsWSSEAuth(
privato $Nomeutente;
$Password privata;
funzione __construct ($nome utente, $password) (
$questo -> Nome utente = $nomeutente;
$questo -> Password = $password;
}
}

Classe clsWSSEToken(
privato $NomeutenteToken;
funzione __costrutto ($innerVal)(
$this -> UsernameToken = $innerVal;
}
}
?>
Passaggio 2: creare variabili soap per nome utente e password

$nomeutente = 1111;
$password = 1111;

//Verifica con il tuo provider quale spazio dei nomi di sicurezza sta utilizzando.
$strWSSENS = "http://schemas.xmlsoap.org/ws/2002/07/secext";

$objSoapVarUser = new SoapVar($nomeutente, XSD_STRING, NULL, $strWSSENS, NULL, $strWSSENS);
$objSoapVarPass = new SoapVar($password, XSD_STRING, NULL, $strWSSENS, NULL, $strWSSENS);
?>
Passaggio 3: crea un oggetto per la classe di autenticazione e passa soap var

$objWSSEAuth = nuovo clsWSSEAuth ($objSoapVarUser, $objSoapVarPass);
?>
Passaggio 4: crea SoapVar dall'oggetto della classe Auth

$objSoapVarWSSEAuth= nuova SoapVar ($objWSSEAuth, SOAP_ENC_OBJECT, NULL, $strWSSENS, "UsernameToken", $strWSSENS);
?>
Passaggio 5: crea un oggetto per la classe token

$objWSSEToken = nuovo clsWSSEToken ($objSoapVarWSSEAuth);
?>
Passaggio 6: crea SoapVar dall'oggetto della classe Token

$objSoapVarWSSEToken= nuova SoapVar ($objWSSEToken, SOAP_ENC_OBJECT, NULL, $strWSSENS, "UsernameToken", $strWSSENS);
?>
Passaggio 7: creare SoapVar per il nodo "Sicurezza".

$objSoapVarHeaderVal=nuova SoapVar ($objSoapVarWSSEToken, SOAP_ENC_OBJECT, NULL, $strWSSENS, "Sicurezza", $strWSSENS);
?>
Passaggio 8: creare un oggetto intestazione dalla soapvar di sicurezza

$objSoapVarWSSEHeader= nuovo SoapHeader ($strWSSENS, "Sicurezza", $objSoapVarHeaderVal, true, "http://abce.com");

//Il terzo parametro qui rende "mustUnderstand=1
//Il quarto parametro genera "actor="http://abce.com ""
?>
Passaggio 9: creare un oggetto di Soap Client

$objClient = nuovo SoapClient ($WSDL, $arrOptions);
?>
Passaggio 10: imposta le intestazioni per l'oggetto soapclient

$objClient -> __setSoapHeaders (array($objSoapVarWSSEHeader ));
?>
Passaggio 11: chiamata finale al metodo

$objResponse = $objClient -> __soapCall ($strMethod, $requestPayloadString);
?>

peter presso webacoustics punto com

Ho scoperto che il recupero WSDL fallisce quando si utilizza l'autenticazione di base nel soapclient. Quindi ho implementato la seguente soluzione alternativa utilizzando wget. Mi rendo conto che wget potrebbe non essere un'opzione per alcuni ambienti, in tal caso cURL sarebbe la cosa più semplice successiva.

$wsdl = get_wsdl ( "https://example.com/soap/service?wsdl");
$this -> client = new SoapClient ($wsdl, array("user" => "someuser", "password" => "somepassword"));

Funzione privata get_wsdl ($url) (
globale $g ;
$url = escapeshellarg($url);
$cache_file = "/tmp/soap.wsdl." . md5($url);

//recupera solo un nuovo wsdl ogni ora
if(! file_esiste ($cache_file) || filectime ($cache_file)< time () - 3600 ) {
$agente = escapeshellarg("--user-agent=($g["useragent"])");
mwexec("wget ​​--quiet --timeout=5 ( $agent ) --no-check-certificate --output-document=($file_cache) ($url)");
if(! file_esiste ($cache_file )) (
lancia una nuova eccezione ("Impossibile caricare WSDL su ( $url )" );
}
}
ritorno
$file_cache;
}
?>

Meltir e Meltir punto com

Per coloro che combattono con i server proxy autenticati NTLM, ecco una soluzione che sto utilizzando atm:

/**
* Un figlio di SoapClient con supporto per l'autenticazione proxy NTLM
*
* @autore Meltir
*
*/
la classe NTLM_SoapClient estende SoapClient (

Funzione pubblica __construct ($wsdl, $options = array()) (
if (empty($opzioni ["proxy_login"]) || vuoto($opzioni ["proxy_password"])) lancia una nuova eccezione ( "Login e password richiesti per l'autenticazione NTLM!");
$questo -> proxy_login = $opzioni ["proxy_login"];
$questo -> proxy_password = $opzioni ["proxy_password"];
$questo -> proxy_host = (vuoto($opzioni ["proxy_host"])? "host locale": $opzioni[ "host_proxy"]);
$questo-> porta proxy= (vuoto($opzioni[ "porta proxy"]) ? 8080 : $opzioni[ "porta proxy"]);
genitore:: __costruire($wsdl, $opzioni);
}

/**
* Chiama un URL utilizzando curl con autenticazione ntlm
*
* @param stringa $url
* @param stringa $dati
* @return stringa
* @genera SoapFault in caso di errore di connessione curl
*/
funzione protettacallCurl($URL, $dati) {
$maniglia= curl_init();
curl_setopt($maniglia, CURLOPT_HEADER, falso);
curl_setopt($maniglia, CURLOPT_URL, $URL);
curl_setopt($maniglia, CURLOPT_FAILONERROR, VERO);
curl_setopt($maniglia, CURLOPT_HTTPHEADER,Vettore("Client PHP SOAP-NTLM"));
curl_setopt($maniglia, CURLOPT_RETURNTRANSFER, VERO);
curl_setopt($maniglia, CURLOPT_POSTFIELDS, $dati);
curl_setopt($maniglia, CURLOPT_PROXYUSERPWD, $questo-> proxy_login. ":" . $questo-> password_proxy);
curl_setopt($maniglia, CURLOPT_PROXY, $questo-> host_proxy. ":" . $questo-> porta proxy);
curl_setopt($maniglia, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
$risposta= curl_exec($maniglia);
se (vuoto(
$risposta)) {
lanciarne di nuovi
SoapFault("Errore CURL: ". curl_errore($maniglia), curl_errno($maniglia));
}
arriccia_chiudi($maniglia);
ritorno
$risposta;
}

Funzione pubblica __doRequest($richiesta, $posizione, $azione, $versione, $solo andata= 0 ) {
ritorno
$questo-> callCurl($posizione, $richiesta);
}

}
?>

Richiede arricciatura e potrebbe essere esteso, ma funziona per le mie esigenze semplici.

Eric punto Caron su Gmail punto com

Pensiero sottolineato da Jan su bestbytes e discusso nel bug n. 27777, una fonte comune di "Parsing WSDL: Impossibile trovare" "l'errore deriva dal tentativo di accedere a un WSDL protetto dall'autenticazione HTTP. Passare login/password nel 2° parametro non sempre funziona; quindi se incontri questo messaggio di errore e stai tentando di accedere a un file WSDL protetto, prova a passare il nome utente e la password con il primo parametro.

Anonimo

Ho dovuto lottare con un comportamento piuttosto strano quando provavo a utilizzare i servizi web Parlay X standard senza successo. Tuttavia, ho trovato un rimedio al mio problema.

Il problema che ho dovuto affrontare riguardava un'errata richiesta di autenticazione di base HTTP non valida inviata al servizio web. Sebbene stessi inviando le credenziali corrette, ricevevo un errore di autenticazione. Risulta che PHP stava inviando richieste HTTP a un altro endpoint che non è esposto direttamente tramite il servizio Web e che quell'endpoint non richiede l'autenticazione.

Il mio rimedio a questo problema è stato utilizzare queste semplici righe nell'esempio dell'utilizzo del metodo sendSms Paraly-X.

Innanzitutto, creando un client soap senza opzioni di autenticazione HTTP:

$cliente= nuovoSoapClient($wsdl_url);
?>

La richiesta precedente memorizzerà nella cache wsdl nella directory /tmp. Subito dopo questa costruzione creiamo un altro client soap, questa volta con opzioni di autenticazione HTTP:

Tentativo (
$cliente= nuovoSoapClient($wsdl_url, vettore("login"=> "grifone",
"parola d'ordine"=> "parola d'ordine"));
) presa (
Eccezione $e) {
printf("Errore: inviaSms: %s\n", $e-> __accordare());
ritorno
falso;
}
?>

Ora dovrebbe funzionare senza alcun problema. Senza la seconda chiamata, PHP chiamerà sendSms senza credenziali risultando in un tentativo fallito a causa della mancanza di informazioni di autenticazione. Ho trovato questa procedura la più semplice.

Questo processo dovrebbe essere eseguito ogni volta che scade il wsdl memorizzato nella cache, o semplicemente si può aumentare il time-to-live per il wsdl memorizzato nella cache da php.ini

jon punto gilbert e net-entwicklung punto de

Tieni presente che la creazione di un client soap per un URL non valido (prova cosa succede quando un servizio non è disponibile, giusto?) di solito genera un'eccezione che può essere intercettata con try..catch. Tuttavia, se xdebug è attivo, verrà visualizzato un errore fatale, che ovviamente non può essere rilevato.

sloloem su Gmail punto com

Ho avuto un problema nel discutere l'uso di classmap e mi ci è voluto un po' di tempo per capirlo. Presumevo che il tipo WSDL a cui si riferivano i documenti fosse il nome dell'elemento restituito nel SOAP, quindi,

E mi chiedevo perché mappare
"classmap"=>array("nodo"=>"MioNodo")

Fatto niente.
Questo perché nel mio WSDL ho definito il nodo come:

La mappa di classe di cui avevo bisogno era:
"classmap"=>array("nodeType"=>"MyNode")

Sono riuscito a trovare i nomi dei tipi utilizzando SoapClient->__getTypes()
Successivamente, ho capito dove avrei potuto cercare all'interno del WSDL il nome del tipo di cui avevo bisogno.

Non so se mi sono perso qualcosa di dolorosamente ovvio, ma forse questo può chiarire alcuni documenti.

Jon

Abbiamo riscontrato alcuni problemi utilizzando SoapClient connettendoci a un server esterno tramite Microsoft ISA (attualmente v.2006 ma questo potrebbe applicarsi anche ad altre versioni). Forniamo proxy_host, proxy_port, proxy_login e proxy_password ma il server ISA riporta il login nel suo registra come "anonimo".

Il nostro amministratore di sistema ritiene che ciò sia dovuto al fatto che PHP non fornisce informazioni NTLN (protocollo di sicurezza di Windows) nel formato corretto (e se debba funzionare con proxy proprietari è ovviamente un altro dibattito). Abbiamo provato "nomeutente", "DOMINIO\nomeutente" senza alcun effetto. La soluzione è aggiungere un'eccezione nel server ISA per il nome host/IP di destinazione; è quindi possibile fornire null per proxy_login e proxy_password e la connessione dovrebbe quindi funzionare come previsto.

In una nota leggermente correlata, se riscontri problemi assicurati che il numero di porta sia fornito come numero intero. Alcune versioni di PHP non utilizzeranno il proxy con SoapClient se il numero di porta viene fornito come stringa.

Jan su bestbytes punto de

PUOI ottenere un wsdl, se è richiesta l'autenticazione di base:

$accedi = "berto";
$password= "password bert";

$cliente= nuovoSoapClient(
"http://". urlencode($accedi) . ":" . urlencode($password) . "@www.server.com/percorso/del/wsdl",
vettore(
"login"=> $accedi,
"parola d'ordine"=> $password
)
);

?>

informazioni su nicksilvestro punto net

Per chiunque abbia problemi con ArrayOf_xsd_string e riceva un errore simile a "Nessun deserializzatore definito per il tipo di array (http://www.w3.org/2001/XMLSchema)string"
Prova a utilizzare il parametro "features", impostato su SOAP_USE_XSI_ARRAY_TYPE: questo assicura che venga utilizzato il deserializzatore corretto.

Per esempio,
$cliente= nuovoSoapClient("alcuni.wsdl", vettore("caratteristiche"=> SOAP_USE_XSI_ARRAY_TYPE));
?>

cecchino

stavo cercando un buon esempio e non sono riuscito a trovarne uno,
finalmente l'ho trovato da qualche parte (ho dimenticato dove), penso che sia questo
il miglior esempio per effettuare una richiesta soap con più parametri

$params->AWSAccessKeyId = AMAZON_API_KEY;
$params->Request->SearchIndex = "Libri";
$params->Richiesta->Parole chiave = "php5 oop";

$amazon = new SoapClient("http://webservices.amazon.com
/AWSECommerceService/AWSECommerceService.wsdl");
$risultato = $amazon->itemSearch($params);

alex su reutone virgola com

Per connettere PHP SOAP a MS SOAP (CRM/EXCHANGE/...) ho creato alcune classi utilizzando la spiegazione seguente e in altri posti.
www.reutone.com/heb/articles.php?instance_id=62&actions=show&id=521

naugtur su Gmail punto com

Eccezione SoapFault: sembra che non sia presente alcun documento XML è già stato menzionato che si verifica quando il tuo server restituisce qualcosa in precedenza ... > etichetta.

Per tutti quelli che hanno problemi con questo, Enessun accesso al codice del server:
Ecco come creare un proxy che pulisca le risposteperVoi

php
/**
* Lezione semplice tratta da una nota di James Ellis
*/
classeProxy_Clientsi estendeSoapClient{
protetto
$cacheDocument= "" ;
funzione pubblica
__costruire($wsdl, $opzioni) {
genitore:: __costruire($wsdl, $opzioni);
}

/**
* SetCacheDocument() imposta il contenuto del documento precedentemente memorizzato nella cache
*/
funzione pubblicaSetCacheDocument($documento) {
$questo-> cacheDocument= $documento;
}

/**
* __doRequest() sovrascrive lo standard SoapClient per gestire una richiesta locale
*/
funzione pubblica__doRequest() {
ritorno
$questo-> cacheDocument;
}
}

//inserisci questo codice nella tua funzione o ovunque tu abbia impostato tutte le variabili richieste

$cliente= nuovoSoapClient($wsdl_url, $array_impostazioni);
$vuoto= $cliente-> $metodo($parametri); //chiamalo per ottenere una risposta dal server

$stringa_risposta= $cliente-> __getLastResponse();

//questa parte rimuove materiale
$inizio= strpos($stringa_risposta, ");
$fine= strrpos($stringa_risposta, ">" );
$stringa_risposta= sost($stringa_risposta, $inizio, $fine- $inizio+ 1 );

//prepara il tuo proxy
$procura= nuovoProxy_Client($wsdl_url, $array_impostazioni);
//e riempilo con la risposta del server
$procura-> SetCacheDocument($stringa_risposta);

$e_finalmente_il_risultato_è= $procura-> $metodo($parametri);

stampa_r($e_finalmente_il_risultato_è); //questo ti permette di vedere cosa c'è

?>

$method è il nome del metodo, ad esempio $method="getVersion";
$params - parametri tipici per un metodo soap