in reply to Re: CGI Uploading (repost)
in thread CGI Uploading (repost)

That documentation is nearly identical to all the other's, that's what I've come to notice about perl. All documenations are the same so if you don't understand one you're in a lot of trouble.

One of the things I don't get is where $filehandle comes from.

while (<$filename>) { print; }
Is that a built in variable or does it automatically assign itself from the upload field or do I need to assign it or what? It doesn't cover that anywhere. I guess this was the main part I couldn't understand.

Replies are listed 'Best First'.
Re: Re: Re: CGI Uploading (repost)
by cees (Curate) on Apr 17, 2003 at 06:17 UTC

    It can be tricky to see the right information when it is all new to you... It actually does explain where $filename comes from on that page, and in the CGI.pm perldocs.

    $filename = $query->param('uploaded_file');

    Where 'uploaded_file' is the name of the form parameter that you put in your HTML file. Right around the same place where the above code appears, it also says the following:

    The filename returned is also a file handle. You can read the contents of the file using standard Perl file reading calls:

    What this means is that the $filename that is returned in the above code actually contains 2 different things. When you look at $filename as a scalar, you will get a string containing the name of the file that was uploaded. However, if you try to use the $filename as a file handle, then you can read from it and get the contents of the file. There is some perl 'magic' going on here that you should not worry about right now, but should look into later when you are more familiar with Perl (You can read the perldata manpage and search for the section on TypeGlobs and Filehandles for more info on what is happening here).

    So, to get back to your question, to get a file upload to work, you need to do something like the following:

    # Get the name of the file and an # open file handle to the file contents $filename = $query->param('uploaded_file'); # Read a text file and print it out while ($line = <$filename>) { print $line; }

    Or if the uploaded file is a binary file like an GIF or JPEG:

    # Get the name of the file and an # open file handle to the file contents $filename = $query->param('uploaded_file'); # Copy a binary file to somewhere safe open (OUTFILE,">>/usr/local/web/users/feedback"); while ($bytesread=read($filename,$buffer,1024)) { print OUTFILE $buffer; } close $filename;

    The way the file upload actually works is that the web server receives the file and stores it in a temporary place. The CGI.pm module opens up this file for reading and gives you the open filehandle. You have to use this filehandle to read the contents of the file, and then do something with it. Usually this just means creating a new file and writing the contents to it.

    Again, this is straight out of the documentation, but I am just trying to point you in the right direction. Feel free to ask more question if you get stuck, but the best way to learn is just to try a bunch of things and see what happens.

    Good Luck

    Update: I forgot about the 'upload' method that chromatic mentions above, so definately look at that as well.

      That's what I thought it was, can you tell me what's wrong with my code below then? I get an error on my open (OUTFILE.. and I receive a software error.
      #!/usr/bin/perl -w use warnings; use CGI qw/:standard/; use CGI::Carp 'fatalsToBrowser'; use POSIX; print header, start_html('upload form'); print start_form(), table( Tr( td("File: "), td(filefield(-name=>'upload', -size=>50, -maxlength=>80), ), ), Tr( td(), td(submit('button','submit'), ) ) ), end_form(), hr; if (param()) { my $filename = param('upload'); while (<$filename>) { print; } open (OUTFILE,">>/home/myname/public_html/upload") || die $!; while ($bytesread=read($filename,$buffer,1024)) { print OUTFILE $buffer; print "the thing is open"; } close $filename; print "The file should be uploaded if everything went right, which it +probably didn't.\n"; }
        There are a few points here.
        • To upload a file, the HTML form needs to have a 'multipart/form-data' encoding type - this is done by 'start_form(-enctype=>'multipart/form-data'), instead of just start_form()'
        • while (<$filename>) {print;} will 'empty' the filehandle. As I explained here, CGI.pm gives you a *handle* to the file it uploaded-and-decoded-and-saved-as-a-tmpfile, allowing you to read from it and write the data to somewhere else (OUTFILE). (For that reason, I generally call it $filehandle). You've been confused by the CGI docs here - that bit of example code is actually *two* examples, as evidenced by the comments - one to read-and-print a text file, one to read-and-save a binary file. you want the second one - you can throw away that while<$filename> structure.
        • You open'ed OUTFILE, so you close OUTFILE, not $filename. $filename is something 'lent' to you by CGI.pm - don't worry - it'll take care of it itself :)
        Hope this clears some stuff up.
        Ben
        Another point is that you are reading the file in binary mode but you are not using binmode() to ensure the file you are writing is binary. When it doesn't matter, it doesn't matter, but where it does matter, it can really matter.  :-)
Re: Re: Re: CGI Uploading (repost)
by chromatic (Archbishop) on Apr 17, 2003 at 05:58 UTC

    $filename comes from just a few lines earlier in the documentation. Of course, a few lines later, the docs suggest this code instead:

    use CGI; my $query = CGI->new(); my $fh = $query->upload('uploaded_file'); while (<$fh>) { print; }

    Assuming you've created a form that posts to the script correctly, uses the POST method, uses multipart/form-data encoding, and contains a file upload field named uploaded_file, this will work for you.

      Ok, with your example... $fh is actually the name of the file it's going to be saved as on the server, right? So doing a while (<$fh>) it's opening up a blank file then saving the contents stored in the buffer? Sorry, I just don't understand how the uploading actually works. I always imagined it upload the file directly from their system, but it looks like that's not the case.

      Other question..Can I set $fh to $fh = param('uploaded_file') or would that be something different?