| <!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN"> |
| <HTML> |
| <HEAD> |
| <TITLE>session_form</TITLE> |
| </HEAD> |
| <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#1F00FF" ALINK="#FF0000" VLINK="#9900DD"> |
| <A NAME="top"> |
| <A NAME="file1"> |
| <H1>session_form.ws3</H1> |
| |
| <PRE> |
| <I><FONT COLOR="#B22222"># This example shows how persistent sessions can be stored |
| </FONT></I><I><FONT COLOR="#B22222"># on the server. |
| </FONT></I><I><FONT COLOR="#B22222"># It shows two HTML forms which have one input field each. |
| </FONT></I><I><FONT COLOR="#B22222"># You can switch between these two forms using the submit |
| </FONT></I><I><FONT COLOR="#B22222"># buttons. All data given in the form |
| </FONT></I> |
| <I><FONT COLOR="#B22222"># Define a memory context to hold some configuration variables. |
| </FONT></I><I><FONT COLOR="#B22222"># The next statement makes a context called 'config' to hold |
| </FONT></I><I><FONT COLOR="#B22222"># these data. It is a cleaner way than making global variables |
| </FONT></I><I><FONT COLOR="#B22222"># because it declares them clearly to be configuration vars. |
| </FONT></I>web::context config |
| |
| <I><FONT COLOR="#B22222"># Now set some configuration variables. Usually put the session |
| </FONT></I><I><FONT COLOR="#B22222"># state files in a directory not accessible through the Web server. |
| </FONT></I>config::cset stateDirectory /tmp/websh/state/ |
| |
| <I><FONT COLOR="#B22222"># Create a file counter that generates the session ids. We take |
| </FONT></I><I><FONT COLOR="#B22222"># here an easy number generator, which produces sequential numbers |
| </FONT></I><I><FONT COLOR="#B22222"># and stores the actual counter value in a file (only create one if |
| </FONT></I><I><FONT COLOR="#B22222"># the current interpreter does not already have one) |
| </FONT></I><B><FONT COLOR="#A020F0">if</FONT></B> {![<B><FONT COLOR="#A020F0">llength</FONT></B> [<B><FONT COLOR="#A020F0">info</FONT></B> commands idGenerator]]} { |
| web::filecounter idGenerator -<B><FONT COLOR="#A020F0">filename</FONT></B> [<B><FONT COLOR="#A020F0">file</FONT></B> <B><FONT COLOR="#A020F0">join</FONT></B> [config::cget stateDirectory] counter] |
| } |
| |
| <I><FONT COLOR="#B22222"># Create a file context named 'state'. The option '-path' defines |
| </FONT></I><I><FONT COLOR="#B22222"># where the session contexts are stored. '-attachto' defines an |
| </FONT></I><I><FONT COLOR="#B22222"># URL parameter name that might contain an existing session. |
| </FONT></I><I><FONT COLOR="#B22222"># (This parameter name could in fact be extracted using |
| </FONT></I><I><FONT COLOR="#B22222"># 'web::param sid' whenever the session is initalized.) |
| </FONT></I>web::filecontext state -path [<B><FONT COLOR="#A020F0">file</FONT></B> <B><FONT COLOR="#A020F0">join</FONT></B> [config::cget stateDirectory] %s] -attachto sid -idgen <B><FONT COLOR="#BC8F8F">"idGenerator nextval"</FONT></B> |
| |
| <I><FONT COLOR="#B22222"># Make sure the session state directory exists |
| </FONT></I><B><FONT COLOR="#A020F0">catch</FONT></B> {<B><FONT COLOR="#A020F0">file</FONT></B> mkdir [config::cget stateDirectory]} |
| |
| <B><FONT COLOR="#A020F0">proc</FONT></B> <B><FONT COLOR="#0000FF">form</FONT></B> {<FONT COLOR="#B8860B">page code</FONT>} { |
| <I><FONT COLOR="#B22222"># Produces a HTML FORM tag. Nested form variables must be output |
| </FONT></I> <I><FONT COLOR="#B22222"># in 'code'. |
| </FONT></I> <I><FONT COLOR="#B22222"># The 'page' parameter describes the web::command to call when |
| </FONT></I> <I><FONT COLOR="#B22222"># the form is submitted. |
| </FONT></I> web::put <B><FONT COLOR="#BC8F8F">"<html><head><title>Session Example</title></head>"</FONT></B> |
| web::put <B><FONT COLOR="#BC8F8F">"<body bgcolor=\"#FFFFFF\">"</FONT></B> |
| <I><FONT COLOR="#B22222"># form starts here |
| </FONT></I> web::put <B><FONT COLOR="#BC8F8F">"<form method=\"POST\" action=\"[web::cmdurl $page]\">"</FONT></B> |
| <B><FONT COLOR="#A020F0">uplevel</FONT></B> $<FONT COLOR="#B8860B">code</FONT> |
| web::put <B><FONT COLOR="#BC8F8F">"</form>"</FONT></B> |
| web::put <B><FONT COLOR="#BC8F8F">"</body></html>"</FONT></B> |
| } |
| |
| |
| <B><FONT COLOR="#A020F0">proc</FONT></B> <B><FONT COLOR="#0000FF">putErrorMessage</FONT></B> {<FONT COLOR="#B8860B">msg</FONT>} { |
| <I><FONT COLOR="#B22222"># emit an error message in red. |
| </FONT></I> web::put <B><FONT COLOR="#BC8F8F">"<p><font color=\"\#ff0000\">[web::htmlify $msg]</font></p>"</FONT></B> |
| } |
| |
| |
| <B><FONT COLOR="#A020F0">proc</FONT></B> <B><FONT COLOR="#0000FF">pageOne</FONT></B> {<FONT COLOR="#B8860B">{errorMessage ""}</FONT>} { |
| <I><FONT COLOR="#B22222"># Display page one of our HTML form. |
| </FONT></I> form processPageOne { |
| <B><FONT COLOR="#A020F0">if</FONT></B> {[<B><FONT COLOR="#A020F0">string</FONT></B> length $<FONT COLOR="#B8860B">errorMessage</FONT>]} { |
| putErrorMessage $<FONT COLOR="#B8860B">errorMessage</FONT> |
| } |
| web::put <B><FONT COLOR="#BC8F8F">"Numbers only: <input type=\"text\" name=\"a\" value=\"[web::htmlify [state::cget a]]\">"</FONT></B> |
| web::put <B><FONT COLOR="#BC8F8F">"<input type=\"submit\" value=\"Page 2\">"</FONT></B> |
| } |
| } |
| |
| |
| <B><FONT COLOR="#A020F0">proc</FONT></B> <B><FONT COLOR="#0000FF">pageTwo</FONT></B> {<FONT COLOR="#B8860B">{errorMessage ""}</FONT>} { |
| <I><FONT COLOR="#B22222"># Display page two of our HTML form. |
| </FONT></I> form processPageTwo { |
| <B><FONT COLOR="#A020F0">if</FONT></B> {[<B><FONT COLOR="#A020F0">string</FONT></B> length $<FONT COLOR="#B8860B">errorMessage</FONT>]} { |
| putErrorMessage $<FONT COLOR="#B8860B">errorMessage</FONT> |
| } |
| web::put <B><FONT COLOR="#BC8F8F">"Not empty: <input type=\"text\" name=\"b\" value=\"[web::htmlify [state::cget b]]\">"</FONT></B> |
| web::put <B><FONT COLOR="#BC8F8F">"<input type=\"submit\" value=\"Page 1\">"</FONT></B> |
| } |
| } |
| |
| |
| <B><FONT COLOR="#A020F0">proc</FONT></B> <B><FONT COLOR="#0000FF">saveAllFields</FONT></B> {<FONT COLOR="#B8860B"></FONT>} { |
| <I><FONT COLOR="#B22222"># Save all form fields to state context. |
| </FONT></I> <I><FONT COLOR="#B22222"># web::formvar without parameters returns a list of HTML form |
| </FONT></I> <I><FONT COLOR="#B22222"># variables sent to this script. web::formvar with the name |
| </FONT></I> <I><FONT COLOR="#B22222"># of a field returns its value, if the field does not exist |
| </FONT></I> <I><FONT COLOR="#B22222"># it returns an empty list (or an optional 2nd parameter 'default |
| </FONT></I> <I><FONT COLOR="#B22222"># value'). |
| </FONT></I> <I><FONT COLOR="#B22222"># For clarity, we do not handle multiple fields with the same |
| </FONT></I> <I><FONT COLOR="#B22222"># name correctly here. If a HTML field is given twice or more |
| </FONT></I> <I><FONT COLOR="#B22222"># 'web::formvar -count <fieldname>' would give us the field count |
| </FONT></I> <I><FONT COLOR="#B22222"># 'web::formvar <fieldname>' returns then a list of n values. |
| </FONT></I> <B><FONT COLOR="#A020F0">foreach</FONT></B> field [web::formvar -names] { |
| state::cset $<FONT COLOR="#B8860B">field</FONT> [web::formvar $<FONT COLOR="#B8860B">field</FONT>] |
| } |
| } |
| |
| |
| <I><FONT COLOR="#B22222"># Define two dispatched commands to each show one page of the |
| </FONT></I><I><FONT COLOR="#B22222"># (mini) form. The names of theses application commands will |
| </FONT></I><I><FONT COLOR="#B22222"># be used in the submit action of the form with 'web::cmdurl'. |
| </FONT></I>web::command processPageOne { |
| state::init |
| <B><FONT COLOR="#A020F0">if</FONT></B> {![<B><FONT COLOR="#A020F0">regexp</FONT></B> {^[0-9]+$} [web::formvar a]]} { |
| <I><FONT COLOR="#B22222"># The input field does not contain only digits, so show page one again |
| </FONT></I> <I><FONT COLOR="#B22222"># including an error message. |
| </FONT></I> pageOne <B><FONT COLOR="#BC8F8F">"Please enter a number."</FONT></B> |
| } else { |
| <I><FONT COLOR="#B22222"># Everything ok, so save the form field to persistant session |
| </FONT></I> <I><FONT COLOR="#B22222"># and proceed with page two. |
| </FONT></I> saveAllFields |
| state::commit |
| pageTwo |
| } |
| } |
| |
| |
| web::command processPageTwo { |
| state::init |
| <B><FONT COLOR="#A020F0">if</FONT></B> {![<B><FONT COLOR="#A020F0">string</FONT></B> length [web::formvar b]]} { |
| <I><FONT COLOR="#B22222"># The input field is empty, so show page two again |
| </FONT></I> <I><FONT COLOR="#B22222"># including an error message. |
| </FONT></I> pageTwo <B><FONT COLOR="#BC8F8F">"Please fill in field."</FONT></B> |
| } else { |
| <I><FONT COLOR="#B22222"># Everything ok, so save the form field to persistant session |
| </FONT></I> <I><FONT COLOR="#B22222"># and proceed with page one. |
| </FONT></I> saveAllFields |
| state::commit |
| pageOne |
| } |
| } |
| |
| |
| <I><FONT COLOR="#B22222"># Define the default command to show page one. |
| </FONT></I>web::command default { |
| <I><FONT COLOR="#B22222"># Initialize a fresh state. |
| </FONT></I> state::init |
| <I><FONT COLOR="#B22222"># Show page one initially. |
| </FONT></I> pageOne |
| } |
| |
| |
| <I><FONT COLOR="#B22222"># Dispatch to one of the web::commands according to a parameter in the |
| </FONT></I><I><FONT COLOR="#B22222"># URL. This parameter was set using 'web::cmdurl' in the FORM tag in |
| </FONT></I><I><FONT COLOR="#B22222"># procedure 'form'. |
| </FONT></I><I><FONT COLOR="#B22222"># At the very beginning we don't have a command in the URL. Then the |
| </FONT></I><I><FONT COLOR="#B22222"># web::command default is called. |
| </FONT></I><I><FONT COLOR="#B22222"># The '-track' parameter is used to take over the URL parameter 'sid' |
| </FONT></I><I><FONT COLOR="#B22222"># from "incoming" URLs to "outgoing" URLs. This parameters holds |
| </FONT></I><I><FONT COLOR="#B22222"># the session id and makes a session survive |
| </FONT></I><I><FONT COLOR="#B22222"># web::dispatch processes the URL - i.e. extracts parameters from the |
| </FONT></I><I><FONT COLOR="#B22222"># URL - and handles HTML form input sent to this script. |
| </FONT></I>web::dispatch -track sid |
| |
| <I><FONT COLOR="#B22222"># cleanup state (so we have no session crosstalk) |
| </FONT></I>state::delete |
| </PRE> |
| <HR> |
| <ADDRESS>Generated by <A HREF="http://www.iki.fi/~mtr/genscript/">GNU enscript 1.6.3</A>.</ADDRESS> |
| </BODY> |
| </HTML> |