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

I have an issue trying to use the upload method from CGI.pm from a package other than main.

From the CGI docs:
If you create the CGI object in one package e.g. "main") and then obtain the filehandle in a different package (e.g. "foo"), the filehandle will be accessible through "main" but not "foo".

An outline of what I am currently doing:
in Foo.cgi:

use Bar; use CGI; our $q = CGI->new(); Bar::do_stuff(\$q);
and then in Bar.pm:
sub do_stuff { # the issue is here my $uf = $main::q->upload($fh); open (FH, "> $uld/$name") while (<$uf>) {print FH}; close(FH); return; }
This works, however since I would like 'Bar.pm' to be a general-purpose module, I would prefer not to have to refer to 'main::q' being that the CGI object may not always be named '$q'. Any thoughts would be greatly appreciated.

Replies are listed 'Best First'.
Re: Yet Another CGI File Upload Question
by BUU (Prior) on Aug 01, 2003 at 23:10 UTC
    Either have Bar.pm create it's own CGI object ( I forget whether or not CGI is a Singleton and so would have multiple objects access the same param code ) or just pass in a cgi object, either when you load it or when you call the func:
    use CGI; my $c = new CGI; use Bar ($c); Bar::do_stuff(); package Bar; my $cgi; sub import { $cgi = $_[1]; } sub do_stuff { $cgi->foo; #etc }

      You can only really call new() once with either CGI.pm or CGI::Simple.pm and probably all the rest of the CGI:: modules.

      REASON: You have to parse the query string with a GET (you can do this over and over) BUT with POST you are reading from STDIN - once you read the data it is GONE so your new objects will exist OK, but they will have no data in them if it was a POST as STDIN will be NULL after the first instantiation.

      cheers

      tachyon

      s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Yet Another CGI File Upload Question
by tachyon (Chancellor) on Aug 02, 2003 at 11:41 UTC

    You don't have to refer to $main::q. You have a ref to the object that works fine across packages.

    package Foo; use CGI; my $q = CGI->new(); # file upload (read from STDIN occurs at this poi +nt Bar::do_stuff(\$q); package Bar; sub do_stuff { my $q_ref = shift; my $uf = $$q_ref->upload(.....

    In fact the object contains most of the data, everything except the actual file contents. The file contents are stored in a temp file the moment you call new() and the $q or whatever object just contains a pointer to it. The upload() method simply looks in the $q object to find out where the file is, what it is called, opens a FH on it and gives it back to you....

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Yet Another CGI File Upload Question
by sgifford (Prior) on Aug 02, 2003 at 09:17 UTC
    I believe that the code you have will work fine. According to the documentation, the problem comes into play if you get a file handle with $q->param($fh), which is why $q->upload($fh) was introduced. You're using the upload method, so you should be fine. According to the documentation:
    To be safe, use the upload() function (new in version 2.47). When called with the name of an upload field, upload() returns a filehandle, or undef if the parameter is not a valid filehandle.
    $fh = $query->upload('uploaded_file'); while (<$fh>) { print; }
    This is the recommended idiom.

    Of course, you still need to get your CGI object into do_stuff, but that's easy---pass it as a parameter. In fact, you're already doing that (using \$q is unnecessary---$q is already a reference), so just using the passed parameter in your sub should solve this.