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

What seems like a trivial problem, has had me stumped for nearly 24 hours already. Not only that, but without any proper documentation (the CGI.pm perldoc doesn't help much), I'm about ready to start pulling out hairs (furthermore, I hate posting seemingly easy problems to this great board... oh well). What I'm trying to do is open an uploaded file for reading using an HTML form. Here's what happens on the server though: I can only read the file when it's already there!! That is, if I actually just copy my test file into the appropriate folder on the server, my script has no probs munching it up, but for some reason, it won't do it with an uploaded file using the form. What this means (I think), is that there's a problem with the way my code handles the upload. Here's a snippet of the relevant parts:
my $filename = $q->param("file"); my @data_from_file = get_file_data($filename); sub get_file_data { my ($filename) = @_; open (INPUTFILE, UPLOAD_DIR . $filename) || die "Can't open $filename" +; my @data_from_file; while (<INPUTFILE>) { push @data_from_file, $_; } close (INPUTFILE) || die "Can't close $filename"; unlink (UPLOAD_DIR . $filename) || die "Can't delete $filename"; return @data_from_file; }
Any ideas? The server logs show no errors by the way, nor does my debugger. Also, I happenned to come over some code that recommended using the upload() function instead of param(). I tried that (perhaps incorrectly though), and it didn't work either. I would be greatful for any comments! I love you guys! :)

Replies are listed 'Best First'.
•Re: A trivial CGI.pm problem...
by merlyn (Sage) on Nov 11, 2003 at 17:49 UTC
    Why are you doing it that way instead of the way shown on the manpage? The $filename is usable as-is. Don't prefix it with an additional path. It's also already open as a filehandle, and can be used directly unless you've also use stricted. Or use the upload function, as indicated:
    $fh = $query->upload('uploaded_file'); while (<$fh>) { print; }

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: A trivial CGI.pm problem...
by clscott (Friar) on Nov 11, 2003 at 18:27 UTC

    The CGI documentation should help you out perfectly.

    Read it carefully and mind everything it says like:
    1. Make sure that your form has the correct enctype e.g enctype='multipart/form-data'
    2. The filename (aka $q->param("file") ) acts as both a scalar ( the filename on the client filesystem ) and a file handle ( to the temporary file on the web server)

    This second part seems to be the part you are missing

    When I had to do file upload for the first time a few weeks ago it worked perfectly.

    #$data_from _file = get_file_data( $q->upload('file') ); sub get_file_data { my $filehandle = shift; my ($data, $buffer, $bytesread); while ($bytesread=read($filehandle,$buffer,1024)) { $data .= $buffer; } return $data; }
    --
    Clayton
      Hopefully this reply will be seen by a few people.

      Thanks everyone for the help. The code cleanup was useful. Randal, since I've use stricted, I used the upload() function instead as you suggested. I also took clscott's code for reference and tried to reproduce it. Still no go however. Allow me to give everyone some more information on my test systems, and then I'll explain what I think is happening.

      Test System: WinXP running Apache2, ActiveState Perl 5.8.0 and I use ActiveState's wonderful Komodo 2.5 for coding/debugging.

      Server System: not my own, but it's Sun Solaris v.something, with Perl 5.6.1, and Apache2.

      Notable behaviours: upload doesn't work on the test system, or on the server system. However, it DOES work when I run the script with Komodo (the CGI environment is emulated at runtime with posts/uploads etc, which work perfectly).

      Some background on the script: the HTML form has 3 inputs. A single-line text field, a multi-line text field, and the upload file field. A $var = $q -> param('fieldname'); is never undef if the field is filled (or the file is uploaded). The filehandle (using the upload function) is also defined throughout the script. Here's where things get funny though. I noticed that at some point (with Perl 5.6.1) I was getting "Use of uninitialized value in join or string at (eval 10) line xx" errors (as well as uninitialized variable errors in CGI.pm). My research led me to the conclusion that CGI.pm had a bug in it (fixed since v2.88) where, if Perl were run under taint mode, file uploads wouldn't work. So I installed CGI.pm v2.98 (the latest version), and this time I get no errors, but the script still doesn't work.

      There's a pattern though. The script doesn't only fail on the file upload. It also fails on the following:

      my $form_accession_number = $q->param('accession'); my $gb_obj = new Bio::DB::GenBank(); $gb_obj = $gb_obj->get_Seq_by_acc($form_accession_number); my $input_seq = $gb_obj->seq();
      $input_seq is undef (though it shouldn't be). By the way, this code snippet works in the debugger. Where the script doesn't fail is on the multi-text field, but I use the value straight off the bat.

      My suspicions: I suspect this problem must have something to do with the way Perl or these modules deal with methods. Like before, I'm completely stumped. Someone in another thread for a similar problem suggested using functions as class-methods... would this work??

Re: A trivial CGI.pm problem...
by Anonymous Monk on Nov 11, 2003 at 17:49 UTC
    param returns a filehandle for an upload field:
    my $upload = param('file'); my $data = do { local $/; <$upload> };
    Really no need to try to reopen it from the filename.