CGI and Perl

Listing 16.2. A personal notepad.

#!/usr/local/bin/perl
 $directory = "/tmp/visitors";
 use CGI::Form;
 $q = new CGI::Form;
 print $q->header();
 print $q->start_html(-title=>`A Personal Notepad');
 print "<H1>A Personal Notepad</H1>\n";
 $client=$q->cgi->var(`REMOTE_ADDR');
 if ($client eq "") {
    print "<P>Sorry, I don't know who you are. I can't continue\n";
    exit;
 } else {
    if ($q->cgi->var(`REQUEST_METHOD') eq `GET') {
       if (-e "$directory/$client") {
          ($text,$visits)=&getUserData("$directory/$client");
       } else {
          $text="";
          $visits=0;
       }
       &printForm($q,$text,$visits);
    } else {
       if ($q->param(`Action') eq "Submit") {
          ($whocares,$visits)=&getUserData("$directory/$client");
          $text=$q->param(`Text');
          $visits++;
          &setUserData("$directory/$client",$text,$visits);
       }
       &printForm($q,$text,$visits);
    }
 }
 print $q->end_html();
 sub printForm {
    my($q)=@_;
    $q->param(`Text',$text);
    print "<P>You have modified this notepad $visits times.<P>\n";
    print $q->start_multipart_form();
    print $q->textarea(-name=>`Text',-default=>$text,
                       -rows=>20,-columns=>50);
    print "<BR>";
    print $q->submit(-name=>`Action',-value=>`Submit');
    print $q->end_form;
 }
 sub getUserData {
    my($file)=@_;
    if (open(IN,"< $file")) {
       $visits=<IN>;
       $text=join(``,<IN>);
       close(IN);
    } else {
       $text="";
       $visits=0;
    }
    return($text,$visits);
 }
 sub setUserData {
    my($file,$text,$visits)=@_;
    if (open(OUT,"> $file")) {
       print OUT "$visits\n";
       print OUT $text;
       close(OUT);
    } else {
       # This is an error condition that shouldn't happen.
       # Handle it properly just the same.
       print "<P>Error! I cannot save your text. Sorry!<BR>\n";
    }
 }

This solution is probably more efficient if you need to save larger amounts of data. However, this solution can also drain your server's resources very quickly. Be sure that you have enough machine resources to handle the expected number of clients for which you'll need to maintain state. Figure 16.2 shows the personal notepad as it appears in the browser.

Hopefully, these examples will be enough to get you thinking about how you can implement your own persistent CGI sessions across multiple transactions.

Figure 16.2. The personal notepad.

Execution and Shell-Like Interfaces Using this idea of preserving session information, we can take the example further and provide a simple remote login type of shell for execution of things on the server. What we'll do in Listing 16.3 is provide a login form, and each subsequent calls to the CGI program will be a command line from which the user can remotely execute programs. This can also be accomplished within a protected directory allowing the login action to be done within the browser. You might also consider limiting the types of commands one could execute using this CGI session.