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

Hey all,

I wouldn't consider myself a perl 'expert' by any stretch of the imagination, but I can't figure out what's wrong with my implementation of this code. Specifically, I was trying to use Ovid's code to implement a file upload utility for my site.

I can't get it to work, though. It gets to the sysopen command, but when it tries to write data, it either freezes, or writes nothing to the file and closes, leaving a zero-length file. What am I doing wrong? The "meat" of the code should be the same as Ovid's source.

Anyways, here's the code. I've put in some extra print statements for debugging purposes.

#!/usr/bin/perl -w use strict; use CGI; use Fcntl; use constant BUFFER_SIZE => 16_384; # Amount of upload file to + read at one time use constant MAX_FILE_SIZE => 1_048_576; # This is the filesize upl +oad limit use constant UPLOAD_DIR => "/data/www/inverse.org/html/muckraker/te +mp/"; $CGI::DISABLE_UPLOADS = 0; # Temporarily reenable upl +oads $CGI::POST_MAX = MAX_FILE_SIZE; # This will stop someone f +rom uploading # a fifty meg file to your + system my $req = CGI->new; my $theext = "gif"; my $donepage = "up2.html"; my %upload_path = ('personal' => 'temp_a/', 'impersonal' => 'temp_b/'); my $path = 'personal'; # my $path = $req->param('path'); if (! exists $upload_path{$path}) { # Oops! It's not in our hash. Someone was being naughty! print $req->redirect("some_error_page.html"); exit; } $path = $upload_path{$path}; print "Content-type: text/html\n\n"; UPLOAD_FILE: { for my $onnum (1..10) { my $file = $req->param("FILE$onnum") or next UPLOAD_FILE; if ($file) { my $buffer; my $file_handle = $req->upload( $file ); my $format = $req->uploadInfo($file)->{'Content-Type'}; print "format is '$format'\n"; # In the following regex, we're getting the image type of +the MIME type. # This is better than checking the extension because if th +ey upload from # a system that doesn't use extensions - or if the user's +redefined their # extensions, we'd have problems. $format =~ s!^image/([a-zA-Z]+)$!$1!; if ($format !~ /$theext/o) { print "skipping to next\n"; next UPLOAD_FILE; } my $fileName = ""; # Create a random filename. Keep running the loop if the +filename exists, # or if $fileName is false. while (! $fileName or -e UPLOAD_DIR.$path.$fileName) { $fileName = ""; my @myarray=('a'..'z','A'..'Z','1'..'9'); for (1..8) { $fileName .= $myarray[rand(@myarray)]; } $fileName .= ".$theext"; } print "creating new file '" . UPLOAD_DIR . " :: $path :: $ +fileName'\n"; # This will create the new file sysopen OUTFILE, UPLOAD_DIR . $path . $fileName, O_CREAT o +r die "Can't open UPLOAD_DIR$path$fileName: $!"; print "sysopen done\n"; # print OUTFILE $file_handle; while ( read( $file_handle, $buffer, BUFFER_SIZE ) ) { print "buffering... "; print OUTFILE $buffer; } print "printing done\n"; close (OUTFILE); print "closing file\n"; } } } print "program done\n";

Sample output:

format is 'image/gif' creating new file '/data/www/inverse.org/html/muckraker/temp/ :: temp_a/ :: Q1ywz4Nt.gif' sysopen done printing done closing file program done</B>

Commented out lines are ones I tried; whenever I used the single unbuffered print command, I got the zero-width file, but the program would freeze when I used the buffered write procedure shown.

I don't know how to debug using the built in tools since I can't 'fake' the GIF file I'm trying to send. I've tried many different .GIF files, all created in Photoshop.

I've tried other code snippets, both from this site and from the CGI.pm documentation, but they all seem to fail at the same point - the writing of the GIF file. I'm uploading from the same HTML file that Ovid referred to, using MSIE 5.5 (though I've tried in Netscape 4.74 and a few other browsers too). Any help on this would be very much appreciated!

Andre Germain

Replies are listed 'Best First'.
Re: I've got a problem with the file upload code
by bikeNomad (Priest) on Jun 27, 2001 at 22:15 UTC
    I don't know what you mean by saying "the program would freeze"; it looks like you're getting the "program done" printout at the end, so isn't freezing.

    If you're using Windows, you might try using binmode() on your file handle (as well as checking for whether the upload succeeded):

    if (!defined($file_handle)) { ... handle it ... } $file_handle->binmode;

    The reason you got an empty file when you did this: print OUTFILE $file_handle; is probably that $file_handle was undef. If it were a valid file handle, you'd have gotten something like "IO::File=GLOB(0x83b3ca4)" in your file (you can't print a file handle to another file and expect the file to get copied).

    Also, if you're on Windows, make sure to binmode OUTFILE too.

      Thanks for the quick response!

      I added binmode OUTFILE; to the beginning of the program, since I wasn't quite sure what it did. I also added the line you mentioned, right after and was indeed getting an undefined $file_handle. What might cause it to be undefined, though? I don't understand why it wouldn't work, since I'm using the same code that was quoted for that section.

      For reference, I have CGI.pm 4.72, and have tried this with ActivePerl on Win98SE, and with FreeBSD, and both give the same results.

        You want to put the binmode after the open of the file. You also probably want to add a binmode for $file_handle.

        An undef $file_handle means that the upload failed, for some reason. If you use CGI::Carp you can see the warnings and/or fatal errors from your script.

Re: I've got a problem with the file upload code
by Anonymous Monk on Jun 27, 2001 at 22:08 UTC
    You want to write the $file_handle into the OUTFILE. How do you think an open filehandle is represented in another file? Linking? Or Embedding? And while perl figures it out you can wait. FOREVER!