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

I'm in the process of writing a web mail package and need to sort out how to upload and download files. The relevant html of my web page in my form is:
<input type="file" value="starting value">
This is passed to a perl script using CGI.pm and I do this:
$file = $query->param('upload_file_name');
The perl references I've read said that all I have to do next is to read from $file. However, this only works when I browse from the same machine the script is on, because it sees the path locally as /path/to/my/file. When I try this from Windows, the path is passed as C:\dos\path\to\file. What I need to know is how to actually have the file upload? Any suggestions, or is this something I may have to do in Javascript?

Replies are listed 'Best First'.
Re: Uploading via HTML/Using CGI.pm
by t0mas (Priest) on Oct 17, 2000 at 13:29 UTC
RE: Uploading via HTML/Using CGI.pm
by agoth (Chaplain) on Oct 17, 2000 at 13:51 UTC
    In addition to the links above from t0mas, the way I have used in the past is via cgi->tmpFileName and using File::Copy,

    A subroutine example is below, msg me if you cant work out which bits might be useful.

    P.S I have a suspicion setting the umask to 000 might not be a good thing but this sub is renaming the files...

    sub storeFiles { my $self = shift; my $cgi = shift; my $mode = shift; # going to be insert or update my $fileerror = '0'; my @filecols = ('DOC_1', 'DOC_2', 'IMG_1', 'IMG_2', 'IMG_3', 'IMG_ +4'); my $umm = umask(000); foreach my $doc (@filecols) { if ($cgi->param($doc)) { # if insert this is an add, else a replace action for upda +tes my $longfile = $cgi->param($doc); my $tempfile = $cgi->tmpFileName($longfile); my $size = -s $tempfile; if (($size < 1) || ($size > 2000000)) { $fileerror = '1'; last; } $longfile =~ s/ //g; # strip sp +aces $longfile =~ s/^(.*[\/\\:])*([^\/\\:]+)$/$2/; # remove p +ath if ($longfile !~ /\./) { $fileerror = '2'; last; } $longfile =~ s/\.(?=.*\.)//g; # substitu +te all but last dot (courtesy of L.Rosler) my ($f, $ext) = split /\./, $longfile; if (!$self->_isValidFile($doc, $ext)) { $fileerror = '3'; last; } my $newfile = $DATA_DIR . $self->{'PAGE'}[2] . "/" . $self +->{'DOCID'}[2] . $doc . "." . $ext; eval { copy ($tempfile, $newfile) or die "cant copy temp *$te +mpfile* to new *$newfile* $! \n longfile is $longfile"; }; if ($@) { $fileerror = '4'; last; } else { $self->{$doc}[2] = $self->{'DOCID'}[2] . $doc . "." . +$ext; } } elsif ($cgi->param("exists$doc")) { $self->{$doc}[2] = $cgi->param("exists$doc"); } else { $self->{$doc}[2] = ''; } if (($cgi->param("chk$doc")) && (!$cgi->param($doc))) { # unlink file if update checkbox is checked my $page = $self->{'PAGE'}[2]; if (($page == 22) || ($page == 26) || ($page == 27)) { my $dir = "../data/$page"; opendir (DIRH, $dir) or Util->showError("Can't Open de +signated directory $dir $!"); my @files = grep /^$self->{'DOCID'}[2]$doc/, readdir D +IRH; @files = map ("$dir/$_", @files); closedir DIRH; unlink @files or Util->showError("oops cant unlink you +r chosen files @files $!"); } $self->{$doc}[2] = ''; } } umask($umm); return $fileerror; }
Re: Uploading via HTML/Using CGI.pm
by Fastolfe (Vicar) on Oct 17, 2000 at 17:03 UTC
    It sounds like you are attempting to use $file as a filename, instead of an open filehandle as described in the CGI.pm documentation.
    my $file = $query->param('upload_file_name'); while (<$file>) { print "Got a line: $_"; }
    Treating $file as a string will give you the filename that the user selected, as if it were a simple text input box. Thus, attempting to open this will fail unless you're on the same system. That's not how it was intended to work anyway. In any browser (except IE on a Mac so far as I've been able to tell), you can just type text in file input fields, without necessarily needing a valid file. This would allow arbitrary strings to appear in $file, which is a huge security problem if you're attempting to blindly open that filename. Treat it as a filehandle.

    You may wish to examine the 'FILE UPLOAD' section of the CGI.pm documentation. It goes into considerable detail about all of this, as well as the tmpFileName method another poster mentioned. It even has examples.

(Ovid) Re: Uploading via HTML/Using CGI.pm
by Ovid (Cardinal) on Oct 17, 2000 at 18:32 UTC
    Don't forget to set the correct ENCTYPE for your form:
    <FORM ACTION="/path/somescript.cgi" METHOD="POST" ENCTYPE="multipart/f +orm-data">
    Make sure you use strict;, but you may have a problem with Perl claiming your file name is a symbolic reference and refusing to open it. If you need a hard reference, you can do the following:
    my $file = $q->param( 'file' ) or someErrorRoutine( $q, "No file recei +ved" ); my $fh = $q->upload( $file );
    $fh is now supposed to be the filehandle for your file. This requires CGI.pm version 2.47 or above. However, I have had a lot of difficulty getting that to work.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just go the the link and check out our stats.

Re: Uploading via HTML/Using CGI.pm
by AgentM (Curate) on Oct 17, 2000 at 19:22 UTC
    As soon as i see someone wanting to write an email package, I like to direct them to NeoMail. No need to write it yourself. You can even embed NeoMail in an existing web app. NeoMail is cooler than Yahoo!, more organized than Outlook, and very user-friendly. I urge you to take a look. It will simplify your entire project as well as appease your worries (tried-and-true security and features). That is, unless you plan to rival NeoMail! :-O
    AgentM Systems or Nasca Enterprises is not responsible for the comments made by AgentM- anywhere.
Re: Uploading via HTML/Using CGI.pm
by radagast (Sexton) on Oct 19, 2000 at 13:27 UTC
    Thanks everyone for the responses. AgentM, perhaps one day I will write something to rival NeoMail. ;) Actually, this is also as much an exercise for me so I can wrap my head around a lot of Perl concepts at once.