home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 27 / IOPROG_27.ISO / SOFT / PERLPAD3.ZIP / PERLPAD3.CAB / Web.ppm < prev    next >
Encoding:
Text File  |  1999-02-06  |  10.3 KB  |  360 lines

  1. Web Functions
  2. Author: Dion Almaer (dion@member.com)
  3. package Web;
  4. require 5.000;
  5. require Exporter;
  6. use FileHandle;
  7.  
  8. @ISA    = qw(Exporter);
  9. @EXPORT = qw(html DebugHTML ErrorHTML Header DieHandle
  10.              ParseForm ParseMulti SendFile ThisURL);
  11.  
  12. use strict;
  13. my $template_dir = $main::VAR{'templates'} || '/www/templates';
  14. $Web::header     = 0;
  15.  
  16. # -----------------------------------------------------------------------
  17. # Subroutine: html  -  Runs through a template sub'in ~variable~
  18. # -----------------------------------------------------------------------
  19. sub html 
  20. {
  21.     my $template = shift || die "No Template File given";;
  22.     my $OH       = shift || \*STDOUT;
  23.     my $delim    = shift || $Web::delim || '~';
  24.  
  25.     #
  26.     # since this is called recursively, we need unique filehandle names
  27.     #
  28.     my $IH = new FileHandle "<$template";
  29.  
  30.     # make sure it exists please :)
  31.     unless (defined($IH)) { &ErrorHTML("Couldn't open $template"); }
  32.  
  33.     #
  34.     # use non-buffered output
  35.     #
  36.     my ($oldfh) = select(STDOUT); $| = 1; select($oldfh);
  37.     #
  38.     # turn relative ref into absolute ref
  39.     #
  40.     $template = "$template_dir/$template" unless $template =~ m.^/.;
  41.  
  42.     if ($::READING{$template} == 1) {
  43.     return 0;                     # avoid infinite loop
  44.     } else {
  45.     $::READING{$template} = 1;
  46.     }
  47.  
  48.     while (<$IH>){
  49.     #
  50.     # implement #include directive in templates
  51.     #
  52.     if (/^\#include \s*(.*\S)\s*$/i){
  53.     #if (/#include (file=|virtual=)?\s*(.*)/i){ # implements SSI
  54.         my $file = $2;
  55.         #$file =~ s/-->$//g;                      implements SSI
  56.         $file =~ s/\"//g;
  57.  
  58.             if ($OH) {
  59.               &html($file, $OH);
  60.             } else {
  61.               &html($file);
  62.             }
  63.         next;
  64.     }
  65.     s/$delim([^$delim]+)$delim/$main::VAR{$1}/g;
  66.         s/$delim{2}/$delim/g;
  67.     print $OH $_;
  68.     }
  69.     delete $::READING{$template};
  70.     close $IH;
  71.     1;
  72. }
  73. # END of html
  74. # -------------------------------------------------------------------------
  75.  
  76. # -------------------------------------------------------------------------
  77. # Subroutine: Header - print the content-type header arg = mime|text/html
  78. #                      sets $Web::header = 1 to show that a header is there
  79. # -------------------------------------------------------------------------
  80. sub Header
  81. {  
  82.    my $type = shift || 'text/html';
  83.    print "Content-type: $type\n\n" unless $Web::header++;
  84. }
  85.  
  86. # -----------------------------------------------------------------------
  87. # Subroutine: ErrorHTML  -  Print out the Error to the Web Page :)
  88. # -----------------------------------------------------------------------
  89. sub ErrorHTML 
  90. {
  91.    my ($error, $exit) = @_;
  92.    &Web::Header;
  93.    print "<H1>$error</H1>\n";
  94.    exit if $exit;
  95. }
  96. # END of ErrorHTML
  97. # -------------------------------------------------------------------------
  98.  
  99. # ----------------------------------------------------------------------------
  100. # Subroutine: DebugHTML - Print out the given message
  101. # ----------------------------------------------------------------------------
  102. sub DebugHTML
  103. {  
  104.    my $msg   = shift or die 'No Message given to DebugHtml';
  105.    my $exit  = shift;
  106.  
  107.    &Header;
  108.    print "$msg\n";
  109.    exit if $exit;
  110. }
  111.  
  112. # ----------------------< Function: ParseForm() >------------------------- #
  113. # Parse the INPUT from a <FORM> to produce $FORM{name} = value;
  114. # ------------------------------------------------------------------------ #
  115. sub ParseForm
  116. {
  117.    my ($check) = @_;
  118.    my ($pair, @pairs, $input, $name, $value);
  119.  
  120.    # Check the METHOD used on the form
  121.    # POST: read input from STDIN
  122.    # GET : use the query string
  123.  
  124.    # Put all the input into $input
  125.    if($ENV{'REQUEST_METHOD'} eq "GET") {
  126.        $input = $ENV{'QUERY_STRING'};
  127.    } else {
  128.        read(STDIN, $input, $ENV{'CONTENT_LENGTH'});
  129.    }
  130.  
  131.    &CheckInput($input) unless $check;
  132.  
  133.    # Now we have the raw data lets split it at the "&"
  134.    @pairs = split(/&/, $input);
  135.  
  136.    # Now lets get an array, indexed by the variable name w/ the values
  137.  
  138.    foreach $pair (@pairs)
  139.    {
  140.      $pair =~ tr/+/ /;                     # Change the "+"'s to " "
  141.  
  142.      ($name, $value) = split(/=/, $pair);  # Split name=value into 2 pieces
  143.  
  144.      $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # %xx -> Hex
  145.  
  146.      if ($main::FORM{$name}) {
  147.         $main::FORM{$name} .= "\0$value";     # Create the Associative Array
  148.      } else {
  149.         $main::FORM{$name} = $value;          # Create the Associative Array
  150.      }
  151.    }
  152.    return %main::FORM;
  153. }
  154. # --------------------------< End ParseForm() >--------------------------- #
  155.  
  156. # ----------------------< Function: ParseMulti() >------------------------ #
  157. # Parse the INPUT from a MULTIPART <FORM> to produce $FORM{name} = value;
  158. # ------------------------------------------------------------------------ #
  159. sub ParseMulti 
  160.     my (%FORM, $input, @input, $delim, @file, $varname);
  161.  
  162.     # Read in ALL the input
  163.     read(STDIN, $input, $ENV{'CONTENT_LENGTH'});
  164.     @input = split("\r\n", $input);
  165.  
  166.     $delim = shift @input;
  167.  
  168.     print "<PRE>Input<BR>$input</PRE><BR>" if $Web::DEBUG;
  169.  
  170.     foreach (@input) 
  171.     {
  172.         if( /Content-Disposition:.+?name="([\w\d\.]+)";\s+filename="(.*)"/i ) {
  173.             $varname=$1;
  174.             $FORM{$varname.'-filename'} = $2; #filename
  175.         } elsif ( /Content-Disposition:.+?name="([\w\d\.]+)"/i ) {
  176.             $varname = $1;
  177.         } elsif ( /Content-Type/i ) { # Ignore 
  178.             next;
  179.         } elsif( /$delim/ ) {
  180.             while($FORM{$varname} ) { $varname .= '0'; } ##ensures unique name
  181.             my $i; 
  182.             for($i=1; $i < scalar(@file); $i++) { #skip the first one $i=1
  183.                 my $a = $file[$i];
  184.                 if( $i== @file - 1) {
  185.                     $FORM{"$varname"} .= $a;
  186.                 }else{
  187.                     $FORM{"$varname"} .= "$a\r\n";
  188.                 }
  189.             }
  190.             undef @file; #reset @file for new variable
  191.         } else {
  192.             push(@file, $_);
  193.         }
  194.     }
  195.     ###now get form vars from query_string
  196.     return %FORM;
  197. }
  198. # --------------------------< End ParseMulti() >-------------------------- #
  199.  
  200. # ----------------------------------------------------------------------------
  201. # Subroutine: SendFile - Given a filename on the system it sends it to the user
  202. #            NOTE: This function must be called before any headers are printed!
  203. # ----------------------------------------------------------------------------
  204. sub SendFile 
  205. {
  206.     my $name  = shift;
  207.     local($/) = undef;
  208.  
  209.     open (FILE, $name) 
  210.         || return "Cannot open file '$name' for input because of $!";
  211.     print "Content-Type: application/octet-stream\n";
  212.     print "Content-Disposition: inline;filename=$name\n\n";
  213.     binmode(FILE);   ##I think this binmode stuff allows function to work
  214.     binmode(STDOUT); ##on WinNT/Win95
  215.     select(STDOUT);
  216.     $|=1;
  217.     print <FILE>;
  218.     close FILE;
  219.     return;
  220. }
  221.  
  222. # -----------------------< Function: CheckInput() > ---------------------- #
  223. # Check for NULL Input and if so exit with a HTML Error                    #
  224. # Usage: CheckInput($string)                                               #
  225. # ------------------------------------------------------------------------ #
  226. sub CheckInput 
  227. {
  228.    my($input) = @_;
  229.  
  230.    if ($input eq "") 
  231.    {
  232.      my $thisurl = &ThisURL;
  233.  
  234.    print <<"EOF";
  235. Content-type: text/html
  236.  
  237. <HTML>
  238. <HEAD>
  239. <TITLE>Error - No Form Used</TITLE>
  240. </HEAD>
  241. <BODY>
  242. <H1 align=center>Please use the HTML FORM Provided</h1>
  243. This program has been accessed without a valid query string.  
  244. Please use the associated FORM at 
  245. <A HREF="$thisurl">$thisurl</A>
  246. <P>
  247. </BODY>
  248. </HTML>
  249. EOF
  250.  
  251.    exit(1);
  252.    }
  253. }
  254.  
  255. # -------------------------< End CheckInput() >--------------------------- #
  256.  
  257. # -----------------------< Function: ThisURL() >-------------------------- #
  258. # Return the Address of the CGI                                            #
  259. # ------------------------------------------------------------------------ #
  260. sub ThisURL {
  261.   return 'http://' . $ENV{'SERVER_NAME'} . $ENV{'SCRIPT_NAME'};
  262. }
  263. # --------------------------< End ThisURL() >----------------------------- #
  264.  
  265. # ----------------------------------------------------------------------------
  266. # Die Handling  -  if program dies it will print happy thoughts
  267. # ----------------------------------------------------------------------------
  268. sub DieHandle {
  269.   $SIG{"__DIE__"} = sub {
  270.       my $why = shift;
  271.     chomp $why;
  272.     &Web::Header;
  273.     print "ERROR: $why\n";
  274.     exit 0;
  275.   }
  276. }
  277.  
  278. 1; # Return TRUE to show that mr.require worked :)
  279.  
  280. __END__
  281.  
  282. =head1 NAME
  283.  
  284. Web.pm - Module for CGI processing
  285.  
  286. =head1 DESCRIPTION
  287.  
  288. This module holds routines for processing Web pages
  289.  
  290. =head1 FUNCTIONS
  291.  
  292. o B<ParseForm>($dontcheck)
  293.  
  294.   Returns a hash of $FORM{name} = value; from a html <FORM>
  295.   (e.g. where <INPUT NAME=name VALUE=value>)
  296.  
  297.   If $dontcheck is true then it won't check for input to the
  298.   script
  299.  
  300. o B<ParseMulti>
  301.  
  302.   Same as ParseForm, but it parses a multipart document 
  303.   (e.g. <FORM ENCTYPE="multipart/form-data">)
  304.   You would use this if you were uploading files etc.
  305.  
  306. o B<html>($template, $outputhandle, $delimiter)
  307.  
  308.   This function runs through the template html file and 
  309.   replaces any variables within the delimiter and
  310.   outputs the result to the output handle. It replaces
  311.   ~foo~ with $::VAR{foo} (if ~ is the delimiter)
  312.  
  313.   $template = html file w/ the delimited special variables
  314.   $outputhandle = defaults to STDOUT but can be routed to a 
  315.                   file
  316.   $delimiter = text between 2 delimiters are replaced, 
  317.                defaults to ~
  318.  
  319. o B<Header>($mimetype)
  320.  
  321.   This function will print the Content-type header unless
  322.   if has already done so.
  323.  
  324. o B<SendFile>($filename)
  325.  
  326.   Given a filename this function sends a file to the user. 
  327.  
  328. o B<DebugHTML>($msg, $exit)
  329.  
  330.   This function prints out $msg to STDOUT. 
  331.   it will exit if $exit is true.
  332.  
  333. o B<ThisURL>
  334.  
  335.   Simply returns the URL of the script that called this function
  336.  
  337. o B<CheckInput>
  338.  
  339.   If no input has been given to the script this function will print
  340.   out an error message and quit
  341.  
  342.  
  343. =head1 EXAMPLE
  344.  
  345.   use Web;
  346.  
  347.   %::VAR = &ParseForm;
  348.  
  349.   &Header;
  350.   &html('/www/foo.html');
  351.  
  352.  
  353.   The above script would take in data from a form and replace the 
  354.   the variables it got with ones in the template and print
  355.   to STDOUT
  356.  
  357.  
  358.  
  359.