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

I'm trying to upload a file using CGI.pm and all the files are resulting in files of size 0. In fact, CGI.pm is not passing a valid file handle when using upload(). I've been fumbling with this for a while now, maybe someone else can see the error.

Form and file input tags:
<form action="server.edu/submit.pl?querystring" enctype="multipart/for +m-data" method="post"> <input type="file" name="uploadfile_0" /> <input type="submit" value="upload" /> </form>
The relevant perl:
my $query = CGI::new(); my $filename = $query->param("uploadfile_0"); next if !$filename; $filename =~ s/^.*[\/\\](.*)/$1/; $filename =~ s/\s/"_"/ge; my $upload = $query->upload("uploadfile_0"); if (!$upload) { $output .= "<p>CGI.pm failed to upload the file.</p>"; next; } open(FILE,">$location/$filename") or die "$!"; binmode FILE; while ( <$upload> ) { print FILE; } close(FILE);
It always hits the !$upload catch. If i remove that catch the file is created as an empty 0 byte file. Hopefully its a simple problem that i'm missing out of frustration.

Replies are listed 'Best First'.
Re: Uploading Files with CGI.pm results in 0 byte files
by imp (Priest) on Nov 19, 2006 at 20:40 UTC
    I tested the provided code locally and did not have any issues with the upload. The problem is elsewhere, whether with other unprovided code, or with local modules/web service/file system.

    Here's a standalone version of the provided code that dumps the file to the browser, along with the temp file name.

    #!/usr/bin/perl use strict; use warnings; use CGI; my $output = ''; my $query = CGI->new(); my $filename = $query->param("uploadfile_0"); my $upload = $query->upload("uploadfile_0"); $output .= "Temp file: " . $query->tmpFileName($filename) . "\n"; if (!$upload) { $output .= "<p>CGI.pm failed to upload the file.</p>"; } else { $output .= "----- Contents: ------\n"; while (<$upload>) { $output .= $_; } } print "Content-type: text/plain\n\n"; print $output;
    Could you provide some details about your environment?
    e.g.:
    OpenBSD 3.5
    Apache 1.3.34
    perl 5.8.2
    CGI 3.20
    
      Found the problem.

      I was checking authentication using CGI::Session and creating a $cgi object with it.

      Apparently, if you have form data and don't use the first CGI object you create you lose the upload, but retain all the additional data.

      Learn something new every day. I've been creating multiple CGI objects for years without any problems. From now on i'll create just one and pass it around to functions as needed.
        That's because POST data comes into the program on STDIN, as opposed to the environment table which is used for GET data ($ENV{QUERY_STRING}). STDIN can only be read once, and so the first CGI object instantiated will suck it all up.
      I too have gotten a stand alone version working (before i saw your reply, that was my next step after posting). I've copied and pasted the working code into my program with no luck. Loaded all the modules i'm loading in the real scripts in the standalone and the standalone still works fine.

      I'm about ready to go back and kick the server.

      Redhat AS4 fully patched perl 5.8.5-36.RHEL4, which ever version of CGI comes with it.
Re: Uploading Files with CGI.pm results in 0 byte files
by barrycarlyon (Beadle) on Nov 20, 2006 at 02:22 UTC

    I had this problem, there is a node somewhere on perl monks by me, I think you forgetting to set up a buffer so I'll just going to dump the code Im currently using:


    use to call
    $final = _upload($localfile,$destination,$filename); if ($final > 0) { #then the file was uploaded successfully! } else { return 'There was an error with the file you supplied, either it + was of 0 bytes size or the system failed!<br /> <a href="javascript: +history.go(-1);" >Back</a>'.$final; }

    Destiantion is obviosuly
    my $destination = "path"; my $localfile = $q->param('upload_image'); my $filename = $q->param('upload_file');

    In your case swap upload_image and upload_file with uploadfile_0, i have to as my form gives the option to rename the file (just another input field). This code snippet (above) should go above the 'calling' bit
    sub _upload { my $localfile = shift; my $totalbytes; my ($bytesread, $buffer); my $num_bytes = 1024; my $destination = shift; my $filename = shift; my $final; my $output_file = $destination . $filename; use CGI::Upload; open (OUTFILE, ">", "$output_file") or die "Couldn't open $output_fi +le for writing"; while ($bytesread = read($localfile, $buffer, $num_bytes)) { $totalbytes += $bytesread; print OUTFILE $buffer; } die "$output_file Read Failure: $!" unless defined($bytesread); unless (defined($totalbytes)) { # $final = "<p>Error: Could not read file $localfile, or was of zer +o length"; $final = 0; } else { # $final = "<p>Done ok, $totalbytes</p>"; $final = $totalbytes; } close OUTFILE or die "Couldn't Close file $!"; return $final; }
    Barry Carlyon barry@barrycarlyon.co.uk