Perl en CGI scripts 1Op deze pagina:
Op de vervolgpagina En daarna: Ik heb deze pagina gesplitst: Gewone webpagina's (.html files) zijn nogal statisch. Wat wordt weergegeven is wat er in staat, en dat is wat er van tevoren in is gezet met bijvoorbeeld een html-editor. Maar, soms wil je de inhoud van een webpagina meer dynamisch laten zijn; bijvoorbeeld de inhoud aanpassen aan de omstandigheden. Een voorbeeld hiervan in mijn zoek-pagina: deze pagina wordt op het moment van aanvraag gemaakt, en geeft dan de resultaten van een zoek-opdracht weer. Andere voorbeelden zijn pagina's die databases raadplegen, die bezoekersstatistieken bijhouden, feedback in een file op de server opslaat (zie onderaan deze pagina), en zo voort. Dit gaat niet zo maar met alleen html, of zelfs java(script). Je moet voor iets dergelijks echt een 'programma' op de web-server laten draaien, die bijvoorbeeld voor de search de daar aanwezige set van html pagina's afzoekt op de gezochte termen. Een manier op dit te doen is met zogeheten CGI scripts, stukjes programma die op verzoek van een gebruiker draaien op de web server. CGI scripts zijn dus anders dan bijvoorbeeld Java scripts: Java scripts draaien op de computer van de gebruiker, en niet op de web server. CGI staat voor 'Common Gateway Interface', en is een standaard manier om gegevens van een gebruiker (dus iemand die een web-page bekijkt met zijn browser) door te geven naar een programma (script) op de server, dus net de andere kant op waarin html pagina's gestuurd worden. Bij de genoemde zoekpagina is dit bijvoorbeeld het woord waarop gezocht moet worden. Perl is vanouds vaak gebruikt voor het maken van deze 'CGI scripts'. Een voorbeeld van een Perl CGI script is de actie onder de zoek-knop op mijn web-pagina's: via het invulformuliertje voor de zoekterm wordt dit woord doorgegeven naar dit CGI script, deze gaat vervolgens mijn webpagina's afzoeken op dat woord, en maakt een HTML-pagina waar de zoekresultaten op te vinden zijn. Ps: een andere veel gebruikte taal voor dit doel is PHP. Deze pagina legt uit hoe je simpele CGI scripts kunt maken met behulp van Perl. Uitgebreidere documentatie van de CGI module is te vinden op onder ander de site van ActiveState, of op CPAN. Ook de Perl-CGI FAQ geeft natuurlijk inzicht. Ps: ik gebruik gewoon de CGI functies, en niet de object-georiënteerde stijl, die ook mogelijk is. Een simpel CGI scriptEen van de simpelste CGI scripts: het befaamde afdrukken van 'hello
world' in het scherm van de internet browser (Internet Explorer, FireFox, of
welk programma dan ook) van de kijkende persoon. De kijker ziet verder niet dat
dit door een CGI script wordt verzorgt, die ziet alleen het resultaat: een
scherm met daarop de tekst ' #!/usr/bin/perl -T De uitleg, regel voor regel, met de gegenereerde output:
De gebruikte CGI functies kunnen nog veel meer, bijvoorbeeld door het meegeven van extra parameters in de headers, maar voor dit simpele voorbeeld ga ik daar niet op in (later, met complexere voorbeelden). Voor meer uitleg, zie de documentatie van de CGI module in Perl. Om dit werkend te krijgen moet dit script nu worden ge-upload naar de server
waarop je je web-pagina's hebt staan (toch wel van tevoren gecheckt of je
provider wel Perl ondersteunt? Is niet altijd het geval). Zoek eerst op in
welke directory de cgi scripts horen te staan, dit is per provider verschillend
(bij mij in de directory ' En nu wat moeilijkerWaarschuwing: In dit voorbeeld wordt de waarde van het argument niet gecheckt voordat het in de HTML-pagina wordt afgedrukt... Dit geeft de gebruiker de kans het script te misbruiken, door bijvoorbeeld een slim gecodeerd Javascript mee te geven (code injection)! Altijd dus checken of wat de gebruiker meegeeft wel met goede bedoelingen is; zie verderop bij 'Input checken!'. Dit was nogal statisch. Hoe krijg je nu bijvoorbeeld input van de gebruiker
in het script, daar was CGI toch voor? Dit kan bijvoorbeeld via de link naar de
pagina, of via een invulformulier. Het script ziet er in beide gevallen
hetzelfde uit: zie dit voorbeeld genaamd ' print
header(),
# create the HTTP header Er is nu een regel bijgekomen, die de meegegeven parameter in de link
ophalen en afdrukken. Met behulp van de functie Hello, World. Wat misschien opviel is hoe het argument werd meegegeven in de link: sommige
tekens mogen niet in een link staan (zoals spaties), deze worden vervangen door
hun hexadecimale code ( Wel is dit natuurlijk nogal lastig voor de gebruiker om zelf zo een link te moeten maken: hoe gaat dit nu netjes en makkelijk, en zonder deze problemen van verboden tekens, via een net invulveldje? Hiervoor moet in je webpagina een html-'form' zijn opgenomen als hieronder (druk gerust op de knop om het te testen, en let op de link van de verschijnende pagina): Voor de duidelijkheid de bijhorende html-code waarmee dit veld werd gemaakt (normaal zie je deze code niet, wordt door je html-editor onder water aangemaakt als je een form maakt): <form
action="http://www.keesmoerman.nl/cgi/argument.cgi" method="get"> Dit staat dus (zoals bij mij het zoek-scherm invulveld) op je normale html-pagina. Bij het drukken op de verzend-knop wordt de waarde van het invulveldje netjes aan een link (opgegeven in de action parameter van de form) geplakt, en doorgestuurd naar de server, waar het CGI-script wordt aangeroepen op de eerder uitgelegde manier. Er is overigens nog een andere manier om parameters mee te geven, dit gaat
via ' Input checken!Zoals al aangegeven met de waarschuwing aan het begin van dit hoofdstuk: check altijd de waardes die de gebruiker invult. Welke check je doet is afhankelijk van wat je met de data gaat doen. In dit geval wil ik voorkomen dat er (bedoeld of onbedoeld) HTML-code in gestopt wordt, die vervolgens in de antwoordpagina wordt ingevoegd. Hier kan dan bijvoorbeeld een Java-script verstopt zitten, met mogelijk kwalijke bedoelingen! In HTML heeft een aantal tekens speciale bedoelingen (bijvoorbeeld de
' Een andere check zou kunnen zijn of de data langer is dan 100 tekens: dan
komt het niet meer uit het formulier (dat de lengte tot 100 tekens beperkt
heeft met Mocht je meer met de input data doen, dan kunnen strengere checks nodig zijn. Voorkom dat mensen commando's kunnen verstoppen (niet bijvoorbeeld je disk kunnen wissen). Beter te veel checken (bv welke tekens mogen er in voor komen?) dan te weinig! Lees ook de opmerkingen over security in deel 2! Met dank aan Mathias, die me hier met een prachtig voorbeeld op gewezen heeft! Nog meer gegevensNaast de parameters (op te vragen met de
Zo zijn er nog meer variabelen om meer te
weten van je omgeving. Een script waar een aantal van deze aanroepen (en nog
wat andere zaken, zoals cookies; zie deel 2)
worden gedemonstreerd is Foutzoeken en debuggenVaak is het lastig om cgi-scripts te debuggen. Ze draaien normaal op de server, waar je niet direct bij kan, en ook niet altijd de foutmeldingen kan bekijken. Hier verschillende hints om foutzoeken in cgi-scripts te vereenvoudigen. Command-line debuggenOm te beginnen: probeer het toch eens gewoon als Perl script op je eigen computer te draaien. De 'get'-methode voor CGI parameter overdracht kan bij de cgi-module namelijk ook nagespeeld worden met command-line parameters, bijvoorbeeld als (bij meerdere argumenten scheiden met spaties). Ook kan je op deze manier de Perl debugger gebruiken. Aanroepvoorbeeld: C:\> perl c:\myscripts\argument.cgi argument=Ook%20hallo Wel moet je even checken wat je nog meer 'na moet bouwen' van je
serveromgeving, bijvoorbeeld bepaalde files, of het zetten van extra cgi-info
in environment-variables (b.v. Foutmeldingen op de server te zien krijgenEen ander veel voorkomend probleem is dat je niet bij de error log op de
server kan komen, en dus niet de door Perl gegenereerde foutmeldingen kan zien.
Een oplossing die daarvoor door de cgi module ondersteund wordt is het
redirecten van de foutmeldingen naar de html output, dus naar je gegenereerde
web pagina. Neem daarvoor de volgende code op in het begin van je code (in
plaats van use CGI::Carp qw(fatalsToBrowser warningsToBrowser); Werkt overigens niet voor alle situaties: bijvoorbeeld fouten met de -T optie (zie eerder op deze pagina) vinden mogelijk te vroeg of op een te hoog niveau plaats om nog hierdoor opgevangen te kunnen worden. Fouten in de aanroep van een CGI scriptOok kan het zijn dat de 'aanroep' van de cgi fout gaat: hier kan je het beste zo vroeg mogelijk in je script op testen, bijvoorbeeld met de volgende code: my $error = cgi_error(); Nette foutmeldingenOm bij later nog zelf gevonden foutsituaties (b.v. kan file niet openen)
nette foutmeldingen te krijgen definieer ik een alternatief voor de
' open FILE, "myfilename.txt" || die_html("Kan file 'myfilename.txt' niet openen"); De routine sub die_html # fatal error: generate HTML error
message Diverse handige functiesNog een handige functie: sommige tekens mogen niet zo maar in HTML strings
voorkomen (zo worden de tekens ' $escaped_string = escapeHTML("unescaped string: <test>"); Verder naar deel 2. |
op mijn site |