Om deze te kunnen gebruiken wou ik een toegang hebben via een locale server alsmede via een webserver .
De locale server is een server geschreven in PEU . De webserver is Lampp(Ubuntu/Mint) of Hiawathi(Puppy) beiden maken gebruikt van CGI interface . Het onderscheid tussen CGI/localeserver wordt gemaakt door een conditionele vertalingsconstante CGI_BIN . Overigens Lampp nog USBserver werken correct in MSwindows daar STDIN niet gekoppeld wordt aan get(0) .
De aanroep is URL?opdracht . (bedenk bij de locale server dat url/opdracht iets niet werkends geeft) De opdracht zelf mag weer een ?subopdracht hebben dus iets als URL?opdracht?subopdracht . Bevreemdend is dat de CGI een leeg commando verschillend weergeeft .
De aanroep via een webbrowser kan tot problemen leiden .
De test aanroep cTESTMENU (of nph-cTESTMENU) roept een shebang aan #!TESTMENU -DCGI_BIN
.
Deze TESTMENU welke zelf een shebang #!../eu/peu TESTMENU.EXW
aanroep .
Dit blijkt niet overal te werken , metname de tweede aanroep wordt niet uitgevoerd (freehostingcloud.com) .
Dit heeft temaken met hoe de shebang de parameters (argv) afbeeld .
Werkt de aanroep niet dan zet in het hoofdprogramma "with define CGI_BIN
" .
De CGI kent twee optie's standaard is de header parsing . Dat houd in dat je geen "HTTP1.1 <status>" mag oversturen maar dit met "status: <status>" moet doen . En dat je de XMLHTTP aanroepen moet voorzien van "content-type: text/plain\n\n" . (Kennelijk vist de CGI dit er weeruit , want kan in XMLHTTP niet worden gebruikt) Dit integenstelling tot de non-parsing-header methode . Deze wordt geactiveerd door toevoeging van nph- aan de naam . Nu moet je zelf de headers maken inclusief "HTTP1.1 <status>" . En mag je geen toevoeging doen aan de XMLHTTP antwoord .
Dit geeft nog een raar verschijnsel in CGI . N.l. dat de header's geen "\r\n" mogen bevatten maar alleen "\n" . Dit in tegenstelling van de locale server welke altijd een "\r\n" moet hebben .
Cookies .
De gelezen cookies staan in de variable COOKIES (<naam>=<waarde>[;<naam>=<value>]..).
De tezetten cookies in setcookie
en de te verwijderen cookies in rescookie
.
Het afsluiten verwijderd de cookie uit de browser , bij afsluiten van de browser zijn ze tevens verwijderd .
Je mag de XMLHTTP response voorzien van het zetten van cookie's .
Dit door toe tevoegen van <naam>=<waarde>[;<naam>=<value>]..|| (|| is het scheidings teken )
Alle FORM's worden verstuurd met POST met default url-encoding . De data wordt ge-encodeerd weggeschreven in het bestand post.cmd . Later wordt dit geschreven in de data string POSTCMD om de server de mogelijkheid te geven meerdere gebruiker gelijk tijdig te bedienen .
Hoofd programma structuur
a) declaraties wat geladen moet worden voor CGI_BIN of geladen moet worden voor geen CGI_BIN (local server) laden wat voor alles gemeenschappenlijk is . | ifdef CGI_BIN putenv("PEUINC=../eu/include") include FCGI.E elsedef include ../teams/FSERVER.E enddef sequence respbuf,respcmd,header="" --worden gebruikt in decoder() procedure response_to() write_client("<pre>"&respbuf&"</pre>") -- continue cmdbuf={} end procedure |
b) mainprogram Voor CGI_BIN haal opdracht van browser voer_opdracht_uit opdracht is juist : deeindig overdracht opdracht onjuist : beeindig session Voor geen CGI_BIN (local server) loop until forever haal opdracht van browser voer_opdracht_uit opdracht is juist : deeindig overdracht opdracht onjuist : beeindig session ; exit loop end loop | -- main program ifdef CGI_BIN if command_from_client() then if nph_flag then header="" else header="Content-type: text/plain\n\n" end if if command_decoder() then close_page() -- close van new_page else quitserver() end if end if elsedef netserver()-- init sever while 1 do -- run server until close session command_from_client() if command_decoder() then close_page() -- close van new_page else quitserver() exit end if end while enddef |
c) voer_opdracht_uit blijft opdrachten in cmd uitvoeren zoals deze niet leeg is . loop cmd!=null sloop opdracht in cmd en buf /* XMLHTTP antwoorden */ case _cmd of _iets: do_iets ; cmd=null else case error onbekende opdracht ; cmd=null end case /* HTTP antwoord */ case cmd of iets: do_iets ; cmd=null QUIT: "sluit server" ; return false else case error onbekende opdracht ; cmd=null end case end loop return true | function command_decoder() constant onbekend="<center><h1>Onbekende opdracht</h1><br><h2>Commando = " integer index while length(cmdbuf) do -- internal command heeft de structuur opdracht?parameters index=find('?',cmdbuf) if index then respcmd=cmdbuf[1..index-1] respbuf=cmdbuf[index+1..] else respcmd=cmdbuf respbuf="" end if -- een XMLHTTPreg welke beantwoord wordt met HTTP blijkt te worden genegeerd . -- bedenk dat de namen voor XMLHTTP en HTTP altijd verschilend zijn . if find('_',respcmd) then --(XMLHTTPreq) deze moeten allen worden benoemd ! if respcmd="_n" then write_client(header&"error| ") -- do nothing [X] venster sluiten , -- maakt formfield leeg write_client(" ") cmdbuf={} elsif respcmd="_ta" then write_client(header&"error| ") -- formulier ingevult inschrijfing() cmdbuf={} else respbuf=onbekend&respcmd&"</h2></center>" write_client(header&"foo|") response_to() cmdbuf={}--unknown command end if else --(HTTPreq) geen XMLHTTPreq dan moet het behandeld worden als HTTPreq if respcmd="4" or lower(respcmd)="quit" then return 0 --quit server elsif respcmd="index" -- default opdracht then -- openings pagina open_inschrijving() cmdbuf={} else -- openings pagina open_inschrijving() cmdbuf={} end if end if end while return 1 end function |
Het idee hierachter is dat er een do_iets
zouden kunnen zijn die zelf een opdracht kan geven .
Stel je hebt een routine gemaakt waarmee je een bestand kunt selecteren .
Deze geeft een antwoord terug van kies a) een andere folder of b) het bestand waar je om vraagt .
Ingeval van a) geef je de routine nog maar een keer aan de uitvoer .
Maar wat moet je met b) doen ? Nu kan b) een ander commando aan cmd
geven om uittevoeren .
Je hebt dus een routine selectfolder
en een routine die het antwoord vanuit de selectfolder
moet uitvoeren .
Dit kan door de selectfolder(opdracht)
(een vorm van callback) . Deze opdracht moet bewaard worden om later
door antwoord op selectfolder te kunnen worden uitgevoerd .
In local server mode is dit geen probleem daar deze het programma niet verlaat en dus alle tussen resultaten
wel bewaard .
In CGI mode is na de verwerking het programma weg en dus ook te resultaten .
We zullen dus de gewenste tussen resultaten ergens moeten opslaan . In een bestand of in een cookie .
Nu kan het antwoord op selectfolder
weten wat het moet gaan doen als een bestand is geseleteerd .
Hoe je dat uitvoerd is maar wat je leuk vindt .
Een manier is de opdracht zetten in cmd
en laat ze door voer_opdracht_uit
doen .
Een andere manier is een call_proc(routine_id_opdracht,{gekozen bestand})
.
Als je start is de eerste opdracht een lege of bevat "index" en deze roept (in bovenstaand voorbeeld) open_inschrijving()
.
Deze moet de eerste pagina naar de browser sturen .
procedure open_inschrijving() -- setup page if respcmd="nomail" then NOMAILFLAG=1 else NOMAILFLAG=0 end if new_page(progname,"?MF.CSS","silver") -- schrijf het menu en schrijf opening program(progname,"0.0",0,routine_id("aanmelding") ) -- geen menu , execute procedure "aanmelding" end procedure procedure aanmelding() write_client("oh wat mooi") add_form("_ta") add_table(0,2,90,1) -- text waarover gaat het add_row(108,2,100,3,0) add_text(108,1,"Ik wil mij opgeven voor (meerde keuzen mogelijk)") -- keuze met check add_row(108,2,30,0,0) add_check(109,'k',101,selectie_text[1],selectie[1],selectie_text[1]) add_col(108,2,30,0,0) add_check(109,'s',102,selectie_text[2],selectie[2],selectie_text[2]) add_col(108,2,30,0,0) add_check(109,'m',103,selectie_text[3],selectie[3],selectie_text[3]) -- vraag om eigen ID gegevens add_row(108,1,30,0,0) add_text(108,1,"Mijn naam is : ") add_input_text(1000,'n',25,202,persoon[1]) add_col(108,2,30,0,0) add_text(108,1," geboorte jaar : ") add_input_text(1000,'n',4,203,persoon[2]) add_col(108,2,30,0,0) add_text(108,1," mijn eMail is : ") add_input_text(1000,'n',30,204,persoon[3]) -- div=error leeg /div add_row(0,2,0,3,0) write_client("<dev id=\"error\">") add_hide(300,sprintf("%4.4i",NOMAILFLAG)) -- geen mail mee sturen write_client(" ") write_client("</dev>") -- add_row(108,2,100,3,0) d_oke_reset_niets() write_client("</table>") write_client("</form>") end procedureDe hier in genoemde variablen zoals
selectext
en persoon
moeten in de aanvang van het programma zijn gedeclareerd .
Na uitvoering geeft dit dan het onderstaande plaatje :
Nu zul je na het een en ander te hebben ingevuld te hebben deze versturen (door op Oke te drukken). Hiermee krijgt server de opdracht "_ta" .
Wat op zijn beurt de procedure inschrijfing()
aanroept . Deze luidt als zijnde :
procedure inschrijfing() lees_page() -- error check -- zijn er fouten ? if length(errors) then d_error(errors,{}) elsif NOMAILFLAG -- wil je mail maken en versturen ? then -- gegeven opdr. nomail of mail is al verstuurd . write_client("<p><h2>er word geen mail gemaakt</h2>") else write_client("<p><h2>U krijgt een bevestigings mail</h2>") NOMAILFLAG=1 add_hide(300,sprintf("%4.4i",NOMAILFLAG)) -- geen mail meer sturen -- maak en verzend mail als bevestiging en naar organisatie end if end procedureDe procedure
lees_page()
leest de ontvangen inschrijving en kontroleert dat op onzin en geeft zondig foutmeldingen terug .
procedure lees_page() sequence post=split_post(split(POSTCMD,'\n')) integer i=1 errors={1} -- default error voor geen selectie gegeven if length(post)!=0 then -- post is een sequence van 2 sequence . --1=sequence van "name" 2=sequence van "value" uit submit form while i<= length(post[1]) do -- de selectie ligt als "name" onder 200 n.l. 101,102,103 if post[1][i]<200 then errors={} selectie[post[1][i]-100]=post[2][i] elsif post[1][i]=202 -- naam then if sequence(post[2][i]) and length(post[2][i])!=0 then persoon[post[1][i]-201]=post[2][i] --naam else errors=append(errors,post[1][i]-200) --geen naam end if elsif post[1][i]=203 -- geb then if sequence(post[2][i]) then if length(post[2][i])=3 then post[2][i]=post[2][i][2..3] end if post[2][i]=value(post[2][i]) if post[2][i][1] then errors=append(errors,post[1][i]-200) -- geen getal else post[2][i]=post[2][i][2] end if elsif post[2][i]<100 -- opgave '00 - '99 of 00 - 99 then if post[2][i]>=short_year--als year = 2015 dan short_year = 15 then post[2][i]+=1900 else post[2][i]+=2000 end if end if if find(post[1][i]-200,errors)=0 -- is al fout sla over then if post[2][i]<=year then persoon[post[1][i]-201]=sprintf("%u",post[2][i]) --geboren else errors=append(errors,post[1][i]-200) -- niet bestand jaar end if end if elsif post[1][i]=204 -- mail then if sequence(post[2][i]) and length(post[2][i])!=0 then -- mail moet min a-z[[a-z][0-9]]@a-z[[a-z][0-9]].a-z[[a-z][0-9]] if is_email_juist(post[2][i]) then persoon[post[1][i]-201]=post[2][i] --mail else errors=append(errors,post[1][i]-200) -- ill mail end if else errors=append(errors,post[1][i]-200) -- no mail end if else -- must be hidden mail flag NOMAILFLAG=post[2][i] end if i+=1 end while else -- error of lege file write_client("<h1>no data</h1>") end if end procedureAls je het niet goed hebt ingevuld zie je het volgende :
Heb je het goed ingevuld dan krijg je dit te zien :
Het gehele programma kun je hier bekijken . Maar dit ging er om enigzinds een verduidelijking te geven .
Een nadere toelichting over een server-client toepassing kun je hier lezen .