# FILE: cgi-utils.pl # DESCRIPTION: # This is a library of useful perl cgi scripting routines. # It's intended for perl4. For perl5 (recommended), use # CGI.pm, located at: # http://www-genome.wi.mit.edu/ftp/pub/software/WWW/ # AUTHOR: Lincoln Stein (lstein@genome.wi.mit.edu) # Function descriptions: # get_query() # Returns the user's query as an array. # Usage: # @keywords = &get_query; # -or- # %parameters = &get_query; # For keyword list searches in the form "key1+key2+key3" # this function returns an array of the unescaped search # terms. # For parameter lists in the form "param1=val1¶m2=val2" # this function returns an associative array. Each parameter # becomes a key in the array. If the same parameter # appears multiple times in the query, the multiple values # will be stored as a packed array separated by the perl # $; character. For example, if the query string is # "sports=tennis&sports=hockey&sports=golf®ion=NW" # then the value of sports can be obtained with # %param = &cgi'get_query; # @sports = split($;,$param{'sports'}); # This function works for both GET and POST scripts. For # debugging scripts offline, you can also place search terms # on the command line or submit them in standard input. In the # latter case, you can separate parameter/value pairs by # newlines, as in: # sports=tennis # sports=hockey # region=NW # cgi'unescape # Translates escape codes back into the original characters. # Usage: # $unescaped = &cgi'unescape($encoded) # cgi'escape # Translates funny characters into escape sequences. # Usage: # $escaped = &cgi'escape($original) package cgi; sub main'get_query { local($query_string); local(@lines); local($method)=$ENV{'REQUEST_METHOD'}; # See whether # If method is GET or HEAD, fetch the query from # the environment. if ($method=~/^(GET|HEAD)$/) { $query_string = $ENV{'QUERY_STRING'}; # If the method is POST, fetch the query from standard # input. } elsif ($method eq 'POST') { read(STDIN,$query_string,$ENV{'CONTENT_LENGTH'}); # If neither is set, assume we're being debugged offline. # Check the command line and then the standard input for data. } elsif (@ARGV) { $query_string = "@ARGV"; # massage it back into standard format $query_string=~tr/ /&/ if $query_string=~/=/; } else { # fetch from standard input chop(@lines = <>); # remove newlines # massage back into standard format if ("@lines" =~ /=/) { $query_string=join("&",@lines); } else { $query_string=join("+",@lines); } } # No data. Return an empty array. return () unless $query_string; # We now have the query string in hand. We do slightly # different things for keyword lists and parameter lists. return &parse_params($query_string) if $query_string =~ /=/; return &parse_keywordlist($query_string); } sub unescape { local($todecode) = @_; $todecode =~ tr/+/ /; # pluses become spaces $todecode =~ s/%([0-9A-Ha-h]{2})/pack("c",hex($1))/ge; return $todecode; } sub escape { local($toencode) = @_; $toencode=~s/([\W])/sprintf("%%%x",ord($1))/eg; return $toencode; } # -------------- semi-private subroutines ----------------- sub parse_keywordlist { local($tosplit) = @_; $tosplit = &unescape($tosplit); # unescape the keywords $tosplit=~tr/+/ /; # pluses to spaces local(@keywords) = split(/\s+/,$tosplit); return @keywords; } sub parse_params { local($tosplit) = @_; ## changed & to [&;] to adhere to the recommendation ## in RFC 1866 section 8.2.1 TC / 30 july 1998 local(@pairs) = split(/[&;]/,$tosplit); local($param,$value,%parameters); foreach (@pairs) { ($param,$value) = split('='); $param = &unescape($param); $value = &unescape($value); unless ($parameters{$param}) { $parameters{$param} = $value; } else { $parameters{$param} .= "$;$value"; } } return %parameters; } 1; # so that require() returns true