Bellissimo il post Visualizing Algorithms di Mike Bostock, che introduce con degli ottimi esempi l'importanza della visualizzazione dei risultati di un algoritmo, del grado di correttezza dello stesso o, semplicemente, dei passi che sono stati necessari per ottenere un determinato risultato.
Nella prima parte, dedicata alle tecniche di campionamento, Mike illustra tre diversi algoritmi per la generazione casuale di punti all'interno di un rettangolo, che si desiderano distribuiti in maniera da evitare pattern riconoscibili. Oltre a visualizzare il risultato, si può visualizzare a colpo d'occhio la bontà del risultato raggiunto. Si confrontino ad esempio queste due immagini
nelle quali le macchie più scure rappresentano le aree sottocampionate, e quelle più chiare le aree sovracampionate. Ci si rende conto facilmente che l'algoritmo alla base della seconda immagine è migliore.
Nella seconda parte, un'immagine mostra meglio di mille parole quale problema può nascere dall'utilizzo di un algoritmo usato per un mescolamento casuale di un mazzo di carte (o di qualsiasi altra cosa):
Se l'obiettivo è di avere una distribuzione equiprobabile delle carte, ci possiamo rendere conto, semplicemente visualizzando con diversi colori la distanza dall'obiettivo, quanto siamo lontani da un'implementazione corretta.
Nella terza parte Mark mostra come si possa visualizzare l'esecuzione "passo passo" di un algoritmo, tracciando un grafico che rappresenta la serie di scambi di un quick sort.
Nella quarta parte, forse la più divertente da vedere, sono poi presentati diversi algoritmi per la generazione di labirinti, con una rappresentazione di alberi e della lunghezza dei singoli percorsi basata su una scala di colori.
Come dice Mark, la visualizzazione degli algoritmi può essere un valido ausilio per l'intrattenimento (è divertente vedere gli algoritmi all'opera), per l'insegnamento, per il debugging e per la costruzione di un'interfaccia utente per l'input di dati che sono collegati reciprocamente tra di loro, come nel caso della scelta tra acquisto di una casa o affitto della stessa. Come dargli torto?
sabato, giugno 28, 2014
giovedì, giugno 05, 2014
Fatture in formato XML
Da domani chiunque emetterà fatture verso gli organi centrali della pubblica amministrazione in Italia, dovrà obbligatoriamente predisporre la fattura in formato XML.
Il Governo ha anche preparato un sito internet, www.fatturapa.gov.it, che offre la necessaria documentazione. E fin qui tutto bene.
Ma se si vanno a leggere le specifiche, si può vedere che tutti gli elementi previsti dal DTD sono in italiano, o in alcuni casi in un innaturale mix italiano-inglese. L'esempio di una fattura singola con una sola linea di fattura prevede elementi di questo tipo:
racchiusi in improbabili elementi quali
FatturaElettronicaHeader e FatturaElettronicaBody.
Il Governo ha anche preparato un sito internet, www.fatturapa.gov.it, che offre la necessaria documentazione. E fin qui tutto bene.
Ma se si vanno a leggere le specifiche, si può vedere che tutti gli elementi previsti dal DTD sono in italiano, o in alcuni casi in un innaturale mix italiano-inglese. L'esempio di una fattura singola con una sola linea di fattura prevede elementi di questo tipo:
<CedentePrestatore>
<DatiAnagrafici>
<IdFiscaleIVA>
<IdPaese>IT</IdPaese>
<IdCodice>01234567890</IdCodice>
</IdFiscaleIVA>
<Anagrafica>
<Denominazione>Societa' alpha S.r.l.</Denominazione>
</Anagrafica>
<RegimeFiscale>RF01</RegimeFiscale>
</DatiAnagrafici>
<Sede>
<Indirizzo>Via Roma</Indirizzo>
<CAP>00166</CAP>
<Comune>Roma</Comune>
<Provincia>RM</Provincia>
<Nazione>IT</Nazione>
</Sede>
<StabileOrganizzazione>
<Indirizzo>Piazza Garibaldi</Indirizzo>
<CAP>00100</CAP>
<Comune>Roma</Comune>
<Provincia>RM</Provincia>
<Nazione>IT</Nazione>
</StabileOrganizzazione>
</CedentePrestatore>
FatturaElettronicaHeader e FatturaElettronicaBody.
Non sarebbe stato molto meglio avere uno standard informatico in inglese, magari condiviso a livello europeo / internazionale, in modo da agevolare la predisposizione di strumenti software comuni? Va bene la salvaguardia della lingua nazionale, ma questa dovrebbe riguardare l'interfaccia delle applicazioni, non la definizione degli standard con cui sono rappresentati i dati. Provate a pensarci: se un programmatore italiano volesse sviluppare un'applicazione per la generazione di fatture in formato XML per i vari paesi dell'Unione Europea, dovrebbe preoccuparsi di imparare il maltese, il finlandese, l'estone, il lituano, il greco, ecc.?
E poi, magari qualche standard per la definizione in formato XML delle fatture esiste. Per citarne uno, quello preparato dal Consorzio non-profit OASIS, disponibile all'indirizzo docs.oasis-open.org/ubl/os-UBL-2.1/UBL-2.1.html#T-INVOICE. Per quale motivo non si è seguito quello standard? Mi riprometto di indagare, ma per adesso noto che tra le FAQ non ci sono notizie in merito. (Se avete informazioni, segnalatemele e aggiornerò volentieri questo post.)
venerdì, dicembre 27, 2013
XML, JSON, ecc.
Pubblico questo post per presentare qualche semplice esempio di informazioni inviate da un server web ad un client in diversi formati.
L'esperienza comune degli utenti è l'interazione con un server web mediata da un browser. Il browser agisce come client, chiedendo una risorsa, il server gliela manda. La risorsa, tipicamente, consiste in un documento ipertestuale (una pagina web), oppure un file binario (un'immagine, un file PDF, ecc.).
Se si tratta di un file binario, esso viene presentato all'utente mediante qualche programma di visualizzazione (spesso integrato nel browser come plugin, o direttamente in esso incorporato). Le pagine HTML vengono semplicemente "rese".
Sempre più spesso, però, capita che le informazioni inviate dal server debbano essere elaborate da un'applicazione sul lato client, per i fini più diversi. Non solo rese, ma elaborate: questo significa che il modo in cui le informazioni arrivano sia studiato in modo che i dati siano facilmente elaborabili.
Immaginiamo che un server debba inviare l'elenco dei libri disponibili per il prestito, il cui autore è Manzoni.
Potrebbe inviare un testo semplice, con i titoli uno sotto l'altro:
Content-type: text/plain
Il Conte di Carmagnola
Adelchi
I promessi sposi
Oppure potrebbe inviare un file codificato in XML:
Content-type: text/xml
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="123"><title>Il Conte di Carmagnola</book>
<book id="456"><title>Adelchi</book>
<book id="789"><title>I promessi sposi</book>
</books>
L'esperienza comune degli utenti è l'interazione con un server web mediata da un browser. Il browser agisce come client, chiedendo una risorsa, il server gliela manda. La risorsa, tipicamente, consiste in un documento ipertestuale (una pagina web), oppure un file binario (un'immagine, un file PDF, ecc.).
Se si tratta di un file binario, esso viene presentato all'utente mediante qualche programma di visualizzazione (spesso integrato nel browser come plugin, o direttamente in esso incorporato). Le pagine HTML vengono semplicemente "rese".
Sempre più spesso, però, capita che le informazioni inviate dal server debbano essere elaborate da un'applicazione sul lato client, per i fini più diversi. Non solo rese, ma elaborate: questo significa che il modo in cui le informazioni arrivano sia studiato in modo che i dati siano facilmente elaborabili.
Immaginiamo che un server debba inviare l'elenco dei libri disponibili per il prestito, il cui autore è Manzoni.
Potrebbe inviare un testo semplice, con i titoli uno sotto l'altro:
Content-type: text/plain
Il Conte di Carmagnola
Adelchi
I promessi sposi
Oppure potrebbe inviare un file codificato in XML:
Content-type: text/xml
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="123"><title>Il Conte di Carmagnola</book>
<book id="456"><title>Adelchi</book>
<book id="789"><title>I promessi sposi</book>
</books>
Oppure ancora, inviare gli stessi dati in formato JSON:
Content-type: application/json
[{"id":123,"title":"Il Conte di Carmagnola"},{"id":456,"title":"Adelchi"},{"id":789,"title":"I promessi sposi"}]
Ci sono vantaggi e svantaggi nella scelta di una di queste soluzioni. Negli ultimi anni sta prendendo sempre più piede il formato JSON, anche in virtù del fatto che sia la codifica sia la decodifica di strutture dati da / verso questo formato è agevole in tutti i linguaggi di programmazione moderni, sia perché spesso ad elaborare i dati lato client sono applicazioni JavaScript, che trovano i dati disponibili in formato nativo.
lunedì, ottobre 28, 2013
Web application deployment with git-ftp
This post has been updated after its initial publication.
In web application development, it happens sometimes that you are stuck with an only way to upload files on your webserver: FTP. If you are used to push changes to a git server like and then pull the changes on your webserver through a SSH connection, there are chances you just can't do that.
I had this problem recently, but I luckily found a very nice shell, git-ftp, that allows me to push changes to the webserver via FTP, recognizing all the files that I updated (or added, or deleted) on my local git repository.
My development / deployment cycle goes now simply like this:
$ # the ordinary "git" stuff...:
$ git add files_to_add
$ git rm files_to_remove
$ git commit -a -m 'description of the changes'
$ git push
Update: for a different project, I needed to use sftp, which is not supported by libcurl with a default Ubuntu installation. Anyway, I followed the instructions found on zeroset and I managed to have it working with no problems.
In web application development, it happens sometimes that you are stuck with an only way to upload files on your webserver: FTP. If you are used to push changes to a git server like and then pull the changes on your webserver through a SSH connection, there are chances you just can't do that.
I had this problem recently, but I luckily found a very nice shell, git-ftp, that allows me to push changes to the webserver via FTP, recognizing all the files that I updated (or added, or deleted) on my local git repository.
My development / deployment cycle goes now simply like this:
$ # the ordinary "git" stuff...:
$ git add files_to_add
$ git rm files_to_remove
$ git commit -a -m 'description of the changes'
$ git push
$ # now push the changes on the deployment server:
$ git-ftp push
The credentials that have to be used to access the deployment server are stored with the ordinary git config command. From the man page of git-ftp:
$ git config git-ftp.user john
$ git config git-ftp.url ftp.example.com
$ git config git-ftp.password secr3t
$ git config git-ftp.syncroot path/dir
$ git config git-ftp.cacert caCertStore
$ git config git-ftp.deployedsha1file mySHA1File
$ git config git-ftp.insecure 1
You can also use git-ftp in dry-mode, to just see what would happen, and in verbose mode, if you are curious about what actually happens.
Update: for a different project, I needed to use sftp, which is not supported by libcurl with a default Ubuntu installation. Anyway, I followed the instructions found on zeroset and I managed to have it working with no problems.
domenica, settembre 29, 2013
Treno + bici, assurdità tutte italiane
Viaggiare in treno con la bicicletta al seguito può essere un'esperienza molto piacevole, visto che si possono esplorare luoghi relativamente lontani sfruttando due tra i mezzi di trasporto più ecologici.
Purtroppo, per motivi che solo in Italia credo possano esistere, l'esperienza viene resa inutilmente difficoltosa.
1. Al momento della pianificazione del viaggio, bisogna naturalmente scegliere i treni giusti, ossia quelli che consentono il trasporto della bicicletta. Il sito di Trenitalia non consente, nemmeno accedendo alle opzioni avanzate, di effettuare una ricerca dei treni adibiti al trasporto biciclette:
I ciclisti italiani sanno, grazie ad un salutare passaparola, che per ottenere l'informazione desiderata si può però consultare il sito delle ferrovie tedesche, anche in italiano, il quale mostra gli orari di tutta Europa, con l'agognata casellina su cui mettere il desiderato segno di spunta:
2. Al momento di fare il biglietto, bisogna considerare che, per motivi misteriosi che qualcuno dovrebbe spiegare, le emettitrici automatiche presenti in tutte le stazioni non consentono l'acquisto del supplemento bici. Quindi, armatevi di pazienza e mettetevi in fila allo sportello (se è aperto dovete farlo, visto che la regola di acquistare il biglietto in treno senza sovrapprezzo vale solo quando in stazione lo sportello non c'è oppure è chiuso).
3. L'accessibilità delle stazioni ferroviare italiane (e dei treni stessi, a dire il vero) è quella che è, lo sappiamo. Dappertutto troviamo i cartelli "Vietato attraversare i binari. Servirsi del sottopassaggio". Basta aver fatto un viaggio piccolo piccolo al di là delle Alpi per capire che i sottopassaggi a cui si può accedere solo scendendo e salendo dei gradini non sono il massimo che la vita può offrire (soprattutto se la bicicletta è carica con qualche bagaglio sulle borse). Tra l'altro, l'accessibilità riguarda anche persone che devono usare una sedia a rotelle, genitori con un passeggino, ecc. Ma in Italia, naturalmente, le priorità sono altre.
4. Una volta arrivati al binario, rimane un ultimo problema da affrontare. Dove sarà la carrozza adibita al trasporto delle biciclette? In testa o in coda al treno? Non c'è modo di saperlo, perché evidentemente sarebbe troppo difficile comunicare questa informazione negli annunci audio, o nei display dove sono elencati i treni in arrivo/partenza. Quindi, non rimane che tirare una monetina e sperare di azzeccarci. Se non avete fortuna, e vi siete messi in coda quando invece la carrozza portabici è in testa, dovrete correre velocemente sul binario per arrivare a caricare il vostro mezzo in tempo. Però attenzione: non potete pedalare sul marciapiede.
Insomma: meno male che «Trenitalia da sempre si impegna per favorire chi sceglie di sostenere l’ambiente per viaggiare, forte della convinzione che treno+bici sia la soluzione di viaggio più eco-friendly, oltre che sempre più trendy», come afferma il sito web dell'azienda. Figuratevi altrimenti.
Purtroppo, per motivi che solo in Italia credo possano esistere, l'esperienza viene resa inutilmente difficoltosa.
1. Al momento della pianificazione del viaggio, bisogna naturalmente scegliere i treni giusti, ossia quelli che consentono il trasporto della bicicletta. Il sito di Trenitalia non consente, nemmeno accedendo alle opzioni avanzate, di effettuare una ricerca dei treni adibiti al trasporto biciclette:
I ciclisti italiani sanno, grazie ad un salutare passaparola, che per ottenere l'informazione desiderata si può però consultare il sito delle ferrovie tedesche, anche in italiano, il quale mostra gli orari di tutta Europa, con l'agognata casellina su cui mettere il desiderato segno di spunta:
2. Al momento di fare il biglietto, bisogna considerare che, per motivi misteriosi che qualcuno dovrebbe spiegare, le emettitrici automatiche presenti in tutte le stazioni non consentono l'acquisto del supplemento bici. Quindi, armatevi di pazienza e mettetevi in fila allo sportello (se è aperto dovete farlo, visto che la regola di acquistare il biglietto in treno senza sovrapprezzo vale solo quando in stazione lo sportello non c'è oppure è chiuso).
3. L'accessibilità delle stazioni ferroviare italiane (e dei treni stessi, a dire il vero) è quella che è, lo sappiamo. Dappertutto troviamo i cartelli "Vietato attraversare i binari. Servirsi del sottopassaggio". Basta aver fatto un viaggio piccolo piccolo al di là delle Alpi per capire che i sottopassaggi a cui si può accedere solo scendendo e salendo dei gradini non sono il massimo che la vita può offrire (soprattutto se la bicicletta è carica con qualche bagaglio sulle borse). Tra l'altro, l'accessibilità riguarda anche persone che devono usare una sedia a rotelle, genitori con un passeggino, ecc. Ma in Italia, naturalmente, le priorità sono altre.
4. Una volta arrivati al binario, rimane un ultimo problema da affrontare. Dove sarà la carrozza adibita al trasporto delle biciclette? In testa o in coda al treno? Non c'è modo di saperlo, perché evidentemente sarebbe troppo difficile comunicare questa informazione negli annunci audio, o nei display dove sono elencati i treni in arrivo/partenza. Quindi, non rimane che tirare una monetina e sperare di azzeccarci. Se non avete fortuna, e vi siete messi in coda quando invece la carrozza portabici è in testa, dovrete correre velocemente sul binario per arrivare a caricare il vostro mezzo in tempo. Però attenzione: non potete pedalare sul marciapiede.
Insomma: meno male che «Trenitalia da sempre si impegna per favorire chi sceglie di sostenere l’ambiente per viaggiare, forte della convinzione che treno+bici sia la soluzione di viaggio più eco-friendly, oltre che sempre più trendy», come afferma il sito web dell'azienda. Figuratevi altrimenti.
venerdì, agosto 30, 2013
PHP - Introduzione alle lezioni
Questo
post fa parte di una serie preparata qualche anno fa per
delle lezioni su PHP.
Introduzione
Le lezioni di questo corso sono strutturate con una serie di esempi e di esercizi per tuffarsi nel modo dello sviluppo di applicazioni web con PHP.L'idea è di non presentare sistematicamente tutto ciò che serve: c'è molta altra documentazione al riguardo, a partire da www.php.net/manual e uno dei principi di base è quello di "non reinventare la ruota". Piuttosto, preferisco procedere per raffinamenti successivi, con refactoring costante delle cose prodotte.
Tenderei anche ad iniziare (quasi) fin da subito un'impostazione basata sull'approccio MVC (model/view/controller) e sul test-driven development, in modo da facilitare il passaggio allo sviluppo basato sull'uso di framework (personalmente, uso e raccomando symfony, ma molti concetti sono applicabili comunque).
La raccolta di esempi e di esercizi presentata qui viene normalmente integrata con spiegazioni in aula, quindi può essere che non tutto sia sempre chiaro se ci si basa solo su quanto letto qui. Se servono integrazioni, o se trovate errori, segnalatemelo.
Alcune buone pratiche
Riporto qui alcune buone pratiche per lo sviluppo di applicazioni web che mi vengono in mente basandomi sulla mia esperienza personale e su qualche buona lettura. Non c'è un ordine di priorità particolare, e probabilmente alcune cose dovranno essere aggiunte. Tra l'altro, ammetto di non riuscire a seguirle tutte neppure io. Ad ogni modo, sono i miei due centesimi...- usare il design pattern MVC (model-view-controller)
- sviluppare codice sorgente in inglese: è meglio setSurname() di setCognome(), soprattutto se poi si chiede aiuto in un qualche tipo di forum internazionale
- usare strumenti che consentono l'internazionalizzazione (i18n) e la localizzazione (l10n) del codice
- essere ben disposti verso il refactoring
- usare un sistema di controllo versione (SVN, GIT...)
- scrivere il codice seguendo degli standard precisi (vedere, ad esempio, quelli di symfony, oppure quelle del progetto o del team in cui si è coinvolti)
- scrivere codice commentato
- scrivere codice autoesplicativo (pensare ai nomi delle funzioni e dei parametri)
- produrre documentazione con phpDoc o sistemi equivalenti
- lavorare con dati di esempio da ricaricare per ogni test (fixtures)
- predisporre test unitari
- predisporre test funzionali
- usare librerie di astrazione dal database
- usare librerie ORM (object-relational-mapping)
- usare framework di sviluppo per non reinventare la ruota
- usare un'interfaccia fluente per gran parte delle funzioni di una classe (tutti i setters, come minimo)
- non usare il metodo GET per cambiare lo stato delle informazioni sul server (niente link "normali" per cancellare un articolo, ad esempio)
- gestire le eccezioni con blocchi try... catch per tutte le operazioni che potenzialmente possono non andare a buon fine
- impostare l'error_reporting a E_ALL, e inizializzare tutte le variabili esplicitamente
- seguire le pratiche dell'usabilità, dell'accessibilità e dell'ottimizzazione per i motori di ricerca
Nell'ambito dell'uso di symfony, inoltre, vale sicuramente la pena di dare un'occhiata alle trenta buone pratiche raccomandate da Nicolas Perriault.
Nota per i puristi
In molti casi gli esempi iniziano con un codice come il seguente:<pre>
<?php
// istruzioni...
Ovviamente, il codice generato non è HTML valido, poiché mancano molti elementi obbligatori e il marcatore di chiusura </pre>.
Visto che l'obiettivo è di visualizzare semplice testo, però, questa è una soluzione accettabile.
La soluzione teoricamente corretta sarebbe di scrivere, invece:
<?php
header('Content-Type: text/plain');
// istruzioni...
Il problema di questa soluzione è che i browser dovrebbero rappresentare il contenuto come testo semplice, ma ce n'è uno, fornito di default con un noto sistema operativo, che non si comporta così, e tenta di rappresentare il testo in altro modo, oppure di aprire il contenuto con altri programmi...
Php - Alcune cose sulle variabili
Questo post fa parte di una serie preparata qualche anno fa per delle lezioni su PHP.
Si consideri il seguente frammento di codice:
ini_set('error_reporting', E_ALL);
function foo()
{
echo $k;
}
$k=1;
foo();
Quello che si ottiene è:
La prima è di dichiararla esplicitamente come globale:
function foo()
{
global $k;
echo $k;
}
$k=1;
foo();
La seconda è di usare l'array globale $GLOBALS:
function foo()
{
echo $GLOBALS['k'];
}
$k=1;
foo();
Ad esempio, si consideri di usare un codice simile a questo:
class WebRequest
{
public function getParameter($name, $default=null)
{
if (array_key_exists($name, $_GET))
{
return htmlentities($_GET[$name]);
// eventualmente qui si possono aggiungere altre sostituzioni...
}
else
{
return $default;
}
}
}
$request = new WebRequest();
echo 'con pulizia: ' . $request->getParameter('bar') . "\n";
echo 'senza pulizia: ' . $_GET['bar'] . "\n";
Richiamando il codice con una query string di questo tipo:
?bar=5>3
si otterrà:
con pulizia: 5>3
senza pulizia: 5>3
con evidenti vantaggi in termini di sicurezza (e con il bonus di poter specificare dei valori di default).
Nota storica: in vecchie versioni di PHP (precedenti alla versione 4.2.0), l'impostazione predefinita (register_globals=on) faceva sì che venissero automaticamente create delle variabili con il nome del parametro ($bar nell'esempio). Questa impostazione è deprecata per motivi di sicurezza, ma è bene conoscerla per il caso in cui ci si debba cimentare nella manutenzione/sostituzione di vecchio software.
function baz()
{
static $number;
$number++;
return 'foo ' . $number . "\n";
}
echo baz();
echo baz();
echo baz();
produce
Mario
Nota: il meccanismo funziona anche con diversi livelli di indirezione.
$expression='$a=5+3;';
eval($expression);
echo $a . "\n";
Attenzione: è bene non abusare di queste cose, che minano la sicurezza del codice e ne mettono a rischio la portabilità. «Se eval() è la risposta, vuol dire che quasi certamente hai posto la domanda sbagliata.» (attribuita a Rasmus Lerdorf)
Ambito di validità delle variabili
Esistono diversi ambiti di validità (scope) di una variabile:- locale (la variabile è visibile solo nella funzione in cui è definita)
- globale (la variabile è definita fuori dalla funzione, ma è specificatamente richiamata)
- superglobale (la variabile è accessibile ovunque senza bisogno di specificazioni
- le variabili globali non sono visibili, in assenza di specificazione, all'interno di una funzione (come invece succede, ad esempio, in Pascal);
- non esiste uno scope per un blocco (come invece succede, ad esempio, in C).
Si consideri il seguente frammento di codice:
ini_set('error_reporting', E_ALL);
function foo()
{
echo $k;
}
$k=1;
foo();
Quello che si ottiene è:
Notice: Undefined variable: k in ... on line ...Se si deve usare la variabile globale all'interno della funzione (anche se non è una buona pratica), ci sono due possibilità.
La prima è di dichiararla esplicitamente come globale:
function foo()
{
global $k;
echo $k;
}
$k=1;
foo();
La seconda è di usare l'array globale $GLOBALS:
function foo()
{
echo $GLOBALS['k'];
}
$k=1;
foo();
Le variabili superglobali
Alcuni array speciali mettono a disposizione di tutte le funzioni valori specifici collegati all'ambiente di esecuzione ($_ENV), ai valori inviati dal browser ($_GET, $_POST, ecc.). In linea di massima, è bene evitare di accedere direttamente a queste variabili e utilizzare invece delle classi che si occupano di fornire i dati in forma "controllata".Ad esempio, si consideri di usare un codice simile a questo:
class WebRequest
{
public function getParameter($name, $default=null)
{
if (array_key_exists($name, $_GET))
{
return htmlentities($_GET[$name]);
// eventualmente qui si possono aggiungere altre sostituzioni...
}
else
{
return $default;
}
}
}
$request = new WebRequest();
echo 'con pulizia: ' . $request->getParameter('bar') . "\n";
echo 'senza pulizia: ' . $_GET['bar'] . "\n";
Richiamando il codice con una query string di questo tipo:
?bar=5>3
si otterrà:
con pulizia: 5>3
senza pulizia: 5>3
con evidenti vantaggi in termini di sicurezza (e con il bonus di poter specificare dei valori di default).
Nota storica: in vecchie versioni di PHP (precedenti alla versione 4.2.0), l'impostazione predefinita (register_globals=on) faceva sì che venissero automaticamente create delle variabili con il nome del parametro ($bar nell'esempio). Questa impostazione è deprecata per motivi di sicurezza, ma è bene conoscerla per il caso in cui ci si debba cimentare nella manutenzione/sostituzione di vecchio software.
Variabili statiche
Una funzione può contenere variabili statiche:function baz()
{
static $number;
$number++;
return 'foo ' . $number . "\n";
}
echo baz();
echo baz();
echo baz();
produce
foo 1 foo 2 foo 3
Variabili di variabili
Una variabile può contenere il nome di un'altra variabile: $name="Mario"; $var='name'; echo $$var . "\n";produce
Mario
Nota: il meccanismo funziona anche con diversi livelli di indirezione.
La funzione eval()
Con la funzione eval() si possono eseguire istruzioni costruite al volo:$expression='$a=5+3;';
eval($expression);
echo $a . "\n";
Attenzione: è bene non abusare di queste cose, che minano la sicurezza del codice e ne mettono a rischio la portabilità. «Se eval() è la risposta, vuol dire che quasi certamente hai posto la domanda sbagliata.» (attribuita a Rasmus Lerdorf)
PHP - Appunti sulla progettazione
Questo
post fa parte di una serie preparata qualche anno fa per
delle lezioni su PHP.
Fasi di progettazione
Le fasi di progettazione di una base di dati e di una o più applicazioni utente che su di essa si basano dovrebbero essere le seguenti:- progettazione logica, che porta ad un diagramma entità/relazioni
- progettazione delle tabelle, che porta allo schema relazionale
- implementazione concreta, che porta alle istruzioni DDL (o equivalenti) per la progettazione delle tabelle con i relativi campi
Consigli per la progettazione delle tabelle
Mantenere la coerenza nei nomi
Bisognerà adottare uno schema per i nomi delle tabelle e dei nomi dei campi ed applicarlo in maniera coerente. Ad esempio, non sembrano coerenti questi nomi di tabelle:- Clienti, fornitori (o scegliamo Clienti e Fornitori, oppure clienti e fornitori)
- Clienti, Fornitori, Fattura (per i nomi delle tabelle usiamo sempre il plurale o sempre il singolare)
- Customers, Fornitori, Invoices (usiamo nomi in italiano o in inglese, non mescolati)
- customer_type, subjectType, BookType (underscore, camelCase o tutte le iniziali in maiuscolo)
Non andare in cerca di guai
In generale, è opportuno limitarsi a nomi di tabelle e nomi di campi:- senza spazi
- senza caratteri fuori dall'insieme [A-Za-z0-9], più eventualmente il simbolo di sottolineatura
Usare dati di prova
Per verificare di aver progettato correttamente le tabelle, è opportuno inserire dei dati di prova:- significativi (ad esempio, tenendo in considerazione ipotetici casi limite, o valori fuori dal comune)
- in numero adeguato (se voglio verificare come si presenta l'interfaccia utente quando ci sono tanti clienti, è bene che nei dati di prova ci siano tanti clienti; viene naturale pensare anche ad una generazione automatica, con numeri progressivi )
- facili da importare (per poter ripristinare una situazione iniziale, nel caso in cui si commettano degli errori).
PHP - PUT e DELETE tramite Javascript
Questo
post fa parte di una serie preparata qualche anno fa per
delle lezioni su PHP.
Limiti dei browser
Normalmente i browser implementano solo i metodi GET e POST. Se si prepara un form con l'attributo method che non vale "GET" o "POST" il browser fa una richiesta tramite GET.Utilizzare Javascript per PUT e DELETE
Se si vuole fare un PUT o un DELETE si può però chiedere al browser di utilizzare Javascript. Questo codice, con un po' di adattamenti, è preso da "Not just Post and Get".<html>
<title>HTTP Methods example</title>
<head>
<script language="Javascript">
<!--
var xmlhttp;
function execute($method,$url)
{
xmlhttp=new XMLHttpRequest();
xmlhttp.open($method,$url,true)
xmlhttp.send(null);
}
function testmethod($method)
{
alert('Executing ' + $method + '...');
execute($method, 'info.php');
}
-->
</script>
</head>
<body>
<?php foreach(array('get', 'post', 'put', 'delete') as $method): ?>
<input
type="button"
value="<?php echo $method ?>"
onclick="testmethod('<?php echo $method ?>');"
/>
<?php endforeach ?>
</body>
</html>
Il codice HTML che si ottiene per il body è il seguente:
<body>
<input
type="button"
value="get"
onclick="testmethod('get');"
/>
<input
type="button"
value="post"
onclick="testmethod('post');"
/>
<input
type="button"
value="put"
onclick="testmethod('put');"
/>
<input
type="button"
value="delete"
onclick="testmethod('delete');"
/>
</body>
Lo script PHP che riceve i dati può limitarsi, giusto per darci la conferma che i metodi PUT o DELETE sono stati ricevuti, a scrivere una specie di file di log:<?php
// file info.php
$fp= fopen('log.txt', 'a');
fwrite($fp, $_SERVER['REQUEST_METHOD']. "\n");
fclose($fp);
?>
PHP - XAMPP
Questo
post fa parte di una serie preparata qualche anno fa per
delle lezioni su PHP.
XAMPP
Per esercitazioni sullo sviluppo web in ambiente Microsoft Windows può essere utile usare XAMPP. Consiglio di scaricare e usare la versione indicata come "Metodo B: 'Installazione' senza l'installer".Dopo aver scompattato il file (ad esempio, in C:\), eseguire lo script setup_xampp.bat per effettuare i cambiamenti necessari a seconda del percorso specificato. Al termine, eseguire xampp_control.exe e tentare di avviare il server Apache.
Problemi e soluzioni
Porta 80 occupata
Ce ne possiamo rendere conto eseguendo xampp-portcheck.exe.Se è in esecuzione Ms Internet Information Server, che occupa la porta 80, non è possibile avviare normalmente Apache.
Soluzione 1: chiudere IIS, con il comando
net stop IISADMIN /y
Soluzione 2: impostare Apache perché ascolti su una porta diversa (ad esempio la porta 8080), modificando il fileapache/conf/httpd.conf (bisogna trovare la riga con scritto Listen 80 e sostituirla con Listen 8080).
Firewall in azione
All'avvio di Apache potrebbe comparire un messaggio che dice che il Firewall di Windows blocca il servizio.Soluzione 1: disattivare il firewall, oppure consentire un'eccezione.
Soluzione 2: lavorare solo da localhost, che dovrebbe comunque rimanere possibile.
PHP - Come procedere
Questo
post fa parte di una serie preparata qualche anno fa per
delle lezioni su PHP.
Alcuni argomenti che meriterebbero di essere trattati
Uno sviluppatore PHP dovrebbe avere una buona idea di come sfruttare alcuni strumenti potenti e flessibili che il linguaggio mette a disposizione. Ne elenco alcuni, senza un particolare ordine di priorità:- le espressioni regolari
- l'interfaccia a riga di comando
- la gestione di immagini
- la manipolazione di file XML
- la produzione di animazioni flash (con Ming) e file pdf (con mPDF)
- la gestione dell'invio automatizzato di posta, ad esempio con SwiftMailer
L'idea fondamentale è che uno sviluppatore web non dovrebbe reinventare la ruota, ma controllare se esistono soluzioni che può sfruttare (possibilmente ricambiando con proprio codice e/o documentazione).
Documentazione
Il codice può essere facilmente documentato, anche in assenza di commenti formattati in maniera particolare. Lo strumento di riferimento è phpDocumentor.Se poi il codice viene commentato adeguatamente, l'utilità è ancora maggiore.
ORM e Framework
Per qualsiasi progetto non banale, vale la pena di sfruttare qualche framework di sviluppo, che spesso è appoggiato a un Object-Relational Mapper.Vale la pena anche di dare un'occhiata a cosa offre il framework Zend.
PHP - Il controllore
Questo
post fa parte di una serie preparata qualche anno fa per
delle lezioni su PHP.
Un unico punto di accesso
Una buona pratica è quella di avere un unico punto di accesso all'applicazione, da usare per tutte le azioni che possono essere compiute dall'utente.Questo punto di accesso sarà in cui verrà invocato il livello controller (nell'ambito del pattern MVC). Ciò comporta una serie di vantaggi:
- centralizzazione dei controlli di validità della richiesta, in base a tutti i parametri ritenuti necessari
- generazione di una sola istanza di classi per l'accesso alla base di dati, agli "oggetti" che rappresentano la connessione HTTP (es. WebRequest e WebResponse, se li definiamo, ecc.)
- possibilità di abilitare/disabilitare agevolmente l'intera applicazione
- possibilità di definire URL più significativi e Search-Engine Optimized.
Definizione degli URL
Potremo definire un unico controller index.php che si occupa di "smistare il traffico" a seconda dell'azione richiesta. In prima approssimazione, gli URL saranno simili ai seguenti:http://www.example.com/myapp/index.php?action=listitems
http://www.example.com/myapp/index.php?action=showitem&id=12
Con il primo invocheremo l'azione listitems, con il secondo l'azione showitem, passando il parametro id=12 da utilizzare per decidere quale elemento mostrare.
Se le azioni list, show, edit, ecc. sono le medesime per diversi tipi di oggetti (es. foto, documenti, video, ecc.) potrà essere conveniente avere azioni in qualche modo raggruppate, così:
http://www.example.com/myapp/index.php?module=photos&action=list
http://www.example.com/myapp/index.php?module=photos&action=show&id=12
http://www.example.com/myapp/index.php?module=videos&action=list
http://www.example.com/myapp/index.php?module=videos&action=show&id=32
Se poi volessimo degli URL più significativi e SEO, potremo fare in modo che il nostro controller effettui un'analisi della query string in modo da poter gestire URL fatti in questo modo:
http://www.example.com/myapp/index.php/photos/list
http://www.example.com/myapp/index.php/photos/show/id/12
http://www.example.com/myapp/index.php/videos/list
http://www.example.com/myapp/index.php/videos/show/id/32
Progettazione degli URL
Gli URL sono una parte importante di un'applicazione web, troppo spesso sottovalutata. Essi dovrebbero essere (vedi i suggerimenti riportati su NewMediaJournalism):- permanenti
- leggibili
- gerarchici
- brevi e chiari
Slug al posto dell'id
Il nome slug identifica un proiettile la cui forma è cambiata a causa del passaggio per la canna della pistola; analogamente, un titolo di un pezzo giornalistico come "Nuove idee per la Wikipedia" potrebbe venire trasformato, anche con procedimenti automatici, nello slug "nuove-idee-per-la-wikipedia".
URL rewriting
http://www.example.com/myapp/photos/list
http://www.example.com/myapp/photos/show/id/12
http://www.example.com/myapp/videos/list
http://www.example.com/myapp/videos/show/id/32
Ulteriori informazioni in merito si possono trovare nella guida all'URL-rewriting del sito HTML.it.
Esercizio
Mettere insieme i pezzi visti fino a qui, e progettare una piccola applicazione con separazione netta dei livelli MVC, definendo le classi appropriate, progettando gli URL, predisponendo i test necessari, ecc.PHP - Modelli (template)
Questo
post fa parte di una serie preparata qualche anno fa per
delle lezioni su PHP.
Livello "vista" tramite modelli (template)
Lo sviluppo che segue la modalità nota come MVC prevede una netta separazione tra modello (accesso ai dati), controllore(autenticazione, gestione del chi può fare cosa, ecc.) e vista (forma di presentazione dei dati).In linea di massima, il modello e il controllo devono limitarsi a estrarre i dati e a fornirli alla vista in forma di semplici variabili (array e oggetti), già pronti per essere rappresentati.
Nella vista, il fatto che i dati derivino da interrogazione di database, da analisi di file XML, o da qualsiasi altra fonte, è assolutamente ininfluente.
Analogamente, il modello non ha idea dello scopo finale per cui vengono richiesti ed estratti dei dati, e li fornirà in maniera il più possibile grezza.
Il controllore ha lo scopo di capire quale interrogazione deve essere fatta e quale forma di visualizzazione adottare. Ad esempio, vengono chiesti i dati sugli articoli che possono essere visualizzati in forma di:
- pagina web tabellare
- pagina web con elenco puntato
- file CSV
- documento XML
- ...
La vista si occupa di formattare i dati nella maniera opportuna. In genere, si predispongono dei template (modelli) e il controllore deciderà quale template utilizzare.
Template in PHP (nativi)
Il modo pìù semplice per prediporre dei template è di usare direttamente PHP.Ad esempio, il file principale (controller) effettuerà le operazioni di estrazione dei dati e richiamerà un template per la visualizzazione.
<?php
$name='George Smith';
$address= '45th & Harris';
include('template.php');
Il file template.php conterrà codice HTML e codice PHP con sintassi alternativa:
<html>
<head>
<title>User Info</title>
</head>
<body>
<p>User Information:<br />
Name: <?php echo $name ?><br />
Address: <?php echo $address ?>
</p>
</body>
</html>
Il risultato sarà, come ci aspettiamo:
User Information: Name: George Smith
Address: 45th & Harris
Vantaggi:
- non serve imparare un nuovo "linguaggio"
- non serve installare nessuna libreria di funzioni
- nel template si possono usare tutte le funzioni di PHP per la formattazione dei dati, non ci sono limiti
- chi prepara il template deve conoscere (almeno un minimo di) PHP
- i template non sono portabili tra ambienti di sviluppo diversi
- i template risultano prolissi e poco comprensibili
- chi prepara il template può comunque eseguire codice PHP "normale" (con eventuali problemi di sicurezza)
Template con codice specifico
In alternativa, si possono usare strumenti per preparare template indipendenti da PHP. Il codice di questi template in genere viene analizzato e tradotto in codice PHP nativo, con la gestione di una cache per evitare di dover fare questa operazione più volte.Il linguaggio per template più noto è probabilmente quello predisposto per Smarty. Per avere un'idea del suo funzionamento, si può dare un'occhiata al suo crash course. Ci sono però oltre cinquanta progetti per i template di pagine web, non c'è che l'imbarazzo della scelta. È presente anche una tabella di comparazione nella Wikipedia.
Un esempio di codice è il seguente (basato sul crash course, con l'aggiunta dell'indicazione dei percorsi per le directory e la libreria):
<?php
require_once('../../../lib/Smarty/libs/Smarty.class.php');
// ovviamente il percorso varia a seconda dell'installazione...
$smarty = new Smarty;
$smarty->template_dir = './smarty_dirs/templates';
$smarty->compile_dir = './smarty_dirs/templates_c';
$smarty->cache_dir = './smarty_dirs/cache';
$smarty->config_dir = './smarty_dirs/configs';
$smarty->assign('name', 'george smith');
$smarty->assign('address', '45th & Harris');
$smarty->display('index.tpl');
Il template (file index.tpl) corrisponderà al seguente:
<html>
<head>
<title>User Info</title>
</head>
<body>
<p>User Information:<br />
Name: {$name}<br />
Address: {$address}
</p>
</body>
</html>
Il risultato corrisponde a quello precedente.
Smarty: un esempio con un array
Se al template Smarty passiamo un array, possiamo sfruttare il codice per la gestione dell'iterazione.Il controller sarà simile al seguente:
<?php
require_once('../../../lib/Smarty/libs/Smarty.class.php');
$smarty = new Smarty;
$smarty->template_dir = './smarty_dirs/templates';
$smarty->compile_dir = './smarty_dirs/templates_c';
$smarty->cache_dir = './smarty_dirs/cache';
$smarty->config_dir = './smarty_dirs/configs';
$pictures=array(
'mountain.jpg',
'desert.jpg',
'sea.jpg',
'lake.jpg',
'countryside.jpg',
);
$smarty->assign('title', 'My pictures');
$smarty->assign('pictures', $pictures);
$smarty->display('smarty2_basic.tpl');
Il template sarà invece fatto così:
<html>
<head>
<title>{$title}</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<h1>{$title}</h1>
<h2>Elenco puntato</h2>
<ul>
{foreach from=$pictures item=picture}
<li>{$picture}</li>
{/foreach}
</ul>
<h2>Testo preformattato</h2>
<pre>
{foreach from=$pictures item=picture}
{$picture}
{/foreach}
</pre>
<h2>Tabella</h2>
<table class="sample">
<tr><th>name</th></tr>
{foreach from=$pictures item=picture}
<tr>
<td>{$picture}</td>
</tr>
{/foreach}
</table>
<h2>Tabella con numero di iterazione</h2>
<table class="sample">
<tr><th>number</th><th>name</th></tr>
{foreach name=picturestable from=$pictures item=picture}
<tr>
<td>{$smarty.foreach.picturestable.iteration}</td>
<td>{$picture}</td>
</tr>
{/foreach}
</table>
<h2>Tabella con colori di sfondo diversi per le righe pari e dispari</h2>
<table class="sample">
<tr><th>name</th></tr>
{foreach name=picturestable from=$pictures item=picture}
<tr>
<td style="background-color: {if $smarty.foreach.picturestable.iteration is even}yellow{else}orange{/if}">{$picture}</td>
</tr>
{/foreach}
</table>
</body>
</html>
Header/Footer o Layout?
Nella predisposizione dei template, si possono usare due strategie: quella di predisporre intestazioni e piè di pagina standard (e di occuparsi dei contenuti) oppure quella di impostare un layout complessivo, in cui è presente un segnaposto per il contenuto specifico.Header/Footer
| Templating basato su Header/Footer (immagine tratta da Practical Symfony) |
L'idea di base è che nel template devo incorporare l'intestazione e il piè di pagina. Nella logica di Smarty dovrò scrivere qualcosa tipo:
{include file="header.tpl" title="Main Menu"}
{* qui va il corpo del template *}
{include file="footer.tpl" logo="http://my.example.com/logo.gif"}
Layout
| Templating basato su Layout (immagine tratta da Practical Symfony) |
L'idea qui è che ci sia un file di layout generico che contiene tutto il codice di base, ad eccezione di quanto comparirà di specifico a seconda dell'azione invocata.
Nella logica di Smarty avrò un file layout.tpl che contiene il layout generico:
<html>
<head>
<title>{$title}</title>
</head>
<body>
<h1>{$title}</h1>
<div id="content">
{include file="$action.tpl"}
</div>
</body>
</html>
Il file di layout includerà un file specifico a seconda dell'azione indicata dal controller, che avrà la seguente forma:
<?php
require_once('../../../lib/Smarty/libs/Smarty.class.php');
$smarty = new Smarty;
$smarty->template_dir = './smarty_dirs/templates';
$smarty->compile_dir = './smarty_dirs/templates_c';
$smarty->cache_dir = './smarty_dirs/cache';
$smarty->config_dir = './smarty_dirs/configs';
$pictures=array(
'mountain.jpg',
'desert.jpg',
'sea.jpg',
'lake.jpg',
'countryside.jpg',
);
$smarty->assign('title', 'My pictures');
$smarty->assign('pictures', $pictures);
$smarty->assign('action', 'list');
$smarty->display('layout.tpl');
Il file list.tpl sarà quello che caratterizza l'azione specifica:
<h2>The list</h2>
<ul>
{foreach from=$pictures item=picture}
<li>{$picture}</li>
{/foreach}
</ul>
Approfondimenti
Nella predisposizione di modelli (template), è bene tenere presente alcuni concetti che possono tornare utili. Qui userò la terminologia usata con Symfony (altri framework potrebbero usare termini diversi per gli stessi oggetti).Slot
È una parte del layout il cui valore viene deciso nel momento in cui viene predisposto il contenuto del template relativo all'azione specifica. L'esempio comune è quello del testo del titolo della pagina.Partial
È una sorta di mini-template che serve per rappresentare una parte dei contenuti e che non ha vita autonoma (non viene richiamato direttamente, almeno di solito, ma da un altro template). È utile per poter sfruttare lo stesso codice in diversi template (un po' come si farebbe con una funzione).Component
Flash
È una parte di pagina web che contiene un testo che viene visualizzato una sola volta (al successivo GET scompare), grazie all'uso di cookies. Tipicamente viene utilizzato per dare feedback all'utente sulla riuscita o meno di operazioni che richiedevano l'uso di un POST (visto che il browser viene ridiretto ad un GET).Helper
Iscriviti a:
Post (Atom)





