|
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.
|