Autor: Ing. Dalibor èrßmek, email: dali@kumbal.vse.cz
RuΦenφ omezenΘ, zmφn∞nΘ v podtitulu, se vztahuje zejmΘna na t°i skuteΦnosti:
Klasick²m p°φkladem jsou poΦφtadla p°φstupu na WWW strßnky, gatewaye k r∙zn²m slovnφk∙m a databßzφm nebo t°eba obm∞≥ujφcφ se reklamy na WWW. Nßsledujφcφ odkazy vedou k ukßzkßm CGI skript∙ na serveru Kumbßl, kterΘ dokumentujφ n∞kterΘ ze zp∙sob∙ vyu₧itφ:
Je takΘ t°eba zajistit, aby CGI skript byl spustiteln² pro WWW server. V UnixovΘm prost°edφ b∞₧φ WWW server obvykle s minimßlnimi prßvy (nap°. u₧ivatel nobody), proto musφ mφt skript nastavenß prßva pro spouÜt∞nφ jak²mkoliv u₧ivatelem.
Abyste se vyhnuli zbyteΦnΘmu hledßnφ chyby ve skriptu, kdy₧ ve skuteΦnosti je Üpatn∞ nakonfigurovan² server, doporuΦuji nejd°φve zkusit zcela jednoduchΘ skripty - ideßln∞ nap°φklad nφ₧e uveden² v²pis prom∞nn²ch prost°edφ.
UrΦitou mo₧nostφ, jak spouÜt∞t skripty na serveru je takΘ SSI.
Chcete-li, aby CGI skript m∞l n∞jak² v²stup, musφ jej zapisovat na za°φzenφ STDOUT (standardnφ v²stup - Φili obvykle obrazovka). Nßsledujφcφ p°φklad ukazuje velmi jednoduch² skript, kter² vypisuje datum (p°φklady jsou psßny pro Bourne shell a jemu podobnΘ).
#!/bin/sh echo Content-type: text/plain echo datePrvnφ °ßdek urΦuje, jak se bude CGI skript interpretovat - konkrΘtn∞ °φkß, ₧e skript se mß spustit pomocφ shellu /bin/sh. Pokud je CGI skript napsan² v interpretovanΘm jazyce (shell, Perl), je nutnΘ tento °ßdek uvßd∞t. Pro kompilovanΘ programy pochopiteln∞ nemß smysl.
Nazvete-li tento skript nap°. date.cgi a budete se na n∞j odkazovat linkem http://mujserver/mojecesta/date.cgi, server skript vykonß a v²sledek v podob∞ aktußlnφho data zaÜle klintovi.
Drobnou zm∞nou hlaviΦky docφlφte mo₧nosti formßtovat v²stup pomocφ HTML.
#!/bin/sh echo Content-type: text/html echo echo "<HTML>" echo "<BODY>" echo "<H3>Aktußlnφ datum a cas</H3>" echo "<B>" date echo "</B>" echo "</BODY>" echo "</HTML>"HTML tagy se vypisujφ takΘ na standardnφ v²stup (povÜimnete si, ₧e v p°φkladu jsou uzav°eny do uvozovek, aby se zabrßnilo interpretaci specißlnφch znak∙ shellem).
JeÜt∞ poznßmka o standardnφch I/O za°φzenφch pro nep°φliÜ zkuÜenΘ programßtory. Se za°φzenφm STDIN a STDOUT se obvykle pracuje t∞mi nejjednoduÜφmi rutinami vstupu a v²stupu. V jazyve C jsou to nap°φklad printf a puts, v Pascalu pak writeln.
#!/bin/sh echo Content-type: text/html echo Pragma: no-cache echoTato hlaviΦka (p°esn∞ji pridan² druh² °ßdek) °φkß klientovi, ₧e dokument nemß uchovßvat ve svΘ pam∞ti cache, co₧ je u prom∞nliv²ch v²stup∙ z CGI skript∙ velmi d∙le₧itΘ.
Jinou mo₧nostφ je vrßtit klientovi stavov² k≤d:
#!/bin/sh echo Content-type: text/html echo Status: 200 OK echoPou₧itelnΘ k≤dy jsou zejmΘna:
Samoz°ejm∞, ₧e ne vÜechny prohlφ₧eΦe tyto k≤dy sprßvn∞ interpretujφ, ale v dneÜnφ dob∞ jich u₧ bude v∞tÜina.
To co se vypisuje v uveden²ch p°φpadech nestaΦφ jako kompletnφ hlaviΦka HTML dokumentu. Server v₧dy doplnφ dalÜφ hodnoty (nezadßte-li stavov² k≤d, server jej vlo₧φ). N∞kterΘ servery umo₧≥ujφ nakonfigurovat tak, ₧e v²stupy zadan²ch skript∙ ji₧ nejsou kontrolovßny (Non Parsed Headers), co₧ m∙₧e vΘst ke zv²Üenφ rychlosti odezvy. Musφte vÜak ve skriptu peΦliv∞ generovat kompletnφ hlaviΦku.
Pro mΘn∞ Φasto spouÜt∞nΘ CGI skripty se doporuΦuje pou₧φvat (v unixovΘm prost°edφ) jazyk PERL, kter² obsahuje mimo jinΘ velmi mocnΘ nßstroje pro prßci s textem. ╚asto spouÜt∞nΘ skripty je optimßlnφ vytvo°it v n∞jakΘm kompilovanΘm jazyce. C a C++ sice neposkytujφ p°i programovßnφ skriptu tak silnΘ prost°edky, to je vÜak vyvß₧eno efektivitou provßd∞nφ.
P°i troÜe snahy lze dnes na Internetu nalΘzt sluÜnΘ mno₧stvφ knihoven pro C a C++, kterΘ umo₧≥ujφ pohodlnΘ pou₧itφ t∞chto jazyk∙ pro psanφ CGI skript∙.
#!/bin/sh echo Content-type: text/plain echo echo "Ukßzka n∞kter²ch prom∞nn²ch:" echo "REMOTE_HOST = $REMOTE_HOST" echo "REMOTE_USER = $REMOTE_USER" echo "QUERY_STRING = $QUERY_STRING"P°ed°azenφ znaku "$" oznßmφ shellu, ₧e se jednß o prom∞nnou prost°edφ. Zavolßte-li tento skript, m∞li byste obdr₧et aktußlnφ hodnoty adresy klienta a jmΘno u₧ivatele (pokud mßte unixovΘho klienta).
#!/bin/sh echo Content-type: text/plain echo echo SERVER_SOFTWARE = $SERVER_SOFTWARE echo SERVER_NAME = $SERVER_NAME echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE echo SERVER_PROTOCOL = $SERVER_PROTOCOL echo SERVER_PORT = $SERVER_PORT echo REQUEST_METHOD = $REQUEST_METHOD echo HTTP_ACCEPT = "$HTTP_ACCEPT" echo PATH_INFO = "$PATH_INFO" echo PATH_TRANSLATED = "$PATH_TRANSLATED" echo SCRIPT_NAME = "$SCRIPT_NAME" echo QUERY_STRING = "$QUERY_STRING" echo REMOTE_HOST = $REMOTE_HOST echo REMOTE_ADDR = $REMOTE_ADDR echo REMOTE_USER = $REMOTE_USER echo AUTH_TYPE = $AUTH_TYPE echo CONTENT_TYPE = $CONTENT_TYPE echo CONTENT_LENGTH = $CONTENT_LENGTHA abychom okusili takΘ z jinΘho soudku, tak te∩ funkΦn∞ podobn² skript v PERLu.
#!/usr/bin/perl print "Content-type: text/html\n\n"; while (($key, $val) = each %ENV) { print "$key = $val \n"; }Jak poznajφ i ti, kte°φ PERL nikdy nevid∞li, vypisuje tento skript v cyklu vÜechny prom∞nnΘ prost°edφ, kterΘ jsou definovßny. FunkΦnφ variantu si m∙₧ete vyzkouÜet na serveru Kumbßl.
<HTML> <BODY> <FORM ACTION="/mojecesta/mujskript.cgi" METHOD="GET"> Zadejte prosφm jmΘno: <INPUT TYPE="text" NAME="jmΘno"> <BR> Zadejte prosφm p°φjmenφ: <INPUT TYPE="text" NAME="prijmeni"> <BR> <INPUT TYPE="submit" VALUE="odeslat"> </FORM> </BODY> </HTML>Hodnota ACTION u tagu formulß°e urΦuje skript, kter² se spustφ po odeslßnφ formulß°e. Hodnota METHOD urΦuje zp∙sob, jak²m budou data z formulß°e skriptu p°edßna. V naÜem p°φpad∞ (metoda GET) bude daty napln∞na prom∞nnß QUERY_STRING. Formßt prom∞nnΘ bude nßsledujφcφ: jmeno=zadanejmeno&prijmeni=zadaneprijmeni
Aby to bylo slo₧it∞jÜφ, jsou specißlnφ znaky vyskytujφcφ se v hodnotßch prom∞nn²ch zak≤dovßny nßsledujφcφm zp∙sobem:
Metoda GET mß jak je zvykem svΘ v²hody a nev²hody. V²hodou je, ₧e klient zasφlß data pro CGI skript v URL. Pro v²Üe uveden² formulß° se bude volat URL: /mojecesta/mujskript.cgi?jmeno=zadanejmeno&prijmeni=zadaneprijmeni. Vidφme, ₧e takov² skript lze volat i ruΦn∞ bez vypl≥ovßnφ formulß°e. ╪ekn∞me, ₧e bychom cht∞li vytvo°it skript, kter² by pracoval jako anglicko-Φesk² slovnφk. Vstup bychom mohli zabezpeΦit nap°φklad nßsledujφcφm formulß°em.
<HTML> <BODY> <FORM ACTION="/mojecesta/slovnik.cgi" METHOD="GET"> Zadejte prosφm hledanΘ slovo: <INPUT TYPE="text" NAME="slovo"> <BR> <INPUT TYPE="submit" VALUE="odeslat"> </FORM> </BODY> </HTML>Stejn∞ dob°e by ale tento slovnφk Üel pou₧φt p°φmo zßpisem: http://muj.server.cz/mojecesta/slovnik.cgi?slovo=meslovo.
To, ₧e se data p°edßvajφ jako souΦßst URL je vÜak zßrove≥ nev²hodou metody GET. Prohlφ₧eΦe toti₧ neumo₧≥ujφ neomezenou dΘlku URL a tak se metoda GET nehodφ pro v∞tÜφ objemy dat. NezanedbatelnΘ nenφ ani to, ₧e tyto °et∞zce se obvykle uschovßvajφ v logu nap°φklad na proxy serveru, pokud jej pou₧φvßte, co₧ znamenß snφ₧enφ ji₧ tak malΘho soukromφ.
Dlouho jsem na tomto mφst∞ sliboval p°φklad - te∩ tady koneΦn∞ je a abych zabil vφce much jednou ranou, tak je v jazyce C. Ve form∞, kterou vidφte, by jej m∞lo jφt bez problΘm∙ zkompilovat na Unixu. V jin²ch OS budou mo₧nß malinko jinΘ pot°ebnΘ hlaviΦkovΘ soubory a nahrazenφ funkce strcasecmp, kterß porovnßvß °et∞zce bez ohledu na velikost pφsmen.
Funkce p°φkladu:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char *method; char *data; /* vypis hlavicky */ puts("Content-type: text/plain\n"); /* zjisteni zpusobu zaslani dat */ method=getenv("REQUEST_METHOD"); /* kontrola definice promenne */ if (method==NULL) { puts("Chyba: neni definovana promenna REQUEST_METHOD!"); exit(1); } /* zkopirovani QUERY_STRINGu, je-li metoda GET */ if (!strcasecmp(method,"GET")) { data=strdup(getenv("QUERY_STRING")); } /* nacteni dat ze STDIN, je-li metoda POST */ if (!strcasecmp(method,"POST")) { int length; length=atoi(getenv("CONTENT_LENGTH")); data=malloc(length+1); /* cteni daneho poctu bytu */ fread(data,length,1,stdin); data[length]=0; } /* pokusny vypis datoveho retezce */ puts(data); /* uvolneni pameti a konec */ free(data); return(0); }
DalÜφ prvky formulß°e si uvedeme na p°φkladu:
Zdrojov² k≤d formulß°e si m∙₧ete prohlΘdnout, pokud zvolφte v klientovi zobrazenφ zdrojovΘho k≤du strßnky. K≤d CGI skriptu pro v²pis prom∞nn²ch je velmi jednoduch²:#!/bin/sh echo "Content-type: text/plain" echo echo "V²pis prom∞nn²ch formulß°e:" echo echo "$QUERY_STRING" | tr "&" "\n"Vidφme, ₧e pro tento skript je nutnΘ zadßvat data metodou GET. Filtr tr pak nahradφ vÜechny znaky ampersand znakem konce °ßdky. Zaslanß data m∙₧ete takΘ vypsat pomocφ skriptu uvedenΘho jako p°φklad u metody POST.
Vra¥me se jeÜt∞ jednou k polφΦk∙m fomulß°e v p°φkladu:
SSI umo₧≥ujφ nap°φklad vlo₧it do strßnky datum jejφ poslednφ ·pravy nebo
v²stup zadanΘho p°φkazu nebo CGI skriptu. Obecn² formßt vsuvky je
nßsledujφcφ:
<!--#p°φkaz parametr1=hodnota parametr2=hodnota ...
-->
Pou₧itelnΘ p°φkazy a jejich parametry: