http://qs1969.pair.com?node_id=278811

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

Hi guys!
I wanna use CGI::Upload to allow file uploading to the server in a file-manager I wrote. I set up a form (Please note that I don't set up the form using cgi.pm objects, just plain html) like this:

<form method="POST" enctype="multipart/form-data" action="url_to_scrip +t.pl?upload"><input type="hidden" name="directory" value="$cur"><br> <input type="file" name="upload" size="20"><br><input type="submit" +value="send"><input type="reset" value="reset"> </form><br><br>
In here $cur is the current working directory, or in other words, the directory to which the file should be uploaded.

Now my problem is that I don't really know how to proccess it to upload the file. I used a little example and wrote this little function:

sub upload { read (STDIN, $in, $ENV{'CONTENT_LENGTH'}); @pairs = split (/&/, $in); foreach $pair (@pairs) { ($name, $value) = split (/=/, $pair); $name =~ s/\+/ /g; $name =~ s/%(..)/pack("C", hex($1))/ge; $value =~ s/\+/ /g; $value =~ s/%(..)/pack("C", hex($1))/ge; $value =~s/<!--(.|\n)*-->//g; if ($parse{$name}) { $parse{$name} .= ", $value"; } else { $parse{$name} = $value; } } my $cgi = CGI->new; my $upload = CGI::Upload->new( $cgi ); if ( $upload->mime_type('upload') eq 'image/gif' ) { my $buffer; my @results; my $fh = $upload->file_handle('upload'); while (read($fh, $buffer, 45)) { push (@results, pack("u", $buffer)); } open (FILE, "+>>$parse{directory}/$upload->file_name('upload')") o +r die "Can't open image file: $!"; for $line (@results) { print FILE "$line"; } close (FILE) or die "Can't close image file: $!"; $fh->close; } filemgr($parse{directory}); # Print directory tree }
As you can see my function takes the file, which should be a gif image, and reads the contents of the temp file created by CGI::Upload. After reading the entire file, I create a new image file and print the contents read before into this file. I don't really know much about how image files work so I wasn't sure that this was valid, but I tried anyway.

On testing the script, I get the error "Malformed multipart POST".

I will be much obliged if someone helps me with this problem and guides me through the steps of writing a script that actually uploades a gif file to the server.

Thanks,
Ido Perelmutter,
Israel,
ido@bnei-yehoda.co.il

20030729 Edit by Corion: Added CODE tags

Replies are listed 'Best First'.
Re: Need help with CGI::Upload
by cfreak (Chaplain) on Jul 29, 2003 at 13:39 UTC

    I think your problem is that you're using a do-it-yourself form processer rather than CGI.pm to get your form parameters, then you're calling CGI.pm as well. CGI handles all form processing for you. If you want a hash of your form parameters you can do this:

    my %parse = $cgi->Vars();

    Or you can do named parameters:

    my $directory = $cgi->param('directory');

    Using the two could be the reason you're getting the 'Malformed multipart POST' ... though I can't be sure. At any rate you should still use just CGI.pm

    Next you're uuencoding your file as it comes in. I don't think you want to do that if you're going to show the file again in anything else. I don't believe that image programs or browsers are going to be expecting it to be encoded that way.

    I don't know if my suggestions will solve your problem but I certainly hope it helps :)

    Lobster Aliens Are attacking the world!
      Huh. You say that like it is a bad thing...
Re: Need help with CGI::Upload
by tcf22 (Priest) on Jul 29, 2003 at 13:27 UTC
    I normally use the following.
    It works for me pretty well for me.
    use CGI; $cgi=new CGI; $file=$cgi->param('file_field'); $newName=&FileUpload($file); sub FileUpload{ my $FileName=shift @_; my $tmpdir ="/your/path"; my $bufferSize=4096; my $limit=10000000;#File Size Limit my ($debug, $FILE, $file, $size, $tmppath, $line, $buffer); $size = 0; if (length($FileName) != 0){ $| = 1; $FILE = $FileName; ($file = $FILE) =~ s/^.*?([^\\\/]+)$/$1/; $tmppath = "$tmpdir\\$file"; open (OUT, ">$tmppath") or print "Error opening $tmppa +th: $!<br>\n"; binmode OUT; while(($line = read ($FileName, $buffer, $bufferSize)) + && ($size < $limit)){ print OUT $buffer; $size += $line; if ($size > $limit){ $err_flag = 1; } } close OUT; $| = 0; $FileName = $file; } else{##Empty File $FileName = ""; } #Upload Error if ($err_flag == 1){ unlink ($tmppath); $FileName = ""; } $FileName; }
    Tom
      Oh dear ... reinventing established wheels ... bad ...

      Since you have already loaded CGI.pm ... why not use CGI::upload ... it's a whole lot easier. Here is a short example that you can modify (add error checking, etc.).

      #!/usr/bin/perl -T use strict; use HTML::Entities; use CGI qw(:standard); print header, start_multipart_form, filefield('file'), submit('go'), end_form, ; if (param('go')) { my $fh = upload('file'); print hr, pre( map { encode_entities $_ } <$fh>); }

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)
      
Re: Need help with CGI::Upload
by ido50 (Scribe) on Jul 30, 2003 at 14:10 UTC
    Thanks everyone, I've used the CGI.pm's HTML shortcuts to print the form and everything and it works good.