Doel van dit project is om een eenduidige interface te verkrijgen voor het gebruik van de routines voor het opbouwen van een Web-Site .

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 procedure
De 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 procedure
De 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 procedure              
Als 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 .