Utilizzare JSON con PHP

  • CommentaScrivi un commento
  • ForumDiscuti sul forum
  • PrecedenteEspressioni regolari con le funzioni PCRE (e differenze con le funzioni POSIX)
  • SuccessivoUtilizzare le API di Google Analytics con PHP

JSON, acronimo di JavaScript Object Notation, è una tecnologia, ma sarebbe meglio definirlo un "formato", concepito per l'interscambio dei dati all'interno di applicazioni di tipo client-server, come per esempio quelle realizzate in Ajax e PHP, ma è largamente utilizzato anche in associazione a linguaggi di programmazione come Java, C, C# e Perl.

In questa guida vedremo come utilizzare JSON con PHP per creare uno scambio dati tra applicazioni client-server.

Caratteristiche di JSON

JSON è basato sul linguaggio JavaScript Standard ECMA-262 3ª nella versione rilasciata durante il dicembre 1999, anche se è stato sviluppato in modo indipendente dal suo sorgente.

La diffusione di questo formato è dovuta, con tutta probabilità, alla sua estrema semplicità d'utilizzo, esso supporta inoltre una grande varietà di tipi di dato che, come è possibile osservare tramite il successivo elenco, sono poi in linea generale gli stessi integrati nei typesystems della maggior parte dei linguaggi per la programmazione e lo scripting:

  • NULL: dato privo di valore;
  • BOOLEAN: valori che possono essere o veri (TRUE o "1") o falsi ("0" o FALSE);
  • INTEGER: valori numerici interi;
  • REAL e FLOAT: valori reali o in virgola mobile;
  • STRING: serie (anche prive di elementi) di caratteri Unicode delimitati tramite doppi apici;
  • ARRAY: serie ordinate composte da valori separati tramite virgole e delimitati da parentesi quadre;
  • ARRAY ASSOCIATIVI: serie ordinate composte da coppie chiave-valore separate tramite virgole e delimitate da parentesi graffe;
  • OGGETTI: serie non ordinate di coppie di nomi e valori separate tramite virgole e delimitati da parentesi graffe.

Se da una parte le similitudini sono immediatamente osservabili, dall'altra è importante notare che vi sono anche alcune differenze tra i tipi di dato di JSON e quelli di molti linguaggi; i più attenti avranno sicuramente notato come il tipo STRING di questo formato sia praticamente identico a quello utilizzato per Java o C, però, si tenga conto che il discorso cambia per i tipi numerici dove JSON non supporta la numerazione ottale o decimale.

Continua dopo la pubblicità...

JSON e PHP

JSON permette l'interscambio di dati attraverso uno stream (o "flusso di input/output"), esso potrà essere sottoposto a parsing, e quindi letto, attraverso un inteprete ("engine") JavaScript grazie alla semplice chiamata ad un'apposita funzione JS denominata eval().
Nel corso di questa guida vedremo come sia possibile sfruttare tale funzione all'interno di script basati su Javascript e PHP, ma è necessario prima fare qualche riferimento ai requisiti minimi per lo sviluppo, JSON richiede infatti:

  • PHP almeno in versione 5.2 o superiore;
  • un browser in grado di fornire un supporto nativo per il formato, quindi, per esempio, non potrete utilizzare una versione di Internet Explorer precedente alla 8.

Sempre riguardo ai browser, è necessario sottolineare che non tutti i programmi di navigazione supportano l'interscambio di dati con JSON, e in particolare il suo modo di manipolare l'elemento XMLHttpRequest, nello stesso modo. Molto, infatti, dipende dalla "qualità" del motore JavaScript integrato; potreste, quindi, notare alcune piccole differenze nel comportamento delle vostre applicazioni nel caso utilizziate Firefox piuttosto che Opera. etc. In linea di massima possiamo dire che più recente è la versione installata nel sistema, migliore sarà il supporto per JSON.

Perché utilizzare PHP in associazione al formato d'interscambio JSON? Per rispondere a questa domanda non c'è niente di meglio che passare immediatamente a degli esempi pratici, si tenga comunque conto del fatto che uno dei vantaggi innegabili sta nel fatto che PHP integra nativamente delle funzioni per la codifica e la decodifica dello stream JSON: esse sono json_ encode() e json_ decode(). A questo proposito, si analizzi il seguente esempio:

<?php
// array per la codifica
$vettore = array("albero", "ramo", "mela");
// codifica JSON
$stringa = json_encode($vettore);
// stampa del risultato
echo $stringa;
?>

Si osservi ora il funzionamento dello script mostrato in precedenza: la funzione json_ encode() svolge il compito di restituire, partendo da una semplice array, una stringa contenente la rappresentazione JSON di un valore, in questo caso il Web server chiamato a gestire l'interscambio tra client e server che ospita l'applicazione, invierà una richiesta di stampa a video dell'operazione di codifica dei dati operata tramite json_encode() (nel nostro caso ["albero","ramo","mela"]), a sua volta l'interprete del client effettuerà una decondifica per restituirli nuovamente sotto forma di vettore, per cui i valori rappresentati nella stringa saranno gli stessi che compongono l'array.

Passiamo ora ad un altro esempio basato sulla funzione opposta a json_encode():

<?php
// definizione dell'oggetto per il parsing
$j = '{"Anno": 2010}';
$oggetto = json_decode($j);
// lettura dello stream JSON
echo $oggetto->{'Anno'}; 
?>

In questo caso, abbiamo la funzione json_ decode() che svolge il compito di decodificare una stringa JSON passata sotto forma di oggetto; tale oggetto si presenta come una coppia nome/valore ("Anno":2010) per cui, in lettura dello stream, il valore corrispondente al nome potrà essere stampato a video tramite una chiamata al primo elemento della coppia, quindi, il nostro script si limiterà a stampare:

2010

La possibilità di effettuare codifiche e decodifiche praticamente "al volo" con JSON, ha messo in luce questo formato come alternativa al metalinguaggio XML, i vantaggi sono infatti evidenti: nel caso di JSON non dovrà essere generato alcun documento (cosa invece necessaria per quanto riguarda XML) e le prestazioni degli script ne risultano avvantaggiate non essendo più costrette ad effettuare il parsing di file che, con l'aumento del numero dei dati da gestire così come del traffico generato dai client, possono diventare anche estremamente "pesanti".

Gestione degli errori

Oltre alle funzioni precedentemente descritte, PHP mette a disposizione anche uno strumento nativo grazie al quale gestire gli eventuali errori di codifica e di decodifica durante l'interscambio dei dati, questa funzione prende il nome di json_last_error(), essa restituisce infatti l'ultimo errore manifestatosi durante il parsing (nel caso esso si verifichi) e integra alcune costanti utili per il lavoro di debugging:

  • JSON_ERROR_NONE: non si sono verificati errori;
  • JSON_ERROR_DEPTH: si è superato il limite consentito dallo stack depth;
  • JSON_ERROR_CTRL_CHAR: si sono verificati dei problemi nella codifica, è relativo al controllo sui caratteri;
  • JSON_ERROR_STATE_MISMATCH: presenza di stringhe JSON malformate o non valide;
  • JSON_ERROR_SYNTAX: presenza di errori sintattici;
  • JSON_ERROR_UTF8: malformazioni nei carattieri con codifica UTF-8 e conseguenti errori di codifica.

Con l'avvertenza che la funzione json_last_error() richiede come minimo la versione 5.3.x di PHP, possiamo passare all'analisi del seguente esempio:

<php
// definizione di una stringa JSON non valida
$j[] = "{'Sito Web': 'MrWebsmater.it'}";

// controllo tramite ciclo di tutti gli elementi della stringa
foreach($j as $value)
{
  echo "Risultato della decodifica: " . $value;
  // decodifica della stringa
  json_decode($value);
  // controllo sulla presenza di eventuali errori
  switch(json_last_error())
  {
    case JSON_ERROR_DEPTH:
      echo " - superato il livello massimo per lo stack";
      break;
    case JSON_ERROR_CTRL_CHAR:
      echo " - utilizzo di caratteri non consentiti";
      break;
    case JSON_ERROR_SYNTAX:
      echo " - errore sintattico";
      break;
    case JSON_ERROR_NONE:
      echo " - Non si è verificato alcun errore";
      break;
  }
}
?>

L'esecuzione del codice proposto porterà al seguente risultato:

Risultato della decodifica:: {'Sito Web': 'MrWebsmater.it'} - errore sintattico

Cosa è accaduto? Molto semplicemente, la stringa su cui è stato effettuato il parsing è stata digitata utilizzando una sintassi invalida per JSON, infatti abbiamo (volontariamente) sbagliato la disposizione degli apici!
La stringa, infatti, è stata scritta in questo modo:

$j[] = "{'Sito Web': 'MrWebsmater.it'}";

mentre avremmo dovuto scriverla nel modo seguente:

$j[] = '{"Sito Web": "MrWebsmater.it"}';

Se ne ricava una regola fondamentale per evitare il verificarsi di errori nell'utilizzo della sintassi per JSON: le parentesi graffe devono essere delimitate con gli apici singoli, gli elementi interni con gli apici doppi.

Caso pratico di utilizzo: select dinamiche con PHP e JSON

Per mostrare un semplice esempio relativamente all'utilizzo di PHP e del formato JSON in un contesto pratico, creeremo una semplice applicazione in grado di gestire un form con dei menù select dinamici; per realizzare il nostro piccolo script avremo bisogno di alcuni strumenti:

  • un database gestito tramite MySQL;
  • il framework Ajax jQuery;
  • PHP con supporto per PDO abilitato (si controlli quindi la presenza della relativa estensione).

Il database si chiamerà "WorldCup" (vedremo presto perché), all'interno di esso dovrà essere presente una tabella, denominata "Vincitori", costituita da tre campi:

  • "id": campo identificatore univoco intero autoincrementale della lunghezza di 2 caratteri numerici;
  • "nazionali": campo VARCHAR della lunghezza massima di 20 caratteri;
  • "vittorie": campo numerico intero (INT) della lunghezza massima di 2 caratteri.

Per comodità del lettore, metteremo a disposizione il codice SQL necessario per la creazione della tabella già popolata con le informazioni che andremo ad utilizzare:

CREATE TABLE `Vincitori` (
  `id` int(2) NOT NULL auto_increment,
  `nazionali` varchar(20) NOT NULL,
  `vittorie` int(2) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;

INSERT INTO `Vincitori` (`id`, `nazionali`, `vittorie`) VALUES
(1, 'Brasile', 5),
(2, 'Italia', 4),
(3, 'Germania', 3),
(4, 'Argentina', 2),
(5, 'Uruguay', 2),
(6, 'Spagna', 1),
(7, 'Francia', 1),
(8, 'Inghilterra', 1);

La nostra applicazione consisterà in un form composto da un primo menù select popolato con i dati presenti nel campo "nazionali" e da un secondo menù select che verrà popolato con le informazioni contenute nel campo "vittorie" a seconda della selezione effettuata tramite la prima select: se, per esempio, selezionassimo "Brasile", nel secondo menù select dovrà comparire la cifra "5", "4" per l'Italia, "3" per la Germania e così via.

Vediamo ora il codice della pagina contenente il form, che potremmo salvare per esempio come "form.html":

<form>
Nazionali:
<!-- prima select -->
<select name="nazionali" id="nomeNazionale">
  <option>Brasile</option>
  <option>Italia</option>
  <option>Germania</option>
  <option>Argentina</option>
  <option>Spagna</option>
  <option>Francia</option>
  <option>Inghilterra</option>
</select>
Vittorie:
<!-- seconda select -->
<select name="vittorie" id="numeroVittorie">
</select>
</form>

Da notare come il secondo menù select sia privo di valori in quanto verrà popolato dinamicamente tramite i dati estratti dal database.

Nella stessa pagina contenente il nostro form, dovremo inserire tra i tag "<head></head>" il seguente codice JavaScript:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
// definizione della funzione
function inserisciVittorie() {
  // determinazione del metodo di interscambio e del primo selettore
  $.getJSON('/vittorie.php', {nomeNazionale:$('#nomeNazionale').val()}, function(data) {
    // popolamento della seconda select tramite array
    var select = $('#numeroVittorie');
    var options = select.attr('options');
    $('option', select).remove();
    $.each(data, function(index, array) {
      options[options.length] = new Option(array['vittorie']);
    });
  });
}

// modifica e inserimento di nuovi valori
$(document).ready(function() { 
  inserisciVittorie();
  $('#nomeNazionale').change(function() {
    inserisciVittorie();
  });
});
</script>

Come sarà semplice notare, nella prima riga di codice abbiamo importato jQuery, di cui abbiamo utilizzato l'ultima versione attualmente disponibile che andiamo a prelevare direttamente dal repository messo a disposizione da Google; fatto questo, abbiamo introdotto, all'interno della funzione "inserisciVittorie()", il selettore "nomeNazionale", che è omonimo dell'Id associato al primo menù select, cioè quello preposto all'invio dei dati alla pagina contenente l'applicazione server side ("vittorie.php").

L'invio di un input da parte del primo menù select determina la valorizzazione di un array ("vittorie"), i cui valori andranno a popolare il secondo menù select (a cui è associato il selettore "numeroVittorie") e saranno prelevati dal campo omonimo della tabella "Vincitori"; nello stesso modo, la funzione si occupera di rimuovere un valore e sostituirlo con uno nuovo a seconda del "nomeNazionale" scelto.
Da notare la determinazione del metodo di interscambio dei dati, in questo caso GET, operata tramite $.getJSON(), metodo che accetta come argomenti la pagina PHP per l'elaborazione degli input e il selettore che si occuperà dell'invio degli input stesso tramite il metodo scelto.

Passiamo ora al codice della pagina "vittorie.php"

<?php
// connessione e selezione del database
$connessione = "mysql:host=localhost;dbname=WorldCup";
// credenziali per l'autenticazione
$utente = "utente";
$password = "password";
// creazione dell'oggetto PDO
$istanza = new PDO($connessione, $utente, $password);
// definizione dell'array da parsare
$risultato = array();
// popolamento dell'array tramite query
if(isset($_GET['nomeNazionale'])) {
  $query = $istanza->prepare("SELECT vittorie FROM Vincitori WHERE nazionali = ? ORDER BY vittorie");
  $query->execute(array($_GET['nomeNazionale']));
  $risultato = $query->fetchAll(PDO::FETCH_ASSOC);
}
// codifica dei risultati
echo json_encode($risultato);
?>

In questo caso il discorso è molto più semplice, l'applicazione infatti non fa altro che stabilire una connessione col DBMS e selezionare il database da utilizzare; fatto questo, viene definito un array ("$risultato") contenente i valori che dovranno essere utilizzati per la codifica JSON; l'input inviato tramite metodo dal form e quindi dal codice JavaScript, verrà utilizzato come termine di confronto all'interno della clausola WHERE della query, una volta associato il valore contenuto nel campo "vittorie" a quello inviato tramite GET, questo potrà essere utilzzato per popolare il secondo menù select.

Una volta testato il codice mostrato, dovremmo ottenere un risultato simile a quello descritto dell'immagine seguente:

Select dinamiche con JSON

Per maggiore sicurezza, l'applicazione potrà essere completata impostando un filtro adeguato alla variabile che ha come valore l'input inviato tramite metodo.

Utilizzare JSON con versioni di PHP precedenti alla 5.2

Recentemente mi è capitato di dover sviluppare una piccola applicazione PHP da installare sullo spazio web di un cliente il quale aveva necessità di utilizzare le classiche funzioni JSON - json_encode() e json_decode() - in un ambiente non proprio aggiornato: la versione di PHP installata, infatti, era la 5.1 (come abbiamo detto nella introduzione di questo articolo, le funzioni JSON sono diventate parte integrante del core di PHP solo a partire dalla versione 5.2).

Per ovviare al problema, tuttavia, esiste una soluzione.
Per prima cosa scaricate la libreria Services_JSON (disponibile a questa pagina) ed includete nel vostro progetto il file JSON.php in questo modo:

require_once('JSON.php');

Fatto questo aggiungete al vostro codice queste righe che, di fatto, verificano la disponibilità delle due funzioni native citate ed, in caso di assenza, le sostituiscono utilizzando, appunto, la libreria appena inclusa:

if( !function_exists('json_encode') ) {
    function json_encode($data) {
        $json = new Services_JSON();
        return( $json->encode($data) );
    }
}
if( !function_exists('json_decode') ) {
    function json_decode($data) {
        $json = new Services_JSON();
        return( $json->decode($data) );
    }
}

>Da questo momento potete utilizzare le funzioni json_encode() e json_decode() tranquillamente... anche se la vostra versione di PHP è precedente alla 5.2

I commenti degli utenti

I commenti sono sottoposti alle linee guida di moderazione e prima di essere visibili devono essere approvati da un moderatore.