Skip to content

10. Server PHP

Poiché i programmi PHP possono essere eseguiti da un server web, un programma di questo tipo diventa un programma lato server in grado di servire più client. Dal punto di vista del client, chiamare un servizio web equivale a richiedere l'URL di quel servizio. Il client può essere scritto in qualsiasi linguaggio, incluso PHP. In quest'ultimo caso, utilizziamo le funzioni di rete appena discusse. Dobbiamo anche sapere come "comunicare" con un servizio web, ovvero comprendere il protocollo HTTP utilizzato per la comunicazione tra un server web e i suoi client. Questo è lo scopo dei seguenti programmi.

Il client web descritto nella Sezione 9.2 ci ha permesso di esplorare parte del protocollo HTTP.

Image

Nella loro forma più semplice, gli scambi client/server sono i seguenti:

  • il client apre una connessione alla porta 80 sul server web
  • effettua una richiesta per un documento
  • il server web invia il documento richiesto e chiude la connessione
  • il client chiude quindi la connessione

Il documento può assumere varie forme: testo HTML, un'immagine, un video, ecc. Può trattarsi di un documento esistente (documento statico) o di un documento generato al volo da uno script (documento dinamico). In quest'ultimo caso, si parla di programmazione web. Lo script per la generazione dinamica dei documenti può essere scritto in vari linguaggi: PHP, Python, Perl, Java, Ruby, C#, VB.NET, ecc.

Qui utilizziamo PHP per generare dinamicamente documenti di testo.

  • In [1], il client stabilisce una connessione con il server, richiede uno script PHP e può inviare o meno dei parametri a tale script
  • In [2], il server web esegue lo script PHP utilizzando l'interprete PHP. Questo script genera un documento che viene inviato al client [3]
  • Il server chiude la connessione. Il client fa lo stesso.

Il server web può gestire più client contemporaneamente. Con il pacchetto software WampServer, il server web è un server Apache, un server open source della Apache Foundation (http://www.apache.org/). Nelle seguenti applicazioni, WampServer deve essere avviato. Ciò attiva tre componenti: il server web Apache, il sistema di gestione di database MySQL e l'interprete PHP.

Gli script eseguiti dal server web saranno scritti utilizzando lo strumento NetBeans. Finora abbiamo scritto script PHP eseguiti in un ambiente console:

L'utente utilizza la console per richiedere l'esecuzione di uno script PHP e ricevere i risultati.

Nelle applicazioni client/server che seguono,

  • lo script client viene eseguito in un ambiente console
  • lo script server viene eseguito in un ambiente web

Lo script PHP del server non può trovarsi in una posizione qualsiasi del file system. Questo perché il server web cerca i documenti statici e dinamici che gli vengono richiesti nelle posizioni specificate dalla configurazione. La configurazione predefinita di WampServer fa sì che i documenti vengano cercati nella cartella <WampServer>/www, dove <WampServer> è la cartella di installazione di WampServer. Pertanto, se un client web richiede un documento D con l'URL [http://localhost/D], il server web fornirà il documento D situato nel percorso [<WampServer>/www/D].

Negli esempi seguenti, inseriremo gli script del server nella cartella [www/web-examples]. Se uno script del server si chiama S.php, verrà richiesto al server web utilizzando l'URL [http://localhost/exemples-web/S.php]. Verrà quindi servito il documento [<WampServer>/www/web-examples/S.php].

Per creare uno script lato server con NetBeans , procederemo come segue:

  • In [1], creiamo un nuovo progetto
  • In [2], selezioniamo la categoria [PHP] e il progetto [PHP Application]
  • in [3], diamo un nome al progetto
  • In [4], scegliamo una cartella per il progetto
  • In [5], specifichiamo che lo script deve essere eseguito da un server web locale (l'URL dello script avrà il formato http://localhost/...). Il server web locale sarà il server web Apache di WampServer.
  • In [6], specifichiamo l'URL del progetto. Qui, decidiamo che uno script denominato S.php nel progetto sarà accessibile tramite l'URL [http://localhost/exemples-web/S.php]. Sulla base di quanto sopra, ciò significa che il percorso dello script S.php nel file system sarà [<WampServer>/www/web-examples/S.php]. Questo è ciò che viene specificato in [7]. Qui, specifichiamo che qualsiasi script S.php nel progetto debba essere copiato nella struttura delle directory del server web Apache.
  • in [8], il nuovo progetto.

Scriviamo uno script di prova:

  • In [1], creiamo un primo script PHP nel progetto [web-examples]
  • In [2], gli diamo un nome
  • in [3], dopo averlo creato, gli attribuiamo il seguente contenuto

Successivamente, WampServer deve essere in esecuzione.

  • In [4], eseguiamo lo script web [example1.php]. NetBeans avvierà quindi il browser predefinito del computer e gli chiederà di visualizzare l'URL [http://localhost/exemples-web/exemple1.php] [5]
  • In [6], il browser visualizza ciò che lo script del server ha inviato al client.

Proseguendo, incontreremo due tipi di client web:

  • un browser come descritto sopra. Abbiamo notato che il server web invia una risposta nella forma: intestazioni HTTP, riga vuota, testo. Il browser visualizza solo il testo.
  • uno script PHP che visualizzerà l'intera risposta: intestazioni HTTP, riga vuota, testo.

D'ora in poi,

  • gli script lato server saranno scritti come [example1.php] sopra
  • gli script lato client saranno scritti come gli script da console che abbiamo scritto finora.

10.1. Applicazione client/server per data e ora

10.1.1. Il server (web_01)


<?php
// time: number of milliseconds since 01/01/1970
// date-time display format
// d: 2-digit day
// m: 2-digit month
// y: 2-digit year
// H: hour 0.23
// i : minutes
// s: seconds
print date("d/m/y H:i:s",time());

In sostanza, lo script PHP sopra riportato visualizza l'ora corrente sullo schermo. Tuttavia, quando viene eseguito da un server web, lo stream 1 — che di solito è associato allo schermo — viene reindirizzato alla connessione che collega il server al suo client. Pertanto, in un contesto web, lo script sopra riportato invia l'ora corrente come testo al client.

Eseguiamo questo script all'interno di NetBeans:

  • In [1], eseguiamo lo script. Viene quindi avviato un browser web.
  • In [2], l'URL richiesto dal browser web
  • In [3], il testo inviato dallo script del server

Il browser client utilizza il protocollo HTTP per comunicare con il server web. Abbiamo già descritto la struttura di questo protocollo.

Il client invia righe di testo che possono essere suddivise in tre parti: intestazioni HTTP, una riga vuota e il documento. Il documento inviato al server web è solitamente vuoto o consiste in un insieme di parametri nella forma parami=vali, dove vali è un valore inserito dall’utente in un modulo HTML.

La risposta del server ha la stessa struttura: intestazioni HTTP, una riga vuota e un documento, dove il documento è questa volta quello richiesto dal browser del client. Se il client ha inviato dei parametri, il documento restituito dipende generalmente da tali parametri.

Con il browser Firefox è possibile visualizzare i dati effettivamente scambiati tra il client e il server web. Esiste un'estensione di Firefox chiamata Firebug che consente di monitorare questo scambio di dati. Firebug è disponibile all'URL [https://addons.mozilla.org/fr/firefox/addon/firebug/]. Se si utilizza il browser Firefox per visitare questo URL, è possibile scaricare il plugin Firebug. Di seguito si presuppone che il plugin Firebug sia stato scaricato e installato. È accessibile tramite un'opzione nel menu di Firefox:

 

Una finestra di Firebug si apre all'interno della finestra del browser Firefox. Questa finestra dispone a sua volta di un menu:

 

Per visualizzare gli scambi client/server durante una richiesta HTTP, inseriamo l'URL [http://localhost/exemples-web/web_01.php] nel browser Firefox. La finestra di Firebug si riempie quindi di informazioni:

Di seguito è riportato un riepilogo degli scambi client/server:

  • [1]: Il client ha inviato la richiesta HTTP: GET /exemples-web/web_01.php HTTP/1.1 per richiedere il documento [web01.php]
  • [2]: Il server ha inviato la risposta: HTTP/1.1 200 OK, indicando di aver trovato il documento richiesto.

Firebug consente di visualizzare gli scambi completi. È sufficiente "espandere" l'URL:

Sopra, vediamo le intestazioni HTTP scambiate tra il client (Richiesta) e il server (Risposta). È possibile ottenere il codice sorgente dello scambio, ovvero le righe di testo effettivamente scambiate [1]. Otteniamo quindi il seguente codice sorgente:

 

Per scrivere uno script lato client per il server web, basta semplicemente replicare il comportamento del browser. Dopo aver stabilito una connessione con il server, lo script lato client potrebbe inviare le 8 righe della richiesta mostrata sopra. In realtà, non tutto è essenziale, e invieremo solo le seguenti tre righe:

1
2
3
GET /exemples-web/web01.php HTTP/1.1
Host: localhost
Connection: close
  • Riga 1: specifica il documento richiesto e il protocollo HTTP utilizzato
  • Riga 2: fornisce il nome host dello script client
  • riga 3: indica che, dopo lo scambio, il client chiuderà la connessione al server

Esaminiamo ora la risposta del server. Sappiamo che è stata generata dallo script PHP [web_01.php]. Sopra, vediamo le intestazioni HTTP della risposta. Il codice dello script [web01.php] mostra che non le ha generate. Ricordiamo la configurazione dello script del server:

È il server web che ha generato le intestazioni HTTP della risposta. Lo script del server può generarle autonomamente. Ne vedremo un esempio più avanti.

Abbiamo accennato al fatto che la risposta del server web ha la forma: intestazioni HTTP, riga vuota, documento. Se il documento è un documento di testo, possiamo visualizzarlo nella scheda [Response] di Firebug:

 

Questa risposta è stata generata dallo script [web_01.php].

10.1.2. Un client (client1_web_01)

Ora scriveremo uno script client per il servizio precedente. Sappiamo che il client deve:

  • aprire una connessione con il server web
  • inviare il testo: intestazioni HTTP, riga vuota
  • leggere la risposta completa del server fino a quando il server non chiude la connessione con il client
  • chiudere la connessione con il server

Lo script client viene eseguito in un ambiente console di NetBeans:

  • in [1], lo script client [client1_web_01.php] è incluso nel progetto NetBeans [examples]
  • in [2], le proprietà del progetto NetBeans [examples]
  • in [3], il progetto NetBeans [examples] viene eseguito in modalità "riga di comando", che abbiamo anche definito modalità "console".

Il codice dello script client è il seguente:


<?php
 
// data
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_01.php";
// open a connection on port 80 of $HOTE
$connexion = fsockopen($HOTE, $PORT);
// mistake?
if (!$connexion) {
  print "Erreur : $erreur\n";
  exit;
}
// protocol HTTP headers must end with an empty line
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Connection
fputs($connexion,"Connection: close\n");
// blank line
fputs($connexion,"\n");
// the server will now respond on channel $connexion. It will send all
// then close the channel. The client therefore reads everything that arrives from $connexion
// until the channel closes
while ($ligne = fgets($connexion, 1000)) {
  print "$ligne";
}//while
// the customer in turn closes the connection
fclose($connexion);
// end
exit;

Commenti

  • riga 8: apertura di una connessione al server
  • riga 16: comando HTTP GET
  • riga 18: comando HTTP Host
  • riga 20: comando HTTP Connection
  • riga 22: riga vuota
  • Righe 26–28: Lettura di tutte le righe di testo inviate dal server fino alla chiusura della connessione.
  • riga 30: il client chiude la connessione

Risultati

L'esecuzione dello script client produce i seguenti risultati:

1
2
3
4
5
6
7
8
9
HTTP/1.1 200 OK
Date: Wed, 17 Aug 2011 13:35:00 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Content-Length: 17
Connection: close
Content-Type: text/html

17/08/11 13:35:00

Commenti

  • Righe 1–7: la risposta HTTP dal server web.
  • Riga 8: la riga vuota che segnala la fine delle intestazioni HTTP
  • Righe 9 e seguenti: il documento. In questo caso, si tratta di un semplice testo che rappresenta la data e l'ora correnti. Questo è il testo scritto dallo script PHP per generare l'output n. 1.
  • Riga 1: il server risponde di aver trovato il documento richiesto.
  • Riga 2: data e ora correnti del server
  • Riga 3: identità del server web
  • riga 4: indica che il documento che segue è generato da uno script PHP
  • Riga 5: numero di caratteri nel documento
  • Riga 6: il server indica che, dopo aver inviato il documento, chiuderà la connessione
  • riga 7: indica che il documento inviato dal server è testo in formato HTML. In questo caso ciò non è corretto. Il documento è testo semplice. Quando il documento non è in formato HTML, spetta allo script PHP indicarlo. In questo caso non lo abbiamo fatto.

10.1.3. Un secondo client (client2_web_01)

Il client precedente visualizzava tutto ciò che il server web gli inviava. In pratica, generalmente ignoriamo le intestazioni HTTP nella risposta e ci concentriamo sul corpo del documento. Qui, vogliamo recuperare la data e l'ora inviate dallo script PHP lato server. Recupereremo queste informazioni utilizzando un'espressione regolare.


<?php
 
// retrieve information sent by a web server
// data
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_01.php";
// open a connection on port 80 of $HOTE
$connexion = fsockopen($HOTE, $PORT);
// mistake?
if (!$connexion) {
  print "Erreur : $erreur\n";
  exit;
}
// protocol HTTP headers must end with an empty line
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Connection
fputs($connexion,"Connection: close\n");
// blank line
fputs($connexion,"\n");
// the server will now respond on channel $connexion. It will send all
// then close the channel. The client therefore reads everything that arrives from $connexion
// until it finds the line it's looking for in the form dd/mm/yy hh:mm:ss
while ($ligne = fgets($connexion, 1000)) {
  print "$ligne";
  if (preg_match("/(\d\d)\/(\d\d)\/(\d\d) (\d\d):(\d\d):(\d\d)/", $ligne, $champs)) {
     // we retrieve the # fields
    array_shift($champs); // e// removes the 1st element from the array fields
     // we retrieve the 6 fields in 6 variables
    list($j, $m, $a, $h, $i, $s) = $champs;
     // result display
    print "\ndateheure=[$j,$m,$a,$h,$i,$s]\n";
  }////if
}//while
// the customer in turn closes the connection
fclose($connexion);
// end
exit;

Risultati

HTTP/1.1 200 OK
Date: Wed, 17 Aug 2011 14:14:51 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Content-Length: 17
Connection: close
Content-Type: text/html

17/08/11 14:14:51
dateheure=[17,08,11,14,14,51]

10.2. Recupero da parte del server dei parametri inviati dal client

Nel protocollo HTTP, un client dispone di due metodi per trasmettere parametri al server web:

  • richiede l'URL del servizio nel modulo

GET url?param1=val1&param2=val2&param3=val3… HTTP/1.0

dove i valori validi devono essere prima codificati in modo che alcuni caratteri riservati vengano sostituiti dai loro valori esadecimali.

  • Richiede l'URL del servizio nella forma

POST url HTTP/1.0

quindi, tra le intestazioni HTTP inviate al server, include la seguente intestazione:

Content-length=N

Il resto delle intestazioni inviate dal client termina con una riga vuota. Può quindi inviare i propri dati nel formato

val1&param2=val2&param3=val3…

dove i valori validi devono, come nel metodo GET, essere codificati in anticipo. Il numero di caratteri inviati al server deve essere N, dove N è il valore dichiarato nell'intestazione

Content-length=N

Lo script PHP che recupera i precedenti parametri parami inviati dal client ottiene i loro valori dall'array:

  • $_GET["parami"] per una richiesta GET
  • $_POST["parami"] per una richiesta POST

10.2.1. Il client GET (client1_web_02)

Lo script PHP riportato di seguito invia tre parametri [last_name, first_name, age] al server.


<?php
 
// client: sends firstname,lastname,age to the server using the GET method
// data
$HOTE = "localhost";
$PORT = 80;
$URL = "/exemples-web/web_02.php";
list($prenom, $nom, $age) = array("jean-paul", "de la hûche", 45);
// web server connection
$connexion = fsockopen($HOTE, $PORT);
// return if error
if (!$connexion) {
  print "Echec de la connexion au site ($HOTE,$PORT) : $erreur";
  exit;
}//if
// information sent to server PHP
// information is encoded
$infos = "prenom=" . urlencode(utf8_decode($prenom)) . "&nom=" . urlencode(utf8_decode($nom)) . "&age=" . urlencode("$age");
// console monitoring
print "infos envoyées au serveur (GET)=$infos\n";
print "URL demandée=[$URL?$infos]\n\n";
// protocol HTTP headers must end with an empty line
// GET
fputs($connexion, "GET $URL?$infos HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Connection
fputs($connexion,"Connection: close\n");
// blank line
fputs($connexion,"\n");
// the server will now respond on channel $connexion. It will send all
// then close the channel. The client reads everything from $connexion until the channel is closed
while ($ligne = fgets($connexion, 1000))
  print "$ligne";
// the customer in turn closes the connection
fclose($connexion);

Commenti

  • riga 7: URL dello script del server
  • riga 8: valori dei 3 parametri
  • riga 10: apre una connessione al server web
  • riga 18: codifica dei 3 parametri. Stiamo lavorando su uno script scritto in NetBeans con codifica dei caratteri UTF-8. Pertanto, i valori dei 3 parametri della riga 8 sono codificati in UTF-8. La funzione utf8_decode converte la loro codifica in ISO-8859-1. Una volta fatto questo, possono essere codificati per l'URL. Tutti i caratteri non alfabetici vengono sostituiti da %xx, dove xx è il valore esadecimale del carattere. Gli spazi vengono sostituiti dal segno +.
  • Riga 24: L'URL richiesto è $URL?$infos, dove $infos ha la forma last_name=val1&first_name=val2&age=val3.

10.2.2. Il server (web_02)

Il server visualizza semplicemente ciò che riceve.


<?php
 
// error management
ini_set("display_errors", "off");
 
// server retrieves information sent by the client
// here firstname=P&lastname=N&age=A
// this information is automatically available in the
// $_GET['prenom'], $_GET['nom'], $_GET['age']
// we send them back to the customer
 
// uTF-8 header
header("Content-Type: text/plain; charset=utf-8");
 
// parameters sent to server
$prenom = isset($_GET['prenom']) ? $_GET['prenom'] : "";
$nom = isset($_GET['nom']) ? $_GET['nom'] : "";
$age = isset($_GET['age']) ? $_GET['age'] : "";
 
// customer response
$réponse = "informations reçues du client [" .
        utf8_encode(htmlspecialchars($prenom, ENT_QUOTES)) .
        "," . utf8_encode(htmlspecialchars($nom, ENT_QUOTES)) .
        "," . utf8_encode(htmlspecialchars($age, ENT_QUOTES)) . "]\n";
print $réponse;

Commenti

  • riga 13: imposta l'intestazione HTTP "Content-Type". Per impostazione predefinita, il server web invia l'intestazione
Content-Type: text/html

, che indica che la risposta è testo in formato HTML. In questo caso, la risposta sarà testo non formattato con caratteri codificati in UTF-8:

Content-Type: text/plain; charset=utf-8

Le intestazioni HTTP devono essere inviate prima della risposta del server. Pertanto, nel codice sopra riportato, la chiamata alla funzione header deve precedere qualsiasi istruzione print.

  • Righe 16–18: recuperiamo i tre parametri dall'array $_GET.
  • Riga 21: costruiamo la stringa che verrà inviata come risposta al client. Alcuni caratteri hanno significati speciali in HTML e devono essere sostituiti con entità HTML per essere visualizzati. htmlspecialchars($string) sostituisce tutti questi caratteri con i loro equivalenti nella stringa $string. Ad esempio, il carattere $ diventa &amp. Quindi, poiché abbiamo specificato alla riga 13 che la risposta sarebbe stata testo UTF-8, codifichiamo i valori recuperati in UTF-8.
  • Riga 25: La risposta viene inviata al client

Test 1

Eseguiamo lo script [web_02] da NetBeans. Si aprirà quindi un browser per visualizzare l'URL [http://localhost/exemples-web/web_02.php]:

  • In [1], il browser visualizza l'URL [http://localhost/exemples-web/web_02.php]. Poiché non abbiamo aggiunto parametri a questo URL, il server ha risposto con parametri vuoti. Ricordiamo che la risposta del server è quella scritta con l'istruzione print.
  • In [2], aggiungiamo dei parametri all'URL. Questa volta, lo script del server li restituisce correttamente.

Si noti che NetBeans non è necessario per eseguire uno script del server. È sufficiente inserire l'URL dello script del server in un browser per eseguirlo.

Test 2

Eseguiamo il client [client1_web_02.php] in NetBeans. Riceviamo la seguente risposta:

infos envoyées au serveur (GET)=prenom=jean-paul&nom=de+la+h%FBche&age=45
URL demandée=[/exemples-web/web_02.php?prenom=jean-paul&nom=de+la+h%FBche&age=45]

HTTP/1.1 200 OK
Date: Wed, 17 Aug 2011 14:31:01 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Content-Length: 59
Connection: close
Content-Type: text/plain; charset=utf-8

informations reçues du client [jean-paul,de la hûche,45]
  • Riga 1: Codifica dei 3 parametri. Si può notare che il carattere û è diventato %FB.
  • Riga 12: la risposta del server

10.2.3. Il client POST (client2_web_03)

Un client HTTP invia la seguente sequenza di testo al server web: intestazioni HTTP, riga vuota, documento. Nel client precedente, questa sequenza era la seguente:

GET /url?paramètres HTTP/1.1
… autres entêtes HTTP
ligne vide

Non c'era alcun documento. Esiste un altro modo per trasmettere i parametri, noto come metodo POST. In questo caso, la sequenza di testo inviata al server web è la seguente:

POST /url HTTP/1.1
… autres entêtes HTTP
ligne vide
paramètres

In questo caso, i parametri che erano inclusi nelle intestazioni HTTP per il client GET fanno parte del documento inviato dopo le intestazioni nel client POST.

Lo script del client POST è il seguente:


<?php
 
// client: sends firstname,lastname,age to the server using the POST method
// data
$HOTE = "localhost";
$PORT = 80;
$URL = "/exemples-web/web_03.php";
list($prenom, $nom, $age) = array("jean-paul", "de la hûche", 45);
// web server connection
$connexion = fsockopen($HOTE, $PORT);
// return if error
if (!$connexion) {
  print "Echec de la connexion au site ($HOTE,$PORT) : $erreur";
  exit;
}//if
// information sent to server PHP
// information is encoded
$infos = "prenom=" . urlencode(utf8_decode($prenom)) . "&nom=" . urlencode(utf8_decode($nom)) . "&age=" . urlencode("$age");
print "client : infos envoyées au serveur (POST) : $infos\n";
// connect to the URL $URL by posting (POST) parameters to it
// protocol HTTP headers must end with an empty line
// POST
fputs($connexion, "POST $URL HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Connection
fputs($connexion,"Connection: close\n");
// Content-type
fputs($connexion, "Content-type: application/x-www-form-urlencoded\n");
// Content-length
// send the size (number of characters) of the information to be sent
fputs($connexion, "Content-length: " . strlen($infos) . "\n");
// send an empty line
fputs($connexion, "\n");
// we send the news
fputs($connexion, $infos);
// the server will now respond on channel $connexion. It will send all
// then close the channel. The client reads everything that arrives from $connexion
// until the channel closes
while ($ligne = fgets($connexion, 1000))
  print "$ligne";
// the customer in turn closes the connection
fclose($connexion);

Commenti

  • Riga 7: L'URL del servizio web a cui si connetterà il client POST. Questo servizio web verrà descritto tra poco.
  • Riga 8: i parametri da inviare al servizio web
  • Riga 10: Connessione al server web
  • riga 18: codifica dei parametri da inviare al servizio web
  • riga 23: comando HTTP POST
  • riga 25: comando HTTP Host
  • riga 27: intestazione HTTP Connection
  • riga 29: intestazione HTTP Content-Type. Abbiamo già incontrato questa intestazione HTTP. È presente ogni volta che viene inviato un documento. Un server web che invia un documento HTML utilizza l'HTTP
Content-type : text/html

Se invia testo non formattato, utilizza l'intestazione HTTP

Content-type : text/plain

Il nostro client POST invia un documento sotto forma di testo nel formato param1=val1&param2=val2&.... Questo tipo di documento ha il tipo application/x-www-form-urlencoded. Non spiegheremo il motivo, poiché ciò richiederebbe una spiegazione di cosa sia un modulo web.

  • Riga 32: direttiva Content-length. Abbiamo già incontrato questo header HTTP. È presente ogni volta che viene inviato un documento. Indica il numero di byte nel documento.
  • Riga 34: La riga vuota che indica la fine delle intestazioni HTTP
  • Riga 36: invio dei parametri
  • Righe 40–41: Lettura della risposta completa dal server
  • Riga 43: chiusura della connessione

10.2.4. Il server (web_03)

Il servizio web [web_03] fa la stessa cosa del servizio web [web_02]. Legge i parametri inviati dal client POST e li rimanda al client. Il suo codice è il seguente:


<?php
 
// error management
ini_set("display_errors", "off");
// uTF-8 header
header("Content-Type: text/plain; charset=utf-8");
 
// server retrieves information sent by the client
// here firstname=P&lastname=N&age=A
// this information is automatically available in the
// $_POST['prenom'], $_POST['nom'], $_POST['age']
// we send them back to the customer
// parameters sent to server
$prenom = isset($_POST['prenom']) ? $_POST['prenom'] : "";
$nom = isset($_POST['nom']) ? $_POST['nom'] : "";
$age = isset($_POST['age']) ? $_POST['age'] : "";
// customer response
$réponse = "informations reçues du client [" .
        utf8_encode(htmlspecialchars($prenom, ENT_QUOTES)) .
        "," . utf8_encode(htmlspecialchars($nom, ENT_QUOTES)) .
        "," . utf8_encode(htmlspecialchars($age, ENT_QUOTES)) . "]\n";
print $réponse;

Commenti

  • righe 14–16: I parametri inviati da un client POST diventano disponibili nell'array $_POST per il servizio web che li riceve.
  • riga 6: intestazione HTTP Content-Type. Potresti essere sorpreso di non trovare l'intestazione HTTP Content-Length tra le intestazioni HTTP, che indica la dimensione del documento rinviato al client. Abbiamo visto che il server web invia le intestazioni HTTP per impostazione predefinita. L'intestazione Content-Length è una di queste.

Risultati

Una volta scritto lo script del server in NetBeans, questo diventa immediatamente disponibile tramite il server Apache WampServer. Ricordate che ciò si ottiene tramite la configurazione (vedere il paragrafo 10). Avviamo il client, che interroga il server, e riceviamo quindi la seguente risposta:

client : infos envoyées au serveur (POST) : prenom=jean-paul&nom=de+la+h%FBche&age=45
HTTP/1.1 200 OK
Date: Sat, 20 Aug 2011 12:55:19 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Content-Length: 59
Connection: close
Content-Type: text/plain; charset=utf-8

informations reçues du client [jean-paul,de la hûche,45]
  • righe 2-10: la risposta del server
  • righe 2-8: le intestazioni HTTP
  • riga 10: il documento
  • riga 6: l'intestazione HTTP Content-Length. Poiché questa intestazione non è stata generata dallo script del server, è stata generata dal server web.
  • Riga 8: l'unica intestazione generata dallo script del server

10.3. Recupero delle variabili di ambiente del server web

Uno script server viene eseguito in un ambiente web a cui può accedere. Questo ambiente è memorizzato nel dizionario $_SERVER. Per prima cosa, scriviamo un'applicazione server che invia il contenuto di questo dizionario ai propri client.

10.3.1. Il server (web_04)


<?php
 
// error management
ini_set("display_errors", "off");
// uTF-8 header
header("Content-Type: text/plain; charset=utf-8");
 
// returns to the client the list of variables available in the server environment
foreach ($_SERVER as $clé => $valeur) {
  print "[$clé,$valeur]\n";
}
  • Le coppie (chiave, valore) del dizionario $_SERVER vengono inviate ai client.

Il risultato ottenuto quando il client è un browser web è il seguente:

Image

Ecco il significato di alcune delle variabili (per Windows. Su Linux sarebbero diverse):

HTTP_CMDE
CMDE rappresenta l'intestazione HTTP inviata dal client. Abbiamo accesso a tutte queste intestazioni.
PATH
Il percorso degli eseguibili sulla macchina in cui è in esecuzione lo script del server
COMSPEC
Il percorso dell'interprete di comandi DOS
PATHEXT
le estensioni dei file eseguibili
WINDIR
la cartella di installazione di Windows
SERVER_SIGNATURE
la firma del server web. Niente qui.
SERVER_SOFTWARE
il tipo di server web
SERVER_NAME
Il nome Internet del computer che ospita il server web
PORTA_SERVER
La porta di ascolto del server web
SERVER_ADDR
l'indirizzo IP del computer del server web
REMOTE_ADDR
l'indirizzo IP del client. In questo caso, il client si trovava sulla stessa macchina del server.
REMOTE_PORT
la porta di comunicazione del client
DOCUMENT_ROOT
la radice dell'albero di directory dei documenti serviti dal server web
SERVER_ADMIN
l'indirizzo e-mail dell'amministratore del server web
SCRIPT_FILENAME
il percorso completo dello script del server
SERVER_PROTOCOL
la versione del protocollo HTTP utilizzato dal server web
REQUEST_METHOD
il metodo HTTP utilizzato dal client. Ce ne sono quattro: GET, POST, PUT, DELETE
QUERY_STRING
i parametri inviati con una richiesta GET /url?parametri
REQUEST_URI
L'URL richiesto dal client. Se il browser richiede l'URL http://machine[:port]/uri, REQUEST_URI sarà uri
SCRIPT_NAME
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_NAME']

10.3.2. Il client (client1_web_04)

Il client visualizza semplicemente tutto ciò che il server gli invia.


<?php
 
// data
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_04.php";
// open a connection on port 80 of $HOTE
$connexion = fsockopen($HOTE, $PORT);
// mistake?
if (!$connexion) {
  print "Erreur : $erreur\n";
  exit;
}
 
// connect to the Web server on a URL
// protocol HTTP headers must end with an empty line
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Connection
fputs($connexion,"Connection: close\n");
// blank line
fputs($connexion,"\n");
// the server will now respond on channel $connexion. It will send all
// then close the channel. The client therefore reads everything that arrives from $connexion
// until the channel closes
while ($ligne = fgets($connexion, 1000)) {
  print "$ligne";
}//while
// the customer in turn closes the connection
fclose($connexion);
// end
exit;

Risultati

HTTP/1.1 200 OK
Date: Sat, 20 Aug 2011 14:11:58 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Content-Length: 1353
Connection: close
Content-Type: text/plain; charset=utf-8

[HTTP_HOST,localhost]
[HTTP_CONNECTION,close]
[PATH,C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Microsoft SQL Server\90\Tools\binn\;...;]
[SystemRoot,C:\Windows]
[COMSPEC,C:\Windows\system32\cmd.exe]
[PATHEXT,.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC]
[WINDIR,C:\Windows]
[SERVER_SIGNATURE,]
[SERVER_SOFTWARE,Apache/2.2.17 (Win32) PHP/5.3.5]
[SERVER_NAME,localhost]
[SERVER_ADDR,127.0.0.1]
[SERVER_PORT,80]
[REMOTE_ADDR,127.0.0.1]
[DOCUMENT_ROOT,C:/serveursSGBD/wamp21/www/]
[SERVER_ADMIN,admin@localhost]
[SCRIPT_FILENAME,C:/serveursSGBD/wamp21/www/exemples-web/web_04.php]
[REMOTE_PORT,54552]
[GATEWAY_INTERFACE,CGI/1.1]
[SERVER_PROTOCOL,HTTP/1.1]
[REQUEST_METHOD,GET]
[QUERY_STRING,]
[REQUEST_URI,/exemples-web/web_04.php]
[SCRIPT_NAME,/exemples-web/web_04.php]
[PHP_SELF,/exemples-web/web_04.php]
[REQUEST_TIME,1313849518]

10.4. Gestione delle sessioni web

Negli esempi client/server precedenti, il processo era il seguente:

  • il client apre una connessione alla porta 80 sul server web
  • invia la sequenza di testo: intestazioni HTTP, riga vuota, [documento]
  • in risposta, il server invia una sequenza dello stesso tipo
  • il server chiude la connessione con il client
  • il client chiude la connessione al server

Se lo stesso client effettua una nuova richiesta al server web poco dopo, viene stabilita una nuova connessione tra il client e il server. Il server non è in grado di distinguere se il client che si sta connettendo abbia già visitato il sito in precedenza o se si tratti di una richiesta iniziale. Tra una connessione e l’altra, il server “dimentica” il proprio client. Per questo motivo, il protocollo HTTP è considerato un protocollo stateless. Tuttavia, è utile che il server ricordi i propri client. Ad esempio, se un'applicazione è sicura, il client invierà al server un nome utente e una password per autenticarsi. Se il server "dimenticasse" il proprio client tra una connessione e l'altra, il client dovrebbe autenticarsi ad ogni nuova connessione, il che non è fattibile.

Per tracciare un client, il server procede come segue: quando un client effettua una richiesta iniziale, il server include un identificatore nella sua risposta, che il client deve poi rispedire con ogni richiesta successiva. Utilizzando questo identificatore, che è unico per ogni client, il server può riconoscere il client. Può quindi mantenere un registro per quel client sotto forma di un file associato in modo univoco all’identificatore del client.

Tecnicamente, ecco come funziona:

  • Nella risposta a un nuovo client, il server include l'intestazione HTTP Set-Cookie: Key=Identifier. Lo fa solo alla prima richiesta.
  • Nelle richieste successive, il client invierà il proprio identificatore tramite l'intestazione HTTP Cookie: Key=Identifier in modo che il server possa riconoscerlo.

Ci si potrebbe chiedere come fa il server a sapere se ha a che fare con un nuovo client piuttosto che con uno già presente. È la presenza dell’intestazione HTTP Cookie nelle intestazioni HTTP del client a dirglielo. Per un nuovo client, questa intestazione è assente.

L'insieme delle connessioni da un dato client è chiamato sessione.

10.4.1. Il file di configurazione

Affinché la gestione delle sessioni funzioni correttamente con PHP, è necessario verificare che sia configurata correttamente. Su Windows, il file di configurazione è PHP.ini. A seconda del contesto di esecuzione (console, web), il file di configurazione [PHP.ini] deve trovarsi in directory diverse. Per individuarle, utilizzare il seguente script:

1
2
3
4
<?php

// infos PHP
phpinfo();

Riga 4: La funzione phpinfo() fornisce informazioni sull'interprete PHP che esegue lo script. In particolare, restituisce il percorso del file di configurazione [PHP.ini] in uso.

In un ambiente console, otterrai un risultato simile al seguente:

1
2
3
4
5
6
Configuration File (PHP.ini) Path => C:\Windows
Loaded Configuration File => C:\serveursSGBD\wamp21\bin\PHP\php5.3.5\PHP.ini
Scan this dir for additional .ini files => (none)
Additional .ini files parsed => (none)

Riga 2: Il file di configurazione principale è c:\windows\PHP.ini

Riga 3: Un file di configurazione secondario è C:\DBServers\wamp21\bin\PHP\php5.3.5\PHP.ini. Consente di modificare alcune opzioni di configurazione nel file di configurazione principale.

In un ambiente web, si ottiene il seguente risultato:

Image

Il file di configurazione secondario qui non è lo stesso dell'ambiente console. È proprio quest'ultimo che esamineremo. In questo file è presente una sezione dedicata alle sessioni:

[Session]
session.save_handler = files
session.save_path = "C:/serveursSGBD/wamp21/tmp"
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.serialize_handler = PHP
session.cache_expire = 180
session.hash_function = 0
  • Riga 1: i dati della sessione del client vengono salvati in un file
  • Riga 3: la directory in cui vengono salvati i dati della sessione. Se questa directory non esiste, non viene segnalato alcun errore e la gestione della sessione non funziona.
  • Righe 4-5: indicano che l'ID di sessione è gestito dalle intestazioni HTTP Set-Cookie e Cookie
  • riga 6: l'intestazione Set-Cookie avrà il formato Set-Cookie: PHPSESSID=session_id
  • Riga 7: Una sessione client non viene avviata automaticamente. Lo script del server deve richiederla esplicitamente utilizzando la funzione session_start().

10.4.2. Server 1 (web_05)

La gestione dell'ID di sessione è trasparente per un servizio web. Questo identificatore è gestito dal server web. Un servizio web accede alla sessione del client tramite la funzione session_start(). Da quel momento in poi, il servizio web può leggere e scrivere nella sessione del client tramite l'array $_SESSION. Il codice seguente mostra la gestione delle sessioni per tre contatori.


<?php
 
// error management
ini_set("display_errors", "off");
// uTF-8 header
header("Content-Type: text/plain; charset=utf-8");
 
// log in
session_start();
// on met 3 variables en session
if (!isset($_SESSION['N1'])) {
  $_SESSION['N1'] = 0;
}
if (!isset($_SESSION['N2'])) {
  $_SESSION['N2'] = 10;
}
if (!isset($_SESSION['N3'])) {
  $_SESSION['N3'] = 100;
}
// incrementing the 3 variables
$_SESSION['N1']++;
$_SESSION['N2']++;
$_SESSION['N3']++;
// sending information to the customer
print "N1=".$_SESSION['N1']."\n";
print "N2=".$_SESSION['N2']."\n";
print "N3=".$_SESSION['N3']."\n";
// end of session
session_close();
  • riga 9: inizio di una sessione client
  • righe 11-13: l'array $_SESSION è un dizionario chiave-valore. I dati memorizzati in questo dizionario persistono tra le richieste provenienti dallo stesso client. Funge da memoria del client sul server.
  • righe 11-19: se i tre contatori N1, N2, N3 non sono presenti nella sessione, vengono aggiunti ad essa.
  • righe 21–23: vengono incrementati di uno
  • righe 25–27: i loro valori vengono inviati al client

Nel rapporto client/server, la gestione della sessione del client sul server dipende da entrambe le parti, il client e il server:

  • il server è responsabile dell'invio di un identificatore al client alla sua prima richiesta
  • il client ha il compito di rispedire questo identificatore ad ogni nuova richiesta. Se non lo fa, il server supporrà che si tratti di un nuovo client e genererà un nuovo identificatore per una nuova sessione.

Risultati

Utilizziamo un browser web come client. Per impostazione predefinita (in realtà, per configurazione), il browser invia effettivamente al server gli identificatori di sessione che il server gli invia. Man mano che vengono effettuate le richieste, il browser riceverà i tre contatori inviati dal server e ne vedrà incrementarsi i valori.

  • In [1], la prima richiesta al servizio web [web_05]
  • In [2], la terza richiesta mostra che i contatori vengono effettivamente incrementati. I valori dei contatori vengono effettivamente memorizzati tra una richiesta e l'altra.

Utilizziamo Firebug per visualizzare le intestazioni HTTP scambiate tra il server e il client. Chiudiamo Firefox per terminare la sessione corrente con il server, lo riapriamo e attiviamo Firebug. Richiediamo il servizio [web_05]:

Sopra, vediamo l'ID di sessione inviato dal server nella sua risposta alla prima richiesta del client. Utilizza l'intestazione HTTP Set-Cookie.

Effettuiamo una nuova richiesta aggiornando (F5) la pagina nel browser web:

Qui noteremo due cose:

  • Il browser web rinvia l'ID di sessione tramite l'intestazione HTTP Cookie.
  • Nella sua risposta, il servizio web non include più questo identificatore. Ora spetta al client inviarlo con ciascuna delle sue richieste.

10.4.3. Client 1 (client1_web_05)

Ora scriveremo uno script lato client basato sullo script lato server precedente. Nella gestione della sessione, deve comportarsi come il browser web:

  • Nella risposta del server alla sua prima richiesta, deve trovare l'ID di sessione che il server gli invia. Sa che lo troverà nell'intestazione HTTP Set-Cookie.
  • Per ogni richiesta successiva, deve inviare l'identificatore ricevuto al server. Lo farà utilizzando l'intestazione HTTP Cookie.

Il codice client è il seguente:


<?php
 
// data
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_05.php";
// tests
$cookie = "";
for ($i = 0; $i < 5; $i++) {
  list($erreur, $cookie, $N1, $N2, $N3) = connecte($HOTE, $PORT, $urlServeur, $cookie);
  print "----------------------------\n";
  print "client(erreur,cookie,N1,N2,N3)=[$erreur,$cookie,$N1,$N2,$N3]\n";
  print "----------------------------\n";
}
// end
exit;
 
function connecte($HOTE, $PORT, $urlServeur, $cookie) {
  // connects client to ($HOTE,$PORT,$urlServeur)
  // sends the $cookie cookie if it is non-empty
  // displays all lines received in response
  // open a connection on port 80 of $HOTE
  $connexion = fsockopen($HOTE, $PORT);
  // mistake?
  if (!$connexion)
    return array("erreur lors de la connexion au serveur ($HOTE, $PORT)");
  // connect to $urlserveur
  // protocol HTTP headers must end with an empty line
  // GET
  fputs($connexion, "GET $urlServeur HTTP/1.1\n");
  // Host
  fputs($connexion, "Host: localhost\n");
  // Connection
  fputs($connexion, "Connection: close\n");
  // send cookie if non-empty
  if ($cookie) {
    fputs($connexion, "Cookie: $cookie\n");
  }////if
  // send empty line
  fputs($connexion, "\n");
  // the web server response is displayed
  // and take care to retrieve any cookies and Ni
  $N = "";
  while ($ligne = fgets($connexion, 1000)) {
    print "$ligne";
    // cookie - only on 1st response
    if (!$cookie) {
      if (preg_match("/^Set-Cookie: (.*?)\s*$/", $ligne, $champs)) {
        $cookie = $champs[1];
      }
    }
    // n1 value
    if (preg_match("/^N1=(.*?)\s*$/", $ligne, $champs))
      $N1 = $champs[1];
    // n2 value
    if (preg_match("/^N2=(.*?)\s*$/", $ligne, $champs))
      $N2 = $champs[1];
    // n3 value
    if (preg_match("/^N3=(.*?)\s*$/", $ligne, $champs))
      $N3 = $champs[1];
  }////while
  // close the connection
  fclose($connexion);
  // return
  return array("", $cookie, $N1, $N2, $N3);
}

Commenti

  • righe 3-16: il programma principale
  • righe 18–67: la funzione di connessione
  • Righe 9–14: il client chiama il server cinque volte e visualizza i valori successivi dei contatori N1, N2 e N3. Se la sessione è gestita correttamente, questi contatori dovrebbero essere incrementati di 1 ad ogni nuova richiesta.
  • Riga 10: la funzione `connecte` utilizza i parametri `$HOTE`, `$PORT` e `$urlServeur` per connettere il client al servizio web. Il parametro `$cookie` rappresenta l'ID della sessione. Alla prima chiamata, è una stringa vuota. Nelle chiamate successive, è l'ID della sessione inviato dal server in risposta alla prima chiamata del client. La funzione `connecte` restituisce i valori dei tre contatori `$N1`, `$N2`, `$N3`, l'ID di sessione `$cookie` ed eventuali errori in `$erreur`.
  • Riga 18: La funzione `connecte` ha le caratteristiche di un client HTTP standard. Commenteremo solo le nuove funzionalità.
  • Righe 30–40: invio delle intestazioni HTTP.
  • Righe 36–38: Se l'ID di sessione è noto, viene inviato al server
  • Righe 44–66: elaborazione di tutte le righe di testo inviate dal server
  • Righe 47–51: se l'ID di sessione non è stato ancora recuperato, viene recuperato dall'intestazione HTTP Set-Cookie utilizzando un'espressione regolare.
  • Righe 53-54: anche il contatore N1 viene ottenuto utilizzando un'espressione regolare
  • righe 56–57, 59–60: lo stesso vale per i contatori N2 e N3
  • riga 63: chiusura della connessione al server.
  • Riga 65: i risultati vengono restituiti come array.

Risultati

L'esecuzione dello script client fa sì che nella console di NetBeans venga visualizzato quanto segue:

HTTP/1.1 200 OK
Date: Sun, 21 Aug 2011 13:59:17 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Set-Cookie: PHPSESSID=ohiqtkv7hu2b26kdshjtqms9p7; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 18
Connection: close
Content-Type: text/plain; charset=utf-8

N1=1
N2=11
N3=101
----------------------------
client(erreur,cookie,N1,N2,N3)=[,PHPSESSID=ohiqtkv7hu2b26kdshjtqms9p7; path=/,1,11,101]
----------------------------
HTTP/1.1 200 OK
Date: Sun, 21 Aug 2011 13:59:18 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 18
Connection: close
Content-Type: text/plain; charset=utf-8

N1=2
N2=12
N3=102
----------------------------
client(erreur,cookie,N1,N2,N3)=[,PHPSESSID=ohiqtkv7hu2b26kdshjtqms9p7; path=/,2,12,102]
----------------------------
HTTP/1.1 200 OK
Date: Sun, 21 Aug 2011 13:59:18 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 18
Connection: close
Content-Type: text/plain; charset=utf-8

N1=3
N2=13
N3=103
----------------------------
client(erreur,cookie,N1,N2,N3)=[,PHPSESSID=ohiqtkv7hu2b26kdshjtqms9p7; path=/,3,13,103]
----------------------------
HTTP/1.1 200 OK
Date: Sun, 21 Aug 2011 13:59:18 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 18
Connection: close
Content-Type: text/plain; charset=utf-8

N1=4
N2=14
N3=104
----------------------------
client(erreur,cookie,N1,N2,N3)=[,PHPSESSID=ohiqtkv7hu2b26kdshjtqms9p7; path=/,4,14,104]
----------------------------
HTTP/1.1 200 OK
Date: Sun, 21 Aug 2011 13:59:18 GMT
Server: Apache/2.2.17 (Win32) PHP/5.3.5
X-Powered-By: PHP/5.3.5
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 18
Connection: close
Content-Type: text/plain; charset=utf-8

N1=5
N2=15
N3=105
----------------------------
client(erreur,cookie,N1,N2,N3)=[,PHPSESSID=ohiqtkv7hu2b26kdshjtqms9p7; path=/,5,15,105]
  • Riga 5: Nella sua prima risposta, il server invia l'ID di sessione. Nelle risposte successive, non lo invia più.
  • È chiaro che il server web conserva i valori di (N1, N2, N3) tra le richieste del client. Questo si chiama tracciamento della sessione.

I due esempi seguenti mostrano che è possibile salvare anche i valori di un array o di un oggetto.

10.4.4. Server 2 (web_06)

Il seguente script del server dimostra che è possibile memorizzare un array o un dizionario in una sessione.


<?php
 
// error management
ini_set("display_errors", "off");
// uTF-8 header
header("Content-Type: text/plain; charset=utf-8");
 
// log in
session_start();
// save a table and a dictionary
// initialize or modify the table
if (isset($_SESSION['tableau'])) {
  for ($i = 0; $i < count($_SESSION['tableau']); $i++) {
    $_SESSION['tableau'][$i]++;
  }
} else {
  for ($i = 0; $i < 10; $i++) {
    $_SESSION['tableau'][$i] = $i * 10;
  }
}
// initialize or modify the dictionary
if (isset($_SESSION['dico'])) {
  foreach (array_keys($_SESSION['dico']) as $clé) {
    $_SESSION['dico'][$clé]++;
  }
} else {
  $_SESSION['dico'] = array("zéro" => 0, "dix" => 10, "vingt" => 20);
}
// sending information to the customer
print "tableau=" . join(",", $_SESSION['tableau']) . "\n";
print "dico=";
foreach ($_SESSION['dico'] as $clé => $valeur) {
  print "($clé,$valeur) ";
}
print "\n";

Commenti

  • righe 17-19: se non esiste già, viene creato un array
  • righe 12–15: se esiste già, i suoi elementi vengono incrementati di 1
  • riga 27: viene inizializzato un dizionario con valori numerici se non esiste già
  • righe 22-25: se è già presente nella sessione, i suoi valori numerici vengono incrementati di 1
  • righe 30-35: l'array e il dizionario vengono inviati al client

10.4.5. Client 2 (client1_web_06)


<?php
 
// data
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_06.php";
// tests
$cookie = "";
for ($i = 0; $i < 5; $i++) {
  connecte($HOTE, $PORT, $urlServeur, $cookie);
}
// end
exit;
 
function connecte($HOTE, $PORT, $urlServeur, &$cookie) {
  // connects client to ($HOTE,$PORT,$urlServeur)
  // sends the $cookie cookie if it is non-empty
  // displays all lines received in response
  // the cookie is passed by reference to be shared between
  // the called program and the calling program
  // open a connection on the $PORT port of $HOTE
  $connexion = fsockopen($HOTE, $PORT);
  // mistake?
  if (!$connexion)
    return array("erreur lors de la connexion au serveur ($HOTE, $PORT)");
  // protocol HTTP headers must end with an empty line
  // GET
  fputs($connexion, "GET $urlServeur HTTP/1.1\n");
  // Host
  fputs($connexion, "Host: localhost\n");
  // Connection
  fputs($connexion, "Connection: close\n");
  // send cookie if non-empty
  if ($cookie) {
    fputs($connexion, "Cookie: $cookie\n");
  }
  // send empty line
  fputs($connexion, "\n");
  // the web server response is displayed
  // and we take care to recover any cookie
  while ($ligne = fgets($connexion, 1000)) {
    print "$ligne";
    // cookie - only on 1st response
    if (!$cookie) {
      if (preg_match("/^Set-Cookie: (.*?)\s*$/", $ligne, $champs)) {
        $cookie = $champs[1];
      }
    }
  }
  // close the connection
  fclose($connexion);
  // return
  return "";
}

Il codice client è simile al codice client già commentato.

Risultati

HTTP/1.1 200 OK
...
Set-Cookie: PHPSESSID=6lvttr0uhpj5q3sl91h4h7p322; path=/
...

tableau=0,10,20,30,40,50,60,70,80,90
dico=(zéro,0) (dix,10) (vingt,20) 

HTTP/1.1 200 OK
...

tableau=1,11,21,31,41,51,61,71,81,91
dico=(zéro,1) (dix,11) (vingt,21) 

HTTP/1.1 200 OK
...

tableau=2,12,22,32,42,52,62,72,82,92
dico=(zéro,2) (dix,12) (vingt,22) 

HTTP/1.1 200 OK
...

tableau=3,13,23,33,43,53,63,73,83,93
dico=(zéro,3) (dix,13) (vingt,23) 

HTTP/1.1 200 OK
...

tableau=4,14,24,34,44,54,64,74,84,94
dico=(zéro,4) (dix,14) (vingt,24) 

10.4.6. Server 3 (web_07)

Il seguente script del server mostra che un oggetto può essere memorizzato in una sessione.


<?php
 
// error management
ini_set("display_errors", "off");
// uTF-8 header
header("Content-Type: text/plain; charset=utf-8");
 
// log in
session_start();
// initialize or modify a Personne object
if (isset($_SESSION['personne'])) {
  $personne = $_SESSION['personne'];
  // increment age
  $personne->setAge($personne->getAge() + 1);
} else {
  // we define the person
  $_SESSION['personne'] = new Personne("paul", "langévin", 10);
}
// customer display
print "personne=".$_SESSION['personne']."\n";
// end
exit;
 
// ----------------------------------------------------------------
class Personne {
 
// class attributes
  private $prénom;
  private $nom;
  private $âge;
 
// getters and setters
  public function getPrénom() {
    return $this->prénom;
  }
 
  public function getNom() {
    return $this->nom;
  }
 
  public function getAge() {
    return $this->âge;
  }
 
  public function setPrénom($prénom) {
    $this->prénom = $prénom;
  }
 
  public function setNom($nom) {
    $this->nom = $nom;
  }
 
  public function setAge($age) {
    $this->âge = $age;
  }
 
// manufacturer
  function __construct($prénom, $nom, $âge) {
    // we go through sets
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }
 
// method toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }
 
}

Commenti

  • riga 17: Aggiungiamo un oggetto Person alla sessione se non è già presente.
  • righe 11-15: se è già presente, aumentiamo la sua età di 1
  • riga 20: inviamo l'oggetto Person al client.

10.4.7. Client 3 (client1_web_07)


<?php
 
// data
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_07.php";
// tests
$cookie = "";
for ($i = 0; $i < 5; $i++) {
  connecte($HOTE, $PORT, $urlServeur, $cookie);
}//if
// end
exit;
 
function connecte($HOTE, $PORT, $urlServeur, &$cookie) {
...
}

Commenti

  • Riga 15: La funzione connect è identica a quella dello script client precedente

Risultati

HTTP/1.1 200 OK
...

personne=[paul,langévin,10]

HTTP/1.1 200 OK
...

personne=[paul,langévin,11]

HTTP/1.1 200 OK
...

personne=[paul,langévin,12]

HTTP/1.1 200 OK
...

personne=[paul,langévin,13]

HTTP/1.1 200 OK
...

personne=[paul,langévin,14]