# This example shows how persistent sessions can be stored # on the server. # It shows two HTML forms which have one input field each. # You can switch between these two forms using the submit # buttons. All data given in the form # Define a memory context to hold some configuration variables. # The next statement makes a context called 'config' to hold # these data. It is a cleaner way than making global variables # because it declares them clearly to be configuration vars. web::context config # Now set some configuration variables. Usually put the session # state files in a directory not accessible through the Web server. config::cset stateDirectory /tmp/websh/state/ # Create a file counter that generates the session ids. We take # here an easy number generator, which produces sequential numbers # and stores the actual counter value in a file (only create one if # the current interpreter does not already have one) if {![llength [info commands idGenerator]]} { web::filecounter idGenerator -filename [file join [config::cget stateDirectory] counter] } # Create a file context named 'state'. The option '-path' defines # where the session contexts are stored. '-attachto' defines an # URL parameter name that might contain an existing session. # (This parameter name could in fact be extracted using # 'web::param sid' whenever the session is initalized.) web::filecontext state -path [file join [config::cget stateDirectory] %s] -attachto sid -idgen "idGenerator nextval" # Make sure the session state directory exists catch {file mkdir [config::cget stateDirectory]} proc form {page code} { # Produces a HTML FORM tag. Nested form variables must be output # in 'code'. # The 'page' parameter describes the web::command to call when # the form is submitted. web::put "Session Example" web::put "" # form starts here web::put "
" uplevel $code web::put "
" web::put "" } proc putErrorMessage {msg} { # emit an error message in red. web::put "

[web::htmlify $msg]

" } proc pageOne {{errorMessage ""}} { # Display page one of our HTML form. form processPageOne { if {[string length $errorMessage]} { putErrorMessage $errorMessage } web::put "Numbers only: " web::put "" } } proc pageTwo {{errorMessage ""}} { # Display page two of our HTML form. form processPageTwo { if {[string length $errorMessage]} { putErrorMessage $errorMessage } web::put "Not empty: " web::put "" } } proc saveAllFields {} { # Save all form fields to state context. # web::formvar without parameters returns a list of HTML form # variables sent to this script. web::formvar with the name # of a field returns its value, if the field does not exist # it returns an empty list (or an optional 2nd parameter 'default # value'). # For clarity, we do not handle multiple fields with the same # name correctly here. If a HTML field is given twice or more # 'web::formvar -count ' would give us the field count # 'web::formvar ' returns then a list of n values. foreach field [web::formvar -names] { state::cset $field [web::formvar $field] } } # Define two dispatched commands to each show one page of the # (mini) form. The names of theses application commands will # be used in the submit action of the form with 'web::cmdurl'. web::command processPageOne { state::init if {![regexp {^[0-9]+$} [web::formvar a]]} { # The input field does not contain only digits, so show page one again # including an error message. pageOne "Please enter a number." } else { # Everything ok, so save the form field to persistant session # and proceed with page two. saveAllFields state::commit pageTwo } } web::command processPageTwo { state::init if {![string length [web::formvar b]]} { # The input field is empty, so show page two again # including an error message. pageTwo "Please fill in field." } else { # Everything ok, so save the form field to persistant session # and proceed with page one. saveAllFields state::commit pageOne } } # Define the default command to show page one. web::command default { # Initialize a fresh state. state::init # Show page one initially. pageOne } # Dispatch to one of the web::commands according to a parameter in the # URL. This parameter was set using 'web::cmdurl' in the FORM tag in # procedure 'form'. # At the very beginning we don't have a command in the URL. Then the # web::command default is called. # The '-track' parameter is used to take over the URL parameter 'sid' # from "incoming" URLs to "outgoing" URLs. This parameters holds # the session id and makes a session survive # web::dispatch processes the URL - i.e. extracts parameters from the # URL - and handles HTML form input sent to this script. web::dispatch -track sid # cleanup state (so we have no session crosstalk) state::delete