teejuht
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
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
need on olnud algselt vastavalt perli script programm.pl
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äbi võtmise huvides
olgu öeldud ,et need
lehekü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änud ja märgiksin
ä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üü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üüsika</FONT><FONT COLOR="#000000"></FONT>
<P><FONT COLOR="#000000">Te olete $count. siia sattunu</FONT>
<BR><FONT COLOR="#000000"></FONT>
</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