CGI - Common Gateway Interface

teejuht
 
1.
sissejuhatus ja konkreetne näide C-s
2.
sama näide perlis
3.
mittegraafiline counter perlis
4.
pildi edastamine browserisse C CGI programmi vahendusel
 näited:
top10c.cgi (C-s), top10.c
  top10pl.cgi (perl'is), top10.pl
  piltc.cgi (C-s), pilt.c
5.
Keskkonnamuutujad, mida webserver seanisga seostab
 

sissejuhatus ja konkreetne näide C-s

Palju inimesi kasutab CGI-d ja mõned inimesed oskavad CGI programme teha. Mina viimaste hulka ei kuulu ja sellepärast on mul hea ja lihtne sellest jutustada :)

Mul oli selline probleem, et pidin panema ülesse kodulehekülje, kus oleks olemas üks pealkiri ekraani keskel ja all kümme nime, mis iga paari päeva järel muutusid. Natuke tülikas oleks olnud iga kord HTML-faili sisu muuta. Ja tõepoolest ega ei peagi. Saab ka teist moodi. Ning all järgneb seletus kuidas seda teha.

Olukord:
 
 
1.  interneti püsiühendusega masin, millel nimi on beryll.physic.ut.ee 
2.  kasutaja imre 
3.  ning fail /home/imre/public_html/linux/cgi.html (muide, see on käesolev fail) kus on sees link top10c.cgi  (vt. teejuhi viimased read!) 
<A HREF="/home/imre/public_html/linux/top10c.cgi">top10c.cgi</A>
4.  ning tavaline kümne reaga ASCII tekstifail /home/imre/public_html/linux/needkymme kus ma kajastatavaid nimesid muudan näiteks telneti terminalis joe'ga või lihtsalt kirjutan vana faili needkymme ftp-ga üle. 
5. 
ja loomulikult fail /home/imre/public_html/linux/top10c.cgi mis on "suure töö tegeija"
 
 

Niisiin, kui süsteem töötab on tarvis vaid muuta ühte ASCII tekstifaili needkymme ja hoobilt on internetis uued nimed üleval.

Kuida see siis käib?

Hakkame vaatama mis ime fail see top10c.cgi siis on, sest ilmselt on sellel failil keskne osa meie loos.

Kõigepealt on top10c.cgi programm (binary) ja vähemalt õigustega rwx --x --x, mis tähendab, et kõik saavad teda käivitada. Ta on C keeles kirjutatud ja ära kompileeritud programm.
 
 
Vahemärkusena olgu öeldud, et Apache'i web'i server on põhimõtteliselt nõus käivitama nii scripte (nt. perl, bash) kui binary'id 
(nt. C -s ärakompileeritud C source't). 
Minu puhul on Apache selliselt seatud, et failid mille laiend on .cgi käivitatakse (vaatamata nende asukohale kataloogistruktuuris) ning kõikide muude laienditega failide sisu (nt. html, txt, pl, c) antakse ASCII -na browserisse. 
Püüdke sellest vahest aru saada katsudes teejuhi vastavadi linke. Need lingid on tehtud ühe ja sama sisuga failidele, erinevus seineb perli puhul vaid nimes! C-puhul on top10c.cgi ikkagi kompileeritud programm mitte ümbernimetatud source. 

Siit tuleb väike segadus: muidu ma nimetan oma C - keele programmide sourse'd .c laiendiga (vastasel juhul gcc (cc) ei kompileeri neid); ning kompileeritud binary nimetan laiendiga .b Siis on kohe selge. Nt. 

cc -o programm.b programm.c 

loob programm.c -st binary programm.b 

Põhimõtteliselt võib olla binary'l mis tahes laiend või see üldse puududa. Tema käivitamiseks peab tal vaid olema käivitamisõigus 
(nt chmod 777 programm.b :) 

Ning siit tuleb paha asi, kuna Apache soovib CGI'de laiendiks ilmtingimata .cgi siis pean ma oma binary'd ümber nimetama, nt. 

mv programm.b programmc.cgi 

viimased viis sümbolit c.cgi tähendavad, et tegu on c keeles tehtud binary'ga mis on CGI-ks mõeldud. 

Etteruttavalt ütlen ära, et allpool kohtate faile nimega nt. 

programmpl.cgi 
programmsh.cgi 

need on olnud algselt vastavalt 

perli script programm.pl 
bash'i script programm.sh 

mida kasutatakse CGI'dena. (Muuseas, kes veel ei tea, siis scripte tavaliselt ei kompileerita). 

 

Kui teha link <A HREF="/home/imre/public_html/linux/top10c.cgi">top10c.cgi</A>, siis peale seal klõpsamist käivitatakse serveris beryll.physic.ut.ee programm top10c.cgi kusjuures see, mida see programm kirjutab töötamise käigus oma standard väljundisse st. terminalile suunatakse nüüd tollesse browseri raami või aknasse kus klõps tehti. Nt. kui top10c.cgi source's  oleks muude ridade seas

printf("Tere kallid vahvad<BR>");

siis ilmub ka browseri ekraanile/raami muu seas tekst "Tere kallid vahvad" ilma jutumärkideta. Siit peaks nüüd selge olema, et kavalus on selles, et browser mitte ei saa oma ihaldet HTML source ASCII failist, vaid see HTML source genereeritakse no."on the fly" Siinkohal meenud üks anekdoot, mille lõpp oli umbes selline, et "when the fly drops six cm then a ...  ". Aga hea.
 

Nüüd on asi ehk põhimõtteliselt klaar:
 
 
1.  järgides linki top10c.cgi C programm top10c.cgi käivitatakse 
2.  ta saadab browserile esimeses järjekorras spetsiaalse teatena ASCII teksti  "Content-type: text/html\n\n" ning seejarel teab browser, et järele hakab tulema HTML source. 
3.  seejärel loeb C- programm kümme nime failist needkymme  (see fail peab olema õigustega rw-r--r--) ja kirjutab need lihtsalt stdout'i pannes iga jargi <BR>, et browser teeks reavahetust. 
4.  hea toon on, et lõpuks annab programm keskonnale milles ta välja kutsuti return 0; 
antud juhul on järgmiseks mõistlik vajutada browseris back nuppu
 
 

Programm top10c.cgi source võiks välja näha nt. selline:

#include<stdio.h>
main()
{
1. FILE *f;
2. char rida[50];
3. f=fopen("/home/imre/linux/needkymme", "r");
4. printf("Content-type: text/html\n\n");
5. while(fscanf(f, "%[^\n]\n", rida)!=EOF)
6. printf("%s<BR>", rida);
7. fclose(f);
8. return 0;
}

Selgitus:
 
 
1.  f on pointer st. mälu aadresse omandav muutuja ja see on vajalik avatud failiga tegelemisel. Võiks ütelda, et ta on faili identifikaator. 
2.  rida[50] on 49 tähemarki ja stringi lõputunnust '\0' mahutav massiiv; kusjuures rida on char tüüpi pointer  aga rida[4] massiivi rida char tüüpi viies liige. Muuseas rida[0] on esimene liige. 
3.  faili needkymme avamine lugemiseks. 
4.  selline (või vahest ka muusugune) rida tuleb trükkida kõige enne, et browser teaks mis sorti inf tulema hakkab. text/html on HTML keelne tekst. 
5.  while(tingimus) järel olev lause, antud juhul stringi rida trükkimine toimub seni kuni tingimus pole võrdne nulliga. See on nii seni kuni End Of File pole vastas. fscanf funktsioon loeb faili f rida haaval ja kohates faili loõppu saab saab fsanf vordseks EOF -ga. Seda viimast kontrollitaksegi iga ringi ajal. "%[^\n]\n", rida loeb jarjest kuni esimese reavahetuseni ning täidab stringi rida loetuga ja järgmise ringi ajal läheb sama moodi edasi. 
7.  faili mille identifikaator on f sulgemine. 
8.  tagastatakse keskkonnale kust programm välja kutsuti väärtus 0, mis tähendab, et programm lõpetas tegevuse normaalselt. 
 
 

Ning needkymme selline

Imre Oolberg
Vladimir Lenin
Kustas Kikerpuu
Valeri Ljontjev
Andres Kuura
Urmas Persidski
Vladislav Korzets
Bill Clintonn
Gennadi Zuganov
Valentin Utkin Pondarjev

Ja main_linux.html põhimõtteliselt nii

<HTML>
<BODY>
<CENTER>
See on koige parem site maailmas, bookmark it now!
</CENTER>
Siin all on meie lingikogu.
<A HREF="/home/imre/public_html/linux/top10c.cgi">23. mail 1998 kymme esimesena pahetulnud poeglapse nime</A>
</BODY>
</HTML>

Lisaks.

Selle asja juures jätab soovida see, et needkymnesse saab teha muutusi vaid beryll.physic.ut.ee -sse sisse logides, aga mitte browseri vahendusel. Ning top10c.cgi on natuke liiga ilma kontrollita programm selles mõttes, et määratlemata on, mis ta peaks tegema, kui näiteks mingil põhjusel ta ei saa avada faili needkymme. Ja peale kõige nimetatu ei suuda ta saata korralikult õäöü tähti.

Kõige parem on kogu seda asja uurida, kui osta poest PC, tõmmata www.slackware.org -ist soft ja see ara installida. root'u  alt sisse logida, WWW serveris Apach ära määrata kus on kataloogid ja siis hakata pihta toodud näitega. Apach'i omadused on peamiselt maaratud kolme failiga:

httpd.conf, srm.conf, access.conf.

Seal saab ara määrata kus kataloogis asuvad käivitatavad programmid (mul on need kõik .cgi lõpulised) ja see kuidas ligi pääseda userite kodukatele (mul /beryll.physic.ut.ee/~imre).

Milles tuleb kindasti veenduda on see, et kui püüda html faili cgi-dele viitavate linkidega mängida, siis peab teil browser näitama lingiga lehte läbi Apachw'i (st. http:// etc.) mitte kui üksikut html faili (st. file://) !
 
sama asi perlis

Kuna nii populaaarne või isegi enam kui C on kirjutada CGI programme perlis siis toon ülaltoodud programmiga ekvivalentse ära ka perli scriptis (põhimõtteliselt võib CGI rakendusi kirjutada milles tahes nt. bash shellis)

top10pl.cgi

#!/usr/bin/perl
open (a, '/home/imre/public_html/needkymme');
@koik=<a>;
close (a);
print "Content-type: text/html\n\n";
foreach $rida(@koik)
{
print "$rida<BR>";
}

No perli script on lühem kui C source kuigi kummagi juures pole tehtud erilisi pingutusi kompaktsuse saavutamisel. Perl ongi tegelikult mõeldud sellist laadi ülessannete täitmiseks.

mittegraafiline counter perlis

Counteri idee seisneb selles, et peale järjekordset lehe laadimist liidetakse mingis failis olevale arvule 1 juurde.
Kui mina oma homesite'i teeks avalehe index.html kus pole peal graafilisi elemente, siis oleks raske pidada arvet mitu korda on teda külastatud. Aga ega avaleht ei pruugi olla tingimata index.html. Minul on see index.cgi ning Apache'st on asi nii seatud, et kui teha http://beryll.pyhsic.ut.ee/~imre/, siis esmalt hakkab Apache otsima faili

/home/imre/public_html/index.html

ja kui sellist pole, siis faili

/home/imre/public_html/index.cgi

mille ta ka leiab.

index.cgi on programm (perli script tegelikult) millel on vaid kaks ülesannet:

1. saata browserisse nö. index.html'li tavaliselt käiv tekst st. avalehe sisu
2. avada loenduri fail (/home/imre/public_html/linux/loe) liita sealolevale arvule 1 juurde ja sulgeda seejärel
3. Muu HTML koodi seas kasutada muutuja $count väärtust sobival kohal.

Ise näeb ta välja selline:

#!/usr/bin/perl
print "Content-type: text/html\n\n";

open (a, '</home/imre/public_html/linux/loe');
$count=<a>;
close (a);
open (a, '>/home/imre/public_html/linux/loe');
$count=$count + 1;
print a "$count";
close (a);
#print "$count\n";
print <<lopp;

<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (X11; I; Linux 2.0.30 i586) [Netscape]">
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFE9CC" LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000">
<B><FONT COLOR="#990000">Realistlikud materjaid</FONT></B><B><FONT COLOR="#990000"></FONT></B>

<P><FONT COLOR="#000000">Tere,</FONT>
<BR><FONT COLOR="#000000">asja selguse ja h&auml;bi v&otilde;tmise huvides
olgu &ouml;eldud ,et need lehek&uuml;ljed on koostanud Imre Oolberg. Kasutatud
on</FONT>
<BR><FONT COLOR="#000000">mitmeid raamatuid ja teisi allikaid:</FONT>
<BR><FONT COLOR="#000000">kuulatud liste arvutid.vestlud\@ut.ee ja EUPS\@ut.ee
ning suheldud mitmete inimestega; lootuses teistele mitte liiga teha avaldaksin
oma t&auml;nud ja m&auml;rgiksin &auml;ra:</FONT><FONT COLOR="#000000"></FONT>

<P><FONT COLOR="#000000">Meelis Roos</FONT>
<BR><FONT COLOR="#000000">Jaan Oras</FONT>
<BR><FONT COLOR="#000000">Tanel Niine</FONT>
<BR><FONT COLOR="#000000">Erik Saarts</FONT><FONT COLOR="#000000"></FONT>

<P><FONT COLOR="#000000">Keskendutud on 12 klassi f&uuml;&uuml;sika eksami
ettevalmistamisele ja arvuti kasutamisele</FONT><FONT COLOR="#000000"></FONT>

<P><FONT COLOR="#000000">1. <A HREF=main_linux.html>OS Linux</A></FONT>
<BR><FONT COLOR="#000000">2. F&uuml;&uuml;sika</FONT><FONT COLOR="#000000"></FONT>

<P><FONT COLOR="#000000">Te olete $count. siia sattunu</FONT>

<BR><FONT COLOR="#000000"></FONT>&nbsp;
</BODY>
</HTML>
lopp
 

No see HTML kood ei pretendeeri eeskujulikuks; oluline, et lopp taha lõpus saab reavahetus! Ilmselt on Apache seadmine suurem kust kui selle konkreetse CGI kirjutamine :)
 

pildi edastamine browserisse C CGI programmi vahendusel

Siin on tarvis browserile saata need baidid millest pilt koosneb õiges järjekorras ning eelnevalt ütelda, et pilt on nt. jpg; kui ta muidugi on.
Olemas on pilt nimega:
/home/imre/public_html/linux/pilt.gif -kõpsake talle peale, et lihtsalt näha (no CGI involved!)
 

Teeme ära C-keeles:

/home/imre/public_html/linux/piltc.cgi - klõpsake ning käivitatakse alltoodud source'ele vastav binary.

Jah, Jah, pealtnäha pole vahet midagi, aga põhimõtteliselt ...
 

#include<stdio.h>
main()
{
int i;
1. FILE *fpjpg;
2. fpjpg=fopen("/home/html/outout/pilt.gif", "r");
3. fprintf(stdout, "Content-type: image/jpeg\n\n");
4. fflush(stdout);
5. while(fscanf(fpjpg, "%c", &i)!=EOF)
6. fprintf(stdout,"%c", i);
7. fflush(stdout);
8. fclose(fpjpg);
}
 
 
1. deklareeritakse faili identifikaator (poinet tegelikult)
2. seostatakse identifikaatoriga fail, avatakse lugemiseks
3. trükitakse väljundisse olulised sõnad, misjärel browser tead, et järgmisena tuleb pilt (gif, jpg)
4. mõnikord pole seda vaja, aga paha ta ei tee. Nimelt linux kirjutakse ise eelmsel real printf 'itud asja välja siis kui tal aega on aga fflush'iga forseerime teda tegema seda kohe
5. kuni faili lõpuni loetakse muutuja i kohale bait ning
6. antakse siis stdout'i ehk browserisse
7. teeme ikka fflush'i
8. sulgeme failie 
 

Praegu me panime piltc.cgi lihtsalt lingi alla:

<A HREF="/home/imre/public_html/linux/piltc.cgi">/home/imre/public_html/linux/piltc.cgi</A>

aga võib ka pildi asemele panna (siis ta käivitatakse pidi laadimisel)

<IMG SRC="/home/imre/public_html/linux/piltc.cgi">

Graafilised counterid mängivad just selle peale. Kui browser sättida nii, et pilte ei laeta, siis graafiline counter ei loe ka.
Graafilise counter'i juures on siiski see imetlusväärne asi, et browserisse saadetav gif genereeritakse iga kord vastavalt kuskil failis olevale külastuskordade arvule. See on juba keerulisem :)
 
 5. Keskkonnamuutujad mida webserver seansiga seostab

Nagu ma avalehel tunnistasin, siis ma pean tagasisidet oma lehe külastatavuse kohta kontrollides teatud keskonnamuutujaid. See toimub siis, kui te minu site'i esilehe endale browserisse laadite. Eriti loeb siin see, et ka taustapilt laaditaks. Nimelt, esilehe source's on selline rida:

<BODY TEXT="#000000" LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000"
BACKGROUND="http://kopka.tkg.tartu.ee/cgi-bin/maria.b" NOSAVE>

Muide, tavaliselt näeks see rida välja selline:

<BODY TEXT="#000000" LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000"
BACKGROUND="maria.gif" NOSAVE>

Niisiis, kui laete esilehte koos piltidega, siis laetakse backgroundiks mitte pilt ise vaid hoopiks käivitatakse teises webiserveris programm maria.b. Too programm annab teie browserile baidid nii nagu annaks maria.gif aga ta teeb ka muud veel. Ta asub sellepärast teises webiserveris kuna suurtes kohtades nagu Tartu Ülikool (www.ut.ee) ei anta lihtkasutajatele õigusi nn. CGI -sid teha.

Nimelt, ta asendab failis 'kopka.tkg.tartu.ee:/home/cgi-bin/mitujuba' olemasoleva arvu ühe võrra suuremaga; ja samas lisab mainitud keskonnamuutujad teise faili: 'kes'.

Vaatame siis milline see programm maria.b'le vastav source välja näeb:
 

 1. #include<stdio.h>
 2. #include<stdlib.h>
 3. main()
 4. {
 5. int j, i, c;
 6. FILE *fpgif, *mitu, *kes;
 7.
 8. fpgif=fopen("/home/cgi-bin/maria.gif", "r");
 9. fprintf(stdout, "Content-type: image/jpeg\n\n");
10. fflush(stdout);
11. while(fscanf(fpgif, "%c", &i)!=EOF)
12.     fprintf(stdout,"%c", i);
13. fclose(fpgif);
14.
15. mitu=fopen("/home/cgi-bin/mitujuba", "r");
16. fscanf(mitu, "%d", &c);
17. fclose(mitu);
18.
19. c++;
20.
21. mitu=fopen("/home/cgi-bin/mitujuba", "w");
22. fprintf(mitu, "%d\n", c);
23. fclose(mitu);
24.
25. kes=fopen("/home/cgi-bin/kes", "a");
26. fprintf(kes, "\n\n\n%d\n", c);
27. for (j=0; environ[j] != NULL; ++j)
28. fprintf(kes, "%s\n", environ[j]);
29. fclose(kes);
30.
31. fflush(stdout);
32. }
 

Selgitused:

8. avame pildi faili lugemiseks
9. trükime stanardväljundisse mis on antud juhul teie browser kohustusliku pealdise (et browser teaks mida baidid sisuliselt kajastavad)
10. fflush(stdout); on hea teha; see puhastab puhvrid koheselt -  vahest on nii, et server jääb ootama enda meelest sobivat hetke
11. 12. saadame pildile vastavad baidid browserisse
13. sulgeme faili

15. 16.avame faili mitujuba lugemiseks ja saame teada mitmes oli viimane järjekorra number
17. sulgeme faili

19. suurendame muutujat

21. avame uuest faili ja nüüd kirjutamiseks (st. ülekirjutamiseks)
22. kirjutame ühe võrra suurendatud järjekorranumbri
23. sulgeme

25. avame faili kes lisamiseks
26. - 28.kirutame meist sõltumatuslt eksisteeriva massiivi environ kõik liimed faili
29. sulgeme faili kes

31. igaks juhuks fflush()
 

Oluline on anda failidele sobivad õigused:

kopka:/home/cgi-bin$ ls -l
total 49
-rwxrwxrwx   1 root     root        17701 Oct  2 08:26 kes*
-rwxr-xr-x   1 root     root        25517 Oct  1 19:11 maria.b*
-rw-r--r--   1 imre     users         653 Oct  1 19:11 maria.c
-rw-r--r--   1 imre     users         182 Oct  1 10:23 maria.gif
-rwxrwxrwx   1 root     root            3 Oct  2 08:26 mitujuba*

Faili mitujuba sisu pole ehk liiga raske ette kujutada - seal on kirjas üks täisärv.

Toome huvi pärast ära environ[] -mentiga kättesaadavad suurused (23 ei kuulu nende hulka):

23
HTTP_CONNECTION=Keep-Alive
HTTP_USER_AGENT=Mozilla/4.05 [en] (X11; I; Linux 2.0.34 i586)
HTTP_HOST=kopka.tkg.tartu.ee
HTTP_ACCEPT=image/gif, image/x-xbitmap, image/jpeg, image/pjpeg image/png
HTTP_ACCEPT_LANGUAGE=en
HTTP_ACCEPT_CHARSET=iso-8859-1,*,utf-8
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/samba/bin:/u
sr/X11R6/bin:/usr/andrew/bin:/usr/openwin/bin:.:/usr/games:/usr/local/src/teTeX/bin/i586-
linux:/usr/local/samba/bin:/usr/X11R6/bin:/usr/andrew/bin:/usr/openwin/bin:.:/usr/games:/
usr/local/src/teTeX/bin/i586-linux
SERVER_SOFTWARE=Apache/1.2.6
SERVER_NAME=kopka.tkg.tartu.ee
SERVER_PORT=80
REMOTE_HOST=s12.loss.eenet.ee
REMOTE_ADDR=193.40.28.112
DOCUMENT_ROOT=/home/html
[email protected]
SCRIPT_FILENAME=/home/cgi-bin/maria.b
REMOTE_PORT=1025
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.0
REQUEST_METHOD=GET
QUERY_STRING=
REQUEST_URI=/cgi-bin/maria.b
SCRIPT_NAME=/cgi-bin/maria.b

Rõhutatud read käivad külastaja kohta. Konkreetselt on tegemist minu endaga kui ma Helistan oma ISP-sse ja browsin seejärel www.ut.ee/~starylle't.
 
 

tere