Using Guestbook Technology to impliment simple Web based applications.

Here is a way of writing simple web applications by using a 'guestbook' server side script and client side JavaScript. There are loads of simple applications that just need a simple sorted list of user's occasional amendments.

Some of these pages result from work on automating our sailing club web site. Our sailing club needed some simple but useful applications without too much effort. This was invented as BTInternet offered three pre written CGI scripts, but did not allow user CGI scripts. If they modified their guestbook script to support this idea, then the site owner could ftp .htm files, and ftp gbookFXXX.js up to the server. Also, I was on a Pay As you Go Dial Up. Editing on line was painful, as every minute costed me. Always on Broadband has changed this.

This is also good if you need a simple application where security is not a big issue, and access to the server is constrained by no telnet access and update is via ftp only via dial up. Also, as the web page code is 'open' to a view source, anybody who wants to rip off and improve for private or public use can!

When your visitor signs this guestbook, the entry is appended to a file of JavaScript, which is downloaded when the page is next loaded by the viewer. Note: users can only append data, and cannot delete entries. Spam can be deleted by the person with FTP access.

Using javascript code that you write, the guestbook entries can be sorted, selected and formatted by JavaScript running on the clients browser.

This allows simple applications to be written.

All the demo applications use the same cgi perl script guestbook.pl hosted on my Web server ccgi.dougrice.plus.com. You could run guestbook.pl ( or ASP / PHP version ) on your Web server.

You write the custom JavaScript to sort and summarise the data in the guestbook, and the data is also available to validate the guestbook form.

This page is tested first in Microsoft IE 5

I first used this to implement an online booking diary for our sailing club boats, which members can use. This diagram shows the split of functionality between the Server and the client.

An example - Sorting the Guestbook entries to display the latest entry first using the HTML and Javascript code below.

<html><body>

<H2>Minimal Form - After use press refresh  to pull down new data. </h2>

<form name="F1" action="http://cgi.dougrice.plus.com/cgi-bin/guestbook.asp" method="POST" >
name: <input type="text" name="name" value="name" size="20" >
email: <input type="text" name="email" value="email" size="20" > <BR>
<!-- You can also have fields: userfield1,userfield2,userfield3,userfield4 -->
<input type="hidden" name="userfield5" value="USERFEILD5" size="20" ><!-- anti spam -->
Please enter any comments:- <BR>
<textarea name="comments" rows="2" cols="80"></textarea><BR>

<input type="hidden" name="guestbook" size="20" value="XXX"  >
<input type="hidden" name="nextpage" size="70" value="http://www.dougrice.plus.com/hp/gbbook/example.htm" " >
<input type="hidden" name="loadnextpage" size="70" value="loadnextpage" >
<input type="submit" name="B1" value="Submit">
</form>
<HR>

<script>
// anti-spam measure - Javascript changes cgi script to real script.
var date= new Date()
var F1 = window.document.forms["F1"]

self.document.forms["F1"].action  = "http://ccgi.dougrice.plus.com" 
self.document.forms["F1"].action += "/cgi-bin/guestbook.pl" 
self.document.forms["F1"].userfield5.value = "uf5 "+ date.toString() 
</script>

<script>
//
// Javascript functions to use the guestbook data and include the guestbook data file.
//
var thisEntry = "", opStr     = ""
var gifsA = "flower.gif,abubble.gif,aflash.gif,aflower.gif,aheart.gif,astar.gif,biled0.gif,biled1.gif,biled2.gif,biled3.gif,".split(",")


// The function below is called once per guestbook entry. 
// You write this function to do what you want!!
function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
  var img = ""
  var imgIndex = userfield2*1
   // pick an image based on the value of userfield2 from an array of image names

  if ( ( imgIndex > 0 ) << ( imgIndex <  gifsA.length ) ){ img = "<img src=./simple/gifs/"+gifsA[ imgIndex ] +" > "  } 
  
  news    = ((""+comments).replace( "<","&lt;")).replace( ">","&gt;")
  updated = new Date( postedOn ).toString()+" by "+name
  thisEntry = "<HR><B>" + img + userfield1 + "</B><BR><pre>" + news + "</pre><BR><i>" + updated + "</i>"
  opStr   = thisEntry + opStr
}
// test call
gbF( "Test Call","email","15 Nov 2003","IPaddress","userfield1","userfield2","userfield3","userfield4","Testcomments")
</script>


<!-- Include remote guestbook and gbF() will be called once per entry.-->
<script  language = "JavaScript" type = "text/javascript" 
   src = "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js" >  
</script>


<H2>Guestbook data expanded by userdefined gbF() function </h2>

<H2> Last Entry</h2>
<script> self.document.write( thisEntry ) </script>

<H2> Prevous Entries</h2> 
<script> self.document.write( opStr ) </script>
</body></html>


The example above. A form to make an entry to this example guestbook. You may need to refresh the example page to see latest entry if you use this form.

A walk through the basics... Examples of minimal applications and code for your web pages and CGI server scripts in asp, perl, php for your CGI server ...

Otherways to look at the data in this guestbook.

Example including update form do view souce to see how it is done.


Examples of Server CGI scripts that append the data sent up onto the end of gookFXXX.js

guestbook.asp

guestbook.php

guestbook.pl

Posted Fields used by guestbook scripts:
name	    =name  - name of person signing guestbook
email	    =email - email address of person signing guestbook
userfield1  =userfield1 - a string that the application can use
userfield2  =userfield2 - a string that the application can use 
userfield3  =userfield3 - a string that the application can use 
userfield4  =userfield4 - a string that the application can use 
userfield5  =uf5 Tue Oct 23 21:47:32 UTC+0100 2007 - anti spam security string set by javascript

comments    =This is a multi line comment

The fields above are copied into the parameters below, suitably escaped:

function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){

This field is use to select the guestbook to update:

guestbook   =XXX  - this string is appended to gbookF{guestbook}.js 

These fields control the next URL to go to:

nextpage    ="http://ccgi.dougrice.plus.com/db0601/db7.php"  - URL of page to go to.
loadnextpage=loadnextpage  - this is a flag to load the next page

Various ways of displaying and sorting gbookFXXX.js

See Simple ways of displaying gbookFXXX.js

Add data to http://ccgi.dougrice.plus.com/gb/gbookFXXX.js using the simple form.

Here are various ways of displaying and sorting gbookFXXX.js. This is all done by your web browser using javascript.

Remember that you can use IE's view source menu option to view the source.

Guestbook Guestbook ( code )
Guestbook-last entry first ( code )
Another Guestbook - last entry first

JavaScript - open then do viewsource for code

SQLite schema and insert statements - open then do viewsource for code

MySQL schema and insert statements and PHP scripts - How to interface to a MySQL database using PHP

and gbookFXXX.js

Or variations of the Sorted Guestbooks:

Sorted:

Sorted + update form ( code )
Intelligently Sorted + update form ( code )

Sortable tables - remembering last sort order

Sortable tables - remembering last sort order - All guestbooks ( ~800 entries )

Collated using linked lists:

Collate data by userfield1 ( code )
tables of data by userfield1 ( code )
or tables of data by userfield1 + updates


Or a Calendar showing when the gbookFXXX was updated. It is a calendar showing when people posted an entry in the guest book. ( Use View Source to see code ).


All the formatting is done by JavaScript on your browser. All the applications use the same cgi perl script guestbook.pl hosted on my Web server ccgi.dougrice.plus.com. This page is tested first in Microsoft IE 5

A technical overview of the idea.

A technical overview of the idea...

A walk through the basics...
Minimal application and code...


There are some Multiple SubForm examples:

There are times when multiple updates are required.

A try at a multiple update form and perl script... This provides multiple sub forms, using data from gbookFmulti.js, which are appended to the gbookFmulti.js using gbook_multi.pl

A minimal multiple update form and perl script... This provides multiple forms.

A try at a multiple update form and perl script... This provides links generated, using data from gbookFmulti.js, you can add sub forms by clicking on hypertext links of by using a dropdown select list.

Another multiple update form... This a page where each item can be edited, and before submit, a list of updated entries can be listed, checked and submitted.

When you submit the data is appended to gbookFmulti.js using gbook_multi.pl


There are some functioning examples:

Updateable Notice Board - with update form

Data dump of guestbooks: Data Dump at www.plus.net

A walk through the basics... Minimal application and code...

This was adopted into a simple fault tracker: Website bug report system

Here is the Mark 1 booking diary that uses a BT Internet Guestbook.

Early work: First try for a booking system
Mark 1 Dinghy Booking . The user is expected to do a copy and paste. Needless to say, we did not go live with this!!!

Early work: Second try for a booking system

Early work: Demo to support new idea

eScrapBook / eWorkingRecords - A User Updateable Sorted lists with history User Updateable Sorted lists. This could be adapted to a loan book, room booking, leave records, Document indexs, Test Spec/ results, Resource Information, Message boards, Fault tracker etc

Christmas Menu Questionnaire, Captured data viewed using eScrapbook

History

A first attempt, that explores Javascript possibilities:

WARNING: If you are trying these off line IE 5 works best, Netscape waits a long time, while trying to download files from the WWW.

Feel free to submit the form, these are demo examples with demo data.

An overview of a database....

Theory

The web is a wonderful thing. Many people, like me can publish ideas and theories at little cost, as it is easy to knock a few Web pages together and push them up to our ISP's free personal web space. However, most free ISP's do not allow you to run CGI or ASP scripts, for valid security reasons. BT Internet is one of them. That is a shame as a simple CGI script can be used to automate a simple application. BTInternet do allow you to run a few of their own CGI scripts.

There are many people who provide web counters and guest book services. These protect the security concerns, and you, the web page author, do not need to get your hands dirty with PERL or UNIX or MySQL or build web servers on your machine to develop your web pages or all that webhosting stuff.

Do you wish that you had a Guest book that did just that little bit more. Maybe, you want to sort the entries by name or uses the information supplied in one of your fields.

I am in a sailing club, and we wanted a booking diary system that was WEB based. It had to be out side the firewall at work, so we need to host on an external webhosting site. BTInternet is an idea first choice.

It needed to keep a record of who had booked the boat, but present the bookings in a number of formats.

It had to keep an audit trail of bookings and allow amendments, so a guestbook that stored every posting was a good choice.

I thought that I could use the BT Internet Guestbook system. If I could find a way to sort people's submissions, then I could present them in diary order and show if the boat is booked or available.

> There is no way that a Web page can read guestbookfile1.html file output by BT Internet's guestbook CGI script, for security reasons.

Well, here is a generic way of doing it.

Use a Guestbook That Outputs To gbookF5.JS in the following format:

<!-- Start of entry -->
/* Start of segment of code output by the BT internet CGI script */ 
/* This would be stored in gbookF5.js */
gbF(
  "doug",  "d@g",  "28/10/02 07:53:02",  "127.0.0.1",
  "userfield1",  "userfield2",  "userfield3",  "userfield4",
  "comments"
  );
<!--  End of entry -->

The CGI / Perl script that runs on the ISP/Guestbook ( BTInternet's ) server would be generic. My Web Page could process this on the Client's browser with what ever JavaScript I can think up!

The data flow is:

On Clients Webpage ( written by you ):

1) Force a reload of the web page.

2) Include gbookF5.js, maybe in a separate frame which can be force reloaded.

3) gbF() is called once for each guestbook entry. copy the data into an array element gbA[count]

3) Summarise and Sort gbA array included in gbook_n.js using JavaScript's sort function. This allows you to write a call back function to select the fields, see example at the end.

4) Use javascript to output the contents of gbA array in the format that you want, to a separate frame. You can provide hypertext links that call different display options.

5) Provide a form called UserForm for the user to fill in. Hypertext links on the frame that your java script has just written to can be used to partially fill this form.

6) Capture the Submit button for UserForm. In the submit function, validate and copy and combine the fields from UserForm onto the MainForm that has the fields:

name, email, 
userfield1, userfield2, userfield3, userfield4,
comments 

If validated, the form can be submitted. I changed the text on the Submit buttion to indicate how the validation was progressing.

These are the user fields on BT Internet's Guestbook CGI. If BTInternet added the fields:

guestbook

then you could update different guestbooks.

Your version of gbF() could filter the data into different arrays, dependant on, say, the value of userfield1.

The different arrays could be used for bookings or status or usernames say.

Currently BTInternet allow 5 guestbooks. These are selected by:

HTTP://www.btinternet.com/cgi-bin/guestbook/~yourUserName?guestbook=5"

6) Now submit this form to the ISP ( BTInternet's ) or Guestbook provider's CGI script for appending onto your guest book.

Your ISP's ( BTInternet's ) guestbook CGI script ( written by them ) takes the SubmitForm's fields and appends it onto your gbookF5.js file that they store in your web space.

The Guestbook provider's CGI script provides a thankyou page that has a link back to your web page, so that you can reload the gbookF5.js file and redisplay it.

A walk through the basics... has minimal size web pages and a working example that provides a frame work for futher development.

If you think that you could use this technology and do not want to go to the expense of setting up a webhosting account, please email me or sign my guestbook. I might set you up a trial guestbook file. Think of a name, say Diary. I would create a file called gbookFDiary.js, which I would have to give universal read and write permissions using FTP or telnet and chmod 666 gbookFDiary.js The perl CGI script errors if it cannot write to an existing file.

This would located at:

http://www.dougrice.webhoster.co.uk/public/gbookFDiary.js

so, to pick up the data, include the following, on your web page:


<script src="http://www.dougrice.webhoster.co.uk/public/gbookFDiary.js" language="JavaScript" type=text/javascript>	></script></code>

First you need to set some variables, so include the following:

<SCRIPT>
<!-- Sec 1.0 Variables -->
var count  = 0
var gbA    = new Array()
var statsA = new Array()

<!-- The CGI script appends the value of  -->
<!-- field name="GuestBookArrayName" value="_mem" -->
<!-- to allow more than one array, so you have to declare them -->        

var count_mem = 0
var gbA_mem  = new Array()

function GB( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
	this.name       = name
	this.email      = email
	this.postedOn   = postedOn
	this.IPaddress  = IPaddress
	this.userfield1 = userfield1
	this.userfield2 = userfield2
	this.userfield3 = userfield3
	this.userfield4 = userfield4
	this.comments   = comments
	//This function is run for each guestbook entry 
        //when the data is loaded add a field to be used 
        //for sorting
	this.JSindex	= count 
        // if userfield1 has a user entered date in it.
        this.date       = new Date( userfield1 )
	// or possibly some output HTML
        self.document.write("loading:"+count+": "+name+" @ "+postedOn+"<BR>")
        // build up some statitics
        // userfield2 could be selected by a drop down list 
        statsA[ userfield2 ] = statsA[ userfield2 ]*1 + 1        

	return this
}

// The guest book CGI script on the server takes the Guestbook's form fields:
//   name,email,postedOn,IPaddress,
//   userfield1,userfield2,userfield3,userfield4,comments
// and wraps the values in the following format:

//
gbF( 
"name", 
"email", 
"28/10/02 07:53:02",
"127.0.0.1", 
"userfield1", 
"userfield2", 
"userfield3", 
"userfield4", 
"comments" );  

The original format below, adds the data to an array. This was simplified to the gbF() format. This new format is simpler to understand.

gbA[ count ]= new GB( 
"name",
"email",
"postedOn", "IP address", 
"userfield1",
"userfield2",
"userfield3",
"userfield4",
"comments" ); 
count = count + 1 

// function call back for data stored in guestbook. 
function gbF(
               name,email,postedOn,IPaddress,
              userfield1,userfield2,userfield3,userfield4,
              comments
           ){
  gbA[ count ] = new GB( 
               name,email,postedOn,IPaddress, 
               userfield1,userfield2,userfield3,userfield4, 
               comments ); 
  count++ 
}
</SCRIPT>

<!-- Now pick up the data from the remote web sites hosting the guest book -->
<script src="http://www.dougrice.webhoster.co.uk/public/gbookFDiary.js" language="JavaScript" type=text/javascript></script>

You also have to edit the form action to:


<form name="F1" action="HTTP://www.dougrice.webhoster.co.uk/cgi-bin/guestbook.pl?guestbook=Diary" method="POST" >

or, as I sometimes use a local webserver 127.0.0.1, I use:


if ( document.location.host == "127.0.0.1" ){
form1.action = "HTTP://127.0.0.1/cgi-bin/guestbook.pl?guestbook=Diary"
} else {
form1.action = "HTTP://www.dougrice.webhoster.co.uk/cgi-bin/guestbook.pl?guestbook=Diary"
}

We have used this technology, and it is simple and works. We had 250 transactions over the year, which trippled our boat usage.

At the bottom of this page is a form that submits and appends to gbookF5.js it is followed by a table that outputs the data in gbookF5.js. The form does a minimal validation of the new entries against the data in gbookF5.js. There are hypertext links on the table that fill the form back in, in case you wish to amend the guestbook entry, and append a new version onto the end of the guestbook.

If you are a web hoster that wants to provide this for free or a nominal charge feel free to use it.

We used this guestbook on our webhoster account to support the sailing club.

I ran two guest books, one for the yacht and one for the dinghies. We had about 250 transactions and 4000 pages hits for the whole site in the year. 22Mbytes for pages, forms and documents was downloaded. It was reasonable to use and given a good example to work from, I am sure many other people could find an application that they could use it for.

The 2002 season has been much better.

"If you invent the perfect Web portal, you will have a beatten path to your mouse trap"

Doug Rice, Copyright 2002

Examples:

A walk through the basics... has minimal size web pages and a working example that provides a frame work for futher development.

JavaScript Code to do the sort and summarise

This is important.

Use the OnLoad function to call doOnLoad(), or before the rest of the code do:

<script>
  doOnLoad()
</script>

It adds the field JSindex to gbA[ ], so that the array can be sorted back to submitted order.

It sorts the array into diary order, using the value stored in gbA[ ].userfield1. If the dates are the same, then sort by submit order now stored in gbA[ ].JSindex. With a diary sorted array, you can now add fields amending and ammendedBy fields to gbA[ ]. These can be used to identify if a second submission for a given date has been made.

The web page author can then choose what to do with amended submissions, when they display the information.

<body background=paper2.jpg bgcolor="#FFFFFF"  onLoad="doOnLoad()">
...

function doOnLoad() {
  if ( gbA.length > 0 ) {  
    //
    // This function is called on the page load.
    // In this function put functionality to summarise the guestbook entries.
    // 
    // Build Indexes here, by adding extra properties of the object.
    //  assuming that one of the userfileds is the diary date  
    //  We could sort the array into diary order and find amending bookings.
    //  which refer to a date previously booked, submitted earlier.
    //
 
    // before Sorting the Guestbook array, add a field = to index
    // this can be used to sort the entries back to the submitted order.
	
    for ( I in gbA ){
	// add a new 
	gbA[ I ].JSindex     = I
	gbA[ I ].amendingJS  = "."
	gbA[ I ].amendedByJS = "."
	gbA[ I ].amendingD   = "."
	gbA[ I ].amendedByD  = "."
    }

    // sort the array into [ diary order, submit order ]
    gbA.sort(  sort_diary )

    // now  your can add links so that amending bookings 
    // and amended bookings can be identified.
    var cnt = 0
    var lastI = ""
    for ( I in gbA ){
	gbA[ I ].diaryOrder = cnt 
	cnt = cnt+1
        //write( "<P>"+lastI+","+I )
	if ( lastI != "" ){
          if ( gbA[ I ].userfield1 == gbA[ lastI ].userfield1 ){

            // use the submitted order
	    gbA[ I ].amendingJS      =  gbA[ lastI ].JSindex
	    gbA[ lastI ].amendedByJS =  gbA[ I ].JSindex

	    // use the current sorted order
	    gbA[ I ].amendingD      =   lastI 
	    gbA[ lastI ].amendedByD =   I
          }
	}
	lastI = I
    }

    // Now display the guestbook sorting by date
    displayGuestBookArray( 2 )
  }


  //populate the Who: select list of the User Form
  var window1 = parent.frames["OPform"]
  var form1  = window1.document.F1
  var form2  = window1.document.F2
  if ( gbA_mem.length > 0 ) {
    for ( I =0 ; I < gbA_mem.length; I++ ) {
      form1.who.options[I]= new Option( gbA_mem[ I ].name,"")
    }
    form1.who.options[0].selected
  }
}