Pubblichiamo un servizio tramite JSON-RPC con Zend Framework
In ambito di calcolo distribuito e sempre più orientato ai servizi web non si può non nominare qualche tecnica di chiamate a procedure remote (RPC: Remote Procedure Call).
RPC si riferisce all’attivazione di una procedura su una macchina remota a seguito di una richiesta effettuata attraverso la rete. Gli standard più diffusi al momento sono sicuramente SOAP e XML-RPC, ma questi stanno, nell’ultimo periodo, perdendo terreno rispetto al più giovane JSON-RPC (Vedi il neanche tanto recente ritiro delle API SOAP da parte di google).
Come suggerisce il nome, JSON-RPC è una tecnica di RPC basata sul formato di interscambio dati JSON, tanto utilizzato nei moderni siti internet con javascript e le chiamate AJAX.
L’Applicazione di Esempio
Per mantenere le cose il più semplici possibile, realizzeremo una pagina web che contiene un solo articolo, con titolo, data e testo, letto da un file (niente database).
Tramite JSON-RPC sarà possibile leggere e scrivere da remoto il contenuto di questo file, aggiornando così la pagina web.
L’esempio conterrà in sostanza 3 file, oltre allo Zend Framework che utilizzeremo per implementare Client e Server JSON-RPC:
- index.php: Visualizza la pagina con l’articolo
- json-rpc.php: Script che implementa il server JSON-RPC
- article.json: Il nostro storage che conterrà i dati dell’articolo
La Homepage
La homepage sarà semplicissima, legge il contenuto del file article.json e lo visualizza:
<?php
$article = json_decode(file_get_contents("article.json"), true);
?>
<!DOCTYPE html>
<html>
<head><title>Test JSON-RPC</title></head>
<body>
<h1><?=$article['title']?></h1>
<h5><?=$article['date']?></h5>
<p><?=$article['content']?></p>
</body>
</html>
Mentre il contenuto di article.json potrebbe essere qualcosa di simile a:
{
"title": "Test",
"date": "13/01/2011",
"content": "<p>Testo di prova</p>"
}
Il Server JSON-RPC
Grazie alla potenza della classe Zend_Json_Server, implementare un server JSON-RPC è semplicissimo.
E’ sufficiente definire la classe PHP con i metodi pubblici da rendere disponibili da remoto e passarla come parametro a Zend_Json_Server, che ne leggerà i metodi e creerà automaticamente la definizione del servizio.
Quello che ci resta da fare è gestire le richieste. Le chiamate JSON-RPC devono avvenire necessariamente in POST, per cui se la richiesta è in GET, forniremo la definizione del servizio:
<?php
// Inizializzo l'ambiente caricando lo zend framework
error_reporting(E_ALL);
require_once "Zend/Loader.php";
Zend_Loader::loadClass("Zend_Loader_Autoloader");
Zend_Loader_Autoloader::getInstance();
// Definisco la classe che legge e scrive il file con l'articolo
class ArticleUpdater {
protected static $storage = 'article.json';
public function set($title, $date, $content) {
file_put_contents(self::$storage, json_encode(array(
'title' => $title,
'date' => $date,
'content' => $content
)));
}
public function get() {
return json_decode(file_get_contents(self::$storage), true);
}
}
// Server JSON
$server = new Zend_Json_Server();
$server->setClass('ArticleUpdater');
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
$server->setTarget('/json-rpc.php')
->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
header('Content-Type: application/json');
echo $server->getServiceMap();
return;
}
$server->handle();
Ovviamente perché questo script funzioni è necessario aver installato lo Zend Framework in una cartella nell’include_path o nella stessa cartella dell’applicazione. Il pacchetto minimal è più che sufficiente.
Impostiamo inoltre i necessari permessi di scrittura al file article.json (666) per poter consentire al metodo set di modificarne il contenuto.
Client remoto (Consumer)
Purtroppo lo Zend Framework non ci fornisce l’implementazione Zend_Json_Client che ci aspetteremmo, ma realizzare un semplice client PHP tramite CURL non è troppo complicato.
Creiamo quindi una semplice funzione per “consumare” un servizio JSON-RPC. I parametri necessari sono l’url del server e il nome del metodo da chiamare. I parametri sono invece opzionali.
function json_rpc_call($url, $method, $params=null) {
$request = array(
'method' => $method,
'id' => 1
);
if (is_array($params))
$request['params'] = $params;
$request = json_encode($request);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($request) . "\r\n",
$request
));
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
curl_close($ch);
$output = json_decode($output, true);
if (!is_null($output['error']))
throw new Exception($output['error']['message']);
return $output['result'];
}
La funzione restituisce il parametro “result” della risposta se tutto ha funzionato correttamente, altrimenti lancerà un’eccezione col messaggio d’errore restituito dal server.
Un test d’uso quindi potrebbe essere questo:
try {
var_dump(json_rpc_call("http://localhost/json-rpc.php", "get"));
var_dump(json_rpc_call("http://localhost/json-rpc.php", "set", array("Nuovo titolo", "17/01/2011", "Nuovo testo dell'articolo")));
var_dump(json_rpc_call("http://localhost/json-rpc.php", "get"));
} catch (Exception $e) {
echo "JSON-RPC call failed with message: {$e->getMessage()}";
}
Ovviamente nulla ci vieta di chiamare le funzioni RPC direttamente da javascript o da qualsiasi altro linguaggio di programmazione. Ad esempio per MooTools, è disponibile una classe apposita sul Forge.
Il codice dell’articolo è disponibile per il download.
ciao,
come un pò tutti gli articoli che ho letto in giro e anche questo, viene accennato al fatto di effettuare la chiamata direttamente da javascript, però non viene mai descritto l’utilizzo proprio senza utilizzare il php come linguaggio primario del client.
inoltre non viene fatto nessun accenno ai criteri di sicurezza di questo sistema, utilizzando le chiamate direttamente da javascript.
se potete pubblicare un esempio sarebbe ben accetto.
Grazie.