Using Guestbook Technology to implement 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.

Download the posts wrapped in a javaScript function gbF(), instead of HTML

This idea modifies the guestbook to return the posts in a format that can be processed by the user's web page. Instead of HTML, download the posts wrapped in a javaScript function gbF().

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 next viewer.

  • function gbF( name, email, postedOn, IPaddress, userfield1, userfield2, userfield3, userfield4, comments )
  • is appended to http://ccgi.dougrice.plus.com/gb/gbookFXXX.js
  • using guestbook script http://ccgi.dougrice.plus.com/cgi-bin/guestbook.pl.
  • http://ccgi.dougrice.plus.com/gb/gbookFXXX.js is included in your web page
  • Your version of gbF() formats the data as required!
  • 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 I paid for every minute I was connected. 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! For our sailing any member could see how it was done, if interested!

    This is also good if you need:-

  • a simple application,
  • where security is not a big issue,
  • prototyping can be done using local files on your PC and local editor.
  • access to the server is constrained
  • there is limited or no telnet access
  • update is via ftp without built in editor
  • 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!
  • You need to understand JavaScript, HTML, CSS
  • You do not need all the normal knowledge of PHP, SQL, and all the server side stuff.
  • You do not need to be a DBA for the database!
  • This idea pre-dated JSON and AJAX.
  • This idea pre-dated innerHTML(). At the time frames were popular!
  • This idea can be used with SVG graphics and has possibilities for visualizing debug output from C code.
  • 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 own 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.

    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.

    Example:

    An example

    Display the latest Guestbook entries first using the HTML and Javascript code below. You may need to refresh the example page to see latest entry if you use this form.

    <!DOCTYPE html> 
    <html><body>
    <link rel="stylesheet" type="text/css" href="club.css">
    
    <H2>Minimal Form - After use press refresh  to pull down new data. </h2>
    
    <form name="F1" action="http://ccgi.dougrice.plus.com/cgi-bin/guestbook.pl" 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>
    //
    // Javascript functions to use the guestbook data and include the guestbook data file.
    //
    var thisEntry = "", opStr     = ""
    
    // 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){
      
      news    = ((""+comments).replace( "<","&lt;")).replace( ">","&gt;")
      updated = new Date( postedOn ).toString()+" by "+name
      thisEntry = "<HR><B>" + 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>
    
    
    

    My entry is appended to: http://ccgi.dougrice.plus.com/gb/gbookFXXX.js

    I put spam into: http://ccgi.dougrice.plus.com/gb/gbookF_guest_XXX.js

    You may need to refresh the example page to see latest entry if you use this form, as the .js file may be cached

    Data dump of guestbooks: Data Dump at www.plus.net
    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.pl

    guestbook.php

    guestbook.asp

    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)
    
    function gbF( "user's name", "user's email", "timestamp postedOn", "users IPaddress", "uf1", "uf2", "uf3", "uf4", " user's 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://www.dougrice.plus.com/hp/gbbook/index.htm"  - URL of page to go to.
    loadnextpage=loadnextpage  - this is a flag to load the next page
    

    Loading and sorting:

    You write gbF() like you write callback functions. What gbF() does is your choice. It can filter the data as required. Use HTML tags and styles to format.

    A more complicated format would be to wrap HTML table tags around the data.

    function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
    
    self.document.write( 
      "<Tr>"+
        	"<TD >"+	name+		"</TD>"+
    	"<TD >"+	email+		"</TD>"+
    	"<TD >"+	<B>postedOn</B>+	"</TD>"+
    	"<TD >"+	IPaddress+	"</TD>"+
    	"<TD >"+	userfield1+	"</TD>"+
    	"<TD >"+	userfield2+	"</TD>"+
    	"<TD >"+	userfield3+	"</TD>"+
    	"<TD >"+	userfield4+	"</TD>"+
    	"<TD >"+	comments+	"</TD>"+
      "</TR>"
    }
    

    Below is an example of loading JavaScript Objects

    var count = 0
    var gbA  = new Array()
    
    function GB( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
            var avA = userfield2.split(",") < 4
            if ( avA.length < 4 ) {
              userfield2 = "0,0,0"
            }
    	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
    	return this
    }
    
    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=count+1;
    }
    
    

    And simplified way of storing the data into an Object.

    Using JavaScript object format

    var gbA  = new Array()
    
    function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
      var  = new Object()
    
      	r.name       = name
    	r.email      = email
    	r.postedOn   = postedOn
    	r.IPaddress  = IPaddress
    	r.userfield1 = userfield1
    	r.userfield2 = userfield2
    	r.userfield3 = userfield3
    	r.userfield4 = userfield4
    	r.comments   = comments
    	r.link	     = ""
    
    	//return r
    	
    	// Append this object to an Array
    	gbA[ gbA.length ] = r
    }
    

    Using JavaScript Objects

     
    var gbA = []
    var gbA = new Array()
    console.log( gbA.length )
    
    function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
      
      gbA[ gbA.length ] =  { 
        "name":name,
    	"email":email,
    	"postedOn":postedOn,
    	"IPaddress":IPaddress,
    	
    	"userfield1":userfield1,
    	"userfield2":userfield2,
    	"userfield3":userfield3,
    	"userfield4":userfield4,
    	
    	"comments":comments,
    
    	"index":gbA.length
    	}
    }
    
    // test call
    gbF( "Test Call1","email","15 Nov 2003","IPaddress","userfield1","userfield2","userfield3","userfield4","Testcomments")
    gbF( "Test Call4","email","15 Nov 2003","IPaddress","userfield1","userfield2","userfield3","userfield4","Testcomments")
    gbF( "Test Call5","email","15 Nov 2003","IPaddress","userfield1","userfield2","userfield3","userfield4","Testcomments")
    gbF( "Test Call2","email","15 Nov 2003","IPaddress","userfield1","userfield2","userfield3","userfield4","Testcomments")
    
    function sortfn( a, b ){
      if (a.name  >  b.name){
        return 1
      } else { 
        return -1
      }
    }
    
    // pass name of sort function
    gbA.sort( sortfn )
    
    /*
    

    Using JSON.stringify() and descend() to dump the data

    For debugging, it is possible to dump the data.

     
    */
    
    self.document.write("<H1> dump using JSON.stringify( gbA, null, 2 ) </H1>");
    
    self.document.write("<pre> dump using "+JSON.stringify( gbA, null, 2 )+"</pre>");
    
    
    /*
    

    Using descend() to dump the data

    For debugging, it is possible to dump the data.

     
    */
    
    
    var calls = 0
     
    /*
      gbA[ index ].name 
      
    is the same as 
      
      gbA[ index ][ "name" ]
    
    typeof() can be used to find the type of the object.
    
    The function below was used dump objects when testing 20 years ago.
    Now you can use JSON.stringify( gbA, null, 2 ) to dump the data.
    */ 
     
    function decend( r, level ){
      // dump a JavaScript Object passed to it
      var opStr = ""
      for ( var I in r ) {
        //opStr += level+" "+I+" =  "+r[ I ] + " " + typeof( r[ I ] )"\n"
     
       if ( typeof( r[ I ] ) == "object" ){
          // attempt to limit it running for ever.
          calls += 1
          if ( calls > 250 ) {
            return opStr + "++++++++++++++ too many objects +++++++++++++++\n"
          }
          opStr += level+" "+typeof( r[ I ] )+": "+I+" [ \n"
     
          // an attempt to look for looping
          if( I != "document" ){
            opStr += decend( r[ I ], level + " " )
          } else {
            opStr += level + " ... \n"
          }  
     
          opStr += level+" ] \n"
        } else {
          opStr += level+" "+typeof( r[ I ] )+": "+I+" =  "+r[ I ] +"\n"    
        }
      }
      return opStr
    }
     
    self.document.write("<H1> decend( gbA, 1 ) </H1>");
    
    self.document.write("<pre>"+decend( gbA, 1 )+"</pre>");
    
    

    For debugging, it is possible to dump the data.

    This web page uses descend() for debugging. Signal boxes

    There are some functioning examples:

    Sailing club booing system:-

    A boat booking system - Life Raft system - demo

    Notice board - shows future events and those last week:-

    Updateable Notice Board - used for 10 years at work

    Updateable Notice Board - with update form

    Gant Chart:-

    Gant Chart demo

    Updateable Club Race Results.

    Scrap book of code samples:-

    code scrap book.

    Interesting Web page logger.

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


    Include data and display using SVG - could be simpler

    Plot Solar cell measurements using SVG graphics See: Solar cell measurements

    This used the mouse to put pins on the diagram - broken

    ePinboard - for Beer festival (Only works in Microsoft IE5 ) - Broken at the moment


    A complicated system that was used for notes:- broken

    My eScrap Book on www.plus.net

    - Dump of data


    A table that can be created from an upload of CSV data. Each row can also be edited.

    Table | Table - allows updates and uploads | Dump of all posts

    This was an early try, and is now broken. Roster Display for A Staff Availability / Sports Club Team - broken .

    A web site bug tracker! a Website bug report system and fault tracker.

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

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

    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


    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.


    Work arounds

    There are a few problems that needs attention.

  • Anti Spam - disable unsolicited posts, using hidden password or unlock cookie or known IP addresses.
  • Cache busting to force downloading the guestbook file
  • Escaping ' and " and HTML tags
  • Use cache busting to show recent updates- try some cache busting so the URL is not cached

    One problem is that JavaScript is cached which means you need to refresh the webpage to see what you have added. Try some cache busting so the URL is not cached.

      
    <script>
    now = new Date()
    /* try some cache busting append the time to the URL to make it different, so the URL is not cached. */
    self.document.write( '<scr'+'ipt src=http://ccgi.dougrice.plus.com/gb/gbookFXXX.js?'+now.getTime()+'  language="JavaScript"> </scr'+'ipt>' )
    
    </script>
    <script>
    
    

    IMPORTANT - ESCAPE inband ' and "

    If the data contains ' or " these need to be escaped and it is really complicated !

    Options are:

  • strip them out
  • escape them for the code being output
  • If the data is wrapped in SQL and JavaScript and these are not escaped correctly, things break.

    When the JavaScript or SQL code is executed again this breaks things and can be exploited by hackers.

    Different character sets like UTF-8 coding and Latin-1, also called ISO-8859-1 encoding can also break things!

    
    
    For JavaScript: v
    
       JavaScript needs inband ' escaped to \'
       JavaScript needs inband " escaped to \"
    
      // PHP escapes ' to \' using addslashes() but SQL needs ' escaped to ''
    
    http://ccgi.dougrice.plus.com/gb/gbookFDemoBookings.js
     
    has the date wrapped in gbF() e.g.
    
    gbF( // guestbook.pl 
    "name","email","Tue, 2 Jun 2020 06:15:06 UTC+0000","212.56.108.219  | dougrice.plus.com  ",
    "userfield1",
    "userfield1",
    "userfield1",
    "userfield1",
    "comments"
    );
    
     
    If the posted data has " or ' within it, it would break the javaScript parser so convert " to \"
    
    Within your code for gbF() you will need to consider that the data may have " within it.
    
    
    For SQL:
    
    This would not work!
      INSERT into GB( comments ) values ( ' Billy's comment ' );
    
    
      INSERT into GB( comments ) values ( ' a comment ' );
      INSERT into GB( comments ) values ( ' Billy''s comment ' );
      INSERT into GB( comments ) values ( ' Billy\'s comment ' );
    
      // SQL INSERT values  need inband ' escaped to ''
      // so replace \' with ''
    
    // for SQL:-
    function esc ( $s ) {
      $ts= str_replace("'","''", $s );
      return $ts ;
    }
    
    For PHP 
      // php escapes ' to \' using addslashes()
    
    For HTML
      needs escaping within tags.
    
    A Web form does a GET or POST which could write SQL or HTML or JavaScript when responding.
    
    
    

    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

    SQL examples using sqlite and MySQL

    Some ways to export the data for SQL databases

    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

    Variations of the Sorted Guestbooks:

    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 ).

    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 ...

    Using JavaScript Includes and SVG for Scope Trace analysis

    Using the idea, it is possible to include data into other pages to analyse data.

    A C program gets data from a scope and saves it in files that can be included into a page to analyse data. The page could reload every few seconds.

    Not working inline yet but click on the links below:

    Scope - iic : Scope - iic

    Scope - RS232 @ 9600 : Scope - RS232 @ 9600

    Scope - RS232 @ 9600 : Scope - RS232 @ 9600

    Arduino Logger : Arduino Logger info

    Arduino Logger : Arduino Logger graph.

    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. This did not work very well.

    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


    I wrote this essay for the TCN, who gave me a special commendation prize.

    Community Groups communicate using the Web - A need for a simple booking system on the web.

    my Essay (MS word 97 )

    Essay1v2.htm


    IOT dabbles:

    IOT: IOT| Simple TCP/IP examples | relayIOTprototype

    Inline DIV

    Use JavaScript to read text and wrap HTML tags around it.

    <div id="gifs">
    biled0.gif
    biled1.gif
    biled2.gif
    biled3.gif
    dnld.gif
    dnlda.gif
    </div>
    
    <script>
    function showImages(){
      if (document.getElementById){
          gifs = document.getElementById( "gifs" ).innerHTML
    	  /* split the list into an array */
          gifsA = gifs.split("\n")
          var opStr = ""
    	  for( var i = 0 ; i < gifsA.length ; i++ ){
    	    opStr += "<br><img src="+gifsA[i]+">"
          }  
          document.getElementById( "gifs" ).innerHTML=opStr
      }
    }
    showImages()
    
    biled0.gif biled1.gif biled2.gif biled3.gif dnld.gif dnlda.gif

    Data

    values

    Graphs - using canvas -

    Use a canvas for a simple graph

    function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){  
      values = userfield1
    }
    
    // test call
    gbF( "Test Call1","email","15 Nov 2003","IPaddress","5,20,15,10,12,15,16,2,5,5,8,9,8,20,30,40,50","userfield2","userfield3","userfield4","Testcomments")
    
    graph( "myCanvasBar",  values ,"bar"  )
    graph( "myCanvasLine", values ,"line" )
    graph( "myCanvasStep", values ,"step" )
    

    do view source to see the code:-