Rubrica Networking

CGI Corner

Contatore di accessi grafico

di Michele Beltrame

Una delle applicazioni piu` diffuse, se non addirittura la piu` diffusa in assoluto, della tecnologia CGI è la creazione di contatori di accesso, cioé di programmi che indichino quante volte è stata visitata una determinata pagina.

Vagando per internet si trovano contatori di accesso di tutti i tipi: grafici, testuali, colorati, digitali, .... Vi sono alcuni siti che permettono di utilizzare, a pagamento, i propri contatori; si possono tuttavia reperire facilmente anche contatori gratuiti da collocare nel proprio server.

I contatori che si trovano in giro però, per definizione, non sono mai esattamente come si vorrebbero. È quindi abbastanza comune scriversi il proprio contatore personalizzato, soluzione che richiede solamente poche ore di lavoro e che non presenta grosse difficoltà.

In questo articolo presenterò un contatore di accessi grafico di mia creazione, disponibile allegato a questo articolo (il prefisso 297 è per compatibilità con il formato di BETA, potete tranquillamente toglierlo). E` anche possibile prelevarne il pacchetto completo, che include anche una serie di GIF rappresentati le cifre da 0 a 9, alla URL http://www.italpro.com/mb/devel.html. In questo articolo verranno descritte le parti più significative del codice sorgente, cosicché ognuno possa poi personalizzare il programma secondo le proprie esigenze ed i propri gusti. Il sorgente è, come al solito, scritto in Perl e funziona perfettamente sotto Linux, utilizzando Apache come Web server. Considerando l'alto livello di portabilità del Perl, non dovrebbe presentarsi alcun problema anche nell'utilizzo sotto altri sistemi operativi e altri Web server.


Alcune note sul funzionamento...

Questo contatore conserva sul server, per ogni pagina HTML in cui esso è utilizzato, un file contenente il numero di accessi relativo a tale pagina: è quindi possibile utilizzare lo stesso contatore per più pagine. Il programma visualizza il numero di accessi a partire da 10 immagini GIF contenenti la rappresentazione grafica dei numeri tra 0 e 9: queste GIF vengono fuse in un'unica immagine, che poi viene visualizzata. La fusione delle immagini è ottenuta utilizzando un programma esterno, il FLY 1.1 di Martin Gleeson. I sorgenti C di esso sono compilabili sotto qualsiasi Unix e sono disponibili presso l'Università di Melbourne, alla URL http://www.unimelb.edu.au/fly/fly.html.


Implementazione

Veniamo dunque al sorgente, denominato senza troppa fantasia Graphical hit counter, ghc per gli amici. ;-) La parte principale del programma si compone di poche righe in quanto la gran parte del lavoro è compiuta da tre subroutine. Analizziamo comunque prima di tutto la parte principale.

  • @allow = ( 'marameo.net' );

    In questo array sono definiti i nomi o gli indirizzi IP degli host a cui è permesso accedere al contatore (il controllo viene effettuato dalla subroutine &checkrefl). Restringere l'accesso al contatore ha una certa importanza in quanto, se non lo si facesse, chiunque potrebbe utilizzarlo e, tra l'altro, i file contententi il numero di accessi verrebbero scritti sul vostro server. È consigliabile inserire, per ogni server a cui si vuole concedere l'autorizzazione, sia il nome che l'indirizzo IP, in quanto non sempre è ad ottenere il nome.

  • $cdir = 'counts/';
    $ddir = 'digits/';


    Nella prima di queste due variabili è definita la directory in cui, verranno creati i file contenenti il numero di accessi. Nella seconda è invece specificato dove risiedono le immagini GIF delle cifre. La prima directory dovrà essere accessibile in scrittura da tutti (a+w), quindi è bene lanciare un chmod 777 counts.

  • ($docu, $dig, $width, $height, $frame_w, $frame_c) = split(/\|/, $ENV{'PATH_INFO'});
    $ref=$ENV{'HTTP_REFERER'};
    $docu =~ s/\//_/g;
    $docu = $cdir.$docu;


    Nella prima di queste righe viene divisa, utilizzando come separatore la barra verticale ( | ), l'extended path info (disponibile nella variabile d'ambiente PATH_INFO). Tramite l'extended path info vengono passati al contatore alcuni parametri. Essi sono, nell'ordine, il nome del file in cui conservare il numero di accessi, il prefisso del nome dei file contenti le cifre (in modo che sia possibile avere diversi tipi di cifre, tipo rosso1.gif, rosso2.gif, ..., blu1.gif, ..., aventi rispettivamente prefisso rosso e blu), la larghezza e l'altezza in pixel delle GIF (tutte le cifre devono avere uguali dimensioni), la larghezza i pixel di un'eventuale cornice (frame) ed il colore di essa (sottoforma di tripletta di numeri decimali separati da virgola).
    Le due righe successive si assicurano che non vi siano fastidiosi slash ( / ) all'interno del nome del file, ed eseguono la concatenazione del nome della directory contenente i conteggi con il nome del file in cui va è memorizzato il numero di accessi relativo alla pagina corrente.

  • if (!&checkrefl) {
    &rwcount;
    &dspcount;
    }


    Viene chiamata la funzione &checkrefl per verificare che l'host sia autorizzato e, se il controllo ha esito positivo, vengono eseguite le subroutine &rwcount (che legge, incrementa e riscrive il numero di accessi) e &dspcount (che visualizza graficamente il conteggio).


Autorizzazione

Analizziamo ora la struttura della funzione &checkrefl, cioé quella che si occupa di verificare che la pagina chiamante risieda su un host autorizzato ad usare il contatore.

  • $ref=$ENV{'HTTP_REFERER'};

    Viene memorizzata in $ref la variabile d'ambiente HTTP_REFERER. In essa infatti si trova la URL della pagina da cui è stato chiamato il CGI, e quindi anche il nome (o l'indirizzo IP qualora non sia stato possibile ottenere il nome) dell'host in cui tale pagina risiede.

  • if ($ref ne '') {
    $prohib=1;
    foreach $allw (@allow) {
    if ($ref =~ /$allw/) {
    $prohib=0;
    last;
    }
    }
    } else { $prohib=0; }


    Il controllo vero e proprio viene effettuato in queste righe. Anzitutto ci si assicura che il contenuto della variabile d'ambiente HTTP_REFERER non sia nullo (cosa possibile), nel qual caso il controllo non viene effettuato (ma sarà comunque possibile utilizzare il contatore). Successivamente tutti gli elementi dell'array @allow vengono confrontati tramite regular expression (ricerca di sottostringhe, in questo caso) con la variabile d'ambiente HTTP_REFERER. Alla fine di questo blocco di istruzioni ci si trova con la variabile $prohib avente valore nullo se l'host è autorizzato, o avente valore 1 se l'host non è tra quelli autorizzati.

  • if ($prohib==1) {
    print "Location: http://www.marameo.net/common/badref.gif\n\n";
    return 1;
    }
    return 0;


    Se $prohib ha valore 1, viene inviato al client un header di tipo Location, che provocherà la visualizzazione di badref.gif (una GIF a vostra scelta che spieghi che il server non è autorizzato). . In questo caso la funzione torna valore positivo (1), altrimenti torna valore nullo.


Lettura/scrittura del conteggio

La funzione che si occupa di leggere, incrementare e scrivere il conteggio del numero di accessi è, come accennato in precedenza, &rwcount. Questa subroutine apre il file contenente il conteggio (creandolo nel caso non esista), ne estrae il valore memorizzandolo nella variabile $ct, lo incrementa e lo riscrive. Il suo funzionamento è molto intuitivo, in quanto si tratta di semplici istruzioni Perl di I/O, quindi non verrà spiegato nel dettaglio.


Visualizzazione grafica del conteggio

Questa subroutine rappresenza senz'altro la parte più interessante del programma, in quanto essa si occupa, con l'ausilio del programma FLY, di preparare "al volo" ed inviare al client la GIF rappresentante il numero di accessi. Vediamone quindi il funzionamento.

  • $ncf = length($ct);
    $imgw = ($width*$ncf) + ($frame_w*2);
    $imgh = $height + ($frame_w*2);


    È anzitutto importante determinare le dimensioni (altezza e larghezza) dell'immagine finale, in quanto esse devono essere passate a FLY. La larghezza viene calcolata moltiplicando il numero di cifre che compongono il conto ( length($ct) ) per la larghezza dell'immagine che rappresenta la singola cifra; a tale quantità viene poi sommata la larghezza dell'eventuale frame, moltiplicata ovviamente per 2. L'altezza è calcolata semplicemente sommando all'altezza dell'immagine della cifra la larghezza della frame moltiplicata per 2.

  • if (open (FLY, ">$docu.fly")) {
    flock (FLY, 2);
    print FLY "new\n";
    print FLY "size $imgw,$imgh\n";
    &makeframe;
    $j = 1;
    while ($j <= $ncf) {
    $num = substr($ct,0,1);
    substr($ct,0,1) = '';
    print FLY "copy $insw,$insh,-1,-1,-1,-1,$ddir/$dig$num\.gif\n";
    $insw = ($insw + $width);
    $j++;
    }
    print FLY "interlace\n";
    flock (FLY, 8);
    close (FLY);
    }


    A questo punto è necessario scrivere un file di istruzioni per FLY, in cui venga specificato quali GIF devono essere unite, come devono essere unite, .... La prima riga di questo file deve contenere l'istruzione new, mentre nella seconda vanno specificate tramite la direttiva size le dimensioni dell'immagine finale, che abbiamo calcolato in precedenza. Il controllo è a questo punto passato ad una funzione che crea l'eventuale frame, di cui parleremo in seguito. Un while si occupa di inserire le istruzioni copy per le cifre necessarie. Come si nota, a copy vengono passate le coordinate in cui va inserita l'immagine (che sono quelle dell'origine a cui è stata sommata la larghezza della frame), ed il nome del file da inserire (le cifre sono ottenute scandendo da sinistra verso destra la stringa che rappresenta il numero di accessi).
    L'ultimo comando inserito prima della chiusura del file è interlace, che fa si che venga generata una GIF interallacciata (l'immagine verrà cioé visualizzata in più passate, a risoluzione sempre maggiore).

  • $output = `./fly -q -i$docu.fly`;
    print &Content-type: image/gif\n\n";
    print $output;
    unlink("$docu.fly");


    A questo punto viene invocato FLY in quiet mode, cioé tramite lo switch -q, in modo che tutti i messaggi da esso generati vengano soppressi. Ad esso viene passato il file di istruzioni appena creato. L'output del programma è la GIF finale. Esso viene memorizzato nella variabile $output e poi inviato al client. Infine il file di istruzioni viene cancellato. È importante notare che il Content-type deve essere di tipo image/gif, cosicché il browser sappia come intepretare ciò che gli viene inviato.


Creazione del frame

La subroutine &makeframe si occupa di creare un contorno per il contatore. Per fare ciò vengono usate le istruzioni line di FLY. Questo comando accetta e richiede come argomenti le coordinate dell'origine e quelle della fine della linea, nonché una tripletta che indichi il colore desiderato per la linea. Ad esempio, il seguente comando disegnerà una linea bianca:

line 0,0,100,235,255,255,255

Qui si tratta semplicemente di far disegnare una o più linee attorno alla GIF contentente il conteggio. Per fare ciò si utilizza un while che, a seconda della dimensione scelta per la frame, eseguirè una o più le istruzioni che disegnano il riquadro. Alle variabili $insw e $insh viene assegnato come valore la larghezza della frame, in modo tale che le GIF delle cifre vengano poi inserite al posto giusto, senza sovrapporsi alla frame stessa. Da notare l'utilizzo della varabile $frame_c, quella cioé che contiene la tripletta che identifica il colore della frame.


Uso e considerazioni finali

Vediamo ora come fare per richiamare il contatore grafico da un documento HTML. Questa volta non si tratta, come qualcuno potrebbe pensare, di inserire nel documento una chiamata in stile SSI (Server Side Include). Il CGI dovrà invece essere chiamato come se si trattasse di una normale immagine, e quindi utilizzando qualcosa di simile a quanto segue:

<IMG SRC="/cgi-bin/ghc.pl/indice|dspazz|15|21|3|255,255,255">

La chiamata va effettuata utilizzando il tag <IMG> in quanto l'output del nostro programma è, come visto prima, di tipo image/gif. Inserendo dunque questa riga in un documento HTML verrà eseguito ghc.pl (suppondendo si trovi in /cgi-bin) ed il conteggio verrà letto e scritto in un file chiamato indice. Come prefisso per il nome delle GIF delle cifre verrà utilizzato dspazz (verranno quindi usate le GIF dpsazz0.gif, ..., dspazz9.gif). Le dimensioni di ciascuna cifra specificate in questo caso sono 15 e 21 (devono corrispondere alle effettive dimensioni delle immagini delle cifre). Verrà inoltre creata una frame bianca (tripletta decimale 255,255,255) della dimensione di 3 pixel.

In questo articolo ho dunque brevemente presentato e spiegato il funzionamento di un contatore grafico, lasciando a ciascuno il compito di modificarlo a proprio piacimento. Nel prossimo numero si parlerà di cookie persistenti, della loro presunta pericolosità, delle loro interessantissime possibilità di applicazione, e di come si usano tramite l'interfaccia CGI. Prima di terminare, ricordo che il sorgente completo del programma visto in questo articolo è disponibile qui.


Bibliografia :
Larry Wall / Randal L. Schwartz - "Programming perl" - O'Reilly & Associates
Shishir Gundavaram - "CGI Programming on the World Wide Web" - O'Reilly & Associates
Apache Documentation - http://www.apache.org/docs/
A. S. Hornby - "Oxford Student's Dictionary of AMERICAN English" - Oxford University Press


Michele Beltrame è Webmaster dei siti Italpro e Showeb, ed è raggiungibile su Internet tramite la redazione


Copyright © 1995-97 BETA. Tutti i diritti riservati.
Copertina Sommario Internet ID Ricerca Redazione Browser