Come programmare script CGI con Python, testarli con CGIHTTPServer ed installarli su WebFaction

Python consente di creare script per la Common Gateway Interface (CGI) e testarli in locale con CGIHTTPServer; in questo articolo, spiego come creare un modulo HTML protetto con reCAPTCHA per raccogliere un feedback degli utenti, ed uno script CGI in Python che invia una e-mail al mio indirizzo. Ho realizzato questo progetto con Pelican e l’ho installato online su WebFaction.

Pubblicato da Roberto Fusi in Web Development. Aggiornato .
Lunghezza testo: 2447 parole. Stima tempo lettura: 10 minuti.
Tag: python, cgi, html. .

La Common Gateway Interface (CGI) permette ad un server web di eseguire particolari programmi, detti script CGI, che processano le informazioni o i comandi inviati attraverso una richiesta HTTP.

I files degli script CGI sono tradizionalmente registrati nella directory cgi-bin, hanno estensione “.cgi” e si possono realizzare con diversi linguaggi di programmazione come C, Perl, Ruby, Python etc…

Quando un server HTTP riceve una richiesta che specifica uno script CGI, esegue il file corrispondente e restituisce il suo output, al posto del file stesso (come normalmente avviene per tutti gli altri file di testo come HTML, JavaScript, CSS etc…).

Questo schema di funzionamento molto semplice, comporta che uno script viene eseguito dal server, ogni volta che si sottomette una richiesta che lo riguarda: ciò, può comportare un alto consumo di risorse. Perciò, gli script CGI sono indicati dove se ne prevede una bassa frequenza di utilizzo.

Inoltre, l’uso di script CGI sul server, richiede di fare attenzione a questi aspetti legati alla sicurezza:

  • la corretta impostazione dei permessi dei file degli script;
  • la pericolosità dell’input trasmesso dall’utente;
  • la riservatezza della username/password, eventualmente inclusa nello script.

La CGI definisce delle variabili d’ambiente standard (CGI standard environment variables), che il web server rende disponibili allo script:

  • AUTH_TYPE = definisce il meccanismo di autenticazione supportato dal server (per esempio, “Basic” o “Digest”);
  • CONTENT_LENGTH = specifica la dimensione del “message-body” allegato alla richiesta HTTP;
  • CONTENT_TYPE = specifica il tipo del “message-body” allegato alla richiesta HTTP;
  • DOCUMENT_ROOT = directory base (radice) del server HTTP (per esempio, “/home/tizio/webapps/_”);
  • GATEWAY_INTERFACE = specifica lo standard CGI supportato dal server (per esempio, CGI/1.1)
  • HTTP_COOKIE = informazioni registrate nel cookie dell’utente (per esempio, “cookieconsent_status=dismiss; __unam=2830861-15ce00f101a-52593115-3; _ga=GA1.2.79693932.1498407696; _gid=GA1.2.751182791.1498514568”);
  • HTTP_HOST = nome di dominio della pagina richiesta (per esempio, “www.ipertesti.com”);
  • HTTP_REFERER = indirizzo URI della pagina web che ha originato la richiesta HTTP (per esempio, https://www.ipertesti.com/pages/contatti.html);
  • HTTP_USER_AGENT = descrizione del browser usato dall’utente (per esempio, Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36);
  • HTTPS = indica se la pagina è stata richiesta attraverso una connessione sicura (se è attiva, la variabile assume il valore “on”);
  • PATH = percorsi da cui è possibile eseguire programmi sul server (per esempio, “/usr/local/bin:/usr/bin:/bin”);
  • PATH_INFO = percorso aggiuntivo che segue il nome dello script CGI nella richiesta HTTP (per esempio, se si richiede l’indirizzo “https://localhost:8000/cgi-bin/environment-vars.py/test-more/”, allora PATH_INFO sarà “/test-more/”);
  • PATH_TRANSLATED = percorso assoluto sul server, derivato da PATH_INFO (per esempio se PATH_INFO=/test-more/, allora PATH_TRANSLATED potrebbe assumere il valore “/home/tizio/webapps/miosito_com/test-more/”);
  • QUERY_STRING = stringa passata allo script CGI con il metodo HTTP GET (per esempio, nell’indirizzo “https://localhost:8000/cgi-bin/environment-vars.py?A=1&B=1”, il valore “A=1&B=1” è la QUERY_STRING);
  • REMOTE_ADDR = indirizzo IP dell’utente che ha inviato la richiesta HTTP;
  • REMOTE_HOST = nome di dominio del computer che ha inviato la richiesta HTTP;
  • REMOTE_IDENT = può indicare un identificativo dell’utente che ha inviato la richiesta HTTP;
  • REMOTE_PORT = nome della porta usata dal computer che ha inviato la richiesta HTTP;
  • REMOTE_USER = specifica il nome dell’utente che ha inviato una richiesta di autenticazione HTTP;
  • REQUEST_METHOD = specifica il modo in cui lo script CGI deve processare la richiesta HTTP (per esempio, “GET”, “POST”, “HEAD”);
  • REQUEST_URI = porzione dell’indirizzo URL oltre il dominio (per esempio, “/cgi-bin/environment-vars.py?A=1&B=1”);
  • SCRIPT_FILENAME = percorso assoluto sul server dello script CGI (per esempio, /home/tizio/webapps/miosito_com/cgi-bin/environment-vars.py);
  • SCRIPT_NAME = percorso relativo rispetto al dominio, dello script CGI (per esempio, “/cgi-bin/environment-vars.py”);
  • SERVER_ADMIN = indirizzo e-mail dell’amministratore del server;
  • SERVER_NAME = nome di dominio del server (per esempio, “www.ipertesti.com”);
  • SERVER_PORT = numero di porta usata dal server HTTP;
  • SERVER_PROTOCOL = protocollo usato per la comunicazione con il server (per esempio, “HTTP/1.0”);
  • SERVER_SOFTWARE = nome “commerciale” del server HTTP.

Oltre a quelle menzionate sopra, uno specifico server HTTP (IIS, Apache, etc…) può aggiungere variabili d’ambiente non standard.

Gli script CGI possono anche ricevere input da console o tramite una richiesta HTTP POST (che non viene registrata nelle variabili d’ambiente).

Di seguito, propongo alcuni script per testate la CGI e processare un modulo HTML per inviare una email; ho programmato ed eseguito gli script con Python 2.7.13 su Windows 10 configurato come ho spiegato in un mio precedente articolo. Inoltre, ho caricato e testato gli script online su hosting WebFaction.

Creazione e test del primo script CGI in Python: Hello World!

Per programmare script CGI con Python, si usa il modulo “cgi”; per iniziare, creerò lo script “hello-world.cgi”.

#!/usr/local/bin/python2.7
import cgi
print("Content-Type:text/html\n\n")
print("<html><body><h1>Hello World!</h1></body></html>")

Per eseguire lo script appena creato sull’hosting WebFaction basato su server Linux, occorre:

  1. Salvare il file dello script CGI con il “fine linea” Unix (LF) e non quello di Windows/DOS (CRLF). Se usi l’editor ATOM, basta far click sul testo “CRLF” riportato in basso a sinistra, sulla barra di stato, per ottenere “LF”. In alternativa, è possibile convertire successivamente il file, tramite la shell SSH del server di WebFaction, eseguento il comando “dos2unix”. Per esempio:

    $ dos3unix hello-world.cgi
    
  2. Collegarsi via SSH o FTP al server, creare la directory “cgi-bin” nell’applicazione WebFaction e copiarci i files degli script CGI. Per far ciò, puoi usare un client FTP come FileZilla, oppure usare RSYNC, come ho descritto in un mio precedente articolo.

  3. Impostare i permessi 711 per la directory “cgi-bin” e tutti gli script CGI che contiene con il comando “chmod”; per esempio:
    $ chmod 711 . *.cgi
    $ chmod 711 . *.py
    

Con WebFaction, i file degli script CGI possono avere estensione .cgi oppure .py. E’ anche possibile specificare altre estensioni come script CGI, impostando la direttiva Apache FileMatch nel file .htaccess; per esempio, se voglio eseguire i file con estensione “.bin” come script CGI, dovrò impostare questa istruzione nel file “.htaccess”:

<FilesMatch \.bin$>
  SetHandler cgi-script
</FilesMatch>

Per ovviare ad un problema che esporrò di seguito (riguardo CGIHTTPServer), suggerisco di assegnare a tutti gli script CGI, l’estensione “.py”.

Le variabili CGI

Dopo aver testato il funzionamento del più semplice script CGI, procedo con l’esplorare le funzionalità del modulo cgi.py. Creo il nuovo script “test.py” e lo carico sul server per scoprire quali sono le variabili disponibili.

#!/usr/local/bin/python2.7
import cgi

print("Content-Type:text/html\n\n")
print("<html><head><title>TEST - CGI Script in Python</title></head><body><h1>TEST - CGI Script in Python</h1>")
print("<h2>cgi.test()</h2>")
cgi.test()
print("<h2>cgi.print_environ()</h2>")
cgi.print_environ()
print("<h2>cgi.print_directory()</h2>")
cgi.print_directory()
print("<h2>cgi.print_environ_usage()</h2>")
cgi.print_environ_usage()
print("</body></html>")

I metodi test(), print_environ(), print_directory(), print_environ_usage() sono usati per stampare output formattato in HTML.

test script CGI in python su webfaction

Ora, creo un nuovo script che mostra come accedere alle variabili d’ambiente definite in os.environ.

#!/usr/local/bin/python2.7
import cgi, os
print("Content-Type:text/html\n\n")
print("<html><head><title>TEST - CGI Script in Python: Environment </title></head><body><h1>TEST - CGI Script in Python: Environment</h1>")
print("<dl>")
for k, v in os.environ.items():
  print('<dt><strong>{0}</strong></dt><dd>{1}</dd>'.format(k, v))
print("</dl></body></html>")

Oltre alle variabili specifiche dell’ambiente di esecuzione dello script, occorre poter elaborare un input proveniente dalle richieste HTTP. Nel Web, é possibile passare dei valori ad uno script in due modi: GET e POST. In modo molto sintetico, GET acquisisce dati sotto forma di stringa di testo (QUERY_STRING) nell’URL, mentre POST trasmette i dati raccolti da un modulo HTML. Per leggere i valori trasmetti ad uno script CGI in Python uso il metodo FieldStorage(). Nel prossimo script, introduco anche il modulo cgitb per tracciare e documentare eventuali eccezioni, che si possono verificare in fase di esecuzione.

Creo lo script “process-cgi-input.py” e lo installo sul server; si noti il parametro logdir=”../logs” di cgitb.enable() che permette di salvare messaggi di errore nella cartella “logs”.

#!/usr/local/bin/python2.7
import cgi, cgitb, os
cgitb.enable(display=0, logdir=os.path.join(os.path.dirname(__file__), '../logs'), format='text')

input_data=cgi.FieldStorage()
try:
  a=int(input_data['a'].value)
  b=int(input_data['b'].value)
  c=a+b
except:
  print('<p>"a" oppure "b", o entrambi, non sono numeri</p>')

print("Content-Type:text/html\n\n")
print('<html><head><title>TEST - CGI Script in Python: Process CGI Input </title></head><body><h1>TEST - CGI Script in Python: Process CGI Input</h1>')
print('<h2>interesting os.environ variables</h2>')
print('<p>os.environ["GATEWAY_INTERFACE"] = %s</p>' % os.environ['GATEWAY_INTERFACE'])
print('<p>os.environ["HTTP_USER_AGENT"] = %s</p>' % os.environ['HTTP_USER_AGENT'])
print('<p>os.environ["QUERY_STRING"] = %s</p>' % os.environ['QUERY_STRING'])
print('<p>os.environ["SERVER_PROTOCOL"] = %s</p>' % os.environ['SERVER_PROTOCOL'])
print('<h2>a + b = c</h2>')
print('<p>{0} + {1} = {2}</p>'.format(a,b,c))
print("</dl></body></html>")

Se digito il percorso per accedere allo script process-cgi-input.py senza la QUERY_STRING, il server ritornerà una pagina di errore; inoltre, lo script salverà un report in formato HTML con tutti i dettagli nella cartella logs che ho citato prima.

test script CGI in python su webfaction

Se invece, accedo allo script passando gli argomenti corretti, vedrò il risultato corretto. Per esempio, digitando l’URI:

cgi-bin/process-cgi-input.cgi?a=1&b=5

Otterrò il seguente output corretto:

test script CGI in python su webfaction

L’esempio appena descritto, visualizza alcune variabili d’ambiente, processa l’input inviato dall’utente con il metodo GET per calcolare una semplice somma, visualizza una pagine web con il risultato ed eventualmente registra una eccezione nella cartella “logs”.

Usare il server web CGIHTTPServer per i test degli script CGI in locale

Fino ad ora, ho trovato conveniente testare gli script CGI direttamente online sul server di WebFaction; ho fatto così, per verificare il funzionamento di semplici script nell’ambiente di produzione, ed anche per esplorare ed annotare i valori delle sue variabili caratteristiche.

Tuttavia, Python è equipaggiato con un server http in grado di eseguire script CGI: si tratta del modulo CGIHTTPServer. Per eseguirlo, è sufficiente digitare il seguente comando dalla cartella radice del sito (per esempio, dalla directory “output” del sito basato su Pelican):

$ python -m CGIHTTPServer

Per impostazione predefinita, CGIHTTPServer tenta di eseguire gli script CGI nelle cartelle “cgi-bin” oppure “htbin”. Tuttavia, se i file degli script non sono eseguibili, il server restituirà un errore 403 specificando “CGI script is not executable”, come nel seguente esempio.

test script CGI in python con CGIHTTPServer - errore 'CGI script is not executable'

In questo caso, il problema é specifico di Windows: anche impostando l’estensione “.cgi” come applicazione Python, CGIHTTPServer non esegue lo script. In Linux/Unix, il problema si risolve impostando i permessi di esecuzione con chmod.

Per aggirare il problema, rinuncio ad attribuire l’estensione “.cgi” agli script in favore di quella più convenzionale “.py”. In questo modo, CGIHTTPServer esegue correttamente lo script CGI anche in ambiente Windows.

test script CGI in python su webfaction

Ricapitolando, se tutto è impostato correttamente, é sufficiente lanciare un paio di comandi da console per mettere in esecuzione il modulo CGIHTTPServer, ed essere così in grado di testate il sito basato su Pelican, con il corredo di script CGI collocati nella cartella cgi-bin/.

test script CGI in python su webfaction

Creare il modulo HTML per scrivere le e-mail ed iscriversi alla newsletter con la protezione reCAPTCHA

Il modulo HTML per l’invio delle email dal sito, è costituito da 4 semplici campi:

  1. il campo testo “Nome”, per raccogliere il nome del mittente;
  2. il campo testo “E-mail”, per raccogliere l’indirizzo del mittente;
  3. il campo testo “Messaggio”, per poter scrivere il testo della e-mail;
  4. la casella di testo “iscriviti alla newsletter”.

Si noti che ho impostato entrambi gli attributi name ed id per i campi HTML che raccolgono l’input dell’utente. Infatti, l’attributo name è usato come identificatore dei campi HTML, nella trasmissione con il metodo POST; l’attributo id è invece usato per identificare gli elementi HTML in CSS e JavaScript.

Il modulo HTML si avvale anche delle classi di formattazione supportate da Bootstrap. Ho anche inserito il controllo reCAPTCHA per prevenire l’invio del modulo da parte di Web Robots. Inoltre, la funzione JavaScript validateForm() previene l’invio dei dati nel caso vi siano omissioni.

<script>
  function validateForm() {
    var errors = 0;
    var reCAPTCHA = document.getElementById("g-recaptcha-response");
    if (reCAPTCHA.value == "") {
        errors++;
        document.getElementById("reCAPTCHAError").innerHTML = "Il test reCAPTCHA deve essere convalidato.";
    }
    if (errors == 0) {
      return true;
    }
    return false
  }
</script>
<form class="form-horizontal" action="/cgi-bin/sendEmail.py" method="POST"  onsubmit="return validateForm()">
<p id="formError"></p>
<div class="form-group">
  <label for="inputName" class="col-sm-2 control-label">Nome</label>
  <div class="col-sm-10">
    <input type="text" class="form-control" name="inputName" id="inputName" placeholder="Scrivi qui il tuo nome" maxlength="60" required="required">
  </div>
</div>
<div class="form-group">
  <label for="inputEmail" class="col-sm-2 control-label">E-mail</label>
  <div class="col-sm-10">
    <input type="email" class="form-control" name="inputEmail" id="inputEmail" placeholder="Scrivi qui la tua e-mail" maxlength="120" required="required">
  </div>
</div>
<div class="form-group">
  <label for="inputMessage" class="col-sm-2 control-label">Messaggio</label>
  <div class="col-sm-10">
    <textarea class="form-control" rows="8" name="inputMessage" id="inputMessage" maxlength="5000" placeholder="Scrivi qui il tuo messaggio" required="required"></textarea>
  </div>
</div>
<div class="form-group">
  <div class="col-sm-offset-2 col-sm-10">
    <div class="checkbox">
      <label>
        <input type="checkbox" name="inputSubscribe" id="inputSubscribe" value="Si"> Iscrivimi alla newsletter
      </label>
    </div>
  </div>
</div>
<div class="form-group">
  <div class="col-sm-offset-2 col-sm-10">
    <div class="g-recaptcha" data-sitekey="6LdxwSYUAAAAAIw88QOYKh1IPJeoqJqTnzbw7Hqk"></div>
    <p id="reCAPTCHAError"></p>
  </div>
</div>
<div class="form-group">
  <div class="col-sm-offset-2 col-sm-10">
    <input type="hidden" name="inputLanguage" id="inputLanguage" value="IT">
    <button type="submit" class="btn btn-default">INVIA</button>
  </div>
</div>
</form>

Infine, ho predisposto altre due pagine:

  1. una per visualizzare un messaggio di conferma dell’invio;
  2. un’altra da visualizzare nel caso non sia stato compilato correttamente il modulo e non sia stato possibile inviare l’e-mail.

Messaggio errore form email

Lo script per inviare l’e-mail

All’inizio di questo articolo, ho spiegato come eseguire script CGI sia nell’ambiente di test, che in quello di produzione su WebFaction; poi, ho predisposto le pagine web per compilare una e-mail e visualizzare dei messaggi di risposta. Ora, creo lo script CGI sendEmail.py per inviare l’e-mail.

#!/usr/local/bin/python2.7
# -*- coding: utf-8 -*-

# Nome script: sendEmail.py
# Author: Roberto Fusi
# Last update: 26th June 2017

import cgi, cgitb, smtplib, os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText

# Configuration
DEBUG = False
ENV = 'Pro' # switch between Dev=Development or Pro=Production
LANG = 'IT' # switch betweeb IT=Italian or EN=English
CONF = {
    'Pro' : {
        'CGITB_LOG_DIR' : os.path.join(os.path.dirname(__file__), '../logs'),
        'SMTP_SERVER' : 'smtp.webfaction.com',
        'SMTP_SERVER_PORT' : 465,
        'USERNAME' : '.......',
        'PASSWORD' : '.......',
        'ORIGIN' : '.......',
        'RECIPIENT_EMAIL' : '.......',
        'RECAPTCHA_SKEY' : '.......',
        'RECAPTCHA_FIELD' : 'g-recaptcha-response',
        'URL_REDIRECT_OK' : 'https://......./contatti_ok.html',
        'URL_REDIRECT_ERROR' : '......../contatti_errore.html',
    },
    'Dev' : {
        'CGITB_LOG_DIR' : os.path.join(os.path.dirname(__file__), '..\logs'),
        'SMTP_SERVER' : 'smtp.webfaction.com',
        'SMTP_SERVER_PORT' : 465,
        'USERNAME' : '.......',
        'PASSWORD' : '.......',
        'ORIGIN' : '.......',
        'RECIPIENT_EMAIL' : '.......',
        'RECAPTCHA_SKEY' : '',
        'RECAPTCHA_FIELD' : 'NA',
        'URL_REDIRECT_OK' : 'http://localhost:8000/pages/contatti_ok.html',
        'URL_REDIRECT_ERROR' : 'http://localhost:8000/pages/contatti_errore.html',
    }
}
TEXT = {
    'IT' : {
        'Subject' : ' - Richiesta di contatto da ',
        'Subscription' : 'Chiede di ricevere la Newsletter: ',
    },
    'EN' : {
        'Subject' : ' - Contact request from ',
        'Subscription' : 'Has asked to receive the Newsletter: ',
    }
}

# Process the e-mail
cgitb.enable(display=0, logdir=CONF[ENV]['CGITB_LOG_DIR'], format='text')
input_data=cgi.FieldStorage()

try:
    if len(input_data) > 0:
        reCAPTCHA_Response = input_data.getvalue(CONF[ENV]['RECAPTCHA_FIELD'], '')
        if reCAPTCHA_Response == "" and ENV == 'Pro':
            raise Exception('reCAPTCHA has been not verified!')
        else:
            LANG = input_data.getvalue('inputLanguage', LANG)
            email = MIMEMultipart()
            email['From'] = input_data.getvalue('inputEmail', '')
            email['To'] = CONF[ENV]['RECIPIENT_EMAIL']
            email['Subject'] = CONF[ENV]['ORIGIN'] + TEXT[LANG]['Subject'] + input_data.getvalue('inputName', 'N/A')
            message = input_data.getvalue('inputMessage', '')
            newsletter = input_data.getvalue('inputSubscribe', "No")
            if email['From'] != "" and message != "":
                email.attach(
                    MIMEText((message + "\n\n" + TEXT[LANG]['Subscription'] + newsletter + "\n\nreCAPTCHA: " + reCAPTCHA_Response + "\n\nHTTP_REFERER: " + os.environ['HTTP_REFERER'] +
                    "\nHTTP_USER_AGENT: " + os.environ['HTTP_USER_AGENT'] +
                    "\nREMOTE_ADDR: " + os.environ['REMOTE_ADDR']
                    ),'plain','utf-8')
                )
                s = smtplib.SMTP_SSL()
                s.set_debuglevel(DEBUG)
                s.connect(CONF[ENV]['SMTP_SERVER'], CONF[ENV]['SMTP_SERVER_PORT'])
                s.login(CONF[ENV]['USERNAME'],CONF[ENV]['PASSWORD'])
                s.sendmail(email['From'], email['To'], email.as_string())
                s.quit()
                print('Status: 302 Found')
                print('Location:' + CONF[ENV]['URL_REDIRECT_OK'] + "\r\n")
            else:
                raise Exception('The email address or the massage has been not written!')
    else:
        raise Exception('FieldStorage() è vuoto! len(FieldStorage()) = 0')
except:
    dumpFieldStorage = "\r\n"
    for i in input_data:
        dumpFieldStorage += i + " = " + input_data[i].value + "\n"
    raise Exception(cgi.FieldStorage(), dumpFieldStorage)
    print('Status: 302 Found')
    print('Location:' + CONF[ENV]['URL_REDIRECT_ERROR'] + "\r\n")

Ho cercato di rendere questo script configurabile con l’impostazione di variabili globali. Le parti dove ho indicato i punti di sospensione “’…….’” vanno chiaramente compilate nel modo opportuno. Ho anche predisposto una variabile globale DEBUG per impostare il dettaglio delle informazioni che si desidera avere, nel caso si verifichi una eccezione durante l’esecuzione dello script.

Purtroppo, si noterà che CGIHTTPServer non eseguirà l’istruzione di re-indirizzamento, perché non è supportata:

print('Location:' + URL_REDIRECT_OK + "\r\n")

Per rilevarne il funzionamento, occorre installare Apache (o un’altro server HTTP) in locale, oppure verificarla direttamente sul server online.

Conclusioni

Python consente di sviluppare script CGI in modo rapido e sicuro.

Questo articolo ha descritto come programmare script CGI nonché come eseguirli in locale ed online.

Tuttavia, si noterà che lo script CGI sendEmail.py potrebbe essere reso ancora più sicuro impostando un controllo sulla variabile d’ambiente “HTTP_REFERER”: in modo, si potrebbe verificare che i dati provengono effettivamente dal proprio sito. Inoltre, la funzione JavaScript validateForm() è “semplificata”: non esegue il controllo di compilazione di tutti i campi obbligatori. Nella prossima revisione di questo articolo, implementerò queste funzionalità mancanti.

Hai qualche altro suggerimento o osservazione? Pubblicala e condividila qui sotto con DISQUS!

Riferimenti

  1. Common Gateway Interface
  2. HOWTO Use Python in the web
  3. CGIHTTPServer — CGI-capable HTTP request handler
  4. cgi — Common Gateway Interface support
  5. cgitb — Traceback manager for CGI scripts
  6. Static Files, CGI Scripts, and PHP Pages
  7. CGI (Common Gateway Interface) Scripts
  8. Apache Tutorial: Dynamic Content with CGI
  9. reCAPTCHA
  10. os — Miscellaneous operating system interfaces
  11. Get reCAPTCHA
  12. email
  13. email: Examples
  14. smtplib — SMTP protocol client
  15. email.mime: Creating email and MIME objects from scratch
  16. Make your software behave: CGI programming made secure
  17. rfc3875 - The Common Gateway Interface (CGI) Version 1.1

Libri suggeriti

Condividi questo articolo

Se ti è piaciuto questo articolo e pensi possa essere utile anche ad altri, condividilo con i tuoi amici e conoscenti, facendo click sui pulsanti dei tuoi social network preferiti.

P.S. Grazie!

Commenti

Cosa pensi di questo articolo? Hai dei suggerimenti da darmi o vuoi segnalare la tua esperienza in questa pagina? Registrati con Disqus ed inserisci il tuo commento qui sotto!

Inoltre, se lo desideri puoi anche scrivermi una e-mail.

Presentazione

IpeRteSTi é un blog curato da Roberto Fusi. Raccoglie suggerimenti ed esperienze personali riguardo Internet, Web Development e la Digital Economy.

Seguimi sui social

LinkedInTwitterGooglePlusFeedburner for IpeRteSTi

Iscriviti alla mia newsletter