in reply to Yet another CGI Upload problem - not like the others!

$query->upload($file)

should be

$query->upload('upfile')

From perldoc CGI (my emphasis)

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.

Replies are listed 'Best First'.
Re: Re: Yet another CGI Upload problem - not like the others!
by stuayres (Novice) on Dec 11, 2002 at 11:29 UTC
    Thanks adrianh for this - it does make the code cleaner, and make more sense than what I was doing. It's actually something I've tried before but it still dies there though. It's running on apache & the error log just says my script died at the 'upload' line. Weird isn't it?

      To debug this change the die to  die $query->cgi_error()

      If that is not revealing then have a look at the CGI object which should contain a blessed? reference to the upload file's tmpdir name.

      use CGI; use Data::Dumper; $q = new CGI; print $q->header; print '<pre>' . $q->escapeHTML(Data::Dumper::Dumper($q)) . '</pre>';

      This will prove one way or another if the file is getting to the server and being written to a tmp dir. This may well be the problem. When you do the upload the file is spooled by CGI.pm to a tmp dir ( CGI.pm uses /tmp /temp and something else in that order from memory). If it can't write here it can't spool. Then when you call upload() it will have nothing to deliver and return false, thus causing death as described.

      If that fails then try my CGI::Simple module which has the same interface as CGI.pm but far more inclusive and revealing cgi_error() messages. It uses IO::File's tmpfile() method to get a FH for spooling so does not need write permission to /tmp. It also has an addition to the upload() method that lets you do the upload in one line. See the docs for details.

      use CGI::Simple; my $q = new CGI::Simple; # <INPUT TYPE="file" NAME="upload_file" SIZE="42"> $files = $q->upload() # number of files uploaded @files = $q->upload(); # names of all uploaded fi +les $filename = $q->param('upload_file') # filename of uploaded fil +e $mime = $q->upload_info($filename,'mime'); # MIME type of uplo +aded file $size = $q->upload_info($filename,'size'); # size of uploaded +file my $fh = $q->upload($filename); # get filehandle to read f +rom while ( read( $fh, $buffer, 1024 ) ) { ... } # short and sweet upload $ok = $q->upload( $q->param('upload_file'), '/path/to/write/file.n +ame' ); print "Uploaded ".$q->param('upload_file')." and wrote it OK!" if +$ok;

      cheers

      tachyon

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

        Hi, I thought I would try out your simple method of file upload. It works fine except the maximum file size dosn't seem to work. I'm uploading 2 meg files to the cgi script below, why isn't the limit working?
        #!/usr/bin/perl use warnings; use strict; use CGI::Simple; $CGI::Simple::POST_MAX = 1024; # max upload via post default 100 +kB $CGI::Simple::DISABLE_UPLOADS = 0; #enable uploads my $upload_dir='uploads'; my $q = new CGI::Simple; print $q->header(); my $files = $q->upload(); # number of files uploaded +; my @files = $q->upload(); # names of all uploaded fil +es my $filename = $q->param('upload_file'); # filename of uploaded fil +e my $mime = $q->upload_info($filename,'mime'); # MIME type of uploa +ded file my $size = $q->upload_info($filename,'size'); # size of uploaded f +ile # short and sweet upload my $ok = $q->upload( $q->param('upload_file'),"$upload_dir/$filename") +; print "Uploaded ".$q->param('upload_file')." and wrote it OK!\n" if $o +k; print "total files = $files<br> filenames = @files<br> filename = $filename<br> mimetype= $mime<br> size=$size<br>";
        Hello Tachyon, Firstly, thanks for the help. I'm constantly amazed at how helpful people are & how good the quality of the advice is here. Secondly, I wanted to tell you how far I've got with it! I've tried the first approach & it's given me some feedback, the meaning of which is not clear to me. The file does not appear to be making it to the server, the blessed? reference appeared as follows:
        '.tmpfiles' => { '3' => { 'info' => { 'Content-Disposition' => 'form-data; name="file +"; filename="C:\\stu\\putty\\stu.txt"', 'Content-Type' => 'text/plain' }, 'name' => bless( do{\(my $o = '/usr/tmp/CGItemp10026') +}, 'TempFile' ) } },
        And:
        'file' => [ bless( \*{'Fh::fh00001C%3A\\stu\\putty\\s +tu.txt'}, 'Fh' ) ],
        The error log now records the reason for death as:
        [Wed Dec 11 15:54:14 2002] new_upload.cgi: Use of uninitialized value +in die at <<path to script>>/new_upload.cgi line 70. [Wed Dec 11 15:54:14 2002] new_upload.cgi: Died at <<path to script>>/ +new_upload.cgi line 70. :$
        and line 70 is:
        while($bytes=(read($fh, $buffer, 1024)or die $q->cgi_error())) { $bytes_read += $bytes; print OUTFILE $buffer; }
        I'm stumped. Does this make the reason for the failure clearer to you? Thanks again for your help.

      With the code shown, not sure what's wrong. I've just taken your example and, with a few tweaks, the following runs fine on my box:

      <FORM ACTION="path_to_form.cgi" METHOD="POST" ENCTYPE="multipart/form- +data"> <INPUT TYPE="text" NAME="filename" SIZE="10" MAXLENGTH="50"> <INPUT TYPE="FILE" NAME="upfile"> <INPUT TYPE="submit" VALUE="upload"> </FORM> #!/usr/bin/perl -w use strict; use warnings; use CGI qw(:standard); use CGI::Carp 'fatalsToBrowser'; $CGI::DISABLE_UPLOADS = 0; $CGI::POST_MAX = 52428800; my $SAVE_DIRECTORY = "/tmp"; my $query=new CGI; my $filename = $query->param("filename") or die "no filename"; # you need to check that the filename only contains sane characters # otherwise you could have users writing anywhere in the file system die "bad filename" unless $filename =~ m/^\w+$/; my $fh = $query->upload("upfile") or die "no file"; # you realise this could allow multiple users to write to the same # filename at the same time. probably not what you want. open(OUTFILE, ">$SAVE_DIRECTORY\/$filename") or die "open failed ($!)" +; binmode OUTFILE; my ($bytes, $buffer, $size); while ($bytes = read($fh,$buffer,1024)) { $size+=$bytes; print OUTFILE $buffer; }; # read can fail with undef - you need to check :-) die "read failure ($!)" unless defined($bytes); close(OUTFILE); print $query->header; print "$filename uploaded: $size bytes" if $size > 0;

      Try the above on your machine and see if it works

      Personally, I would suspect your HTML - it looks like you're not passing upfile for some reason...

      The best way of solving this sort of problem is to actually write a smaller version of the code that demonstrates the problem. Once you have your "other code" and "other html" out of the way the error will probably become obvious :-)