1. Web Services in PHP:
da xmlrpc a json e ritorno
Ing. Gaetano Giunta
PHP Day 2006
canale Developer
Bari 20 maggio 2006
2. Intro
Programma della presentazione:
Breve introduzione ai webservices, con focus su
XMLRPC, SOAP e JSON
Creazione di un client xmlrpc
Creazione di un server xmlrpc
Estensione del server xmlrpc con supporto per json-rpc
Estensione del server con supporto per chiamate
effettuate direttamente dal browser (AJAX? Mai sentito!)
3. Dr. Webservice, suppongo?
a Web service is a software system designed to support
interoperable machine-to-machine interaction over a network. It
has an interface that is described in a machine-processible
format such as WSDL. Other systems interact with the Web
service in a manner prescribed by its interface using messages,
which may be enclosed in a SOAP envelope, or follow a REST
approach. These messages are typically conveyed using HTTP,
and normally comprise XML in conjunction with other Web-
related standards
da wikipedia, maggio 2006
in pratica sta per
comunicazione tra applicazioni via XML ed HTTP
(ma n辿 xml n辿 http sono obbligatori...)
4. XMLRPC (www.xmlrpc.com)
Il primo nato: spec. del 1999 (implementato nel 1998?)
Copyright sulla specifica: UserLand SW (Dave Winer)
primo utilizzo diffuso di xml su piattaforme diverse
Implementazioni esistenti in tutti i linguaggi: javascript,
java, C, php, phyton, perl, ruby, delphi, VB, etc...
Legato a doppio filo ad HTTP e chiamate sincrone
Limitate capacit di descrizione delle interfacce
esposte
Non integrato con standard xml successivi
(namespaces, xml schema, wsdl)
5. XMLRPC - sintassi
Basato su 6 tipi base: stringa, intero, floating point,
booleano, base64, data e 2 ricorsivi: array, struttura
Non fa uso di attributi o namespace
La sintassi con cui si definiscono i servizi esposti 竪
quella di una chiamata di funzione:
risultato = funzione (p1, p2, ..., pn)
previsto un risultato di tipo errore (numero intero +
stringa) all'invocazione del metodo
Xml generato verboso ma comprensibile
6. XMLRPC - esempio
<?xml version="1.0"?>
<methodCall>
<methodName>system.methodHe
lp</methodName>
<params>
<param>
<value>
<string>system.methodHelp</
string>
</value>
</param>
</params>
</methodCall>
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value>
<string>Returns
help text if defined for
the method passed,
otherwise returns an empty
string</string>
</value>
</param>
</params>
</methodResponse>
String system.MethodHelp(String methodname)
7. SOAP (www.w3.org/TR/soap/)
Nato per sopperire alle carenze di xmlrpc
Standard approvato dal W3C (solo la versione 1.2)
Supportato da Microsoft, IBM, SUN
Permette di descrivere nel dettaglio le interfacce
(WSDL)
In teoria: permette di svincolare la sintassi di una
chiamata dalla sua rappresentazione fisica (e dal
protocollo di trasporto)
In pratica: grossi problemi di interoperabilit sin
dall'inizio tra le diverse implementazioni
8. SOAP - WSDL
Basato su XML Schema per la definizione dei tipi (in
teoria anche Relax NG 竪 utilizzabile, ma non 竪
supportato dalle librerie disponibili)
Ridondante e verboso per ottenere la necessaria
flessibilit...
...ma il binding HTTP 竪 l'unico utilizzato da tutti (con
rappresentazione document/literal)
Estremamente complesso da sviluppare a mano
Un anti-pattern dei linguaggi di descrizione delle
interfacce?
9. SOAP - esempio
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<sendMessages xmlns="SmsServer">
<outMessageList xmlns="">
<outputMessage>
<message>
<telephoneNumber>1-800-neo</telephoneNumber>
<messageText>follow the white rabbit</messageText>
</message>
<requestConfirmation>false</requestConfirmation>
</outputMessage>
</outMessageList>
<senderID xmlns="">the matrix</senderID>
</sendMessages>
</soap:Body>
</soap:Envelope>
<?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<sendMessagesResponse xmlns="">
<messageID xmlns="">0</messageID>
</sendMessagesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Servizio: invio di
una serie di
SMS
11. JSON (www.json.org)
L'ultimo nato
Come xmlrpc, si basa su un set limitato di tipi base:
numero, stringa, booleano, null, array, oggetto
Abbandona la notazione xml per una pi湛 sintetica e
semplice da decodificare
Rappresenta un sottoinsieme della 'object literal
notation', parte della specifica javascript (ECMA 262)
Descrive esclusivamente un formato di
rappresentazione dei dati, non un protocollo di
trasporto n辿 un pattern di scambio messaggi
12. JSON il partner per AJAX
Vantaggi evidenti nell'utilizzo per la comunicazione tra
browser e server:
Formato pi湛 conciso di XML: minori dati transitano sulla rete
Rapidit nell'esecuzione del parsing dei messaggi in oggetti
javascript (non necessita di librerie xml)
Semplicit del codice javascript che fa uso dei dati ricevuti
(nessuna navigazione di DOM o metodi di accesso similari)
var result = eval( json_data );
Attenzione ai grossi problemi di sicurezza insiti nel
codice qui sopra!
13. JSON - esempio
{
"method": "system.methodHelp",
"params": ["system.methodHelp" ],
"id": 0
}
{
"id": 0,
"error": null,
"result": "Returns help text if defined for the method
passed, otherwise returns an empty string"
}
14. Quale protocollo devo usare?
YMMV (in altre parole: dipende...)
SOAP 'ha vinto' la guerra degli standard ed 竪 la base
per molti altri standard: la famiglia WS-*
Gli altri due sono diffusissimi in internet!
Si controllano entrambi i lati della comunicazione o
uno solo?
Esistono toolkit stabili e semplici da utilizzare per la
piattaforma di sviluppo in uso?
Privilegiare tool che fanno tutto da soli (protocollo
nascosto) o semplici da estendere/modificare?
Velocit di esecuzione del codice vs. semplicit dello
stesso
15. PHP per i webservices
Estensione XMLRPC: nel core a partire dal PHP 4
Estensione SOAP: PHP 5
Estensione JSON: PHP 6 (forse gi 5.2?)
Oltre alle estensioni native, esistono decine di librerie
implementate in php:
PEAR::xmlrpc, phpxmlrpc, Incutio, Keith Devens,
Zend_XmlRpc, ...
PEAR::soap, nusoap, ...
PEAR::json, phpxmlrpc-extras, JSON-PHP, Zend_json, ...
16. PHPXMLRPC
La prima libreria per xmlrpc in php (1999)
Codice debuggato e stabile*
:
Solamente 2 files
Inclusa in decine di applicazioni PHP
Supporta numerose features: compressione http,
gestione dei character set, cookies, http 1.1, https,
autenticazione basic ed ntlm, proxy, ...
Flessibile: gestione da 'automagica' a 100% manuale
della conversione di variabili php in xmlrpc e di
funzioni in webservices (e viceversa)
Include un comodo debugger
* dopo la correzione dei problemi di iniezione di codice del 2005
17. PHPXMLRPC - extras
Aggiunge supporto per JSONRPC, un dialetto di
JSON (http://json-rpc.org/)
Oltre a json, altre funzioni interessanti:
Generazione automatica di documentazione HTML delle
interfacce
Nuove classi per interazioni ajax semplificate
Generazione del WSDL per i metodi esposti ?
Codice ancora in fase beta
18. XMLRPC - installazione
Scaricare il software, da
http://sourceforge.net/projects/phpxmlrpc
sia il pacchetto phpxmlrpc che extras
Copiare in una directory che faccia parte del path di
inclusione del PHP i seguenti file:
xmlrpc.inc, xmlrpcs.inc(libreria base)
jsonrpc.inc, jsonrpcs.inc, docxmlrpcs.inc,
ajaxmlrpc.inc (estensioni)
Copiare la cartella debugger da qualche parte sotto
la web root
Creare una cartella in cui risiederanno i web services
(sotto la web root, ovviamente ;)
19. XMLRPC - concetti
Classi:
xmlrpcval un valore xmlrpc (scalare o ricorsivo)
xmlrpcmsg inviato dal client al server
xmlrpcresp inviata dal server al client
xmlrpc_client invia messaggi al server
xmlrpc_server riceve le richieste dai client, le inoltra
alle appropriate funzioni utente e
gestisce l'invio della risposta
Esistono inoltre alcune funzioni di utilit generale
20. Creazione di un client 1
<?php
include("xmlrpc.inc");
$par = new xmlrpcval('system.methodHelp', 'string');
$msg = new xmlrpcmsg('system.methodHelp', array($par));
$c = new xmlrpc_client("/server.php", "phpxmlrpc.sf.net", 80);
$r = $c->send($msg);
if(!$r->faultCode())
{
$v = $r->value();
$result = $v->scalarval(); // non funzionerebbe con array!
print "Got: " . htmlspecialchars($result);
}
else
{
print "An error occurred:n";
print " Code: " . htmlspecialchars($r->faultCode())."n";
print " Reason: " . htmlspecialchars($r->faultString());
}
?>
21. Creazione di un client 2
$v = new xmlrpcval(array(
"thearray" => new xmlrpcval(array(
new xmlrpcval("ABCDEFHIJ"),
new xmlrpcval(1234, 'int'),
new xmlrpcval(1, 'boolean'),
new xmlrpcval(0, 'boolean'),
new xmlrpcval(true, 'boolean'),
new xmlrpcval(false, 'boolean')),
"array"),
"theint" => new xmlrpcval(23, 'int'),
"thestring" => new xmlrpcval("foobarwhizz"),
"thestruct" => new xmlrpcval(array(
"one" => new xmlrpcval(1, 'int'),
"two" => new xmlrpcval(2, 'int')),
"struct")
),
"struct");
La conversione manuale da variabili PHP a oggetti
xmlrpcval diventa rapidamente tediosa...
22. Creazione di un client - 3
// ...
$par = php_xmlrpc_encode($some_extremely_complex_php_array);
$msg = new xmlrpcmsg('whatever', array($par));
$c = new xmlrpc_client("/server.php", "phpxmlrpc.sf.net", 80);
$r = $c->send($msg);
if(!$r->faultCode())
{
$result = php_xmlrpc_decode($r->value());
var_dump($result);
}
else
{
print "An error occurred:n";
print " Code: " . htmlspecialchars($r->faultCode())."n";
print " Reason: " . htmlspecialchars($r->faultString());
}
... ma vi si pu嘆 ovviare facilmente
23. Creazione di un client - 4
Per i veramente pigri: conversione di metodi remoti in
funzioni PHP locali
$c = new xmlrpc_client("phpxmlrpc.sourceforge.net/server.php");
$funcname = wrap_xmlrpc_method($c, "system.methodHelp");
if ($funcname)
{
$methodhelp = $funcname("system.methodHelp");
if (is_a($methodhelp, "xmlrpcresp"))
print "KO: method invocation failed";
else
print "Got: " . htmlspecialchars($methodhelp);
}
else
{
print "KO: Cannot get method synposis from server";
}
24. Creazione di un server - 1
<?php
include('xmlrpc.inc');
include('xmlrpcs.inc');
$methods = array(
'USstatename' => array(
'function' => 'findstate',
'signature' => array(array($xmlrpcString,
$xmlrpcInt)),
'docstring' => 'Converts an integer value to its US
state name' )
);
function findstate($msg)
{
// funzionalit da implementare...
}
$server = new xmlrpc_server($methods);
?>
25. Creazione di un server - 2
Funzione che implementa un metodo: espone
un'interfaccia standard
function findstate($msg) {
global $stateNames, $xmlrpcerruser;
$in = php_xmlrpc_decode($msg);
$snv = $in[0]; // la dispatch map ci garantisce un int
if ($snv >= 0 && $snv <= 50)
{
$resp = new xmlrpcresp(
php_xmlrpc_encode($stateNames[$snv-1]));
} else {
$resp = new xmlrpcresp(0, $xmlrpcerruser,
"I don't have a state for the index '" . $snv . "'";
}
return $resp;
}
26. Creazione di un server - 3
Per i veramente pigri: conversione di funzioni PHP locali
in metodi remoti (solo con PHP 5.0.3 o successivi)
/** Converts an integer value to its US state name
* @param int $snv
* @return string */
function findstate2($snv) {
global $stateNames;
if ($snv >= 0 && $snv <= 50)
$resp = $stateNames[$snv-1];
else
$resp = "I don't have a state for the index ".$snv;
return $resp;
}
$findtstate_sig = wrap_php_function('findstate2');
if ($findtstate_sig)
$methods['automagic.findstate'] = $findtstate_sig;
27. Uso del debugger
Problema ricorrente nello sviluppo di webservices (e, in
generale, protocolli di comunicazione): l'osservabilit
29. Documentazione per umani
Oltre alla lista dei metodi e alla sintassi di chiamata di
ogni metodo, si ottiene un form in cui completare la
richiesta (come xml) e testarla immediatamente
30. Supporto per json-rpc: le classi
Le classi che forniscono il supporto per json-rpc sono
sottoclassi di quelle usate per xml-rpc
xmlrpcval = jsonrpcval
xmlrpcmsg = jsonrpcmsg
xmlrpcresp = jsonrpcresp
xmlrpc_client = jsonrpc_client
xmlrpc_server = jsonrpc_server
la magia 竪 tutta nella classe server, che riconosce il
protocollo usato dal client e serializza le risposte in
modo appropriato.
32. Combinando le potenzialit...
if($_SERVER['REQUEST_METHOD'] != 'POST' ||
$_SERVER['CONTENT_TYPE'] == 'application/x-www-form-
urlencoded')
{
include('docxmlrpcs.inc');
$server = new documenting_xmlrpc_server($methods);
}
else
{
if strpos($_SERVER['CONTENT_TYPE'], 'text/xml') === 0)
{
$server = new xmlrpc_server($methods);
}
else
{
include('jsonrpc.inc'); include('jsonrpcs.inc');
$server = new jsonrpc_server($methods);
}
}
33. AJAX e WS: da PHP a JS
Come si riescono a convertire le funzioni PHP in metodi
xmlrpc o jsonrpc, si potrebbero convertire tali metodi in
funzioni javascript?
Grazie all'aiuto di Jsolait (http://jsolait.net/) si possono
invocare i webservices direttamente dal browser
Limitazione di base: si possono invocare webservices
solamente sul server originante della pagina web (a
meno di orrendi hacks o di creare un proxy)
34. AJAX e WS: da PHP a JS
<script type="text/javascript" src=/slideshow/phpday-2006-ws-in-php/240435816/"./jsolait/init.js">
<script type="text/javascript">
var xmlrpc = importModule("xmlrpc");
var serviceURL =
"http://phpxmlrpc.sourceforge.net/server.php";
var methods = ["USstatename"];
try{
var service = new xmlrpc.ServiceProxy(serviceURL,
methods);
txRsult.value = service.USstatename(1);
}catch(e){
printTrace(e);
}
</script>
35. AJAX e WS: da PHP a JS
Per i veramente pigri: tutto in una sola pagina PHP!
<?php
require_once('xmlrpc.inc');
require_once('xmlrpcs.inc');
require_once('ajaxmlrpc.inc');
// definizione delle funzioni e dispatch map: nessuna differenza!
$server = new js_rpc_server($dmap);
?>
<html>
<head>
<?php $server->importMethods2JS(); ?>
</head>
<body>
<a href="#"
onclick="alert(USstatename(10)); return false;"
>here</a> to execute a webservice call and display results in a
popup message...
36. AJAX e WS: da PHP a JS
Un layout appena pi炭 complesso...
Funzioni esposte
<?php
require('dichiarazioni.inc.php);
...
?>
Front end: HTML
<html><head><?php
require('dichiarazioni.inc.php);
js_wrap_dispatch_map(...);
?></head>
...
Front end: WS
<?php
require('funzioni.inc.php);
$server = new xmlrpc_server();
?>
Dispatch map
require_once('xmlrpc.inc');
require_once('xmlrpcs.inc');
require_once('ajaxmlrpc.inc');
...