fred has asked for the wisdom of the Perl Monks concerning the following question:

I have a web page that, for various reasons, is using multiple server side includes written in Perl. That is, the edit.shtml file contains lines similar to <!--#include virtual="/cgi-bin/edit.pl"-->;.

When I link to the page with a parameter, with something like <a href="/edit.shtml?id=200">, I would like to be able to access the id parameter in my perl script using the CGI module. However, the following code snippet fails to recognize them:

#!/usr/bin/perl -w use CGI; my $page = new CGI; my $id = $page->param("id"); print $page->header(); print "<P>ID = [$id]\n";
I would hope that it would print, "ID = [200]", and it does when I link directly to the perl script. But when its an SSI, it prints "ID = []". Is there a good way to get my parameters back short of parsing $ENV{QUERY_STRING_UNESCAPED} by hand?

Replies are listed 'Best First'.
Re: SSI losing CGI parameters
by dws (Chancellor) on Jan 25, 2001 at 22:46 UTC
    Previous stab at this revoked after an experiment with Apache.

    I didn't know that an SSI #include would actually invoke scripts, but it does with Apache. Cool.

    It appears that Apache isn't passing along the environment variables that CGI.pm needs. But there is something in the environment that you can use. I'll lead you to within sight of it, and from then on you're on your own.

    Have your test.shtml invoked the following script:

    #!/usr/bin/perl -w print "Content-type: text/html\n\n"; print "<pre>"; foreach $key ( sort keys %ENV ) { print $key, ": ", $ENV{$key}\n"; } print "</pre>\n";
    I think you'll find something sitting around in the environment that you can use. Witha little trickery, you might even be able to get CGI.pm working, though you'll have to stuff some missing stuff into the environment.

    Followup: my well-worn copy of O'Reilly's Webmaster in a Nutshell is out-of-date with respect to #exec vs. #include. Isotope's link below is authoritative (at least if you're running a current version of Apache).

      include virtual is the currently accepted way of including CGI content with SSI. Looking at my own test case, though, I see that Apache isn't populating the QUERY_STRING as expected... the query string is only available in QUERY_STRING_UNESCAPED as the author mentioned.

      Update: Reading through the Apache documentation, it looks like include virtual calls the CGI with whatever parameters you include in the SSI tag (which could include SSI variables, such as ${QUERY_STRING}. exec cgi seems to call the CGI with the environment of the requested parsed page.

      --isotope
      http://www.skylab.org/~isotope/
Re: SSI losing CGI parameters
by baku (Scribe) on Jan 26, 2001 at 01:56 UTC

    Some work-arounds:

    • Use #exec cgi,
    • If the params are known in advance, use something like #include virtual="script?id=$id&other=$other"
    • Possible, but untested: maybe use #include virtual="script?$QUERY_STRING" to pass off the query string as parsed for the X-SSI?

    The latter two assume that something like #echo var="QUERY_STRING" or #echo var="id" work in your X-SSI normally.

    What I suspect Apache is doing is giving the X-SSI "subshell" (whatever) the query, so you can do simple stuff like #echo var or #if/#else/#endif, so it doesn't propagate that to the script's environment; that gives you the ability to do #include virtual="otherscript?new-param=unrelated-value (like #include virtual="sidebar?site-section=frontdoor&style=blue") which might not depend upon the $QUERY_STRING's contents

Re: SSI losing CGI parameters
by jeorgen (Pilgrim) on Feb 02, 2001 at 13:03 UTC
    I had the same problem last week and solved it this way:

    You check the QUERY_STRING_UNESCAPED environment variable. It will contain the parameter list that is provided to the page, as opposed to the parameter list that is sent with your SSI.

    You then take away the backslashes in QUERY_STRING_UNESCAPED and force-feed it to CGI.pm (if you are using CGI.pm, that is). You may also want to check that your dealing with the same ID in the query strings, in case if you (like me) want to have several embedded cgi scripts as SSIs in one page. ID is "poll_id" in the code below:

    unless ($ENV{"REQUEST_METHOD"} eq "POST") { my $url_query_string = $ENV{'QUERY_STRING_UNESCAPED'}; $url_query_string =~ s§\\§§g; $url_query_string =~ m§poll_id\=([\d_]+)§; my $poll_id = $1; $ENV{'QUERY_STRING'}=~ m§poll_id\=([\d_]+)§; my $ssi_poll_id = $1; # if there is a dicrepancy between the two query string vars, +and # there is actually something in # ENV{'QUERY_STRING_UNESCAPED'}, it's because the cgi is calle +d as an SSI, # but with arguments on the url, # and then we want CGI to use those instead # "not $cgi_parameters" below handles if we get params from a +test harness script if ($url_query_string and $url_query_string ne $ENV{'QUERY_STR +ING'} and not $cgi_parameters and $poll_id eq $ssi_poll_id) { $cgi_parameters = $url_query_string; } } my $q = new CGI($cgi_parameters);

    /jeorgen

Re: SSI losing CGI parameters
by fred (Acolyte) on Jan 26, 2001 at 07:59 UTC

    I've verified that using #exec rather than #include does indeed solve my initial problem. There were a few caveats, but nothing I couldn't solve (though, for what it's worth, I still prefer #include).

    Although, now that I have access to my CGI parameters, I'd still like to use them in a POST method (within an SSI). However, Apache refuses to allow a POST operation to a .shtml file. That is, I want the included CGI to serve as a form handler. Apache, however, gives an error 405: resource unavailable.

    I understand that this isn't a good implementation, but I'm stuck with a lot of work that's been done on these .shtml's and the various included perl scripts. I'd rather not spend a week cutting and pasting code so that I have a true .pl script when it seem's like Apache should understand that a .shtml file can in fact handle a POST.

    So a question remains. How can I convince Apache to accept that an SSI is a valid POST target? I've scoured the web, but all I've been able to find is others with the same problem.

      If you really, really want Apache to allow POSTs to .shtml files to pass through to SSI-embedded CGI scripts, then you still have two options left open:
      1. Do it yourself. Download an Apache source tarball, and start hacking on the source until it works the way you want it to. Depending on your C skills, this might take 1-10 days.

      2. Pay someone else to do it. If you're unable or unwilling to hack Apache source yourself, consider sponsoring a project at Collab.net. Someone might take up the challenge for a few thousand dollars.

      If you're willing to retreat a bit on your desire to have Apache do something that it doesn't do out-of-the-box, then you have a third option -- one hinted at in at least one reply above: Modify your CGI scripts. Before creating a CGI object, force-feed %ENV with the variables that CGI.pm expects to find. You'll find what you need in the enviroment.