Homepage di Marco Buzzo
Python
Python
Introduzione
Documentazione
Pubblicazioni
Faq CGI
Slides Seminario
Tkinter
Supporto Emacs
Link
Argomenti
Circuit Macros
Varie
 Chia
Contatti
marcobuzzo@tiscalinet.it
 
La programmazione CGI in Python

 




La programmazione CGI viene comunemente identificata con la programmazione in Perl, in quanto quest’ultimo è universalmente riconosciuto come il Principe tra i linguaggi di scripting. In realtà abbiamo a disposizione un ampio ventaglio di linguaggi, in funzione delle nostre esigenze, ma la fama del Perl è legata ad un suo grande sostenitore, Jhon Udell, ed al notevole successo della sua rubrica web techniques dalle pagine di Byte

Nelle righe che seguono vedremo alcune delle possibilità offerte dal Python per la programmazione CGI, e proveremo a realizzare qualche esempio in modo da evidenziare la semplicità che ne sta alla base. 

Cosa significa CGI?

Il significato di CGI è Common Gateway Interface, uno standard per interfacciare applicazioni esterne con un server web. Quando il nostro browser mostra una pagina HTML, viene letto un file che risiede sul server; questo documento è statico, in quanto il suo contenuto non può cambiare. Lo stesso browser è anche in grado di leggere un file CGI, un file dinamico il cui contenuto può variare. Il file CGI richiamato dal nostro browser infatti, viene eseguito sul server con un certo numero di parametri che possono anche essere inseriti dall’utente tramite speciali moduli (form), ed in base a questo l’output può essere diverso. 

Se volessimo creare un database con i prodotti di cui dispone la nostra azienda, potremo scrivere un CGI eseguibile da qualunque utente connesso ad Internet che interroga un archivio. L’utente potrebbe trovarsi di fronte ad un form che mostra i vari articoli, in modo da selezionare quelli che desidera, per ricevere come output i relativi prezzi.

Non ci sono limiti alla programmazione CGI, se non quello del tempo necessario all’esecuzione. Se infatti la complessità del compito dovesse tradursi in un tempo di attesa eccessivo da parte dell’utente, il lavoro sarebbe inutile: difficilmente un navigatore trascorre più di 10 secondi in attesa di un responso. 

Perché Python?

Non intendo trattare le caratteristiche del Python in questa sede; basti dire che si tratta di un solido linguaggio orientato agli oggetti (diversamente dal Perl che è Object Based), con una sintassi estremamente chiara e semplice. Questo agevola la manutenibilità del codice da parte di più persone e la stessa riusabilità. 

L’estensibilità del Python garantisce la disponibilità di moduli con eccellente documentazione relativi alle più disparate funzionalità. Questo è vero soprattutto per l’insieme di moduli correlati ad Internet, con librerie dedicate alla gestione degli URL, del protocollo POP, del CGI e tanto altro ancora. 

Come iniziare

Non mi propongo di realizzare una trattazione teorica, ma auspico che chiunque legga questo documento sia pronto a realizzare i semplici esempi che verranno proposti per capire meglio i meccanismi che stanno alla base del CGI.

Perché questo sia realizzabile bisogna disporre di un server HTTP; il più conosciuto, diffuso e meglio documentato è sicuramente il web server Apache. Da questo punto in poi presupporrò che disponiate di un Apache di versione almeno 1.1.x. Questo nella sua configurazione di default non dovrebbe avere abilitata l’esecuzione di programmi CGI. I file di configurazione dovrebbero risiedere in una directory tipo /etc/httpd/conf/ e sono tre: httpd.conf, access.conf, srm.conf

In genere il server viene impostato in modo che la directory root sia /home/httpd/html/; questo significa che l’indirizzo locale http://localhost/ o http://127.0.0.1/ dovrebbe mostrare il file /home/httpd/html/index.html; nel caso dell’Apache questo dovrebbe avere come titolo "It Worked!". A questo punto dobbiamo abilitare l’esecuzione di programmi CGI; abbiamo due possibilità:

  • Limitare l’esecuzione ai soli programmi residenti nella dir /home/httpd/cgi-bin/. Per ottenere questo risultato è necessario modificare il file access.conf e modificare la seguente riga :
<Directory /home/httpd/cgi-bin> Options Indexes FollowSymLinks </Directory> 

in

<Directory /home/httpd/cgi-bin> Options FollowSymLinks ExecCGI </Directory>

  • Garantire l’esecuzione a tutti i programmi presenti nelle varie subdir di /home/httpd/html/. Per fare questo è necessario modificare il file acess.conf ed eliminare il cancelletto # in testa alla riga 
<Directory /home/httpd/html> Options All </Directory>

Inoltre è necessario aggiungere al file srm.conf la riga:

AddHandler cgi-script .py 
 
 

A questo punto perché un programma sia universalmente eseguibile, deve poter disporre dei relativi permessi, che possono essere conferiti mediante chmod ugo+rx miofile.py.

Il primo script. 

Di solito il primo esempio di programmazione è Hallo World!; ho pensato di mantenere invariata la tradizione; vediamo il listato di ciao.py:

#!/usr/bin/python

def main():

print "Content-type: text/html"

print

print "<TITLE> Hello, World!</TITLE>"

print "Hello, World!"
 
 

La prima riga contiene il percorso dell’interprete; in questo modo se abbiamo il permesso di esecuzione, il programma può essere chiamato all’interno della sua dir con ./ciao.py. Se omettiamo la prima riga, il programma continua a girare se richiamato dalla shell, ma solo se invochiamo anche l’interprete: python ciao.py. Ovviamente nel nostro caso sarà il browser a richiamare indirettamente il programma per cui la prima riga è assolutamente necessaria.

La seconda riga definisce la funzione principale main(); le righe che seguono indentate rappresentano il corpo della funzione (per chiarire il significato dell’indentazione nel Python vedi http://web.tiscalinet.it/python/doc/index.html ).

Le righe che seguono iniziano tutte con print e si occupano di stampare il relativo contenuto nello standard output. In questo modo la prima comunica al browser il tipo del contenuto del documento: in questo caso si tratta di text/html. La riga successiva stampa una riga bianca, risultato che si sarebbe potuto ottenere anche con print "Content-Type: text/plain\n\n" usando il relativo carattere di escape. 

La porzione di codice che segue fornice dapprima il titolo al documento che visualizzerà il browser, e quindi il contenuto: Hello,World!
 
 

Stampiamo un’immagine

Utilizziamo i concetti acquisit nel precedente esempio per stampare una immagine. Ipotizziamo di disporre di una foto ferrari.gif; in linea di principio dovrebbe essere necessario comunicare al bowser che il contenuto del file è una immagine. In realtà lo script corretto è un po’ più complesso:

import sys

immagine = open('ferrari.gif','rb').read()

sys.stdout.write('Content-type: image/gif\r\n')

sys.stdout.write('\r\n')

sys.stdout.write(immagine)
 
 

La apparente maggiore complessità di questo script è essenzialmente legata al fatto che stampare l’immagine con print è poco opportuno: potrebbe non essere interpretato correttamente dal browser, o in concomitanza di una riga vuota potrebbe persino non essere interpretato. 

Per ovviare a questo inconveniente, si richiama inizialmente il modulo sys contenente le operazioni di sistema come sys.stout.write() che rappresenta l’equivalente di print

La riga che segue serve per leggere il file in cui è contenuta l’immagine (ferrari.gif), in modalità ‘rb’, dove r sta per read only, in quanto il file è aperto in sola lettura; l’opzione b è necessaria solo nel caso in cui si debba lavorare con Windows, nel qual caso è necessario distinguere tra file binario (come in questo caso) o di testo.

A questo punto troviamo la comunicazione al browser sul contenuto del documento, quindi i caratteri di escape per andare a capo, ed infine l’effettiva stampa dell’immagine. 

Coordinate temporali

Vediamo spesso delle pagine web in cui in un piccolo riquadro viene stampata l’ora locale; proviamo a realizzarla. Il risultato che ci proponiamo di ottenere è incredibilmente semplice, come appare dal seguente listato:

#!/usr/bin/python

from time import *

def main():

print "Content-type: text/html"

print

print "<TITLE>In mezzo al Mediterraneo</TITLE>"

print "Ciao!"

print "<P>Eccoci in Sardegna!<br>Oggi e'", ctime( time() ) + ".<P>"
 
 

In pratica il compito è demandato al modulo time richiamato inizialmente che si basa sull’orologio interno del server, e mediante la sua funzione ctime, visualizza giorno, ora ed anno.

I form

I form sono una sorta di modulo virtuale nel quale l’utente può inserire del testo, rispondere a quesiti, selezionare delle scelte mediante bottoni. Alla fine del form, si trovano in genere due bottoni: invia e resetta. Tutto questo è realizzato mediante codice HTML.

Quando l’utente invia il form, il contenuto viene passato ad un programma CGI, che lo valuta e ad esempio può aggiornare un database. 

Proviamo a realizzare un modulo per la ricerca di un dipendente tra quelli appartenenti ad una azienda. Ecco il codice HTML del file form.html:

<HTML>

<Head>

<Title>Questionario per i Clienti</Title>

</Head>

</Body>

<H1>Ricerca nell'archivio degli <em>impiegati</em></H1>

<br>

<Form 

Method = "POST"

Action = "http://localhost/echoform.py"

>

<Input Name="nomi" type=hidden value="clienti">

<P>Codice :<Input Name="codice" Type=int>

<P>Nome :<Input Name="nome" Type=text size=32>

<P>Indirizzo : <Input Name="indirizzo" Type=text maxsize=80>

<br>Cap : <Input Name="cap" Type=text size=8>

<br>Città : <Input Name="città" Type=text size=32>

<P>Tel. : <Input Name="tel" Type=text size=16>

<br>Fax : <Input Name="fax" Type=text size=16>

<P>Commenti :

<br><Textarea Name="commenti" Rows=2 Cols=80></Textarea>

<P><Input Name="submit" Type=submit value="Invia">

<Input Name="reset" Type=reset value="Resetta">

</Form>

</Body>

</HTML>

Credo che spiegare il contenuto di questo file sia inutile, in quanto è molto più immediato vederne il risultato; tuttavia è interessante notare la possibilità fornita dal HTML di definire un campo hidden, nascosto.

Vediamo adesso il listato del programma CGI echoform.cgi, che deve analizzare i dati:

#! /usr/bin/python

import cgi
 
 

def print_header() :

#stampa l'intestazione

print "Content-type: text/html"

print

print "<HTML>"

print "<Head><Title>Restituzione Parametri</Title></Head>"

print "<Body><H1>Restituzione Parametri</H1><hr>"
 
 

def display_query( form ) :

#mostra i dati

fields = form.keys()

print "<P><H2>Sono stati ricevuti i seguenti parametri:</H2>"

print "<UL>"

if len( fields ) == 0 :

print "<LI>Nothing"

else :

for f in fields :

print "<LI>", f, " : ", cgi.escape( form[ f ] )

print "</UL>"

def print_footer() :

#stampa il termine della pagina

print "</Body></HTML>"
 
 

def Main() :

#funzione principale

form = cgi.SvFormContentDict()

print_header()

display_query( form )

print_footer()
 
 

Main()
 
 

Inizialmente importiamo il modulo builtin CGI, nel quale sono definite funzioni come cgi.escape. A questo punto viene definita la funzione print_header(); si occupa di stampare l’intestazione (come evidenzia la docstring) e non è molto diversa dal precedente Hello, World!

La seconda funzione stampa i dati che sono stati inseriti; l’istruzione if controlla se effettivamente sono stati inseriti dati; in questo caso, il ciclo for si occupa di stampare solo le voci relative ai dati inseriti dall’utente. La funzione escape ha come effetto quello convertire caratteri come &, <, > in stringhe che possono essere interpretate senza equivoci dal browser. 

La terza funzione ha come scopo quella di concludere il documento, fornendo le istruzioni terminali alla pagina HTML.

In conclusione viene definita la funzione principale main(), dove il contenuto del form è assegnato alla classe SvFormContentDict(), che lo trasforma in un dizionario. Vengono poi richiamate le funzioni definite precedentemente. 

Conclusioni

Spero che questo documento abbia stimolato il vostro interesse nei confronti di Python, e vi invito a dare uno sguardo presso la sua homepage italiana http://web.tiscalinet.it/python o presso http://www.python.org .
 



 
 


Marco Buzzo
marcobuzzo@tiscalinet.it