BR's crystallographic computing tutorials


By Bernhard Rupp
 

CGI scripting - this page now available in Serbo-Croatian and a Hungarian translation courtesy of Zsolt Boros

There is a little CGI script that decodes a space group. Just enter a valid space goup symbol or a spacegroup number (1-230) and voila! here we go:

Enter a spacegroup or spacegroup number and hit enter

 Cool, isn't it? So how does it work?

Introduction

The web pages you actually see are the client side of a client-server connection through the internet. If your browser (the client) wants to see a web page, for example, it sends a request to the host you specify in the URL (Uniform Resource Locator) using the specified protocol (HTTP in this case, Hyper Text Transfer Protocol). Example for a URL : http://www.ruppweb.org/default.htm (protocol://site.domain/document). The site name is nothing but a name assigned to the IP address of the machine (example 128.115.150.112) running the (web) server. (NOTE : in this context the server is a program running the web service on the machine, not the computer itself - the computer is the host).

When the server receives such a request, it responds and sends back a page, or whatever the request was for. The language in which the server and client communicate is HTML (Hyper Text Markup Language). Beyond static requests for web pages, one may want the server to execute a certain task (such as searching a data base or decode a space group). There must be a mechanism for the server to receive information about what to do and to hand it down to the application that handles the request. This interface is the CGI (Common Gateway Interface). The server essentially sets certain system environment variables, which the called program can read and process. The output is passed back to the server forwarding it through the internet to the requesting browser which displays the result. You may want to check out the Microsoft Internet Development CD or the other references for more information on the subject.

Example

In this web page I used following script to create the input box and define the action to be taken :

<form action="/cgi-bin/sexie32.exe" method="GET">
  <p>Enter a spacegroup or spacegroup number 
  <input type="text" size="11" name="spcgrp"> 
  and hit enter</p>
</form>

This minimal code creates the above input box, assigns the input to the variable named 'spcgrp' and executes the program sexie32 which does the job. How do I get the space group variable into the program? By specifying GET as method, the server adds the variable name and its contents after a question mark to the program name and stores this string in an environment variable QUERY_STRING. All the program does is read this environment variable string, decode it, and after the calculation, write the result as an HTML file to the standard output (console) which the server redirects to the requester. Most scripting languages provide libraries and one does not have to deal with the details of reading the system environment.

FORTRAN

As scientists, we may have a useful program in FORTAN that does a nice job and it would be desirable to make it available on the web. The obvious benefit is that you do not have to deal with platform and implementation issues - no unvalidated version proliferation, no source code mess etc - the application runs on your host computer, and the browsers take care of the platform specific implementation. All of a sudden your old F66 code has a graphical windows interface!

Subroutine WEBSPC reads the environment variables and returns the spacegroup string to the main routine :

       subroutine webspc (spcgrp,title,igr,ierr)                         WEBS0001
c ----------------------------------------------------------------------WEBS0002
c     returns space group passed from web server through GET method     WEBS0003
c ----------------------------------------------------------------------WEBS0004
      USE MSFLIB                                                        WEBS0005
      integer*4 lstr                                                    WEBS0006
      integer igr(36)                                                   WEBS0007
      character today*24,spcgrp*10,title*60,usradd*15,fname*60,qstr*80  WEBS0008
      character usrnam*80,browsr*80                                     WEBS0009
                                                                        WEBS0010
c --- Set spacegroup blank                                              WEBS0011
      spcgrp='          '                                               WEBS0012
      ierr=0                                                            WEBS0013

Here is how to read the environment variables which were set by the server according to the action instructions in the HTML code fragment above. You'll find a listing of other variables that are set in most books on web programming (some of them are read by webspc as well). The key is QUERY_STRING which contains the variable part of the URL constructed by the action listed above:

http://ruppweb.dyndns.org/cgi-bin/sexie32.exe?spcgrp=I+4%2Fm+m+m

QUERY_STRING contains: spcgrp=I+4%2Fm+m+m (NOTE: if you enter the URL above or click it, the CGI script will actually be executed). Notice also that the CGI interface substitutes blanks with + signs and special characters with their hexadecimal code preceeded by a % sign (e.g., the slash is %2F). The actual input string in the box was 'I 4/m m m' in this case.

                                                                        WEBS0014
c --- get the client name and the query_string from environment         WEBS0015
      ladd = GETENVQQ('REMOTE_ADDR', usradd)                            WEBS0016
      lnam = GETENVQQ('REMOTE_USR', usrnam)                             WEBS0017
      lbrs = GETENVQQ('HTTP_USER_AGENT', browsr)                        WEBS0018
      lstr = GETENVQQ('QUERY_STRING', qstr)                             WEBS0019
                                                                        WEBS0020
c --- read space group - if an integer decode by number                 WEBS0021
      read(qstr,'(7x,i3)',err=0001) ispa                                WEBS0022
c --- if we get here, it was read successfully as a number              WEBS0023

Note that I use the error label when reading the symbol as a integer to distinguish whether a space group symbol or a space group number was entered.

      call spsymc (spcgrp,ispa)                                         WEBS0024
c --- ispa returns the symbol now proceed with checks                   WEBS0025
      goto 2002                                                         WEBS0026
                                                                        WEBS0027
c --- parse the input string if not a number                            WEBS0028
0001  continue                                                          WEBS0029
      ilen=lstr-7                                                       WEBS0030
      j=0                                                               WEBS0031
c --- begin loop over query_string                                      WEBS0032

Notice that the CGI interface substitutes blanks with + signs and special characters with hexadecimal code preceeded by a % sign (e.g., / is %2F), so we need to parse that string:

      i=8                                                               WEBS0033
1000  continue                                                          WEBS0034
c ---    replace + with blank                                           WEBS0035
         if (qstr(i:i).eq.'+') then                                     WEBS0036
            j=j+1                                                       WEBS0037
            spcgrp(j:j)=' '                                             WEBS0038
            i=i+1                                                       WEBS0039
c ---    replace special character hex code with character              WEBS0040
         else if (qstr(i:i).eq.'%') then                                WEBS0041
c ---       %2F is slash                                                WEBS0042
            if (qstr(i+1:i+2).eq.'2F') then                             WEBS0043
               j=j+1                                                    WEBS0044
               spcgrp(j:j)='/'                                          WEBS0045
               i=i+3                                                    WEBS0046
            end if                                                      WEBS0047
         else                                                           WEBS0048
            j=j+1                                                       WEBS0049
            spcgrp(j:j)=qstr(i:i)                                       WEBS0050
            i=i+1                                                       WEBS0051
         end if                                                         WEBS0052
c --- repeat until finished with string                                 WEBS0053
      if (i.lt.(ilen+8)) goto 1000                                      WEBS0054
                                                                        WEBS0055
c --- now check if a valid space group symbol                           WEBS0056
 2002 call upstrg(spcgrp,10)                                            WEBS0057
      read(spcgrp,'(10a1)') (igr(i), i=1,10)                            WEBS0058
      ispa=0                                                            WEBS0059
      call spsymc (spcgrp,ispa)                                         WEBS0060
                                                                        WEBS0061
c --- get a date string, format is :Wed Nov 20 15:33:29 1996            WEBS0062
      call fdate (today)                                                WEBS0063
      title='Webjob on '//today(1:10)//today(20:24)//' at'//            WEBS0064
     & today(11:19) //' from '//usradd                                  WEBS0065

The program also keeps a log of the users.

c --- log the job                                                       WEBS0066
      fname='C:\inetsrv\wwwroot\webjobs.html'                           WEBS0067
      open (66,file=fname,access='append',position='append')            WEBS0068
c --- overwrite old </body> tag                                         WEBS0069
      backspace (66)                                                    WEBS0070
      write(66,'(a,a,a)')' <p>Date   : '//today//'<br>'                 WEBS0071
      write(66,'(a,a,a)')' Client : '//usradd(1:ladd)//'<br>'           WEBS0072
      write(66,'(a,a,a)')' Browser : '//browsr(1:lbrs)//'<br>'          WEBS0073
      write(66,'(a,a,a)')' Spacegr: '//spcgrp//'<br>'                   WEBS0074
      if (ispa.lt.0) then                                               WEBS0075
         write(66,'(a)')' Status : failed!</p>'                         WEBS0076
      else                                                              WEBS0077
         write(66,'(a)')' Status : ok</p>'                              WEBS0078
      end if                                                            WEBS0079
      write(66,'(a)')    ' <hr>'                                        WEBS0080
      write(66,'(a)')    ' </BODY>'                                     WEBS0081
      close(66)                                                         WEBS0082
c --- if something went wrong, return message and termination signal    WEBS0083
      if (ispa.lt.0) then                                               WEBS0084
         call webtxt (1,spcgrp)                                         WEBS0085
         ierr=1                                                         WEBS0086
         close(5)                                                       WEBS0087
         return                                                         WEBS0088
      else                                                              WEBS0089
         close(5)                                                       WEBS0090
         return                                                         WEBS0091
      end if                                                            WEBS0092
      return                                                            WEBS0093
      end                                                               WEBS0094

The variable spcgrp gets returned to the main routine which decodes the space group. The output is written to a file, and all that is needed is a tiny routine to write this output as a HTML file to the standard output (console).

      subroutine htmake                                                 HTMA0001
                                                                        HTMA0002
      character*80 line                                                 HTMA0003
                                                                        HTMA0004
      open(6,file='sexie.out')                                          HTMA0005
      write(*,*)'Content-type: text/html'                               HTMA0006
      write(*,*)                                                        HTMA0007
      write(*,*)'<BODY bgcolor="#FFFDE6" TEXT="#0000FF">'               HTMA0008
      write(*,*)'<TITLE>Space group decoding</TITLE>'                   HTMA0009
      write(*,*)'<pre>'                                                 HTMA0010
      do i=1,100000                                                     HTMA0011
         read(6,'(1x,a)',end=9999) line                                 HTMA0012
         write(*,'(1x,a)') line                                         HTMA0013
      end do                                                            HTMA0014
9999  close(6)                                                          HTMA0015
      open(6,file='xyz.txt')                                            HTMA0016
      write(*,'(//a//)')                                                HTMA0017
     &  ' Alternate listing of symmetry operators follows'              HTMA0018
      do i=1,100000                                                     HTMA0019
         read(6,'(1x,a)',end=9990) line                                 HTMA0020
         write(*,'(1x,a)') line                                         HTMA0021
      end do                                                            HTMA0022
9990  close(6)                                                          HTMA0023
      write(*,*) '</pre>'						HTMA0024
      write(*,*) '</BODY>'                                              HTMA0025
      return                                                            HTMA0026
      end                                                               HTMA0027

So, that's all there is to basic CGI scripting. Just go ahead, write a little code fragment yourself and play around a little. I used Microsoft Frontpage [2] to create my site and the forms, and Microsoft FORTRAN professional edition for the F90 programming. Your FORTRAN compiler may use a different way to get the environment variables, but you should be able to find this in your documentation. Of course, this is NOT an encouragement to write CGI scripts in Fortran. The executables are bulky and full with overhead, and for many tasks, C, Pearl, J++ etc are faster. But if you have a solid peace of code, hey, why not make it useable on the web!


 References

[1] CGI developer's guide, E.E.Kim, SamsNet Publishing (1996)
[2] http://www.microsoft.com/frontpage/documents/technical11/default.htm
[3] Mastering Internet Development, Micosoft CD-ROM


Back to Introduction
This World Wide Web site conceived and maintained by Bernhard Rupp
Last revised December 26, 2009 16:40