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

I am rewriting a debugging module to be object-oriented. This module makes extensive use of CGI.pm's HTML tag generation capability. As a result, it instantiates a new CGI object when my object's new() constructor is called. Unfortunately, if the calling CGI program uses the POST method to receive data, my routine's instantiation of a new CGI object will cause the data in STDIN to be read. As a result, if they create my object before a new CGI object, they lose all of their POST data!

To get around this, I try to read $ENV{'CONTENT_LENGTH'} amount of data from STDIN if the POST method is used. If read any data, I kill the program telling the user that they need to instantiate a new CGI object before they instantiate a debugging object. Here's the code:

sub new { my $class = $_[0]; my $buffer; if ( $ENV{'REQUEST_METHOD'} eq 'POST' ) { read (STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } my $cgi = CGI->new(); if ( length $buffer ) { print $cgi->header( "text/plain" ) . "Data was read from STDIN while using the POST method.\n +" . "You must instantiate a new CGI::DebugVars object AFTER\ +n" . "instantiating a CGI object."; exit; } my $objref = { _active => 1, _border => 1, _continue => 0, _cgi => $cgi, _pretty_not_installed => 0 }; bless $objref, $class; return $objref; }
My problem is that it seems like a very ugly hack. I'm really not testing to see if a CGI object already exists, I'm inferring its existence from the presense of data available in STDIN. Is there a clean way to determine if the user has already instantiated a CGI object (short of searching through the packages for one)?

I'm also wondering if it's possible that other data may be available through STDIN in a CGI script? Since my routine reads that data, it will cause a problem for the end-user's code.

Cheers,
Ovid

Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

Replies are listed 'Best First'.
RE: CGI object already instantiated?
by Dominus (Parson) on Nov 13, 2000 at 00:36 UTC
    You're doing way too much work. The CGI::new method will only read the POST data by default. If you specify another source of data, it won't read the POST data at all.

    Try this:

    my $cgi = CGI->new({});

    This tells CGI to make a new query object using the data from the anonymous hash you passed. Since there isn't any data, you get a new, empty query.

    See the documentation for the CGI::new method for more complete information.

      It's also amazing how I could use the wrong browser and fail to log in.

      The new "Mark Dominus Approved" ;) method:

      sub new { my $class = $_[0]; my $cgi = CGI->new({}); my $objref = { _active => 1, _border => 1, _continue => 0, _cgi => $cgi, _pretty_not_installed => 0 }; bless $objref, $class; return $objref; }
      Much simpler, much easier, no headaches. Thanks!

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

      Gah! It's amazing how simple that was. Thanks!

      Cheers, Ovid

(tye)Re: CGI object already instantiated?
by tye (Sage) on Nov 13, 2000 at 00:32 UTC

    Two ideas. First, $INC{"CGI.pm"} won't be set until someone has done something like require CGI. So this might give you a false positive if someone has done require CGI and not use CGI but that seem pretty unlikely.

    Second, you could check if %CGI::EXPORT is empty. It appears to me that just about any flavor of use CGI will put values into %CGI::EXPORT.

    Between the two, I'd use the first one since it doesn't depend on how CGI.pm is implemented and I can't think of any reason to only require CGI.

            - tye (but my friends call me "Tye")