CGI en mod_perl
Spreker: Juerd
Duur:
45 minuten ruim een uur
Dutch Perl Workshop 2004
Werkt waarschijnlijk alleen goed in Mozilla
(?:Fire(?:Bird|Fox))? (F11 voor full screen) en andere op Gecko gebaseerde
browsers. Bovendien gebruik ik een lettertype dat vast bijna niemand heeft :)
De slides zijn gemaakt door een scriptje(text/plain) dat een groot semi-html-bestand gebruikt als bron en alles aan de hand
van dit template in losse bestanden zet. The English translation is here.
Inhoud
- HTTP en HTML
- CGI
- Templates
- Wizards
- Sessies
- Cookies
- mod_perl
HTTP
- HTTP is sessieloos
- HTTP is simpel
- Weinig web coders kennen HTTP
HTTP request
- Request-regel
GET /cgi-bin/foo?bar=baz HTTP/1.1
of POST /cgi-bin/bar HTTP/1.1
- Headers
Host: www.leukesite.nl
User-Agent: Mozilla/4.5 (Compatible; blaat)
Accept: text/html, text/plain
- Lege regel
- Body (bij POST requests)
HTTP response
- Status-regel
HTTP/1.1 200 OK
of HTTP/1.1 404 Not found
of HTTP/1.1 500 Internal Server Error
of ...
- Headers
Content-Type: text/html
- Lege regel
- Body (de pagina zelf)
HTTP-misbruik
- Je kan HTTP makkelijk voor andere dingen gebruiken
- Voornamelijk RPC
- SOAP
- HTTP::Daemon / LWP::UserAgent
- Gratis proxy-support
HTML forms
<form method="POST" action="test.cgi">
- method = GET of POST
- action = URL
- Invoervelden, drop-downs, knoppen
- Gelijke namen => array in Perl!
HTML > CGI
- Einde HTTP/HTML
- Vragen?
- Hierna: CGI
CGI
- Niet perl-specifiek!
- STDIN heeft POST body
- STDOUT gaat naar de browser
- %ENV zit vol met info
- Headers beginnen met HTTP_
- Zoals: $ENV{HTTP_USER_AGENT} en $ENV{HTTP_HOST}
Een CGI-script
- Aanmeldingsscript
- Vraagt om:
- Gebruikersnaam, wachtwoord
- Naam, adres, woonplaats
- Telefoonnummer
- E-mailadres, homepage URL
- Geen foutcontrole
- Bedankt-pagina
CGI + HTML
#!/usr/bin/perl -w
use strict;
use CGI;
my $cgi = CGI->new;
print $cgi->header;
if ($cgi->request_method eq 'POST') {
doe iets;
print <<'END_OF_HTML';
[[[html>
[[[head>
[[[title>Bedankt![[[/title>
[[[/head>
[[[body>
Hartelijk bedankt voor uw aanmelding!
U ontvangt spoedig een bevestiging
per e-mail.
[[[/body>
[[[/html>
END_OF_HTML
} else {
print <<'END_OF_HTML';
[[[html>
[[[head>
[[[title>Aanmelden[[[/title>
[[[/head>
[[[body>
Vul onderstaande velden in:[[[br>
Gewenste gebruikersnaam: [[[input type=text name=user>
Wachtwoord: [[[input type=password name=pass>[[[br>
Nogmaals: [[[input type=password name=pass>
[[[hr>
Naam: [[[input type=text name=naam>[[[br>
Adres: [[[input type=text name=adres>[[[br>
Postcode: [[[input type=text name=postcode>[[[br>
Woonplaats: [[[input type=text name=woonplaats>
[[[hr>
Telefoonnummer: [[[input type=text name=telefoon>[[[br>
E-mailadres: [[[input type=text name=mail>[[[br>
Homepage URL: [[[input type=text name=url>
[[[hr>
[[[input type=submit value="Aanvraag versturen">
[[[/body>
[[[/html>
END_OF_HTML
}
CGI.pm kan HTML maken
- Nog steeds HTML
- Iets minder lelijk
- Veel trager
- Handige 'sticky' values
CGI > Templates
- Einde CGI
- Vragen?
- Hierna: Templates
Pagina's in bestanden
#!/usr/bin/perl -w
use strict;
use CGI;
use File::Slurp;
my $cgi = CGI->new;
print $cgi->header;
if ($cgi->request_method eq 'POST') {
doe iets;
print read_file 'bedankt.html';
} else {
print read_file 'aanmelden.html';
}
Flexibeler met templates
- Variabelen!
- Je kan een aap trainen voor de HTML
- Nette code
- Voorbeeld:
E-mailadres in bedankpagina:
<TMPL_VAR NAME=MAIL>
Voorbeeld
#!/usr/bin/perl -w
use strict;
use CGI;
use HTML::Template;
my $cgi = CGI->new;
print $cgi->header;
if ($cgi->request_method eq 'POST') {
doe iets;
my $template = HTML::Template->new(
filename => 'bedankt.html'
);
$template->param(mail => $cgi->param('mail'));
print $template->output
} else {
print read_file 'aanmelden.html';
}
Templating modules
- HTML::Template
- Template (Template Toolkit II)
- Text::Template
- Zelf maken:
s/\$(\w+)/$vars{$1}/g
- Mijn favoriet: Template Toolkit
Templates > Wizards
- Einde Templates
- Vragen?
- Hierna: Wizards, CGI::Application
Gebruikersinterface
- Belangrijker dan je code!
- Twee opties:
- 1. Grote pagina vol velden
- Makkelijk voor de programmeur
- Overweldigend voor de gebruiker
- 2. "Wizard"
- Moeilijk voor de programmeur
- Makkelijk voor de gebruiker
Wizards: voordelen
- Hapklare brokken
- Elke gebruiker snapt het
- Veel ruimte voor uitleg
Wizards: nadelen
- Veel werk
- Informatie rondsturen
- Geavanceerde gebruikers vinden het niks
CGI::Application
- Wizard-like
- Doet veel voor ons
- Gebruikt HTML::Template
Wizards > Sessies
- Einde Wizards
- Vragen?
- Hierna: Sessies
POST-problemen
- Steeds heen en weer sturen van data is inefficient
- Er kunnen dingen bijzitten die de user niet mag weten
- Browserbugs met encodings
Oplossing: sessies
- Gegevens blijven op de server
- Browser krijgt nog maar 1 waarde: sessie-id
Een sessie...
- heeft een uniek, gegenereerd id
- verloopt ooit
- verbergt werking, verhoogt veiligheid
- brengt waarden onder, meestal een simpele hash
Sessies zijn vooral handig voor:
- Authenticatie
- Uitloggen gaat nog steeds niet automatisch: http is sessieloos!
Sessie-id meegeven
- Verborgen formulierveld
- In elke URL
- In de query string (veel werk)
- In het pad ($ENV{PATH_INFO})
- Als cookie!
Modules
- Volop keuze
- Apache::Session
- CGI::Session
- PHP::Session
Sessies > Cookies
- Einde Sessies
- Vragen?
- Hierna: Cookies
Cookies
- Cookies worden bij elk request meegestuurd
- In principe veilig, maar MSIE zuigt
- CGI::Cookie maakt het makkelijk
Cookie headers
- Set-Cookie
Set-Cookie: session=15423; expires=Sun, 17-Jan-2005 19:14:07 GMT; path=/; domain=.example.com
Set-Cookie: login=juerd; expires=Sun, 17-Jan-2005 19:14:09 GMT; path=/; domain=.example.com
- Cookie
Cookie: session=15423; login=juerd
Cookie maken
use CGI::Cookie;
my $cookie = CGI::Cookie->new(
-name => 'session',
-value => $session_id,
-domain => '.example.com',
-path => '/',
-expires => '+3M' # 3 maanden
);
print $cgi->header(
-cookie => $cookie
);
Cookie uitlezen
use CGI::Cookie;
my %cookies = CGI::Cookie->fetch;
Cookies > mod_perl
- Einde Cookies
- Vragen?
- Hierna: mod_perl
mod_perl
- Perl in apache
- Perl kan communiceren met apache
- Instellingen wijzigen
- Handlers
- Supersnel met apache's kracht
- 20 tot 25 keer zo snel als CGI!
Eindeloze interpreter: nadelen
- Alsof je HTTP::Daemon gebruikt: alles is 1 programma
- Globals
- Module caching (eigenlijk andersom)
- Veel speciale variabelen worden gereset, gelukkig
Problemen voorkomen
use strict;
Stomme vraag
Wanneer mag je in mod_perl of een module use strict; overslaan?
Stomme vraag
Wanneer mag je in mod_perl of een module use strict; overslaan?
Als je die vraag niet zelf kunt beantwoorden:
NOOIT!
Waarom strict?
- Het helpt typfouten te vinden
- Het helpt andere potentieel stomme dingen te vinden
- MAAR: echt stomme dingen kunnen nog steeds
- Nadenken is dus niet optioneel
CGI scripts in mod_perl
- mod_perl is nooit bedoeld voor dit soort dingen
- Maar het kan wel
- Als je maar goed oplet
CGI scripts in mod_perl
- Makkelijkst: Apache::PerlRun
- Bijna helemaal compatible
- Ranzig programmeren min of meer mogelijk
- Met PerlRunOnce helemaal mogelijk, ten koste van snelheid
Overgaan op mod_perl
- CGI.pm is mod_perl-compatible
- mod_perl direct gebruiken is sneller
- Handige modules zijn soms te zwaar
- CGI
- CGI::Application
- HTML::Template
mod_perl is CGI compatible
... by default
- STDIN werkt
- STDOUT werkt
- %ENV werkt
- Vooral hierom is CGI.pm mod_perl compatible :)
$r
- Request object
- Sleutel naar alles
- Iedereen noemt 't $r
- Dus jij ook
- Net als $dbh
- Net als $sth
$r->isa('Apache')
CGI vs mod_perl
- STDIN vs $r->content
- STDOUT vs$r->headerspul, $r->print
- %ENV vs $r->foo en $r->header_in
mod_perl 'scripts'
- Apache::Registry-script
- Gebruikelijke naam: "mod_perl script"
- mod_perl scripts bestaan niet
Apache::Registry
- Compilet code naar 'n sub met eval
- Herlaadt automatisch bij verandering
- Doet verder verbazingwekkend weinig
Een eigen handler
- Herladen niet nodig?
- Eigen handler is niet moeilijker
- Wel sneller
- Geen stat() call bij elk request
Voorbeeld
package Apache::MijnHandler
use Apache::Constants qw(OK);
sub handler {
my $r = shift;
$r->send_http_header('text/plain');
$r->print('voorbeeld');
return OK;
}
1;
httpd.conf
PerlModule Apache::MijnHandler
bijvoorbeeld voor *.qhtml:
<Files *.qhtml>
PerlHandler Apache::MijnHandler
</Files>
bijvoorbeeld voor 1 lokatie (ter vervanging van script)
<Location /foo/bar>
PerlHandler Apache::MijnHandler
</Location>
Oppassen in mod_perl
- Globals
- Speciale variabelen: $`, $& en $' NOOIT gebruiken
- Ook geen modules die ze gebruiken
- Text::Balanced
- Parse::RecDescent
- re (use re 'debug' is niet lexical!)
- en meer...
Modules in mod_perl
- Herladen kan op veel manieren
- Niet elke module gaat er goed mee om!
- Vooral Class::DBI is een PITA
- Remedie: steeds apache restarten
- Beter: aparte ontwikkelserver!!
mod_perl alternatieven
- FastCGI
- PPerl (?)
- HTTP::Daemon
- Allemaal dezelfde problemen, behalve Apache-toegang
mod_perl > einde
- Einde mod_perl
- Vragen?
- Hierna: bijna niets
CPAN
- Het wiel bestaat al
- http://search.cpan.org/
- Bergen CGI/mod_perl modules
- Ook veel slechte: vraag naar ervaringen
Besproken modules
- Apache
- Apache::Constants
- Apache::PerlRun
- Apache::Registry
- Apache::Session
- CGI
- CGI::Application
- CGI::Cookie
- CGI::Session
- Class::DBI
- File::Slurp
- HTML::Template
- HTTP::Daemon
- LWP::UserAgent
- Parse::RecDescent
- PHP::Session
- Template
- Text::Balanced
- re
- strict