|
Perl CGI Framework
Dit is een vervolg-pagina op deel
1 en deel 2!
Op deze pagina
Al met al heb ik ondertussen een beetje een standaard structuur in al mijn
CGI scripts, om snel andere scripts op te zetten (zoals voor mijn Sinterklaaslijstjes). Hier wat uitleg over de delen die de
basis vormen.
Begin van
het CGI script
Hier wordt het script opgezet. Een aantal zaken zijn hier van belang:
- Het zetten van de
-T optie, vanuit het punt van
veiligheid (zie mijn vorige CGI pagina, sectie over veiligheid)
- Ook zet ik waarschuwingen altijd aan, om programmeerfoutjes snel te
vinden
- Dan volgt er een stuk commentaar, dat ook als helptekst gebruikt kan worden
(bij uitvoer van het programma met de
-help of -?
optie, waar dan ook vervolgens op getest wordt). Dit kan normaal alleen via de
command line, niet als cgi in een web page.
#!/usr/bin/perl -T
# Framework for new CGI scripts, Kees Moerman (c) 2004-2010
# set some security and programming mistake preventions
# (note also -T option in line 1)
use warnings; # comparable to -w option
use strict; # don't forget to prefix vars with
my
my 1 = "v2.0.0019"; # version number
tracking
my $help_text = <<HELP; # help text is
placed below, up to HELP
# $0 version 1, Kees Moerman (c) 2004-2010
#
# Syntax: run as cgi script on web server, not via command line
#
# Put a more extensive desription here...
#
# Structure of the program is a kind of state machine,
# with the current state (plus machine state) encoded into the forms
# (as the cgi protocol is stateless).
#
HELP
$help_text =~ s/^# ?//gm; # clean up comment
characters
#
# Change list:
# ....
#
# To do:
# ....
# call from command line possible, e.g. 'script.pl a=1 b=2'
# run from command line with help request?
if (defined $ARGV[0] && ($ARGV[0] eq "-?" || $ARGV[0] eq
"-h" || $ARGV[0] eq "-help"))
{ print $help_text;
exit 1;
}
Opzetten
van de CGI module
Het opzetten van de CGI module, ook weer met wat veiligheidsinstellingen, maar ook dusdanig dat
foutmeldingen ook in de browser terecht komen, in plaats van in een of andere
duistere server log file.
# set up CGI module and supporting items,
esp for error handling
# This way, we do not have to look through server logs to find
warnings
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
use CGI qw/:standard -no_xhtml/; # load standard
CGI routines
$CGI::POST_MAX=1024 * 10; # max 10K size posts
$CGI::DISABLE_UPLOADS = 1; # no uploads
allowed
warningsToBrowser(1);
BEGIN { warningsToBrowser(1); } # want warning as
HTML comments
# if you need only one CGI object, you can use the
function form instead
my $cgi = new CGI;
# cgi caller error handler
my $error = $cgi->cgi_error;
if ($error) # any error already while opening
script?
{ # then try to make the best of it
print $cgi->header(-status=>$error),
$cgi->start_html('Problems'),
$cgi->h2('Request not processed'),
$cgi->strong($error);
exit 1;
}
Foutafhandeling in het programma
Een routine om ook zelf duidelijke foutmeldingen te kunnen genereren (met
name de routine die_html). Wel even aanpassen aan je eigen email
adres.
my $html_header_sent = 0; # no cgi
header send yet? (for die_html)
sub die_html # fatal error: generate HTML error
message
{
my $message = shift || "no message passed";
my $program = $0; $program =~ s@.*/@@; # remove
path
my CGI framework = "Error in '$program'";
if(!$html_header_sent)
{
$html_header_sent = 1;
print header(); # CGI header: simple document
type
print start_html(-title => CGI framework, -BGCOLOR=>'#F0FFFF');
}
print
h1(CGI framework), "\n",
p("Error message: $message"), "\n",
p("Please contact the web master of these web pages:\n",
a({href=>("mailto:yourmailaddress\@yourdomain.nl")})
), "\n",
end_html(); # end of HTML page
if(open LOGFILE, ">>logfile.txt")
{ print LOGFILE "Fatal error detected in '$program' at " .
localtime()
. " line $., message is '$message', \$\@ = '$@', \$! = '$!'\n";
close LOGFILE;
}
exit(0);
}
De
dispatcher
Complexe CGI scripts (bijvoorbeeld met veel forms) worden vaak aangeroepen
vanuit verschillende fases, bijvoorbeeld het initiële scherm met de vraag
om in te loggen, een scherm met een invulformulier, en een scherm met de
resultaten van het opsturen van een formulier. Dit kunnen ieder verschillende
CGI programma's zijn, maar dan moet je je programma verdelen over verschillende
scripts.
In plaats hiervan programmeer ik mijn complexere CGI functies vaak als een
soort state machine, bijvoorbeeld met states 'login' (het
inlogscherm met login form), 'select' (met de main form), en
'add' (bevestigingsboodschap). De state wordt meegegeven in de cgi
aanroep als een GET/POST argument (zie de vorige
pagina's), in de vorm van action=nextstate. De dispatcher
zorgt er vervolgens voor dat de juiste routines worden aangeroepen. Hier een
voorbeeld uit mijn Sinterklaaslijstjes
programma.
print $cgi->header(); # CGI
header: simple document type
print my_html_header(); # does the title,
etc
$html_header_sent = 1;
# State machine core state diagram:
# Next state is passed through the action parameter in the calling form
# ....
my $cgi_action = $cgi->param('action') || 'unknown';
if ($cgi_action eq 'unknown'){ sint_login(); }
elsif ($cgi_action eq 'login') { sint_login(); }
elsif ($cgi_action eq 'select') { sint_select(0); }
elsif ($cgi_action eq 'add') { sint_own(0); }
elsif ($cgi_action eq 'buy') { sint_buy(0); }
else { die_html("Unknown command '$cgi_action'"); }
Verdere
functies
Daarnaast heb ik nog standaard routines om HTML uit een template te plukken,
configuratiefiles te lezen en te schrijven, en dergelijke, om snel nieuwe
scripts in elkaar te kunnen draaien. Maar, dat heeft niets meer te maken met de
CGI problematiek, is meer algemene Perl vaardigheden, dus die ga ik hier niet
verder beschrijven.
|